--- /dev/null
+# ====================================================================
+#
+# board_eth_drivers.cdl
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+
+cdl_package CYGPKG_DEVS_ETH_ARM_IMX_3STACK {
+ display "Ethernet driver for Freescale MXC Board development board"
+
+ parent CYGPKG_IO_ETH_DRIVERS
+ active_if CYGPKG_IO_ETH_DRIVERS
+
+ include_dir cyg/io
+
+ # FIXME: This really belongs in the SMSC LAN92xx package
+ cdl_interface CYGINT_DEVS_ETH_SMSC_LAN92XX_REQUIRED {
+ display "SMSC LAN92XX ethernet driver required"
+ }
+
+ define_proc {
+ puts $::cdl_system_header "/***** ethernet driver proc output start *****/"
+ puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_SMSC_LAN92XX_INL <cyg/io/devs_eth_arm_board.inl>"
+ puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_SMSC_LAN92XX_CFG <pkgconf/devs_eth_arm_imx_3stack.h>"
+ puts $::cdl_system_header "/***** ethernet driver proc output end *****/"
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0 {
+ display "MXC Board ethernet port driver"
+ flavor bool
+ default_value 1
+ description "
+ This option includes the ethernet device driver for the
+ MXC Board port."
+
+ implements CYGHWR_NET_DRIVER_ETH0
+ implements CYGINT_DEVS_ETH_SMSC_LAN92XX_REQUIRED
+
+ cdl_option CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME {
+ display "Device name for the ETH0 ethernet driver"
+ flavor data
+ default_value {"\"eth0\""}
+ description "
+ This option sets the name of the ethernet device."
+ }
+
+ cdl_component CYGSEM_DEVS_ETH_ARM_MXCBOARD_ETH0_SET_ESA {
+ display "Set the ethernet station address"
+ flavor bool
+ default_value 0
+ description "Enabling this option will allow the ethernet
+ station address to be forced to the value set by the
+ configuration. This may be required if the hardware does
+ not include a serial EEPROM for the ESA."
+
+ cdl_option CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_ESA {
+ display "The ethernet station address"
+ flavor data
+ default_value {"{0x08, 0x88, 0x12, 0x34, 0x56, 0x78}"}
+ description "The ethernet station address"
+ }
+ }
+ }
+}
--- /dev/null
+//==========================================================================
+//
+// devs_eth_arm_board.inl
+//
+// Board ethernet I/O definitions.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
+
+#include <cyg/hal/hal_intr.h> // CYGNUM_HAL_INTERRUPT_ETHR
+#include <cyg/hal/hal_if.h>
+
+#ifdef CYGPKG_REDBOOT
+#include <pkgconf/redboot.h>
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <redboot.h>
+#include <flash_config.h>
+#endif
+#endif
+
+extern unsigned int sys_ver;
+
+#ifdef __WANT_DEVS
+
+#ifdef CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
+#if defined(CYGPKG_REDBOOT) && defined(CYGSEM_REDBOOT_FLASH_CONFIG)
+RedBoot_config_option("Set " CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME " network hardware address [MAC]",
+ eth0_esa,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL, false
+ );
+RedBoot_config_option(CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME " network hardware address [MAC]",
+ eth0_esa_data,
+ "eth0_esa", true,
+ CONFIG_ESA, 0
+ );
+#endif // CYGPKG_REDBOOT && CYGSEM_REDBOOT_FLASH_CONFIG
+
+#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+// Note that this section *is* active in an application, outside RedBoot,
+// where the above section is not included.
+
+#include <cyg/hal/hal_if.h>
+
+#ifndef CONFIG_ESA
+#define CONFIG_ESA (6)
+#endif
+#ifndef CONFIG_BOOL
+#define CONFIG_BOOL (1)
+#endif
+
+cyg_bool _board_provide_eth0_esa(unsigned char * mac)
+{
+ cyg_bool set_esa;
+ int ok;
+ ok = CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,
+ "eth0_esa", &set_esa, CONFIG_BOOL);
+ if (ok && set_esa) {
+ ok = CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,
+ "eth0_esa_data", mac, CONFIG_ESA);
+ }
+
+ return ok && set_esa;
+}
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+
+#endif // CYGPKG_DEVS_ETH_ARM_MXCBOARD_ETH0
+
+#endif // __WANT_DEVS
--- /dev/null
+# ====================================================================
+#
+# smsc_lan92xx_eth_drivers.cdl
+#
+# Ethernet drivers - support for LAN92XX compatible ethernet controllers
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2007 Fred Fan
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Fred Fan
+# Contributors: Fred Fan
+# Date: 2007-9-27
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_SMSC_LAN92XX {
+ display "SMSC LAN92XX compatible ethernet driver"
+ description "Ethernet driver for SMSC LAN92XX compatible controllers."
+
+ parent CYGPKG_IO_ETH_DRIVERS
+ active_if CYGPKG_IO_ETH_DRIVERS
+
+ implements CYGHWR_NET_DRIVERS
+ implements CYGINT_IO_ETH_MULTICAST
+
+ active_if CYGINT_DEVS_ETH_SMSC_LAN92XX_REQUIRED
+
+ include_dir cyg/io
+ compile -library=libextras.a if_lan92xx.c
+
+ define_proc {
+ puts $::cdl_header "#include <pkgconf/system.h>";
+ puts $::cdl_header "#include CYGDAT_DEVS_ETH_SMSC_LAN92XX_CFG";
+ }
+
+ cdl_component CYGPKG_DEVS_ETH_SMSC_LAN92XX_OPTIONS {
+ display "LAN92XX ethernet driver build options"
+ flavor none
+ no_define
+
+ cdl_option CYGPKG_DEVS_ETH_SMSC_LAN91CXX_CFLAGS_ADD {
+ display "Additional compiler flags"
+ flavor data
+ no_define
+ default_value { "-D_KERNEL -D__ECOS" }
+ description "
+ This option modifies the set of compiler flags for
+ building the LAN91CXX ethernet driver package.
+ These flags are used in addition
+ to the set of global flags."
+ }
+ }
+}
--- /dev/null
+#ifndef CYGONCE_DEVS_ETH_SMSC_LAN92XX_LAN92XX_H
+#define CYGONCE_DEVS_ETH_SMSC_LAN92XX_LAN92XX_H
+//==========================================================================
+//
+// lan92xx.h
+//
+// SMCS LAN9217 (LAN92XX compatible) Ethernet chip
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Nick Garnett
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD or other sources,
+// and are covered by the appropriate copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_endian.h>
+
+#define __WANT_CONFIG
+#include CYGDAT_DEVS_ETH_SMSC_LAN92XX_CFG
+#undef __WANT_CONFIG
+
+typedef struct
+{
+ unsigned short id;
+ unsigned short ver;
+ char *id_name;
+}smsc_lan92xx_id_t;
+
+// LAN92xx register offset
+#define LAN92XX_RX_DATA 0x00
+#define LAN92XX_TX_DATA 0x20
+#define LAN92XX_RX_STATUS1 0x40
+#define LAN92XX_RX_STATUS2 0x44
+#define LAN92XX_TX_STATUS1 0x48
+#define LAN92XX_TX_STATUS2 0x4C
+#define LAN92XX_ID_REV 0x50
+#define LAN92XX_IRQ_CFG 0x54
+#define LAN92XX_INT_STS 0x58
+#define LAN92XX_INT_EN 0x5C
+#define LAN92XX_RESERVED1 0x60
+#define LAN92XX_BYTE_TEST 0x64
+#define LAN92XX_FIFO_INT 0x68
+#define LAN92XX_RX_CFG 0x6C
+#define LAN92XX_TX_CFG 0x70
+#define LAN92XX_HW_CFG 0x74
+#define LAN92XX_RX_DP_CTRL 0x78
+#define LAN92XX_RX_FIFO_INF 0x7C
+#define LAN92XX_TX_FIFO_INF 0x80
+#define LAN92XX_PMT_CTRL 0x84
+#define LAN92XX_GPIO_CFG 0x88
+#define LAN92XX_GPT_CFG 0x8C
+#define LAN92XX_GPT_CNT 0x90
+#define LAN92XX_RESERVED2 0x94
+#define LAN92XX_WORD_SWAP 0x98
+#define LAN92XX_FREE_RUN 0x9C
+#define LAN92XX_RX_DROP 0xA0
+#define LAN92XX_MAC_CMD 0xA4
+#define LAN92XX_MAC_DATA 0xA8
+#define LAN92XX_AFC_CFG 0xAC
+#define LAN92XX_E2P_CMD 0xB0
+#define LAN92XX_E2P_DATA 0xB4
+
+// Access these MAC registers indirectly through MAC_CMD and MAC_DATA
+// registers.
+#define MAC_MAC_CR 1
+#define MAC_ADDRH 2
+#define MAC_ADDRL 3
+#define MAC_HASHH 4
+#define MAC_HASHL 5
+#define MAC_MII_ACC 6
+#define MAC_MII_DATA 7
+#define MAC_FLOW 8
+#define MAC_VLAN1 9
+#define MAC_VLAN2 10
+#define MAC_WUFF 11
+#define MAC_WUCSR 12
+
+// These PHY registers are accessed indirectly through the MAC via the
+// MII interface using the MII_ACC and MII_DATA registers. PHY controls
+// the 802.3 physical layer such as 10/100Mbps, full/half mode.
+#define PHY_BCR 0
+#define PHY_BSR 1
+#define PHY_ID1 2
+#define PHY_ID2 3
+#define PHY_ANAR 4
+#define PHY_ANLPAR 5
+#define PHY_ANER 6
+#define PHY_MCSR 17
+#define PHY_SMR 18
+#define PHY_SCSI 27
+#define PHY_ISR 29
+#define PHY_IMR 30
+#define PHY_SCSR 31
+
+#define PHY_100TX_FD 0x4000
+#define PHY_100TX_HD 0x2000
+#define PHY_10T_RD 0x1000
+#define PHY_10T_HD 0x0800
+#define PHY_LINK_ON 0x0004
+
+#define IS_DUPLEX(x) ((x) & (PHY_100TX_FD | PHY_10T_RD))
+
+#define MAC_TIMEOUT (1000 * 100)
+#define MAC_TICKET 2
+
+#define E2P_CMD_SHIFT 28
+#define E2P_CMD_BUSY 0x80000000
+#define E2P_CMD_TIMEOUT 0x00000200
+#define E2P_CMD_LOADED 0x00000100
+
+enum epc_cmd {
+ E2P_CMD_READ = 0 << E2P_CMD_SHIFT,
+ E2P_CMD_EWDS = 1 << E2P_CMD_SHIFT,
+ E2P_CMD_EWEN = 2 << E2P_CMD_SHIFT,
+ E2P_CMD_WRITE = 3 << E2P_CMD_SHIFT,
+ E2P_CMD_WRAL = 4 << E2P_CMD_SHIFT,
+ E2P_CMD_ERASE = 5 << E2P_CMD_SHIFT,
+ E2P_CMD_ERAL = 6 << E2P_CMD_SHIFT,
+ E2P_CMD_Reload = 7 << E2P_CMD_SHIFT,
+};
+#define E2P_CMD(cmd, addr) (E2P_CMD_BUSY | (cmd) | (addr))
+
+#define E2P_CONTEXT_ID 0xA5
+
+typedef struct
+{
+ unsigned int base;
+ int status;
+ int tx_busy;
+ int tx_key;
+ unsigned char mac_addr[6];
+} smsc_lan92xx_t;
+
+#ifndef LAN92XX_REG_BASE
+#define LAN92XX_REG_BASE PBC_BASE
+#endif
+
+#ifndef LAN92XX_REG_READ
+#define LAN92XX_REG_READ(reg_offset) \
+ (*(volatile unsigned int *)(LAN92XX_REG_BASE + reg_offset))
+#endif
+
+#ifndef LAN92XX_REG_WRITE
+#define LAN92XX_REG_WRITE(reg_offset, val) \
+ (*(volatile unsigned int *)(LAN92XX_REG_BASE + reg_offset) = (val))
+#endif
+
+#endif // CYGONCE_DEVS_ETH_SMSC_MAC_MAC_H
--- /dev/null
+//==========================================================================
+//
+// dev/if_lan92xx.c
+//
+// Ethernet device driver for SMSC LAN92XX compatible controllers
+//
+//==========================================================================
+//==========================================================================
+
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Fred Fan
+// Contributors:
+// Date: 2007-10-16
+// Purpose:
+// Description: Driver for SMSC LAN92xx ethernet controller
+//
+// Note:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+#include <pkgconf/system.h>
+#include <pkgconf/io_eth_drivers.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_diag.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/io/eth/eth_drv.h>
+#include <cyg/io/smsc_lan92xx.h>
+
+
+#ifdef CYGPKG_NET
+#include <pkgconf/net.h>
+#include <cyg/kernel/kapi.h>
+#include <net/if.h> /* Needed for struct ifnet */
+#endif
+
+//#define LAN92XX_DEBUG
+#ifdef LAN92XX_DEBUG
+#define PDEBUG(fmt, args...) diag_printf(fmt, ##args)
+#else
+#define PDEBUG(fmt, args...)
+#endif /*LAN92XX_DEBUG*/
+
+#define __WANT_DEVS
+#include CYGDAT_DEVS_ETH_SMSC_LAN92XX_INL
+#undef __WANT_DEVS
+
+#define LAN_92XX_DRV_VER "1.1"
+
+#define MAX_RX_NUM (CYGNUM_IO_ETH_DRIVERS_NUM_PKT - 1)
+static smsc_lan92xx_id_t smsc_lan92xx_id_table[] =
+{
+ {0x117A, 0x0000, "SMSC LAN9217"},
+ {0x9220, 0x0000, "SMSC LAN9220"},
+ {0},
+};
+
+static int lan92xx_eeprom_present = 1;
+
+static smsc_lan92xx_t lan92xx_dev;
+static inline void
+lan92xx_set_mac_addr(struct eth_drv_sc *sc, unsigned char *enaddr);
+static void lan92xx_soft_reset(struct eth_drv_sc *sc);
+static inline unsigned int
+lan92xx_mac_read(struct eth_drv_sc *sc, unsigned char reg);
+static inline void
+lan92xx_mac_write(struct eth_drv_sc *sc, unsigned char reg, unsigned long val);
+static inline unsigned int
+lan92xx_mii_read(struct eth_drv_sc *sc, unsigned char addr);
+static inline void
+lan92xx_mii_write(struct eth_drv_sc *sc, unsigned char addr, unsigned int val);
+
+/*!
+ * This function set the value of PHY registers by MII interface
+ */
+static void
+lan92xx_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
+{
+ unsigned int val;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ lan92xx_set_mac_addr(sc, enaddr);
+
+ pdev->tx_busy = 0;
+
+ val = lan92xx_mac_read(sc, MAC_MAC_CR)& (~0x800);
+ val |= 0x0010080C;
+ lan92xx_mac_write(sc, MAC_MAC_CR, val);
+ val = lan92xx_mac_read(sc, MAC_MAC_CR);
+}
+
+/*!
+ * This function pauses the FEC controller.
+ */
+static void
+lan92xx_stop(struct eth_drv_sc *sc)
+{
+ unsigned int val;
+
+ val = lan92xx_mac_read(sc, MAC_MAC_CR);
+ val &= ~(0x0000000C);
+ lan92xx_mac_write(sc, MAC_MAC_CR, val);
+}
+
+static int
+lan92xx_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length)
+{
+ /*TODO:: Add support */
+ PDEBUG("%s: key=0x%x, data=0x%x, data_len=0x%x\n",
+ __FUNCTION__, key, (unsigned long)data, (unsigned long)data_length);
+ return 0;
+}
+
+/*!
+ * This function checks the status of FEC control.
+ */
+static int
+lan92xx_can_send(struct eth_drv_sc *sc)
+{
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ if (!(pdev->status & PHY_LINK_ON)) return 0;
+ if (pdev->tx_busy) return 0;
+
+ return 1;
+}
+
+/*!
+ * This function transmits a frame.
+ */
+static void
+lan92xx_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total, unsigned long key)
+{
+ int i, j, len, freespace;
+ unsigned int tx_cmd1, tx_cmd2, data, *pdata;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+ freespace = LAN92XX_REG_READ(LAN92XX_TX_FIFO_INF) & 0xFFFF;
+
+ if (freespace < total + 16 ) {
+ sc->funs->eth_drv->tx_done(sc, key, -1);
+ return;
+ }
+ for (i = 0; i < sg_len; i++) {
+ len = (sg_list[i].len + 3) >> 2;
+ if (i == (sg_len - 1))
+ tx_cmd1 = 0x1000;
+ else if (i)
+ tx_cmd1 = 0x0000;
+ else
+ tx_cmd1 = 0x2000;
+
+ tx_cmd1 |= sg_list[i].len;
+ tx_cmd2 = (total << 16) + total;
+ LAN92XX_REG_WRITE(LAN92XX_TX_DATA, tx_cmd1);
+
+ LAN92XX_REG_WRITE(LAN92XX_TX_DATA, tx_cmd2);
+ pdata = (unsigned int *)sg_list[i].buf;
+
+ for (j=0; j<len; j++) {
+ data = *(pdata++);
+ LAN92XX_REG_WRITE(LAN92XX_TX_DATA, data);
+ for (data=0; data<2; data++) {
+ asm volatile("nop");
+ asm volatile("nop");
+ asm volatile("nop");
+ asm volatile("nop");
+ }
+ }
+ }
+ pdev->tx_busy = 1;
+ pdev->tx_key = key;
+}
+
+static void
+lan92xx_drop_packet(struct eth_drv_sc *sc, int count)
+{
+ unsigned int data;
+ if (count >= 4) {
+ LAN92XX_REG_WRITE(LAN92XX_RX_DP_CTRL, 0x80000000);
+ while (LAN92XX_REG_READ(LAN92XX_RX_DP_CTRL) & 0x80000000) {
+ }
+ } else {
+ while (count--)
+ data = LAN92XX_REG_READ(LAN92XX_RX_DATA);
+ }
+}
+
+/*!
+ * This function receives ready Frame in DB.
+ */
+static void
+lan92xx_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
+{
+ unsigned int i, rlen;
+ unsigned int *pdata = (unsigned int *)(sg_list->buf);
+
+ rlen = (sg_list->len + 3) >> 2;
+ if ((void *)(sg_list->buf) == NULL) {
+ goto Drop;
+ }
+
+ for (i = 0; i < rlen; i++) {
+ *(pdata++) = LAN92XX_REG_READ(LAN92XX_RX_DATA);
+ }
+ return;
+Drop:
+ lan92xx_drop_packet(sc, rlen);
+}
+
+static void
+lan92xx_deliver(struct eth_drv_sc *sc)
+{
+ /*TODO::When redboot support thread ,
+ * the polling function will be called at here
+ */
+ return;
+}
+
+static void
+lan92xx_link_status(struct eth_drv_sc *sc)
+{
+ unsigned int val;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+ val = lan92xx_mii_read(sc, PHY_ISR);
+ if (val&0x50) {
+ val = lan92xx_mii_read(sc, PHY_BSR);
+ if (val != pdev->status) {
+ pdev->status = val;
+ val = lan92xx_mac_read(sc, MAC_MAC_CR) & (~0x802F0800);
+ if ( IS_DUPLEX(pdev->status)) {
+ val |= 0x00100000;
+ }
+ lan92xx_mac_write(sc, MAC_MAC_CR, val);
+ }
+ }
+}
+/*!
+ * This function checks the event of FEC controller
+ */
+static void
+lan92xx_poll(struct eth_drv_sc *sc)
+{
+ unsigned int val, reg;
+ int rx_num = 0;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ reg = LAN92XX_REG_READ(LAN92XX_INT_STS);
+ LAN92XX_REG_WRITE(LAN92XX_INT_STS, reg);
+
+ //diag_printf("INT_STS: %x\n", reg);
+ if (reg & 0x40000) {
+ lan92xx_link_status(sc);
+ }
+
+ if (reg & 0xE000) {
+ diag_printf("%s:: TX or RX error [0x%x]\n", __FUNCTION__, reg);
+ lan92xx_soft_reset(sc);
+ return;
+ }
+
+ while (1) {
+ reg = LAN92XX_REG_READ(LAN92XX_RX_FIFO_INF);
+ if (!(reg & 0xFF0000))
+ break;
+ reg = LAN92XX_REG_READ(LAN92XX_RX_STATUS1);
+
+ if (reg & 0x4000909A) {
+ val = (reg >> 16) & 0x3FFF;
+ val = (val + 3) >> 2;
+ lan92xx_drop_packet(sc, val);
+ } else {
+ val = (reg >> 16) & 0x3FFF;
+ sc->funs->eth_drv->recv(sc, val);
+ rx_num++;
+ }
+
+ if ( rx_num >= MAX_RX_NUM) break;
+ }
+
+ while (1) {
+ reg = LAN92XX_REG_READ(LAN92XX_TX_FIFO_INF);
+ if (!(reg & 0xFF0000)) break;
+
+ if (!LAN92XX_REG_READ(LAN92XX_TX_STATUS2)) {
+ diag_printf("***FIFO %x, wrong status =%x: int_sts=%x\n",
+ reg, LAN92XX_REG_READ(LAN92XX_TX_STATUS2),
+ LAN92XX_REG_READ(LAN92XX_INT_STS));
+ continue;
+ }
+ reg = LAN92XX_REG_READ(LAN92XX_TX_STATUS1);
+ if (reg & 0x8000) {
+ sc->funs->eth_drv->tx_done(sc, pdev->tx_key, -1);
+ } else {
+ sc->funs->eth_drv->tx_done(sc, pdev->tx_key, 0);
+ }
+ pdev->tx_busy = 0;
+ }
+}
+
+static int
+lan92xx_int_vector(struct eth_drv_sc *sc)
+{
+ PDEBUG("%s::\n", __FUNCTION__);
+
+ /*TODO::
+ * get FEC interrupt number
+ */
+ return -1;
+}
+
+static smsc_lan92xx_id_t *lan92xx_probe(unsigned long id)
+{
+ smsc_lan92xx_id_t *p = smsc_lan92xx_id_table;
+ while (p->id) {
+ if (id == p->id)
+ return p;
+ p++;
+ }
+ return NULL;
+}
+
+static inline unsigned int
+lan92xx_mac_read(struct eth_drv_sc *sc, unsigned char reg)
+{
+ unsigned int cmd;
+
+ if (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000) {
+ diag_printf("Error: %d. MAC is busy\n", __LINE__);
+ return 0xFFFFFFFF;
+ }
+
+ cmd = 0xC0000000 | (reg & 0xFF);
+ LAN92XX_REG_WRITE(LAN92XX_MAC_CMD, cmd);
+
+ /* Workaround for hardware read-after-write */
+ LAN92XX_REG_READ(LAN92XX_BYTE_TEST);
+
+ while (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000);
+
+ return LAN92XX_REG_READ(LAN92XX_MAC_DATA);
+}
+
+static inline void
+lan92xx_mac_write(struct eth_drv_sc *sc, unsigned char reg, unsigned long val)
+{
+ unsigned int cmd;
+
+ if (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000) {
+ diag_printf("Error: %d. MAC is busy\n", __LINE__);
+ return;
+ }
+
+ LAN92XX_REG_WRITE(LAN92XX_MAC_DATA, val);
+ cmd = 0x80000000 | (reg & 0xFF);
+ LAN92XX_REG_WRITE(LAN92XX_MAC_CMD, cmd);
+
+ /* Workaround for hardware read-after-write */
+ LAN92XX_REG_READ(LAN92XX_BYTE_TEST);
+
+ while (LAN92XX_REG_READ(LAN92XX_MAC_CMD) & 0x80000000);
+}
+
+static inline void
+lan92xx_set_mac_addr(struct eth_drv_sc *sc, unsigned char *enaddr)
+{
+ unsigned int val;
+ val = enaddr[3];
+ val = (val << 8) | enaddr[2];
+ val = (val << 8) | enaddr[1];
+ val = (val << 8) | enaddr[0];
+ lan92xx_mac_write(sc, MAC_ADDRL, val);
+
+ val = lan92xx_mac_read(sc, MAC_ADDRH) >> 16;
+ val = (val << 8) | enaddr[5];
+ val = (val << 8) | enaddr[4];
+ lan92xx_mac_write(sc, MAC_ADDRH, val);
+}
+
+static inline unsigned int
+lan92xx_mii_read(struct eth_drv_sc *sc, unsigned char addr)
+{
+ unsigned int cmd;
+
+ cmd = (0x1 << 11 ) | (addr << 6) | 1;
+ lan92xx_mac_write(sc, MAC_MII_ACC, cmd);
+ while (lan92xx_mac_read(sc, MAC_MII_ACC) & 1);
+
+ return lan92xx_mac_read(sc, MAC_MII_DATA)&0xFFFF;
+}
+
+static inline void
+lan92xx_mii_write(struct eth_drv_sc *sc, unsigned char addr, unsigned int val)
+{
+ unsigned int cmd;
+
+ cmd = (0x1 << 11 ) | (addr << 6) | 3;
+ lan92xx_mac_write(sc, MAC_MII_DATA, val);
+ lan92xx_mac_read(sc, MAC_MII_DATA);
+ lan92xx_mac_write(sc, MAC_MII_ACC, cmd);
+
+ while (lan92xx_mac_read(sc, MAC_MII_ACC) & 1);
+}
+
+static int lan92xx_phy_init(struct eth_drv_sc *sc)
+{
+ int val;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ lan92xx_mii_write(sc, PHY_BCR, 0x8000);
+
+ while (lan92xx_mii_read(sc, PHY_BCR) & 0x8000);
+
+ for (val = 0; val < 2500; val++)
+ hal_delay_us(4);
+
+ val = lan92xx_mii_read(sc, PHY_ANAR);
+ val |= 0x01E1;
+ lan92xx_mii_write(sc, PHY_ANAR, val);
+ lan92xx_mii_write(sc, PHY_SMR, 0x00E1);
+ lan92xx_mii_write(sc, PHY_SCSI, 0x400B);
+ lan92xx_mii_write(sc, PHY_IMR, 0x00F0);
+ lan92xx_mii_write(sc, PHY_BCR, 0x1200);
+
+ while ((lan92xx_mii_read(sc, PHY_BCR) & 0x200));
+
+ pdev->status = lan92xx_mii_read(sc, PHY_BSR);
+
+ return 0;
+}
+
+static int lan92xx_mac_init(struct eth_drv_sc *sc)
+{
+ static int mac_init = 0;
+ unsigned int val;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ val = lan92xx_mac_read(sc, MAC_MAC_CR) & (~0x802F0800);
+ if (IS_DUPLEX(pdev->status)) {
+ val |= 0x00100000;
+ }
+ lan92xx_mac_write(sc, MAC_MAC_CR, val);
+
+ lan92xx_mac_write(sc, MAC_HASHH, 0);
+ lan92xx_mac_write(sc, MAC_HASHL, 0);
+
+ if (mac_init)
+ return 0;
+
+ mac_init = 1;
+
+#if CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+ if (!_board_provide_eth0_esa(pdev->mac_addr))
+#endif
+ {
+ // make sure EPC not busy
+ while ((val = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
+
+ if (val & E2P_CMD_TIMEOUT) {
+ lan92xx_eeprom_present = 0;
+ diag_printf("LAN9217: NO EEPROM\n");
+ return -1;
+ }
+
+ if (!(LAN92XX_REG_READ(LAN92XX_E2P_CMD) & E2P_CMD_LOADED)) {
+ diag_printf("LAN9217:EEPROM is empty\n");
+ }
+ val = lan92xx_mac_read(sc, MAC_ADDRH);
+ pdev->mac_addr[5] = (val >> 8) & 0xFF;
+ pdev->mac_addr[4] = val&0xFF;
+ val = lan92xx_mac_read(sc, MAC_ADDRL);
+ pdev->mac_addr[3] = (val >> 24) & 0xFF;
+ pdev->mac_addr[2] = (val >> 16) & 0xFF;
+ pdev->mac_addr[1] = (val >> 8) & 0xFF;
+ pdev->mac_addr[0] = val & 0xFF;
+ }
+ return 0;
+}
+
+/*
+ * This function reset LAN9219 .
+ */
+static void
+lan92xx_soft_reset(struct eth_drv_sc *sc)
+{
+ unsigned int timeout = MAC_TIMEOUT;
+
+ LAN92XX_REG_WRITE(LAN92XX_HW_CFG, 1);
+ while ((LAN92XX_REG_READ(LAN92XX_HW_CFG) & 1) && (--timeout)) {
+ hal_delay_us(MAC_TICKET);
+ }
+
+ if (!timeout) {
+ diag_printf("LAN92XX: Reset fail \n");
+ return ;
+ }
+
+ LAN92XX_REG_WRITE(LAN92XX_INT_EN, 0);
+ LAN92XX_REG_WRITE(LAN92XX_HW_CFG, 0x150000);
+ LAN92XX_REG_WRITE(LAN92XX_AFC_CFG, 0x6E3740);
+ LAN92XX_REG_WRITE(LAN92XX_TX_CFG, 0x2);
+
+ timeout = MAC_TIMEOUT;
+
+ while ((LAN92XX_REG_READ(LAN92XX_E2P_CMD) & 0x80000000) && (--timeout)) {
+ hal_delay_us(MAC_TICKET);
+ }
+
+ LAN92XX_REG_WRITE(LAN92XX_GPIO_CFG, 0x70070000);
+ LAN92XX_REG_WRITE(LAN92XX_INT_STS, 0xFFFFFFFF);
+ lan92xx_mac_init(sc);
+}
+
+/*!
+ * This function initializes the LAN92xx driver.
+ * It is called by net_init in net module of RedBoot during RedBoot init
+ */
+static bool
+lan92xx_init(struct cyg_netdevtab_entry *tab)
+{
+ unsigned int reg, timeout;
+ smsc_lan92xx_id_t *id;
+ struct eth_drv_sc *sc = tab ? tab->device_instance : NULL;
+ smsc_lan92xx_t *pdev = (smsc_lan92xx_t *)(sc->driver_private);
+
+ diag_printf("\nLAN92xx Driver version %s\n", LAN_92XX_DRV_VER);
+ if (!pdev) {
+ diag_printf("LAN92xx:: Driver don't attach with device\n");
+ return false;
+ }
+ reg = LAN92XX_REG_READ(LAN92XX_ID_REV);
+ id = lan92xx_probe(reg >> 16);
+ if (id) {
+ diag_printf("%s: ID = 0x%x REV = 0x%x\n", id->id_name, id->id, id->ver);
+ } else {
+ diag_printf("LAN92XX: unknow chip ID = %x\n", reg);
+ return false;
+ }
+
+ timeout = MAC_TIMEOUT;
+ while ((!(LAN92XX_REG_READ(LAN92XX_PMT_CTRL) & 1)) && (--timeout)) {
+ hal_delay_us(MAC_TICKET);
+ }
+ if (timeout == 0) {
+ diag_printf("LAN92XX: is not ready to access\n");
+ return false;
+ }
+
+ lan92xx_phy_init(sc);
+
+ lan92xx_soft_reset(sc);
+ (sc->funs->eth_drv->init)(sc, pdev->mac_addr);
+ return true;
+}
+
+/*!
+ * Global variable which defines the LAN92xx driver,
+ */
+ETH_DRV_SC(lan92xx_sc,
+ &lan92xx_dev, // Driver specific data
+ CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME,
+ lan92xx_start,
+ lan92xx_stop,
+ lan92xx_control,
+ lan92xx_can_send,
+ lan92xx_send,
+ lan92xx_recv,
+ lan92xx_deliver, // "pseudoDSR" called from fast net thread
+ lan92xx_poll, // poll function, encapsulates ISR and DSR
+ lan92xx_int_vector);
+
+/*!
+ * Global variable which defines the FEC device
+ */
+NETDEVTAB_ENTRY(lan92xx_netdev,
+ "lan92xx_" CYGDAT_DEVS_ETH_ARM_MXCBOARD_ETH0_NAME,
+ lan92xx_init,
+ &lan92xx_sc);
+
+// Low level function to issue a command to the eeprom controller.
+// return 0 on success and -1 on failure
+static inline int
+_lan92xx_e2p_do_cmd(unsigned int cmd)
+{
+ unsigned int v;
+ LAN92XX_REG_WRITE(LAN92XX_E2P_CMD, cmd);
+ while ((v = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
+ if (v & E2P_CMD_TIMEOUT) {
+ diag_printf("%s:: EEPROM timeout\n", __FUNCTION__);
+ // clear the timeout status bit
+ LAN92XX_REG_WRITE(LAN92XX_E2P_CMD, E2P_CMD_TIMEOUT);
+ while ((v = LAN92XX_REG_READ(LAN92XX_E2P_CMD)) & E2P_CMD_BUSY);
+ return -1;
+ }
+ return 0;
+}
+
+// for all the 7 EEPROM operations
+// return 0 on success and -1 on failure
+static int
+lan92xx_e2p_op(enum epc_cmd cmd, unsigned char addr, unsigned char *data)
+{
+ switch (cmd) {
+ case E2P_CMD_READ:
+ if (_lan92xx_e2p_do_cmd(E2P_CMD(cmd, addr)) != 0)
+ return -1;
+ *data = (unsigned char)LAN92XX_REG_READ(LAN92XX_E2P_DATA);
+ return 0;
+ break;
+ case E2P_CMD_WRAL:
+ case E2P_CMD_WRITE:
+ LAN92XX_REG_WRITE(LAN92XX_E2P_DATA, *data);
+ break;
+ default:
+ break;
+ }
+
+ if (_lan92xx_e2p_do_cmd(E2P_CMD(cmd, addr)) != 0)
+ return -1;
+
+ return 0;
+}
+
+static void setMac(int argc, char *argv[])
+{
+ int i;
+ unsigned char data[7];
+ unsigned long temp;
+
+ if (!lan92xx_eeprom_present) {
+ diag_printf("NO EEPROM present\n\n");
+ return;
+ }
+
+ if (argc == 1) {
+ for (i = 0; i < 7 ; i++) {
+ if (lan92xx_e2p_op(E2P_CMD_READ, i, &data[i]) != 0) {
+ diag_printf("read MAC %d address fail\n\n", i);
+ return;
+ }
+ }
+
+ if (data[0] != E2P_CONTEXT_ID) {
+ diag_printf("Warning: Unprogrammed MAC address: 0x%x\n", data[0]);
+ return;
+ }
+
+ diag_printf("MAC address: ");
+ diag_printf("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n\n",
+ data[1], data[2], data[3],
+ data[4], data[5], data[6]);
+ return;
+ }
+
+ if (argc != 2) {
+ diag_printf("Error: Wrong argument\n");
+ return;
+ }
+
+ data[0] = E2P_CONTEXT_ID;
+ for (i = 1; i < 7; i++) {
+ if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
+ diag_printf("Error: failed to parse command: %d\n", __LINE__);
+ return;
+ }
+ if (temp > 0xFF) {
+ diag_printf("Error: invalid valie: 0x%x\n", (unsigned int)temp);
+ return;
+ }
+ data[i] = temp;
+ }
+
+ // enable erase/write
+ if (lan92xx_e2p_op(E2P_CMD_EWEN, 0, data) != 0) {
+ diag_printf("%s:: Enable write/erase fail\n", __FUNCTION__);
+ return;
+ }
+ for (i = 0; i < 7; i++) {
+ if (lan92xx_e2p_op(E2P_CMD_ERASE, i, &data[i]) != 0 ||
+ lan92xx_e2p_op(E2P_CMD_WRITE, i, &data[i]) != 0) {
+ diag_printf("Error: failed to program eeprom at %d\n", i);
+ return;
+ }
+ }
+
+ // disable erase/write
+ if (lan92xx_e2p_op(E2P_CMD_EWDS, 0, data) != 0) {
+ diag_printf("%s:: Enable write/erase fail\n", __FUNCTION__);
+ }
+}
+
+RedBoot_cmd("setmac",
+ "Set Ethernet MAC address in EEPROM",
+ "[0x##:0x##:0x##:0x##:0x##:0x##]",
+ setMac
+ );
--- /dev/null
+# ====================================================================
+#
+# flash_board_spansion.cdl
+#
+# FLASH memory - Hardware support
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): gthomas
+# Original data: gthomas
+# Contributors:
+# Date: 2000-07-26
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_FLASH_IMX_3STACK_SPANSION {
+ display "Freescale Spansion FLASH memory support"
+
+ parent CYGPKG_IO_FLASH
+ active_if CYGPKG_IO_FLASH
+
+ implements CYGHWR_IO_FLASH_DEVICE
+
+ compile board_spansionflash.c
+
+ # Arguably this should do in the generic package
+ # but then there is a logic loop so you can never enable it.
+ cdl_interface CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED {
+ display "Generic AMD FlashFile driver required"
+ }
+
+ implements CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED
+
+ requires CYGHWR_DEVS_FLASH_AMD_S29GL512N
+}
--- /dev/null
+//==========================================================================
+//
+// board_spansionflash.c
+//
+// Flash programming for AMD Flash devices
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Patrick Doyle <wpd@delcomsys.com>
+// Contributors: Patrick Doyle <wpd@delcomsys.com>
+// Date: 2002-11-26
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/hal/hal_soc.h>
+
+//--------------------------------------------------------------------------
+// Device properties
+
+// We use the one SPANSION S29WS256N part on the EVB.
+#define CYGNUM_FLASH_INTERLEAVE (1)
+#define CYGNUM_FLASH_SERIES (1)
+#define CYGNUM_FLASH_WIDTH (16)
+#define CYGNUM_FLASH_BASE (CS0_BASE_ADDR)
+
+#define CYGNUM_FLASH_TIMEOUT_QUERY 5000000
+#define CYGNUM_FLASH_TIMEOUT_ERASE_TIMER 100000000
+#define CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE 100000000
+#define CYGNUM_FLASH_TIMEOUT_PROGRAM 100000000
+//--------------------------------------------------------------------------
+// Platform specific extras
+
+//--------------------------------------------------------------------------
+// Now include the driver code.
+#include "cyg/io/flash_am29xxxxx.inl"
--- /dev/null
+# ====================================================================
+#
+# flash_board_spansion.cdl
+#
+# FLASH memory - Hardware support
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): gthomas
+# Original data: gthomas
+# Contributors:
+# Date: 2000-07-26
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_FLASH_MX35EVB_SPANSION {
+ display "Freescale Spansion FLASH memory support"
+
+ parent CYGPKG_IO_FLASH
+ active_if CYGPKG_IO_FLASH
+
+ implements CYGHWR_IO_FLASH_DEVICE
+
+ compile board_spansionflash.c
+
+ # Arguably this should do in the generic package
+ # but then there is a logic loop so you can never enable it.
+ cdl_interface CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED {
+ display "Generic AMD FlashFile driver required"
+ }
+
+ implements CYGINT_DEVS_FLASH_AMD_AM29XXXXX_REQUIRED
+
+ requires CYGHWR_DEVS_FLASH_S29WS256N
+}
--- /dev/null
+# ====================================================================
+#
+# flash_board_strata.cdl
+#
+# FLASH memory - Hardware support
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): gthomas
+# Original data: gthomas
+# Contributors:
+# Date: 2000-07-26
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_FLASH_MX35EVB_STRATA {
+ display "Freescale FLASH memory support"
+
+ parent CYGPKG_IO_FLASH
+ active_if CYGPKG_IO_FLASH
+
+ requires CYGPKG_DEVS_FLASH_STRATA
+ requires CYGNUM_DEVS_FLASH_STRATA_MAX_BLOCKS == 256
+
+ implements CYGHWR_IO_FLASH_BLOCK_LOCKING
+
+ include_dir cyg/io
+
+ # Arguably this should do in the generic package
+ # but then there is a logic loop so you can never enable it.
+ cdl_interface CYGINT_DEVS_FLASH_STRATA_REQUIRED {
+ display "Generic StrataFLASH driver required"
+ }
+
+ implements CYGINT_DEVS_FLASH_STRATA_REQUIRED
+
+ define_proc {
+ puts $::cdl_system_header "/***** strataflash driver proc output start *****/"
+ puts $::cdl_system_header "#define CYGDAT_DEVS_FLASH_STRATA_INL <cyg/io/board_strataflash.inl>"
+ puts $::cdl_system_header "#define CYGDAT_DEVS_FLASH_STRATA_CFG <pkgconf/devs_flash_board_strata.h>"
+ puts $::cdl_system_header "/***** strataflash driver proc output end *****/"
+ }
+}
+
--- /dev/null
+#ifndef CYGONCE_DEVS_FLASH_BOARD_STRATAFLASH_INL
+#define CYGONCE_DEVS_FLASH_BOARD_STRATAFLASH_INL
+//==========================================================================
+//
+// board_strataflash.inl
+//
+// Flash programming - device constants, etc.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas, hmt
+// Contributors: gthomas
+// Date: 2001-02-24
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// The system has one 16-bit devices.
+// a StrataFlash 28F256L18. The 256 means 256Mbit, so 32Mbyte with 16bit width.
+
+#define CYGNUM_FLASH_DEVICES (1)
+#define CYGNUM_FLASH_BASE (0xA0000000u)
+#define CYGNUM_FLASH_BASE_MASK (0xFE000000u) // 32MB devices (size=0x02000000 -> mask=0xFE000000)
+#define CYGNUM_FLASH_WIDTH (16)
+#define CYGNUM_FLASH_BLANK (1)
+
+#endif // CYGONCE_DEVS_FLASH_BOARD_STRATAFLASH_INL
\ No newline at end of file
--- /dev/null
+//==========================================================================
+//
+// board_spansionflash.c
+//
+// Flash programming for AMD Flash devices
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Patrick Doyle <wpd@delcomsys.com>
+// Contributors: Patrick Doyle <wpd@delcomsys.com>
+// Date: 2002-11-26
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/hal/hal_soc.h>
+
+//--------------------------------------------------------------------------
+// Device properties
+
+// We use the one SPANSION S29WS256N part on the EVB.
+#define CYGNUM_FLASH_INTERLEAVE (1)
+#define CYGNUM_FLASH_SERIES (1)
+#define CYGNUM_FLASH_WIDTH (16)
+#define CYGNUM_FLASH_BASE (CS0_BASE_ADDR)
+
+#define CYGNUM_FLASH_TIMEOUT_QUERY 5000000
+#define CYGNUM_FLASH_TIMEOUT_ERASE_TIMER 100000000
+#define CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE 100000000
+#define CYGNUM_FLASH_TIMEOUT_PROGRAM 100000000
+//--------------------------------------------------------------------------
+// Platform specific extras
+
+//--------------------------------------------------------------------------
+// Now include the driver code.
+#include "cyg/io/flash_am29xxxxx.inl"
--- /dev/null
+#ifndef CARD_MX32_H
+#define CARD_MX32_H
+
+#include <cyg/infra/cyg_type.h>
+
+/*sdhc memory map*/
+typedef struct _sdhc
+{
+ cyg_uint32 sdhc_clk;
+ cyg_uint32 sdhc_status;
+ cyg_uint32 sdhc_clk_rate;
+ cyg_uint32 sdhc_dat_cont;
+ cyg_uint32 sdhc_response_to;
+ cyg_uint32 sdhc_read_to;
+ cyg_uint32 sdhc_blk_len;
+ cyg_uint32 sdhc_nob;
+ cyg_uint32 sdhc_rev_no;
+ cyg_uint32 sdhc_int_cntr;
+ cyg_uint32 sdhc_cmd;
+ cyg_uint32 sdhc_arg;
+ cyg_uint32 sdhc_reserved;
+ cyg_uint32 sdhc_res_fifo;
+ cyg_uint32 sdhc_buffer_access;
+}sdhc_t, *psdhc_t;
+
+/* Defines for card types */
+typedef enum
+{
+ TYPE_NONE,
+ SD_CSD_1_0,
+ SD_CSD_2_0,
+ MMC_CSD_1_0,
+ MMC_CSD_1_1,
+ MMC_CSD_1_2,
+ MMC_UNKNOWN
+}card_type;
+
+typedef struct _card_specific_data
+{
+ cyg_uint32 csd0;
+ cyg_uint32 csd1;
+ cyg_uint32 csd2;
+ cyg_uint32 csd3;
+}CARD_SPECIFIC_DATA;
+
+/* Defines for card types */
+typedef struct _card_id
+{
+ cyg_uint32 cid0;
+ cyg_uint32 cid1;
+ cyg_uint32 cid2;
+ cyg_uint32 cid3;
+}CARD_ID;
+
+enum sdhc_clk_val
+{
+ SDHC_CLK_START = 0x2,
+ SDHC_CLK_STOP = 0x1,
+ SDHC_CLK_RESET = 0x8
+};
+
+typedef enum frequency_mode
+{
+ iden_mode = 0x1,
+ trans_mode = 0x2
+} frequency_mode_t;
+
+typedef struct command
+{
+ cyg_uint32 index;
+ cyg_uint32 data_control;
+ cyg_uint32 arg;
+}command_t;
+
+
+#define NO_ARG 0
+#define ENABLE 1
+#define DISABLE 0
+#define PASS 0
+#define SUCCESS 0
+#define FAIL 1
+
+#define CARD_STATE 0x1E00
+#define CARD_STATE_SHIFT 9
+
+/*Defines of CSD data*/
+#define CSD_STRUCT_MSK 0x00C00000
+#define CSD_STRUCT_SHIFT 22
+
+
+/* Define the states of the card*/
+enum states
+{
+ IDLE,
+ READY,
+ IDENT,
+ STBY,
+ TRAN,
+ DATA,
+ RCV,
+ PRG,
+ DIS
+};
+
+
+/* SDHC Response */
+typedef struct _response
+{
+ cyg_uint32 rsp0;
+ cyg_uint32 rsp1;
+ cyg_uint32 rsp2;
+ cyg_uint32 rsp3;
+}response_t;
+
+
+typedef enum card_mode
+{
+ NONE = 0,
+ SD = 1,
+ MMC = 2
+}card_mode_t;
+
+enum RW
+{
+ READ = 0,
+ WRITE = 1
+};
+
+enum cmd_response
+{
+ RESPONSE_NO = 0x0,
+ RESPONSE_48_CRC = 0x1,
+ RESPONSE_136 = 0x2,
+ RESPONSE_48_WITHOUT_CRC = 0x3
+};
+
+enum status_bus_width
+{
+ ONE = 0x0,
+ FOUR = 0x2
+};
+
+
+#define SDHC_INT 0xc015
+
+#define OCR_VALUE 0x80ff8000
+#define OCR_VALUE_MASK 0x00ff8000
+#define CARD_BUSY 0x80000000
+#define SD_R1_APP_CMD_MSK 0x20
+
+#define BLOCK_LEN 0x200
+
+
+
+/* Status regsiter Masks */
+#define SDHC_STATUS_END_CMD_RESP_MSK 0x2000
+#define SDHC_STATUS_WRITE_OP_DONE_MSK 0x1000
+#define SDHC_STATUS_READ_OP_DONE_MSK 0x800
+#define SDHC_STATUS_WR_CRC_ERR_CODE_MSK 0x600
+#define SDHC_STATUS_CARD_BUS_CLK_RUN_MSK 0x100
+#define SDHC_STATUS_RESP_CRC_ERR_MSK 0x20
+#define SDHC_STATUS_BUF_READ_RDY_MSK 0x80
+#define SDHC_STATUS_BUF_WRITE_RDY_MSK 0x40
+#define SDHC_STATUS_READ_CRC_ERR_MSK 0x8
+#define SDHC_STATUS_WRITE_CRC_ERR_MSK 0x4
+#define SDHC_STATUS_TIME_OUT_RESP_MSK 0x2
+#define SDHC_STATUS_TIME_OUT_READ 0x1
+
+#define SDHC_STATUS_CLEAR ((cyg_uint32)(0xC0007E2F))
+
+
+
+/* Command (data control) masks */
+#define SDHC_CMD_FROMAT_OF_RESP 0x00000007
+#define SDHC_CMD_DATA_ENABLE 0x00000008
+#define SDHC_CMD_WRITE_READ 0x00000010
+#define SDHC_CMD_INIT 0x00000080
+#define SDHC_CMD_BUS_WIDTH 0x00000300
+#define SDHC_CMD_START_READWAIT 0x00000400
+#define SDHC_CMD_STOP_READWAIT 0x00000800
+#define SDHC_CMD_DATA_CTRL_CMD_RESP_LONG_OFF 0x00001000
+
+/* Command (data control) shift */
+#define SDHC_CMD_FROMAT_OF_RESP_SHIFT 0x0
+#define SDHC_CMD_DATA_ENABLE_SHIFT 0x3
+#define SDHC_CMD_BUS_WIDTH_SHIFT 0x8
+#define SDHC_CMD_WRITE_READ_SHIFT 0x4
+#define SDHC_CMD_INIT_SHIFT 0x7
+
+//#define SDHC_CMD_FROMAT_OF_RESP_NONE 0x0
+//#define SDHC_CMD_DATA_CTRL_FROMAT_OF_RESP_48 0x1
+//#define SDHC_CMD_DATA_CTRL_FROMAT_OF_RESP_136 0x2
+//#define SDHC_CMD_DATA_CTRL_FROMAT_OF_RESP_48_N0_CRC 0x3
+//#define SDHC_CMD_DATA_CTRL_BUS_WIDTH_1_BIT 0x0
+//#define SDHC_CMD_DATA_CTRL_BUS_WIDTH_4_BIT 0x2
+
+/* Define each command */
+enum commands
+{
+ CMD0= 0,
+ CMD1= 1,
+ CMD2= 2,
+ CMD3= 3,
+ CMD5= 5,
+ CMD6=6,
+ ACMD6= 6,
+ CMD7= 7,
+ CMD8 = 8,
+ CMD9=9,
+ CMD12 = 12,
+ CMD13 = 13,
+ CMD16 = 16,
+ CMD17 = 17,
+ CMD18 = 18,
+ CMD24 = 24,
+ CMD25 = 25,
+ CMD26 = 26,
+ CMD32 = 32,
+ CMD33 = 33,
+ CMD35 = 35,
+ CMD36 = 36,
+ CMD38 = 38,
+ ACMD41 = 41,
+ ACMD51 = 51,
+ CMD55 = 55
+};
+
+extern cyg_uint32 CCC; /* Card Command Class */
+
+extern cyg_uint32 mxcmci_init (cyg_uint32 bus_width, cyg_uint32 base_address);
+extern cyg_uint32 mmc_data_write (cyg_uint32 *src_ptr,cyg_uint32 length,cyg_uint32 offset);
+extern cyg_uint32 mmc_data_erase (cyg_uint32 offset, cyg_uint32 size);
+extern cyg_uint32 mmc_data_read (cyg_uint32 *,cyg_uint32 ,cyg_uint32);
+extern cyg_uint32 card_flash_query(void* data);
+extern cyg_uint32 card_get_capacity_size (void);
+
+struct csd_v1_0 {
+ cyg_uint32 rsv3:1,
+ crc:7,
+ rsv2:2,
+ file_format:2,
+ tmp_write_protect:1,
+ perm_write_protect:1,
+ copy:1,
+ file_format_grp:1,
+ rsv1:5,
+ write_bl_partial:1,
+ write_bl_len:4,
+ r2w_factor:3,
+ rsv0:2,
+ wp_grp_enable:1;
+ cyg_uint32 wp_grp_size:7,
+ sector_size:7,
+ erase_blk_en:1,
+ c_size_mult:3,
+ vdd_w_curr_max:3,
+ vdd_w_curr_min:3,
+ vdd_r_curr_max:3,
+ vdd_r_curr_min:3,
+ c_size_lo:2;
+ cyg_uint32 c_size_up:10,
+ rsv4:2,
+ dsr_imp:1,
+ read_blk_misalign:1,
+ write_blk_misalign:1,
+ read_bl_partial:1,
+ read_bl_len:4,
+ ccc:12;
+ cyg_uint32 tran_speed:8,
+ nsac:8,
+ taac:8,
+ rsv5:6,
+ csd_structure:2;
+} __attribute__ ((packed));
+
+struct csd_v2_0 {
+ cyg_uint32
+ rsv3:1,
+ crc:7,
+ rsv2:2,
+ file_format:2,
+ tmp_write_protect:1,
+ perm_write_protect:1,
+ copy:1,
+ file_format_grp:1,
+ rsv1:5,
+ write_bl_partial:1,
+ write_bl_len:4,
+ r2w_factor:3,
+ rsv0:2,
+ wp_grp_enable:1;
+ cyg_uint32
+ wp_grp_size:7,
+ sector_size:7,
+ erase_blk_en:1,
+ rsv9:1,
+ c_size_lo:16;
+ cyg_uint32
+ c_size_up:6,
+ rsv4:6,
+ dsr_imp:1,
+ read_blk_misalign:1,
+ write_blk_misalign:1,
+ read_bl_partial:1,
+ read_bl_len:4,
+ ccc:12;
+ cyg_uint32 tran_speed:8,
+ nsac:8,
+ taac:8,
+ rsv5:6,
+ csd_structure:2;
+} __attribute__ ((packed));
+
+#endif
--- /dev/null
+#ifndef _IMX_NFC_H_
+#define _IMX_NFC_H_
+//==========================================================================
+//
+// imx_nfc.h
+//
+// Flash programming to support NAND flash on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Kevin Zhang <k.zhang@freescale.com>
+// Contributors: Kevin Zhang <k.zhang@freescale.com>
+// Date: 2008-06-02
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#define NFC_DEBUG_MIN 1
+#define NFC_DEBUG_MED 2
+#define NFC_DEBUG_MAX 3
+#define NFC_DEBUG_DEF NFC_DEBUG_MED
+
+extern int _mxc_boot;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+//----------------------------------------------------------------------------
+// Common device details.
+#define FLASH_Read_ID (0x90)
+#ifdef CYGHWR_DEVS_FLASH_MXC_NAND_RESET_WORKAROUND
+#define FLASH_Reset 0xFFFF
+#else
+#define FLASH_Reset (0xFF)
+#endif
+#define FLASH_Read_Mode1 (0x00)
+#define FLASH_Read_Mode1_LG (0x30)
+#define FLASH_Read_Mode2 (0x01)
+#define FLASH_Read_Mode3 (0x50)
+#define FLASH_Program (0x10)
+#define FLASH_Send_Data (0x80)
+#define FLASH_Status (0x70)
+#define FLASH_Block_Erase (0x60)
+#define FLASH_Start_Erase (0xD0)
+
+enum nfc_page_area {
+ NFC_SPARE_ONLY,
+ NFC_MAIN_ONLY,
+};
+
+enum {
+ MXC_NAND_8_BIT = 8,
+ MXC_NAND_16_BIT = 16,
+};
+
+enum {
+ NAND_SLC = 0,
+ NAND_MLC = 1,
+};
+
+// read column 464-465 byte but only 464 for bad block marker
+#define BAD_BLK_MARKER_464 (NAND_MAIN_BUF3 + 464)
+// read column 4-5 byte, but only 5 is used for swapped main area data
+#define BAD_BLK_MARKER_SP_5 (NAND_SPAR_BUF3 + 4)
+
+typedef void nfc_iomuxsetup_func_t(void);
+
+#endif // _IMX_NFC_H_
--- /dev/null
+#ifndef _IMX_SPI_NOR_H_
+#define _IMX_SPI_NOR_H_
+//==========================================================================
+//
+// imx_nfc.h
+//
+// Flash programming to support NAND flash on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Kevin Zhang <k.zhang@freescale.com>
+// Contributors: Kevin Zhang <k.zhang@freescale.com>
+// Date: 2008-11-14
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// dummy defines - not used
+#define CYGNUM_FLASH_INTERLEAVE 1
+#define CYGNUM_FLASH_SERIES 1
+#define CYGNUM_FLASH_WIDTH 8
+#define CYGNUM_FLASH_BASE 0
+#define CYGNUM_FLASH_BLANK 1
+
+#define READ 0x03 // tx: 1 byte cmd + 3 byte addr; rx: variable bytes
+#define READ_HS 0x0B // tx: 1 byte cmd + 3 byte addr + 1 byte dummy; rx: variable bytes
+#define RDSR 0x05 // read status register 1 byte tx cmd + 1 byte rx status
+ #define RDSR_BUSY (1 << 0) // 1=write-in-progress (default 0)
+ #define RDSR_WEL (1 << 1) // 1=write enable (default 0)
+ #define RDSR_BP0 (1 << 2) // block write prot level (default 1)
+ #define RDSR_BP1 (1 << 3) // block write prot level (default 1)
+ #define RDSR_BP2 (1 << 4) // block write prot level (default 1)
+ #define RDSR_BP3 (1 << 5) // block write prot level (default 1)
+ #define RDSR_AAI (1 << 6) // 1=AAI prog mode; 0=byte prog (default 0)
+ #define RDSR_BPL (1 << 7) // 1=BP3,BP2,BP1,BP0 RO; 0=R/W (default 0)
+#define WREN 0x06 // write enable. 1 byte tx cmd
+#define WRDI 0x04 // write disable. 1 byte tx cmd
+#define EWSR 0x50 // Enable write status. 1 byte tx cmd
+#define WRSR 0x01 // Write status register. 1 byte tx cmd + 1 byte tx value
+#define ERASE_4K 0x20 // sector erase. 1 byte cmd + 3 byte addr
+#define ERASE_32K 0x52 // 32K block erase. 1 byte cmd + 3 byte addr
+#define ERASE_64K 0xD8 // 64K block erase. 1 byte cmd + 3 byte addr
+#define ERASE_CHIP 0x60 // whole chip erase
+#define BYTE_PROG 0x02 // all tx: 1 cmd + 3 addr + 1 data
+#define AAI_PROG 0xAD // all tx: [1 cmd + 3 addr + 2 data] + RDSR
+ // + [1cmd + 2 data] + .. + [WRDI] + [RDSR]
+#define JEDEC_ID 0x9F // read JEDEC ID. tx: 1 byte cmd; rx: 3 byte ID
+
+#define SZ_64K 0x10000
+#define SZ_32K 0x8000
+#define SZ_4K 0x1000
+
+extern imx_spi_init_func_t *spi_nor_init;
+extern imx_spi_xfer_func_t *spi_nor_xfer;
+extern struct imx_spi_dev imx_spi_nor;
+static int spi_nor_status(void);
+static int spi_nor_cmd_1byte(unsigned char cmd);
+int spi_nor_erase_block(void* block_addr, unsigned int block_size);
+static int spi_nor_write_status(unsigned char val);
+int spi_nor_program_buf(void *addr, void *data, int len);
+
+#endif // _IMX_SPI_NOR_H_
--- /dev/null
+#ifndef _IMX_ATA_H_
+#define _IMX_ATA_H_
+//==========================================================================
+//
+// mxc_ata.h
+//
+// Support ATA on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
+// Contributors: Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
+// Date: 2008-11-18
+//
+//==========================================================================
+#define FSL_ATA_TIMING_REGS 0x00
+#define FSL_ATA_FIFO_FILL 0x20
+#define FSL_ATA_CONTROL 0x24
+#define FSL_ATA_INT_PEND 0x28
+#define FSL_ATA_INT_EN 0x2C
+#define FSL_ATA_INT_CLEAR 0x30
+#define FSL_ATA_FIFO_ALARM 0x34
+#define FSL_ATA_ADMA_ERROR_STATUS 0x38
+#define FSL_ATA_SYS_DMA_BADDR 0x3C
+#define FSL_ATA_ADMA_SYS_ADDR 0x40
+#define FSL_ATA_BLOCK_COUNT 0x48
+#define FSL_ATA_BURST_LENGTH 0x4C
+#define FSL_ATA_SECTOR_SIZE 0x50
+#define FSL_ATA_DRIVE_DATA 0xA0
+#define FSL_ATA_DFTR 0xA4
+#define FSL_ATA_DSCR 0xA8
+#define FSL_ATA_DSNR 0xAC
+#define FSL_ATA_DCLR 0xB0
+#define FSL_ATA_DCHR 0xB4
+#define FSL_ATA_DDHR 0xB8
+#define FSL_ATA_DCDR 0xBC
+#define FSL_ATA_DRIVE_CONTROL 0xD8
+
+/* bits within FSL_ATA_CONTROL */
+#define FSL_ATA_CTRL_DMA_SRST 0x1000
+#define FSL_ATA_CTRL_DMA_64ADMA 0x800
+#define FSL_ATA_CTRL_DMA_32ADMA 0x400
+#define FSL_ATA_CTRL_DMA_STAT_STOP 0x200
+#define FSL_ATA_CTRL_DMA_ENABLE 0x100
+#define FSL_ATA_CTRL_FIFO_RST_B 0x80
+#define FSL_ATA_CTRL_ATA_RST_B 0x40
+#define FSL_ATA_CTRL_FIFO_TX_EN 0x20
+#define FSL_ATA_CTRL_FIFO_RCV_EN 0x10
+#define FSL_ATA_CTRL_DMA_PENDING 0x08
+#define FSL_ATA_CTRL_DMA_ULTRA 0x04
+#define FSL_ATA_CTRL_DMA_WRITE 0x02
+#define FSL_ATA_CTRL_IORDY_EN 0x01
+
+/* bits within the interrupt control registers */
+#define FSL_ATA_INTR_ATA_INTRQ1 0x80
+#define FSL_ATA_INTR_FIFO_UNDERFLOW 0x40
+#define FSL_ATA_INTR_FIFO_OVERFLOW 0x20
+#define FSL_ATA_INTR_CTRL_IDLE 0x10
+#define FSL_ATA_INTR_ATA_INTRQ2 0x08
+#define FSL_ATA_INTR_DMA_ERR 0x04
+#define FSL_ATA_INTR_DMA_TRANS_OVER 0x02
+
+/* ADMA Addr Descriptor Attribute Filed */
+#define FSL_ADMA_DES_ATTR_VALID 0x01
+#define FSL_ADMA_DES_ATTR_END 0x02
+#define FSL_ADMA_DES_ATTR_INT 0x04
+#define FSL_ADMA_DES_ATTR_SET 0x10
+#define FSL_ADMA_DES_ATTR_TRAN 0x20
+#define FSL_ADMA_DES_ATTR_LINK 0x30
+
+#define PIO_XFER_MODE_0 0
+#define PIO_XFER_MODE_1 1
+#define PIO_XFER_MODE_2 2
+#define PIO_XFER_MODE_3 3
+#define PIO_XFER_MODE_4 4
+
+#define ATA_ID_PROD 27
+#define ATA_ID_PROD_LEN 40
+
+#define ATA_BUSY (1 << 7)
+#define ATA_DRQ (1 << 3)
+#define ATA_ERR (1)
+
+#define ATA_IEN (1 << 1)
+#define ATA_SRST (1 << 2)
+
+#define ATA_CMD_READ 0x20
+#define ATA_CMD_WRITE 0x30
+#define ATA_CMD_READ_MULTI 0xC4
+#define ATA_CMD_WRITE_MULTI 0xC5
+#define ATA_CMD_ID_ATA 0xEC
+#define ATA_CMD_SET_FEATURES 0xEF
+
+#define ATA_SECTOR_SIZE 512
+#define MAX_NUMBER_OF_SECTORS 256
+#endif // _IMX_ATA_H_
--- /dev/null
+/*=================================================================================
+
+ Module Name: mxc_mmc.h
+
+ General Description: Limited Bootloader eSDHC Driver.
+
+===================================================================================
+ Copyright: 2004,2005,2006,2007,2008 FREESCALE, INC.
+ All Rights Reserved. This file contains copyrighted material.
+ Use of this file is restricted by the provisions of a
+ Freescale Software License Agreement, which has either
+ accompanied the delivery of this software in shrink wrap
+ form or been expressly executed between the parties.
+
+
+Revision History:
+ Modification Tracking
+Author (core ID) Date Number Description of Changes
+------------------------- ------------ ---------- --------------------------
+Lewis Liu 18-Feb-2008
+
+
+Portability: Portable to other compilers or platforms.
+
+====================================================================================================*/
+
+#ifndef __MXC_MMC_H__
+#define __MXC_MMC_H__
+
+#include <pkgconf/system.h>
+
+#define FLASH_DEBUG_MIN 1
+#define FLASH_DEBUG_MED 2
+#define FLASH_DEBUG_MAX 3
+#define FLASH_DEBUG_LEVEL FLASH_DEBUG_MED
+#define flash_dprintf(level, args...) \
+ do { \
+ if (FLASH_DEBUG_LEVEL >= level) \
+ diag_printf(args); \
+ } while(0)
+
+#define CHECK_RUN_TIMES(n) { \
+ static int count = 0;\
+ if(++count > n){\
+ diag_printf("%s: the loop gets the limitation, WRONG!\n", __FUNCTION__);break;}
+
+#endif //__MXC_MMC_H__
--- /dev/null
+#ifndef _MXC_NFC_V3_H_
+#define _MXC_NFC_V3_H_
+//==========================================================================
+//
+// mxc_nfc_v3.h
+//
+// Flash programming to support NAND flash on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Kevin Zhang <k.zhang@freescale.com>
+// Contributors: Kevin Zhang <k.zhang@freescale.com>
+// Date: 2008-06-02
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/devs_flash_onmxc.h>
+#include "mxc_nand_specifics.h"
+
+#define PG_2K_DATA_OP_MULTI_CYCLES() false
+#define ADDR_INPUT_SIZE 8
+
+#define NAND_MAIN_BUF0 (NFC_BASE + 0x000)
+#define NAND_MAIN_BUF1 (NFC_BASE + 0x200)
+#define NAND_MAIN_BUF2 (NFC_BASE + 0x400)
+#define NAND_MAIN_BUF3 (NFC_BASE + 0x600)
+#define NAND_MAIN_BUF4 (NFC_BASE + 0x800)
+#define NAND_MAIN_BUF5 (NFC_BASE + 0xA00)
+#define NAND_MAIN_BUF6 (NFC_BASE + 0xC00)
+#define NAND_MAIN_BUF7 (NFC_BASE + 0xE00)
+#define NAND_SPAR_BUF0 (NFC_BASE + 0x1000)
+#define NAND_SPAR_BUF1 (NFC_BASE + 0x1040)
+#define NAND_SPAR_BUF2 (NFC_BASE + 0x1080)
+#define NAND_SPAR_BUF3 (NFC_BASE + 0x10C0)
+#define NAND_SPAR_BUF4 (NFC_BASE + 0x1100)
+#define NAND_SPAR_BUF5 (NFC_BASE + 0x1140)
+#define NAND_SPAR_BUF6 (NFC_BASE + 0x1180)
+#define NAND_SPAR_BUF7 (NFC_BASE + 0x11C0)
+
+// The following defines are not used. Just for compilation purpose
+#define ECC_STATUS_RESULT_REG 0xDEADFFFF
+#define NFC_DATA_INPUT(buf_no, earea, en)
+#define NFC_DATA_INPUT_2k(buf_no)
+// dummy function as it is not needed for automatic operations
+#define NFC_ADDR_INPUT(addr)
+#define NFC_ARCH_INIT()
+#define NUM_OF_CS_LINES 8
+#define NFC_BUFSIZE 4096
+
+enum nfc_internal_buf {
+ RAM_BUF_0 = 0x0 << 4,
+ RAM_BUF_1 = 0x1 << 4,
+ RAM_BUF_2 = 0x2 << 4,
+ RAM_BUF_3 = 0x3 << 4,
+ RAM_BUF_4 = 0x4 << 4,
+ RAM_BUF_5 = 0x5 << 4,
+ RAM_BUF_6 = 0x6 << 4,
+ RAM_BUF_7 = 0x7 << 4,
+};
+
+enum nfc_output_mode {
+ FDO_PAGE_SPARE = 0x0008,
+ FDO_SPARE_ONLY = 0x1008, // LSB has to be 0x08
+ FDO_FLASH_ID = 0x0010,
+ FDO_FLASH_STATUS = 0x0020,
+};
+
+#define wait_for_auto_prog_done() \
+ do { \
+ while ((readl(NFC_IPC_REG) & NFC_IPC_AUTO_DONE) == 0) \
+ {} \
+ write_nfc_ip_reg((readl(NFC_IPC_REG) & ~NFC_IPC_AUTO_DONE), NFC_IPC_REG); \
+ } while (0)
+
+// Polls the NANDFC to wait for an operation to complete
+#define wait_op_done() \
+ do { \
+ while ((readl(NFC_IPC_REG) & NFC_IPC_INT) == 0) \
+ {} \
+ write_nfc_ip_reg(0, NFC_IPC_REG); \
+ } while (0)
+
+static void write_nfc_ip_reg(u32 val, u32 reg)
+{
+ writel(NFC_IPC_CREQ, NFC_IPC_REG);
+ while((readl(NFC_IPC_REG) & NFC_IPC_CACK) == 0);
+
+ writel(val, reg);
+ writel((readl(NFC_IPC_REG) & ~NFC_IPC_CREQ), NFC_IPC_REG);
+}
+
+/*!
+ * NAND flash data output operation (reading data from NAND flash)
+ * @param buf_no internal ram buffer number that will contain data
+ * to be outputted from the NAND flash after operation done
+ * @param mode one of the mode defined in enum nfc_output_mode
+ * @param ecc_en 1 - ecc enabled; 0 - ecc disabled
+ */
+static void NFC_DATA_OUTPUT(enum nfc_internal_buf buf_no, enum nfc_output_mode mode,
+ int ecc_en)
+{
+ u32 v = readl(NFC_FLASH_CONFIG2_REG);
+
+ if ((v & NFC_FLASH_CONFIG2_ECC_EN) != 0 && ecc_en == 0) {
+ write_nfc_ip_reg(v & ~NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
+ }
+ if ((v & NFC_FLASH_CONFIG2_ECC_EN) == 0 && ecc_en != 0) {
+ write_nfc_ip_reg(v | NFC_FLASH_CONFIG2_ECC_EN, NFC_FLASH_CONFIG2_REG);
+ }
+
+ v = readl(NAND_CONFIGURATION1_REG);
+
+ if (mode == FDO_SPARE_ONLY) {
+ v = (v & ~0x71) | buf_no | NAND_CONFIGURATION1_SP_EN;
+ } else {
+ v = (v & ~0x71) | buf_no;
+ }
+
+ writel(v, NAND_CONFIGURATION1_REG);
+
+ writel(mode & 0xFF, NAND_LAUNCH_REG);
+ wait_op_done();
+}
+
+static void NFC_CMD_INPUT(u32 cmd)
+{
+ writel(cmd & 0xFFFF, NAND_CMD_REG);
+ writel(NAND_LAUNCH_FCMD, NAND_LAUNCH_REG);
+ wait_op_done();
+}
+
+static void NFC_SET_NFC_ACTIVE_CS(u32 cs_line)
+{
+ u32 v;
+
+ v = readl(NAND_CONFIGURATION1_REG) & (~0x7071);
+ v |= (cs_line << 12);
+ writel(v, NAND_CONFIGURATION1_REG);
+}
+
+static u16 NFC_STATUS_READ(void)
+{
+ u32 status;
+ u16 status_sum = 0;
+ int i;
+
+#ifdef IMX51_TO_2
+ return readl(NAND_STATUS_SUM_REG);
+#else
+ /* Cannot rely on STATUS_SUM register due to errata */
+ for (i = 0; i < num_of_nand_chips; i++) {
+ NFC_SET_NFC_ACTIVE_CS(i);
+ do {
+ writel(NAND_LAUNCH_AUTO_STAT, NAND_LAUNCH_REG);
+ status = (readl(NAND_CONFIGURATION1_REG) & 0x00FF0000) >> 16;
+ } while ((status & 0x40) == 0); // make sure I/O 6 == 1
+ /* Get Pass/Fail status */
+ status = (readl(NAND_CONFIGURATION1_REG) >> 16) & 0x1;
+ status_sum |= (status << i);
+ }
+ return status_sum;
+#endif
+}
+
+/* This function uses a global variable for the page size. It shouldn't be a big
+ * problem since we don't expect mixed page size nand flash parts on the same IC.
+ * Note for address 0, it will always be correct regardless the page size. So for
+ * ID read, it doesn't need to have the correct page size global variable first.
+ */
+static void start_nfc_addr_ops(u32 ops, u32 pg_no, u16 pg_off, u32 is_erase, u32 cs_line, u32 num_of_chips)
+{
+ u32 add0, add8, page_number;
+ int num_of_bits[] = {0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4};
+
+ if (ops == FLASH_Read_ID) {
+ // issue addr cycle
+ writel(0x0, NAND_ADD0_REG + (4 * cs_line));
+ writel(NAND_LAUNCH_FADD, NAND_LAUNCH_REG);
+ wait_op_done();
+ return;
+ }
+
+ if (num_of_chips > 1) {
+ page_number = (pg_no << num_of_bits[num_of_chips]) | (cs_line & (num_of_chips - 1));
+ } else {
+ page_number = pg_no;
+ }
+ if (is_erase) {
+ add0 = page_number;
+ add8 = 0;
+ } else {
+ // for both read and write
+ if (g_is_2k_page || g_is_4k_page) {
+ // the first two addr cycles are for column addr. Page number starts
+ // from the 3rd addr cycle.
+ add0 = pg_off | (page_number << 16);
+ add8 = page_number >> 16;
+ } else {
+ diag_printf("too bad, die\n");
+ asm("1: b 1b");
+ // For 512B page, the first addr cycle is for column addr. Page number
+ // starts from the 2nd addr cycle.
+ add0 = (pg_off & 0xFF) | (page_number << 8);
+ add8 = page_number >> 24;
+ }
+ }
+ writel(add0, NAND_ADD0_REG);
+ writel(add8, NAND_ADD8_REG);
+}
+
+/*
+ * Do a page read at random address
+ *
+ * @param pg_no page number offset from 0
+ * @param pg_off byte offset within the page
+ * @param ecc_force can force ecc to be off. Otherwise, by default it is on
+ * unless the page offset is non-zero
+ * @param cs_line indicates which NAND of interleaved NAND devices is used
+ *
+ * @return 0 if successful; non-zero otherwise
+ */
+static int nfc_read_pg_random(u32 pg_no, u32 pg_off, u32 ecc_force, u32 cs_line, u32 num_of_chips)
+{
+ u32 ecc = NFC_FLASH_CONFIG2_ECC_EN;
+ u32 v, res = 0;
+
+ // clear the NAND_STATUS_SUM_REG register
+ writel(0, NAND_STATUS_SUM_REG);
+
+ // the 2nd condition is to test for unaligned page address -- ecc has to be off.
+ if (ecc_force == ECC_FORCE_OFF || pg_off != 0 ) {
+ ecc = 0;
+ }
+
+ // Take care of config1 for RBA and SP_EN
+ v = readl(NAND_CONFIGURATION1_REG) & (~0x71);
+ writel(v, NAND_CONFIGURATION1_REG);
+
+ // For ECC
+ v = readl(NFC_FLASH_CONFIG2_REG) & (~NFC_FLASH_CONFIG2_ECC_EN);
+ // setup config2 register for ECC enable or not
+ write_nfc_ip_reg(v | ecc, NFC_FLASH_CONFIG2_REG);
+
+ start_nfc_addr_ops(FLASH_Read_Mode1, pg_no, pg_off, 0, cs_line, num_of_chips);
+
+ if (g_is_2k_page || g_is_4k_page) {
+ // combine the two commands for 2k/4k page read
+ writel((FLASH_Read_Mode1_LG << 8) | FLASH_Read_Mode1, NAND_CMD_REG);
+ } else {
+ // just one command is enough for 512 page
+ writel(FLASH_Read_Mode1, NAND_CMD_REG);
+ }
+
+ // start auto-read
+ writel(NAND_LAUNCH_AUTO_READ, NAND_LAUNCH_REG);
+ wait_op_done();
+
+ v = readl(NAND_STATUS_SUM_REG);
+ // test for CS0 ECC error from the STATUS_SUM register
+ if ((v & (0x0100 << cs_line)) != 0) {
+ // clear the status
+ writel((0x0100 << cs_line), NAND_STATUS_SUM_REG);
+ diag_printf("ECC error from NAND_STATUS_SUM_REG(0x%x) = 0x%x\n",
+ NAND_STATUS_SUM_REG, v);
+ diag_printf("NAND_ECC_STATUS_RESULT_REG(0x%x) = 0x%x\n", NAND_ECC_STATUS_RESULT_REG,
+ readl(NAND_ECC_STATUS_RESULT_REG));
+ res = -1;
+ }
+ return res;
+}
+
+/*!
+ * The NFC has to be preset before performing any operation
+ */
+static void NFC_PRESET(u32 max_block_count)
+{
+ // not needed. It is done in plf_hardware_init()
+}
+
+#endif // _MXC_NFC_V3_H_
--- /dev/null
+#ifndef _MXCMCI_CORE_H_
+#define _MXCMCI_CORE_H_
+
+/*=================================================================================
+
+ Module Name: mxcmci_core.h
+
+ General Description: Limited Bootloader eSDHC Driver.
+
+===================================================================================
+ Copyright: 2004,2005,2006,2007,2008 FREESCALE, INC.
+ All Rights Reserved. This file contains copyrighted material.
+ Use of this file is restricted by the provisions of a
+ Freescale Software License Agreement, which has either
+ accompanied the delivery of this software in shrink wrap
+ form or been expressly executed between the parties.
+
+
+Revision History:
+ Modification Tracking
+Author (core ID) Date Number Description of Changes
+------------------------- ------------ ---------- --------------------------
+Lewis Liu 18-June-2008
+
+
+Portability: Portable to other compilers or platforms.
+
+====================================================================================================*/
+
+#include "mxcmci_mmc.h"
+#include "mxcmci_host.h"
+
+#define SUCCESS 0
+#define FAIL 1
+#define NO_ARG 0
+#define RCA_SHIFT 16
+#define ONE 1
+#define FOUR 4
+#define EIGHT 8
+#define TWO_K_SIZE 2048
+#define MMCSD_READY_TIMEOUT 3000 /* ~(3s / (2 * 48 * 10us)) */
+#define ESDHC_ACMD41_TIMEOUT 48000 /* 1.5 sec =1500 msec delay for ACMD41 cmd */
+#define MMCSD_SUPPORT
+
+#define CURR_CARD_STATE(r) ((cyg_uint32) ((r) & 0x1E00) >> 9)
+
+/*Defines of CSD data*/
+#define CSD_STRUCT_MSK 0x00C00000
+#define CSD_STRUCT_SHIFT 22
+#define MMC_CSD_SPEC_VERS_MASK 0x003C0000
+#define MMC_CSD_SPEC_VERS_SHIFT 18
+
+extern cyg_uint32 Card_rca;
+extern cyg_uint32 address_mode;
+extern cyg_uint32 MMC_Spec_vers;
+extern card_specific_data csd; /* Global variable for Card Specific Data */
+extern cyg_uint32 Card_capacity_size; /* Capacity size (C_SIZE) for card*/
+extern cyg_uint32 CCC; /* Card Command Class */
+
+
+/* Defines the id for each command */
+enum commands
+{
+ CMD0= 0,
+ CMD1= 1,
+ CMD2= 2,
+ CMD3= 3,
+ CMD5= 5,
+ CMD6=6,
+ ACMD6= 6,
+ CMD7= 7,
+ CMD8=8,
+ CMD9=9,
+ CMD12 = 12,
+ CMD13 = 13,
+ CMD16 = 16,
+ CMD17 = 17,
+ CMD18 = 18,
+ CMD24 = 24,
+ CMD25 = 25,
+ CMD26 = 26,
+ CMD32 = 32,
+ CMD33 = 33,
+ CMD35 = 35,
+ CMD36 = 36,
+ CMD37 = 37,
+ CMD38 = 38,
+ CMD39 = 39,
+ ACMD41 = 41,
+ CMD43 = 43,
+ ACMD51 = 51,
+ CMD55 = 55,
+ CMD60 = 60,
+ CMD61 = 61,
+ CMD62 = 62,
+};
+
+/* Defines for the states of the card*/
+enum states
+{
+ IDLE,
+ READY,
+ IDENT,
+ STBY,
+ TRAN,
+ DATA,
+ RCV,
+ PRG,
+ DIS
+};
+
+/* Defines for card types */
+typedef enum
+{
+ TYPE_NONE,
+ SD_CSD_1_0,
+ SD_CSD_2_0,
+ MMC_CSD_1_0,
+ MMC_CSD_1_1,
+ MMC_CSD_1_2,
+ MMC_UNKNOWN
+}card_type;
+
+typedef struct
+{
+ cyg_uint32 cid0;
+ cyg_uint32 cid1;
+ cyg_uint32 cid2;
+ cyg_uint32 cid3;
+}card_ident;
+
+
+/* CARD Flash Configuration Parameters Structure */
+typedef struct {
+ cyg_uint32 length; /* Length of Card data to read */
+} CARD_FLASH_CFG_PARMS_T;
+
+/*==================================================================================================
+ ENUMS
+==================================================================================================*/
+
+/*==================================================================================================
+ Global Function
+==================================================================================================*/
+extern cyg_uint32 mxcmci_init (cyg_uint32 bus_width, cyg_uint32 base_address);
+extern cyg_uint32 mxcmci_data_read (cyg_uint32* dest_ptr,cyg_uint32 len,cyg_uint32 offset);
+extern cyg_uint32 mxcmci_software_reset (void);
+extern cyg_uint32 mxcmci_get_cid (void);
+extern cyg_uint32 mxcmci_trans_prepare(void);
+extern void mxcmci_cmd_config (command_t *cmd_config,cyg_uint32 index,cyg_uint32 argument,xfer_type_t transfer,response_format_t format,
+ data_present_select data,crc_check_enable crc,cmdindex_check_enable cmdindex);
+
+
+#endif //_MXCMCI_CORE_H_
--- /dev/null
+#ifndef _MXCMCI_HOST_H_
+#define _MXCMCI_HOST_H_
+
+// ==========================================================================
+//
+// Module Name: mxcmci_host.h
+//
+// General Description: Limited Bootloader eSDHC Driver.
+//
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//
+//####DESCRIPTIONEND####
+//====================================================================================================
+
+#include <cyg/infra/cyg_type.h>
+
+
+#define ESDHC_SOFTWARE_RESET 0x01000000 /* RSTA bit of ESDHC system control register*/
+#define ESDHC_CMD_INHIBIT 0x00000003 /* Command inhibit bits*/
+#define ESDHC_SOFTWARE_INIT 0x08000000 /* INITA bit of ESDHC system control register */
+#define ESDHC_LITTLE_ENDIAN_MODE 0x00000020 /* Little Endian mode */
+#define ESDHC_HW_BIG_ENDIAN_MODE 0x00000010 /* Half Word Big Endian mode */
+#define ESDHC_BIG_ENDIAN_MODE 0x00000000 /* Big Endian mode */
+#define ESDHC_ONE_BIT_SUPPORT 0x00000000 /* 1 Bit Mode support */
+#define ESDHC_FOUR_BIT_SUPPORT 0x00000002 /* 4 Bit Mode support */
+#define ESDHC_EIGHT_BIT_SUPPORT 0x00000004 /* 8 Bit Mode support */
+#define ESDHC_CLOCK_ENABLE 0x00000007 /* Clock Enable */
+#define ESDHC_ENABLE 0x00000008 /* Enable SD */
+
+#define ESDHC_FREQ_MASK 0xffff0007
+#define ESDHC_IDENT_FREQ 0x0000800e /* SDCLKFS 0x08 ; DVS 0xe */
+#define ESDHC_OPERT_FREQ 0x00000200 /* SDCLKFS 0x02 ; DVS 0x0 */
+#define ESDHC_INTERRUPT_ENABLE 0x007f0123 /* Enable Interrupts */
+#define ESDHC_CONFIG_BLOCK 0x00010200 /* 512 byte block size*/
+#define ESDHC_CLEAR_INTERRUPT 0xffffffff
+
+#define ESDHC_CONFIG_BLOCK_512 0x00000200 /* 512 byte block size*/
+#define ESDHC_CONFIG_BLOCK_64 0x00000040 /* 64 byte block size*/
+#define ESDHC_BLOCK_SHIFT 16
+
+#define ESDHC_CLEAR_INTERRUPT 0xffffffff
+#define ESDHC_OPER_TIMEOUT 96 /* 3 msec time out */
+#define ESDHC_READ_TIMEOUT 3264 /* 102 msec read time out */
+#define ESDHC_ACMD41_TIMEOUT 48000 /* 1.5 sec =1500 msec delay for ACMD41 cmd */
+
+#define ESDHCI_SPACE_AVAILABLE 0x00000400
+#define ESDHCI_DATA_AVAILABLE 0x00000800
+
+/*==================================================================================================
+ DEFINES
+==================================================================================================*/
+#define DATA_TRANSFER_SHIFT 4
+#define RESPONSE_FORMAT_SHIFT 16
+#define DATA_PRESENT_SHIFT 21
+#define CRC_CHECK_SHIFT 19
+#define CMD_INDEX_CHECK_SHIFT 20
+#define CMD_INDEX_SHIFT 24
+#define BLOCK_COUNT_ENABLE_SHIFT 1
+#define MULTI_SINGLE_BLOCK_SELECT_SHIFT 5
+#define BLK_LEN 512
+#define SWITCH_BLK_LEN 64
+#define FIFO_SIZE 128
+#define WRITE_READ_WATER_MARK_LEVEL 0x00200020
+#define ESDHC3 2
+#define ESDHC2 1
+#define ONE 1
+#define ESDHC1 0
+/*==================================================================================================
+ ENUS
+==================================================================================================*/
+#define ESDHC_STATUS_END_CMD_RESP_MSK 0x1
+#define ESDHC_STATUS_END_CMD_RESP_TIME_MSK 0x00010001
+#define ESDHC_STATUS_TIME_OUT_RESP_MSK 0x10000
+#define ESDHC_STATUS_RESP_CRC_ERR_MSK 0x20000
+#define ESDHC_STATUS_RESP_INDEX_ERR_MSK 0x80000
+#define ESDHC_STATUS_BUF_READ_RDY_MSK 0x20
+#define ESDHC_STATUS_BUF_WRITE_RDY_MSK 0x10
+#define ESDHC_STATUS_TRANSFER_COMPLETE_MSK 0x2
+#define ESDHC_STATUS_TIME_OUT_READ 0x100000
+#define ESDHC_STATUS_READ_CRC_ERR_MSK 0x200000
+
+#define ESDHC_RESET_CMD_MSK 0x02000000
+#define ESDHC_RESET_DAT_MSK 0x04000000
+#define ESDHC_RESET_ALL_MSK 0x01000000
+
+typedef enum
+{
+ WRITE = 0,
+ READ = 1,
+}xfer_type_t;
+
+typedef enum
+{
+ RESPONSE_NONE,
+ RESPONSE_136,
+ RESPONSE_48,
+ RESPONSE_48_CHECK_BUSY
+}response_format_t;
+
+
+typedef enum
+{
+ DATA_PRESENT_NONE = 0,
+ DATA_PRESENT = 1
+}data_present_select;
+
+typedef enum
+{
+ DISABLE = 0,
+ ENABLE = 1
+}crc_check_enable,cmdindex_check_enable,block_count_enable;
+
+typedef enum
+{
+ SINGLE = 0,
+ MULTIPLE = 1
+}multi_single_block_select;
+
+typedef struct
+{
+ cyg_uint32 command;
+ cyg_uint32 arg;
+ xfer_type_t data_transfer;
+ response_format_t response_format;
+ data_present_select data_present;
+ crc_check_enable crc_check;
+ cmdindex_check_enable cmdindex_check;
+ block_count_enable block_count_enable_check;
+ multi_single_block_select multi_single_block;
+}command_t;
+
+typedef struct
+{
+ response_format_t format;
+ cyg_uint32 cmd_rsp0;
+ cyg_uint32 cmd_rsp1;
+ cyg_uint32 cmd_rsp2;
+ cyg_uint32 cmd_rsp3;
+}command_response_t;
+
+typedef enum
+{
+ BIG_ENDIAN,
+ HALF_WORD_BIG_ENDIAN,
+ LITTLE_ENDIAN
+}endian_mode_t;
+
+typedef enum
+{
+ OPERATING_FREQ = 20000, /* in kHz */
+ IDENTIFICATION_FREQ = 400 /* in kHz */
+}sdhc_freq_t;
+
+
+enum esdhc_data_status
+{
+ ESDHC_DATA_ERR = 3,
+ ESDHC_DATA_OK = 4
+};
+
+enum esdhc_int_cntr_val
+{
+ ESDHC_INT_CNTR_END_CD_RESP = 0x4,
+ ESDHC_INT_CNTR_BUF_WR_RDY = 0x8
+};
+
+enum esdhc_reset_status
+{
+ ESDHC_WRONG_RESET = 0,
+ ESDHC_CORRECT_RESET = 1
+};
+
+typedef struct
+{
+ volatile cyg_uint32 dma_system_address;
+ volatile cyg_uint32 block_attributes;
+ volatile cyg_uint32 command_argument;
+ volatile cyg_uint32 command_transfer_type;
+ volatile cyg_uint32 command_response0;
+ volatile cyg_uint32 command_response1;
+ volatile cyg_uint32 command_response2;
+ volatile cyg_uint32 command_response3;
+ volatile cyg_uint32 data_buffer_access;
+ volatile cyg_uint32 present_state;
+ volatile cyg_uint32 protocol_control;
+ volatile cyg_uint32 system_control;
+ volatile cyg_uint32 interrupt_status;
+ volatile cyg_uint32 interrupt_status_enable;
+ volatile cyg_uint32 interrupt_signal_enable;
+ volatile cyg_uint32 autocmd12_status;
+ volatile cyg_uint32 host_controller_capabilities;
+ volatile cyg_uint32 watermark_level;
+ cyg_uint32 reserved1[2];
+ volatile cyg_uint32 force_event;
+ volatile cyg_uint32 adma_error_status_register;
+ volatile cyg_uint32 adma_system_address;
+ cyg_uint32 reserved[40];
+ volatile cyg_uint32 host_controller_version;
+}host_register, *host_register_ptr;
+
+
+extern host_register_ptr esdhc_base_pointer;
+//extern cyg_uint32 available_mask;
+
+extern void host_reset(cyg_uint32 data_transfer_width, cyg_uint32 endian_mode);
+extern void host_cfg_clock(sdhc_freq_t);
+extern void host_read_response(command_response_t *);
+extern cyg_uint32 host_send_cmd(command_t *cmd);
+extern cyg_uint32 host_data_read(cyg_uint32 *,cyg_uint32);
+extern cyg_uint32 host_data_write(cyg_uint32 *,cyg_uint32);
+extern void host_cfg_block(cyg_uint32 blk_len, cyg_uint32 nob);
+extern void host_init(cyg_uint32 base_address);
+extern void esdhc_softreset(cyg_uint32 mask);
+/*================================================================================================*/
+#endif /* _MXCMCI_HOST_H_ */
--- /dev/null
+#ifndef _MXCMCI_MMC_H_
+#define _MXCMCI_MMC_H_
+
+// ==========================================================================
+//
+// Module Name: mxcmci_mmc.h
+//
+// General Description: Limited Bootloader eSDHC Driver.
+//
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//
+//####DESCRIPTIONEND####
+//====================================================================================================
+
+
+#define MMC_OCR_VALUE 0x40FF8000
+#define MMC_OCR_VALUE_BAK 0x80FFC000
+#define MMC_OCR_HC_RES 0xC0FF8000
+#define MMC_OCR_LC_RES 0x80FF8000
+#define MMC_OCR_VALUE_MASK 0x00FF8000
+#define BYTE_MODE 0
+#define SECT_MODE 1
+#define CARD_BUSY_BIT 0x80000000
+#define CURR_STATE_SHIFT 9
+#define MMC_SPEC_VER 0x003C0000
+#define MMC_SPEC_VER_SHIFT 18
+#define MMC_R1_SWITCH_ERROR_MASK 0x80
+#define SWITCH_ERROR_SHIFT 7
+#define BUS_SIZE_SHIFT 2
+#define BUS_WIDTH 0x3b700000
+
+
+extern cyg_uint32 mmc_init(cyg_uint32);
+extern cyg_uint32 mmc_data_read (cyg_uint32 *,cyg_uint32 ,cyg_uint32);
+extern cyg_uint32 mmc_data_write (cyg_uint32 *src_ptr,cyg_uint32 length,cyg_uint32 offset);
+extern cyg_uint32 mmc_data_erase (cyg_uint32 offset, cyg_uint32 size);
+extern cyg_uint32 mmc_voltage_validation (void);
+extern cyg_uint32 mmc_get_spec_ver (void);
+extern cyg_uint32 sd_voltage_validation (void);
+extern cyg_uint32 sd_init(cyg_uint32);
+extern cyg_uint32 card_flash_query(void* data);
+
+typedef struct
+{
+ cyg_uint32 csd0;
+ cyg_uint32 csd1;
+ cyg_uint32 csd2;
+ cyg_uint32 csd3;
+}card_specific_data;
+
+#endif /* _MXCMCI_MMC_H_ */
+
--- /dev/null
+#ifndef CYGONCE_DEVS_FLASH_SPI_NOR_PARTS_INL
+#define CYGONCE_DEVS_FLASH_SPI_NOR_PARTS_INL
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Kevin Zhang <k.zhang@freescale.com>
+// Contributors: Kevin Zhang <k.zhang@freescale.com>
+// Date: 2008-11-14
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+ {
+ device_id : 0xbf, // Samsung K9F5608x0C (on EVB SDR memory card)
+ device_id2 : 0x25,
+ device_id3 : 0x41,
+ device_id4 : 0xFF,
+ block_size : SZ_64K,
+ block_count: 32,
+ device_size: SZ_64K * 32,
+ fis_start_addr: 0x80000, // first 0.5MB reserved for Redboot
+ vendor_info: "SST25VF016B - 2MB ",
+ },
+#endif // CYGONCE_DEVS_FLASH_SPI_NOR_PARTS_INL
--- /dev/null
+// ==========================================================================
+//
+// card_mx32.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Ivan Xu <yu.xu@freescale.com>
+// Contributors: Ivan Xu <yu.xu@freescale.com>
+// Date: 2008-06-13 Initial version
+// Purpose:
+// Description:
+// Support SD/MMC cards based on SDHC controller.
+// only base functionality is implemented: Card init, read, write and erase.
+// Write protection are not supported so far.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/io/card_mx32.h>
+#include <cyg/hal/hal_io.h>
+#include <redboot.h>
+#include <stdlib.h>
+
+//#define diag_printf1 diag_printf
+#define diag_printf1(fmt,args...)
+
+volatile psdhc_t pSDHC;
+card_mode_t Card_Mode;
+cyg_uint32 HighCapacityCard = 0;
+cyg_uint32 card_address;
+card_type Card_type; /* Card Type*/
+CARD_ID card_id;
+CARD_SPECIFIC_DATA csd; /* Global variable for Card Specific Data */
+cyg_uint32 CCC = 0; /* Card Command Class */
+
+static struct csd_v1_0 g_csd_val;
+
+static void configure_cmd (command_t *cmd,cyg_uint32 index, cyg_uint32 argument,
+ cyg_uint32 transfer,cyg_uint32 response_format, cyg_uint32 data_enable,
+ cyg_uint32 bus_width )
+{
+ /* Configure Command index */
+ cmd->index = index;
+
+ /* Configure Command argument */
+ cmd->arg = argument;
+ /* workaround for CMD0, send 80 clock cycles before CMD0 */
+ if (cmd->index == 0)
+ {
+ cmd->data_control = (((transfer) << SDHC_CMD_WRITE_READ_SHIFT) |
+ ((response_format) << SDHC_CMD_FROMAT_OF_RESP_SHIFT) |
+ ((data_enable) << SDHC_CMD_DATA_ENABLE_SHIFT) |
+ ((bus_width) << SDHC_CMD_BUS_WIDTH_SHIFT)) |
+ (0x1 << SDHC_CMD_INIT_SHIFT );
+ } else {
+ cmd->data_control = (((transfer) << SDHC_CMD_WRITE_READ_SHIFT) |
+ ((response_format) << SDHC_CMD_FROMAT_OF_RESP_SHIFT) |
+ ((data_enable) << SDHC_CMD_DATA_ENABLE_SHIFT) |
+ ((bus_width) << SDHC_CMD_BUS_WIDTH_SHIFT));
+ }
+}
+
+static void stop_clk(void)
+{
+ /* Stop the clock */
+// pSDHC->sdhc_clk = SDHC_CLK_STOP;
+
+ /* Wait till the clock has stopped */
+// while((pSDHC->sdhc_status & SDHC_STATUS_CARD_BUS_CLK_RUN_MSK));
+ return;
+}
+
+static void start_clk(void)
+{
+ /* Start the clock */
+ pSDHC->sdhc_clk = SDHC_CLK_START;
+
+ /* Wait till the clock has started */
+ while(!(pSDHC->sdhc_status & SDHC_STATUS_CARD_BUS_CLK_RUN_MSK));
+ return;
+}
+
+static void configure_clk(frequency_mode_t mode)
+{
+ if(mode == iden_mode)
+ {
+ /* Below 400 kHz */
+ pSDHC->sdhc_clk_rate = 0x207;
+ }
+ else if(mode == trans_mode)
+ {
+ /* Below 20 MHz */
+ pSDHC->sdhc_clk_rate = 0x3;
+ }
+
+ diag_printf1("pSDHC->sdhc_clk_rate=0x%x\n", pSDHC->sdhc_clk_rate);
+}
+
+static void read_response(cyg_uint32 response_mode, response_t*response)
+{
+ cyg_uint32 resp1=0;
+ cyg_uint32 resp2=0;
+ cyg_uint32 resp3=0;
+ cyg_uint32 count;
+
+ if(response_mode != 0)
+ {
+ if((response_mode == RESPONSE_48_CRC) || (response_mode == RESPONSE_48_WITHOUT_CRC))
+ {
+ resp1 = readl(0x50004000 + 0x34) & 0xffff;
+ resp2 = readl(0x50004000 + 0x34) & 0xffff;
+ resp3 = readl(0x50004000 + 0x34) & 0xffff;
+
+ response->rsp0 = (resp1 << 24) | (resp2 << 8) | (resp3 >> 8);
+ }
+ else if(response_mode == RESPONSE_136)
+ {
+ resp1 = pSDHC->sdhc_res_fifo & 0xffff;
+ resp2 = pSDHC->sdhc_res_fifo & 0xffff;
+ response->rsp3 = (resp1 << 16) | resp2;
+ resp1 = pSDHC->sdhc_res_fifo & 0xffff;
+ resp2 = pSDHC->sdhc_res_fifo & 0xffff;
+ response->rsp2 = (resp1 << 16) | resp2;
+
+ resp1 = pSDHC->sdhc_res_fifo & 0xffff;
+ resp2 = pSDHC->sdhc_res_fifo & 0xffff;
+ response->rsp1 = (resp1 << 16) | resp2;
+
+ resp1 = pSDHC->sdhc_res_fifo & 0xffff;
+ resp2= pSDHC->sdhc_res_fifo & 0xffff;
+ response->rsp0 = (resp1 << 16) | resp2;
+ }
+
+ /* Stop the clock */
+ stop_clk();
+ /* Clear w1c bits from STATUS register */
+ pSDHC->sdhc_status |= SDHC_STATUS_CLEAR;
+ }
+
+ //return status;
+}
+
+static cyg_uint32 check_response(void)
+{
+ cyg_uint32 status = PASS;
+
+ if((pSDHC->sdhc_status & SDHC_STATUS_END_CMD_RESP_MSK) &&
+ !(pSDHC->sdhc_status & SDHC_STATUS_TIME_OUT_RESP_MSK) &&
+ !(pSDHC->sdhc_status & SDHC_STATUS_RESP_CRC_ERR_MSK))
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ diag_printf("response status: %x Fail!\n", pSDHC->sdhc_status);
+ }
+ return status;
+}
+
+static cyg_uint32 send_cmd_and_wait_resp(command_t *cmd)
+{
+ /* Clear Interrupt status Register and enable int*/
+ pSDHC->sdhc_status = 0xFFFFFFFF;
+ pSDHC->sdhc_int_cntr = SDHC_INT;
+
+ /* Write command index */
+ pSDHC->sdhc_cmd = cmd->index;
+
+ /* Write command arg */
+ pSDHC->sdhc_arg = cmd->arg;
+
+ /* Write command data control */
+ pSDHC->sdhc_dat_cont = cmd->data_control;
+
+ /* Start clock */
+ start_clk();
+
+ /* Wait for the response of command end */
+ while(!(pSDHC->sdhc_status & SDHC_STATUS_END_CMD_RESP_MSK) );
+
+ /* Mask all interrupts */
+ pSDHC->sdhc_int_cntr = 0;
+
+ /* Check if an error occured */
+ return check_response();
+}
+
+static cyg_uint32 card_get_csd (void)
+{
+ command_t cmd;
+ response_t response;
+ cyg_uint32 status = FAIL;
+ //cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD9 for MMC/SD card */
+ /* 16bit card address is expected as Argument */
+ configure_cmd(&cmd,CMD9,card_address,READ,RESPONSE_136, DISABLE, ONE);
+
+ /* Send Command CMD9 to Extrace CSD register contents */
+ if(send_cmd_and_wait_resp(&cmd) != FAIL)
+ {
+ /* Read Command response */
+ read_response (RESPONSE_136, &response);
+ /* Assign Response to CSD Strcuture */
+ csd.csd0 = response.rsp0;
+ csd.csd1 = response.rsp1;
+ csd.csd2 = response.rsp2;
+ csd.csd3 = response.rsp3;
+ diag_printf1("CSD:%x:%x:%x:%x\n", csd.csd0, csd.csd1, csd.csd2, csd.csd3);
+ status = SUCCESS;
+ // save csd
+ memcpy(&g_csd_val, &csd, sizeof(struct csd_v1_0));
+ diag_printf1("g_csd_val.c_size_mult=0x%x\n", g_csd_val.c_size_mult);
+ diag_printf1("g_csd_val addr=%p\n", &g_csd_val);
+ }
+
+ return status;
+}
+
+static cyg_uint32 csd_get_value(CARD_SPECIFIC_DATA * pcsd, cyg_uint32 start_bit, cyg_uint32 end_bit)
+{
+ cyg_uint32 value;
+ if (start_bit == 84) {
+ value = g_csd_val.ccc;
+ } else if (start_bit == 62) {
+ value = (g_csd_val.c_size_up << 2) | g_csd_val.c_size_lo;
+ } else if (start_bit == 47) {
+ value = g_csd_val.c_size_mult;
+ } else if (start_bit == 80) {
+ value = g_csd_val.read_bl_len;
+ } else if (start_bit == 48) {
+ struct csd_v2_0 *ptr = (struct csd_v2_0 *) &g_csd_val;
+ value = (ptr->c_size_up << 16) | ptr->c_size_lo;
+ } else {
+ diag_printf1("start_bit=%d is not supported\n", start_bit);
+ while (1) {}
+ }
+ diag_printf1("start_bit=%d, end_bit=%d, value=0x%x\n", start_bit, end_bit, value);
+ return value;
+}
+
+static cyg_uint32 mmc_init(void)
+{
+ cyg_uint32 status = FAIL;
+ command_t cmd;
+ response_t resp;
+
+ cyg_uint32 card_status = 0;
+
+
+ card_address = 0x1<<16;
+ /* get cid of MMC */
+ /* Configure CMD2 for card */
+ configure_cmd(&cmd,CMD2,NO_ARG,READ,RESPONSE_136,DISABLE,ONE);
+
+ /* Send CMD2 to card to determine CID contents */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response(RESPONSE_136, &resp);
+ /* Assign CID values to mmc_cid structures */
+ card_id.cid0 = resp.rsp0;
+ card_id.cid1 = resp.rsp1;
+ card_id.cid2 = resp.rsp2;
+ card_id.cid3 = resp.rsp3;
+
+ //status = PASS;
+ }
+
+ /* get rca of MMC */
+ /* Configure CMD3 for MMC card */
+ configure_cmd(&cmd,CMD3,card_address,READ,RESPONSE_48_CRC, DISABLE, ONE);
+
+ /* Assigns relative address to the card */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response(RESPONSE_48_CRC, &resp);
+ card_status = resp.rsp0;
+ card_status = (((cyg_uint32) (card_status & CARD_STATE)) >> CARD_STATE_SHIFT);
+ if(card_status == IDENT)
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ return status;
+ }
+ }
+
+ card_get_csd();
+
+ configure_clk(trans_mode);
+
+ /*Send MMC to Transfer State */
+ /* Configure CMD7 for MMC card */
+ configure_cmd(&cmd,CMD7,card_address,READ,RESPONSE_48_CRC, DISABLE,ONE);
+
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
+ configure_cmd(&cmd,CMD13,card_address,READ,RESPONSE_48_CRC,DISABLE,ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response (RESPONSE_48_CRC, &resp);
+ card_status = resp.rsp0;
+ card_status = (((cyg_uint32) (card_status & CARD_STATE)) >> CARD_STATE_SHIFT);
+
+ if(card_status == TRAN)
+ {
+ status = PASS;
+ }
+ else
+ {
+ status= FAIL;
+ }
+ }
+ }
+
+ return status;
+}
+
+static cyg_uint32 check_sd(void)
+{
+ command_t cmd;
+ //command_response_t response;
+ cyg_uint32 count =0;
+ cyg_uint32 default_rca = 0;
+ cyg_uint32 ocr_value=0;
+ cyg_uint32 status = FAIL;
+ response_t resp;
+
+ configure_cmd(&cmd,CMD8,0x1AA,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ send_cmd_and_wait_resp(&cmd);
+
+ while((count < 3000) && (status != PASS))
+ {
+ /* Configure CMD55 for SD card */
+ configure_cmd(&cmd,CMD55,default_rca,READ,RESPONSE_48_CRC, DISABLE, ONE);
+
+ /* Send CMD55 to SD Memory card*/
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ //count++;
+ diag_printf1("CMD55 FAIL!\n");
+ break;
+ //continue;
+ }
+ else
+ {
+ ocr_value = ((cyg_uint32)(OCR_VALUE) & 0xFFFFFFFF);
+ /* Configure ACMD41 for SD card */
+ configure_cmd(&cmd,ACMD41,ocr_value,READ,RESPONSE_48_WITHOUT_CRC,DISABLE, ONE);
+ /* SEND ACMD41 to SD Memory card to determine OCR value */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ diag_printf1("ACMD41 FAIL!\n");
+ break;
+ }
+ else
+ {
+ /* Read Response from CMDRSP0 Register */
+ read_response(RESPONSE_48_WITHOUT_CRC, &resp);
+ ocr_value = resp.rsp0;
+ diag_printf1("SD: response ocr value: 0x%x\n", ocr_value);
+ /* Check if volatge lies in range or not*/
+ if((ocr_value & OCR_VALUE_MASK) == OCR_VALUE_MASK)
+ {
+ diag_printf1("response.cmd_rsp0: 0x%x\n", ocr_value);
+ /* Check if card busy bit is cleared or not */
+ if(ocr_value & CARD_BUSY)
+ {
+ status = PASS;
+ }
+ else
+ {
+ count++;
+ diag_printf1("SD: Busy! \n");
+ }
+ }
+ else
+ {
+ count++;
+ diag_printf("SD: response ocr value: 0x%x FAIL!\n", ocr_value);
+ }
+ }
+ }
+ }
+ return status;
+}
+
+
+static cyg_uint32 sd_init(cyg_uint32 bus_width)
+{
+ cyg_uint32 status = FAIL;
+ command_t cmd;
+ response_t resp;
+ cyg_uint32 card_status = 0;
+ cyg_uint32 read_resp = 0;
+
+ card_address = 0;
+
+ /* get cid of MMC */
+ /* Configure CMD2 for card */
+ configure_cmd(&cmd,CMD2,NO_ARG,READ,RESPONSE_136,DISABLE,ONE);
+
+ /* Send CMD2 to card to determine CID contents */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response(RESPONSE_136, &resp);
+ /* Assign CID values to mmc_cid structures */
+ card_id.cid0 = resp.rsp0;
+ card_id.cid1 = resp.rsp1;
+ card_id.cid2 = resp.rsp2;
+ card_id.cid3 = resp.rsp3;
+
+ //status = PASS;
+ }
+
+ /* get rca of card */
+ /* Configure CMD3 for card */
+ configure_cmd(&cmd,CMD3,NO_ARG,READ,RESPONSE_48_CRC, DISABLE, ONE);
+
+ /* Assigns relative address to the card */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response(RESPONSE_48_CRC, &resp);
+ card_status = resp.rsp0;
+ card_address = ((cyg_uint32) (card_status & (0xffffff00)));
+ card_status = (((cyg_uint32) (card_status & CARD_STATE)) >> CARD_STATE_SHIFT);
+ if(card_status == IDENT)
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ return status;
+ }
+ }
+
+ card_get_csd();
+ configure_clk(trans_mode);
+
+ /*Send card to Transfer State */
+ /* Configure CMD7 for card */
+ configure_cmd(&cmd,CMD7,card_address,READ,RESPONSE_48_CRC, DISABLE,ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
+ configure_cmd(&cmd,CMD13,card_address,READ,RESPONSE_48_CRC,
+ DISABLE,ONE);
+
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response (RESPONSE_48_CRC, &resp);
+ card_status = resp.rsp0;
+ card_status = (((cyg_uint32) (card_status & CARD_STATE)) >> CARD_STATE_SHIFT);
+ if(card_status == TRAN)
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ }
+ }
+ }
+
+
+ /* set bus width */
+ if ((bus_width == FOUR ) || (bus_width == ONE))
+ {
+ /* Configure CMD55 for SD card */
+ configure_cmd(&cmd,CMD55,card_address,READ,RESPONSE_48_CRC, DISABLE, ONE);
+
+ /* Issue CMD55 to SD Memory card*/
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response(RESPONSE_48_CRC, &resp);
+ read_resp = resp.rsp0;
+ if(read_resp & SD_R1_APP_CMD_MSK)
+ {
+ bus_width = (bus_width>>ONE);
+
+ /* Configure ACMD6 for SD card */
+ configure_cmd(&cmd,ACMD6,bus_width,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ /* Send ACMD6 to SD Memory card*/
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ return status;
+ }
+ else
+ {
+ status = PASS;
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+static cyg_uint32 check_mmc(void)
+{
+ command_t cmd;
+ response_t resp;
+ //cyg_uint32 response;
+ cyg_uint32 count=0;
+ cyg_uint32 ocr_value=0;
+ cyg_uint32 status = FAIL;
+
+
+ while((count < 10) && (status != PASS))
+ {
+ /* Configure CMD1 for MMC card */
+ configure_cmd(&cmd, CMD1, OCR_VALUE, READ, RESPONSE_48_WITHOUT_CRC,DISABLE, ONE);
+
+ /* Issue CMD1 to MMC card to determine OCR value */
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ count++;
+ diag_printf1("CMD1 FAIL!\n");
+ break;
+ //continue;
+ }
+ else
+ {
+ read_response(RESPONSE_48_WITHOUT_CRC, &resp);
+ ocr_value = resp.rsp0;
+
+ /* Mask OCR value against 0x00FF8000 and compare with response*/
+ if ((ocr_value & OCR_VALUE_MASK) == OCR_VALUE_MASK)
+ {
+ /* Check if card busy bit is cleared or not */
+ if(ocr_value & CARD_BUSY)
+ {
+ status = PASS;
+ }
+ else
+ {
+ count++;
+ }
+ }
+ else
+ {
+ count++;
+ }
+ }
+ }
+
+ return status;
+}
+
+static cyg_uint32 check_card(cyg_uint32 bus_width)
+{
+
+ cyg_uint32 status = FAIL;
+ Card_Mode = NONE;
+
+ //wait
+ hal_delay_us(2000);
+ diag_printf1("check SD\n");
+ if(check_sd() == PASS){
+ Card_Mode = SD;
+ diag_printf1("SD init\n");
+ status = sd_init(bus_width);
+ Card_type = ((csd.csd3 & CSD_STRUCT_MSK)? SD_CSD_2_0: SD_CSD_1_0);
+
+ /* Card Command Class */
+ CCC = csd_get_value(&csd, 84, 95);
+ }
+ else{
+ //wait
+ hal_delay_us(2000);
+ diag_printf1("check MMC\n");
+ if(check_mmc() == PASS){
+ Card_Mode = MMC;
+
+ status = mmc_init();
+ Card_type = ((csd.csd3 & CSD_STRUCT_MSK) >> CSD_STRUCT_SHIFT) + SD_CSD_2_0;
+ /* Card Command Class */
+ CCC = csd_get_value(&csd, 84, 95);
+ }
+ }
+ return status;
+}
+
+static void sdhc_init(cyg_uint32 base_address)
+{
+ cyg_uint32 iomux_base = 0x43FAC000;
+ cyg_uint32 gpio_base = 0x53FA4000;
+ cyg_uint32 iomux_sw_mux_ctl1 = readl(iomux_base + 0x18);
+ cyg_uint32 iomux_sw_mux_ctl2 = readl(iomux_base + 0x1C);
+ unsigned long reg;
+
+ iomux_sw_mux_ctl1 &= 0x000000FF;
+ iomux_sw_mux_ctl1 |= 0x12121200;
+ writel(iomux_sw_mux_ctl1, iomux_base + 0x18);
+
+ iomux_sw_mux_ctl2 &= 0xFF000000;
+ iomux_sw_mux_ctl2 |= 0x00121012;
+ writel(iomux_sw_mux_ctl2, iomux_base + 0x1C);
+
+ writel(0x0A529485, iomux_base + 0x168);
+ writel(0x0A5294A5, iomux_base + 0x16c);
+
+ /* Initialize base address */
+ pSDHC = (psdhc_t)base_address;
+}
+
+static void sdhc_reset(void)
+{
+ pSDHC->sdhc_clk = SDHC_CLK_RESET;
+ pSDHC->sdhc_clk = SDHC_CLK_RESET | SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+ pSDHC->sdhc_clk = SDHC_CLK_STOP;
+}
+
+static cyg_uint32 card_reset(void)
+{
+ command_t cmd;
+
+ configure_clk(iden_mode);
+
+ /*set size of read and response fifo */
+ //pSDHC->sdhc_read_to = 0xffff;
+ pSDHC->sdhc_read_to = 0x2DB4;
+ pSDHC->sdhc_response_to = 0xff;
+ hal_delay_us(20000);
+
+ /* CMD0 to reset SD/MMC cards */
+ configure_cmd(&cmd,CMD0,NO_ARG,READ, RESPONSE_NO, DISABLE, ONE);
+
+ return send_cmd_and_wait_resp(&cmd);
+}
+
+static void wait_transfer_done(cyg_uint32 mask)
+{
+ /* Wait interrupt (WRITE_OP_DONE/READ_OP_DONE) */
+ while(!(pSDHC->sdhc_status & mask));
+}
+
+static cyg_uint32 check_data(cyg_uint32 done_mask, cyg_uint32 crc_err_code_mask, cyg_uint32 crc_err_mask)
+{
+ cyg_uint32 status = FAIL;
+ /* Check whether the interrupt is an OP_DONE or a data time out or a CRC error */
+ if((pSDHC->sdhc_status & done_mask) &&
+ !(pSDHC->sdhc_status & crc_err_code_mask) &&
+ !(pSDHC->sdhc_status & crc_err_mask))
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ }
+ return status;
+}
+
+static cyg_uint32 check_card_status(void)
+{
+ command_t cmd;
+ cyg_uint32 status = PASS;
+ cyg_uint32 card_state;
+ cyg_uint32 read_resp;
+ response_t resp;
+ //cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ configure_cmd(&cmd,CMD13,card_address,READ,RESPONSE_48_CRC, DISABLE, ONE);
+
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ }
+ else
+ {
+ /* Read Command response */
+ read_response (RESPONSE_48_CRC, &resp);
+ read_resp = resp.rsp0;
+ card_state = ((cyg_uint32) (read_resp & CARD_STATE) >> CARD_STATE_SHIFT);
+
+ if(card_state == TRAN)
+ {
+ status = PASS;
+ }
+ else
+ {
+ status = FAIL;
+ }
+ }
+ return status;
+}
+
+
+
+/*==========================================================================
+FUNCTION: static cyg_uint32 card_get_capacity_size(void)
+DESCRIPTION:
+ this function will analize MMC/SD CSD register and return the capacity size (in unit of KB)
+
+ARGUMENTS PASSED:
+ None
+
+RETURN VALUE:
+ cyg_uint32
+
+PRE-CONDITIONS:
+ None
+
+POST-CONDITIONS:
+ None
+
+Detailed Description:
+==============================================================================*/
+cyg_uint32 card_get_capacity_size (void)
+{
+ cyg_uint32 capacity = 0;
+ cyg_uint32 c_size, c_size_mult, blk_len;
+
+ if(!csd.csd0 && !csd.csd1 && !csd.csd2 && !csd.csd3)
+ diag_printf("WARNINGS:card_init should be done first!\n");
+
+ switch(Card_type)
+ {
+ case SD_CSD_1_0:
+ case MMC_CSD_1_0:
+ case MMC_CSD_1_1:
+ case MMC_CSD_1_2:
+ case SD_CSD_2_0:
+ c_size = csd_get_value(&csd, 62, 73);
+ c_size_mult = csd_get_value(&csd, 47, 49);
+ blk_len = csd_get_value(&csd, 80, 83);
+ capacity = (((c_size+1) << (c_size_mult +2)) << blk_len) / 1024;
+ diag_printf1("c_size=0x%x, c_size_mult=0x%x, blk_len=0x%x, capacity(KB)=0x%x\n",
+ c_size, c_size_mult, blk_len, capacity);
+ break;
+#if 0 // todo
+ case SD_CSD_2_0:
+ //blk_len = csd_get_value(&csd, 80, 83);
+ c_size = csd_get_value(&csd, 48, 69);
+ capacity = (c_size + 1) * 512; // block length is fixed to 512B
+ diag_printf1("card capacity2=0x%x\n", capacity);
+ break;
+#endif
+ default:
+ break;
+ }
+ if (capacity > (0x80000000 / 1024))
+ HighCapacityCard = 1;
+ else
+ HighCapacityCard = 0;
+
+ return capacity;
+}
+
+cyg_uint32 mxcmci_init (cyg_uint32 bus_width, cyg_uint32 base_address)
+{
+ sdhc_init(base_address);
+
+ /* Software Reset to SDHC */
+ sdhc_reset();
+
+ /* Software Reset to card */
+ card_reset();
+
+ return check_card(bus_width);
+}
+
+cyg_uint32 mmc_data_read (cyg_uint32 *ram_ptr, cyg_uint32 length, cyg_uint32 offset)
+{
+ command_t cmd;
+ cyg_uint32 len, retry = 15;
+ cyg_uint32 status = PASS;
+ cyg_uint32 i, j, k = 0;
+
+ diag_printf1("\ncard_data_read !-- offset: %x, length: %x \n", offset, length);
+
+ len = (length + BLOCK_LEN - 1) & (~(BLOCK_LEN - 1));
+
+ if (HighCapacityCard)
+ offset = offset / 512;
+
+ /* Configure SDHC block and number of blocks */
+ pSDHC->sdhc_blk_len = BLOCK_LEN;
+ pSDHC->sdhc_nob = 0x1;
+
+ /* Configure CMD16 to set block length as 512 bytes.*/
+ configure_cmd(&cmd,CMD16,BLOCK_LEN,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ diag_printf1("CMD16 Fail!\n");
+ }
+ else
+ {
+ while(len != 0 && !status)
+ {
+ //check card status whether it is in transfer mode, so as to start next transfer
+ while((status = check_card_status())!=PASS);
+
+ diag_printf1("length left: %x \n", len);
+
+ /* Send CMD17 for single block read */
+ configure_cmd(&cmd,CMD17,offset,READ,RESPONSE_48_CRC, ENABLE, ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status= FAIL;
+ diag_printf1("CMD17 Fail!\n");
+ }
+ else
+ {
+ /* Enable int */
+ pSDHC->sdhc_int_cntr = SDHC_INT;
+ for(i = 0; i < BLOCK_LEN/16; i++)
+ {
+ /* Wait for BRR bit to be set */
+ while(!(pSDHC->sdhc_status & SDHC_STATUS_BUF_READ_RDY_MSK)) {
+ hal_delay_us(10);
+ }
+ for(j=0;j<4;j++)
+ {
+ /* Read 32 bit data from buffer access fifo */
+ *ram_ptr = pSDHC->sdhc_buffer_access;
+ ram_ptr++;
+ }
+ }
+ /* Wait for transfer complete */
+ wait_transfer_done(SDHC_STATUS_READ_OP_DONE_MSK);
+
+ /* Check for status errors (crc or timeout)*/
+ status = check_data(SDHC_STATUS_READ_OP_DONE_MSK, SDHC_STATUS_TIME_OUT_READ, SDHC_STATUS_READ_CRC_ERR_MSK);
+
+ offset = offset + BLOCK_LEN;
+ len = len - BLOCK_LEN;
+ //ram_ptr= ram_ptr + (BLOCK_LEN/4);
+ diag_printf1("length left3: %x \n", len);
+ }
+ }
+ }
+ diag_printf1("End of card data read!\n");
+ return status;
+}
+
+cyg_uint32 mmc_data_write (cyg_uint32 *ram_ptr, cyg_uint32 length, cyg_uint32 offset)
+{
+ command_t cmd;
+ cyg_uint32 len;
+ cyg_uint32 status = PASS;
+ cyg_uint32 i, j = 0;
+
+ len = (length + BLOCK_LEN - 1) & (~(BLOCK_LEN - 1));
+
+ /* Configure SDHC block and number of blocks */
+ pSDHC->sdhc_blk_len = BLOCK_LEN;
+ pSDHC->sdhc_nob = 0x1;
+
+ /* high capacity card uses sector mode */
+ if (HighCapacityCard)
+ offset = offset / 512;
+
+ /* Send CMD16 to set block length as 512 bytes.*/
+ configure_cmd(&cmd,CMD16,BLOCK_LEN,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ }
+ else
+ {
+ while(len != 0 && !status)
+ {
+ //check card status whether it is in transfer mode, so as to start next transfer
+ while((status = check_card_status())!=PASS);
+ /* Comfigure command CMD24 for block write--write address */
+ configure_cmd(&cmd,CMD24,offset,WRITE,RESPONSE_48_CRC, ENABLE, ONE);
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ }
+ else
+ {
+ /* Enable int */
+ pSDHC->sdhc_int_cntr = SDHC_INT;
+
+ for(i = 0; i < (BLOCK_LEN)/4; i++)
+ {
+ /* Wait for BWR bit to be set */
+ while(!(pSDHC->sdhc_status & SDHC_STATUS_BUF_WRITE_RDY_MSK));
+ //copy data from ram to sdhc buffer access fifo
+ pSDHC->sdhc_buffer_access = *ram_ptr;
+ ram_ptr++;
+ }
+
+ /* Wait for transfer done */
+ wait_transfer_done(SDHC_STATUS_WRITE_OP_DONE_MSK);
+
+ /* Check for status errors (crc or timeout)*/
+ status = check_data(SDHC_STATUS_WRITE_OP_DONE_MSK, 0, SDHC_STATUS_WRITE_CRC_ERR_MSK);
+
+ len = len - BLOCK_LEN;
+ offset += BLOCK_LEN;
+ //ram_ptr = ram_ptr + (BLOCK_LEN/4);
+ }
+ }
+ }
+ return status;
+}
+
+cyg_uint32 mmc_data_erase (cyg_uint32 offset, cyg_uint32 size)
+{
+ command_t cmd;
+ cyg_uint32 startEraseBlockCmd;
+ cyg_uint32 endEraseBlockCmd;
+ cyg_uint32 startBlock = offset/BLOCK_LEN;
+ cyg_uint32 endBlock = (offset+size)/BLOCK_LEN;
+ cyg_uint32 status = FAIL;
+
+ /* Fix erase operation on MX31/32 */
+ return 0;
+ if(Card_Mode == MMC) {
+ startBlock *=BLOCK_LEN;
+ endBlock *= BLOCK_LEN;
+ startEraseBlockCmd = CMD35;
+ endEraseBlockCmd = CMD36;
+ }
+ else if(Card_Mode == SD) {
+ startBlock *=BLOCK_LEN;
+ endBlock *= BLOCK_LEN;
+ startEraseBlockCmd = CMD32;
+ endEraseBlockCmd = CMD33;
+ }
+ if (HighCapacityCard) {
+ startBlock /= BLOCK_LEN;
+ endBlock /= BLOCK_LEN;
+ }
+
+ /* Configure start erase command to set first block*/
+ configure_cmd(&cmd,startEraseBlockCmd,startBlock,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ if((status = send_cmd_and_wait_resp(&cmd)) == PASS){
+
+ /* Configure end erase command to set end block*/
+ configure_cmd(&cmd,endEraseBlockCmd,endBlock,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ if((status = send_cmd_and_wait_resp(&cmd)) == PASS){
+ /* Comfigure command to start erase*/
+ configure_cmd(&cmd,CMD38,0,READ,RESPONSE_48_CRC, DISABLE, ONE);
+ if((status = send_cmd_and_wait_resp(&cmd)) == PASS){
+ //wait for completion
+ return status;
+ }
+ }
+ }
+
+ return status;
+}
+
+cyg_uint32 card_flash_query(void* data)
+{
+ command_t cmd;
+ cyg_uint32 status = PASS;
+ response_t response;
+
+ // Configure CMD2 for card No Argument is expected for CMD2
+ configure_cmd(&cmd,CMD2,NO_ARG,READ,RESPONSE_136, DISABLE, ONE);
+
+ // Send CMD2 to card to determine CID contents
+ if(send_cmd_and_wait_resp(&cmd) == FAIL)
+ {
+ status = FAIL;
+ diag_printf("%s: can't send query command\n", __FUNCTION__);
+ }
+ else
+ {
+ cyg_uint32* d = (cyg_uint32*)data;
+ // Read Command response
+ read_response (RESPONSE_136, &response);
+
+ // Assign CID values to mmc_cid structures
+ *d++ = response.rsp0;
+ *d++ = response.rsp1;
+ *d++= response.rsp2;
+ *d= response.rsp3;
+
+ // Assign cid_request as SUCCESS
+ status = PASS;
+ }
+ diag_printf( "%s(PASS?=%d):(ID=0x%x: 0x%x, 0x%x, 0x%x)\n",
+ __FUNCTION__, status,*(cyg_uint32*)(data), *(cyg_uint32*)((cyg_uint32)data+4),
+ *(cyg_uint8*)((cyg_uint32)data+8), *(cyg_uint8*)((cyg_uint32)data+12));
+ return;
+}
+
+
--- /dev/null
+//==========================================================================
+//
+// mxc_ata.c
+//
+// Flash programming to support ATA flash on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
+// Contributors: Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
+// Date: 2008-11-18 Initial version
+//
+//==========================================================================
+//
+
+#include <cyg/hal/hal_cache.h>
+#include <stdlib.h>
+#include <cyg/io/mxc_ata.h>
+#include <redboot.h>
+
+static struct fsl_ata_time_regs {
+ unsigned char time_off, time_on, time_1, time_2w;
+ unsigned char time_2r, time_ax, time_pio_rdx, time_4;
+ unsigned char time_9, time_m, time_jn, time_d;
+ unsigned char time_k, time_ack, time_env, time_rpx;
+ unsigned char time_zah, time_mlix, time_dvh, time_dzfs;
+ unsigned char time_dvs, time_cvh, time_ss, time_cyc;
+};
+extern void mxc_ata_iomux_setup(void);
+
+/*
+ * This structure contains the timing parameters for
+ * ATA bus timing in the 5 PIO modes. The timings
+ * are in nanoseconds, and are converted to clock
+ * cycles before being stored in the ATA controller
+ * timing registers.
+ */
+static struct {
+ short t0, t1, t2_8, t2_16, t2i, t4, t9, tA;
+} pio_specs[] = {
+ [0] = {
+ .t0 = 600, .t1 = 70, .t2_8 = 290, .t2_16 = 165, .t2i = 40, .t4 =
+ 30, .t9 = 20, .tA = 50,},
+ [1] = {
+ .t0 = 383, .t1 = 50, .t2_8 = 290, .t2_16 = 125, .t2i = 0, .t4 =
+ 20, .t9 = 15, .tA = 50,},
+ [2] = {
+ .t0 = 240, .t1 = 30, .t2_8 = 290, .t2_16 = 100, .t2i = 0, .t4 =
+ 15, .t9 = 10, .tA = 50,},
+ [3] = {
+ .t0 = 180, .t1 = 30, .t2_8 = 80, .t2_16 = 80, .t2i = 0, .t4 =
+ 10, .t9 = 10, .tA = 50,},
+ [4] = {
+ .t0 = 120, .t1 = 25, .t2_8 = 70, .t2_16 = 70, .t2i = 0, .t4 =
+ 10, .t9 = 10, .tA = 50,},
+ };
+
+#define NR_PIO_SPECS (sizeof pio_specs / sizeof pio_specs[0])
+
+static void update_timing_config(struct fsl_ata_time_regs *tp)
+{
+ unsigned int *lp = (unsigned int *) tp;
+ unsigned int *ctlp = (unsigned int *) ATA_BASE_ADDR;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ writel(*lp, ctlp);
+ lp++;
+ ctlp++;
+ }
+}
+
+static void set_ata_bus_timing(unsigned char xfer_mode)
+{
+ int speed = xfer_mode;
+ struct fsl_ata_time_regs tr = { 0 };
+ int T = 1 * 1000 * 1000 * 1000 / get_main_clock(IPG_CLK);
+
+ if (speed >= NR_PIO_SPECS)
+ return;
+ tr.time_off = 3;
+ tr.time_on = 3;
+
+ tr.time_1 = (pio_specs[speed].t1 + T) / T;
+ tr.time_2w = (pio_specs[speed].t2_8 + T) / T;
+
+ tr.time_2r = (pio_specs[speed].t2_8 + T) / T;
+ tr.time_ax = (pio_specs[speed].tA + T) / T + 2;
+ tr.time_pio_rdx = 1;
+ tr.time_4 = (pio_specs[speed].t4 + T) / T;
+
+ tr.time_9 = (pio_specs[speed].t9 + T) / T;
+
+ update_timing_config(&tr);
+}
+
+static unsigned char ata_sff_busy_wait(unsigned int bits, unsigned int max, unsigned int delay)
+{
+ unsigned char status;
+ unsigned int iterations = 1;
+
+ if (max != 0)
+ iterations = max;
+
+ do {
+ hal_delay_us(delay);
+ status = readb(ATA_BASE_ADDR + FSL_ATA_DCDR);
+ if (max != 0)
+ iterations--;
+ } while (status != 0xff && (status & bits) && (iterations > 0));
+
+ if (iterations == 0) {
+ diag_printf("ata_sff_busy_wait timeout status = %x\n", status);
+ return 0xff;
+ }
+
+ return status;
+}
+
+static void ata_sff_exec_command(unsigned short cmd)
+{
+ writeb(cmd, ATA_BASE_ADDR + FSL_ATA_DCDR);
+ readb(ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+ hal_delay_us(4);
+}
+
+static int ata_dev_set_feature(unsigned int feature)
+{
+ unsigned char status;
+
+ writeb(feature, ATA_BASE_ADDR + FSL_ATA_DFTR);
+ //Issue Set feature command
+ ata_sff_exec_command(ATA_CMD_SET_FEATURES);
+ status = ata_sff_busy_wait(ATA_BUSY, 5000, 500);
+
+ if (status == 0xff)
+ return 1;
+ if (status & ATA_ERR) {
+ return 1;
+ }
+ return 0;
+}
+
+void ata_id_string(int *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+/**
+ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an odd number.
+ *
+ * This function is identical to ata_id_string except that it
+ * trims trailing spaces and terminates the resulting string with
+ * null. @len must be actual maximum length (even number) + 1.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_c_string(int *id)
+{
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ ata_id_string(id, model_num, ATA_ID_PROD, ATA_ID_PROD_LEN);
+
+ model_num[ATA_ID_PROD_LEN] = '\0';
+
+ diag_printf("ATA Model number = %s\n", model_num);
+}
+
+static int read_dev_id(void)
+{
+ int i, tried_spinup = 0;
+ int CIS[256], err_mask = 0;
+
+retry:
+
+ //identify device command
+ ata_sff_exec_command(ATA_CMD_ID_ATA);
+ if (ata_sff_busy_wait(ATA_BUSY, 5000, 500) == 0xff)
+ return 1;
+ memset((void *)CIS, 0, sizeof(int) * 256);
+
+ for (i=0 ; i < 256; i++ ) {
+ CIS[i] = readw(ATA_BASE_ADDR + FSL_ATA_DRIVE_DATA);
+ }
+
+ if ((CIS[0] & (1 << 15)) == 0) {
+ if (!tried_spinup && (CIS[2] == 0x37c8 || CIS[2] == 0x738c)) {
+ tried_spinup = 1;
+ err_mask = ata_dev_set_feature(0x7);
+ if (err_mask && CIS[2] != 0x738c) {
+ diag_printf("ATA SPINUP Failed \n");
+ goto err_out;
+ }
+ if (CIS[2] == 0x37c8)
+ goto retry;
+ }
+ ata_id_c_string(CIS);
+ return 0;
+ } else {
+ diag_printf("ATA IDENTIFY DEVICE command Failed \n");
+ }
+err_out:
+ return 1;
+}
+
+static void write_sector_pio(unsigned int *addr, int num_of_sectors)
+{
+ int i, j;
+
+ for (i = 0; i < num_of_sectors; i++) {
+ for (j= 0; j < ATA_SECTOR_SIZE; j = j + 4) {
+ /* Write 4 bytes in each iteration */
+ writew((*addr & 0xFFFF), ATA_BASE_ADDR + FSL_ATA_DRIVE_DATA) ;
+ writew(((*addr >> 16 ) & 0xFFFF), ATA_BASE_ADDR + FSL_ATA_DRIVE_DATA) ;
+ addr++;
+ }
+ ata_sff_busy_wait(ATA_BUSY, 5000, 50);
+ }
+ readb(ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+}
+
+static void read_sector_pio(unsigned int *addr, int num_of_sectors)
+{
+ int i, j;
+ unsigned int data[2];
+
+ for (i = 0; i < num_of_sectors; i++) {
+ for (j = 0; j < ATA_SECTOR_SIZE; j = j + 4) {
+ /* Read 4 bytes in each iteration */
+ data[0] = readw(ATA_BASE_ADDR + FSL_ATA_DRIVE_DATA);
+ data[1] = readw(ATA_BASE_ADDR + FSL_ATA_DRIVE_DATA);
+ *addr = ((data[1] << 16) & 0xFFFF0000) | (data[0] & 0xFFFF);
+ addr++;
+ }
+ ata_sff_busy_wait(ATA_BUSY, 5000, 10);
+ }
+ readb(ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+}
+
+void ata_hwr_init(void)
+{
+ mxc_ata_iomux_setup();
+
+ /* Deassert the reset bit to enable the interface */
+ writel(FSL_ATA_CTRL_ATA_RST_B, ATA_BASE_ADDR + FSL_ATA_CONTROL);
+ writel(FSL_ATA_CTRL_ATA_RST_B | FSL_ATA_CTRL_FIFO_RST_B, ATA_BASE_ADDR + FSL_ATA_CONTROL);
+ /* Set initial timing and mode */
+ set_ata_bus_timing(PIO_XFER_MODE_4);
+ writeb(20, ATA_BASE_ADDR+ FSL_ATA_FIFO_ALARM) ; /* set fifo alarm to 20 halfwords, midway */
+
+ /* software reset */
+ writeb(ATA_IEN, ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+ hal_delay_us(20);
+ writeb(ATA_IEN | ATA_SRST, ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+ hal_delay_us(20);
+ writeb(ATA_IEN, ATA_BASE_ADDR + FSL_ATA_DRIVE_CONTROL);
+
+ writeb(0, ATA_BASE_ADDR + FSL_ATA_DDHR);
+ if (ata_sff_busy_wait(ATA_BUSY | ATA_DRQ, 6000, 1000) == 0xff) {
+ diag_printf("Failed to initialize the ATA drive\n");
+ return;
+ }
+
+ /* Read the device ID */
+ if (read_dev_id())
+ diag_printf("Failed to initialize the ATA drive\n");
+}
+
+static void ata_read_buf(int argc, char *argv[]);
+RedBoot_cmd("ata_read",
+ "Read Ata",
+ "-f <flash_addr> -b <mem_base> -l <image_length>",
+ ata_read_buf
+ );
+
+static void ata_program_buf(int argc, char *argv[]);
+RedBoot_cmd("ata_write",
+ "Write Ata",
+ "-f <flash_addr> -b <mem_base> -l <image_length>",
+ ata_program_buf
+ );
+
+static void ata_read_buf(int argc, char *argv[])
+{
+ unsigned int total_sectors, num_of_sectors;
+ unsigned char lba_addr[4];
+ CYG_ADDRESS addr, data;
+ unsigned long sect_addr;
+ unsigned long len;
+ unsigned char status;
+ bool mem_addr_set = false;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ struct option_info opts[3];
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&data, (bool *)&mem_addr_set, "memory base address");
+ init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&length_set, "image length [in FLASH]");
+
+ if (!scan_opts(argc, argv, 1, opts, 3, 0, 0, 0)) {
+ diag_printf("invalid arguments");
+ return;
+ }
+
+ if (!mem_addr_set || !flash_addr_set || !length_set) {
+ diag_printf("required parameter missing\n");
+ return;
+ }
+
+ if ((addr % ATA_SECTOR_SIZE) != 0) {
+ diag_printf("Need a sector-aligned (512 byte) address in ATA\n\n");
+ return;
+ }
+
+ total_sectors = (len / ATA_SECTOR_SIZE);
+ sect_addr = addr / ATA_SECTOR_SIZE;
+
+ do {
+ lba_addr[0] = sect_addr & 0xFF;
+ lba_addr[1] = (sect_addr >> 8) & 0xFF;
+ lba_addr[2] = (sect_addr >> 16) & 0xFF;
+ /* Enable the LBA bit */
+ lba_addr[3] = (1 << 6) | ((sect_addr >> 24) & 0xF);
+
+ if (total_sectors >= MAX_NUMBER_OF_SECTORS)
+ num_of_sectors = 0;
+ else
+ num_of_sectors = total_sectors;
+
+ ata_sff_busy_wait(ATA_BUSY | ATA_DRQ, 5000, 50);
+ writeb(num_of_sectors, ATA_BASE_ADDR + FSL_ATA_DSCR);
+ writeb(lba_addr[0], ATA_BASE_ADDR + FSL_ATA_DSNR);
+ writeb(lba_addr[1], ATA_BASE_ADDR + FSL_ATA_DCLR);
+ writeb(lba_addr[2], ATA_BASE_ADDR + FSL_ATA_DCHR);
+ writeb(lba_addr[3], ATA_BASE_ADDR + FSL_ATA_DDHR);
+
+ //Issue Read command
+ ata_sff_exec_command(ATA_CMD_READ);
+ status = ata_sff_busy_wait(ATA_BUSY, 5000, 50);
+ if (status & ATA_ERR) {
+ diag_printf("Error while issuing ATA Read command\n");
+ return;
+ }
+ if (num_of_sectors == 0) {
+ read_sector_pio((unsigned int *)data, MAX_NUMBER_OF_SECTORS);
+ total_sectors -= MAX_NUMBER_OF_SECTORS;
+ sect_addr += MAX_NUMBER_OF_SECTORS;
+ data += (MAX_NUMBER_OF_SECTORS * ATA_SECTOR_SIZE);
+ } else {
+ read_sector_pio((unsigned int *)data, num_of_sectors);
+ total_sectors -= num_of_sectors;
+ sect_addr += num_of_sectors;
+ data += (num_of_sectors * ATA_SECTOR_SIZE);
+ }
+ } while (total_sectors > 0);
+}
+
+static void ata_program_buf(int argc, char *argv[])
+{
+ int total_sectors, num_of_sectors, lba_addr[4];
+ CYG_ADDRESS addr, data;
+ unsigned long len;
+ unsigned long sect_addr;
+ unsigned char status;
+ bool mem_addr_set = false;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ struct option_info opts[3];
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&data, (bool *)&mem_addr_set, "memory base address");
+ init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&length_set, "image length [in FLASH]");
+
+ if (!scan_opts(argc, argv, 1, opts, 3, 0, 0, 0)) {
+ diag_printf("invalid arguments");
+ return;
+ }
+
+ if (!mem_addr_set || !flash_addr_set || !length_set) {
+ diag_printf("required parameter missing\n");
+ return;
+ }
+
+ if ((addr % ATA_SECTOR_SIZE) != 0) {
+ diag_printf("Need a sector-aligned (512 byte) address in ATA\n\n");
+ return;
+ }
+
+ total_sectors = (len / ATA_SECTOR_SIZE);
+ sect_addr = addr / ATA_SECTOR_SIZE;
+
+ do {
+ lba_addr[0] = sect_addr & 0xFF;
+ lba_addr[1] = (sect_addr >> 8) & 0xFF;
+ lba_addr[2] = (sect_addr >> 16) & 0xFF;
+ /* Enable the LBA bit */
+ lba_addr[3] = (1 << 6) | ((sect_addr >> 24) & 0xF);
+
+ if (total_sectors >= MAX_NUMBER_OF_SECTORS)
+ num_of_sectors = 0;
+ else
+ num_of_sectors = total_sectors;
+
+ ata_sff_busy_wait(ATA_BUSY | ATA_DRQ, 5000, 50);
+ writeb(num_of_sectors, ATA_BASE_ADDR + FSL_ATA_DSCR);
+ writeb(lba_addr[0], ATA_BASE_ADDR + FSL_ATA_DSNR);
+ writeb(lba_addr[1], ATA_BASE_ADDR + FSL_ATA_DCLR);
+ writeb(lba_addr[2], ATA_BASE_ADDR + FSL_ATA_DCHR);
+ writeb(lba_addr[3], ATA_BASE_ADDR + FSL_ATA_DDHR);
+
+ //Issue Write command
+ ata_sff_exec_command(ATA_CMD_WRITE);
+ ata_sff_busy_wait(ATA_BUSY, 5000, 50);
+ if (status & ATA_ERR) {
+ diag_printf("Error while issuing ATA Write command\n");
+ return;
+ }
+ if (num_of_sectors == 0) {
+ write_sector_pio((unsigned int *)data, MAX_NUMBER_OF_SECTORS);
+ total_sectors -= MAX_NUMBER_OF_SECTORS;
+ sect_addr += MAX_NUMBER_OF_SECTORS;
+ data += (MAX_NUMBER_OF_SECTORS * ATA_SECTOR_SIZE);
+ } else {
+ write_sector_pio((unsigned int *)data, num_of_sectors);
+ total_sectors -= num_of_sectors;
+ sect_addr += num_of_sectors;
+ data += (num_of_sectors * ATA_SECTOR_SIZE);
+ }
+ } while (total_sectors > 0);
+}
+
--- /dev/null
+// ==========================================================================
+//
+// mxc_mmc.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+// Support SD/MMC cards based on eSDHC controller.
+// only base functionality is implemented: Card init, read and write.
+// Erase and write protection are not supported so far.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#ifdef CYGPKG_REDBOOT_HAL_OPTIONS
+ #include <redboot.h>
+#endif
+#include <stdlib.h>
+#define _FLASH_PRIVATE_
+#include <cyg/io/flash.h>
+#include <cyg/io/mxc_mmc.h>
+
+#if defined(CYGPKG_HAL_ARM_MX31ADS) || defined(CYGPKG_HAL_ARM_MX31_3STACK)
+ #include <cyg/io/card_mx32.h>
+#endif
+
+#if defined(CYGPKG_HAL_ARM_MX25_3STACK) || defined(CYGPKG_HAL_ARM_MX35_3STACK) || defined(CYGPKG_HAL_ARM_MX37_3STACK) || defined(CYGPKG_HAL_ARM_MX51)
+ #include <cyg/io/mxcmci_core.h>
+#endif
+
+//hardware init for MMC card
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_hwr_init(void)
+#else
+int mmcflash_hwr_init(void)
+#endif
+{
+ cyg_uint32 status = FAIL;
+ cyg_uint32 capacity = 0;
+ int i = 5;
+ while (status != SUCCESS && i--) {
+ hal_delay_us(100000);
+ status = mxcmci_init(1, ESDHC1_REG_BASE);
+ }
+
+ if (FAIL == status) {
+ diag_printf("Error: Card initialization failed!\n");
+ return status;
+ }
+ diag_printf("Card initialization successful!\n");
+ //set flash_info structure
+ externC struct flash_info flash_info;
+ flash_dprintf(FLASH_DEBUG_MAX,"%s: status=%d\n", __FUNCTION__, status);
+ capacity = card_get_capacity_size(); // in unit of KB
+ diag_printf("Actual capacity of the card is %dKB\n", capacity);
+ //if the capacity size is larger than 2G or equals zero, force to be 2G
+ if (capacity > 0x200000 || capacity == 0) {
+ capacity = 0x200000;
+ }
+ diag_printf("Redboot uses %dKB\n", capacity);
+
+ flash_info.block_size = 0x20000; // = 128KB
+ flash_info.blocks = capacity / 128;
+ flash_info.start = (void *)MXC_MMC_BASE_DUMMY;
+ flash_info.end = (void *)(MXC_MMC_BASE_DUMMY + flash_info.block_size * flash_info.blocks);
+
+ return status;
+}
+
+
+// Read data into buffer
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_read_buf(void* addr, void* data, int len)
+#else
+int mmcflash_read_buf(void* addr, void* data, int len)
+#endif
+{
+ flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug:1:addr=%X, data=%X, len=%d\n", __FUNCTION__, (cyg_uint32)addr, (cyg_uint32)data, len);
+ return mmc_data_read(data, len, (cyg_uint32)addr);
+}
+
+
+// Get CID to pointer data (should hold 4*4 byte space)
+#ifndef MXCFLASH_SELECT_MULTI
+void flash_query(void* data)
+#else
+void mmcflash_query(void* data)
+#endif
+{
+ return card_flash_query(data);
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_hwr_map_error(int e)
+#else
+int mmcflash_hwr_map_error(int e)
+#endif
+{
+ return e;
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+bool flash_code_overlaps(void *start, void *end)
+#else
+bool mmcflash_code_overlaps(void *start, void *end)
+#endif
+{
+ extern char _stext[], _etext[];
+
+ bool ret = ((((unsigned long)&_stext >= (unsigned long)start) &&
+ ((unsigned long)&_stext < (unsigned long)end)) ||
+ (((unsigned long)&_etext >= (unsigned long)start) &&
+ ((unsigned long)&_etext < (unsigned long)end)));
+ flash_dprintf(FLASH_DEBUG_MAX,"%s: flash code overlap::%d\n", __FUNCTION__, ret);
+ return ret;
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_erase_block(void* block, unsigned int size)
+#else
+int mmcflash_erase_block(void* block, unsigned int size)
+#endif
+{
+ flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug:1:block=0x%X, size=%d\n", __FUNCTION__, (cyg_uint32)block, size);
+ return mmc_data_erase((cyg_uint32)block, size);
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_program_buf(void* addr, void* data, int len)
+#else
+int mmcflash_program_buf(void* addr, void* data, int len)
+#endif
+{
+ flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug:1:addr=0x%X, data=0x%X, len=%d\n", __FUNCTION__, (cyg_uint32)addr, (cyg_uint32)data, len);
+ return mmc_data_write((cyg_uint32*)data, len, (cyg_uint32)addr);
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_lock_block(void* block)
+#else
+int mmcflash_lock_block(void* block)
+#endif
+{
+ //not support yet
+ return 0;
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_unlock_block(void* block, int block_size, int blocks)
+#else
+int mmcflash_unlock_block(void* block, int block_size, int blocks)
+#endif
+{
+ //not support yet
+ return 0;
+}
+
+void mxc_mmc_print_info(void)
+{
+ extern card_type Card_type;
+ cyg_uint32 i = 0;
+ cyg_uint8* cmd_class[] = {
+ "basic", //class 0
+ "reserved", //class 1
+ "block-read", //class 2
+ "reserved", //class 3
+ "block-write", //class 4
+ "erase", //class 5
+ "write-protect", //class 6
+ "lock", //class 7
+ "app-command", //class 8
+ "IO-mode", //class 9
+ "switch", //class 10
+ "reserved" //class 11
+ };
+
+ switch (Card_type) {
+ case SD_CSD_1_0:
+ diag_printf("\nBooting from [SD card, CSD Version 1.0]\n");
+ break;
+ case SD_CSD_2_0:
+ diag_printf("\nBooting from [SD card, CSD Version 2.0]\n");
+ break;
+ case MMC_CSD_1_0:
+ diag_printf("\nBooting from [MMC card, CSD Version 1.0]\n");
+ break;
+ case MMC_CSD_1_1:
+ diag_printf("\nBooting from [MMC card, CSD Version 1.1]\n");
+ break;
+ case MMC_CSD_1_2:
+ diag_printf("\nBooting from [MMC card, CSD Version 1.2]\n");
+ break;
+ case MMC_UNKNOWN:
+ diag_printf("\nBooting from [MMC card (?) ]\n");
+ break;
+ default:
+ diag_printf("\nBooting from [unknown version card ]\n");
+ break;
+ }
+ diag_printf("Supporting Card Command Class: ");
+ for (;i<12;i++) {
+ if (CCC & (1 << i))
+ diag_printf("%s, ", cmd_class[i]);
+ }
+
+ diag_printf("\n\n");
+}
--- /dev/null
+// ==========================================================================
+//
+// mxcmci_core.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/io/mxcmci_host.h>
+#include <cyg/io/mxcmci_core.h>
+#include <cyg/io/mxcmci_mmc.h>
+#include <cyg/hal/hal_soc.h>
+#include <cyg/io/mxc_mmc.h>
+
+static cyg_uint32 csd_get_value(cyg_uint32 * pcsd, cyg_uint32 start_bit,
+ cyg_uint32 end_bit);
+
+#define MMCSD_INIT_DELAY 64
+
+cyg_uint32 Card_rca = 0x1; /* Relative Card Address */
+card_ident Card_identification; /* Card Identification Data */
+card_type Card_type; /* Card Type */
+cyg_uint32 MMC_Spec_vers = 0x1; /* Spec vers used for MMC */
+card_specific_data csd; /* Global variable for Card Specific Data */
+cyg_uint32 Card_capacity_size = 0; /*Card capacity size */
+cyg_uint32 CCC = 0; /* Card Command Class */
+int Card_Mode = 2;
+int HighCapacityCard = 0;
+
+/*==========================================================================
+ Global FUNCTIONS
+==========================================================================*/
+
+cyg_uint32 mxcmci_init(cyg_uint32 bus_width, cyg_uint32 base_address)
+{
+ cyg_uint32 init_status = FAIL;
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to init base address...\n",
+ __FUNCTION__);
+ /* initialize Interface Controller */
+ host_init(base_address);
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to software reset...\n",
+ __FUNCTION__);
+
+ /* Software Reset to Interface Controller */
+ host_reset(ESDHC_ONE_BIT_SUPPORT, ESDHC_LITTLE_ENDIAN_MODE);
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to set identification freq...\n",
+ __FUNCTION__);
+
+ /* Enable Identification Frequency */
+ host_cfg_clock(IDENTIFICATION_FREQ);
+
+ /* Add delay of 2 msec, let mmc/sd card to initialize */
+ hal_delay_us(2 * 1000);
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to software resetto card...\n",
+ __FUNCTION__);
+
+ //diag_printf("SW Reset...\n");
+ /* Issue Software Reset to card */
+ if (mxcmci_software_reset())
+ return FAIL;
+
+ //diag_printf("Check Card...\n");
+
+ /* Check if the card is SD Memory Card */
+ if (!sd_voltage_validation()) {
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to verify SD card...\n",
+ __FUNCTION__);
+ /* Call SD Initialization Function */
+ init_status = sd_init(bus_width);
+ Card_type =
+ ((csd.csd3 & CSD_STRUCT_MSK) ? SD_CSD_2_0 : SD_CSD_1_0);
+ Card_Mode = 1;
+ /* Card Command Class */
+ CCC = csd_get_value(&csd, 84, 95);
+ } else {
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:try to verify MMC card...\n",
+ __FUNCTION__);
+ /* Check if the card is MMC Memory Card */
+ if (!mmc_voltage_validation()) {
+
+ /* Call MMC Initialization Function */
+ init_status = mmc_init(bus_width);
+ Card_Mode = 0;
+ Card_type = ((csd.csd3 & CSD_STRUCT_MSK) >> CSD_STRUCT_SHIFT) + SD_CSD_2_0;
+ MMC_Spec_vers = (csd.csd3 & MMC_CSD_SPEC_VERS_MASK) >> MMC_CSD_SPEC_VERS_SHIFT;
+ /* Card Command Class */
+ CCC = csd_get_value(&csd, 84, 95);
+ }
+ }
+
+ return init_status;
+}
+
+/*==========================================================================
+FUNCTION: static cyg_uint32 card_get_csd (void)
+DESCRIPTION:
+ this function will read MMC/SD CSD register and store in the global Variable.
+
+ARGUMENTS PASSED:
+ None
+
+RETURN VALUE:
+ cyg_uint32
+
+PRE-CONDITIONS:
+ None
+
+POST-CONDITIONS:
+ None
+
+Detailed Description:
+ 1.Send CMD9 to get CSD value of MMC/SD Card.
+ 2.Extract CSD value from CMDRSP0,CMDRSP1,CMDRSP2,CMDRSP3 registers.
+==============================================================================*/
+cyg_uint32 card_get_csd(void)
+{
+
+ command_t cmd;
+ command_response_t response;
+ cyg_uint32 status = FAIL;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD9 for MMC/SD card */
+ /* 16bit card address is expected as Argument */
+ mxcmci_cmd_config(&cmd, CMD9, card_address, READ, RESPONSE_136,
+ DATA_PRESENT_NONE, ENABLE, DISABLE);
+
+ /* Issue Command CMD9 to Extrace CSD register contents */
+
+ if (host_send_cmd(&cmd) != FAIL) {
+ /* Read Command response */
+ response.format = RESPONSE_136;
+ host_read_response(&response);
+
+ /* Assign Response to CSD Strcuture */
+ csd.csd0 = response.cmd_rsp0;
+ csd.csd1 = response.cmd_rsp1;
+ csd.csd2 = response.cmd_rsp2;
+ csd.csd3 = response.cmd_rsp3;
+
+ flash_dprintf(FLASH_DEBUG_MAX, "CSD:%x:%x:%x:%x\n", csd.csd0,
+ csd.csd1, csd.csd2, csd.csd3);
+ status = SUCCESS;
+ } else {
+ diag_printf("Get CSD Failed.\n");
+ }
+
+ return status;
+
+}
+
+static cyg_uint32 csd_get_value(cyg_uint32 * pcsd, cyg_uint32 start_bit,
+ cyg_uint32 end_bit)
+{
+ cyg_uint32 index = (start_bit / 32);
+ cyg_uint32 end_index = (end_bit / 32);
+ cyg_uint32 offset = (start_bit - 8) % 32;
+ cyg_uint32 end_offset = (end_bit - 8) % 32;
+ cyg_uint32 value;
+ cyg_uint32 temp;
+ //pcsd = &(csd.csd0);
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "start_bit=%d, end_bit=%d, index=%d, end_index=%d, offset=%d\n",
+ start_bit, end_bit, index, end_index, offset);
+
+ if (index == end_index) {
+ flash_dprintf(FLASH_DEBUG_MAX, "onl1y in index register\n");
+ value =
+ (*((cyg_uint32 *) ((cyg_uint32) pcsd + (index << 2)))) &
+ ((1 << (end_offset + 1)) - (1 << offset));
+ value = (value >> offset);
+ } else {
+ flash_dprintf(FLASH_DEBUG_MAX, "index and index+1 registers\n");
+ value =
+ *((cyg_uint32 *) ((cyg_uint32) pcsd +
+ (index << 2))) & (0xFFFFFFFF -
+ (1 << offset) + 1);
+ value = (value >> offset);
+ temp = (1 << (offset + end_bit - start_bit - 31)) - 1;
+ temp =
+ (*((cyg_uint32 *) ((cyg_uint32) pcsd + (index + 1) * 4)) &
+ temp);
+ value += temp << (32 - offset);
+ }
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:value=%x (CSD:%x:%x:%x:%x)\n",
+ __FUNCTION__, value, *pcsd, *(pcsd + 1), *(pcsd + 2),
+ *(pcsd + 3));
+ return value;
+
+}
+
+cyg_uint32 card_get_capacity_size(void)
+{
+ cyg_uint32 capacity = 0;
+ cyg_uint32 c_size, c_size_mult, blk_len;
+
+ if (!csd.csd0 && !csd.csd1 && !csd.csd2 && !csd.csd3)
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "WARNINGS:mxcmci_init should be done first!\n");
+
+ switch (Card_type) {
+ case SD_CSD_1_0:
+ case MMC_CSD_1_0:
+ case MMC_CSD_1_1:
+ case MMC_CSD_1_2:
+ c_size = csd_get_value(&csd, 62, 73);
+ c_size_mult = csd_get_value(&csd, 47, 49);
+ blk_len = csd_get_value(&csd, 80, 83);
+ capacity = (c_size + 1) << (c_size_mult + 2 + blk_len - 10);
+ break;
+ case SD_CSD_2_0:
+ //blk_len = csd_get_value(&csd, 80, 83);
+ c_size = csd_get_value(&csd, 48, 69);
+ capacity = (c_size + 1) * 512; /* block length is fixed to 512B */
+ break;
+ default:
+ capacity = 1;
+ break;
+ }
+
+ /* check whether the card is high capacity card */
+ if(capacity>2*1024*1024)
+ HighCapacityCard = 1;
+ else
+ HighCapacityCard = 0;
+
+ return capacity;
+
+}
+
+cyg_uint32 mxcmci_data_read(cyg_uint32 * dest_ptr, cyg_uint32 len,
+ cyg_uint32 offset)
+{
+ cyg_uint32 read_status = FAIL;
+
+ read_status = mmc_data_read(dest_ptr, len, offset);
+
+ if (read_status) {
+ len = 0;
+ }
+ return len;
+
+}
+
+cyg_uint32 mxcmci_software_reset(void)
+{
+ command_t cmd;
+ cyg_uint32 response = FAIL;
+
+ /*Configure CMD0 for MMC/SD card */
+ /*CMD0 doesnt expect any response */
+ mxcmci_cmd_config(&cmd, CMD0, NO_ARG, READ, RESPONSE_NONE,
+ DATA_PRESENT_NONE, DISABLE, DISABLE);
+
+ /*Issue CMD0 to MMC/SD card to put in active state */
+ if (host_send_cmd(&cmd) != FAIL) {
+ response = SUCCESS;
+ } else {
+ diag_printf("Card SW Reset Failed.\n");
+ }
+
+ return response;
+}
+
+cyg_uint32 mxcmci_get_cid(void)
+{
+
+ command_t cmd;
+ cyg_uint32 cid_request = FAIL;
+ command_response_t response;
+
+ /* Configure CMD2 for card */
+ /* No Argument is expected for CMD2 */
+ mxcmci_cmd_config(&cmd, CMD2, NO_ARG, READ, RESPONSE_136,
+ DATA_PRESENT_NONE, ENABLE, DISABLE);
+
+ /* Issue CMD2 to card to determine CID contents */
+ if (host_send_cmd(&cmd) == FAIL) {
+ cid_request = FAIL;
+ diag_printf("Send CMD2 Failed.\n");
+ } else {
+ /* Read Command response */
+ response.format = RESPONSE_136;
+ host_read_response(&response);
+
+ /* Assign CID values to mmc_cid structures */
+ Card_identification.cid0 = response.cmd_rsp0;
+ Card_identification.cid1 = response.cmd_rsp1;
+ Card_identification.cid2 = response.cmd_rsp2;
+ Card_identification.cid3 = response.cmd_rsp3;
+
+ /* Assign cid_request as SUCCESS */
+ cid_request = SUCCESS;
+ }
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:CID=%X:%X:%X:%X\n", __FUNCTION__,
+ Card_identification.cid0, Card_identification.cid1,
+ Card_identification.cid2, Card_identification.cid3);
+ return cid_request;
+}
+
+cyg_uint32 mxcmci_trans_prepare(void)
+{
+ command_t cmd;
+ cyg_uint32 card_state = 0;
+ cyg_uint32 transfer_status = 0;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD7 for MMC card */
+ /* 16bit card address is expected as Argument */
+ mxcmci_cmd_config(&cmd, CMD7, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Sending the card from stand-by to transfer state */
+ if (host_send_cmd(&cmd) == FAIL) {
+ transfer_status = FAIL;
+ diag_printf("Send CMD7 Failed.\n");
+ } else {
+
+ /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
+ mxcmci_cmd_config(&cmd, CMD13, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ transfer_status = FAIL;
+ diag_printf("Send CMD13 Failed.\n");
+ } else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ card_state = CURR_CARD_STATE(response.cmd_rsp0);
+
+ if (card_state == TRAN) {
+ transfer_status = SUCCESS;
+
+ } else {
+ diag_printf("card_state: 0x%x\n", card_state);
+ transfer_status = FAIL;
+ }
+ }
+
+ }
+
+ return transfer_status;
+
+}
+
+cyg_uint32 mxcmci_trans_status(void)
+{
+ command_t cmd;
+ cyg_uint32 card_state = 0;
+ cyg_uint32 transfer_status = 0;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
+ mxcmci_cmd_config(&cmd, CMD13, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("Fail, CMD13\n");
+ transfer_status = FAIL;
+ }
+
+ else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ card_state = CURR_CARD_STATE(response.cmd_rsp0);
+
+ if (card_state == TRAN) {
+ transfer_status = SUCCESS;
+ //diag_printf("card_state: 0x%x\n", card_state);
+ }
+
+ else {
+ //diag_printf("card_state: 0x%x\n", card_state);
+ transfer_status = FAIL;
+ }
+ }
+ return transfer_status;
+
+}
+
+void mxcmci_cmd_config(command_t * cmd_config, cyg_uint32 index,
+ cyg_uint32 argument, xfer_type_t transfer,
+ response_format_t format, data_present_select data,
+ crc_check_enable crc, cmdindex_check_enable cmdindex)
+{
+
+ command_t *cmd;
+
+ /* Assign cmd to cmd_config */
+ cmd = cmd_config;
+
+ /* Configure Command index */
+ cmd->command = index;
+
+ /* Configure Command Argument */
+ cmd->arg = argument;
+
+ /* Configure Data transfer type */
+ cmd->data_transfer = transfer;
+
+ /* Configure Response Format */
+ cmd->response_format = format;
+
+ /* Configure Data Present Select */
+ cmd->data_present = data;
+
+ /* Configiure CRC check Enable */
+ cmd->crc_check = crc;
+
+ /*Configure Command index check enable */
+ cmd->cmdindex_check = cmdindex;
+
+ /* if multi-block is used */
+ if (CMD18 == index || CMD25 == index) {
+ /*Configure Block count enable */
+ cmd->block_count_enable_check = ENABLE;
+ /*Configure Multi single block select */
+ cmd->multi_single_block = MULTIPLE;
+ } else {
+ /*Configure Block count enable */
+ cmd->block_count_enable_check = DISABLE;
+
+ /*Configure Multi single block select */
+ cmd->multi_single_block = SINGLE;
+ }
+}
--- /dev/null
+// ==========================================================================
+//
+// mxcmci_host.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/io/mxcmci_host.h>
+#include <cyg/io/mxcmci_core.h>
+#include <cyg/io/mxcmci_mmc.h>
+#include <cyg/hal/hal_soc.h>
+#include <cyg/io/mxc_mmc.h>
+
+host_register_ptr esdhc_base_pointer;
+extern void mxc_mmc_init(unsigned int module_base);
+
+static void esdhc_cmd_config(command_t *);
+static int esdhc_wait_end_cmd_resp_intr(void);
+static cyg_uint32 esdhc_check_response(void);
+static void esdhc_wait_buf_rdy_intr(cyg_uint32, multi_single_block_select);
+static void esdhc_wait_op_done_intr(cyg_uint32);
+static cyg_uint32 esdhc_check_data(cyg_uint32, cyg_uint32, cyg_uint32);
+static void esdhc_set_data_transfer_width(cyg_uint32 data_transfer_width);
+static void esdhc_set_endianness(cyg_uint32 endian_mode);
+static int esdhc_check_for_send_cmd(int data_present);
+
+void host_reset(cyg_uint32 data_transfer_width, cyg_uint32 endian_mode)
+{
+ int counter = 0;
+
+ /* Reset the entire host controller by writing 1 to RSTA bit of SYSCTRL Register */
+ esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_RESET;
+
+ //use WDOG timer: 3 ms delay
+ hal_delay_us(3 * 1000);
+
+ /* Wait for clearance of CIHB and CDIHB Bits */
+ while (esdhc_base_pointer->present_state & ESDHC_CMD_INHIBIT) {
+ if (counter++ > 200) {
+ diag_printf
+ ("%s: something goes wrong with the DSDHC and int is not received!\n",
+ __FUNCTION__);
+ counter = 0;
+ break;
+ }
+ }
+
+ /* send 80 clock ticks for card to power up */
+ esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_INIT;
+
+ /* Set data bus width of ESDCH */
+ esdhc_set_data_transfer_width(data_transfer_width);
+
+ /* Set Endianness of ESDHC */
+ esdhc_set_endianness(endian_mode);
+
+}
+
+void esdhc_softreset(cyg_uint32 mask)
+{
+ //wait max timeout 100ms
+ cyg_uint32 timeout = 100;
+
+ esdhc_base_pointer->system_control |= mask;
+
+ /* hw clears the bit when it's done */
+ while (esdhc_base_pointer->system_control & mask) {
+ if (timeout == 0) {
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "%s:Reset 0x%X never complete!\n");
+ return;
+ }
+ timeout--;
+ hal_delay_us(100);
+ }
+}
+
+void host_init(cyg_uint32 base_address)
+{
+ esdhc_base_pointer = (host_register_ptr) base_address;
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s: interface_esdc=%d\n", __FUNCTION__,
+ base_address);
+
+ mxc_mmc_init(base_address);
+}
+
+void host_cfg_clock(sdhc_freq_t frequency)
+{
+ unsigned int timeout = 9000;
+ /* Enable ipg_perclk, HCLK enable, IPG Clock enable. */
+ esdhc_base_pointer->system_control |= ESDHC_CLOCK_ENABLE;
+
+ esdhc_base_pointer->system_control |= 0xe0000; //set timeout counter
+
+ /* Clear DTOCV SDCLKFS bits, clear SD clk enable bit to change frequency */
+ esdhc_base_pointer->system_control &= ESDHC_FREQ_MASK;
+
+ /* Disable SD clock */
+ esdhc_base_pointer->system_control &= ~ESDHC_ENABLE;
+
+ if (frequency == IDENTIFICATION_FREQ) {
+ /* Input frequecy to eSDHC is 36 MHZ */
+ /* PLL3 is the source of input frequency */
+ /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency below 400 KHZ (70.31 KHZ) */
+ esdhc_base_pointer->system_control |= ESDHC_IDENT_FREQ;
+ } else if (frequency == OPERATING_FREQ) {
+ /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency around 25 MHz.(18 MHz) */
+ esdhc_base_pointer->system_control |= ESDHC_OPERT_FREQ;
+ }
+
+ /* Wait for clock to be steady */
+ while (((esdhc_base_pointer->present_state & 0x8) == 0) && (timeout != 0)) {
+ timeout--;
+ hal_delay_us(10);
+ }
+
+ /* Enable SD clock */
+ esdhc_base_pointer->system_control |= ESDHC_ENABLE;
+}
+
+static void esdhc_set_data_transfer_width(cyg_uint32 data_transfer_width)
+{
+
+ /* Set DWT bit of protocol control register according to bus_width */
+ esdhc_base_pointer->protocol_control &= ~0x6;
+ esdhc_base_pointer->protocol_control |= data_transfer_width;
+
+}
+
+static void esdhc_set_endianness(cyg_uint32 endian_mode)
+{
+
+ /* Set DWT bit of protocol control register according to bus_width */
+ esdhc_base_pointer->protocol_control |= endian_mode;
+
+}
+
+cyg_uint32 host_send_cmd(command_t * cmd)
+{
+
+ /* Clear Interrupt status register */
+ esdhc_base_pointer->interrupt_status = ESDHC_CLEAR_INTERRUPT;
+ //esdhc_base_pointer->interrupt_status = 0x117f01ff;
+
+ /* Enable Interrupt */
+ esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
+ //esdhc_base_pointer->interrupt_status_enable |= 0x007f0123;
+
+#if 0
+ if (esdhc_check_for_send_cmd(cmd->data_present)) {
+ diag_printf("Data/Cmd Line Busy.\n");
+ return FAIL;
+ }
+#endif
+
+ /* Configure Command */
+ esdhc_cmd_config(cmd);
+
+ /* Wait interrupt (END COMMAND RESPONSE) */
+ //diag_printf("Wait for CMD Response.\n");
+ if (esdhc_wait_end_cmd_resp_intr()) {
+ diag_printf("Wait CMD (%d) RESPONSE TIMEOUT.\n", cmd->command);
+ return FAIL;
+ }
+ //Just test for Erase functionality:Lewis-20080505:
+ if (cmd->command == CMD38) {
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:Check DAT0 status:\n",
+ __FUNCTION__);
+ //while(((esdhc_base_pointer->present_state) & 0x01000004)){
+ // flash_dprintf(FLASH_DEBUG_MAX,".");
+ // hal_delay_us(1000);
+ //}
+ /* I'm not sure the minimum value of delay */
+ hal_delay_us(100000);
+ hal_delay_us(100000);
+ hal_delay_us(100000);
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "\nCheck DAT0 status DONE: present_state=%x\n",
+ (cyg_uint32) (esdhc_base_pointer->present_state));
+ }
+
+ /* Mask all interrupts */
+ //esdhc_base_pointer->interrupt_signal_enable =0;
+
+ /* Check if an error occured */
+ return esdhc_check_response();
+}
+
+static void esdhc_cmd_config(command_t * cmd)
+{
+ unsigned int transfer_type;
+
+ /* Write Command Argument in Command Argument Register */
+ esdhc_base_pointer->command_argument = cmd->arg;
+
+ /* *Configure e-SDHC Register value according to Command */
+ transfer_type = (((cmd->data_transfer) << DATA_TRANSFER_SHIFT) |
+ ((cmd->response_format) << RESPONSE_FORMAT_SHIFT) |
+ ((cmd->data_present) << DATA_PRESENT_SHIFT) |
+ ((cmd->crc_check) << CRC_CHECK_SHIFT) |
+ ((cmd->cmdindex_check) << CMD_INDEX_CHECK_SHIFT) |
+ ((cmd->command) << CMD_INDEX_SHIFT) |
+ ((cmd->
+ block_count_enable_check) <<
+ BLOCK_COUNT_ENABLE_SHIFT) | ((cmd->
+ multi_single_block) <<
+ MULTI_SINGLE_BLOCK_SELECT_SHIFT));
+
+ esdhc_base_pointer->command_transfer_type = transfer_type;
+
+ //diag_printf("arg: 0x%x | tp: 0x%x\n", esdhc_base_pointer->command_argument, esdhc_base_pointer->command_transfer_type);
+
+}
+
+static int esdhc_wait_end_cmd_resp_intr(void)
+{
+ /* Wait interrupt (END COMMAND RESPONSE) */
+ cyg_uint32 i = 50000;
+ while (!
+ ((esdhc_base_pointer->
+ interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK) && i) {
+ i--;
+ hal_delay_us(10);
+ //diag_printf("0x%x\n", esdhc_base_pointer->interrupt_status);
+ }
+
+ if (!
+ ((esdhc_base_pointer->
+ interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK)) {
+ //diag_printf("%s: can't get END COMMAND RESPONSE! Tried %d times\n", __FUNCTION__, (5000000-i));
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static cyg_uint32 esdhc_check_response(void)
+{
+ cyg_uint32 status = FAIL;
+
+ /* Check whether the interrupt is an END_CMD_RESP
+ * or a response time out or a CRC error
+ */
+ if ((esdhc_base_pointer->
+ interrupt_status & ESDHC_STATUS_END_CMD_RESP_MSK)
+ && !(esdhc_base_pointer->
+ interrupt_status & ESDHC_STATUS_TIME_OUT_RESP_MSK)
+ && !(esdhc_base_pointer->
+ interrupt_status & ESDHC_STATUS_RESP_CRC_ERR_MSK)
+ && !(esdhc_base_pointer->
+ interrupt_status & ESDHC_STATUS_RESP_INDEX_ERR_MSK)) {
+
+ status = SUCCESS;
+ } else {
+ //diag_printf("Warning: Check CMD response, Intr Status: 0x%x\n", esdhc_base_pointer->interrupt_status);
+ status = FAIL;
+ }
+
+ return status;
+
+}
+
+void host_read_response(command_response_t * cmd_resp)
+{
+ /* get response values from e-SDHC CMDRSP registers. */
+ cmd_resp->cmd_rsp0 = (cyg_uint32) esdhc_base_pointer->command_response0;
+ cmd_resp->cmd_rsp1 = (cyg_uint32) esdhc_base_pointer->command_response1;
+ cmd_resp->cmd_rsp2 = (cyg_uint32) esdhc_base_pointer->command_response2;
+ cmd_resp->cmd_rsp3 = (cyg_uint32) esdhc_base_pointer->command_response3;
+}
+
+static void esdhc_wait_buf_rdy_intr(cyg_uint32 mask,
+ multi_single_block_select
+ multi_single_block)
+{
+
+ /* Wait interrupt (BUF_READ_RDY) */
+
+ cyg_uint32 i;
+ for (i = 3000; i > 0; i--) {
+ if (esdhc_base_pointer->interrupt_status & mask) {
+ break;
+ }
+ hal_delay_us(100);
+ }
+
+ if (multi_single_block == MULTIPLE
+ && esdhc_base_pointer->interrupt_status & mask)
+ esdhc_base_pointer->interrupt_status |= mask;
+ if (i == 0)
+ flash_dprintf(FLASH_DEBUG_MAX, "%s:Debug: tried %d times\n",
+ __FUNCTION__, (3000 - i));
+
+}
+
+static void esdhc_wait_op_done_intr(cyg_uint32 transfer_mask)
+{
+ /* Wait interrupt (Transfer Complete) */
+
+ cyg_uint32 i;
+ while (!(esdhc_base_pointer->interrupt_status & transfer_mask)) ;
+
+ //diag_printf("Wait OP Done Failed.\n");
+ //flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug: tried %d times\n", __FUNCTION__, (3001-i));
+
+}
+
+static cyg_uint32 esdhc_check_data(cyg_uint32 op_done_mask,
+ cyg_uint32 read_time_out_mask,
+ cyg_uint32 read_crc_err_mask)
+{
+
+ cyg_uint32 status = FAIL;
+
+ /* Check whether the interrupt is an OP_DONE
+ * or a data time out or a CRC error */
+ if ((esdhc_base_pointer->interrupt_status & op_done_mask) &&
+ !(esdhc_base_pointer->interrupt_status & read_time_out_mask) &&
+ !(esdhc_base_pointer->interrupt_status & read_crc_err_mask)) {
+ status = SUCCESS;
+ } else {
+ status = FAIL;
+ //diag_printf("Warning: Check data, interrupt_status=%X\n", (esdhc_base_pointer->interrupt_status));
+ }
+
+ return status;
+}
+
+void host_cfg_block(cyg_uint32 blk_len, cyg_uint32 nob)
+{
+ /* Configre block Attributes register */
+ esdhc_base_pointer->block_attributes =
+ ((nob << 16) | (blk_len & 0xffff));
+
+ //diag_printf("nob: 0x%x, block_attributes: 0x%x\n", nob, esdhc_base_pointer->block_attributes);
+
+ /* Set Read Water Mark Level register */
+ esdhc_base_pointer->watermark_level = WRITE_READ_WATER_MARK_LEVEL;
+}
+
+cyg_uint32 host_data_read(cyg_uint32 * dest_ptr, cyg_uint32 read_len)
+{
+ cyg_uint32 j, k;
+ cyg_uint32 status = FAIL;
+ unsigned int len = WRITE_READ_WATER_MARK_LEVEL & 0xff;
+ //int counter = 0;
+
+ /* Enable Interrupt */
+ esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
+
+ for (j = 0; j < read_len / (len * 4); j++) {
+ //StartCounter();
+ /* wait for read fifo full (equal or beyond the watermark) */
+ while (!(esdhc_base_pointer->present_state & (1 << 11))) ;
+
+ //counter = StopCounter();
+ //diag_printf("counter: 0x%x\n", counter);
+
+ for (k = 0; k < len; k++) {
+ *dest_ptr++ = esdhc_base_pointer->data_buffer_access;
+ }
+ }
+
+ /* Wait for transfer complete operation interrupt */
+ esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
+
+ /* Check for status errors */
+ status =
+ esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
+ ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
+
+ return status;
+
+}
+
+cyg_uint32 host_data_write(cyg_uint32 * src_ptr, cyg_uint32 write_len)
+{
+ cyg_uint32 i = 0, k;
+ cyg_uint32 status = FAIL;
+ unsigned int len = (WRITE_READ_WATER_MARK_LEVEL >> 16) & 0xff;
+ //cyg_uint32 counter = 0;
+
+ /* Enable Interrupt */
+ esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
+
+ //StartCounter();
+ for (i = 0; i < (write_len) / (len * 4); i++) {
+ /* wait for write fifo empty (equal or less than the watermark), BWEN */
+ while (!(esdhc_base_pointer->present_state & (1 << 10))) ;
+
+ for (k = 0; k < len; k++) {
+ esdhc_base_pointer->data_buffer_access = *src_ptr++;
+ }
+
+ }
+
+ /* Wait for transfer complete operation interrupt */
+ esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
+
+ //counter = StopCounter();
+ //diag_printf("0x%x\n", counter);
+
+ /* Check for status errors */
+ status =
+ esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
+ ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
+
+ return status;
+
+}
+
+static int esdhc_check_for_send_cmd(int data_present)
+{
+
+ int status = SUCCESS;
+ int counter;
+
+ /* Wait for the command line to be free (poll the CIHB bit of
+ * the present state register.
+ */
+ counter = 1000;
+ while (((esdhc_base_pointer->present_state & 0x1) == 0x1) && counter--) {
+ hal_delay_us(10);
+ }
+
+ if (!counter)
+ return FAIL;
+
+ /* Wait for the data line to be free (poll the CDIHB bit of
+ * the present state register.
+ */
+ counter = 1000;
+ if (data_present == DATA_PRESENT) {
+ while (((esdhc_base_pointer->present_state & 0x2) == 0x2) && counter--) {
+ hal_delay_us(10);
+ }
+
+ }
+
+ if (!counter)
+ return FAIL;
+
+ return status;
+}
--- /dev/null
+// ==========================================================================
+//
+// mxcmci_mmc.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/io/mxcmci_host.h>
+#include <cyg/io/mxcmci_core.h>
+#include <cyg/io/mxcmci_mmc.h>
+#include <cyg/io/mxc_mmc.h>
+
+extern int HighCapacityCard;
+
+static cyg_uint32 mmc_set_rca(void);
+static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width);
+static cyg_uint32 mmc_set_high_speed_mode(void);
+
+cyg_uint32 address_mode; /* Global variable for addressing mode */
+
+cyg_uint32 mmc_init(cyg_uint32 bus_width)
+{
+ cyg_uint32 status = FAIL;
+ cyg_uint32 spec_version;
+ /* Get CID number of MMC Card */
+ if (!mxcmci_get_cid()) {
+ /* Set RCA of the MMC Card */
+ if (!mmc_set_rca()) {
+ flash_dprintf(FLASH_DEBUG_MAX, "%s: mmc_set_rca OK!",
+ __FUNCTION__);
+ /* Get Spec version supported by the card */
+ spec_version = mmc_get_spec_ver();
+ //diag_printf("SPEC Version: %d\n", spec_version);
+
+ /*Enable operating frequency */
+ host_cfg_clock(OPERATING_FREQ);
+
+ /*Put MMC in Transfer State */
+ if (!mxcmci_trans_prepare()) {
+#if 0
+ if (mmc_set_high_speed_mode()) {
+ return FAIL;
+ }
+#endif
+
+ /* Set block length for transfer */
+ //diag_printf("Send CMD to Set Block Length.\n");
+ if (sdmmc_set_blklen(BLK_LEN))
+ return FAIL;
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s: mxcmci_trans_prepare OK!",
+ __FUNCTION__);
+
+ if (!mmc_set_bus_width(bus_width)) {
+ esdhc_base_pointer->protocol_control &= ~(0x3 << 1);
+ esdhc_base_pointer->protocol_control |= (bus_width >> 2) << 1;
+ status = SUCCESS;
+ diag_printf("Bus Width: %d\n",
+ bus_width);
+ }
+
+ }
+ }
+ }
+
+ return status;
+
+}
+
+cyg_uint32 mmc_data_read(cyg_uint32 * dest_ptr, cyg_uint32 length,
+ cyg_uint32 offset)
+{
+ command_t cmd;
+ int len;
+ cyg_uint32 read_block_status = 0;
+ cyg_uint32 blk_len = BLK_LEN;
+ unsigned int SectorNum = 0;
+
+ /* Assing length of data to be read */
+ SectorNum = length / blk_len;
+ if ((length % blk_len) != 0)
+ SectorNum++;
+ /* hight capacity card uses sector mode */
+ if(HighCapacityCard)
+ offset = offset/512;
+
+ /* wait until in transfer mode */
+ while (mxcmci_trans_status()) {
+ hal_delay_us(5);
+ }
+
+ reread:
+ /* Configure interface block and number of blocks */
+ host_cfg_block(BLK_LEN, SectorNum);
+
+ if (SectorNum == 1) {
+ //diag_printf("Send CMD17...\n");
+ /* Comfigure command CMD17 for single block read */
+ mxcmci_cmd_config(&cmd, CMD17, offset, READ, RESPONSE_48,
+ DATA_PRESENT, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Can't send CMD17!\n", __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK |
+ ESDHC_RESET_DAT_MSK);
+ read_block_status = FAIL;
+
+ } else {
+ //diag_printf("host_data_read! dest_ptr: 0%x \n", dest_ptr);
+ /* Call interface Data read function */
+ read_block_status = host_data_read(dest_ptr, BLK_LEN);
+
+ if (read_block_status) { /* fail */
+ //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
+ /* re-transfer if data transfer error occurs */
+ goto reread;
+ }
+ }
+ } else { /* read multi-blocks */
+
+ /* Comfigure command CMD18 for multiple block read */
+ mxcmci_cmd_config(&cmd, CMD18, offset, READ, RESPONSE_48,
+ DATA_PRESENT, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Can't send CMD18!\n", __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ read_block_status = FAIL;
+ } else {
+ /* Call interface Data read function */
+ read_block_status =
+ host_data_read(dest_ptr, BLK_LEN * SectorNum);
+
+ /* Comfigure command CMD12 for multi-block read stop */
+ mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Can't send CMD12!\n",
+ __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ //read_block_status = FAIL;
+ }
+
+ if (read_block_status) { /* fail */
+ //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
+ /* re-transfer if data transfer error occurs */
+ goto reread;
+ }
+
+ }
+
+ }
+ return read_block_status;
+}
+
+cyg_uint32 mmc_data_write(cyg_uint32 * src_ptr, cyg_uint32 length,
+ cyg_uint32 offset)
+{
+
+ command_t cmd;
+ cyg_int32 len;
+ cyg_uint32 blk_len = BLK_LEN;
+ cyg_uint32 write_block_status = SUCCESS;
+ unsigned int SectorNum;
+ //int counter;
+ //diag_printf("%s: src: 0x%x, offset: 0x%x, length: 0x%x\n", __FUNCTION__, (unsigned int)src_ptr, offset, length);
+ /* Write data size aligned with block size */
+ SectorNum = length / blk_len;
+ if ((length % blk_len) != 0)
+ SectorNum++;
+
+ /* hight capacity card uses sector mode */
+ if(HighCapacityCard)
+ offset = offset/512;
+
+ //need waiting until CARD out of Prg status, or will cause CMD25 timeout
+ //hal_delay_us(100);
+
+ //StartCounter();
+
+ while (mxcmci_trans_status()) {
+ hal_delay_us(2);
+ }
+
+ //counter = StopCounter();
+ //diag_printf("counter: 0x%x\n",counter);
+
+ rewrite:
+ /* Configure interface block and number of blocks , SctorNum will decrease to zero after transfer */
+ host_cfg_block(BLK_LEN, SectorNum);
+
+ if (SectorNum == 1) {
+ //diag_printf("Send CMD24...\n");
+ /* Comfigure command CMD24 for single block write */
+ mxcmci_cmd_config(&cmd, CMD24, offset, WRITE, RESPONSE_48,
+ DATA_PRESENT, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Failed in configuring CMD24\n",
+ __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ write_block_status = FAIL;
+
+ //hal_delay_us(1000);
+ goto rewrite;
+
+ } else {
+ //diag_printf("Start host_data_write:\n");
+ /* Call interface write read function */
+ write_block_status = host_data_write(src_ptr, BLK_LEN);
+ //diag_printf("0x%x\n", esdhc_base_pointer->present_state);
+
+ if (write_block_status) { /* fail */
+ //diag_printf("transfer failed.(0x%x)\n", esdhc_base_pointer->block_attributes);
+ while (mxcmci_trans_status()) ;
+ //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
+ /* re-transfer */
+ goto rewrite;
+ }
+
+ }
+ } else { /* multi-block write */
+
+ //diag_printf("Send CMD25...\n");
+ /* Comfigure command CMD25 for single block write */
+ mxcmci_cmd_config(&cmd, CMD25, offset, WRITE, RESPONSE_48,
+ DATA_PRESENT, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ //diag_printf("%s: Failed in configuring CMD25\n",
+ // __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ write_block_status = FAIL;
+ goto rewrite;
+ } else {
+ /* Call interface write read function */
+ write_block_status =
+ host_data_write(src_ptr, SectorNum * BLK_LEN);
+
+ /* Comfigure command CMD12 for multi-block read stop */
+ mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Can't send CMD12!\n",
+ __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ //write_block_status = FAIL;
+ }
+
+ if (write_block_status) { /* fail */
+ //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
+ while (mxcmci_trans_status());
+ /* re-transfer */
+ goto rewrite;
+ }
+ }
+ }
+
+ return write_block_status;
+
+}
+
+cyg_uint32 mmc_data_erase(cyg_uint32 offset, cyg_uint32 size)
+{
+ command_t cmd;
+ extern int Card_Mode;
+ cyg_uint8 startEraseBlockCmd = CMD35;
+ cyg_uint8 endEraseBlockCmd = CMD36;
+
+ cyg_uint32 startBlock = offset / BLK_LEN;
+ cyg_uint32 endBlock = (offset + size - 1) / BLK_LEN;
+ cyg_uint32 ret;
+// diag_printf("card_data_erase\n");
+ if (Card_Mode == 0) {
+ startBlock *= BLK_LEN;
+ endBlock *= BLK_LEN;
+ startEraseBlockCmd = CMD35;
+ endEraseBlockCmd = CMD36;
+ }
+
+ else if (Card_Mode == 1) {
+ startBlock *= BLK_LEN;
+ endBlock *= BLK_LEN;
+ startEraseBlockCmd = CMD32;
+ endEraseBlockCmd = CMD33;
+ }
+#if 1
+ /* hight capacity card uses sector mode */
+ if(HighCapacityCard)
+ startBlock /= BLK_LEN;
+ endBlock /= BLK_LEN;
+#endif
+// diag_printf("0x%x - 0x%x, size: 0x%x\n", startBlock, endBlock, size);
+ /* Configure start erase command to set first block */
+ mxcmci_cmd_config(&cmd, startEraseBlockCmd, startBlock, READ,
+ RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
+ /* wait response */
+ if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "%s: successful for host_send_cmd\n",
+ __FUNCTION__);
+ /* Configure end erase command to set end block */
+ mxcmci_cmd_config(&cmd, endEraseBlockCmd, endBlock, READ,
+ RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
+ if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "%s: successful for host_send_cmd:2\n",
+ __FUNCTION__);
+ /* Comfigure command to start erase */
+ mxcmci_cmd_config(&cmd, CMD38, 0, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+ if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "%s: successful for host_send_cmd:3\n",
+ __FUNCTION__);
+ //wait for completion
+ return ret;
+ }
+ }
+ }
+
+ flash_dprintf(FLASH_DEBUG_MAX, "%s: Error return (%d)\n", __FUNCTION__,
+ ret);
+ return ret;
+}
+
+cyg_uint32 mmc_voltage_validation(void)
+{
+ command_t cmd;
+ command_response_t response;
+ cyg_uint32 voltage_validation_command = 0;
+ cyg_uint32 ocr_val = 0;
+ cyg_uint32 voltage_validation = FAIL;
+
+ ocr_val = (cyg_uint32) ((MMC_OCR_VALUE) & 0xFFFFFFFF);
+
+ while ((voltage_validation_command < MMCSD_READY_TIMEOUT)
+ && (voltage_validation != SUCCESS)) {
+ /* Configure CMD1 for MMC card */
+ mxcmci_cmd_config(&cmd, CMD1, ocr_val, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, DISABLE, DISABLE);
+
+ /* Issue CMD1 to MMC card to determine OCR value */
+ if (host_send_cmd(&cmd) == FAIL) {
+ voltage_validation = FAIL;
+ break;
+ } else {
+ /* Read Response from CMDRSP0 Register */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Check if card busy bit is cleared or not */
+ if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
+ /* Iterate One more time */
+ voltage_validation_command++;
+ } else {
+ if ((response.cmd_rsp0 & MMC_OCR_HC_RES) ==
+ MMC_OCR_HC_RES) {
+ address_mode = SECT_MODE;
+ voltage_validation = SUCCESS;
+ } else if ((response.cmd_rsp0 & MMC_OCR_LC_RES)
+ == MMC_OCR_LC_RES) {
+ address_mode = BYTE_MODE;
+ voltage_validation = SUCCESS;
+ }
+ }
+
+ }
+ }
+
+ return voltage_validation;
+}
+
+static cyg_uint32 mmc_set_rca(void)
+{
+ command_t cmd;
+ cyg_uint32 card_state = 0;
+ cyg_uint32 rca_request = 0;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD3 for MMC card */
+ /* 32bit card address is expected as Argument */
+ mxcmci_cmd_config(&cmd, CMD3, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Assigns relative address to the card
+ */
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ rca_request = FAIL;
+ }
+
+ else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+ card_state = CURR_CARD_STATE(response.cmd_rsp0);
+ if (card_state == IDENT) {
+ rca_request = SUCCESS;
+
+ } else {
+ rca_request = FAIL;
+ }
+ }
+
+ return rca_request;
+}
+
+cyg_uint32 mmc_get_spec_ver(void)
+{
+
+ cyg_uint32 mmc_spec_version;
+
+ if (card_get_csd() == FAIL) {
+ mmc_spec_version = 0;
+ } else {
+ mmc_spec_version = ((csd.csd3 && MMC_SPEC_VER) >> MMC_SPEC_VER_SHIFT);
+ }
+
+ return mmc_spec_version;
+
+}
+
+cyg_uint32 card_flash_query(void *data)
+{
+ command_t cmd;
+ cyg_uint32 cid_request = FAIL;
+ command_response_t response;
+
+ /* Configure CMD2 for card */
+ mxcmci_cmd_config(&cmd, CMD2, NO_ARG, READ, RESPONSE_136,
+ DATA_PRESENT_NONE, ENABLE, DISABLE);
+ /* Issue CMD2 to card to determine CID contents */
+ if (host_send_cmd(&cmd) == FAIL) {
+ cid_request = FAIL;
+ flash_dprintf(FLASH_DEBUG_MAX, "%s: can't send query command\n",
+ __FUNCTION__);
+ } else {
+ cyg_uint32 *d = (cyg_uint32 *) data;
+ /* Read Command response */
+ response.format = RESPONSE_136;
+ host_read_response(&response);
+ /* Assign CID values to mmc_cid structures */
+ *d++ = response.cmd_rsp0;
+ *d++ = response.cmd_rsp1;
+ *d++ = response.cmd_rsp2;
+ *d = response.cmd_rsp3;
+
+ /* Assign cid_request as SUCCESS */
+ cid_request = SUCCESS;
+ }
+ flash_dprintf(FLASH_DEBUG_MAX,
+ "%s(Success?=%d):(ID=0x%x: 0x%x, 0x%x, 0x%x)\n",
+ __FUNCTION__, cid_request, *(cyg_uint32 *) (data),
+ *(cyg_uint32 *) ((cyg_uint32) data + 4),
+ *(cyg_uint8 *) ((cyg_uint32) data + 8),
+ *(cyg_uint8 *) ((cyg_uint32) data + 12));
+ return;
+}
+
+static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width)
+{
+ command_t cmd;
+ cyg_uint32 set_bus_width_status = FAIL;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ if ((bus_width == FOUR) || (bus_width == EIGHT) || (bus_width == ONE)) {
+
+ /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
+ mxcmci_cmd_config(&cmd, CMD6, 0x03b70001 | ((bus_width >> 2) << 8), READ,
+ RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == SUCCESS) {
+ set_bus_width_status = SUCCESS;
+ } else {
+ diag_printf("Setting MMC bus width failed.\n");
+ }
+ }
+
+ return set_bus_width_status;
+}
+
+static cyg_uint32 mmc_set_high_speed_mode(void)
+{
+ command_t cmd;
+ command_response_t response;
+ cyg_uint32 status = FAIL;
+
+ //diag_printf("Send CMD6 to Set High Speed Mode.\n");
+ /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
+ mxcmci_cmd_config(&cmd, CMD6, 0x03b90100, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == SUCCESS) {
+ /* wait until in transfer mode */
+ while (mxcmci_trans_status()) {
+ hal_delay_us(5);
+ }
+
+ status = SUCCESS;
+ } else {
+ diag_printf("Setting MMC High Speed Mode FAILED.\n");
+ }
+
+ return status;
+}
+
+int sdmmc_set_blklen(int len)
+{
+ int status = FAIL;
+ command_t cmd;
+ command_response_t response;
+
+ /* Configure CMD16 to set block length as 512 bytes. */
+ mxcmci_cmd_config(&cmd, CMD16, len, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue command CMD16 to set block length as 512 bytes */
+ if (host_send_cmd(&cmd) == FAIL) {
+ diag_printf("%s: Can't set block length!(CMD16)\n",
+ __FUNCTION__);
+ esdhc_softreset(ESDHC_RESET_CMD_MSK);
+ status = FAIL;
+ } else {
+ status = SUCCESS;
+ }
+
+ return status;
+}
+
+int sdmmc_stop_transmission(void)
+{
+ int status = FAIL;
+ command_t cmd;
+ command_response_t response;
+
+ /* Comfigure command CMD12 for read stop */
+ mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ //diag_printf("%s: Can't send CMD12!\n", __FUNCTION__);
+ //esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
+ //read_block_status = FAIL;
+ }
+
+ return 0;
+}
+
+static unsigned int mmc_set_extendCSD(unsigned int ECSD_index, unsigned int value, unsigned int access_mode)
+{
+ unsigned int argument = 0;
+ command_t cmd;
+
+ /* access mode: 0b01 set bits/ 0b10 clear bits/ 0b11 write bytes */
+ argument = (access_mode << 24) | (ECSD_index << 16) | (value << 8);
+ //argument = 0x1b30000;
+
+ mxcmci_cmd_config(&cmd, CMD6, argument, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ if(host_send_cmd(&cmd) == SUCCESS) {
+ return 0;
+ } else {
+ //diag_printf("%s: Setting MMC boot Failed.\n", __FUNCTION__);
+ return 1;
+ }
+}
+
+static void mmc_set_boot_partition_size(unsigned int value)
+{
+ command_t cmd;
+ command_response_t response;
+ cyg_uint32 card_state = 0;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ mxcmci_cmd_config(&cmd, CMD62, 0XEFAC62EC, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+ host_send_cmd(&cmd);
+
+ mxcmci_cmd_config(&cmd, CMD62, 0X00CBAEA7, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+ host_send_cmd(&cmd);
+
+ mxcmci_cmd_config(&cmd, CMD62, value, READ, RESPONSE_48,
+ DATA_PRESENT, ENABLE, ENABLE);
+ host_send_cmd(&cmd);
+}
+
+cyg_uint32 emmc_set_boot_partition (cyg_uint32 *src_ptr, cyg_uint32 length)
+{
+ cyg_uint32 status=FAIL;
+ unsigned int value;
+ unsigned int eMMCBootDataSize = (length / (128 * 1024)) + 1;
+
+ if (MMC_Spec_vers < 4)
+ return 1;
+
+ /* read back 1KB data as we are programming to user are and want to aviod erasing MBR
+ * will be removed once we program Redboot to boot partition of the card
+ */
+ mmc_data_read(src_ptr, 0x400, 0);
+
+ /* Set boot partition */
+ /* 1. Configure CMD6 to write to EXT_CSD register for eMMC boot partition, Byte 179*/
+ /* boot partition: user area enable and r/w enable */
+ value = (0x7 << 3) | (0x7);
+ //value = (0x1 << 3) | (0x1);
+ status = mmc_set_extendCSD(179, value, 0x3);
+ if(status) {
+ return 1; /* failed */
+ }
+
+ /* 2. Set boot partition size: n*128KB */
+ value = eMMCBootDataSize;
+ //status = mmc_set_extendCSD(226, value, 0x3);
+ //if(status) {
+ // return 1; /* failed */
+ //}
+ //mmc_set_boot_partition_size(value);
+
+ //diag_printf("Boot partition size: 0x%xKB\n", eMMCBootDataSize * 128);
+
+ /* 3. Program to boot partition, default address is alway 0x0 */
+ status = mmc_data_write (src_ptr, eMMCBootDataSize*128*1024, 0);
+ if(status) {
+ return 1; /* failed */
+ }
+
+ while (mxcmci_trans_status());
+
+ /* 4. Clear boot partition access bits, to protect w/r of boot partition */
+ /* bit 6: send boot ack signal, boot partition: user area enable and r/w access disable */
+ //value = (0x1 << 6) | (0x1 << 3) | (0x0);
+ value = (0x1 << 6) | (0x7 << 3) | (0x0);
+ status = mmc_set_extendCSD(179, value, 0x3);
+ if(status) {
+ return 1; /* failed */
+ }
+
+ return 0;
+}
+
+/* end of mxcmci_mmc.c */
--- /dev/null
+// ==========================================================================
+//
+// mxcmci_sd.c
+// (c) 2008, Freescale
+//
+// MMC card driver for MXC platform
+//
+// ==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Lewis Liu <weizhi.liu@freescale.com>
+// Contributors: Lewis Liu <weizhi.liu@freescale.com>
+// Date: 2008-05-13 Initial version
+// Purpose:
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/io/mxcmci_host.h>
+#include <cyg/io/mxcmci_core.h>
+#include <cyg/io/mxcmci_mmc.h>
+
+static cyg_uint32 sd_get_rca(void);
+static cyg_uint32 sd_get_bit_mode_support(void);
+static cyg_uint32 sd_set_bus_width(cyg_uint32);
+static cyg_uint32 sd_set_high_speed_mode(void);
+
+#define SD_OCR_VALUE_HV_LC 0x00ff8000 /* nirp_oct07: <- 3.3v, LC */
+#define SD_OCR_VALUE_HV_HC 0x40ff8000 /* nirp_oct07: <- 3.3v, HC */
+/* nirp_oct07: LV_LC not needed - 1.8v is only supported under eSD which supports HC by default (SD>2.00) */
+#define SD_OCR_VALUE_LV_HC 0x40000080 /* nirp_oct07: <- 1.8v, HC */
+
+#define SD_OCR_HC_RES 0x40000000
+#define SD_OCR_LC_RES 0x00000000
+
+#define SD_IF_HV_COND_ARG 0x000001AA
+#define SD_IF_LV_COND_ARG 0x000002AA
+
+#define RCA_SHIFT 16
+#define SD_R1_STATUS_APP_CMD_MSK 0x20
+#define BIT_MODE_4_SUPPORT 5
+#define SD_BUS_WIDTH_OFFSET 6
+#define BIT_4_MODE 4
+#define SD_STATUS_LEN 64
+
+#define SD_BOOT_SWITCH_ARG 0x80FFFF2F
+#define SD_PARTITION1 0x01000000
+
+cyg_uint32 sd_init(cyg_uint32 bus_width)
+{
+ cyg_uint32 status = FAIL;
+ cyg_uint32 bus_size = bus_width;
+
+ /* Get CID number of SD Memory Card */
+ if (!mxcmci_get_cid()) {
+ //diag_printf("%s:mxcmci_get_cid OK!\n", __FUNCTION__);
+ /* Set RCA of the SD Card */
+ if (!sd_get_rca()) {
+ //diag_printf("%s:sd_get_rca OK!\n", __FUNCTION__);
+ /*Get CSD from Card */
+ if (card_get_csd())
+ return FAIL;
+
+ /*Enable operating frequency */
+ host_cfg_clock(OPERATING_FREQ);
+
+ //diag_printf("Set SD Card in Transfer State.\n");
+
+ /*Put SD Card in Transfer State */
+ if (!mxcmci_trans_prepare()) {
+#if 0
+ if (sd_set_high_speed_mode()) {
+ return FAIL;
+ }
+#endif
+
+ if (sdmmc_set_blklen(BLK_LEN))
+ return FAIL;
+
+ /* SD can only support 1/4 bit bitwidth, 8 bit is not supported */
+ if (EIGHT == bus_width) {
+ bus_width = FOUR;
+ }
+ if (!sd_set_bus_width(bus_width)) {
+ esdhc_base_pointer->protocol_control &=
+ ~(0x3 << 1);
+ esdhc_base_pointer->protocol_control |=
+ (bus_width / 4) << 1;
+ diag_printf("Bus Width: %d\n",
+ bus_width);
+ status = SUCCESS;
+ }
+ }
+ }
+
+ } else {
+ diag_printf("Get CID Failed.\n");
+
+ }
+
+ //diag_printf("%s:failed to Init SD card!\n", __FUNCTION__);
+ return status;
+
+}
+
+cyg_uint32 sd_voltage_validation(void)
+{
+ //wait max timeout (unit: ms)
+ cyg_uint32 timeout = 15000;
+
+ command_t cmd;
+ command_response_t response;
+ cyg_uint32 voltage_validation_command = 0;
+ cyg_uint32 default_rca = 0;
+
+ cyg_uint32 ocr_value = SD_OCR_VALUE_HV_LC; /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
+ cyg_uint32 voltage_validation = FAIL;
+ cyg_uint32 interface_value = 0;
+ cyg_uint32 card_usable = SUCCESS;
+
+ /* Configure Command CMD8 to check for High capacity support */
+ /* try 3.3V first */
+ mxcmci_cmd_config(&cmd, CMD8, SD_IF_HV_COND_ARG, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue Command CMD8 to SD Memory card */
+ if (host_send_cmd(&cmd) == SUCCESS) { /* nirp_oct07: <- changed order of detection */
+ //diag_printf("%s:CMD8 OK!\n", __FUNCTION__);
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Obtain Interface value from the response buffer */
+ interface_value = response.cmd_rsp0;
+
+ /* Check if volatge lies in range or not */
+ if ((interface_value & SD_IF_HV_COND_ARG) == SD_IF_HV_COND_ARG) {
+ ocr_value = ((cyg_uint32) (SD_OCR_VALUE_HV_HC) & 0xFFFFFFFF); /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
+ }
+
+ /* start timer for a delay of 1.5sec, for ACMD41 */
+ hal_delay_us(1500);
+
+ while ((voltage_validation_command < 20)
+ && (voltage_validation != SUCCESS)
+ && (card_usable == SUCCESS)) {
+ /* Configure CMD55 for SD card */
+ /* This command expects defualt RCA 0x0000 as argument. */
+ mxcmci_cmd_config(&cmd, CMD55, default_rca, READ,
+ RESPONSE_48, DATA_PRESENT_NONE,
+ ENABLE, ENABLE);
+
+ /* Issue CMD55 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ voltage_validation = FAIL;
+ //diag_printf("Send CMD55 Failed.\n");
+ break;
+ } else {
+ /* Configure ACMD41 for SD card */
+ /* This command expects operating voltage range as argument. */
+ /* CODE REVIEW START: Need to check why BUSY was expected */
+ /* INTERNAL CODE REVIEW: Accepted - to fix original code if needed */
+ /* nirp: changed RESPONSE_48_CHECK_BUSY to RESPONSE_48 */
+ /* nirp_oct03: why with busy again? ACMD41 doesn't hold busy line */
+ mxcmci_cmd_config(&cmd, ACMD41, ocr_value, READ,
+ RESPONSE_48, DATA_PRESENT_NONE, DISABLE,
+ DISABLE);
+
+ /* Issue ACMD41 to SD Memory card to determine OCR value */
+ if (host_send_cmd(&cmd) == FAIL) {
+ voltage_validation = FAIL;
+ diag_printf("Send CMD41 Failed.\n");
+ break;
+ } else {
+ /* Read Response from CMDRSP0 Register */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Obtain OCR Values from the response */
+ /* Obtain OCR value from the response buffer */
+ ocr_value = response.cmd_rsp0;
+
+ /* Check if card busy bit is cleared or not */
+ if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
+ /* Iterate One more time */
+ voltage_validation_command++;
+ } else {
+
+ /*CODE REVIEW START: Update code and check only bit 30, HC or LC card type. All voltage bits needs to be masked. */
+ /* INTERNAL CODE REVIEW: Accepted - need fix the code accordingly */
+ /* nirp: It may be better to check the actual power supply voltage - requiring the entire range (0xff8000) may fail the sequence even if the device can be supported */
+ /*CODE REVIEW END: */
+
+ if ((response.cmd_rsp0 & SD_OCR_HC_RES) == SD_OCR_HC_RES) {
+ address_mode = SECT_MODE;
+ voltage_validation = SUCCESS;
+ }
+ /* CODE REVIEW 3: (same as above) Check is logically correct, but seems redundent.
+ Anything that fails the HC check, is assumed Low Capacity */
+ /* nirp_oct03: this can be just an "else". the LC macro is 0 anyway,
+ and anything not HC is LC by default */
+ /* removed else if */
+ else {
+ address_mode = BYTE_MODE;
+ voltage_validation = SUCCESS;
+ }
+ }
+ }
+ }
+
+ hal_delay_us(1000);
+ }
+
+ if (voltage_validation == FAIL) {
+ card_usable = FAIL;
+ }
+
+ } else {
+ /*3.3v test failed, try to test 1.8v mode! */
+ mxcmci_cmd_config(&cmd, CMD8, SD_IF_LV_COND_ARG, READ,
+ RESPONSE_48, DATA_PRESENT_NONE, ENABLE,
+ ENABLE);
+
+ /* Issue Command CMD8 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ //diag_printf("%s:CMD8 for 1.8v failed!\n", __FUNCTION__);
+ /* nirp_oct07: CMD8 failed both in 3.3 and in 1.8v, try SD 1.x case - no CMD8, LC, 3.3v only */
+ ocr_value = ((cyg_uint32) (SD_OCR_VALUE_HV_LC) & 0xFFFFFFFF); /* nirp_oct07: <- changed order of detection */
+ } else {
+ //diag_printf("%s:CMD8 for 1.8v OK!\n", __FUNCTION__);
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Obtain Interface value from the response buffer */
+ interface_value = response.cmd_rsp0;
+
+ /* Check if volatge lies in range or not */
+ if ((interface_value & SD_IF_LV_COND_ARG) == SD_IF_LV_COND_ARG) {
+ ocr_value = ((cyg_uint32) (SD_OCR_VALUE_LV_HC) & 0xFFFFFFFF); /* nirp_oct07: <- split OCR to 3.3v and 1.8v cases */
+ }
+ /* nirp_oct07: otherwise, try with HV_LC settings (set at function start) */
+ }
+
+ }
+
+ /* start timer for a delay of 1.5sec, for ACMD41 */
+ hal_delay_us(1500);
+
+ /* nirp_oct03: MMCSD_READY_TIMEOUT too long.
+ ACMD41 also takes longer than CMD1 (twice - ~200 clocks for CMD55+resp+CMD41+resp */
+ /* In any case ,ACMD 41 will loop not more than 1.5 sec */
+ while ((voltage_validation_command < 20)
+ && (voltage_validation != SUCCESS) && (card_usable == SUCCESS)) {
+ /* Configure CMD55 for SD card */
+ /* This command expects defualt RCA 0x0000 as argument. */
+ mxcmci_cmd_config(&cmd, CMD55, default_rca, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue CMD55 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ voltage_validation = FAIL;
+ //diag_printf("Send CMD55 Failed!\n");
+ break;
+ } else {
+ /* Configure ACMD41 for SD card */
+ /* This command expects operating voltage range as argument. */
+ /* CODE REVIEW START: Need to check why BUSY was expected */
+ /* INTERNAL CODE REVIEW: Accepted - to fix original code if needed */
+ /* nirp: changed RESPONSE_48_CHECK_BUSY to RESPONSE_48 */
+ /* nirp_oct03: why with busy again? ACMD41 doesn't hold busy line */
+ mxcmci_cmd_config(&cmd, ACMD41, ocr_value, READ,
+ RESPONSE_48, DATA_PRESENT_NONE,
+ DISABLE, DISABLE);
+
+ /* CODE REVIEW END: */
+
+ /* Issue ACMD41 to SD Memory card to determine OCR value */
+ if (host_send_cmd(&cmd) == FAIL) {
+ voltage_validation = FAIL;
+ diag_printf("Send ACMD41 Failed!\n");
+ break;
+ } else {
+ /* Read Response from CMDRSP0 Register */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Obtain OCR Values from the response */
+ /* Obtain OCR value from the response buffer
+ */
+ ocr_value = response.cmd_rsp0;
+
+ /* Check if card busy bit is cleared or not */
+ if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
+ /* Iterate One more time */
+ voltage_validation_command++;
+ } else {
+ /*CODE REVIEW START: Update code and check only bit 30, HC or LC card type. All voltage bits needs to be masked. */
+ /* INTERNAL CODE REVIEW: Accepted - need fix the code accordingly */
+ /* nirp: It may be better to check the actual power supply voltage - requiring the entire range (0xff8000) may fail the sequence even if the device can be supported */
+ /*CODE REVIEW END: */
+
+ if ((response.cmd_rsp0 & SD_OCR_HC_RES) == SD_OCR_HC_RES) {
+ address_mode = SECT_MODE;
+ voltage_validation = SUCCESS;
+ }
+ /* CODE REVIEW 3: (same as above) Check is logically correct, but seems redundent.
+ Anything that fails the HC check, is assumed Low Capacity */
+ /* nirp_oct03: this can be just an "else". the LC macro is 0 anyway,
+ and anything not HC is LC by default */
+ else {
+ address_mode = BYTE_MODE;
+ voltage_validation = SUCCESS;
+ }
+ }
+ }
+
+ }
+
+ hal_delay_us(1000);
+
+ }
+
+ return voltage_validation;
+}
+
+static cyg_uint32 sd_get_rca(void)
+{
+ command_t cmd;
+ cyg_uint32 card_state = 0;
+ cyg_uint32 rca_request = 0;
+ command_response_t response;
+
+ /* Configure CMD3 for MMC card */
+ /* 32bit card address is expected as Argument */
+ mxcmci_cmd_config(&cmd, CMD3, NO_ARG, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Get relative address of the card */
+
+ if (host_send_cmd(&cmd) == FAIL) {
+ rca_request = FAIL;
+ diag_printf("Send CMD3 Failed.\n");
+ } else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ Card_rca = ((cyg_uint32) (response.cmd_rsp0 >> RCA_SHIFT));
+
+ card_state = CURR_CARD_STATE(response.cmd_rsp0);
+
+ if (card_state == IDENT) {
+ rca_request = SUCCESS;
+ } else {
+ rca_request = FAIL;
+ diag_printf("Get RCA Failed.\n");
+ }
+ }
+
+ return rca_request;
+}
+
+static cyg_uint32 sd_get_bit_mode_support(void)
+{
+ command_t cmd;
+ cyg_uint32 rd_data_buff[128];
+ cyg_uint32 bit4_mode_support;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ /* Configure CMD55 for SD card */
+ /* This command expects RCA as argument. */
+ mxcmci_cmd_config(&cmd, CMD55, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue CMD55 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ bit4_mode_support = 0;
+ } else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Afetr giving ACMD Command, the R1 response should have
+ * STATUS_APP_CMD set
+ */
+ if (response.cmd_rsp0 & SD_R1_STATUS_APP_CMD_MSK) {
+
+ /* Configure ACMD51 for SD card */
+ /* This command expects No argument. */
+
+ mxcmci_cmd_config(&cmd, ACMD51, NO_ARG, READ,
+ RESPONSE_48, DATA_PRESENT, ENABLE,
+ ENABLE);
+
+ /* Issue ACMD51 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ bit4_mode_support = 0;
+ } else {
+ /* Read Response from e-SDHC buffer */
+ host_data_read(rd_data_buff, 512);
+
+ /* Check for bus width supported */
+ bit4_mode_support = (rd_data_buff[SD_BUS_WIDTH_OFFSET] & BIT_MODE_4_SUPPORT);
+
+ if (bit4_mode_support) {
+ bit4_mode_support = BIT_4_MODE;
+ }
+
+ }
+ }
+ }
+
+ return bit4_mode_support;
+}
+
+static cyg_uint32 sd_set_bus_width(cyg_uint32 bus_width)
+{
+ command_t cmd;
+ cyg_uint32 set_bus_width_status = 0;
+ command_response_t response;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+
+ if ((bus_width == FOUR) || (bus_width == ONE)) {
+ /* Configure CMD55 for SD card */
+ /* This command expects RCA as argument. */
+
+ mxcmci_cmd_config(&cmd, CMD55, card_address, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue CMD55 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ set_bus_width_status = FAIL;
+ } else {
+ /* Read Command response */
+ response.format = RESPONSE_48;
+ host_read_response(&response);
+
+ /* Afetr giving ACMD Command, the R1 response should have
+ * STATUS_APP_CMD set
+ */
+ if (response.cmd_rsp0 & SD_R1_STATUS_APP_CMD_MSK) {
+ bus_width = (bus_width >> ONE);
+
+ /* Configure ACMD6 for SD card */
+ mxcmci_cmd_config(&cmd, ACMD6, bus_width, READ,
+ RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE,
+ ENABLE);
+
+ /* Issue ACMD6 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ set_bus_width_status = FAIL;
+ } else {
+ set_bus_width_status = SUCCESS;
+ }
+ }
+ }
+ }
+
+ return set_bus_width_status;
+}
+
+/*==========================================================================
+FUNCTION: cyg_uint32 sd_set_boot_partition (void)
+DESCRIPTION:
+ sd_set_boot_partition() will set set boot partition for Partition1
+
+RETURN VALUE:
+ SUCCESS / FAILURE
+
+PRE-CONDITIONS:
+ None
+
+POST-CONDITIONS:
+ None
+
+Detailed Description:
+
+==============================================================================*/
+
+cyg_uint32 esd_set_boot_partition(cyg_uint32 *src_ptr, cyg_uint32 length)
+{
+ command_t cmd;
+ cyg_uint32 set_partition_status = FAIL;
+ command_response_t response;
+ cyg_uint8 response_data[512];
+ cyg_uint32 *response_pointer = (cyg_uint32 *) response_data;
+ cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
+ cyg_uint32 card_state;
+
+ /* Send CMD43 to select partition PARTITION1 active */
+ mxcmci_cmd_config(&cmd, CMD43,
+ 0x1<<24,
+ READ,
+ RESPONSE_48,
+ DATA_PRESENT_NONE,
+ ENABLE,
+ ENABLE);
+
+ if(host_send_cmd(&cmd) == FAIL) {
+ //diag_printf("%s: Send CMD43 Failed.\n", __FUNCTION__);
+ return 1;
+ }
+
+ set_partition_status = mmc_data_write (src_ptr, length, 0);
+ if(set_partition_status) {
+ return 1; /* failed */
+ }
+
+ return 0;
+}
+
+static cyg_uint32 sd_set_high_speed_mode(void)
+{
+ command_t cmd;
+ cyg_uint32 status = FAIL;
+ command_response_t response;
+
+ /* Configure CMD6 for SD card */
+ mxcmci_cmd_config(&cmd, CMD6, 0xfffff1, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue CMD6 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ status = FAIL;
+ diag_printf("Send CMD6 Failed.\n");
+ return FAIL;
+ } else {
+ hal_delay_us(1000);
+ status = SUCCESS;
+
+ }
+
+ mxcmci_cmd_config(&cmd, CMD6, 0x80fffff1, READ, RESPONSE_48,
+ DATA_PRESENT_NONE, ENABLE, ENABLE);
+
+ /* Issue CMD6 to SD Memory card */
+ if (host_send_cmd(&cmd) == FAIL) {
+ status = FAIL;
+ diag_printf("Send CMD6 Failed.\n");
+ } else {
+ /* wait until in transfer mode */
+ while (mxcmci_trans_status()) {
+ hal_delay_us(5);
+ }
+
+ status = SUCCESS;
+ }
+
+ return status;
+}
+
+/* end of mxcmic_sd.c */
--- /dev/null
+//==========================================================================
+//
+// spi_nor.c
+//
+// SPI NOR flash support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//========================================================================*/
+
+#include <pkgconf/hal.h>
+#include <pkgconf/system.h>
+#include <redboot.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+#include <cyg/hal/hal_io.h>
+#define _FLASH_PRIVATE_
+#include <cyg/io/flash.h>
+
+#include <cyg/io/imx_spi.h>
+#include <cyg/io/imx_spi_nor.h>
+
+static unsigned char g_tx_buf[256];
+static unsigned char g_rx_buf[256];
+static int spi_nor_init_ok;
+
+#define WRITE_ENABLE() spi_nor_cmd_1byte(WREN)
+#define WRITE_DISABLE() spi_nor_cmd_1byte(WRDI)
+#define ENABLE_WRITE_STATUS() spi_nor_cmd_1byte(EWSR)
+
+#ifndef MXCFLASH_SELECT_MULTI
+void flash_query(void* data)
+#else
+void spi_norflash_query(void* data)
+#endif
+{
+ unsigned char tmp[4];
+ unsigned char *ptr = (unsigned char *)data;
+
+ g_tx_buf[3] = JEDEC_ID;
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, tmp, 4) != 0) {
+ return;
+ }
+ diag_printf("JEDEC ID: 0x%02x:0x%02x:0x%02x\n", tmp[2], tmp[1], tmp[0]);
+ ptr[0] = tmp[2];
+ ptr[1] = tmp[1];
+ ptr[2] = tmp[0];
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_program_buf(void* addr, void* data, int len)
+#else
+int spi_norflash_program_buf(void* addr, void* data, int len)
+#endif
+{
+ return spi_nor_program_buf(addr, data, len);
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_erase_block(void* block, unsigned int size)
+#else
+int spi_norflash_erase_block(void* block, unsigned int size)
+#endif
+{
+ return spi_nor_erase_block(block, size);
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+bool flash_code_overlaps(void *start, void *end)
+#else
+bool spi_norflash_code_overlaps(void *start, void *end)
+#endif
+{
+ extern unsigned char _stext[], _etext[];
+
+ return ((((unsigned long)&_stext >= (unsigned long)start) &&
+ ((unsigned long)&_stext < (unsigned long)end)) ||
+ (((unsigned long)&_etext >= (unsigned long)start) &&
+ ((unsigned long)&_etext < (unsigned long)end)));
+}
+
+#ifndef MXCFLASH_SELECT_MULTI
+int flash_hwr_map_error(int e)
+#else
+int spi_norflash_hwr_map_error(int e)
+#endif
+{
+ return e;
+}
+
+//----------------------------------------------------------------------------
+// Now that device properties are defined, include magic for defining
+// accessor type and constants.
+#include <cyg/io/flash_dev.h>
+
+// Information about supported devices
+typedef struct flash_dev_info {
+ cyg_uint8 device_id;
+ cyg_uint8 device_id2;
+ cyg_uint8 device_id3;
+ cyg_uint8 device_id4;
+ cyg_uint32 block_size;
+ cyg_int32 block_count;
+ cyg_uint32 device_size;
+ cyg_uint32 fis_start_addr;
+ cyg_uint8 vendor_info[96];
+} __attribute__((aligned(4),packed))flash_dev_info_t;
+
+static const flash_dev_info_t* flash_dev_info;
+static const flash_dev_info_t supported_devices[] = {
+#include <cyg/io/spi_nor_parts.inl>
+};
+
+#define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
+
+#define ASSERT_SPI_NOR_INIT() \
+ do { \
+ if (spi_nor_init(&imx_spi_nor) != 0) { \
+ diag_printf("Error: failed to initialize SPI NOR\n"); \
+ return -1; \
+ } \
+ } while (0); \
+
+int
+#ifndef MXCFLASH_SELECT_MULTI
+flash_hwr_init(void)
+#else
+spi_norflash_hwr_init(void)
+#endif
+{
+ cyg_uint8 id[4];
+ int i;
+
+ if (!spi_nor_init_ok) {
+ diag_printf("Initializing SPI-NOR flash...\n");
+ if (spi_nor_init(&imx_spi_nor) != 0) {
+ diag_printf("Error: failed to initialize SPI NOR\n");
+ return -1;
+ }
+ spi_nor_init_ok = 1;
+ }
+ // Look through table for device data
+ flash_dev_query(id);
+ flash_dev_info = supported_devices;
+ for (i = 0; i < NUM_DEVICES; i++) {
+ if ((flash_dev_info->device_id == id[0]) &&
+ (flash_dev_info->device_id2 == id[1]) &&
+ (flash_dev_info->device_id3 == id[2]))
+ break;
+ flash_dev_info++;
+ }
+
+ // Do we find the device? If not, return error.
+ if (NUM_DEVICES == i) {
+ diag_printf("Unrecognized SPI NOR part: 0x%02x, 0x%02x, 0x%02x\n",
+ id[0], id[1], id[2]);
+ return FLASH_ERR_DRV_WRONG_PART;
+ }
+
+ // Hard wired for now
+ flash_info.block_size = flash_dev_info->block_size;
+ flash_info.blocks = flash_dev_info->block_count;
+ flash_info.start = (void *)0;
+ flash_info.end = (void *)flash_dev_info->device_size;
+
+ diag_printf("SPI NOR: block_size=0x%x, blocks=0x%x, start=%p, end=%p\n",
+ flash_info.block_size, flash_info.blocks,
+ flash_info.start, flash_info.end);
+
+ return FLASH_ERR_OK;
+}
+
+// used by redboot/current/src/flash.c
+int mxc_spi_nor_fis_start(void)
+{
+ return (flash_dev_info->fis_start_addr);
+}
+
+static int spi_nor_cmd_1byte(unsigned char cmd)
+{
+ g_tx_buf[0] = cmd;
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 1) != 0) {
+ diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * Read from SPI NOR at src address to RAM at dest with len bytes
+ * @param src source address in the flash
+ * @param dest destination address in the RAM
+ * @param len # of bytes to copy
+ */
+int spi_nor_read(void *src, void *dest, int len)
+{
+ unsigned int *cmd = (unsigned int *)g_tx_buf;
+ unsigned int max_rx_sz = imx_spi_nor.fifo_sz - 4; // max rx bytes per burst
+ unsigned char *d_buf = (unsigned char *) dest;
+ unsigned char *s_buf;
+ int i;
+
+ imx_spi_nor.us_delay = 100;
+ diag_printf1("%s(from flash=%p to ram=%p len=0x%x)\n", __FUNCTION__,
+ src, dest, len);
+
+ if (len == 0)
+ return 0;
+
+ *cmd = (READ << 24) | ((unsigned int)src & 0x00FFFFFF);
+
+ while (1) {
+ if (len == 0) {
+ imx_spi_nor.us_delay = 0;
+ return 0;
+ }
+ if (len < max_rx_sz) {
+ diag_printf1("last read len=0x%x\n", len);
+ // deal with the last read
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, len + 4) != 0) {
+ diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
+ return -1;
+ }
+ s_buf = g_rx_buf + 4; // throw away 4 bytes (5th received bytes is real)
+ // now adjust the endianness
+ for (i = len; i >= 0; i -= 4, s_buf += 4) {
+ if (i < 4) {
+ if (i == 1) {
+ *d_buf = s_buf[0];
+ } else if (i == 2) {
+ *d_buf++ = s_buf[1];
+ *d_buf++ = s_buf[0];
+ } else if (i == 3) {
+ *d_buf++ = s_buf[2];
+ *d_buf++ = s_buf[1];
+ *d_buf++ = s_buf[0];
+ }
+ imx_spi_nor.us_delay = 0;
+ return 0;
+ }
+ // copy 4 bytes
+ *d_buf++ = s_buf[3];
+ *d_buf++ = s_buf[2];
+ *d_buf++ = s_buf[1];
+ *d_buf++ = s_buf[0];
+ }
+ }
+ // now grab max_rx_sz data (+4 is needed due to 4-throw away bytes
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, max_rx_sz + 4) != 0) {
+ diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
+ return -1;
+ }
+ s_buf = g_rx_buf + 4; // throw away 4 bytes (5th received bytes is real)
+ // now adjust the endianness
+ for (i = 0; i < max_rx_sz; i += 4, s_buf += 4) {
+ *d_buf++ = s_buf[3];
+ *d_buf++ = s_buf[2];
+ *d_buf++ = s_buf[1];
+ *d_buf++ = s_buf[0];
+ }
+ *cmd += max_rx_sz; // increase # of bytes in NOR address as cmd == g_tx_buf
+ len -= max_rx_sz; // # of bytes left
+
+ diag_printf1("d_buf=%p, g_rx_buf=%p, len=0x%x\n", d_buf, g_rx_buf, len);
+ }
+
+ imx_spi_nor.us_delay = 0;
+}
+
+static int spi_nor_program_1byte(unsigned char data, void *addr)
+{
+ unsigned int addr_val = (unsigned int) addr;
+
+ // need to do write-enable command
+ if (WRITE_ENABLE() != 0) {
+ diag_printf("Error : %d\n", __LINE__);
+ return -1;
+ }
+ g_tx_buf[0] = BYTE_PROG; // need to skip bytes 1, 2, 3
+ g_tx_buf[4] = data;
+ g_tx_buf[5] = addr_val & 0xFF;
+ g_tx_buf[6] = (addr_val >> 8) & 0xFF;
+ g_tx_buf[7] = (addr_val >> 16) & 0xFF;
+
+ diag_printf("0x%x: 0x%x\n", *(unsigned int*)g_tx_buf, *(unsigned int*)(g_tx_buf + 4));
+ diag_printf("addr=0x%x\n", addr_val);
+
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 5) != 0) {
+ diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
+ return -1;
+ }
+
+ while (spi_nor_status() & RDSR_BUSY) {
+ }
+ return 0;
+}
+
+/*!
+ * program data from RAM to flash
+ * @param addr destination address in flash
+ * @param data source address in RAM
+ * @param len # of bytes to program
+ * Note: - when starting AAI programming,
+ * 1) the starting addr has to be 16-bit aligned
+ * 2) the prog len has to be even number of bytes
+ */
+int spi_nor_program_buf(void *addr, void *data, int len)
+{
+ unsigned int d_addr = (unsigned int) addr;
+ unsigned char *s_buf = (unsigned char *) data;
+
+ if (len == 0)
+ return 0;
+
+ diag_printf1("%s(flash addr=%p, ram=%p, len=0x%x)\n", __FUNCTION__, addr, data, len);
+ imx_spi_nor.us_delay = 0;
+
+ if (ENABLE_WRITE_STATUS() != 0 || spi_nor_write_status(0) != 0) {
+ diag_printf("Error: %s: %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ if ((d_addr & 1) != 0) {
+ // program 1st byte
+ if (spi_nor_program_1byte(s_buf[0], (void *)d_addr) != 0) {
+ diag_printf("Error: %s(%d)\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ if (--len == 0)
+ return 0;
+ d_addr++;
+ s_buf++;
+ }
+
+ // need to do write-enable command
+ if (WRITE_ENABLE() != 0) {
+ diag_printf("Error : %d\n", __LINE__);
+ return -1;
+ }
+
+ // These two bytes write will be copied to txfifo first with
+ // g_tx_buf[1] being shifted out and followed by g_tx_buf[0].
+ // The reason for this is we will specify burst len=6. So SPI will
+ // do this kind of data movement.
+ g_tx_buf[0] = d_addr >> 16;
+ g_tx_buf[1] = AAI_PROG; // need to skip bytes 1, 2
+ // byte shifted order is: 7, 6, 5, 4
+ g_tx_buf[4] = s_buf[1];
+ g_tx_buf[5] = s_buf[0];
+ g_tx_buf[6] = d_addr;
+ g_tx_buf[7] = d_addr >> 8;
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 6) != 0) {
+ diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
+ return -1;
+ }
+
+ while (spi_nor_status() & RDSR_BUSY) {
+ }
+
+ for (d_addr += 2, s_buf += 2, len -= 2 ;
+ len > 1;
+ d_addr += 2, s_buf += 2, len -= 2) {
+ // byte shifted order is: 2,1,0
+ g_tx_buf[2] = AAI_PROG;
+ g_tx_buf[1] = s_buf[0];
+ g_tx_buf[0] = s_buf[1];
+
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 3) != 0) {
+ diag_printf("Error: %s(%d): failed\n", __FILE__, __LINE__);
+ return -1;
+ }
+
+ while (spi_nor_status() & RDSR_BUSY) {
+ }
+ if ((len % flash_dev_info->block_size) == 0) {
+ diag_printf(".");
+ }
+ }
+ WRITE_DISABLE();
+ while (spi_nor_status() & RDSR_BUSY) {
+ }
+
+ if (WRITE_ENABLE() != 0) {
+ diag_printf("Error : %d\n", __LINE__);
+ return -1;
+ }
+ if (len == 1) {
+ // need to do write-enable command
+ // only 1 byte left
+ if (spi_nor_program_1byte(s_buf[0], (void *)d_addr) != 0) {
+ diag_printf("Error: %s(%d)\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int spi_nor_status(void)
+{
+ g_tx_buf[1] = RDSR;
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 2) != 0) {
+ diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
+ return 0;
+ }
+ return g_rx_buf[0];
+}
+
+/*!
+ * Write 'val' to flash WRSR (write status register)
+ */
+static int spi_nor_write_status(unsigned char val)
+{
+ g_tx_buf[0] = val;
+ g_tx_buf[1] = WRSR;
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 2) != 0) {
+ diag_printf("Error: %s(): %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * Erase a block_size data from block_addr offset in the flash
+ */
+int spi_nor_erase_block(void* block_addr, unsigned int block_size)
+{
+ unsigned int *cmd = (unsigned int *)g_tx_buf;
+ unsigned int addr = (unsigned int) block_addr;
+
+ imx_spi_nor.us_delay = 0;
+
+ if (block_size != SZ_64K && block_size != SZ_32K && block_size != SZ_4K) {
+ diag_printf("Error - block_size is not 64kB: 0x%x\n", block_size);
+ return -1;
+ }
+
+ if ((addr & (block_size -1)) != 0) {
+ diag_printf("Error - block_addr is not 64kB aligned: %p\n", block_addr);
+ return -1;
+ }
+ if (ENABLE_WRITE_STATUS() != 0 || spi_nor_write_status(0) != 0) {
+ diag_printf("Error: %s: %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ // need to do write-enable command
+ if (WRITE_ENABLE() != 0) {
+ diag_printf("Error : %d\n", __LINE__);
+ return -1;
+ }
+
+ if (block_size == SZ_64K) {
+ *cmd = (ERASE_64K << 24) | (addr & 0x00FFFFFF);
+ } else if (block_size == SZ_32K) {
+ *cmd = (ERASE_32K << 24) | (addr & 0x00FFFFFF);
+ } else if (block_size == SZ_4K) {
+ *cmd = (ERASE_4K << 24) | (addr & 0x00FFFFFF);
+ }
+
+ // now do the block erase
+ if (spi_nor_xfer(&imx_spi_nor, g_tx_buf, g_rx_buf, 4) != 0) {
+ return -1;
+ }
+
+ while (spi_nor_status() & RDSR_BUSY) {
+ }
+ return 0;
+}
+
+/*!
+ * Erase a variable bytes data from SPI NOR flash for 64K blocks
+ * @param block_addr starting addresss in the SPI NOR flash
+ * @param size # of bytes to erase
+ */
+int spi_nor_erase_64k(void* block_addr, unsigned int size)
+{
+ unsigned int addr = (unsigned int) block_addr;
+
+ if ((size % SZ_64K) != 0 || size == 0) {
+ diag_printf("Error: size (0x%x) is not integer multiples of 64kB(0x10000)\n", size);
+ return -1;
+ }
+ if ((addr & (SZ_64K -1)) != 0) {
+ diag_printf("Error - addr is not 64kB(0x10000) aligned: %p\n", block_addr);
+ return -1;
+ }
+ for (; size > 0; size -= SZ_64K, addr += SZ_64K) {
+ if (spi_nor_erase_block((void *)addr, SZ_64K) != 0) {
+ diag_printf("Error: spi_nor_erase_64k(): %d\n", __LINE__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void spi_nor_setup(void)
+{
+ if (!spi_nor_init_ok) {
+ diag_printf("Initializing SPI-NOR flash...\n");
+ if (spi_nor_init(&imx_spi_nor) != 0) {
+ diag_printf("Error: failed to initialize SPI NOR\n");
+ }
+ spi_nor_init_ok = 1;
+ }
+}
+
+RedBoot_init(spi_nor_setup, RedBoot_INIT_PRIO(6800));
+
+////////////////////////////// commands ///////////////////
+static void do_spi_nor_op(int argc, char *argv[]);
+RedBoot_cmd("spiflash",
+ "Read/Write/Erase SPI NOR flash",
+ "<ram-addr> <flash-addr> <len-bytes> <r/w/e>",
+ do_spi_nor_op
+ );
+
+static void do_spi_nor_op(int argc,char *argv[])
+{
+ unsigned int ram, flash, len;
+ unsigned char op;
+ int stat = -1;
+
+ if (argc == 1 || argc != 5) {
+ diag_printf("\tRead: spiflash <ram-addr> <flash-addr> <len-bytes> <r>\n");
+ diag_printf("\tWrite: spiflash <ram-addr> <flash-addr> <len-bytes> <w>\n");
+ diag_printf("\tErase: spiflash <ram-addr> <flash-addr> <len-bytes> <e>\n");
+ diag_printf(" NOTE: For erase, the ram-addr is ignored\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)&ram, &argv[1], ":")) {
+ diag_printf("Error: Invalid ram parameter\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[2]), (unsigned long *)&flash, &argv[2], ":")) {
+ diag_printf("Error: Invalid flash parameter\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[3]), (unsigned long *)&len, &argv[3], ":")) {
+ diag_printf("Error: Invalid length parameter\n");
+ return;
+ }
+
+ op = argv[4][0];
+ switch (op) {
+ case 'r':
+ case 'R':
+ diag_printf("Reading SPI NOR flash 0x%x [0x%x bytes] -> ram 0x%x\n", flash, len, ram);
+ stat = spi_nor_read((void *)flash, (void *)ram, len);
+ break;
+ case 'w':
+ case 'W':
+ diag_printf("Writing SPI NOR flash 0x%x [0x%x bytes] <- ram 0x%x\n", flash, len, ram);
+ stat = spi_nor_program_buf((void *)flash, (void *)ram, len);
+ break;
+ case 'e':
+ case 'E':
+ diag_printf("Erasing SPI NOR flash 0x%x [0x%x bytes]\n", flash, len);
+ stat = spi_nor_erase_64k((void *)flash, len);
+ break;
+ default:
+ diag_printf("Error: unknown operation: 0x%02x\n", op);
+ }
+ diag_printf("%s\n\n", (stat == 0)? "SUCCESS": "FAILED");
+ return;
+}
--- /dev/null
+# ====================================================================
+#
+# mxc_i2c.cdl
+#
+# A Freescale MXC I2C package.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric, Ltd
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Kevin Zhang
+# Contributors:
+# Date: 2006-08-23
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_MXC_I2C {
+ display "I2C driver for FSL MXC-based platforms"
+
+ compile -library=libextras.a mxc_i2c.c
+
+ include_dir cyg/io
+}
--- /dev/null
+//==========================================================================
+//
+// mxc_i2c.h
+//
+// I2C support on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#ifndef __MXC_I2C_H__
+#define __MXC_I2C_H__
+
+#define I2C_AR 0x0
+#define I2C_IFDR 0x4
+#define I2C_I2CR 0x8
+#define I2C_I2SR 0xC
+#define I2C_I2DR 0x10
+
+#define I2C_I2CR_IEN (1 << 7)
+#define I2C_I2CR_IIEN (1 << 6)
+#define I2C_I2CR_MSTA (1 << 5)
+#define I2C_I2CR_MTX (1 << 4)
+#define I2C_I2CR_TXAK (1 << 3)
+#define I2C_I2CR_RSTA (1 << 2)
+
+#define I2C_I2SR_ICF (1 << 7)
+#define I2C_I2SR_IAAS (1 << 6)
+#define I2C_I2SR_IBB (1 << 5)
+#define I2C_I2SR_IAL (1 << 4)
+#define I2C_I2SR_SRW (1 << 2)
+#define I2C_I2SR_IIF (1 << 1)
+#define I2C_I2SR_RXAK (1 << 0)
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+struct mxc_i2c_request {
+ unsigned int dev_addr;
+ unsigned int reg_addr;
+ unsigned int reg_addr_sz;
+ unsigned char * buffer;
+ unsigned int buffer_sz;
+};
+
+extern unsigned int i2c_base_addr[];
+extern unsigned int i2c_num;
+
+extern int i2c_init(unsigned int base, unsigned int baud);
+extern int i2c_xfer(unsigned int i2c_nr, struct mxc_i2c_request *rq, int dir);
+
+#endif /* __MXC_I2C_H__ */
--- /dev/null
+//==========================================================================
+//
+// mxc_i2c.c
+//
+// I2C support on Freescale MXC platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#include <redboot.h>
+#include <stdlib.h>
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+
+#include <cyg/hal/fsl_board.h>
+#include <cyg/io/mxc_i2c.h>
+
+extern void mxc_i2c_init(unsigned int module_base);
+
+//#define MXC_I2C_DEBUG
+#undef MXC_I2C_DEBUG
+
+#ifdef MXC_I2C_DEBUG
+#define diag_printf1 diag_printf
+#else
+#define diag_printf1(fmt,args...)
+#endif
+
+struct clk_div_table {
+ int reg_value;
+ int div;
+};
+
+static const struct clk_div_table i2c_clk_table[] = {
+ {0x20, 22}, {0x21, 24}, {0x22, 26}, {0x23, 28},
+ {0, 30}, {1, 32}, {0x24, 32}, {2, 36},
+ {0x25, 36}, {0x26, 40}, {3, 42}, {0x27, 44},
+ {4, 48}, {0x28, 48}, {5, 52}, {0x29, 56},
+ {6, 60}, {0x2A, 64}, {7, 72}, {0x2B, 72},
+ {8, 80}, {0x2C, 80}, {9, 88}, {0x2D, 96},
+ {0xA, 104}, {0x2E, 112}, {0xB, 128}, {0x2F, 128},
+ {0xC, 144}, {0xD, 160}, {0x30, 160}, {0xE, 192},
+ {0x31, 192}, {0x32, 224}, {0xF, 240}, {0x33, 256},
+ {0x10, 288}, {0x11, 320}, {0x34, 320}, {0x12, 384},
+ {0x35, 384}, {0x36, 448}, {0x13, 480}, {0x37, 512},
+ {0x14, 576}, {0x15, 640}, {0x38, 640}, {0x16, 768},
+ {0x39, 768}, {0x3A, 896}, {0x17, 960}, {0x3B, 1024},
+ {0x18, 1152}, {0x19, 1280}, {0x3C, 1280}, {0x1A, 1536},
+ {0x3D, 1536}, {0x3E, 1792}, {0x1B, 1920}, {0x3F, 2048},
+ {0x1C, 2304}, {0x1D, 2560}, {0x1E, 3072}, {0x1F, 3840},
+ {0, 0}
+};
+
+#define ERR_TX -1
+#define ERR_RX -2
+#define ERR_ARB_LOST -3
+#define ERR_NO_ACK -4
+#define ERR_XFER -5
+#define ERR_RX_ACK -6
+
+static inline int wait_till_busy(unsigned int base)
+{
+ int i = 10000;
+
+ while(((readw(base + I2C_I2SR) & I2C_I2SR_IBB) == 0) && (--i > 0)) {
+ if (readw(base + I2C_I2SR) & I2C_I2SR_IAL) {
+ diag_printf1("Error: arbitration lost!\n");
+ return ERR_ARB_LOST;
+ }
+ }
+
+ if (i <= 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static unsigned int g_dev_addr_width, g_dev_data_width;
+static unsigned char g_dev_value[4];
+static unsigned int g_i2c_nr = -1;
+
+static inline int is_bus_free(unsigned int base)
+{
+ return ((readw(base + I2C_I2SR) & I2C_I2SR_IBB) == 0);
+}
+
+#define ASSERT_NO_ARBITRATION_LOST(stat) \
+{ \
+ if (stat & I2C_I2SR_IAL) { \
+ diag_printf("Error %d: Arbitration lost\n", __LINE__); \
+ return ERR_ARB_LOST; \
+ } \
+}
+
+#define WAIT_RXAK_LOOPS 1000000
+
+static inline unsigned short wait_op_done(unsigned int base, int is_tx)
+{
+ volatile unsigned short v;
+ int i = WAIT_RXAK_LOOPS;
+
+ while ((((v = readw(base + I2C_I2SR)) & I2C_I2SR_IIF) == 0 ||
+ (v & I2C_I2SR_ICF) == 0) && --i > 0) {
+ if (v & I2C_I2SR_IAL) {
+ diag_printf1("Error %d: Arbitration lost\n", __LINE__);
+ return ERR_ARB_LOST;
+ }
+
+ }
+ if (i <= 0) {
+ diag_printf1("I2C Error: timeout unexpected\n");
+ return -1;
+ }
+ if (is_tx) {
+ if (v & I2C_I2SR_IAL) {
+ diag_printf1("Error %d: Arbitration lost\n", __LINE__);
+ return ERR_ARB_LOST;
+ }
+ if (v & I2C_I2SR_RXAK) {
+ diag_printf1("Error %d: no ack received\n", __LINE__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+//
+// For master TX, always expect a RXAK signal to be set!
+static int tx_byte(unsigned char *data, unsigned int base)
+{
+ diag_printf1("%s(data=0x%02x, base=0x%x)\n", __FUNCTION__, *data, base);
+
+ // clear both IAL and IIF bits
+ writew(0, base + I2C_I2SR);
+
+ writew(*data, base + I2C_I2DR);
+
+ if (wait_op_done(base, 1) != 0)
+ return -1;
+
+ return 0;
+}
+
+// For master RX
+static int rx_bytes(unsigned char *data, unsigned int base, int sz)
+{
+ unsigned short i2cr;
+ int i;
+
+ for (i = 0; sz > 0; sz--, i++) {
+ if (wait_op_done(base, 0) != 0)
+ return -1;
+
+ // clear both IAL and IIF bits
+ writew(0, base + I2C_I2SR);
+
+ // the next two if-statements setup for the next read control register value
+ if (sz == 1) {
+ // last byte --> generate STOP
+ i2cr = readw(base + I2C_I2CR);
+ writew(i2cr & ~(I2C_I2CR_MSTA | I2C_I2CR_MTX), base + I2C_I2CR);
+ }
+ if (sz == 2) {
+ // 2nd last byte --> set TXAK bit to NOT generate ACK
+ i2cr = readw(base + I2C_I2CR);
+ writew(i2cr | I2C_I2CR_TXAK, base + I2C_I2CR);
+ }
+
+ // read the true data
+ data[i] = readw(base + I2C_I2DR);
+ diag_printf1("OK 0x%02x\n", data[i]);
+ }
+ return 0;
+}
+
+int i2c_xfer(unsigned int i2c_nr, struct mxc_i2c_request *rq, int dir)
+{
+ unsigned int base, reg;
+ unsigned char i, data;
+ unsigned short i2cr;
+ int ret = 0;
+
+ if ( rq == NULL || i2c_nr >= i2c_num) {
+ diag_printf("Invalid request or invalid i2c port number\n");
+ return -1;
+ }
+
+ base = i2c_base_addr[i2c_nr];
+ if (rq->reg_addr_sz == 0 || rq->buffer_sz == 0 || rq->buffer == NULL) {
+ diag_printf("Invalid register address size=%x, buffer size=%x, buffer=%x\n",
+ rq->reg_addr_sz, rq->buffer_sz, (unsigned int)rq->buffer);
+ return -1;
+ }
+
+ // reset and enable I2C
+ writew(0, base + I2C_I2CR);
+
+ writew(I2C_I2CR_IEN, base + I2C_I2CR);
+
+ /* Need wait at least 2 cycles of per_clk*/
+ for (i = 0; i < 16; i++) {
+ asm("nop");
+ }
+ // Step 1: generate START signal
+ // 1.1 make sure bus is free
+ if (!is_bus_free(base)) {
+ return -1;
+ }
+ // 1.2 clear both IAL and IIF bits
+ writew(0, base + I2C_I2SR);
+
+ // 1.3 assert START signal and also indicate TX mode
+ i2cr = I2C_I2CR_IEN | I2C_I2CR_MSTA | I2C_I2CR_MTX;
+ writew(i2cr, base + I2C_I2CR);
+
+ // 1.4 make sure bus is busy after the START signal
+ if (wait_till_busy(base) != 0) {
+ return ERR_TX;
+ }
+
+ // Step 2: send slave address + read/write at the LSB
+ data = (rq->dev_addr << 1) | I2C_WRITE;
+ if (tx_byte(&data, base) != 0) {
+ return -1;
+ }
+
+ // Step 3: send I2C device register address
+ if (rq->reg_addr_sz > 4) {
+ diag_printf("Warning register address size %d should less than 4\n",
+ rq->reg_addr_sz);
+ rq->reg_addr_sz = 4;
+ }
+ reg = rq->reg_addr;
+
+ for (i = 0; i < rq->reg_addr_sz; i++, reg>>=8) {
+ data = reg & 0xFF;
+ diag_printf1("sending I2C=0x%x device register: data=0x%x, byte %d\n",
+ base, data, i);
+ if (tx_byte(&data, base) != 0) {
+ return -1;
+ }
+ }
+ // Step 4: read/write data
+ if (dir == I2C_READ) {
+ // do repeat-start
+ i2cr = readw(base + I2C_I2CR);
+ writew(i2cr | I2C_I2CR_RSTA, base + I2C_I2CR);
+
+ // send slave address again, but indicate read operation
+ data = (rq->dev_addr << 1) | I2C_READ;
+ if (tx_byte(&data, base) != 0) {
+ return -1;
+ }
+
+ // change to receive mode
+ i2cr = readw(base + I2C_I2CR);
+ if (rq->buffer_sz == 1) {
+ // if only one byte to read, make sure don't send ack
+ i2cr |= I2C_I2CR_TXAK;
+ }
+ writew(i2cr & ~I2C_I2CR_MTX, base + I2C_I2CR);
+ // dummy read
+ readw(base + I2C_I2DR);
+
+ // now reading ...
+ if (rx_bytes(rq->buffer, base, rq->buffer_sz) != 0) {
+ return -1;
+ }
+ } else {
+ // I2C_WRITE
+ for (i = 0; i < rq->buffer_sz; i++) {
+ // send device register value
+ data = rq->buffer[i];
+ if ((ret = tx_byte(&data, base)) != 0) {
+ break;
+ }
+ }
+ // generate STOP by clearing MSTA bit
+ writew(I2C_I2CR_IEN | I2C_I2CR_MTX, base + I2C_I2CR);
+ }
+
+ return ret;
+}
+
+/*!
+ * Initialize and enable a i2c module -- mainly enable the I2C clock, module
+ * itself and the I2C clock prescaler.
+ *
+ * @param base base address of i2c module (also assigned for I2Cx_CLK)
+ * @param baue the desired data rate
+ *
+ * @return 0 if successful; non-zero otherwise
+ */
+int i2c_init(unsigned int base, unsigned int baud)
+{
+ unsigned int clock = get_main_clock(IPG_PER_CLK);
+ int div = clock / baud;
+ struct clk_div_table *p = (struct clk_div_table *)&i2c_clk_table[0];
+
+ mxc_i2c_init(base);
+
+ // reset and enable I2C
+ writew(0, base + I2C_I2CR);
+ writew(I2C_I2CR_IEN, base + I2C_I2CR);
+
+ while (p->div != 0) {
+ if (div <= p->div)
+ break;
+ p++;
+ }
+
+ if (p->div == 0) {
+ diag_printf("Error: can't meet I2C baud rate request (%d) for 0x%x)\n",
+ baud, base);
+ return -1;
+ }
+
+ diag_printf1("baud=%d, div=%d, reg_val=%d\n", baud, p->div, p->reg_value);
+
+ writew(p->reg_value, base + I2C_IFDR);
+
+ diag_printf1("requested data rate is: %d, actual rate is: %d\n",
+ baud, clock / p->div);
+
+ return 0;
+}
+
+static void do_i2c(int argc, char *argv[]);
+RedBoot_cmd("i2c",
+ "i2c R/W operations as master",
+ "<i2c slave addr> <register index> [<regisetr val>]]",
+ do_i2c
+ );
+
+
+static void do_i2c(int argc,char *argv[])
+{
+ int dir = I2C_READ, i;
+ unsigned long v;
+ unsigned int dev_addr, dev_reg;
+ struct mxc_i2c_request rq;
+
+ if (g_i2c_nr == -1) {
+ diag_printf("I2C module [%d] not initialized. Issue i2c_init first\n\n", g_i2c_nr);
+ return;
+ }
+ if (argc == 1) {
+ diag_printf("\tRead: i2c <i2c_dev_addr> <dev_reg_addr>\n");
+ diag_printf("\tWrite: i2c <i2c_dev_addr> <dev_reg_addr> <dev_reg_val>\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)&dev_addr, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter %d\n", __LINE__);
+ return;
+ }
+
+ if (!parse_num(*(&argv[2]), (unsigned long *)&dev_reg, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter %d\n", __LINE__);
+ return;
+ }
+
+ if (argc == 4) {
+ if (!parse_num(*(&argv[3]), &v, &argv[3], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ dir = I2C_WRITE;
+ diag_printf("Writing I2C[%d] for addr 0x%x register 0x%x with value 0x%08lx\n",
+ g_i2c_nr, dev_addr, dev_reg, v);
+ for (i = 0; i < g_dev_data_width; i++) {
+ g_dev_value[i] = v >> (8 * (g_dev_data_width - i - 1)) & 0xff;
+ }
+ diag_printf1("testing reversed data: 0x%08x\n", *(unsigned int*)g_dev_value);
+
+ } else {
+ diag_printf("Reading I2C [%d] from slave addr [0x%x] register [0x%x]\n",
+ g_i2c_nr, dev_addr, dev_reg);
+ }
+
+ rq.dev_addr = dev_addr;
+ rq.reg_addr = dev_reg;
+ rq.reg_addr_sz = g_dev_addr_width;
+ rq.buffer = g_dev_value;
+ rq.buffer_sz = g_dev_data_width;
+
+ if (i2c_xfer(g_i2c_nr, &rq, dir) != 0) {
+ diag_printf("Error I2C transfer 1\n\n");
+ return;
+ }
+
+ if (dir == I2C_READ) {
+ diag_printf("---> ");
+ for (i = 0; i < g_dev_data_width; i++) {
+ diag_printf("0x%02x ", g_dev_value[i]);
+ }
+ diag_printf("\n\n");
+ }
+}
+
+static void do_i2c_init(int argc, char *argv[]);
+RedBoot_cmd("i2c_init",
+ "Initialize i2c (i2c_num is 0-indexed)",
+ "<i2c_num> <frequency> <device addr width> <device reg width>",
+ do_i2c_init
+ );
+
+static void do_i2c_init(int argc,char *argv[])
+{
+ unsigned freq;
+
+ if (argc == 1 || argc != 5) {
+ diag_printf("\ni2c_init <i2c_num> <frequency> <device addr width> <device data width>\n\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)&g_i2c_nr, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ if (g_i2c_nr > i2c_num - 1) {
+ diag_printf("invalide i2c number: %d, max number is: %d\n", g_i2c_nr, i2c_num - 1);
+ return;
+ }
+ diag_printf1("i2c max number is: %d\n", i2c_num - 1);
+
+ if (!parse_num(*(&argv[2]), (unsigned long *)&freq, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ if (!parse_num(*(&argv[3]), (unsigned long *)&g_dev_addr_width, &argv[3], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ if (!parse_num(*(&argv[4]), (unsigned long *)&g_dev_data_width, &argv[4], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ i2c_init(i2c_base_addr[g_i2c_nr], freq);
+
+ diag_printf("initializing i2c:%d, addr-width:%d, data-width:%d\n\n",
+ g_i2c_nr, g_dev_addr_width, g_dev_data_width);
+}
--- /dev/null
+# ====================================================================
+#
+# mc34704.cdl
+#
+# A PMIC package for i.MX25 3stack.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric, Ltd
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Quinn Jensen
+# Contributors:
+# Date: 2008-05-08
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_PMIC_ARM_IMX25_3STACK {
+ display "PMIC driver for i.MX25 3stack platforms"
+
+ compile -library=libextras.a mc34704.c
+
+ include_dir cyg/io
+
+ define_proc {
+ puts $::cdl_header "#include <pkgconf/system.h>";
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C {
+ display "Support I2C interface to PMIC"
+ default_value 0
+ active_if CYGPKG_DEVS_MXC_I2C
+ description "
+ When this option is enabled, it enables i2c interface
+ to access pmic device on the i.MX25 3stack platform"
+ define_proc {
+ puts $::cdl_system_header "#define MXC_PMIC_I2C_ENABLED"
+ }
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C_PORT {
+ display "I2C interface number to PMIC"
+ flavor data
+ default_value 0
+ active_if CYGHWR_DEVS_PMIC_I2C
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C_ADDR {
+ display "I2C addess of PMIC"
+ flavor data
+ default_value 0
+ active_if CYGHWR_DEVS_PMIC_I2C
+ }
+}
--- /dev/null
+//==========================================================================
+//
+// mc34704.h
+//
+// PMIC support on i.mx25 3stack platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#ifndef __MC34704_H__
+#define __MC34704_H__
+
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write);
+
+#endif /* __MC34704_H__ */
--- /dev/null
+//==========================================================================
+//
+// mc34704.c
+//
+// PMIC support on i.MX25 3stack platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#include <redboot.h>
+#include <stdlib.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/devs_pmic_arm_imx25_3stack.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/fsl_board.h>
+#include <cyg/io/mxc_i2c.h>
+#include <cyg/io/mc34704.h>
+
+#define MC34704_REG_MAX 0x59
+
+static void mxc_pmic_init(void)
+{
+ if (CYGHWR_DEVS_PMIC_I2C_PORT >= i2c_num)
+ return;
+
+ i2c_init(i2c_base_addr[CYGHWR_DEVS_PMIC_I2C_PORT], 40000);
+
+ diag_printf("Turning on PMIC regulators: 1,2,3,4,5\n");
+
+ pmic_reg(0x02, 0x09, 1);
+}
+
+RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
+
+static void do_pmic(int argc, char *argv[]);
+RedBoot_cmd("pmic",
+ "Read/Write internal PMIC register",
+ "<reg num> [value to be written]",
+ do_pmic);
+
+static void do_pmic(int argc,char *argv[])
+{
+ unsigned int reg, temp, val = 0, write = 0;
+
+ if (argc == 1) {
+ diag_printf("\tRead: pmic <reg num>\n");
+ diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ if (argc == 3) {
+ if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ write = 1;
+ }
+
+ temp = pmic_reg(reg, val, write);
+
+ diag_printf("\tval: 0x%08x\n\n", temp);
+}
+
+static unsigned int pmic_reg_i2c(unsigned int reg, unsigned int val, unsigned int write)
+{
+ struct mxc_i2c_request rq;
+ rq.dev_addr = CYGHWR_DEVS_PMIC_I2C_ADDR;
+ rq.reg_addr = reg;
+ rq.reg_addr_sz = 1;
+ rq.buffer = (unsigned char *)&val;
+ rq.buffer_sz = 1;
+ write = write ? I2C_WRITE : I2C_READ;
+ if (i2c_xfer(CYGHWR_DEVS_PMIC_I2C_PORT, &rq, write) != 0) {
+ diag_printf("Error in I2C transaction\n\n");
+ return 0;
+ }
+ return val;
+}
+
+/*!
+ * To read/write to a PMIC register. For write, it does another read for the
+ * actual register value.
+ *
+ * @param reg register number inside the PMIC
+ * @param val data to be written to the register; don't care for read
+ * @param write 0 for read; 1 for write
+ *
+ * @return the actual data in the PMIC register
+ */
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
+{
+ if (reg > MC34704_REG_MAX) {
+ diag_printf("<reg num> = %d is invalid. Should be less than %d\n",
+ reg, MC34704_REG_MAX);
+ return 0;
+ }
+ return pmic_reg_i2c(reg, val, write);
+}
--- /dev/null
+# ====================================================================
+#
+# mc9s08dz.cdl
+#
+# A PMIC package for i.MX35 3stack.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric, Ltd
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Fred Fan
+# Contributors:
+# Date: 2008-05-08
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_PMIC_ARM_IMX35_3STACK {
+ display "PMIC driver for i.MX35 3stack platforms"
+
+ compile -library=libextras.a mc9s08dz.c
+
+ include_dir cyg/io
+
+ define_proc {
+ puts $::cdl_header "#include <pkgconf/system.h>";
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_SPI {
+ display "Support SPI interface to PMIC"
+ default_value 0
+ active_if CYGPKG_DEVS_MXC_SPI
+
+ description "
+ When this option is enabled, it enables spi interface
+ to access pmic device on the i.MX35 3stack platform"
+ define_proc {
+ puts $::cdl_system_header "#define MXC_PMIC_SPI_ENABLED"
+ }
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_SPI_PORT {
+ display "SPI interface number to PMIC"
+ flavor data
+ default_value 0
+ active_if CYGHWR_DEVS_PMIC_SPI
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C {
+ display "Support I2C interface to PMIC"
+ default_value 0
+ active_if CYGPKG_DEVS_MXC_I2C
+ description "
+ When this option is enabled, it enables i2c interface
+ to access pmic device on the i.MX35 3stack platform"
+ define_proc {
+ puts $::cdl_system_header "#define MXC_PMIC_I2C_ENABLED"
+ }
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C_PORT {
+ display "I2C interface number to PMIC"
+ flavor data
+ default_value 0
+ active_if CYGHWR_DEVS_PMIC_I2C
+ }
+
+ cdl_option CYGHWR_DEVS_PMIC_I2C_ADDR {
+ display "I2C addess of PMIC"
+ flavor data
+ default_value 0
+ active_if CYGHWR_DEVS_PMIC_I2C
+ }
+}
--- /dev/null
+//==========================================================================
+//
+// mc9s08dz.h
+//
+// PMIC support on i.mx35 3stack platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#ifndef __MC9S08DZ_H__
+#define __MC9S08DZ_H__
+
+#define MC9S08DZ_MAX_REGS 0x28
+
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write);
+
+#endif /* __MC9S08DZ_H__ */
--- /dev/null
+//==========================================================================
+//
+// mc9s08dz.c
+//
+// PMIC support on i.MX35 3stack platforms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+
+#include <redboot.h>
+#include <stdlib.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/devs_pmic_arm_imx35_3stack.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/fsl_board.h>
+#ifdef MXC_PMIC_I2C_ENABLED
+#include <cyg/io/mxc_i2c.h>
+#endif // MXC_PMIC_I2C_ENABLED
+#include <cyg/io/mc9s08dz.h>
+
+extern unsigned int system_rev;
+
+static void mxc_pmic_init(void)
+{
+ volatile unsigned int rev_id;
+
+#ifdef MXC_PMIC_I2C_ENABLED
+ if (CYGHWR_DEVS_PMIC_I2C_PORT >= i2c_num)
+ return;
+// 40kHz data rate
+ i2c_init(i2c_base_addr[CYGHWR_DEVS_PMIC_I2C_PORT], 40000);
+#else
+#error "Please select a valid interface"
+#endif // MXC_PMIC_I2C_ENABLED
+
+ rev_id = pmic_reg(0, 0, 0);
+ diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
+ switch (rev_id & 0x1F) {
+ case 0x10:
+ diag_printf("1.0");
+ break;
+ default:
+ diag_printf("unknown");
+ break;
+ }
+ diag_printf("]\n");
+}
+
+RedBoot_init(mxc_pmic_init, RedBoot_INIT_PRIO(100));
+
+static void do_pmic(int argc, char *argv[]);
+RedBoot_cmd("pmic",
+ "Read/Write internal PMIC register",
+ "<reg num> [value to be written]", do_pmic);
+
+static void do_pmic(int argc, char *argv[])
+{
+ unsigned int reg, temp, val = 0, write = 0;
+
+ if (argc == 1) {
+ diag_printf("\tRead: pmic <reg num>\n");
+ diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ if (argc == 3) {
+ if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ write = 1;
+ }
+
+ temp = pmic_reg(reg, val, write);
+
+ diag_printf("\tval: 0x%08x\n\n", temp);
+}
+
+#ifdef MXC_PMIC_I2C_ENABLED
+static unsigned int pmic_reg_i2c(unsigned int reg, unsigned int val,
+ unsigned int write)
+{
+ struct mxc_i2c_request rq;
+ rq.dev_addr = CYGHWR_DEVS_PMIC_I2C_ADDR;
+ rq.reg_addr = reg;
+ rq.reg_addr_sz = 1;
+ rq.buffer = (unsigned char *)&val;
+ rq.buffer_sz = 1;
+ write = write ? I2C_WRITE : I2C_READ;
+ if (i2c_xfer(CYGHWR_DEVS_PMIC_I2C_PORT, &rq, write) != 0) {
+ diag_printf("Error I2C transfer\n\n");
+ return 0;
+ }
+ return val;
+}
+#endif //MXC_PMIC_I2C_ENABLED
+/*!
+ * To read/write to a PMIC register. For write, it does another read for the
+ * actual register value.
+ *
+ * @param reg register number inside the PMIC
+ * @param val data to be written to the register; don't care for read
+ * @param write 0 for read; 1 for write
+ *
+ * @return the actual data in the PMIC register
+ */
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
+{
+ if (reg > MC9S08DZ_MAX_REGS) {
+ diag_printf("<reg num> = %d is invalide. Should be less then 0x28\n",
+ reg);
+ return 0;
+ }
+#ifdef MXC_PMIC_I2C_ENABLED
+ return pmic_reg_i2c(reg, val, write);
+#else
+ return 0;
+#endif //MXC_PMIC_I2C_ENABLED
+}
+
+static void mxc_pmic_detect(void)
+{
+ struct mxc_i2c_request rq;
+ unsigned char buf[4] = { 0 };
+
+ rq.dev_addr = 0x34;
+ rq.reg_addr = 0x10;
+ rq.reg_addr_sz = 1;
+ rq.buffer = buf;
+ rq.buffer_sz = 1;
+
+ if (i2c_xfer(0, &rq, I2C_WRITE) != 0) {
+ /* v2.0 board which does not have max8660 */
+ system_rev |= 0x1 << 8;
+ /* workaround for WDOG reset pin */
+ writel(0x11, IOMUXC_BASE_ADDR + 0xC);
+ diag_printf("Board version V2.0\n");
+ } else {
+ diag_printf("Board version V1.0\n");
+ }
+
+#ifdef CYGPKG_DEVS_ETH_FEC
+ /**
+ * if we have v2.0 board, need to enable
+ * APLite VGEN1 regulator
+ */
+ if (system_rev & 0xF00) {
+ /* set VGEN voltage to 3.3v */
+ rq.dev_addr = 0x08;
+ rq.reg_addr = 0x1E; /* VGEN REG0 setting */
+ rq.reg_addr_sz = 1;
+ rq.buffer = buf;
+ rq.buffer_sz = 3;
+ i2c_xfer(0, &rq, I2C_READ);
+ rq.buffer_sz = 3;
+ buf[2] |= 0x3;
+ i2c_xfer(0, &rq, I2C_WRITE);
+ /* enable FEC 3v3 */
+ rq.dev_addr = 0x08;
+ rq.reg_addr = 0x20; /* VGEN REG0 */
+ rq.reg_addr_sz = 1;
+ rq.buffer = buf;
+ rq.buffer_sz = 3;
+ i2c_xfer(0, &rq, I2C_READ);
+ rq.buffer_sz = 3;
+ buf[2] |= 0x1;
+ i2c_xfer(0, &rq, I2C_WRITE);
+ }
+#endif
+
+}
+
+RedBoot_init(mxc_pmic_detect, RedBoot_INIT_PRIO(101));
--- /dev/null
+# ====================================================================
+#
+# spi.cdl
+#
+# A Freescale i.MX SPI package.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric, Ltd
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Kevin Zhang
+# Contributors:
+# Date: 2008-11-14
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_IMX_SPI {
+ display "SPI driver for FSL i.MX based platforms"
+
+ compile -library=libextras.a imx_spi.c
+
+ include_dir cyg/io
+
+}
--- /dev/null
+#ifndef __IMX_SPI_H__
+#define __IMX_SPI_H__
+
+#undef IMX_SPI_DEBUG
+//#define IMX_SPI_DEBUG
+
+#ifdef IMX_SPI_DEBUG
+#define diag_printf1 diag_printf
+#else
+#define diag_printf1(fmt,args...)
+#endif
+
+#define IMX_SPI_ACTIVE_HIGH 1
+#define IMX_SPI_ACTIVE_LOW 0
+#define SPI_RETRY_TIMES 100
+
+// Only for SPI master support
+struct imx_spi_dev {
+ unsigned int base; // base address of SPI module the device is connected to
+ unsigned int freq; // desired clock freq in Hz for this device
+ unsigned int ss_pol; // ss polarity: 1=active high; 0=active low
+ unsigned int ss; // slave select
+ unsigned int in_sctl; // inactive sclk ctl: 1=stay low; 0=stay high
+ unsigned int in_dctl; // inactive data ctl: 1=stay low; 0=stay high
+ unsigned int ssctl; // single burst mode vs multiple: 0=single; 1=multi
+ unsigned int sclkpol; // sclk polarity: active high=0; active low=1
+ unsigned int sclkpha; // sclk phase: 0=phase 0; 1=phase1
+ unsigned int fifo_sz; // fifo size in bytes for either tx or rx. Don't add them up!
+ unsigned int us_delay; // us delay in each xfer
+ void *reg; // pointer to a set of SPI registers
+};
+
+struct spi_v2_3_reg {
+ unsigned int ctrl_reg;
+ unsigned int cfg_reg;
+};
+
+// setup IOMUX for the spi device
+//
+int imx_spi_init_v2_3 (
+ struct imx_spi_dev *dev
+ );
+
+// transfer up to fifo bytes data via spi. The data transferred is the sum of both the tx and rx
+int imx_spi_xfer_v2_3 (
+ struct imx_spi_dev *dev, // spi device pointer
+ unsigned char *tx_buf, // tx buffer (has to be 4-byte aligned)
+ unsigned char *rx_buf, // rx buffer (has to be 4-byte aligned)
+ int burst_bytes // total number of bytes in one burst or xfer
+ );
+
+typedef int imx_spi_init_func_t(struct imx_spi_dev *);
+typedef int imx_spi_xfer_func_t(struct imx_spi_dev *, unsigned char *, unsigned char *, int);
+
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write);
+
+void io_cfg_spi(struct imx_spi_dev *dev);
+
+#endif // __IMX_SPI_H__
--- /dev/null
+#include <redboot.h>
+#include <stdlib.h>
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+
+#include <cyg/hal/fsl_board.h>
+#include <cyg/io/imx_spi.h>
+
+/*!
+ * Initialization function for a spi slave device. It must be called BEFORE
+ * any spi operations. The SPI module will be -disabled- after this call.
+ */
+int imx_spi_init_v2_3 (struct imx_spi_dev *dev)
+{
+ unsigned int clk_src = get_peri_clock(dev->base);
+ unsigned int pre_div = 0, post_div = 0, i, reg_ctrl, reg_config;
+ struct spi_v2_3_reg *reg = (struct spi_v2_3_reg *)dev->reg;
+
+ if (dev->freq == 0) {
+ diag_printf("Error: desired clock is 0\n");
+ return -1;
+ }
+ // iomux config
+ io_cfg_spi(dev);
+
+ reg_ctrl = readl(dev->base + 0x8);
+ // reset the spi
+ writel(0, dev->base + 0x8);
+ writel(reg_ctrl | 0x1, dev->base + 0x8);
+
+ // control register setup
+ if (clk_src > dev->freq) {
+ pre_div = clk_src / dev->freq;
+ if (pre_div > 16) {
+ post_div = pre_div / 16;
+ pre_div = 15;
+ }
+ if (post_div != 0) {
+ for (i = 0; i < 16; i++) {
+ if ((1 << i) >= post_div)
+ break;
+ }
+ if (i == 16) {
+ diag_printf("Error: no divider can meet the freq: %d\n",
+ dev->freq);
+ return -1;
+ }
+ post_div = i;
+ }
+ }
+ diag_printf1("pre_div = %d, post_div=%d\n", pre_div, post_div);
+ reg_ctrl = (reg_ctrl & ~(3 << 18)) | dev->ss << 18;
+ reg_ctrl = (reg_ctrl & ~(0xF << 12)) | pre_div << 12;
+ reg_ctrl = (reg_ctrl & ~(0xF << 8)) | post_div << 8;
+ reg_ctrl |= 1 << (dev->ss + 4); // always set to master mode !!!!
+ reg_ctrl &= ~0x1; // disable spi
+
+ reg_config = readl(dev->base + 0xC);
+ // configuration register setup
+ reg_config = (reg_config & ~(1 << ((dev->ss + 12)))) |
+ (dev->ss_pol << (dev->ss + 12));
+ reg_config = (reg_config & ~(1 << ((dev->ss + 20)))) |
+ (dev->in_sctl << (dev->ss + 20));
+ reg_config = (reg_config & ~(1 << ((dev->ss + 16)))) |
+ (dev->in_dctl << (dev->ss + 16));
+ reg_config = (reg_config & ~(1 << ((dev->ss + 8)))) |
+ (dev->ssctl << (dev->ss + 8));
+ reg_config = (reg_config & ~(1 << ((dev->ss + 4)))) |
+ (dev->sclkpol << (dev->ss + 4));
+ reg_config = (reg_config & ~(1 << ((dev->ss + 0)))) |
+ (dev->sclkpha << (dev->ss + 0));
+
+ diag_printf1("reg_ctrl = 0x%x\n", reg_ctrl);
+ writel(reg_ctrl, dev->base + 0x8);
+ diag_printf1("reg_config = 0x%x\n", reg_config);
+ writel(reg_config, dev->base + 0xC);
+ // save config register and control register
+ reg->cfg_reg = reg_config;
+ reg->ctrl_reg = reg_ctrl;
+
+ // clear interrupt reg
+ writel(0, dev->base + 0x10);
+ writel(3 << 6, dev->base + 0x18);
+
+ return 0;
+}
+
+/*!
+ * This function should only be called after the imx_spi_init_xxx().
+ * It sets up the spi module according to the initialized value and then
+ * enables the SPI module. This function is called by the xfer function.
+ *
+ * Note: If one wants to change the SPI parameters such as clock, the
+ * imx_spi_init_xxx() needs to be called again.
+ */
+static void spi_start_v2_3(struct imx_spi_dev *dev,
+ struct spi_v2_3_reg *reg, int len)
+{
+ if (reg->ctrl_reg == 0) {
+ diag_printf("Error: spi(base=0x%x) has not been initialized yet\n",
+ dev->base);
+ return;
+ }
+ // iomux config
+ io_cfg_spi(dev);
+ reg->ctrl_reg = (reg->ctrl_reg & ~0xFFF00000) | ((len * 8 - 1) << 20);
+
+ writel(reg->ctrl_reg | 0x1, dev->base + 0x8);
+ writel(reg->cfg_reg, dev->base + 0xC);
+ diag_printf1("ctrl_reg=0x%x, cfg_reg=0x%x\n",
+ readl(dev->base + 0x8), readl(dev->base + 0xC));
+}
+
+/*!
+ * Stop the SPI module that the slave device is connected to.
+ */
+static void spi_stop_v2_3(struct imx_spi_dev *dev)
+{
+ writel(0, dev->base + 0x8);
+}
+
+/*!
+ * Transfer up to burst_bytes bytes data via spi. The amount of data
+ * is the sum of both the tx and rx.
+ * After this call, the SPI module that the slave is connected to will
+ * be -disabled- again.
+ */
+int imx_spi_xfer_v2_3 (
+ struct imx_spi_dev *dev, // spi device pointer
+ unsigned char *tx_buf, // tx buffer (has to be 4-byte aligned)
+ unsigned char *rx_buf, // rx buffer (has to be 4-byte aligned)
+ int burst_bytes // total number of bytes in one burst (or xfer)
+ )
+{
+ int val = SPI_RETRY_TIMES;
+ unsigned int *p_buf;
+ unsigned int reg;
+ int len, ret_val = 0;
+
+ if (burst_bytes > dev->fifo_sz) {
+ diag_printf("Error: maximum burst size is 0x%x bytes, asking 0x%x\n",
+ dev->fifo_sz, burst_bytes);
+ return -1;
+ }
+
+ spi_start_v2_3(dev, dev->reg, burst_bytes);
+
+ // move data to the tx fifo
+ for (p_buf = (unsigned int *)tx_buf, len = burst_bytes; len > 0;
+ p_buf++, len -= 4) {
+ writel(*p_buf, dev->base + 0x4);
+ }
+ reg = readl(dev->base + 0x8);
+ reg |= (1 << 2); // set xch bit
+ diag_printf1("control reg = 0x%08x\n", reg);
+ writel(reg, dev->base + 0x8);
+
+ // poll on the TC bit (transfer complete)
+ while ((val-- > 0) && (readl(dev->base + 0x18) & (1 << 7)) == 0) {
+ if (dev->us_delay != 0) {
+ hal_delay_us(dev->us_delay);
+ }
+ }
+
+ // clear the TC bit
+ writel(3 << 6, dev->base + 0x18);
+ if (val == 0) {
+ diag_printf("Error: re-tried %d times without response. Give up\n", SPI_RETRY_TIMES);
+ ret_val = -1;
+ goto error;
+ }
+
+ // move data in the rx buf
+ for (p_buf = (unsigned int *)rx_buf, len = burst_bytes; len > 0;
+ p_buf++, len -= 4) {
+ *p_buf = readl(dev->base + 0x0);
+ }
+error:
+ spi_stop_v2_3(dev);
+ return ret_val;
+}
+
+#ifdef PMIC_SPI_BASE
+extern imx_spi_init_func_t *spi_pmic_init;
+extern imx_spi_xfer_func_t *spi_pmic_xfer;
+extern struct imx_spi_dev imx_spi_pmic;
+
+static void show_pmic_info(void)
+{
+ volatile unsigned int rev_id;
+
+ spi_pmic_init(&imx_spi_pmic);
+ rev_id = pmic_reg(7, 0, 0);
+ diag_printf("PMIC ID: 0x%08x [Rev: ", rev_id);
+ switch (rev_id & 0x1F) {
+ case 0x1:
+ diag_printf("1.0");
+ break;
+ case 0x9:
+ diag_printf("1.1");
+ break;
+ case 0xA:
+ diag_printf("1.2");
+ break;
+ case 0x10:
+ diag_printf("2.0");
+ break;
+ case 0x11:
+ diag_printf("2.1");
+ break;
+ case 0x18:
+ diag_printf("3.0");
+ break;
+ case 0x19:
+ diag_printf("3.1");
+ break;
+ case 0x1A:
+ diag_printf("3.2");
+ break;
+ case 0x2:
+ diag_printf("3.2A");
+ break;
+ case 0x1B:
+ diag_printf("3.3");
+ break;
+ case 0x1D:
+ diag_printf("3.5");
+ break;
+ default:
+ diag_printf("unknown");
+ break;
+ }
+ diag_printf("]\n");
+}
+
+RedBoot_init(show_pmic_info, RedBoot_INIT_PRIO(100));
+
+static void do_pmic(int argc, char *argv[]);
+RedBoot_cmd("pmic",
+ "Read/Write internal PMIC register",
+ "<reg num> [value to be written]",
+ do_pmic
+ );
+
+static void do_pmic(int argc, char *argv[])
+{
+ unsigned int reg, temp, val = 0, write = 0;
+
+ if (argc == 1) {
+ diag_printf("\tRead: pmic <reg num>\n");
+ diag_printf("\tWrite: pmic <reg num> <value to be written>\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ if (argc == 3) {
+ if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ write = 1;
+ }
+
+ spi_pmic_init(&imx_spi_pmic);
+ temp = pmic_reg(reg, val, write);
+
+ diag_printf("\tval: 0x%08x\n\n", temp);
+}
+
+static unsigned int pmic_tx, pmic_rx;
+/*!
+ * To read/write to a PMIC register. For write, it does another read for the
+ * actual register value.
+ *
+ * @param reg register number inside the PMIC
+ * @param val data to be written to the register; don't care for read
+ * @param write 0 for read; 1 for write
+ *
+ * @return the actual data in the PMIC register
+ */
+unsigned int pmic_reg(unsigned int reg, unsigned int val, unsigned int write)
+{
+ if (reg > 63 || write > 1 ) {
+ diag_printf("<reg num> = %d is invalide. Should be less then 63\n", reg);
+ return 0;
+ }
+ pmic_tx = (write << 31) | (reg << 25) | (val & 0x00FFFFFF);
+ diag_printf1("reg=0x%x, val=0x%08x\n", reg, pmic_tx);
+
+ spi_pmic_xfer(&imx_spi_pmic, (unsigned char *)&pmic_tx,
+ (unsigned char *)&pmic_rx, 4);
+
+ if (write) {
+ pmic_tx &= ~(1 << 31);
+ spi_pmic_xfer(&imx_spi_pmic, (unsigned char *)&pmic_tx,
+ (unsigned char *)&pmic_rx, 4);
+ }
+
+ return pmic_rx;
+}
+#endif // PMIC_SPI_BASE
+
+#ifdef CPLD_SPI_BASE
+
+unsigned int spi_cpld_xchg_single(unsigned int data, unsigned int data1, unsigned int base)
+{
+ volatile unsigned int cfg_reg = readl(base + SPI_CTRL_REG_OFF);
+ unsigned int temp;
+
+ /* Activate the SS signal */
+ cfg_reg |= CPLD_SPI_CHIP_SELECT_NO;
+ writel(cfg_reg, CPLD_SPI_BASE + SPI_CTRL_REG_OFF);
+
+ /* Write the data */
+ writel(data, base + SPI_TX_REG_OFF);
+ writel(data1, base + SPI_TX_REG_OFF);
+
+ cfg_reg |= SPI_CTRL_REG_XCH_BIT;
+ writel(cfg_reg, base + SPI_CTRL_REG_OFF);
+
+ while ((((cfg_reg = readl(base + SPI_TEST_REG_OFF)) &
+ SPI_TEST_REG_RXCNT_MASK) >> SPI_TEST_REG_RXCNT_OFFSET) != 2) {
+ }
+
+ /* Deactivate the SS signal */
+ cfg_reg = readl(base + SPI_CTRL_REG_OFF);
+ cfg_reg &= ~SPI_CTRL_CS_MASK;
+ writel(cfg_reg, base + SPI_CTRL_REG_OFF);
+
+ /* Read from RX FIFO, second entry contains the data */
+ temp = readl(base + SPI_RX_REG_OFF);
+ temp = readl(base + SPI_RX_REG_OFF);
+ return ((temp >> 6) & 0xffff);
+}
+
+static void mxc_cpld_spi_init(void)
+{
+ unsigned int ctrl;
+
+ ctrl = SPI_CTRL_REG_BIT_COUNT46 | CPLD_SPI_CTRL_MODE_MASTER | SPI_CTRL_EN;
+
+ spi_init(CPLD_SPI_BASE, 18000000, // 54MHz data rate
+ ctrl);
+}
+
+RedBoot_init(mxc_cpld_spi_init, RedBoot_INIT_PRIO(102));
+
+static void do_cpld(int argc, char *argv[]);
+
+RedBoot_cmd("spi_cpld",
+ "Read/Write 16-bit internal CPLD register over CSPI",
+ "<reg num> [16-bit value to be written]",
+ do_cpld
+ );
+
+static void do_cpld(int argc,char *argv[])
+{
+ unsigned int reg, temp, val = 0, read = 1;
+
+ if (argc == 1) {
+ diag_printf("\tRead: spi_cpld <reg num>\n");
+ diag_printf("\tWrite: spi_cpld <reg num> <value to be written>\n");
+ return;
+ }
+
+ if (!parse_num(*(&argv[1]), (unsigned long *)®, &argv[1], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+
+ if (argc == 3) {
+ if (!parse_num(*(&argv[2]), (unsigned long *)&val, &argv[2], ":")) {
+ diag_printf("Error: Invalid parameter\n");
+ return;
+ }
+ read = 0;
+ }
+
+ mxc_cpld_spi_init();
+ temp = cpld_reg(reg, val, read);
+
+ diag_printf("\tval: 0x%04x\n\n", temp);
+}
+
+/*!
+ * To read/write to a CPLD register.
+ *
+ * @param reg register number inside the CPLD
+ * @param val data to be written to the register; don't care for read
+ * @param read 0 for write; 1 for read
+ *
+ * @return the actual data in the CPLD register
+ */
+unsigned int cpld_reg_xfer(unsigned int reg, unsigned int val, unsigned int read)
+{
+ unsigned int local_val1, local_val2;
+
+ reg >>= 1;
+
+ local_val1 = (read << 13) | ((reg & 0x0001FFFF) >> 5) | 0x00001000;
+ if (read) {
+ //local_val1 = (read << 22) | (reg << 4) | 0x00200004;
+ //local_val2 = 0x1F;
+ local_val2 = ( ((reg & 0x0000001F) << 27) | 0x0200001f);
+
+ } else {
+ //local_val1 = (read << 22) | (reg << 4) | 0x00200007;
+ //local_val2 = ((val & 0xFFFF) << 6) | 0x00400027;
+ local_val2 = ( ((reg & 0x0000001F) << 27) | ((val & 0x0000FFFF) << 6) | 0x03C00027);
+
+ }
+
+ diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
+ return spi_cpld_xchg_single(local_val1, local_val2, CPLD_SPI_BASE);
+}
+
+/*!
+ * To read/write to a CPLD register. For write, it does another read for the
+ * actual register value.
+ *
+ * @param reg register number inside the CPLD
+ * @param val data to be written to the register; don't care for read
+ * @param read 0 for write; 1 for read
+ *
+ * @return the actual data in the CPLD register
+ */
+unsigned int cpld_reg(unsigned int reg, unsigned int val, unsigned int read)
+{
+ unsigned int temp;
+
+ if (reg > 0x20068 || read > 1 ) {
+ diag_printf("<reg num> = %x is invalid. Should be less then 0x20068\n", reg);
+ return 0;
+ }
+
+ temp = cpld_reg_xfer(reg, val, read);
+ diag_printf1("reg=0x%x, val=0x%08x\n", reg, val);
+
+ if (read == 0) {
+ temp = cpld_reg_xfer(reg, val, 1);
+ }
+
+ return temp;
+}
+
+#endif // CPLD_SPI_BASE
--- /dev/null
+# ====================================================================
+#
+# usbs_mx37.cdl
+#
+# MX37 USB OTG Device Mode support.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+# This file is a part of Diagnosis Package based on eCos for Freescale i.MX
+# Family microprocessor.
+## Copyright (C) 2008 Freescale Semiconductor, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): fisherz
+# Original data: fisherz
+# Contributors:
+# Date: 2008-10-16
+# Comment: Porting to MX51
+#
+#####DESCRIPTIONEND####
+# ====================================================================
+cdl_package CYGPKG_DEVS_USB_IMX_OTG {
+ display "Freescale i.MX51 or i.MX37 USB OTG Device Driver"
+ include_dir "cyg/io/usb"
+ parent CYGPKG_USB
+ implements CYGHWR_IO_USB_SLAVE
+
+ # Make sure that we are running on the right hardware.
+ requires CYGPKG_HAL_ARM
+# requires CYGPKG_HAL_ARM_MX51
+# requires CYGPKG_HAL_ARM_MX51_3STACK
+ requires CYGPKG_IO_USB
+ requires CYGPKG_IO_USB_SLAVE
+ compile usbs_imx.c
+
+ description "
+ The on-chip USB OTG core on the MX51 or MX37 works as a USB
+ device controller, facilitating the use of this processor
+ in USB peripherals. This package provides a suitable eCos
+ device driver."
+
+ cdl_option CYGHWR_USB_DEVS_MX51_OTG {
+ display "i.MX51 USB OTG"
+ flavor bool
+ default_value 0
+ description "
+ i.MX51 is the default OTG device for this package"
+ }
+
+ cdl_option CYGHWR_USB_DEVS_MX37_OTG {
+ display "i.MX37 USB OTG"
+ flavor bool
+ default_value 0
+ description "
+ i.MX37 is not the default OTG device for this package"
+ }
+
+ cdl_option CYGHWR_MXC_USB_BUFFER_USE_IRAM {
+ display "Determine where the USB buffer is"
+ flavor bool
+ default_value 1
+ description "
+ USB buffer is defaultly in the internal RAM for better performance"
+ }
+
+ cdl_option CYGHWR_IMX_USB_DOWNLOAD_SUPPORT {
+ display "USB Download for redboot is supported, i.MX OTG works in poll mode"
+ flavor bool
+ default_value 0
+ description "
+ USB Download function is an add-value function for redboot, and USB OTG will work
+ under poll mode"
+ }
+
+}
+
+
\ No newline at end of file
--- /dev/null
+//==========================================================================
+//
+// include/usbs_imx.h
+//
+// The interface exported by the i.MX37 or i.MX51 USB OTG device driver
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is a part of Diagnosis Package based on eCos for Freescale i.MX
+// Family microprocessor.
+// Copyright (C) 2008 Freescale Semiconductor, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): fisherz
+// Contributors: fisherz
+// Date: 2008-07-22
+// Purpose:
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+#ifndef CYGONCE_USBS_IMX_H
+#define CYGONCE_USBS_IMX_H
+
+#include <cyg/io/usb/usbs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define USBS_DEBUG 0
+
+/*
+ * This function is an exported API for application to initialize
+ * MX37 or MX51 USB OTG in device mode from hardware to driver.
+ */
+void usbs_imx_otg_device_init(void);
+void usbs_imx_otg_device_deinit(void);
+#if defined(CYGBLD_IMX_USB_DOWNLOAD_SUPPORT)
+void usbs_imx_otg_download(unsigned char * buffer, unsigned int length);
+#endif
+/*
+ * The i.MX37 and 51 family comes with on-chip USB OTG support. This
+ * provides three endpoints. Endpoint 0 can only be used for control
+ * messages. Endpoints 1 and 2 can only be used for bulk transfers,
+ * host->slave for endpoint 1 and slave->host for endpoint 2.
+ */
+extern usbs_control_endpoint usbs_imx_otg_ep0;
+extern usbs_rx_endpoint usbs_imx_otg_ep1;
+extern usbs_tx_endpoint usbs_imx_otg_ep2;
+
+
+/************************************************************************/
+#define BUFFER_SIZE 0x800
+
+#if defined(CYGHWR_USB_DEVS_MX37_OTG)
+#define USB_BASE_ADDRESS 0xC3FD4000
+#define MX37_IRQ_USB_SERVICE_REQUEST 18 //i.MX37 USB OTG Interrupt
+#define MX37_IRQ_USB_PRIORITY 99 //i.MX37 USB Interrupt Priority
+#define IMX_IRQ_USB_DEV_SERVICE_REQUEST MX37_IRQ_USB_SERVICE_REQUEST
+#define IMX_IRQ_USB_DEV_PRIORITY MX37_IRQ_USB_PRIORITY
+
+#define CCM_BASE_ADDR 0xE3F8C000
+#define CCM_CSCMR1_OFFSET 0x34
+#define CCM_CSCMR1 (CCM_BASE_ADDR + CCM_CSCMR1_OFFSET)
+#define REGVAL_CCM_CSCMR1 (*((volatile cyg_uint32*)CCM_CSCMR1))
+#define USB_MX37_SET_PHY_CLK_24MHZ() (REGVAL_CCM_CSCMR1&=(~((0x1) <<26)))
+
+#define USB_IMX_SET_TD_OFFSET(offset,num) offset=num
+#endif
+
+
+#if defined(CYGHWR_USB_DEVS_MX51_OTG)
+#define USB_BASE_ADDRESS 0x73F80000
+#define MX51_IRQ_USB_SERVICE_REQUEST 18 //i.MX51 USB OTG Interrupt
+#define MX51_IRQ_USB_PRIORITY 99 //i.MX51 USB Interrupt Priority
+#define IMX_IRQ_USB_DEV_SERVICE_REQUEST MX51_IRQ_USB_SERVICE_REQUEST
+#define IMX_IRQ_USB_DEV_PRIORITY MX51_IRQ_USB_PRIORITY
+
+#define USB_OTG_BASE_ADDR ((cyg_uint32)USB_BASE_ADDRESS + 0x000)
+#define USB_H1_BASE_ADDR ((cyg_uint32)USB_BASE_ADDRESS + 0x200)
+#define USB_H2_BASE_ADDR ((cyg_uint32)USB_BASE_ADDRESS + 0x400)
+#define USB_H3_BASE_ADDR ((cyg_uint32)USB_BASE_ADDRESS + 0x400)
+#define USB_CONTROL_REG ((cyg_uint32)USB_BASE_ADDRESS + 0x800)
+#define USB_OTG_MIRROR_REG ((cyg_uint32)USB_BASE_ADDRESS + 0x804)
+#define USB_PHY_CTRL_0_REG ((cyg_uint32)USB_BASE_ADDRESS + 0x808)
+#define USB_PHY_CTRL_1_REG ((cyg_uint32)USB_BASE_ADDRESS + 0x80c)
+#define USB_CTRL_1_REG ((cyg_uint32)USB_BASE_ADDRESS + 0x810)
+
+#define CCM_BASE_ADDR 0x73FD4000
+#define CCM_CSCMR1_OFFSET 0x1C
+#define CCM_CSCDR1_OFFSET 0x24
+#define CCM_CSCMR1 (CCM_BASE_ADDR + CCM_CSCMR1_OFFSET)
+#define CCM_CSCDR1 (CCM_BASE_ADDR + CCM_CSCDR1_OFFSET)
+#define CCM_CSCMR1_REGVAL (*(cyg_uint32 *)(CCM_BASE_ADDR + CCM_CSCMR1_OFFSET))
+#define CCM_CSCDR1_REGVAL (*(cyg_uint32 *)(CCM_BASE_ADDR + CCM_CSCDR1_OFFSET))
+/* CSCMR1 register */
+#define CSCMR1_USBOH3_PHY_CLK_SEL_MASK 0x04000000
+#define CSCMR1_USBOH3_PHY_CLK_SEL_VALUE 0x04000000
+#define CSCMR1_USBOH3_CLK_SEL_MASK 0x00c00000
+#define CSCMR1_USBOH3_CLK_SEL_VALUE 0x00400000
+/*CSCDR1 register config*/
+#define CSCDR1_USBOH3_CLK_PRED_SEL_MASK 0x00000700
+#define CSCDR1_USBOH3_CLK_PRED_SEL_VALUE 0x00000400 /* divide by 5 */
+#define CSCDR1_USBOH3_CLK_PODF_SEL_MASK 0x000000C0
+#define CSCDR1_USBOH3_CLK_PODF_SEL_VALUE 0x00000040 /* divide by 2 */
+/* CDCDR register */
+#define CDCDR_USB_CLK_PREDF_MASK 0x00000070
+#define CDCDR_USB_CLK_PREDF_VALUE 0x00000010 /* divide by 2 */
+#define CDCDR_USB_CLK_PODF_MASK 0x0000000E
+#define CDCDR_USB_CLK_PODF_VALUE 0x00000002 /* divide by 2 */
+
+/*Hash Defines for PHY_CTRL_REG_1*/
+#define USB_PHY_CTRL_PLLDIVVALUE_MASK 0x00000003
+#define USB_PHY_CTRL_PLLDIVVALUE_19_2_MHZ 0x00000000
+#define USB_PHY_CTRL_PLLDIVVALUE_24_MHZ 0x00000001
+#define USB_PHY_CTRL_PLLDIVVALUE_26_MHZ 0x00000002
+#define USB_PHY_CTRL_PLLDIVVALUE_27_MHZ 0x00000003
+
+
+#define USB_IMX_SET_TD_OFFSET(offset,num) offset=num//do{}while(0)
+#endif
+/************************************************************************/
+#define IMX_USB_INTR_DEV_SLE (1<<8) //DCSuspend - Sleep Enable
+#define IMX_USB_INTR_DEV_SRE (1<<7) //SOF Received Enable
+#define IMX_USB_INTR_DEV_RESET (1<<6) //USB Reset Enable
+#define IMX_USB_INTR_DEV_SEE (1<<4) //System Error Enable
+#define IMX_USB_INTR_DEV_PCE (1<<2) //Port Change Detect Enable
+#define IMX_USB_INTR_DEV_USBINT (1<<0) //USBINT Enable, IOS@dQH, IOC@dTD will be available
+
+#define IMX_USB_STS_DCSPD (1<<8) //DCSuspend Interrupt
+#define IMX_USB_STS_SOFRSV (1<<7) //SOF Received Interrupt
+#define IMX_USB_STS_RESET (1<<6) //USB Reset Received Interrupt
+#define IMX_USB_STS_SYSERR (1<<4) //System Error Interrupt, not implemented in Marley, always '0'
+#define IMX_USB_STS_PTCHANGE (1<<2) //Port Change Detect Interrupt
+#define IMX_USB_STS_USBINT (1<<0) //USB Interrupt
+/************************************************************************/
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+/* Device Queue Head and Device Transfer Descriptor Related Defination */
+#define SIZE_OF_QHD 0x40
+#define SIZE_OF_DTD0 0x20
+#define SIZE_OF_DTD1 0x20
+#define dTD_SIZE_EPIN (SIZE_OF_DTD0 + SIZE_OF_DTD1) //0x40
+#define dTD_SIZE_EPOUT (SIZE_OF_DTD0 + SIZE_OF_DTD1) //0x40
+
+#define BUFFER_USED_PER_EP ((SIZE_OF_QHD + dTD_SIZE_EPIN) +(SIZE_OF_QHD + dTD_SIZE_EPOUT)) //0x100
+
+#define ZLT_ENABLE 0
+#define ZLT_DISABLE 1
+
+#define IOS_NOTSET 0
+#define IOS_SET 1
+
+#define IOC_NOTSET 0
+#define IOC_SET 1
+
+#define TERMINATE 1
+#define NOT_TERMINATE 0
+
+#define NO_STATUS 0
+#define ACTIVE BIT7
+
+#define EPOUT_COMPLETE BIT0
+#define EPIN_COMPLETE BIT16
+
+#define EPOUT_PRIME BIT0
+#define EPIN_PRIME BIT16
+
+#define EPOUT_ENABLE BIT7
+#define EPIN_ENABLE BIT23
+
+#define STALL_RX 0x00000001
+#define STALL_TX 0x00010000
+
+/* Buffer size of the buffer used for bulk data transfer */
+
+#define CONTROL_BUFFER_SIZE 0x40
+#define BULK_BUFFER_SIZE 0x200
+#define NUM_OF_BULK_BUFFER 0x2
+#define TOTAL_DATA_BUFFER_SIZE ((BULK_BUFFER_SIZE * NUM_OF_BULK_BUFFER) + CONTROL_BUFFER_SIZE)//512*2+64=1088
+
+#define BULK_TD_BUFFER_TOTAL_SIZE 0x4000
+#define BULK_TD_BUFFER_PAGE_SIZE 0x1000
+/************************************************************************/
+#define USB_OTG_TRANS_MASK 0xC0000000
+#define USB_OTG_TRANS_SERIAL 0xC0000000
+#define USB_OTG_TRANS_ULPI 0x80000000
+#define USB_OTG_TRANS_PHILIP 0x40000000
+#define USB_OTG_TRANS_UTMI 0x00000000
+#define USB_OTG_FS_ONLY 0x01000000
+#define USB_OTG_TRANS_WIDTH 0x10000000
+
+/***********************USB OTG Register Map*****************************/
+// ----------------------------------------------------------------------------
+// This device driver for i.MX37 has three endpoints.
+//
+// Endpoint 0 can only be used for bi-directional control messages.
+//
+// Endpoint 1 can only be used for host->slave bulk OUT transfers.
+//
+// Endpoint 2 can only be used for slave-host bulk IN transfers.
+//
+// Start with definitions of the hardware. The use of a structure and
+// a const base pointer should allow the compiler to do base/offset
+// addressing and keep the hardware base address in a register. This
+// is better than defining each hardware register via a separate
+// address. Although the registers are only a byte wide, the peripheral
+// bus only supports word accesses.
+//
+// The USB_OTG_ID etc. macros allow for an alternative way of
+// accessing the hardware if a better approach is presented, without
+// having to rewrite all the code. Macros that correspond to registers
+// are actually addresses, making it easier in the code to distinguish
+// them from bit values: the & and * operators will just cancel out.
+typedef struct usbs_imx_otg_hardware{
+ volatile cyg_uint32 id; //0x000, Identification Register
+ volatile cyg_uint32 hwgeneral; //0x004, General HW Parameters
+ volatile cyg_uint32 hwhost; //0x008, Host HW Parameters
+ volatile cyg_uint32 hwdevice; //0x00c, Device HW Parameters
+ volatile cyg_uint32 hwtxbuf; //0x010, TX Buffer HW Parameters
+ volatile cyg_uint32 hwrxbuf; //0x014, RX Buffer HW Parameters
+ int rsv1[26];
+ volatile cyg_uint32 gptimer0ld; //0x080, GP Timer0 Load Register
+ volatile cyg_uint32 gptimer0ctrl; //0x084, GP Timer0 Control Register
+ volatile cyg_uint32 gptimer1ld; //0x088, GP Timer1 Load Register
+ volatile cyg_uint32 gptimer1ctrl; //0x08c, GP Timer1 control register
+ volatile cyg_uint32 sbuscfg; //0x090, System Bus Interface Control
+ int rsv2[27];
+ volatile unsigned char caplength; //0x100, Capability Length Register
+ char rsv3;
+ volatile cyg_uint16 hciversion; //0x102, Host Interface Version Number
+ volatile cyg_uint32 hcsparams; //0x104, Host Control Structural Parameters
+ volatile cyg_uint32 hccparams; //0x108, Host Control Capability Parameters
+ int rsv4[5];
+ volatile cyg_uint16 dciversion; //0x120, Device Interface Version Number
+ short rsv5;
+ volatile cyg_uint32 dccparams; //0x124, Device Control Capability Parameters
+ int rsv6[6];
+ volatile cyg_uint32 usbcmd; //0x140, USB Command
+ volatile cyg_uint32 usbsts; //0x144, USB Status
+ volatile cyg_uint32 usbintr; //0x148, USB Interrupt Enable
+ volatile cyg_uint32 frindex; //0x14c, USB Frame Index
+ int rsv7;
+ volatile cyg_uint32 devaddr; //0x154, USB Device Address
+ volatile cyg_uint32 endptlistaddr; //0x158, Address of Endpoint list in memory
+ volatile cyg_uint32 ttctrl; //0x15c, TT status and control
+ volatile cyg_uint32 burstsize; //0x160, Programmable Burst Size
+ volatile cyg_uint32 txfilltuning; //0x164, Host Transmit Pre-Buffer Packet Tuning
+ volatile cyg_uint32 txttfilltuning; //0x168,Host TT Transmit Pre-Buffer packet Tuning
+ int rsv8;
+ volatile cyg_uint32 ulpiviewpoint; //0x170, ULPI Viewport
+ int rsv9;
+ volatile cyg_uint32 endptnak; //0x178, Endpoint NAK
+ volatile cyg_uint32 endptnaken; //0x17c, Endpoint NAK Enable
+ volatile cyg_uint32 configflag; //0x180, Configured Flag Register
+ volatile cyg_uint32 portsc1; //0x184~0x1a0, Port Status/Control 1~8
+ volatile cyg_uint32 portsc2;
+ volatile cyg_uint32 portsc3;
+ volatile cyg_uint32 portsc4;
+ volatile cyg_uint32 portsc5;
+ volatile cyg_uint32 portsc6;
+ volatile cyg_uint32 portsc7;
+ volatile cyg_uint32 portsc8;
+ volatile cyg_uint32 otgsc; //0x1a4, OTG Status and Control
+ volatile cyg_uint32 usbmode; //0x1a8, USB Device Mode
+ volatile cyg_uint32 endptsetupstat; //0x1ac,Endpoint Setup Status
+ volatile cyg_uint32 endptprime; //0x1b0, Endpoint Initialization
+ volatile cyg_uint32 endptflush; //0x1b4, Endpoint De-Initialization
+ volatile cyg_uint32 endptstatus; //0x1b8, Endpoint Status
+ volatile cyg_uint32 endptcomplete; //0x1bc, Endpoint Complete
+ volatile cyg_uint32 endptctrl[16]; //0x1c0~0x1fc, Endpoint Control 0~15
+}usbs_imx_otg_hardware;
+/*************************usb structures typedefs*************************/
+//-----------------------------------------------
+//USB buffer data structure
+typedef struct {
+ cyg_uint32 buffer_address;
+ cyg_uint32 buffer_size;
+}usb_plat_config_data_t;
+
+//setup data for Queue Header
+typedef struct dqh_setup_t{
+ cyg_uint32 dqh_word0;
+ cyg_uint32 dqh_word1;
+ cyg_uint32 dqh_word2;
+ cyg_uint32 dqh_word3;
+ cyg_uint32 dqh_word4;
+ cyg_uint32 dqh_word5;
+ cyg_uint32 dqh_word6;
+ cyg_uint32 dqh_word7;
+ cyg_uint32 dqh_word8;
+ cyg_uint32 dqh_word9;
+ cyg_uint32 dqh_word10;
+ cyg_uint32 dqh_word11;
+} dqh_setup_t;
+//setup data for Transfer Descriptor
+typedef struct dtd_setup_t {
+ cyg_uint32 dtd_word0;
+ cyg_uint32 dtd_word1;
+ cyg_uint32 dtd_word2;
+ cyg_uint32 dtd_word3;
+ cyg_uint32 dtd_word4;
+ cyg_uint32 dtd_word5;
+ cyg_uint32 dtd_word6;
+ cyg_uint32 dtd_word7;
+} dtd_setup_t;
+
+//structure for Queue Header
+typedef struct dqh_t {
+ cyg_uint32 dqh_base;
+ cyg_uint32 next_link_ptr;
+ cyg_uint32 buffer_ptr0;
+ cyg_uint32 buffer_ptr1;
+ cyg_uint32 buffer_ptr2;
+ cyg_uint32 buffer_ptr3;
+ cyg_uint32 buffer_ptr4;
+ cyg_uint16 total_bytes;
+ cyg_uint16 mps;
+ cyg_uint16 current_offset;
+ cyg_uint8 zlt;
+ cyg_uint8 ios;
+ cyg_uint8 terminate;
+ cyg_uint8 ioc;
+ cyg_uint8 status;
+}dqh_t;
+
+//structure for Transfer Descriptor
+typedef struct dtd_t {
+ cyg_uint32 dtd_base;
+ cyg_uint32 next_link_ptr;
+ cyg_uint32 buffer_ptr0;
+ cyg_uint32 buffer_ptr1;
+ cyg_uint32 buffer_ptr2;
+ cyg_uint32 buffer_ptr3;
+ cyg_uint32 buffer_ptr4;
+ cyg_uint16 total_bytes;
+ cyg_uint16 current_offset;
+ cyg_uint8 terminate;
+ cyg_uint8 ioc;
+ cyg_uint8 status;
+}dtd_t;
+
+//structure for Transfer Descriptor layout
+typedef volatile struct TransferDescriptor {
+ unsigned terminal :1 ;
+ unsigned rsv1 :4 ;
+ unsigned nxt_pt :27 ;
+
+ unsigned status :8 ;
+ unsigned rsv2 :2 ;
+ unsigned multo :2 ;
+ unsigned rsv3 :3 ;
+ unsigned ioc :1 ;
+ unsigned totalbytes :15 ;
+ unsigned rsv4 :1 ;
+
+ unsigned offset :12 ;
+ unsigned bufferptr0 :20 ;
+
+ unsigned frame_num :11 ;
+ unsigned rsv5 :1 ;
+ unsigned bufferptr1 :20 ;
+
+ unsigned rsv6 :12 ;
+ unsigned bufferptr2 :20 ;
+
+ unsigned rsv7 :12 ;
+ unsigned bufferptr3 :20 ;
+
+ unsigned rsv8 :12 ;
+ unsigned bufferptr4 :20 ;
+}__attribute__((packed)) TransferDescriptor;
+
+//structure for Queue Header layout
+typedef volatile struct QueueHeader {
+ unsigned rsv1 :15 ;
+ unsigned ios :1 ;
+ unsigned mps :11 ;
+ unsigned rsv2 :2 ;
+ unsigned zlt :1 ;
+ unsigned mult :2 ;
+
+ unsigned rsv3 :5 ;
+ unsigned current_dtd :27 ;
+
+ struct TransferDescriptor dtd ;
+
+ unsigned rsv4 :32 ;
+
+ unsigned setupbuf0 :8 ;
+ unsigned setupbuf1 :8 ;
+ unsigned setupbuf2 :8 ;
+ unsigned setupbuf3 :8 ;
+
+ unsigned setupbuf4 :8 ;
+ unsigned setupbuf5 :8 ;
+ unsigned setupbuf6 :8 ;
+ unsigned setupbuf7 :8 ;
+}__attribute__((packed)) QueueHeader;
+
+//bulk buffer status
+enum {
+ BUFFER_FREED,
+ BUFFER_RELEASED,
+ BUFFER_ALLOCATED
+};
+
+//structure of bulk buffer
+typedef struct {
+ unsigned char * buffer;
+ cyg_uint32 stat;
+}bulk_buffer_t;
+
+//bulk buffer status
+enum {
+ MASS_STORAGE_CBW_TYPE = 1,
+ MASS_STORAGE_DATA_TYPE
+};
+
+//structure of USB buffer map
+typedef struct {
+ cyg_uint32 ep_dqh_base_addrs; /* Base Address of Queue Header */
+ cyg_uint32 ep_dtd_base_addrs; /* Base Address of Transfer Descriptor */
+ cyg_uint32 ep0_buffer_addrs; /* Buffer Addres for EP0 IN */
+ cyg_uint32 buffer1_address; /* Buffer1 address for bulk transfer */
+ cyg_uint32 buffer1_status; /* Status of Buffer1 */
+ cyg_uint32 buffer2_address; /* Buffer2 address for bulk transfer */
+ cyg_uint32 buffer2_status; /* Status of Buffer2 */
+}buffer_map_t;
+
+//Data Structure used for configuring the Endpoints.
+typedef struct {
+ cyg_uint8 end_pt_no; /* Endpoint number */
+ cyg_uint8 direction; /* Direction of endpoint */
+ cyg_uint8 transfer_type; /* type of transfer supporting on the endpoint */
+ cyg_uint16 max_pkt_size; /* maximum packet size in bytes */
+}usb_end_pt_info_t;
+
+//Buffer descriptor used for data transfer on USB
+typedef struct {
+ void * buffer ; /* Address of the buffer to/from data is to be transmitted */
+ cyg_uint32 size ; /* size of the buffer to be transmitted/recieved */
+ cyg_uint32 bytes_transfered; /* actual number of bytes transfered */
+}usb_buffer_descriptor_t;
+
+/*************************important constant in usb transaction*************************/
+/* Maximum packet size defination */
+#define MPS_8 8
+#define MPS_64 64
+
+#define SETUP_DATA_LENGTH 0x8
+#define ENDPT_NUMBER_MASK 0x0F
+#define ENDPT_DIR_MASK 0x80
+#define ENDPT_DIR_SHIFT 0x7
+#define ENDPT_TRNS_TYPE_MASK 0x03
+
+#define USB_MAX_DEVICE_ADDR 127
+#define USB_DEV_VALUE_OF_UNCONFIG 0x0
+
+#define USB_DEV_CONFIG_DESC_CONFIG_VALUE 0x01
+/* Default device address */
+#define USB_DEFAULT_ADDR 0x00
+
+/* DESCRIPTOR Type */
+#define DEVICE_DESC 0x1
+#define CONF_DESC 0x2
+#define STRING_DESC 0x3
+#define INTERFACE_DESC 0x4
+#define ENDPOINT_DESC 0x5
+#define DEVICE_QUALIFIER 0x6
+#define OTHER_SPEED_CONF_DESC 0x7
+
+/* String SUB DESCRIPTOR type */
+#define STR_DES0 0x0
+#define STR_DES1 0x1
+#define STR_DES2 0x2
+#define STR_DES3 0x3
+#define STR_DES4 0x4
+#define STR_DES5 0x5
+
+/* Descriptor Index */
+#define FILL_DEVICE_DESC 0x1
+#define FILL_DEVICE_QF_DESC 0x2
+#define FILL_CONF_DESC 0x3
+#define FILL_OT_CONF_DESC 0x4
+#define FILL_STR_DES0 0x5
+#define FILL_STR_DES1 0x6
+#define FILL_STR_DES2 0x7
+#define FILL_STR_DES3 0x8
+#define FILL_SN_DESC 0x9 //mandatory descriptor for mass storage device
+
+#define LEN_OF_CONFIG_VALUE 0x1
+
+#define NUM_OF_ENDPT_OFFSET 0x4
+#define CONFIG_NUMBER_OFFSET 0x5
+#define STRING_DESC_LEN_OFFSET 0x0
+#define DEVICE_DESC_LEN_OFFSET 0x0
+#define CONF_DESC_LEN_OFFSET 0x0
+#define INF_DESC_LEN_OFFSET 0x0
+#define EP_DESC_LEN_OFFSET 0x0
+
+/*************************usb enums typedefs*************************/
+typedef enum {
+ USB_DEFAULT_STATE,
+ USB_ADDRESSED_STATE,
+ USB_CONFIGURED_STATE,
+ USB_SUSPENDED_STATE
+} USB_DEVICE_STATE_T;
+
+/* USB Device State which are handled by DCD */
+typedef enum
+{
+ USB_DEV_DUMMY_STATE,
+ USB_DEV_DEFAULT_STATE,
+ USB_DEV_ADDRESSED_STATE,
+ USB_DEV_CONFIGURED_STATE
+}usb_state_t;
+
+/* Status of all transaction on USB */
+typedef enum
+{
+ USB_SUCCESS,
+ USB_FAILURE,
+ USB_INVALID = -1 /* Always Keep this entry in last */
+}usb_status_t;
+
+/* enum for endpoint numbers */
+enum
+{
+ EP0,
+ EP1,
+ EP2,
+ EP3,
+ EP4,
+ EP5
+};
+
+enum
+{
+ OUT,
+ IN
+};
+/* enum for data transfer type on endpoints */
+enum
+{
+ CONTROL,
+ ISOCHRONOUS,
+ BULK,
+ INTERRUPT
+};
+
+/* Constants defined to represent the elements within the setup packet. */
+enum
+{
+ BMREQUESTTYPE,
+ BREQUEST,
+ WVALUE_LOWBYTE,
+ WVALUE_HIGHBYTE,
+ WINDEX_LOWBYTE,
+ WINDEX_HIGHBYTE,
+ WLENGTH_LOWBYTE,
+ WLENGTH_HIGHBYTE
+};
+
+/* Enum constants for function to identify the USB Standard Request defined
+ * in USB Specification.
+ */
+enum
+{
+ USB_GET_STATUS,
+ USB_CLEAR_FEATURE,
+ USB_RESERVED_REQ_ONE,
+ USB_SET_FEATURE,
+ USB_RESERVED_REQ_TWO,
+ USB_SET_ADDRESS,
+ USB_GET_DESCRIPTOR,
+ USB_SET_DESCRIPTOR,
+ USB_GET_CONFIGURATION,
+ USB_SET_CONFIGURATION,
+ USB_GET_INTERFACE,
+ USB_SET_INTERFACE,
+ USB_SYNCH_FRAME
+};
+
+/* Mass Storage Class-specific request
+ */
+enum{
+ USB_MSC_GET_MAX_LUN=0xFE,
+ USB_MSC_BOT_RESET
+};
+#define USB_REQTYPE_RESET 0x21
+#define USB_REQTYE_GETMAXLUN 0xA1
+
+/* Status of the buffer used for bulk transfer */
+enum {
+ BUFFER_FREE,
+ BUFFER_IN_USE
+};
+
+/***********************usb_descriptor_definitions*************************/
+#define VID 0x15A2
+#define PID 0x002C
+
+/* Constants defined to represent device descriptor elements. */
+#define USB_DEV_DESC_LEN 0x12
+#define USB_DEV_DESC_TYPE 0x01
+#define USB_DEV_DESC_SPEC_LB 0x00
+#define USB_DEV_DESC_SPEC_HB 0x02
+#define USB_DEV_DESC_DEV_CLASS 0x00 /*ROM Code definition*///0x02 /* Fisher: CDC bDeviceClass */
+#define USB_DEV_DESC_DEV_SUBCLASS 0x00 //0x02 /* Fisher: Abstract Control Model*/
+#define USB_DEV_DESC_DEV_PROTOCOL 0x00
+#define USB_DEV_DESC_EP0_MAXPACKETSIZE 0x40
+#define USB_DEV_DESC_VENDORID_LB (VID & 0x00FF)
+#define USB_DEV_DESC_VENDORID_HB ((VID & 0xFF00) >> 0x8)
+#define USB_DEV_DESC_PRODUCTID_LB (PID & 0x00FF)
+#define USB_DEV_DESC_PRODUCTID_HB ((PID & 0xFF00) >> 0x8)
+#define USB_DEV_DESC_DEV_RELEASE_NUM_LB 0x01
+#define USB_DEV_DESC_DEV_RELEASE_NUM_HB 0x00
+#define USB_DEV_DESC_DEV_STRING_IND_MANUFACTURE 0x01
+#define USB_DEV_DESC_DEV_STRING_IND_PRODUCT 0x02
+#if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+#define USB_DEV_DESC_DEV_STRING_IND_SERIAL_NUM 0x00
+#else
+#define USB_DEV_DESC_DEV_STRING_IND_SERIAL_NUM 0x05 /*for mass storage device, it must >0*/
+#endif
+#define USB_DEV_DESC_DEV_NUM_CONFIGURATIONS 0x01
+
+
+
+/* Constants defindes to represent elements of configuration descriptor. */
+
+#define USB_DEV_CONFIG_DESC_LEN 0x09 /* Length of configuration descriptor. */
+#define USB_DEV_CONFIG_DESC_TYPE 0x02 /* Descriptor type. */
+#define USB_DEV_CONFIG_DESC_TTL_LEN_LB 0x20 /* Total length of configuration information. */
+#define USB_DEV_CONFIG_DESC_TTL_LEN_HB 0x00 /* Total length of configuration information. */
+#define USB_DEV_CONFIG_DESC_NUM_0F_INF 0x01 /* Number of interfaces in this configuration. */
+#define USB_DEV_CONFIG_DESC_CONFIG_VALUE 0x01 /* Configuration value. */
+#if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+#define USB_DEV_CONFIG_DESC_STRING_INDEX 0x04 /* String index for this configuration. */
+#else
+#define USB_DEV_CONFIG_DESC_STRING_INDEX 0x00 /* String index for this configuration. */
+#endif
+#define USB_DEV_CONFIG_DESC_ATTRIBUTES 0xC0/* Self powered and supported remote wakeup. */
+ /* 0x80 Self powered and supported remote wakeup. */
+
+#define USB_DEV_CONFIG_DESC_MAX_POWER 0x32 /* 100ma,Max power consumed by phone. */
+
+#define USB_DEV_INF_DESC_LEN 0x09 /* Interface descriptor length. */
+#define USB_DEV_INF_DESC_TYPE 0x04 /* The descriptor type, 4 interface descriptor. */
+#define USB_DEV_INF_DESC_INF_INDEX 0x00 /* Interface index. */
+#define USB_DEV_INF_DESC_ALT_SETTING 0x00 /* The alternate setting is 0. */
+#define USB_DEV_INF_DESC_NUM_OF_EP 0x02 /* Control endpoint and data endpoint 1 and 2. */
+#define USB_DEV_INF_DESC_INF_CLASS_VENDOR 0xFF /* Interface class: Vendor Specific. */
+#define USB_DEV_INF_DESC_INF_CLASS_MSC 0x08 /* Interface class: Mass Storage. */
+#define USB_DEV_INF_DESC_INF_SUBCLASS_S_BLANK 0x40 /* (Subclass) Motorola Flash Download. */
+#define USB_DEV_INF_DESC_INF_SUBCLASS_NS_BLANK 0x42
+#define USB_DEV_INF_DESC_INF_SUBCLASS_MSC_SCSI 0x06 /* SCSI transparent command set for mass storage*/
+#define USB_DEV_INF_DESC_INF_PROTOCOL 0x01 /* (Interface protocol) Vendor Specific, ROM bootloader interface. */
+#define USB_DEV_INF_DESC_INF_PROTOCOL_MSC_BOT 0x50 /* Mass Storage Bulk Only Transport*/
+#if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+#define USB_DEV_INF_DESC_STRING_INDEX 0x05 /* Index of interface string descriptor. */
+#else
+#define USB_DEV_INF_DESC_STRING_INDEX 0x04 /* Index of interface string descriptor. */
+#endif
+
+/* Constants defined to represent the endpoint descriptor elements. */
+#define USB_MAX_PACKET_SIZE 0x0200
+#define USB_MAX_PACKET_SIZE_LO (USB_MAX_PACKET_SIZE&0xFF)
+#define USB_MAX_PACKET_SIZE_HI ((USB_MAX_PACKET_SIZE>>8)&0xFF)
+
+/* Endpoint 1 descriptor. */
+#define USB_EP1_DESC_SIZE 0x07 /* Size of descriptor in bytes. */
+#define USB_EP1_DESC_TYPE 0x05 /* Descriptor type. */
+#define USB_EP1_DESC_EP_ADDR 0x01 /* (Endpoint address) Endpoint 1, OUT. */
+#define USB_EP1_DESC_ATTRIBUTES 0x02 /* (Attributes) Bulk Endpoint. */
+#define USB_EP1_DESC_MAX_PACKET_SIZE_FS_LB 0x40 /* Max Packet Size. */
+#define USB_EP1_DESC_MAX_PACKET_SIZE_FS_HB 0x00 /* Max Packet Size. */
+#define USB_EP1_DESC_MAX_PACKET_SIZE_HS_LB USB_MAX_PACKET_SIZE_LO /* Max Packet Size. */
+#define USB_EP1_DESC_MAX_PACKET_SIZE_HS_HB USB_MAX_PACKET_SIZE_HI /* Max Packet Size. */
+#define USB_EP1_DESC_INTERVAL 0x00 /* Interval, ignored. */
+#define USB_EP1_DESC_INTERVAL_HS 0x01 /* at most 1NAK. */
+/* Endpoint 2 descriptor. */
+#define USB_EP2_DESC_SIZE 0x07 /* Size of descriptor in bytes. */
+#define USB_EP2_DESC_TYPE 0x05 /* Descriptor type. */
+#define USB_EP2_DESC_EP_ADDR 0x82 /* (Endpoint address) Endpoint 2, IN. */
+#define USB_EP2_DESC_ATTRIBUTES 0x02 /* (Attributes) Bulk Endpoint. */
+#define USB_EP2_DESC_MAX_PACKET_SIZE_FS_LB 0x40 /* Max Packet Size. */
+#define USB_EP2_DESC_MAX_PACKET_SIZE_FS_HB 0x00 /* Max Packet Size. */
+#define USB_EP2_DESC_MAX_PACKET_SIZE_HS_LB USB_MAX_PACKET_SIZE_LO/* Max Packet Size. */
+#define USB_EP2_DESC_MAX_PACKET_SIZE_HS_HB USB_MAX_PACKET_SIZE_HI /* Max Packet Size. */
+
+#define USB_EP2_DESC_INTERVAL 0x00 /* Interval, ignored. */
+#define USB_EP2_DESC_INTERVAL_HS 0x01 /* at most 1NAK. */
+/* String Descriptor 0 */
+#define USB_STR0_DESC_SIZE 0x04 /* Size of descriptor in bytes. */
+#define USB_STR0_DESC_TYPE 0x03 /* Descriptor type. */
+#define USB_LANGUAGE_ID_LB 0x09 /* Language id of english */
+#define USB_LANGUAGE_ID_HB 0x04 /* Language id of english */
+
+/* String Descriptor 1 */
+#define USB_STR1_DESC_SIZE 0x3A /* Size of descriptor in bytes. */
+#define USB_STR1_DESC_TYPE 0x03 /* Descriptor type. */
+
+/* String Descriptor 2 */
+#define USB_STR2_DESC_SIZE_NS 0x20 /* Size of descriptor in bytes for Non Secure Download*/
+#define USB_STR2_DESC_SIZE_SE 0x20 /* Size of descriptor in bytes for Secure Engg. download*/
+#define USB_STR2_DESC_SIZE_S 0x20 /* Size of descriptor in bytes for Secure production download*/
+#define USB_STR2_DESC_TYPE 0x03 /* Descriptor type. */
+
+/* String Descriptor 3 */
+#define USB_STR3_DESC_SIZE 0x20 /* Size of descriptor in bytes. */
+#define USB_STR3_DESC_TYPE 0x03 /* Descriptor type. */
+
+/* Serial number string descriptor */
+#define USB_SN_DESC_LEN 0x1A /* Size of descriptor length*/
+#define USB_SN_DESC_TYPE 0x03 /* type of descriptor*/
+/*************************usb descriptor typedefs********************/
+typedef struct {
+ usb_configuration_descriptor usb_config_desc;
+ usb_interface_descriptor usb_interface_desc;
+ usb_endpoint_descriptor usb_endpoint_desc[USB_DEV_INF_DESC_NUM_OF_EP];
+}__attribute__((packed)) usb_conf_desc;
+/* USB device serial number for mass storage requiremen*/
+typedef struct {
+ cyg_uint8 length;
+ cyg_uint8 descriptor_type;
+ cyg_uint8 string[24];
+}__attribute__((packed)) usb_str4_desc;
+/* USB string Descriptor structure 0 according to USB2.0 Specification */
+typedef struct {
+ cyg_uint8 length;
+ cyg_uint8 descriptor_type;
+ cyg_uint8 language_id0_l;
+ cyg_uint8 language_id0_h;
+}__attribute__((packed)) usb_str0_desc;
+
+/* USB string Descriptor structure 1 according to USB2.0 Specification */
+typedef struct {
+ cyg_uint8 length;
+ cyg_uint8 descriptor_type;
+ cyg_uint8 string[56];
+}__attribute__((packed)) usb_str1_desc;
+
+/* USB string Descriptor structure 2 according to USB2.0 Specification */
+typedef struct {
+ cyg_uint8 length;
+ cyg_uint8 descriptor_type;
+ cyg_uint8 string[34];
+}__attribute__((packed)) usb_str2_desc;
+
+/* USB string Descriptor structure 3 according to USB2.0 Specification */
+typedef struct {
+ cyg_uint8 length;
+ cyg_uint8 descriptor_type;
+ cyg_uint8 string[30];
+}__attribute__((packed)) usb_str3_desc;
+
+#define usb_dev_desc usb_device_descriptor //rename the structure
+
+/* ALL USB Descriptors for both FS and HS */
+typedef struct {
+ usb_dev_desc* device_desc;
+ usb_conf_desc* config_desc;
+ usb_str4_desc* sn_desc;
+ usb_str0_desc* str_desc0;
+ usb_str1_desc* str_desc1;
+ usb_str2_desc* str_desc2;
+ usb_str3_desc* str_desc3;
+
+}usb_descriptor;
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+
+#endif /* CYGONCE_USBS_IMX_H */
--- /dev/null
+//==========================================================================
+//
+// usbs_imx.c
+//
+// Device driver for the i.MX51 or i.MX37 USB OTG port.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is a part of Diagnosis Package based on eCos for Freescale i.MX
+// Family microprocessor.
+// Copyright (C) 2008 Freescale Semiconductor, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): fisherz
+// Contributors: fisherz
+// Date: 2008-10-16
+//
+// This code implements support for the on-chip USB OTG port on the Freescale i.MX
+// family of processors. The code has been developed on the i.MX and
+// may or may not work on other members of the i.MX family. There
+// have problems with the USB support on certain revisions of the silicon,
+// so the errata sheet appropriate to the specific processor being used
+// should be consulted. There also appear to be problems which do not
+// appear on any errata, which this code attempts to work around.
+//
+// [Note] DMA is not enabled for USB transfer
+//####DESCRIPTIONEND####
+//
+//####REVISION HISTORY####
+// Date Author Comments
+// 22Jul08 Fisher ZHU(b18985) Created for i.MX37 eCos USB device driver
+// 16Oct08 Fisher ZHU(b18985) Ported to i.MX51 USB OTG core
+//==========================================================================
+#include <string.h> //use memset() of C run-time library
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h>
+#include <pkgconf/hal_arm.h>
+#include <pkgconf/devs_usb_imx_otg.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_cache.h>
+#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+#include <cyg/error/codes.h>
+#endif
+#include <cyg/io/usb/usb.h>
+#include <cyg/io/usb/usbs.h>
+#include <cyg/io/usb/usbs_imx.h>
+
+#pragma O0 //this pragma is useful when Realview tool chain is used
+#define VOLATILE volatile
+
+#if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+//this error code is defined in error/include/codes.h
+//but when the usb driver is used in redboot, the codes.h won't
+//be included, so that this definition will solve the problem
+#define EPIPE 304
+
+/* Constants */
+#define SDP_CMD_MAX_LEN 0x10 /* 16 bytes */
+#define SDP_CMD_ACK_LEN 0x4 /* 4 bytes */
+/* Command Packet Format: Header(2)+Address(4)+Format(1)+ByteCount(4)+Data(4) */
+#define READ_HEADER 0x0101 //Read the flag in an assigned address on the target board
+#define WRITE_HEADER 0x0202
+#define WRITE_FILE 0x0404 //Write a file in host PC to target board
+#define READ_FILE 0x0A0A //Read a block of RAM to host PC and save in a file
+#define ERROR_STATUS_HEADER 0x0505
+
+/* SDP Responses */
+#define WRITE_COMPLETE 0x128A8A12
+
+/* SDP States */
+#define CONTINUE 0
+#define DONE 1
+#define COMPLETE 0x88
+
+#define USB_DOWNLOAD_TIMEOUT_LIMIT 0x1D000000
+cyg_uint32 usb_download_address;
+cyg_uint32 usb_download_length;
+static cyg_uint8 sdp_payload_data[SDP_CMD_MAX_LEN]; /* Used to send or receive Command/ACK */
+static cyg_uint8 sdp_command[SDP_CMD_MAX_LEN]; /* Used to store Command */
+static cyg_uint8 g_error_status;
+static cyg_uint8 g_usb_download_state = CONTINUE;
+static cyg_uint32 g_timeout_value = 0;
+static cyg_uint32 g_load_cycle;
+static cyg_bool pl_get_command(void);
+static cyg_uint8 pl_command_start(void);
+static cyg_uint8 pl_handle_command(cyg_uint8 g_error_status);
+static void pl_command_ack(cyg_uint32 ack);
+static void pl_handle_write_file(cyg_uint32 address, cyg_uint32 total_bytes);
+static cyg_uint32 usb_rx_processing(cyg_uint8* read_ptr, usb_status_t* status, cyg_uint32 data_length);
+static usb_status_t usb_tx_processing(cyg_uint8* write_ptr, cyg_uint32 data_len);
+#endif
+
+/* Bit3 - Mass Storage Information
+ Bit2 - Enumeration Information
+ Bit1 - Transaction Information
+ Bit0 - Basic Information
+*/
+//#define DEBUG_TRANS 0x8 //also defined in usbs_msc.c
+#define DEBUG_ENUM 0x4
+#define DEBUG_TRANS 0x2
+#define DEBUG_BASIC 0x1
+
+//#define USBDBGMSG(str) if(g_debug_switch&0x1) diag_printf(str)
+#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+extern cyg_uint32 g_debug_switch; //the lowest 4-bit is used for USB debug
+#if 1
+#define USBDBGMSG(opt,fmt,args...) if(g_debug_switch&opt) diag_printf(fmt, ## args)
+#else
+#define USBDBGMSG(opt,fmt,args...)
+#endif
+
+#else
+#define USBDBGMSG(opt,fmt,args...) //diag_printf(fmt, ## args)
+#define D(fmt,args...) diag_printf(fmt, ## args)
+#endif
+
+// ----------------------------------------------------------------------------
+//volatile cyg_uint8 g_bulkbuffer[BULK_TD_BUFFER_TOTAL_SIZE*NUM_OF_BULK_BUFFER] __attribute__((aligned(0x1000)));
+bulk_buffer_t g_bulkbuffer_a;
+bulk_buffer_t g_bulkbuffer_b;
+
+//This variable is used to workaround the 31-byte packet issue in i.MX37
+//It is initialized as "0x1",
+//When data read/write, it must initialize as '0x0'
+cyg_uint32 g_td_buffer_offset = 0;
+
+//The below two flags is used to distinguish the received data is data or command
+cyg_uint32 g_received_data_type;
+
+/* This is used to pause the EP2 In wait for complete, just a workaround for this issue
+ It is not sure to be a bug of IC or software, need to check later.
+*/
+//cyg_uint8 g_tx_done=1; //to keep EP1 issue sempahore to scsi after the previous CBW processed
+cyg_uint8 g_ep2_complete_bit_set = 0;
+
+#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+extern cyg_sem_t usbs_msc_sem; //semaphore to schedule mass storage command handling thread
+#endif
+
+// ----------------------------------------------------------------------------
+// Static pointers for USB buffer layout
+/*=============================================================================
+ STATIC VARIABLES
+//============================================================================*/
+
+// Allocate 2k-byte buffer as USB QueueHeaderList region.
+// Don't use #pragma arm section in GCC
+// !!!!USB buffer should not be cached and buffered.
+//#pragma arm section rwdata="usb_buffer_no_init", zidata="usb_buffer_no_init"
+//2k aligned, this buffer must be uncacheable and unbufferable.
+
+#if defined(CYGHWR_IMX_USB_BUFFER_USE_IRAM)
+static volatile cyg_uint8 usb_buffer[BUFFER_SIZE] __attribute__((aligned(0x800)));
+static volatile cyg_uint8 bulk_buffer[BULK_TD_BUFFER_TOTAL_SIZE*NUM_OF_BULK_BUFFER] __attribute__((aligned(0x1000)));
+//#pragma arm section
+#else
+/* iRAM is configured as uncacheable and unbufferable in MMU initialization
+ Reserve 0x800 bytes as USB buffer
+ Don't use 0x10001000~0x10001800 for other program. */
+#if defined(CYGHWR_USB_DEVS_MX37_OTG)
+static volatile cyg_uint8 * usb_buffer=(cyg_uint8 *)(0x10001000);
+static volatile cyg_uint8 * bulk_buffer = (cyg_uint8 *)(0x10002000);
+#endif
+
+#if defined(CYGHWR_USB_DEVS_MX51_OTG)
+static volatile cyg_uint8 * usb_buffer=(cyg_uint8 *)(0x1FFE9000);
+static volatile cyg_uint8 * bulk_buffer = (cyg_uint8 *)(0x1FFEA000);
+#endif
+//
+#endif //defined(CYGHWR_IMX_USB_BUFFER_USE_IRAM)
+
+VOLATILE usbs_imx_otg_hardware* usbs_imx_otg_base = (VOLATILE usbs_imx_otg_hardware* const) USB_BASE_ADDRESS;
+
+static void usbs_imx_otg_config_utmi_clock(void);
+
+
+/* Base address of the buffer allocated to IP Layer */
+static VOLATILE cyg_uint32 g_bulkbuffer_address_base;
+/* length of the buffer */
+static VOLATILE cyg_uint32 g_bulkbuffer_length;
+/* Buffer information used for data transfer */
+static VOLATILE buffer_map_t g_bulkbuffer_map;
+/* Number of Endpoints configured in system */
+static VOLATILE cyg_uint8 g_max_ep_supported;
+/* State os USB Device */
+static VOLATILE usb_state_t g_usb_dev_state = USB_DEV_DUMMY_STATE;
+/* Length of setup data received */
+static VOLATILE cyg_uint8 * g_usb_setup_data;
+/* Array to keep information about the endpoints used */
+static VOLATILE usb_end_pt_info_t g_end_pt_info[USB_DEV_INF_DESC_NUM_OF_EP];
+/* Number of endpoints */
+static VOLATILE cyg_uint8 g_number_of_endpoints;
+/* USB Descriptors */
+static VOLATILE usb_descriptor g_usb_desc;
+/* Number of Endpoint configured as IN */
+static VOLATILE cyg_uint8 g_in_endpoint;
+/* Number of Endpoint configured as OUT*/
+static VOLATILE cyg_uint8 g_out_endpoint;
+
+/* Support for the interrupt handling code.*/
+static cyg_interrupt g_usbs_dev_intr_data;
+static cyg_handle_t g_usbs_dev_intr_handle;
+static volatile int g_isr_status_bits = 0;
+
+// ----------------------------------------------------------------------------
+// get the base address of queue header for an endpointer
+#define USBS_EP_GET_dQH(endptno,dir) (g_bulkbuffer_map.ep_dqh_base_addrs + (SIZE_OF_QHD * (endptno * 2 + dir)))
+#define USBS_EP_GET_dTD(endptno,dir) (g_bulkbuffer_map.ep_dtd_base_addrs + (SIZE_OF_DTD0 + SIZE_OF_DTD1) * ( endptno * 2 + dir))
+// ----------------------------------------------------------------------------
+// USB interrupt enable/disable macros
+#define USBS_IMX_OTG_INTR_MASK() (usbs_imx_otg_base->usbintrclr = 0xFFFFFFFF)//0|IMX_USB_INTR_DEV_RESET|IMX_USB_INTR_DEV_USBINT)
+#define USBS_IMX_OTG_INTR_UNMASK(intr) (usbs_imx_otg_base->usbintr = 0|(intr))
+
+// ----------------------------------------------------------------------------
+// Check if the IOS bit of QueueHeader or the IOC bit of Transfer Descriptor are set
+#define USBS_dQH_IOS_CHECK(ep_num,dir) (((*(cyg_uint32*)USBS_EP_GET_dQH(ep_num,dir))&0x8000)?1:0)
+#define USBS_dTD_IOC_CHECK(ep_num,dir) (((*(cyg_uint32*)USBS_EP_GET_dTD(ep_num,dir))&0x8000)?1:0)
+
+// ----------------------------------------------------------------------------
+// Set USB device address
+#define USBS_DEVICE_SET_ADDRESS(addr) (usbs_imx_otg_base->devaddr = ((cyg_uint32)addr & 0x7F) << 25)
+/*
+#*************
+# OTG
+#*************
+*/
+#define USB_OTG_ID (&(usbs_imx_otg_base->id)) /* Identification Register */
+#define USB_OTG_HWGENERAL (&(usbs_imx_otg_base->hwgeneral)) /* General Hardware Parameters */
+#define USB_OTG_HWHOST (&(usbs_imx_otg_base->hwhost)) /* Host Hardware Parameters */
+#define USB_OTG_HWDEVICE (&(usbs_imx_otg_base->hwdevice)) /* Device Hardware Parameters */
+#define USB_OTG_HWTXBUF (&(usbs_imx_otg_base->hwtxbuf)) /* TX Buffer Hardware Parameters */
+#define USB_OTG_HWRXBUF (&(usbs_imx_otg_base->hwrxbuf)) /* RX Buffer Hardware Parameters */
+
+#define USB_OTG_CAPLENGTH (&(usbs_imx_otg_base->caplength)) /* Capability Register Length */
+#define USB_OTG_HCIVERSION (&(usbs_imx_otg_base->hciversion)) /* Host Interface Version Number */
+#define USB_OTG_HCSPARAMS (&(usbs_imx_otg_base->hcsparams)) /* Host Ctrl. Structural Parameters */
+#define USB_OTG_HCCPARAMS (&(usbs_imx_otg_base->hccparams)) /* Host Ctrl. Capability Parameters */
+#define USB_OTG_DCIVERSION (&(usbs_imx_otg_base->dciversion)) /* Dev. Interface Version Number */
+#define USB_OTG_DCCPARAMS (&(usbs_imx_otg_base->dccparams)) /* Dev. Ctrl. Capability Parameters */
+
+#define USB_OTG_USBCMD (&(usbs_imx_otg_base->usbcmd)) /* USB Command */
+#define USB_OTG_USBSTS (&(usbs_imx_otg_base->usbsts)) /* USB Status */
+#define USB_OTG_USBINTR (&(usbs_imx_otg_base->usbintr)) /* USB Interrupt Enable */
+#define USB_OTG_FRINDEX (&(usbs_imx_otg_base->frindex)) /* USB Frame Index */
+
+#define USB_OTG_DEVICEADDR (&(usbs_imx_otg_base->devaddr)) /* USB Device Address */
+#define USB_OTG_PERIODICLISTBASE USB_OTG_DEVICEADDR /* Frame List Base Address */
+#define USB_OTG_ENDPOINTLISTADDR (&(usbs_imx_otg_base->endptlistaddr)) /*Address of Endpt list in memory*/
+#define USB_OTG_ASYNCLISTADDR USB_OTG_ENDPOINTLISTADDR /* Next Asynchronous List Address */
+
+#define USB_OTG_BURSTSIZE (&(usbs_imx_otg_base->burstsize)) /* Programmable Burst Size */
+#define USB_OTG_TXFILLTUNING (&(usbs_imx_otg_base->txfilltuning)) /* Host TX Pre-Buffer Packet Tuning */
+#define USB_OTG_VIEWPORT (&(usbs_imx_otg_base->ulpiviewport)) /* ULPI Register */
+#define USB_OTG_ENDPTNAK (&(usbs_imx_otg_base->endptnak)) /*Endpoint NAK */
+#define USB_OTG_ENDPTNAKEN (&(usbs_imx_otg_base->endptnaken)) /*Endpoint NAK Enable */
+#define USB_OTG_CONFIGFLAG (&(usbs_imx_otg_base->configflg)) /* Configured Flag Register */
+#define USB_OTG_PORTSC1 (&(usbs_imx_otg_base->portsc1)) /* Port 0 Status/Control */
+#define USB_OTG_OTGSC (&(usbs_imx_otg_base->otgsc)) /* OTG Status and Control */
+#define USB_OTG_USBMODE (&(usbs_imx_otg_base->usbmode)) /* USB Device Mode */
+#define USB_OTG_ENDPTSETUPSTAT (&(usbs_imx_otg_base->endptsetupstat)) /* Endpoint Setup Status */
+#define USB_OTG_ENDPTPRIME (&(usbs_imx_otg_base->endptprime)) /* Endpoint Initialization */
+#define USB_OTG_ENDPTFLUSH (&(usbs_imx_otg_base->endptflush)) /* Endpoint De-Initialize */
+#define USB_OTG_ENDPTSTATUS (&(usbs_imx_otg_base->endptstatus))/* Endpoint Status */
+#define USB_OTG_ENDPTCOMPLETE (&(usbs_imx_otg_base->endptcomplete)) /* Endpoint Complete */
+#define USB_OTG_ENDPTCTRL0 (&(usbs_imx_otg_base->endptctrl[0])) /* Endpoint Control 0 */
+#define USB_OTG_ENDPTCTRL1 (&(usbs_imx_otg_base->endptctrl[1])) /* Endpoint Control 1 */
+#define USB_OTG_ENDPTCTRL2 (&(usbs_imx_otg_base->endptctrl[2])) /* Endpoint Control 2 */
+#define USB_OTG_ENDPTCTRL3 (&(usbs_imx_otg_base->endptctrl[3])) /* Endpoint Control 3 */
+#define USB_OTG_ENDPTCTRL4 (&(usbs_imx_otg_base->endptctrl[4])) /* Endpoint Control 4 */
+#define USB_OTG_ENDPTCTRL5 (&(usbs_imx_otg_base->endptctrl[5])) /* Endpoint Control 5 */
+#define USB_OTG_ENDPTCTRL6 (&(usbs_imx_otg_base->endptctrl[6])) /* Endpoint Control 6 */
+#define USB_OTG_ENDPTCTRL7 (&(usbs_imx_otg_base->endptctrl[7])) /* Endpoint Control 7 */
+// ****************************************************************************
+// -----------------------USB Device Descriptors-------------------------------
+// ****************************************************************************
+/* USB Device Descriptor according to USB2.0 Specification */
+static VOLATILE usb_device_descriptor g_usb_device_desc ={
+ USB_DEV_DESC_LEN,
+ USB_DEV_DESC_TYPE,
+ USB_DEV_DESC_SPEC_LB,
+ USB_DEV_DESC_SPEC_HB,
+ USB_DEV_DESC_DEV_CLASS,
+ USB_DEV_DESC_DEV_SUBCLASS,
+ USB_DEV_DESC_DEV_PROTOCOL,
+ USB_DEV_DESC_EP0_MAXPACKETSIZE,
+ USB_DEV_DESC_VENDORID_LB,
+ USB_DEV_DESC_VENDORID_HB,
+ USB_DEV_DESC_PRODUCTID_LB,
+ USB_DEV_DESC_PRODUCTID_HB,
+ USB_DEV_DESC_DEV_RELEASE_NUM_LB,
+ USB_DEV_DESC_DEV_RELEASE_NUM_HB,
+ USB_DEV_DESC_DEV_STRING_IND_MANUFACTURE,
+ USB_DEV_DESC_DEV_STRING_IND_PRODUCT,
+ USB_DEV_DESC_DEV_STRING_IND_SERIAL_NUM,
+ USB_DEV_DESC_DEV_NUM_CONFIGURATIONS
+};
+
+
+/* USB Config Descriptor according to USB2.0 Specification */
+static VOLATILE usb_conf_desc g_usb_config_desc = {
+ {
+ USB_DEV_CONFIG_DESC_LEN,
+ USB_DEV_CONFIG_DESC_TYPE,
+ USB_DEV_CONFIG_DESC_TTL_LEN_LB ,
+ USB_DEV_CONFIG_DESC_TTL_LEN_HB ,
+ USB_DEV_CONFIG_DESC_NUM_0F_INF,
+ USB_DEV_CONFIG_DESC_CONFIG_VALUE ,
+ USB_DEV_CONFIG_DESC_STRING_INDEX,
+ USB_DEV_CONFIG_DESC_ATTRIBUTES,
+ USB_DEV_CONFIG_DESC_MAX_POWER
+ },
+ /* USB Interface Descriptor according to USB2.0 Specification */
+ {//09
+ USB_DEV_INF_DESC_LEN,
+ USB_DEV_INF_DESC_TYPE,
+ USB_DEV_INF_DESC_INF_INDEX,
+ USB_DEV_INF_DESC_ALT_SETTING,
+ USB_DEV_INF_DESC_NUM_OF_EP, /* NOTE : This should not be more than 2 */
+ #if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ USB_DEV_INF_DESC_INF_CLASS_VENDOR,
+ USB_DEV_INF_DESC_INF_SUBCLASS_NS_BLANK,
+ USB_DEV_INF_DESC_INF_PROTOCOL,
+ #else
+ USB_DEV_INF_DESC_INF_CLASS_MSC,
+ USB_DEV_INF_DESC_INF_SUBCLASS_MSC_SCSI,
+ USB_DEV_INF_DESC_INF_PROTOCOL_MSC_BOT,
+ #endif
+ USB_DEV_INF_DESC_STRING_INDEX
+ },
+ /* USB Endpoint 1 Descriptors according to USB2.0 Specification, OUT */
+ {
+ {//18
+ USB_EP1_DESC_SIZE,
+ USB_EP1_DESC_TYPE,
+ USB_EP1_DESC_EP_ADDR,
+ USB_EP1_DESC_ATTRIBUTES,
+ USB_EP1_DESC_MAX_PACKET_SIZE_HS_LB,
+ USB_EP1_DESC_MAX_PACKET_SIZE_HS_HB,
+ USB_EP1_DESC_INTERVAL
+ },
+ /* USB Endpoint 2 Descriptors according to USB2.0 Specification, IN */
+ {//25
+ USB_EP2_DESC_SIZE,
+ USB_EP2_DESC_TYPE,
+ USB_EP2_DESC_EP_ADDR,
+ USB_EP2_DESC_ATTRIBUTES,
+ USB_EP2_DESC_MAX_PACKET_SIZE_HS_LB,
+ USB_EP2_DESC_MAX_PACKET_SIZE_HS_HB,
+ USB_EP2_DESC_INTERVAL
+ }
+ }
+};
+
+/* USB String Descriptors 0, according to USB2.0 Specification */
+static VOLATILE usb_str0_desc g_usb_otg_str0_desc ={
+ USB_STR0_DESC_SIZE,
+ USB_STR0_DESC_TYPE,
+ USB_LANGUAGE_ID_LB,
+ USB_LANGUAGE_ID_HB
+};
+
+/*
+ STRING DESCRIPTOR
+ See table 9-15 in USB2.0 spec (www.usb.org)
+ iManufacturer
+*/
+static VOLATILE usb_str1_desc g_usb_otg_string_desc1 ={
+ USB_STR1_DESC_SIZE, /* bLength */
+ USB_STR1_DESC_TYPE, /* bDescriptorType */
+ {
+ 'F', 0x00, /* bString */
+ 'r', 0x00,
+ 'e', 0x00,
+ 'e', 0x00,
+ 's', 0x00,
+ 'c', 0x00,
+ 'a', 0x00,
+ 'l', 0x00,
+ 'e', 0x00,
+ ' ', 0x00,
+ 'S', 0x00,
+ 'e', 0x00,
+ 'm', 0x00,
+ 'i', 0x00,
+ 'C', 0x00,
+ 'o', 0x00,
+ 'n', 0x00,
+ 'd', 0x00,
+ 'u', 0x00,
+ 'c', 0x00,
+ 't', 0x00,
+ 'o', 0x00,
+ 'r', 0x00,
+ ' ', 0x00,
+ 'I', 0x00,
+ 'n', 0x00,
+ 'c', 0x00,
+ '.', 0x00
+ }
+};
+#if defined(CYGHWR_USB_DEVS_MX37_OTG)
+/*iProduct*/
+static VOLATILE usb_str2_desc g_usb_otg_string_desc2 = {
+ USB_STR2_DESC_SIZE_NS, /* bLength */
+ USB_STR2_DESC_TYPE, /* bDescriptorType */
+ {
+ 'M', 0x00, /* bString */
+ 'A', 0x00,
+ 'R', 0x00,
+ 'L', 0x00,
+ 'E', 0x00,
+ 'Y', 0x00,
+ ' ', 0x00,
+ 'U', 0x00,
+ 'S', 0x00,
+ 'B', 0x00,
+ ' ', 0x00,
+ 'O', 0x00,
+ 'T', 0x00,
+ 'G', 0x00,
+ ' ', 0x00
+ }
+};
+//#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+/* USB Serial Number Descriptor which is mandatory to Mass Storage Device */
+static VOLATILE usb_str4_desc g_usb_serialnumber_desc = {
+ USB_SN_DESC_LEN,
+ USB_SN_DESC_TYPE,
+ {
+ '2',0x00,
+ '0',0x00,
+ '0',0x00,
+ '8',0x00,
+ '1',0x00,
+ '8',0x00,
+ '9',0x00,
+ '8',0x00,
+ '5',0x00,
+ '0',0x00,
+ '3',0x00,
+ '7',0x00
+ }
+};
+//#endif
+#endif
+
+#if defined(CYGHWR_USB_DEVS_MX51_OTG)
+static VOLATILE usb_str2_desc g_usb_otg_string_desc2 = {
+ USB_STR2_DESC_SIZE_NS, /* bLength */
+ USB_STR2_DESC_TYPE, /* bDescriptorType */
+ {
+ 'E', 0x00, /* bString */
+ 'l', 0x00,
+ 'v', 0x00,
+ 'i', 0x00,
+ 's', 0x00,
+ ' ', 0x00,
+ 'U', 0x00,
+ 'S', 0x00,
+ 'B', 0x00,
+ ' ', 0x00,
+ 'O', 0x00,
+ 'T', 0x00,
+ 'T', 0x00,
+ ' ', 0x00,
+ ' ', 0x00
+ }
+};
+//#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+/* USB Serial Number Descriptor which is mandatory to Mass Storage Device */
+static VOLATILE usb_str4_desc g_usb_serialnumber_desc = {
+ USB_SN_DESC_LEN,
+ USB_SN_DESC_TYPE,
+ {
+ '2',0x00,
+ '0',0x00,
+ '0',0x00,
+ '8',0x00,
+ '1',0x00,
+ '8',0x00,
+ '9',0x00,
+ '8',0x00,
+ '5',0x00,
+ '0',0x00,
+ '5',0x00,
+ '1',0x00
+ }
+};
+//#endif
+#endif
+
+/* STRING DESCRIPTOR
+ See table 9-15 in USB2.0 spec (www.usb.org)
+ iSerialNumber */
+static VOLATILE usb_str3_desc g_usb_otg_string_desc3 = {
+ USB_STR3_DESC_SIZE, /* bLength */
+ USB_STR3_DESC_TYPE, /* bDescriptorType */
+ {
+ 'F', 0x00, /* bString */
+ 'r', 0x00,
+ 'e', 0x00,
+ 'e', 0x00,
+ 's', 0x00,
+ 'c', 0x00,
+ 'a', 0x00,
+ 'l', 0x00,
+ 'e', 0x00,
+ ' ', 0x00,
+ 'F', 0x00,
+ 'l', 0x00,
+ 'a', 0x00,
+ 's', 0x00,
+ 'h', 0x00
+ }
+};
+
+
+// ****************************************************************************
+// ----------------------------------------------------------------------------
+// ****************************************************************************
+// ----------------------------------------------------------------------------
+// Static data. There is a data structure for each endpoint. The
+// implementation is essentially a private class that inherits from
+// common classes for control and data endpoints, but device drivers
+// are supposed to be written in C so some ugliness is required.
+
+// ----------------------------------------------------------------------------
+// Endpoint 0 is always present, this module would not get compiled
+// otherwise.
+static void usbs_imx_otg_dev_ep0_start(usbs_control_endpoint*);
+static void usbs_imx_otg_dev_poll(usbs_control_endpoint*);
+
+typedef enum ep0_state {
+ EP0_STATE_IDLE = 0,
+ EP0_STATE_IN = 1,
+ EP0_STATE_OUT = 2
+} ep0_state;
+
+typedef struct ep0_impl {
+ usbs_control_endpoint common; //struct usbs_control_endpoint defined in usbs.h
+ ep0_state ep_state;
+ int length;
+ int transmitted;
+} ep0_impl;
+
+static ep0_impl ep0 = {
+ common:
+ {
+ state: USBS_STATE_POWERED, // The hardware does not distinguish between detached, attached and powered.
+ enumeration_data: (usbs_enumeration_data*) 0,
+ start_fn: &usbs_imx_otg_dev_ep0_start,
+ poll_fn: &usbs_imx_otg_dev_poll,
+ interrupt_vector: IMX_IRQ_USB_DEV_SERVICE_REQUEST,
+ control_buffer: { 0, 0, 0, 0, 0, 0, 0, 0 },
+ state_change_fn: (void (*)(usbs_control_endpoint*, void*, usbs_state_change, int)) 0,
+ state_change_data: (void*) 0,
+ standard_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
+ standard_control_data: (void*) 0,
+ class_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
+ class_control_data: (void*) 0,
+ vendor_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
+ vendor_control_data: (void*) 0,
+ reserved_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0,
+ reserved_control_data: (void*) 0,
+ buffer: (unsigned char*) 0,
+ buffer_size: 0,
+ fill_buffer_fn: (void (*)(usbs_control_endpoint*)) 0,
+ fill_data: (void*) 0,
+ fill_index: 0,
+ complete_fn: (usbs_control_return (*)(usbs_control_endpoint*, int)) 0
+ },
+ ep_state: EP0_STATE_IDLE,
+ length: 0,
+ transmitted: 0
+};
+
+extern usbs_control_endpoint usbs_imx_otg_ep0 __attribute__((alias ("ep0")));
+
+// Endpoint 1 is optional. If the application only involves control
+// messages or only slave->host transfers then the endpoint 1
+// support can be disabled.
+//#ifdef CYGPKG_DEVS_USB_MX37_EP1
+
+typedef struct ep1_impl {
+ usbs_rx_endpoint common; //struct usbs_rx_endpoint defined in usbs.h
+ int fetched;
+ cyg_bool using_buf_a;
+} ep1_impl;
+
+static void ep1_start_rx(usbs_rx_endpoint*);
+static void ep1_set_halted(usbs_rx_endpoint*, cyg_bool);
+
+static ep1_impl ep1 = {
+ common: {
+ start_rx_fn: &ep1_start_rx,
+ set_halted_fn: &ep1_set_halted,
+ complete_fn: (void (*)(void*, int)) 0,
+ complete_data: (void*) 0,
+ buffer: (unsigned char*) 0,
+ buffer_size: 0,
+ halted: 0,
+ },
+ fetched: 0,
+ using_buf_a: 0
+};
+
+extern usbs_rx_endpoint usbs_imx_otg_ep1 __attribute__((alias ("ep1")));
+//#endif
+
+// Endpoint 2 is optional. If the application only involves control
+// messages or only host->slave transfers then the endpoint 2 support
+// can be disabled.
+//#ifdef CYGPKG_DEVS_USB_MX37_EP2
+
+typedef struct ep2_impl {
+ usbs_tx_endpoint common; //struct usbs_tx_endpoint defined in usbs.h
+ int transmitted;
+ int pkt_size;
+} ep2_impl;
+
+static void ep2_start_tx(usbs_tx_endpoint*);
+static void ep2_set_halted(usbs_tx_endpoint*, cyg_bool);
+
+static ep2_impl ep2 = {
+ common: {
+ start_tx_fn: &ep2_start_tx,
+ set_halted_fn: &ep2_set_halted,
+ complete_fn: (void (*)(void*, int)) 0,
+ complete_data: (void*) 0,
+ buffer: (const unsigned char*) 0,
+ buffer_size: 0,
+ halted: 0,
+ },
+ transmitted: 0,
+ pkt_size: 0
+};
+
+extern usbs_tx_endpoint usbs_imx_otg_ep2 __attribute__ ((alias ("ep2")));
+//#endif
+
+// ****************************************************************************
+// -----------------------Static Functions Initialization----------------------
+// ****************************************************************************
+static void usbs_handle_get_descriptor(void);
+static void usbs_handle_set_configuration(void);
+static void usbs_handle_get_device_desc(void);
+static void usbs_handle_get_config_desc(void);
+static void usbs_handle_get_string_desc(void);
+static void usbs_handle_get_configuration(void);
+static void usbs_handle_set_address(void);
+
+static void usbs_ep0in_fill_buffer(cyg_uint8 type, cyg_uint32 buffer_addrs);
+static usb_status_t usbs_ep0_send_data(usb_buffer_descriptor_t* bd,cyg_uint8 zlt);
+static usb_status_t usbs_ep0_receive_data(usb_buffer_descriptor_t* bd);
+
+static void usbs_setup_queuehead(struct dqh_t* qhead);
+static void usbs_setup_transdesc(struct dtd_t* td);
+static void usbs_endpoint_stall(cyg_uint8 endpoint , cyg_uint8 direction);
+static void usbs_status_phase(cyg_uint8 trans_type, cyg_uint8 direction);
+
+static void usbs_imx_otg_dev_set_configuration(usb_end_pt_info_t* config_data);
+static void usbs_imx_otg_dev_handle_bus_reset(void);
+static void usbs_imx_otg_dev_handle_port_change(void);
+static void usbs_imx_otg_hardware_init(void);
+
+cyg_uint32 util_alloc_buffer(void);
+void util_free_buffer(cyg_uint32 address);
+void util_set_status_bulk_buffer(cyg_uint32 buffer_addr,int buffer_status);
+// ****************************************************************************
+// -----------------------Static Functions ------------------------------------
+// ****************************************************************************
+/*=============================================================================
+FUNCTION: usbs_setup_queuehead
+DESCRIPTION: This function is used to setup the dQH
+ ------------------------
+ | EP0 IN (64 bytes) |
+ | |
+ ------------------------ dQH1
+ | EP0 OUT (64 bytes) |
+ | |
+ ------------------------ dQH0
+ARGUMENTS PASSED:
+ cyg_uint32 dqh_base - Base Address of the dQH
+ cyg_uint8 zlt - zero lengh packet termination (enable - ZLT_ENABLE; disable - ZLT_DISABLE)
+ cyg_uint16 mps - Max packet length
+ cyg_uint8 ios - interrupt on Setup
+ cyg_uint32 next_link_ptr - Next Link Pointer,
+ cyg_uint8 terminate - terminate - TERMINATE; not terminate - NOT_TERMINATE
+ cyg_uint16 total_bytes - Total Bytes to be transfered in this dQH
+ cyg_uint8 ioc - interrupt on complete, set - IOC_SET, not set - IOC_NOTSET
+ cyg_uint8 status - status
+ cyg_uint32 buffer_ptr0 - Buffer Pointer page 0
+ cyg_uint16 current_offset - current offset
+ cyg_uint32 buffer_ptr1 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr2 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr3 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr4 - Buffer Pointer page 1
+
+RETURN VALUE: None
+IMPORTANT NOTES:None
+=============================================================================*/
+static void
+usbs_setup_queuehead(struct dqh_t* qhead)
+{
+ volatile struct dqh_setup_t* dqh_word = (volatile struct dqh_setup_t*) qhead->dqh_base;
+
+ /*Bit31:30 Mult; Bit29 zlt; Bit26:16 mps; Bit15 ios */
+ dqh_word->dqh_word0 = (((cyg_uint32)(qhead->zlt) << 29)|((cyg_uint32)(qhead->mps) <<16) | ((cyg_uint32)(qhead->ios) <<15));
+
+ /*Current dTD Pointer => for hw use, not modified by DCD software */
+ dqh_word->dqh_word1 = 0x0;
+
+ /*Next dTD Pointer */
+ dqh_word->dqh_word2 = (((qhead->next_link_ptr) & 0xFFFFFFE0) | qhead->terminate);
+
+ /*Bit30:16 total_bytes; Bit15 ioc; Bit11:10 MultO; Bit7:0 status */
+ dqh_word->dqh_word3 = ((((cyg_uint32)(qhead->total_bytes) & 0x7FFF) << 16) | ((cyg_uint32)(qhead->ioc) <<15) | (qhead->status));
+
+ /*Bit31:12 Buffer Pointer (Page 0) */
+ dqh_word->dqh_word4 = ((qhead->buffer_ptr0 & 0xFFFFF000) | (qhead->current_offset & 0xFFF));
+
+ /*Bit31:12 Buffer Pointer (Page 1) */
+ dqh_word->dqh_word5 = (qhead->buffer_ptr1 & 0xFFFFF000);
+
+ /*Bit31:12 Buffer Pointer (Page 2) */
+ dqh_word->dqh_word6 = (qhead->buffer_ptr2 & 0xFFFFF000);
+
+ /*Bit31:12 Buffer Pointer (Page 3) */
+ dqh_word->dqh_word7 = (qhead->buffer_ptr3 & 0xFFFFF000);
+
+ /*Bit31:12 Buffer Pointer (Page 4) */
+ dqh_word->dqh_word8 = (qhead->buffer_ptr4 & 0xFFFFF000);
+
+ /*Reserved */
+ dqh_word->dqh_word9 = 0;
+
+ /*Setup Buffer 0 */
+ dqh_word->dqh_word10 = 0;
+
+ /*Setup Buffer 1 */
+ dqh_word->dqh_word11 = 0;
+}
+/*=============================================================================
+FUNCTION: usbs_setup_transdesc
+DESCRIPTION: This function is used to setup the dTD
+ARGUMENTS PASSED:
+ cyg_uint32 dtd_base - Base Address of the dTD
+ cyg_uint32 next_link_ptr - Next Link Pointer,
+ cyg_uint8 terminate - terminate - TERMINATE; not terminate - NOT_TERMINATE
+ cyg_uint16 total_bytes - Total Bytes to be transfered in this dQH
+ cyg_uint8 ioc - interrupt on complete, set - IOC_SET, not set - IOC_NOTSET
+ cyg_uint8 Status - Status
+ cyg_uint32 buffer_ptr0 - Buffer Pointer page 0
+ cyg_uint16 current_offset - current offset
+ cyg_uint32 buffer_ptr1 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr2 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr3 - Buffer Pointer page 1
+ cyg_uint32 buffer_ptr4 - Buffer Pointer page 1
+RETURN VALUE: None
+IMPORTANT NOTES:None
+==============================================================================*/
+static void
+usbs_setup_transdesc(struct dtd_t* td)
+{
+ volatile struct dtd_setup_t* dtd_word = (volatile struct dtd_setup_t *) td->dtd_base;
+
+ /* Bit31:5 Next Link Pointer ; Bit0 terminate */
+ dtd_word->dtd_word0 = ((td->next_link_ptr & 0xFFFFFFE0) | td->terminate);
+
+ /* Bit30:16 total_bytes, Bit15 ioc, Bit7:0 status */
+ dtd_word->dtd_word1 = ((((cyg_uint32)td->total_bytes & 0x7FFF) << 16)| ((cyg_uint32)td->ioc <<15) | (td->status));
+
+ /* Bit31:12 Buffer Pointer Page 0 ; Bit11:0 Current Offset */
+ dtd_word->dtd_word2 = ((td->buffer_ptr0 & 0xFFFFF000) | (td->current_offset & 0xFFF));
+
+ /* Bit31:12 Buffer Pointer Page 1 ; Bit10:0 Frame Number */
+ dtd_word->dtd_word3 = (td->buffer_ptr1 & 0xFFFFF000);
+
+ /* Bit31:12 Buffer Pointer Page 2 ; */
+ dtd_word->dtd_word4 = (td->buffer_ptr2 & 0xFFFFF000);
+
+ /* Bit31:12 Buffer Pointer Page 3 ; */
+ dtd_word->dtd_word5 = (td->buffer_ptr3 & 0xFFFFF000);
+
+ /* Bit31:12 Buffer Pointer Page 4 ; */
+ dtd_word->dtd_word6 = (td->buffer_ptr4 & 0xFFFFF000);
+
+}
+
+/*==================================================================================================
+FUNCTION: util_alloc_buffer
+DESCRIPTION: This utility function allocate the free buffer available
+ARGUMENTS PASSED: None
+RETURN VALUE: cyg_uint32 address : address of the allocated buffer
+IMPORTANT NOTES: If Buffer1 is FREE then return Buffer1 and mark this as Busy else check for buffer2 . If
+ none of the buffer is free then return NULL.
+==================================================================================================*/
+cyg_uint32 util_alloc_buffer(void)
+{
+ cyg_uint32 buffer_addr = (cyg_uint32)NULL; //force type conversion for multiple NULL definitions
+
+ /* Check if buffer1 is free then mark it busy and return address */
+ if (g_bulkbuffer_map.buffer1_status == BUFFER_FREE )
+ {
+ buffer_addr = g_bulkbuffer_map.buffer1_address;
+ g_bulkbuffer_map.buffer1_status = BUFFER_IN_USE;
+ }
+ /* Check if buffer2 is free then mark it busy and return address */
+ else if(g_bulkbuffer_map.buffer2_status == BUFFER_FREE)
+ {
+ buffer_addr = g_bulkbuffer_map.buffer2_address;
+ g_bulkbuffer_map.buffer2_status = BUFFER_IN_USE;
+ }
+
+ return buffer_addr ;
+}
+/*==================================================================================================
+FUNCTION: util_free_buffer
+DESCRIPTION: This function put the buffer in free state.
+ARGUMENTS PASSED: cyg_uint32 address : address of the buffer .
+RETURN VALUE: None
+IMPORTANT NOTES: None
+
+==================================================================================================*/
+void util_free_buffer(cyg_uint32 address)
+{
+ if( address == g_bulkbuffer_map.buffer1_address )
+ {
+ g_bulkbuffer_map.buffer1_status = BUFFER_FREE;
+ }
+ else if ( address == g_bulkbuffer_map.buffer2_address )
+ {
+ g_bulkbuffer_map.buffer2_status = BUFFER_FREE;
+ }
+}
+/*==================================================================================================
+FUNCTION: util_set_bulk_buffer_stat
+DESCRIPTION: This function change the bulk buffer status
+ARGUMENTS PASSED: cyg_uint32 buffer_addr: buffer base address
+ int buffer_status: new buffer_status
+enum {
+ BUFFER_FREED,
+ BUFFER_RELEASED,
+ BUFFER_ALLOCATED
+};
+RETURN VALUE: None
+IMPORTANT NOTES: None
+
+==================================================================================================*/
+void util_set_status_bulk_buffer(cyg_uint32 buffer_addr,int buffer_status)
+{
+ if( buffer_addr == (cyg_uint32)g_bulkbuffer_a.buffer)
+ {
+ g_bulkbuffer_a.stat = buffer_status;
+ }
+ else if ( buffer_addr == (cyg_uint32)g_bulkbuffer_b.buffer )
+ {
+ g_bulkbuffer_b.stat = buffer_status;
+ }
+ else
+ return;
+}
+/*=============================================================================
+FUNCTION: usbs_endpoint_stall
+DESCRIPTION: This function Send/Receive the STALL HANDSHAKE to USB Host
+ARGUMENTS PASSED:
+ cyg_uint8 endpoint - Endpoint Number .
+ cyg_uint8 direction - IN/OUT : direction of EndPoint.
+RETURN VALUE: None
+IMPORTANT NOTES:None
+==============================================================================*/
+static void
+usbs_endpoint_stall(cyg_uint8 endpoint , cyg_uint8 direction)
+{
+ if( direction == OUT )
+ {
+ usbs_imx_otg_base->endptctrl[endpoint]|= STALL_RX;
+ }
+ else
+ {
+ usbs_imx_otg_base->endptctrl[endpoint] |= STALL_TX;
+ }
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - EP%d - %d stalled\n",endpoint,direction);
+}
+
+static void
+usbs_endpoint_unstall(cyg_uint8 endpoint , cyg_uint8 direction)
+{
+ if( direction == OUT )
+ {
+ usbs_imx_otg_base->endptctrl[endpoint]&= ~STALL_RX;
+ }
+ else
+ {
+ usbs_imx_otg_base->endptctrl[endpoint]&= ~STALL_TX;
+ }
+}
+
+/*=============================================================================
+FUNCTION: usbs_status_phase
+DESCRIPTION: This function Send/Receive the Status to/from Host.
+ARGUMENTS PASSED: cyg_uint8 direction OUT Receive Status Command From Host
+ IN Send Status Command to Host
+RETURN VALUE: None
+IMPORTANT NOTES:
+===============================================================================*/
+static void
+usbs_status_phase(cyg_uint8 trans_type, cyg_uint8 direction)
+{
+ usb_buffer_descriptor_t bd ;
+
+ /* Buffer pointer is not used for EP0 */
+ bd.buffer = (cyg_uint32 *) 0xFFFFFFFF;
+ bd.size = 0x0;
+
+ if(trans_type==CONTROL)
+ {
+ switch ( direction )
+ {
+ case OUT :
+ /* Receive ZERO length Length Data */
+ usbs_ep0_receive_data(&bd);
+ break;
+ case IN :
+ /* Send ZERO length Length Data */
+ usbs_ep0_send_data(&bd,0);
+ break;
+ }
+ }
+ else if(trans_type==BULK)/*TODO*/
+ {
+ switch ( direction )
+ {
+ case OUT :
+ /* Send ZERO length Length Data */
+ //usbs_ep2_send_data(EP2,&bd,FALSE);
+ break;
+ case IN :
+ /* Receive ZERO length Length Data */
+ //usbs_ep1_receive_data(EP1,&bd);
+ break;
+ }
+ }
+
+}
+// ---------------------------------------------------------------------------
+// The following static functions are for USB device enumeration processing
+/*============================================================================
+FUNCTION: usbs_handle_get_descriptor
+DESCRIPTION: This function Handle the GET DESCRIPTOR request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+============================================================================*/
+static void
+usbs_handle_get_descriptor()
+{
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get descriptor handler\n");
+ switch (g_usb_setup_data[WVALUE_HIGHBYTE])
+ {
+ case DEVICE_DESC: /* device descriptor*/
+ usbs_handle_get_device_desc(); //Device will send the MPS to host
+ break;
+ case CONF_DESC: /* configuration descriptor*/
+ usbs_handle_get_config_desc(); //Device will send the whole device descriptor to host
+ break;
+ case STRING_DESC: /* string descriptor*/
+ usbs_handle_get_string_desc();
+ break;
+ case INTERFACE_DESC:
+ case ENDPOINT_DESC:
+ case DEVICE_QUALIFIER:
+ case OTHER_SPEED_CONF_DESC:
+ default: /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ break;
+ }
+
+
+}
+/*=============================================================================
+FUNCTION: usbs_handle_get_device_desc
+DESCRIPTION: This function Handle the GET DEVICE DESCRIPTOR request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+==============================================================================*/
+static void
+usbs_handle_get_device_desc(void)
+{
+ usb_buffer_descriptor_t bd ;
+ cyg_uint32 buffer_addrs;
+ cyg_uint16 desc_length = 0x0;
+ cyg_uint8 zlt = 0;//0 means false
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get device descriptor\n");
+
+ /* get the buffer address for data transfer over EP0 */
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs; //256bytes before the two Bulk buffers
+
+ /* Fill the buffer with the descriptor data */
+ usbs_ep0in_fill_buffer(FILL_DEVICE_DESC,buffer_addrs);
+
+ /* Get the length of descriptor requested */
+ desc_length = g_usb_setup_data[WLENGTH_LOWBYTE];
+ desc_length |= ( g_usb_setup_data[WLENGTH_HIGHBYTE] <<0x8);
+
+ /* If requested length of descriptor is lesser than actual length of descriptor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if( g_usb_dev_state == USB_DEV_DEFAULT_STATE )
+ {
+ bd.size = MPS_8;
+ }
+ else
+ {
+ bd.size = USB_DEV_DESC_LEN;
+ }
+
+ /* Send descriptor - Data Phase*/
+ usbs_ep0_send_data(&bd,zlt); //zlt is false=>not zero length packet
+ //send dev descriptor to host.
+
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT); //Get Zero-length data packet from Host, Device sends status: ACK(success), NAK(busy), or STALL(failed)
+
+
+}
+/*=============================================================================
+FUNCTION: usbs_handle_get_config_desc
+DESCRIPTION: This function Handle the GET CONFIGURATION DESCRIPTOR request
+ARGUMENTS PASSED:
+RETURN VALUE: None
+IMPORTANT NOTES:None
+=============================================================================*/
+static void
+usbs_handle_get_config_desc(void)
+{
+ usb_buffer_descriptor_t bd;
+ cyg_uint32 buffer_addrs;
+ cyg_uint16 desc_length_req = 0x0;
+ cyg_uint16 desc_length = 0x0;
+ int zlt = 0;
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get config descriptor\n");
+ /* get the buffer address for data transfer over EP0 */
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs;
+
+ /* Fill the buffer with the descriptor data */
+ usbs_ep0in_fill_buffer(FILL_CONF_DESC, buffer_addrs);
+
+ /* total length of descriptor */
+ desc_length = ((g_usb_desc.config_desc->usb_config_desc.total_length_lo) \
+ | ( g_usb_desc.config_desc->usb_config_desc.total_length_hi << 0x8 ));
+ /* Get the length of descriptor requested */
+ desc_length_req = g_usb_setup_data[WLENGTH_LOWBYTE];
+ desc_length_req |= ( g_usb_setup_data[WLENGTH_HIGHBYTE] <<0x8);
+
+
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= desc_length)
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = desc_length;
+
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ usbs_ep0_send_data(&bd,zlt);
+
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+
+}
+/*=============================================================================
+FUNCTION: usbs_handle_get_string_desc
+DESCRIPTION: This function Handle the GET STRING DESCRIPTOR request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+==============================================================================*/
+static void
+usbs_handle_get_string_desc(void)
+{
+ usb_buffer_descriptor_t bd;
+ cyg_uint32 buffer_addrs;
+ cyg_uint16 desc_length_req = 0x0;
+ cyg_uint16 length_of_desc = 0x0;
+ int zlt = 0;
+
+
+ /* Get Buufer to fill the data to be received/transmitted. */
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs;
+
+ /* Get the length of descriptor requested */
+ desc_length_req = g_usb_setup_data[WLENGTH_LOWBYTE];
+ desc_length_req |= ( g_usb_setup_data[WLENGTH_HIGHBYTE] <<0x8);
+
+ switch (g_usb_setup_data[WVALUE_LOWBYTE])
+ {
+ case STR_DES0:
+ usbs_ep0in_fill_buffer(FILL_STR_DES0,buffer_addrs);
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= g_usb_desc.str_desc0->length )
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = g_usb_desc.str_desc0->length;
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ /* Data Phase -- IN */
+ usbs_ep0_send_data(&bd,zlt);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get string descriptor 0\n");
+ break;
+
+ case STR_DES1: /*iManufacturer */
+ usbs_ep0in_fill_buffer(FILL_STR_DES1,buffer_addrs);
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= g_usb_desc.str_desc1->length )
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = g_usb_desc.str_desc1->length;
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ /* Data Phase -- IN */
+ usbs_ep0_send_data(&bd,zlt);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get string descriptor 1\n");
+ break;
+
+ case STR_DES2: /*iProduct */
+ usbs_ep0in_fill_buffer(FILL_STR_DES2,buffer_addrs );
+ length_of_desc = g_usb_desc.str_desc2->length;
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= length_of_desc )
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = length_of_desc;
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ /* Data Phase -- IN */
+ usbs_ep0_send_data(&bd,zlt);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get string descriptor 2\n");
+ break;
+
+ case STR_DES3:
+ /* send zero length data */
+ usbs_status_phase(CONTROL,IN);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ break;
+
+ case STR_DES5: /*iSerialNumber */
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ usbs_ep0in_fill_buffer(FILL_SN_DESC,buffer_addrs );
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= g_usb_desc.sn_desc->length )
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = g_usb_desc.sn_desc->length;
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ /* Data Phase -- IN */
+ usbs_ep0_send_data(&bd,zlt);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get string descriptor - SN\n");
+ break;
+ #endif
+ case STR_DES4: /*iSerialNumber */
+ usbs_ep0in_fill_buffer(FILL_STR_DES3,buffer_addrs );
+ /* If requested length of descriptor is lesser than actual length of descriotor then send
+ * requested length of descroptor only else send the actual length of descriptor*/
+ if(desc_length_req <= g_usb_desc.str_desc3->length )
+ {
+ bd.size = desc_length_req;
+ }
+ else
+ {
+ bd.size = g_usb_desc.str_desc3->length;
+ if ( bd.size > MPS_64)
+ {
+ zlt = 1;
+ }
+ }
+ /* Data Phase -- IN */
+ usbs_ep0_send_data(&bd,zlt);
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get string descriptor 3\n");
+ break;
+ default:
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ //USBDBGMSG("+USBDBGMSG:EP0 IN stalled at get string desc\n");
+ break;
+ }
+
+
+}
+
+/*=============================================================================
+FUNCTION: usbs_handle_set_address
+DESCRIPTION: This function Handle the SET ADDRESS Request from USB Host
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES:
+==============================================================================*/
+static void
+usbs_handle_set_address(void)
+{
+ cyg_uint16 device_addrs;
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - set address handler\n");
+ /* Get the Device Address to be SET from the Setup Data */
+ device_addrs = g_usb_setup_data[WVALUE_LOWBYTE] + (g_usb_setup_data[WVALUE_HIGHBYTE]<<8);
+
+ if ((g_usb_setup_data[WINDEX_LOWBYTE] == 0) &&
+ (g_usb_setup_data[WINDEX_HIGHBYTE] == 0) &&
+ (g_usb_setup_data[WLENGTH_LOWBYTE] == 0) &&
+ (g_usb_setup_data[WLENGTH_HIGHBYTE] == 0) &&
+ (device_addrs <= USB_MAX_DEVICE_ADDR))
+ {
+ switch(g_usb_dev_state)
+ {
+ case USB_DEV_DEFAULT_STATE :
+ /* Send Ack to Host */
+ usbs_status_phase(CONTROL,IN);
+ if (device_addrs != USB_DEFAULT_ADDR)
+ {
+ /* Set the Device Address */
+ USBS_DEVICE_SET_ADDRESS(device_addrs);
+ /* Change state to ADDRESSED STATE */
+ g_usb_dev_state = USB_DEV_ADDRESSED_STATE;
+ }
+ break;
+
+ case USB_DEV_ADDRESSED_STATE :
+ /* Send Ack to Host */
+ usbs_status_phase(CONTROL,IN);
+ if ( device_addrs == USB_DEFAULT_ADDR )
+ {
+ /* Set the Device Address */
+ USBS_DEVICE_SET_ADDRESS(USB_DEFAULT_ADDR);
+ /* Change state to ADDRESSED STATE */
+ g_usb_dev_state = USB_DEV_DEFAULT_STATE;
+ }
+ else
+ {
+ /* Set the Device Address */
+ USBS_DEVICE_SET_ADDRESS(device_addrs);
+ }
+ break;
+
+ case USB_DEV_CONFIGURED_STATE :
+ if ( device_addrs == USB_DEFAULT_ADDR)
+ {
+ /* Send Ack to Host */
+ usbs_status_phase(CONTROL,IN);
+ /* Set the Device Address */
+ USBS_DEVICE_SET_ADDRESS(device_addrs);
+ /* Change state to ADDRESSED STATE */
+ g_usb_dev_state = USB_DEV_DEFAULT_STATE;
+ }
+ else
+ {
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ }
+ default :
+ break;
+ }
+ }
+ else
+ {
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ }
+
+
+}
+/*=============================================================================
+FUNCTION: usbs_handle_get_configuration
+DESCRIPTION: This function Handle the GET CONFIGURATION request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+=============================================================================*/
+static void
+usbs_handle_get_configuration(void)
+{
+ usb_buffer_descriptor_t bd;
+ cyg_uint32 buffer_addrs;
+ cyg_uint32* buffer_ptr;
+
+ if((g_usb_setup_data[WINDEX_LOWBYTE] == 0) &&
+ (g_usb_setup_data[WINDEX_HIGHBYTE] == 0) &&
+ (g_usb_setup_data[WVALUE_LOWBYTE] == 0) &&
+ (g_usb_setup_data[WVALUE_HIGHBYTE] == 0) &&
+ (g_usb_setup_data[WLENGTH_LOWBYTE] == LEN_OF_CONFIG_VALUE) &&
+ (g_usb_setup_data[WLENGTH_HIGHBYTE] == 0))
+ {
+ switch(g_usb_dev_state)
+ {
+ case USB_DEV_DEFAULT_STATE :
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ break;
+ case USB_DEV_ADDRESSED_STATE:
+ /* If the Device is in Address state then return 0x0 : See USB2.0 Spec */
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs;
+ buffer_ptr = (cyg_uint32 *)buffer_addrs;
+ *buffer_ptr = 0x0;
+
+ bd.buffer = buffer_ptr;
+ bd.size=LEN_OF_CONFIG_VALUE;
+
+ usbs_ep0_send_data(&bd,0);
+
+ /* Receive Ack from Host*/
+ usbs_status_phase(CONTROL,OUT);
+ break;
+
+ case USB_DEV_CONFIGURED_STATE:
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs;
+ buffer_ptr = (cyg_uint32 *)buffer_addrs;
+
+ *buffer_ptr = (cyg_uint32 )g_usb_desc.config_desc->usb_config_desc.configuration_id;
+
+ bd.buffer = buffer_ptr;
+ bd.size=LEN_OF_CONFIG_VALUE;
+
+ usbs_ep0_send_data(&bd,0);
+
+ /* Receive Ack from Host*/
+ usbs_status_phase(CONTROL,OUT);
+ break;
+
+ default:
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ }
+
+ }
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - get config handler\n");
+}
+/*=============================================================================
+FUNCTION: usbs_handle_set_configuration
+DESCRIPTION: This function Handle the SET CONFIGURATION request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+=============================================================================*/
+static void
+usbs_handle_set_configuration(void)
+{
+ usb_end_pt_info_t config_data ;
+ cyg_uint8 i;
+
+ switch (g_usb_dev_state)
+ {
+ case USB_DEV_ADDRESSED_STATE :
+ if (g_usb_setup_data[WVALUE_LOWBYTE] == USB_DEV_VALUE_OF_UNCONFIG)
+ {
+ /* Send Ack to Host*/
+ usbs_status_phase(CONTROL,IN);
+ }
+ /* Check if the configuration value received request is same as in Config descriptor */
+ else if(g_usb_setup_data[WVALUE_LOWBYTE] == g_usb_desc.config_desc->usb_config_desc.configuration_id)
+ {
+ /* Configure endpoints */
+ for ( i = 0 ; i< g_number_of_endpoints ; i++)
+ {
+ config_data.end_pt_no = g_end_pt_info[i].end_pt_no;
+ config_data.direction = g_end_pt_info[i].direction;
+ config_data.transfer_type = g_end_pt_info[i].transfer_type;
+ config_data.max_pkt_size = g_end_pt_info[i].max_pkt_size;
+
+ usbs_imx_otg_dev_set_configuration(&config_data);
+ }
+
+ /* Send Ack to Host*/
+ usbs_status_phase(CONTROL,IN);
+
+ g_usb_dev_state = USB_DEV_CONFIGURED_STATE ;
+ }
+ else
+ {
+ /* Invalid configuration value. Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ //USBDBGMSG("+USBDBGMSG:EP0 IN stalled at set conf in addr state\n");
+ }
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - set conf@ADDRESSED_STATE\n");
+ break;
+ case USB_DEV_CONFIGURED_STATE :
+ if(g_usb_setup_data[WVALUE_LOWBYTE] == USB_DEV_CONFIG_DESC_CONFIG_VALUE)
+ {
+ /* Send Ack to Host*/
+ usbs_status_phase(CONTROL,IN);
+ }
+ else if (g_usb_setup_data[WVALUE_LOWBYTE] == USB_DEV_VALUE_OF_UNCONFIG)
+ {
+ /* Send Ack to Host*/
+ usbs_status_phase(CONTROL,IN);
+
+ /* Change USB State to Addressed State */
+ g_usb_dev_state = USB_DEV_ADDRESSED_STATE;
+ }
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - set conf@CONFIGURED_STATE\n");
+ break;
+ default :
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - set conf@incorrect state\n");
+ break;
+ }
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: enum - set config handler\n");
+}
+/*=============================================================================
+FUNCTION: usbs_handle_msc_get_maxlun
+DESCRIPTION: This function Handle the GET MAX LUN Mass Storage class
+ specific request
+ARGUMENTS PASSED: None
+RETURN VALUE: None
+IMPORTANT NOTES: None
+=============================================================================*/
+static void
+usbs_handle_msc_get_maxlun(void)
+{
+ usb_buffer_descriptor_t bd ;
+ cyg_uint32 buffer_addrs;
+ cyg_uint16 desc_length = 0x0;
+ cyg_uint8 zlt = 0;//0 means false
+ cyg_uint8 Max_Lun=0;
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: MASS - Get MAX LUN\n");
+
+ /* get the buffer address for data transfer over EP0 */
+ buffer_addrs = g_bulkbuffer_map.ep0_buffer_addrs; //256bytes before the two Bulk buffers
+
+ /* Get the length of descriptor requested */
+ desc_length = g_usb_setup_data[WLENGTH_LOWBYTE];
+ desc_length |= ( g_usb_setup_data[WLENGTH_HIGHBYTE] <<0x8);
+
+ /* If requested length of descriptor is zero*/
+ if(desc_length==0)
+ {
+ /* Fill the buffer with the descriptor data */
+ *(cyg_uint8 *)buffer_addrs = 0;//Max_Lun;
+ bd.size = 0;
+ }
+ else
+ {
+ /* Fill the buffer with the descriptor data */
+ *(cyg_uint8 *)buffer_addrs = Max_Lun;
+ bd.size = desc_length;
+ }
+
+ /* Send descriptor - Data Phase*/
+ usbs_ep0_send_data(&bd,zlt); //zlt is false=>not zero length packet
+ //send dev descriptor to host.
+
+ /* Status Phase -- OUT */
+ usbs_status_phase(CONTROL,OUT); //Get Zero-length data packet from Host, Device sends status: ACK(success), NAK(busy), or STALL(failed)
+
+
+}
+/*=============================================================================
+FUNCTION: usbs_ep0in_fill_buffer
+DESCRIPTION: This function is used to fill the corresponding
+ response for the data phase of SETUP Transfer
+ARGUMENTS PASSED:
+ cyg_uint8 type: type of descriptor
+ cyg_uint32 buffer_addrs - buffer pointer to be filled
+RETURN VALUE: None
+IMPORTANT NOTES:None
+=============================================================================*/
+static void
+usbs_ep0in_fill_buffer(cyg_uint8 type, cyg_uint32 buffer_addrs)
+{
+ const cyg_uint8 *data=0;
+ cyg_uint32 *buffer_page = (cyg_uint32*)buffer_addrs;
+ int k = 0;
+ //USBDBGMSG("+USBDBGMSG: enum - copy descriptor to buffer\n");
+ switch (type)
+ {
+ case FILL_DEVICE_DESC: /*5*32 bit */
+ data = (cyg_uint8 *)g_usb_desc.device_desc;
+ break;
+ case FILL_CONF_DESC: /*8*32 bit */
+ data = (cyg_uint8 *)g_usb_desc.config_desc;
+ break;
+ case FILL_STR_DES0: /*1*32 bit */
+ data = (cyg_uint8 *)g_usb_desc.str_desc0;
+ break;
+ case FILL_STR_DES1: /*7*32 bit */
+ data =(cyg_uint8 *)g_usb_desc.str_desc1;
+ break;
+ case FILL_STR_DES2: /*7*32 bit */
+ data = (cyg_uint8 *)g_usb_desc.str_desc2;
+ break;
+ case FILL_STR_DES3: /*6*32 bit */
+ data = (cyg_uint8 *)g_usb_desc.str_desc3;
+ break;
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ case FILL_SN_DESC:
+ data = (cyg_uint8 *)g_usb_desc.sn_desc;
+ break;
+ #endif
+ }
+
+ for (k=0; k<(MPS_64/sizeof(cyg_uint32)); k++)
+ {
+ *buffer_page = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
+ //USBDBGMSG("+USBDBGMSG: desc[k] = 0x%x\n",(*buffer_page));
+ buffer_page++;
+ data += 4;
+
+ }
+
+
+}
+
+/*=============================================================================
+FUNCTION: usbs_ep0_init_dqh
+DESCRIPTION: This function is used to initialize the queue header of EP0
+ARGUMENTS PASSED: NONE
+RETURN VALUE: NONE
+IMPORTANT NOTES: called by usbs_imx_otg_dev_ep0_init(),usbs_imx_otg_dev_handle_bus_reset()
+=============================================================================*/
+static void
+usbs_ep0_init_dqh(void)
+{
+ struct dqh_t qhead;
+ cyg_uint32 total_bytes;
+ volatile cyg_uint32 * ep_q_hdr_base;
+ cyg_int8 i;
+
+ //clear queue header
+ ep_q_hdr_base = ((volatile cyg_uint32 *)g_bulkbuffer_map.ep_dqh_base_addrs);
+ /* Clear the dQH Memory */
+ for ( i = 0; i < (SIZE_OF_QHD*g_max_ep_supported*2)/sizeof(cyg_uint32) ; i++)
+ {
+ *ep_q_hdr_base++ = 0;
+ }
+
+ /******************************************************************************
+ / =================
+ / dQH0 for EP0OUT
+ / =================
+ / Initialize device queue heads in system memory
+ / 8 bytes for the 1st setup packet */
+
+ total_bytes = 0x8;
+ qhead.dqh_base = USBS_EP_GET_dQH(EP0,OUT);
+ qhead.zlt = ZLT_DISABLE;
+ qhead.mps = MPS_64;
+ qhead.ios = IOS_SET;
+ qhead.next_link_ptr = USBS_EP_GET_dTD(EP0,OUT);
+ qhead.terminate = NOT_TERMINATE;
+ qhead.total_bytes = total_bytes;
+ qhead.ioc = IOC_SET;
+ qhead.status = NO_STATUS;
+ qhead.buffer_ptr0 = 0;
+ qhead.current_offset= 0;
+ qhead.buffer_ptr1 = 0;
+ qhead.buffer_ptr2 = 0;
+ qhead.buffer_ptr3 = 0;
+ qhead.buffer_ptr4 = 0;
+ /* Set Device Queue Head */
+ usbs_setup_queuehead(&qhead);
+
+ /* ==================
+ END of dQH0 setup
+ ====================*/
+ /*=================
+ dQH1 for EP0IN
+ ================= */
+
+ total_bytes = 0x8;
+ qhead.dqh_base = USBS_EP_GET_dQH(EP0,IN);
+ qhead.zlt = ZLT_DISABLE;
+ qhead.mps = MPS_64;
+ qhead.ios = IOS_SET;
+ qhead.next_link_ptr = USBS_EP_GET_dTD(EP0,IN);
+ qhead.terminate = TERMINATE;
+ qhead.total_bytes = total_bytes;
+ qhead.ioc = IOC_SET;
+ qhead.status = NO_STATUS;
+ qhead.buffer_ptr0 = g_bulkbuffer_map.ep0_buffer_addrs;
+ qhead.current_offset= (g_bulkbuffer_map.ep0_buffer_addrs & 0xFFF);
+ qhead.buffer_ptr1 = 0;
+ qhead.buffer_ptr2 = 0;
+ qhead.buffer_ptr3 = 0;
+ qhead.buffer_ptr4 = 0;
+
+ /* Set Device Queue Head */
+ usbs_setup_queuehead(&qhead);
+
+ /* ==================
+ / END of dQH1 setup
+ / ================*/
+}
+/*=============================================================================
+FUNCTION: usbs_ep0_send_data
+DESCRIPTION: This function Send Data to host through EP0-IN Pipe.
+ARGUMENTS PASSED:
+ usb_buffer_descriptor_t *bd : This is the pointer to the buffer descriptor.
+ cyg_uint8 zlt : Flag to decide if Zero Length Packet to be sent
+RETURN VALUE:
+ USB_SUCCESS - The buffer was successfully processed by the USB device and
+ data sent to the Host.
+ USB_FAILURE - Some failure occurred in transmitting the data.
+IMPORTANT NOTES: None
+=============================================================================*/
+static usb_status_t
+usbs_ep0_send_data(usb_buffer_descriptor_t* bd,cyg_uint8 zlt)
+{
+ struct dtd_t td;
+ cyg_uint32 total_bytes ;
+ cyg_uint32 dtd_address,dqh_address;
+
+ usb_status_t status = USB_FAILURE;
+
+ /* Get Device Transfer Descriptor of the requested endpoint */
+ dtd_address = USBS_EP_GET_dTD(EP0,IN);
+
+ /* Get Device Queue head of the requested endpoint */
+ dqh_address = USBS_EP_GET_dQH(EP0,IN);
+
+ /* Get Total Bytes to Be recieved */
+ total_bytes = bd->size;
+
+ /* Setup Transfer Descriptor for EP0 IN*/
+ td.dtd_base = dtd_address;
+ td.next_link_ptr = 0;
+ td.terminate = TERMINATE;
+ td.total_bytes = total_bytes;
+ td.ioc = IOC_SET;
+ td.status = ACTIVE;
+ td.buffer_ptr0 = g_bulkbuffer_map.ep0_buffer_addrs;
+ td.current_offset = (g_bulkbuffer_map.ep0_buffer_addrs & 0xFFF);
+ td.buffer_ptr1 = 0;
+ td.buffer_ptr2 = 0;
+ td.buffer_ptr3 = 0;
+ td.buffer_ptr4 = 0;
+
+ /* Set the transfer descriptor */
+ usbs_setup_transdesc(&td);
+
+ /* Enable ZLT when data size is in multiple of Maximum Packet Size */
+ if(zlt)
+ {
+ /* set ZLT enable */
+ (*(volatile cyg_uint32*)(dqh_address)) &= ~0x20000000;
+ }
+
+ /* 1. write dQH next ptr and dQH terminate bit to 0 */
+ *(volatile cyg_uint32*)(dqh_address+0x8)= (dtd_address);
+
+ /* 2. clear active & halt bit in dQH */
+ *(volatile cyg_uint32*)(dqh_address+0xC) &= ~0xFF;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME */
+ usbs_imx_otg_base->endptprime |= BIT16;
+
+ /* wait for complete set and clear */
+ while (!(usbs_imx_otg_base->endptcomplete & EPIN_COMPLETE));
+
+ usbs_imx_otg_base->endptcomplete = EPIN_COMPLETE;
+
+ status = USB_SUCCESS;
+
+ return status;
+}
+/*=============================================================================
+FUNCTION: usbs_ep0_recevie_data
+DESCRIPTION: This function Handle the Status Token (IN/OUT) from USB Host
+ARGUMENTS PASSED:
+ usb_buffer_descriptor_t *bd : This is the pointer to the buffer descriptor.
+RETURN VALUE:
+ USB_SUCCESS - : The buffer was successfully processed by the USB device and
+ data is received from the host.
+ USB_FAILURE - : Some failure occurred in receiving the data.
+ USB_INVALID - : If the endpoint is invalid.
+IMPORTANT NOTES:None
+=============================================================================*/
+static usb_status_t usbs_ep0_receive_data(usb_buffer_descriptor_t* bd)
+{
+ struct dtd_t td;
+ usb_status_t status = USB_FAILURE;
+ cyg_uint32 total_bytes;
+ cyg_uint32 dtd_address;
+ cyg_uint32 dqh_address;
+
+ /* Get Device Device Queue Head of the requested endpoint */
+ dqh_address = USBS_EP_GET_dQH(EP0, OUT);
+
+ /* Get Device Transfer Descriptor of the requested endpoint */
+ dtd_address = USBS_EP_GET_dTD(EP0, OUT);
+
+ /* Get the total bytes to be received */
+ total_bytes = bd->size;
+
+ td.dtd_base = dtd_address;
+ td.next_link_ptr = dtd_address + 0x20;
+ td.terminate = TERMINATE;
+ td.total_bytes = total_bytes;
+ td.ioc = IOC_SET;
+ td.status = ACTIVE;
+ td.buffer_ptr0 = g_bulkbuffer_map.ep0_buffer_addrs;
+ td.current_offset = (g_bulkbuffer_map.ep0_buffer_addrs & 0xFFF);
+ td.buffer_ptr1 = 0;
+ td.buffer_ptr2 = 0;
+ td.buffer_ptr3 = 0;
+ td.buffer_ptr4 = 0;
+
+ /* Set the Transfer Descriptor */
+ usbs_setup_transdesc(&td);
+
+ /* 1. write dQH next ptr and dQH terminate bit to 0 */
+ *(volatile cyg_uint32*)(dqh_address+0x8)= dtd_address;
+
+ /* 2. clear active & halt bit in dQH */
+ *(volatile cyg_uint32*)(dqh_address+0xC) &= ~0xFF;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME */
+ usbs_imx_otg_base->endptprime |= ( EPOUT_PRIME << EP0 );
+
+ /* 4. Wait for the Complete Status */
+ while (!((usbs_imx_otg_base->endptprime) & ( EPOUT_COMPLETE << EP0)));
+
+ /*clear the complete status */
+ usbs_imx_otg_base->endptprime = (EPOUT_COMPLETE << EP0);
+
+ status = USB_SUCCESS;
+
+ return status;
+}
+// ****************************************************************************
+// -----------------------Endpoint 0 Functions---------------------------------
+// ****************************************************************************
+/*=============================================================================
+// This is where all the hard work happens. It is a very large routine
+// for a DSR, but in practice nearly all of it is nested if's and very
+// little code actually gets executed. Note that there may be
+// invocations of callback functions and the driver has no control
+// over how much time those will take, but those callbacks should be
+// simple.
+// so far, ep0 DSR works only during enumeration here.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_ep0_dsr(void)
+{
+ usb_buffer_descriptor_t bd ;
+ usb_status_t status = USB_FAILURE;
+ volatile struct dqh_setup_t * dqh_word ;
+ cyg_uint32 dqh_address;
+ cyg_uint32 temp;
+
+ //USBDBGMSG("+USBDBGMSG: enter ep0 dsr.\n");
+ /* 1. Receive Setup Data*/
+ bd.buffer = (cyg_uint32 *)g_usb_setup_data;
+ bd.size = 0;
+
+ /* Get the Device Queue Head Address for EP0 OUT */
+ dqh_address = USBS_EP_GET_dQH(EP0,OUT);
+ dqh_word = (volatile struct dqh_setup_t*)dqh_address;
+
+ /* write '1' to clear corresponding bit in ENDPTSETUPSTAT */
+ temp = usbs_imx_otg_base->endptsetupstat;
+ usbs_imx_otg_base->endptsetupstat = temp;
+
+// if(usbs_imx_otg_base->endptsetupstat & BIT0)
+// usbs_imx_otg_base->endptsetupstat = BIT0;
+
+ do{
+ /* write '1' to Setup Tripwire (SUTW) in USBCMD register */
+ usbs_imx_otg_base->usbcmd |= BIT13;
+
+ /* Copy the SetupBuffer into local software byte array */
+ temp = (dqh_word->dqh_word10);
+
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )(temp & 0x000000FF);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0x0000FF00)>>8);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0x00FF0000)>>16);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0xFF000000)>>24);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+
+ temp = (dqh_word->dqh_word11);
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )(temp & 0x000000FF);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0x0000FF00)>>8);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0x00FF0000)>>16);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ *((cyg_uint8 *)(bd.buffer)) = (cyg_uint8 )((temp & 0xFF000000)>>24);
+ (bd.buffer) =(cyg_uint8 *)(bd.buffer) + 1;
+ }while (!(usbs_imx_otg_base->usbcmd & BIT13));
+
+ /* Write '0' to clear SUTW in USBCMD register */
+ usbs_imx_otg_base->usbcmd &= ~BIT13;
+ status = USB_SUCCESS;
+
+ #if 0
+ USBDBGMSG("+USBDBGMSG: setup packet:(LSB)");
+ for(temp=0;temp<8;temp++)
+ {
+ USBDBGMSG("%02X",g_usb_setup_data[temp]);
+ }
+ USBDBGMSG("(MSB)\n");
+ #endif
+
+ /* 2. Process Setup Data*/
+ /* switch construct to handle different request*/
+ /* Parser the Setup Request Type */
+ switch (g_usb_setup_data[BREQUEST])
+ {
+ case USB_GET_DESCRIPTOR:
+ /* Handle the GET DESCRIPTOR Request */
+ usbs_handle_get_descriptor();
+ break;
+
+ case USB_SET_ADDRESS:
+ /* Handle the SET ADDRESS Request */
+ usbs_handle_set_address();
+ break;
+
+ case USB_SET_CONFIGURATION:
+ /* Handle the SET CONFIGURATION Request */
+ if ((g_usb_setup_data[WINDEX_LOWBYTE] == 0) &&
+ (g_usb_setup_data[WINDEX_HIGHBYTE] == 0)&&
+ (g_usb_setup_data[WLENGTH_LOWBYTE] == 0)&&
+ (g_usb_setup_data[WLENGTH_HIGHBYTE] == 0)&&
+ (g_usb_setup_data[WVALUE_HIGHBYTE] == 0))
+ {
+ usbs_handle_set_configuration();
+ }
+ else
+ {
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ //USBDBGMSG("+USBDBGMSG:EP0 IN stalled at set conf in ep0 dsr\n");
+ }
+ break;
+
+ case USB_GET_CONFIGURATION:
+ /* GET CONFIGURATION request handler */
+ usbs_handle_get_configuration();
+ break;
+ case USB_MSC_GET_MAX_LUN:
+ usbs_handle_msc_get_maxlun();
+ break;
+ case USB_MSC_BOT_RESET:
+
+ default:
+ /* Send STALL Handshake */
+ usbs_endpoint_stall(EP0,IN);
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG:EP0 IN stalled in ep0 dsr\n");
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG:Setup Request Type 0x%02x,0x%02X\n",g_usb_setup_data[BMREQUESTTYPE],g_usb_setup_data[BREQUEST]);
+ break;
+ }
+
+ USBDBGMSG(DEBUG_ENUM,"+USBDBGMSG: ep0 dsr\n");
+}
+/*=============================================================================
+// Endpoint 0 initialization.
+// Control Endpoint, bi-direction
+// This may get called during system start-up or following a reset
+// from the host.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_ep0_init(void)
+{
+ /*initialize Endpoint 0 Queue Header*/
+ usbs_ep0_init_dqh();
+
+ {
+ /*fill the structure for ep0*/
+ if ((EP0_STATE_IDLE != ep0.ep_state) &&
+ ((usbs_control_return (*)(usbs_control_endpoint*, int)) 0 != ep0.common.complete_fn))
+ {
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ (*ep0.common.complete_fn)(&ep0.common, -EPIPE);
+ #endif
+ }
+ ep0.common.state = USBS_STATE_POWERED;
+ memset(ep0.common.control_buffer, 0, 8);
+ ep0.common.buffer = (unsigned char*) 0;
+ ep0.common.buffer_size = 0;
+ ep0.common.fill_buffer_fn = (void (*)(usbs_control_endpoint*)) 0;
+ ep0.common.fill_data = (void*) 0;
+ ep0.common.fill_index = 0;
+ ep0.common.complete_fn = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0;
+ ep0.ep_state = EP0_STATE_IDLE;
+ ep0.length = 0;
+ ep0.transmitted = 0;
+ }
+}
+// ----------------------------------------------------------------------------
+/*=============================================================================
+// The start function is called by higher-level code when things have
+// been set up, i.e. the enumeration data is available, appropriate
+// handlers have been installed for the different types of control
+// messages, and communication with the host is allowed to start. The
+// next event that should happen is a reset operation from the host,
+// so all other interrupts should be blocked. However it is likely
+// that the hardware will detect a suspend state before the reset
+// arrives, and hence the reset will act as a resume as well as a
+// reset.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_ep0_start(usbs_control_endpoint* endpoint)
+{
+ cyg_uint32 temp;
+
+ CYG_ASSERT( endpoint == &ep0.common, "USB startup involves the wrong endpoint");
+
+ /*clear all interrupt status bits*/
+ temp = usbs_imx_otg_base->usbsts;
+ usbs_imx_otg_base->usbsts = temp; //clear all the previous interrupts
+
+ /*enable all the sub-interrupt sources for USB device*/
+ USBS_IMX_OTG_INTR_UNMASK(IMX_USB_INTR_DEV_PCE|IMX_USB_INTR_DEV_RESET|IMX_USB_INTR_DEV_USBINT);
+
+ /*set Run/Stop bit to Run Mode*/
+ usbs_imx_otg_base->usbcmd |= BIT0;
+
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: mx37 ep0 start.\n");
+}
+// ****************************************************************************
+// -----------------------Endpoint 1 Functions---------------------------------
+// ****************************************************************************
+/*=============================================================================
+// Complete a transfer. This takes care of invoking the completion
+// callback and resetting the buffer.
+=============================================================================*/
+static void
+ep1_rx_complete(int result)
+{
+ //cyg_uint32 total_bytes;
+ cyg_uint32 dtd_address;
+ cyg_uint32 dqh_address;
+ cyg_uint32 received_buffer_addrs = 0x0;
+ cyg_uint32 received_data_length = 0x0;
+ cyg_uint32* temp = 0x0;
+
+ int i;
+
+ if(g_usb_dev_state != USB_DEV_CONFIGURED_STATE)
+ return; //EP1 only receives data when the USB device has been configured
+
+ if(ep1.common.buffer == NULL)
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete: NULL buffer \n");
+ return; //there is not a buffer used to store the data from host
+ }
+
+ /* Get Device Device Queue Head of the out endpoint */
+ dqh_address = USBS_EP_GET_dQH(EP1,OUT);
+
+ /* Get Device Transfer Descriptor of the out endpoint */
+ dtd_address = USBS_EP_GET_dTD(EP1,OUT);
+
+ /*clear the complete status */
+ usbs_imx_otg_base->endptcomplete |= (EPOUT_COMPLETE << EP1);
+
+ //received_buffer_addrs = (*((unsigned int *)dtd_address + 2)) & 0xFFFFF000;
+ received_buffer_addrs = (cyg_uint32)ep1.common.buffer;
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete: received_buffer_addrs 0x%08X \n",received_buffer_addrs);
+ if( received_buffer_addrs == 0)
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete: NULL rx buffer \n");
+ return;
+ }
+
+ /* calculate the received data length using number of bytes left in TD */
+ temp = (cyg_uint32 *)dtd_address;
+ temp++; //pointer to total bytes in dtd, second work in dTD
+ received_data_length = (ep1.common.buffer_size - (((*temp) >> 16 )&0x7FFF)); //recevied data length <= BULK_TD_BUFFER_TOTAL_SIZE
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete: received length %d \n",received_data_length);
+ #if 0
+ /* Check if the received packet is SCSI WRITE, if yes, assign the TD buffer offset
+ is zero, otherwise, one. This is a bug in MX37 USB OTG */
+ if((received_data_length==31)&&(*(destination_ptr+0xF)==0x2A))//WRITE10 received
+ {
+ g_bulk_out_transdesc_buffer_offset = 0;
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_start_rx - set offset to zero \n");
+ }
+
+ else if((g_bulk_out_sector_number_is_one == 1)&&(received_data_length!=31)) //last bulk out data sector
+ g_bulk_out_transdesc_buffer_offset = 1;
+ #endif
+
+ /* tell ep1 how many bytes data is received*/
+ ep1.fetched = received_data_length;
+
+ if(ep1.fetched)
+ {
+ if(ep1.fetched == 31)
+ g_received_data_type = MASS_STORAGE_CBW_TYPE;
+ else
+ g_received_data_type = MASS_STORAGE_DATA_TYPE;
+ ep1.common.complete_data = (void*)(ep1.common.buffer);
+
+ #if 0
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete: \n");
+ USBDBGMSG(DEBUG_TRANS,"----Dump Bulk-Out Recevied Data----\n");
+ for(i=0;i<32;i++)
+ {
+ USBDBGMSG(DEBUG_TRANS,"%02X ", *((cyg_uint8 *)(ep1.common.complete_data)+i));
+ }
+ USBDBGMSG(DEBUG_TRANS,"\n");
+ #endif
+ //USB_IMX_SET_TD_OFFSET(g_td_buffer_offset, 0);
+ ep1.common.buffer = (unsigned char*) 0;
+ ep1.common.buffer_size = 0;
+ ep1_start_rx((usbs_rx_endpoint *)(&(ep1.common))); //prevent to receive more CBW before processing done
+ }
+
+ #if 0
+ if(ep1.fetched == 31)
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_rx_complete - recevied data: \n");
+ for(i=0;i<32;i++)
+ {
+ USBDBGMSG(DEBUG_TRANS,"%02X ", *((cyg_uint8 *)(ep1.common.complete_data)+i));
+ }
+ USBDBGMSG(DEBUG_TRANS,"\n");
+
+ for(i=0;i<32;i++)
+ {
+ USBDBGMSG(DEBUG_TRANS,"%02X ", *((cyg_uint8 *)received_buffer_addrs+i));
+ }
+ USBDBGMSG(DEBUG_TRANS,"\n");
+ }
+ #endif
+
+
+}
+/*=============================================================================
+// Start to receive data from host. This functionality is overloaded to cope with
+// waiting for stalls to complete.
+// The transfer descriptor is prepared
+=============================================================================*/
+static void
+ep1_start_rx(usbs_rx_endpoint* endpoint)
+{
+ struct dtd_t td;
+ cyg_uint32 total_bytes;
+ cyg_uint32 dtd_address;
+ cyg_uint32 dqh_address;
+ cyg_uint32 buffer_addrs_page0;
+
+ if(g_usb_dev_state != USB_DEV_CONFIGURED_STATE)
+ return; //EP1 only receives data when the USB device has been configured
+ #if 0 //don't check to prevent EP1 from receiving data before processing the previous.
+ if(endpoint->buffer == NULL)
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1_start_rx: NULL buffer \n");
+ return; //there is not a buffer used to store the data from host
+ }
+ #endif
+ /* Get Device Device Queue Head of the out endpoint */
+ dqh_address = USBS_EP_GET_dQH(EP1,OUT);
+
+ /* Get Device Transfer Descriptor of the out endpoint */
+ dtd_address = USBS_EP_GET_dTD(EP1,OUT);
+
+ /* ==Prepare TD for next bulk out transfer== */
+ /* get the dTD buffer pointer */
+ buffer_addrs_page0 = (cyg_uint32)(endpoint->buffer);
+
+ /* Get the total bytes to be received */
+ total_bytes = endpoint->buffer_size;
+
+ /* OUT setup dTD */
+ td.dtd_base = dtd_address;
+ td.next_link_ptr = dtd_address + 0x20;
+ td.terminate = TERMINATE;
+ td.total_bytes = total_bytes;
+ td.ioc = IOC_SET;
+ td.status = ACTIVE;
+ td.buffer_ptr0 = buffer_addrs_page0 ;
+ td.current_offset = ( buffer_addrs_page0 & 0xFFF ) + g_td_buffer_offset;
+ td.buffer_ptr1 = 0;
+ td.buffer_ptr2 = 0;
+ td.buffer_ptr3 = 0;
+ td.buffer_ptr4 = 0;
+
+ /* re-define the buffer page pointers based on the total_bytes*/
+ if(total_bytes > BULK_TD_BUFFER_PAGE_SIZE)
+ td.buffer_ptr1 = (td.buffer_ptr0 + BULK_TD_BUFFER_PAGE_SIZE);
+ if(total_bytes > BULK_TD_BUFFER_PAGE_SIZE*2)
+ td.buffer_ptr2 = (td.buffer_ptr1 + BULK_TD_BUFFER_PAGE_SIZE);
+ if(total_bytes > BULK_TD_BUFFER_PAGE_SIZE*3)
+ td.buffer_ptr3 = (td.buffer_ptr2 + BULK_TD_BUFFER_PAGE_SIZE);
+
+ /* Set the Transfer Descriptor */
+ usbs_setup_transdesc(&td);
+
+ /* 1. write dQH next ptr and dQH terminate bit to 0 */
+ *(volatile cyg_uint32 *)(dqh_address+0x8)= dtd_address;
+
+ /* 2. clear active & halt bit in dQH */
+ *(volatile cyg_uint32 *)(dqh_address+0xC) &= ~0xFF;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME
+ prime bulk out endpoint after sending the CSW of last command
+ */
+ //usbs_imx_otg_base->endptprime |= ( EPOUT_PRIME << EP1 );
+
+}
+/*=============================================================================
+// The exported interface to halt the EP1
+=============================================================================*/
+static void
+ep1_set_halted(usbs_rx_endpoint* endpoint, cyg_bool new_value)
+{
+ if (ep1.common.halted == new_value) {
+ return;
+ }
+ if (new_value) {
+ // The endpoint should be stalled. There is a potential race
+ // condition here with the current transfer and DSR invocation.
+ // Updating the stalled flag means that the DSR will do nothing.
+ usbs_endpoint_stall(EP1,OUT);
+ ep1.common.halted = 1;
+ }
+ else {
+ // Take care of the hardware so that a new transfer is allowed.
+ usbs_endpoint_unstall(EP1,OUT);
+ ep1.common.halted = 0;
+ }
+
+}
+/*=============================================================================
+// The DSR is invoked following an interrupt. According to the docs an
+// endpoint 1 interrupt can only happen if the receive-packet-complete
+// bit is set.
+// [Note] EP1 DSR is only used to receive the command block wrapper from host
+// to USB mass storage device
+=============================================================================*/
+
+static void
+usbs_imx_otg_dev_ep1_dsr(void)
+{
+ int result = 0; //contains the actual recevied data length from bulk-out endpoint
+ g_received_data_type = 0;//MASS_STORAGE_CBW_TYPE
+
+ if(ep1.common.buffer)//buffer of TD is not null, then receive
+ {
+ ep1_rx_complete(result);
+ }
+ //USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1 dsr - result = %d\n",result);
+ //recevie mass storage device CBW
+
+ if((ep1.fetched == 31)&&(g_received_data_type == MASS_STORAGE_CBW_TYPE))
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1 dsr - CBW received\n");
+ //post the semaphore of MSC command handler thread
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ cyg_semaphore_post(&usbs_msc_sem);
+ #endif
+ ep1.fetched = 0;
+ }
+ else
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep1 dsr - received %d byte\n",ep1.fetched);
+
+}
+
+/*=============================================================================
+// Endpoint 1 initialization.
+// Bulk-OUT Endpoint
+// This may get called during system start-up or following a reset
+// from the host.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_ep1_init(void)
+{
+ //at present, ep1.common.buffer is NULL. The buffer should be initialized
+ //by upper layer caller.
+ /*buffer is assigned in MSC initialization*/
+
+ // Endpoints should never be halted during a start-up.
+ ep1.common.halted = 0; //false =0, true =1
+ ep1.common.complete_fn = ep1_rx_complete;
+ // If there has been a reset and there was a receive in progress,
+ // abort it. This also takes care of sorting out the endpoint
+ // fields ready for the next rx.
+ ep1_rx_complete(-EPIPE);
+}
+
+// ****************************************************************************
+// -----------------------Endpoint 2 Functions---------------------------------
+// ****************************************************************************
+/*=============================================================================
+// A utility routine for completing a transfer. This takes care of the
+// callback as well as resetting the buffer.
+=============================================================================*/
+static void
+ep2_tx_complete(int result)
+{
+ void (*complete_fn)(void*, int) = ep2.common.complete_fn;
+ void* complete_data = ep2.common.complete_data;
+
+ ep2.common.buffer = (unsigned char*) 0;
+ ep2.common.buffer_size = 0;
+ ep2.common.complete_fn = (void (*)(void*, int)) 0;
+ ep2.common.complete_data = (void*) 0;
+
+ if ((void (*)(void*, int))0 != complete_fn) {
+ (*complete_fn)(complete_data, result);
+ }
+}
+
+/*=============================================================================
+// The exported interface to start to transmit data to Host
+=============================================================================*/
+static void
+ep2_start_tx(usbs_tx_endpoint* endpoint)
+{
+ int timeout = 400;
+ struct dtd_t td;
+ cyg_uint32 total_bytes ;
+ cyg_uint32 dtd_address,dqh_address;
+ cyg_uint32 buffer_addrs_page0;
+ cyg_uint32 size = 0x0;
+
+ /* Get Device Transfer Descriptor of the requested endpoint */
+ dtd_address = USBS_EP_GET_dTD(EP2,IN);
+
+ /* Get Device Queue head of the requested endpoint */
+ dqh_address = USBS_EP_GET_dQH(EP2,IN);
+
+ /* allocate memory for data transfer */
+ buffer_addrs_page0 = endpoint->buffer;
+
+ if(buffer_addrs_page0 == 0)
+ {
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep2_start_tx: NULL tx buffer \n");
+ return;
+ }
+
+ total_bytes = (cyg_uint32)(endpoint->buffer_size);
+ size = (total_bytes < BULK_TD_BUFFER_TOTAL_SIZE )?total_bytes:(BULK_TD_BUFFER_TOTAL_SIZE);
+
+ td.dtd_base = dtd_address;
+ td.next_link_ptr = dtd_address + 0x20 ;
+ td.terminate = TERMINATE;
+ td.total_bytes = size;
+ td.ioc = IOC_SET;
+ td.status = ACTIVE;
+ td.buffer_ptr0 = buffer_addrs_page0 ;
+ td.current_offset = (buffer_addrs_page0 & 0xFFF)+ g_td_buffer_offset;
+ td.buffer_ptr1 = 0;
+ td.buffer_ptr2 = 0;
+ td.buffer_ptr3 = 0;
+ td.buffer_ptr4 = 0;
+
+ /* re-define the buffer page pointers based on the total_bytes*/
+ if(size > BULK_TD_BUFFER_PAGE_SIZE)
+ td.buffer_ptr1 = (td.buffer_ptr0 + BULK_TD_BUFFER_PAGE_SIZE);
+ if(size > BULK_TD_BUFFER_PAGE_SIZE*2)
+ td.buffer_ptr2 = (td.buffer_ptr1 + BULK_TD_BUFFER_PAGE_SIZE);
+ if(size > BULK_TD_BUFFER_PAGE_SIZE*3)
+ td.buffer_ptr3 = (td.buffer_ptr2 + BULK_TD_BUFFER_PAGE_SIZE);
+
+ /* Set the Transfer Descriptor */
+ usbs_setup_transdesc(&td);
+
+ /* 1. write dQH next ptr and dQH terminate bit to 0 */
+ *(volatile cyg_uint32 *)(dqh_address+0x8)= (dtd_address);
+
+ /* 2. clear active & halt bit in dQH */
+ *(volatile cyg_uint32 *)(dqh_address+0xC) &= ~0xFF;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME */
+ usbs_imx_otg_base->endptprime = ( EPIN_PRIME << EP2 );
+
+ /* wait for complete set and clear */
+ while (!((usbs_imx_otg_base->endptcomplete) & (EPIN_COMPLETE<<EP2)));
+
+ usbs_imx_otg_base->endptcomplete |= (EPIN_COMPLETE << EP2);
+
+ ep2.transmitted = size;
+
+ ep2_tx_complete(-EPIPE);
+
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep2 tx done\n");// ep2.transmitted);
+
+}
+/*=============================================================================
+// The exported interface to halt the EP2
+=============================================================================*/
+static void
+ep2_set_halted(usbs_tx_endpoint* endpoint, cyg_bool new_value)
+{
+ if (ep2.common.halted == new_value) {
+ return;
+ }
+ if (new_value) {
+ // The endpoint should be stalled. There is a potential race
+ // condition here with the current transfer and DSR invocation.
+ // Updating the stalled flag means that the DSR will do nothing.
+ usbs_endpoint_stall(EP2,IN);
+ ep2.common.halted = 1;
+ }
+ else {
+ // Take care of the hardware so that a new transfer is allowed.
+ usbs_endpoint_unstall(EP2,IN);
+ ep2.common.halted = 0;
+ }
+}
+/*=============================================================================
+// The dsr will be invoked when the transmit-packet-complete bit is
+// set. Typically this happens when a packet has been completed
+=============================================================================*/
+
+static void
+usbs_imx_otg_dev_ep2_dsr(void)
+{
+ USBDBGMSG(DEBUG_TRANS,"+USBDBGMSG: ep2 dsr\n");
+ /* EP2 DSR will be called as soon as a transfer complete to clear status*/
+ usbs_imx_otg_base->endptcomplete |= (EPIN_COMPLETE << EP2);
+
+
+ if(ep2.common.buffer_size==0)
+ {
+ ep2_tx_complete(-EPIPE);
+ ep2.transmitted = 0; //clear the field to wait for the next transmit
+ }
+
+}
+
+/*=============================================================================
+// Endpoint 2 initialization.
+// Bulk-IN Endpoint
+// This may be called during system start-up or following a reset
+// from the host.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_ep2_init(void)
+{
+ //at initialization, ep2.common.buffer is NULL. The buffer should be initialized
+ //by upper layer caller.
+
+ // Endpoints should never be halted after a reset
+ ep2.common.halted = false;
+
+ // If there has been a reset and there was a receive in progress,
+ // abort it. This also takes care of clearing the endpoint
+ // structure fields.
+ ep2_tx_complete(-EPIPE);
+}
+
+// ****************************************************************************
+// -----------------------MX37 USB Device Driver API Functions-----------------
+// ****************************************************************************
+
+/*=============================================================================
+// The DSR. This can be invoked directly by poll(), or via the usual
+// interrupt subsystem. It acts as per the current value of
+// g_isr_status_bits. If another interrupt goes off while this
+// DSR is running, there will be another invocation of the DSR and
+// the status bits will be updated.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ int status = 0;
+ cyg_uint32 temp;
+ CYG_ASSERT(MX51_IRQ_USB_SERVICE_REQUEST == vector, "USB DSR should only be invoked for USB interrupts" );
+ CYG_ASSERT(0 == data, "The i.MX37 USB DSR needs no global data pointer");
+ //USBDBGMSG("+USBDBGMSG: enter mx37 dsr\n");
+ // There is no atomic swap support, so interrupts have to be
+ // blocked. It might be possible to do this via the USBS_CONTROL
+ // register, but at the risk of messing up the status register
+ // if another interrupt comes in. Blocking interrupts at the
+ // processor level is less intrusive on the USB code.
+ //cyg_drv_isr_lock();
+ status = g_isr_status_bits;
+ g_isr_status_bits = 0;
+ //cyg_drv_isr_unlock();
+
+ // Reset is special, since it invalidates everything else.
+ // If the reset is still ongoing then do not attempt any
+ // further processing, there will just be another interrupt.
+ // Otherwise handle_reset() does the hard work. Unmasking
+ // the interrupt means that another interrupt will occur
+ // immediately if reset is still asserted, i.e. no threads
+ // will run, but there is no easy way of triggering action
+ // at the end of reset.
+ if (status & IMX_USB_STS_RESET)
+ {
+ int new_status = usbs_imx_otg_base->usbsts;
+ if (0 == (new_status & IMX_USB_STS_RESET))
+ {
+ usbs_imx_otg_dev_handle_bus_reset();
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: !!USB BUS RESET\n");
+ }
+
+ // This unmask is likely to cause another interrupt immediately
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ cyg_interrupt_unmask(MX51_IRQ_USB_SERVICE_REQUEST);
+ #endif
+ }
+ else if(status & IMX_USB_STS_USBINT)
+ {
+
+ if(usbs_imx_otg_base->endptsetupstat & BIT0)
+ {// if Setup Packet arrived
+ usbs_imx_otg_dev_ep0_dsr();
+ }
+
+ else if((usbs_imx_otg_base->endptcomplete) & ( EPIN_COMPLETE << EP2))
+ {// EP2 Queue Header buffer completes sending data
+ //complete bit is cleared in ep2_start_tx
+ }
+
+
+ else if((usbs_imx_otg_base->endptcomplete) & ( EPOUT_COMPLETE << EP1))
+ {// EP1 Queue Header buffer get data
+ usbs_imx_otg_dev_ep1_dsr();
+
+ }
+
+ else if((usbs_imx_otg_base->endptcomplete) & ( EPOUT_COMPLETE << EP0))
+ {
+ //usbs_imx_otg_dev_ep0_dsr();
+ usbs_imx_otg_base->endptcomplete = ( EPOUT_COMPLETE << EP0);
+ }
+ else
+ {//do nothing, only for constructure integrity
+ temp = usbs_imx_otg_base->endptcomplete;
+ usbs_imx_otg_base->endptcomplete = temp;
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: usbsts int - unknown.\n");
+ }
+
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ // This unmask is likely to cause another interrupt immediately
+ cyg_interrupt_unmask(MX51_IRQ_USB_SERVICE_REQUEST);
+ #endif
+ }
+ else
+ {
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ // This unmask is likely to cause another interrupt immediately
+ cyg_interrupt_unmask(MX51_IRQ_USB_SERVICE_REQUEST);
+ #endif
+ }
+
+
+}
+/*=============================================================================
+// The DSR thread
+=============================================================================*/
+#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+#define CYGNUM_DEVS_USB_OTG_DEV_THREAD_STACK_SIZE 1024
+#define CYGNUM_DEVS_USB_OTG_DEV_THREAD_PRIORITY 29
+static unsigned char usbs_imx_otg_dev_thread_stack[CYGNUM_DEVS_USB_OTG_DEV_THREAD_STACK_SIZE];
+static cyg_thread usbs_imx_otg_dev_thread;
+static cyg_handle_t usbs_imx_otg_dev_thread_handle;
+static cyg_sem_t usbs_imx_otg_dev_sem;
+
+
+static void
+usbs_imx_otg_dev_thread_fn(cyg_addrword_t param)
+{
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: usb driver thread\n");
+ for (;;) {
+ cyg_semaphore_wait(&usbs_imx_otg_dev_sem);
+ usbs_imx_otg_dev_dsr(IMX_IRQ_USB_DEV_SERVICE_REQUEST, 0, 0);
+ }
+ CYG_UNUSED_PARAM(cyg_addrword_t, param);
+}
+
+static void
+usbs_imx_otg_dev_thread_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ CYG_ASSERT( 0 != isr_status_bits, "DSR's should only be scheduled when there is work to do");
+ cyg_semaphore_post(&usbs_imx_otg_dev_sem);
+
+
+ CYG_UNUSED_PARAM(cyg_vector_t, vector);
+ CYG_UNUSED_PARAM(cyg_ucount32, count);
+ CYG_UNUSED_PARAM(cyg_addrword_t, data);
+}
+#endif
+/*=============================================================================
+// The interrupt handler. This does as little as possible.
+=============================================================================*/
+static cyg_uint32
+usbs_imx_otg_dev_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ cyg_uint32 old_status_bits = g_isr_status_bits;
+ cyg_uint32 status_bits;
+
+ CYG_ASSERT(IMX_IRQ_USB_DEV_SERVICE_REQUEST == vector, "USB ISR should only be invoked for USB interrupts" );
+ CYG_ASSERT(0 == data, "The MX51 USB ISR needs no global data pointer" );
+
+ //USBDBGMSG("+USBDBGMSG: enter mx51 isr\n");
+ // Read the current status. Reset is special, it means that the
+ // whole chip has been reset apart from the one bit in the status
+ // register. Nothing should be done about this until the DSR sets
+ // the endpoints back to a consistent state and re-enables
+ // interrupts in the control register.
+ status_bits = usbs_imx_otg_base->usbsts;
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: usb intr 0x%08X\n",status_bits);
+ if (status_bits & IMX_USB_STS_RESET)
+ {
+
+ g_isr_status_bits |= IMX_USB_STS_RESET;
+ usbs_imx_otg_base->usbsts |= IMX_USB_STS_RESET;
+ cyg_interrupt_mask(IMX_IRQ_USB_DEV_SERVICE_REQUEST);
+ }
+ else if(status_bits & IMX_USB_STS_USBINT)
+ {
+ g_isr_status_bits |= IMX_USB_STS_USBINT;
+ usbs_imx_otg_base->usbsts |= IMX_USB_STS_USBINT;
+ cyg_interrupt_mask(IMX_IRQ_USB_DEV_SERVICE_REQUEST);
+ }
+ else
+ {
+ usbs_imx_otg_base->usbsts = status_bits; //clear the status bit of USBSTS
+ g_isr_status_bits &= ~status_bits;
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: unknown usb intr\n");
+ }
+
+ // Now keep the rest of the system happy.
+ cyg_interrupt_acknowledge(vector); //reenable the USB interrupt
+ return (old_status_bits != g_isr_status_bits) ? CYG_ISR_CALL_DSR : CYG_ISR_HANDLED;
+}
+/*=============================================================================
+// Polling support. This acts mostly like the interrupt handler: it
+// sets the isr status bits and causes the dsr to run. Reset has to be
+// handled specially: polling does nothing as long as reset is asserted.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_poll(usbs_control_endpoint* endpoint)
+{
+ CYG_ASSERT( endpoint == &ep0.common, "USB poll involves the wrong endpoint");
+
+ if (g_isr_status_bits & IMX_USB_STS_RESET)
+ {
+ // Reset was detected the last time poll() was invoked. If
+ // reset is still active, do nothing. Once the reset has
+ // completed things can continue.
+ if (0 == (IMX_USB_STS_RESET & usbs_imx_otg_base->usbsts))
+ {
+ g_isr_status_bits = 0;
+ usbs_imx_otg_dev_handle_bus_reset();
+ }
+ }
+ else
+ {
+ g_isr_status_bits = usbs_imx_otg_base->usbsts;
+ if (IMX_USB_STS_PTCHANGE & g_isr_status_bits)
+ {
+ //process Port Change Detect
+ usbs_imx_otg_dev_handle_port_change();
+ }
+ else if (IMX_USB_STS_USBINT & g_isr_status_bits)
+ {
+ usbs_imx_otg_dev_dsr(IMX_IRQ_USB_DEV_SERVICE_REQUEST, 0, (cyg_addrword_t) 0);
+ }
+ else
+ {
+ usbs_imx_otg_base->usbsts = g_isr_status_bits; //clear the don't-care status
+ }
+ }
+}
+/*=============================================================================
+// Perform reset operations on all endpoints that have been
+// configured in. It is convenient to keep this in a separate
+// routine to allow for polling, where manipulating the
+// interrupt controller mask is a bad idea.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_handle_bus_reset(void)
+{
+ cyg_uint32 temp;
+
+ usbs_imx_otg_base->usbcmd &= ~BIT0; //detach device from bus temprorarily
+ usbs_imx_otg_base->usbsts |= BIT6; //clear reset bit in USBSTS
+
+ //temp = usbs_imx_otg_base->usbsts;
+ //usbs_imx_otg_base->usbsts = temp;
+
+ /*1. Reading and writing back the ENDPTSETUPSTAT register
+ clears the setup token semaphores */
+ temp = usbs_imx_otg_base->endptsetupstat;
+ usbs_imx_otg_base->endptsetupstat = temp;
+
+ /*2. Reading and writing back the ENDPTCOMPLETE register
+ clears the endpoint complete status bits */
+ temp = usbs_imx_otg_base->endptcomplete;
+ usbs_imx_otg_base->endptcomplete = temp;
+
+ /*3. Cancel all primed status by waiting until all bits in ENDPTPRIME are 0
+ and then write 0xFFFFFFFF to ENDPTFLUSH */
+ while(usbs_imx_otg_base->endptprime);
+ usbs_imx_otg_base->endptflush = 0xFFFFFFFF;
+
+
+ /*4. Initialize EP0 Queue Head again*/
+ usbs_ep0_init_dqh();
+
+ usbs_imx_otg_base->endptlistaddr = g_bulkbuffer_map.ep_dqh_base_addrs;
+
+ usbs_imx_otg_base->usbcmd |= BIT0; //re-attach device to the bus
+
+ g_usb_dev_state = USB_DEV_DEFAULT_STATE;
+
+
+}
+/*=============================================================================
+// Perform port change operations on all endpoints that have been
+// configured in. It is convenient to keep this in a separate
+// routine to allow for polling, where manipulating the
+// interrupt controller mask is a bad idea.
+=============================================================================*/
+static void
+usbs_imx_otg_dev_handle_port_change(void)
+{
+ /*Port Change happens when USB device enters/exits FS or HS mode
+ When exiting from FS or HS due to Bus reset or DCSuspend, the notification
+ mechanisms are Reset Received and DCSuspend.
+ This function only processes the port change on entering FS or HS
+ Don't enable Port Change Detect interrupt, it's no sense for operation.*/
+ usbs_imx_otg_base->usbsts |= IMX_USB_STS_PTCHANGE; //clear Port change status
+
+}
+
+// ****************************************************************************
+// ----------------------------------------------------------------------------
+// ****************************************************************************
+/*=============================================================================
+FUNCTION: usbs_imx_otg_dev_set_configuration
+DESCRIPTION: This function Handle the SET CONFIGRATION Request.
+ARGUMENTS PASSED: usb_end_pt_info_t* config_data;
+RETURN VALUE: None
+IMPORTANT NOTES: None
+=============================================================================*/
+static void
+usbs_imx_otg_dev_set_configuration(usb_end_pt_info_t* config_data)
+{
+ struct dtd_t td;
+ cyg_uint32 total_bytes = 0x0;
+ cyg_uint32 buffer_addrs_page0 = 0;
+ cyg_uint32 dqh_address = 0;
+ cyg_uint32 dtd_address = 0;
+ cyg_uint8 endpt_num,direction;
+
+ struct dqh_t qhead;
+
+
+ /* get endpoint number to be configured and its direction */
+ endpt_num= config_data->end_pt_no;
+ direction= config_data->direction;
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: set config - ep%d\n",endpt_num);
+ /* Check if the endpoint number and direction is withing the permitted range or not */
+ if (( endpt_num != EP0 ) && (endpt_num <= ( g_max_ep_supported - 1)) &&
+ ( direction == OUT || direction == IN))
+ {
+ /* get the device q head and deice TD */
+ dqh_address = USBS_EP_GET_dQH(endpt_num,direction);
+ dtd_address = USBS_EP_GET_dTD(endpt_num,direction);
+
+ if ( direction == OUT )
+ {
+ total_bytes = BULK_BUFFER_SIZE ;
+
+ qhead.dqh_base = dqh_address;
+ qhead.zlt = ZLT_DISABLE;
+ qhead.mps = config_data->max_pkt_size;
+ qhead.ios = IOS_SET;
+ qhead.next_link_ptr = dtd_address ;
+ qhead.terminate = TERMINATE;
+ qhead.total_bytes = total_bytes;
+ qhead.ioc = IOC_SET;
+ qhead.status = NO_STATUS;
+ qhead.buffer_ptr0 = 0;
+ qhead.current_offset= 0;
+ qhead.buffer_ptr1 = 0;
+ qhead.buffer_ptr2 = 0;
+ qhead.buffer_ptr3 = 0;
+ qhead.buffer_ptr4 = 0;
+
+ usbs_setup_queuehead(&qhead);
+
+ /* Endpoint 1 : MPS = 64, OUT (Rx endpoint) */
+ usbs_imx_otg_base->endptctrl[endpt_num] = 0x00080048;
+ /* Enable EP1 OUT */
+ usbs_imx_otg_base->endptctrl[endpt_num] |= EPOUT_ENABLE;
+
+ /* allocate buffer for receiving data */
+ /* free the usb buffer after re-enumeration*/
+ //g_bulkbuffer_map.buffer1_status = BUFFER_FREE;
+ //g_bulkbuffer_map.buffer2_status = BUFFER_FREE;
+ g_bulkbuffer_a.stat = BUFFER_FREED;
+ g_bulkbuffer_b.stat = BUFFER_FREED;
+
+ //buffer_addrs_page0 = util_alloc_buffer();
+ ep1.common.buffer = g_bulkbuffer_a.buffer;
+ ep1.common.buffer_size = total_bytes;
+ g_bulkbuffer_a.stat = BUFFER_ALLOCATED;
+ buffer_addrs_page0 = (cyg_uint32)(ep1.common.buffer);
+
+
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: set config - ep1 dtd buffer 0x%08X\n",buffer_addrs_page0);
+
+ /* OUT setup dTD */
+ td.dtd_base = dtd_address;
+ td.next_link_ptr = dtd_address + 0x20;
+ td.terminate = TERMINATE;
+ td.total_bytes = total_bytes;
+ td.ioc = IOC_SET;
+ td.status = ACTIVE;
+ td.buffer_ptr0 = buffer_addrs_page0;
+ td.current_offset = (buffer_addrs_page0 & 0xFFF) + g_td_buffer_offset;
+ td.buffer_ptr1 = 0x0;
+ td.buffer_ptr2 = 0x0;
+ td.buffer_ptr3 = 0x0;
+ td.buffer_ptr4 = 0x0;
+
+ /* Set the Transfer Descriptor */
+ usbs_setup_transdesc(&td);
+
+ /* 1. write dQH next ptr and dQH terminate bit to 0 */
+ *(volatile cyg_uint32*)(dqh_address+0x8)= dtd_address;
+
+ /* 2. clear active & halt bit in dQH */
+ *(volatile cyg_uint32*)(dqh_address+0xC) &= ~0xFF;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME */
+ usbs_imx_otg_base->endptprime |= ( EPOUT_PRIME << endpt_num );
+ /* Endpoint Configured for output */
+ g_out_endpoint= endpt_num;
+
+
+ }
+
+ else
+ {
+ total_bytes = 0x4 ;
+
+ qhead.dqh_base = USBS_EP_GET_dQH(endpt_num,direction);
+ qhead.zlt = ZLT_DISABLE;
+ qhead.mps = config_data->max_pkt_size;
+ qhead.ios = IOS_SET;
+ qhead.next_link_ptr = USBS_EP_GET_dQH(endpt_num,direction);
+ qhead.terminate = TERMINATE;
+ qhead.total_bytes = total_bytes;
+ qhead.ioc = IOC_SET;
+ qhead.status = NO_STATUS;
+ qhead.buffer_ptr0 = 0;
+ qhead.current_offset= 0;
+ qhead.buffer_ptr1 = 0;
+ qhead.buffer_ptr2 = 0;
+ qhead.buffer_ptr3 = 0;
+ qhead.buffer_ptr4 = 0;
+
+ usbs_setup_queuehead(&qhead);
+
+ /* Endpoint Configured for Input */
+ g_in_endpoint= endpt_num;
+
+ /* Endpoint 2: MPS = 64, IN (Tx endpoint) */
+ usbs_imx_otg_base->endptctrl[endpt_num] = 0x00480008;
+
+ /* Enable EP2 IN */
+ usbs_imx_otg_base->endptctrl[endpt_num] |= EPIN_ENABLE;
+
+ /* 3. prime endpoint by writing '1' in ENDPTPRIME */
+ usbs_imx_otg_base->endptprime |= (EPIN_PRIME << g_in_endpoint);
+
+ }
+ }
+ else
+ {
+ /* TODO: error handling TBD */
+ }
+
+}
+
+static void usbs_imx_otg_config_utmi_clock(void)
+{
+ #if defined(CYGHWR_USB_DEVS_MX37_OTG)
+ USB_MX37_SET_PHY_CLK_24MHZ();
+ #endif
+
+ #if defined(CYGHWR_USB_DEVS_MX51_OTG)
+ cyg_uint32 temp;
+ /*Configure USB_PHYCLOCK_ROOT source as 24MHz OSC*/
+ CCM_CSCMR1_REGVAL = CCM_CSCMR1_REGVAL & (~CSCMR1_USBOH3_PHY_CLK_SEL_VALUE); //configure USB CRM
+ /*Configure plldivvalue of USB_PHY_CTRL_1_REG for 24 Mhz*/
+ temp = *(volatile cyg_uint32 *)USB_PHY_CTRL_1_REG;
+ temp &= ~USB_PHY_CTRL_PLLDIVVALUE_MASK;
+ temp |= USB_PHY_CTRL_PLLDIVVALUE_24_MHZ;
+ *(volatile cyg_uint32 *)USB_PHY_CTRL_1_REG = temp;
+ #endif
+}
+
+/*=============================================================================
+// The USB OTG hardware relevant initialization.
+=============================================================================*/
+static void
+usbs_imx_otg_hardware_init(void)
+{
+ cyg_uint32 temp;
+ cyg_uint32 timeout = 0x1D0000;
+ usb_plat_config_data_t config_data_ptr;
+ cyg_uint8 i;
+
+ /*Enable USB Internal PHY Clock as 24MHz on-board Ocsillator*/
+ usbs_imx_otg_config_utmi_clock();
+
+ {/*Setup USB Buffer Map*/
+ config_data_ptr.buffer_address = (cyg_uint32)usb_buffer;
+ config_data_ptr.buffer_size = BUFFER_SIZE;
+
+ /* Base address of the buffer allocated to IP Layer */
+ g_bulkbuffer_address_base = config_data_ptr.buffer_address;
+
+ /* length of the buffer */
+ g_bulkbuffer_length = config_data_ptr.buffer_size;
+
+ /* Maximum Number of EPs to be confiured */
+ g_max_ep_supported = (( g_bulkbuffer_length - TOTAL_DATA_BUFFER_SIZE)/(BUFFER_USED_PER_EP)); //=(2048-1088)/256~=3.75->3
+
+ /* Base of queue Head Pointer */
+ g_bulkbuffer_map.ep_dqh_base_addrs = g_bulkbuffer_address_base;
+
+ /* Total size of qhead */
+ temp = (SIZE_OF_QHD * (g_max_ep_supported * 2)); //total size of QH is 384byte
+
+ /* Base Address of dTDs */
+ g_bulkbuffer_map.ep_dtd_base_addrs = (g_bulkbuffer_map.ep_dqh_base_addrs + temp);
+
+ /* Total size of transfer descriptor */
+ temp = ((dTD_SIZE_EPIN * g_max_ep_supported) + (dTD_SIZE_EPOUT * g_max_ep_supported )); //total size of TD is 384 byte
+
+ /* Base Address of EP0 Buffer */
+ g_bulkbuffer_map.ep0_buffer_addrs = (g_bulkbuffer_map.ep_dtd_base_addrs + temp ); //256byte
+
+ /*Bulk Buffer Areas, 512byte per buffer*/
+ /*Actually, the dual 512 byte bulk buffers are not used, because two larger 16kB bulk buffers are used*/
+ /* transfer buffer 1 */
+ g_bulkbuffer_map.buffer1_address=(g_bulkbuffer_address_base + g_bulkbuffer_length -(BULK_BUFFER_SIZE*NUM_OF_BULK_BUFFER));
+ g_bulkbuffer_map.buffer1_status = BUFFER_FREE;
+
+ /* transfer buffer 2 */
+ g_bulkbuffer_map.buffer2_address = g_bulkbuffer_map.buffer1_address + BULK_BUFFER_SIZE;
+ g_bulkbuffer_map.buffer2_status = BUFFER_FREE;
+ }
+
+ {/*Set USB OTG at device only mode*/
+ usbs_imx_otg_base->usbmode = 0x2; //set OTG as a device controller
+ temp = 0xA5A55A5A;
+ while (!(usbs_imx_otg_base->usbmode == 0x2))
+ {
+ if(temp != (usbs_imx_otg_base->usbmode))
+ {
+ temp = (usbs_imx_otg_base->usbmode);
+ USBDBGMSG(DEBUG_BASIC,"usbmode is 0x%08X\n",temp);
+ }
+ timeout--;
+ if(timeout==0) break;
+ } //check that device controller was configured to device mode only
+ }
+
+ {
+ usbs_imx_otg_base->endptlistaddr = g_bulkbuffer_map.ep_dqh_base_addrs; // Configure ENDPOINTLISTADDR Pointer
+ usbs_imx_otg_base->otgsc |= BIT3; // Set OTG termination, controls the pulldown on DM
+ usbs_imx_otg_base->endptnak = 0x00010001; // Enable Endpoint NAK
+ usbs_imx_otg_base->usbmode |= BIT3; // Disable Setup Lockout by writing '1' to SLOM in USBMODE
+ //usbs_imx_otg_base->usbcmd |= BIT0; // Set Run/Stop bit to Run Mode, make USB run in usbs_imx_otg_dev_ep0_start()
+ }
+
+ {
+ /* set it to be utmi interface */
+ temp = usbs_imx_otg_base->portsc1;
+ temp &= ~USB_OTG_TRANS_MASK;
+ temp |= USB_OTG_TRANS_UTMI;
+ temp &= ~USB_OTG_FS_ONLY; //enable high speed
+ temp |= USB_OTG_TRANS_WIDTH;
+
+ usbs_imx_otg_base->portsc1 = temp;
+ }
+
+ {// The USB OTG transaction relevant initialization.
+ /* Select the common descriptors , these descriptor are independent of speed and security mode */
+ g_usb_desc.device_desc = &g_usb_device_desc ;
+ g_usb_desc.config_desc = &g_usb_config_desc;
+ g_usb_desc.sn_desc = &g_usb_serialnumber_desc;
+ g_usb_desc.str_desc0 = &g_usb_otg_str0_desc; //language desc
+ g_usb_desc.str_desc1 = &g_usb_otg_string_desc1; //Manufacturer desc
+ g_usb_desc.str_desc2 = &g_usb_otg_string_desc2; //USB Name Desc
+ g_usb_desc.str_desc3 = &g_usb_otg_string_desc3; //Device Name Desc
+
+ /* Get Number of Endpoints supported from Configuration Descriptor*/
+ g_number_of_endpoints = g_usb_desc.config_desc->usb_interface_desc.number_endpoints;
+
+ /* Store the Endpoint specific information in local variable structure to this Layer */
+ for ( i = 0 ; i< g_number_of_endpoints ; i++)
+ {
+ g_end_pt_info[i].end_pt_no = ((g_usb_desc.config_desc->usb_endpoint_desc[i].endpoint) & ENDPT_NUMBER_MASK);
+ g_end_pt_info[i].direction = (((g_usb_desc.config_desc->usb_endpoint_desc[i].endpoint) & ENDPT_DIR_MASK )>>ENDPT_DIR_SHIFT);
+ g_end_pt_info[i].transfer_type = (g_usb_desc.config_desc->usb_endpoint_desc[i].attributes & ENDPT_TRNS_TYPE_MASK);
+ g_end_pt_info[i].max_pkt_size = ((g_usb_desc.config_desc->usb_endpoint_desc[i].max_packet_lo) \
+ | (( g_usb_desc.config_desc->usb_endpoint_desc[i].max_packet_hi ) << 8 ));
+ }
+
+ g_usb_dev_state = USB_DEV_DEFAULT_STATE;
+ }
+}
+// ****************************************************************************
+// ----------------------------------------------------------------------------
+// ****************************************************************************
+/*=============================================================================
+// Initialization i.MX37(Marley) USB OTG Hardware
+// This function is the only extern function of this device driver, and it
+// registers the driver ISR and DSRs to the kernel.
+=============================================================================*/
+void
+usbs_imx_otg_device_init(void) //works like usb port open when
+{
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: USB Device Driver Start Initializing...\n");
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: USB OTG REG BASE@0x%08X\n",USB_BASE_ADDRESS);
+ g_usb_setup_data = ep0.common.control_buffer;
+
+ g_td_buffer_offset = 0;
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ USB_IMX_SET_TD_OFFSET(g_td_buffer_offset,1);
+ #endif
+
+ /*ping-pang buffer A*/
+ g_bulkbuffer_a.buffer = bulk_buffer;
+ g_bulkbuffer_a.stat = BUFFER_FREED;
+
+ /*ping-pang buffer B*/
+ g_bulkbuffer_b.buffer = bulk_buffer + BULK_TD_BUFFER_TOTAL_SIZE;
+ g_bulkbuffer_b.stat = BUFFER_FREED;
+
+ usbs_imx_otg_hardware_init();
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: Usb Hardware Initialize Complete.\n");
+ usbs_imx_otg_dev_ep0_init();
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: Usb Ep0 Initialize Complete.\n");
+ usbs_imx_otg_dev_ep1_init();
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: Usb Ep1 Initialize Complete.\n");
+ usbs_imx_otg_dev_ep2_init();
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: Usb Ep2 Initialize Complete.\n");
+
+ #if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+ cyg_semaphore_init(&usbs_imx_otg_dev_sem, 0);
+ cyg_thread_create(CYGNUM_DEVS_USB_OTG_DEV_THREAD_PRIORITY,
+ &usbs_imx_otg_dev_thread_fn,
+ 0,
+ "i.MX37/51 USB Device",
+ usbs_imx_otg_dev_thread_stack,
+ CYGNUM_DEVS_USB_OTG_DEV_THREAD_STACK_SIZE,
+ &usbs_imx_otg_dev_thread_handle,
+ &usbs_imx_otg_dev_thread
+ );
+ cyg_thread_resume(usbs_imx_otg_dev_thread_handle);
+ // It is also possible and desirable to install the interrupt
+ // handler here, even though there will be no interrupts for a
+ // while yet.
+ cyg_interrupt_create(IMX_IRQ_USB_DEV_SERVICE_REQUEST,
+ IMX_IRQ_USB_DEV_PRIORITY, // priority
+ 0, // data
+ &usbs_imx_otg_dev_isr,
+ &usbs_imx_otg_dev_thread_dsr,
+ &g_usbs_dev_intr_handle,
+ &g_usbs_dev_intr_data);
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: cyg_interrupt_create@vector %d.\n",IMX_IRQ_USB_DEV_SERVICE_REQUEST);
+ cyg_interrupt_attach(g_usbs_dev_intr_handle); //fill interrupt handler table for USB
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: cyg_interrupt_attach.\n");
+ cyg_interrupt_unmask(IMX_IRQ_USB_DEV_SERVICE_REQUEST); //enable USB interrrupt
+ USBDBGMSG(DEBUG_BASIC,"+USBDBGMSG: cyg_interrupt_unmask.\n");
+ #endif
+ ep0.common.start_fn(&(ep0.common));
+
+}
+
+void
+usbs_imx_otg_device_deinit(void) //works like usb port close
+{
+ usbs_imx_otg_base->usbcmd &= (~BIT0); // Set Run/Stop bit to Stop Mode
+ g_usb_dev_state = USB_DEV_DUMMY_STATE;
+}
+
+#if defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT)
+
+static cyg_uint32 get_free_bulk_buffer(void)
+{
+ cyg_uint32 buff_addr = 0;
+ int i = 0;
+ while(buff_addr == 0)
+ {
+ if(g_bulkbuffer_a.stat == BUFFER_FREED)
+ {
+ buff_addr = (cyg_uint32)(g_bulkbuffer_a.buffer);
+ break;
+ }
+ else if(g_bulkbuffer_b.stat == BUFFER_FREED)
+ {
+ buff_addr = (cyg_uint32)(g_bulkbuffer_b.buffer);
+ break;
+ }
+ /*
+ else
+ {
+ i++;
+ if(i==0xD0000)
+ {
+ diag_printf("no bulk buffer free\n");
+ break;
+ }
+
+ }
+ */
+ }
+ return buff_addr;
+}
+
+cyg_bool set_status_bulk_buffer(cyg_uint32 buff_addr, int buff_stat)
+{
+ cyg_bool ret = true;
+ if(buff_addr == (cyg_uint32)(g_bulkbuffer_a.buffer))
+ g_bulkbuffer_a.stat = buff_stat;
+ else if (buff_addr == (cyg_uint32)(g_bulkbuffer_b.buffer))
+ g_bulkbuffer_b.stat = buff_stat;
+ else
+ ret = false;
+
+ return ret;
+}
+static usb_status_t usb_bulk_receive_data(usb_buffer_descriptor_t * bd)
+{
+ usb_status_t status;
+ int res;
+
+ /* Check if Bus Reset Received */
+ if((usbs_imx_otg_base->usbsts) & IMX_USB_STS_RESET)
+ {
+ /* Handle Bus Reset */
+ usbs_imx_otg_dev_handle_bus_reset();
+ }
+ /* Check if Reset is already received and Setup Token Received */
+ if((usbs_imx_otg_base->endptsetupstat) & BIT0)
+ {
+ /* Handle Setup Token */
+ usbs_imx_otg_dev_ep0_dsr();
+ }
+
+ if((usbs_imx_otg_base->endptcomplete) & ( EPOUT_COMPLETE << EP1))
+ {
+ ep1_rx_complete(res);
+ if(ep1.common.complete_data)
+ {
+ bd->bytes_transfered = ep1.fetched;
+ memcpy(bd->buffer,ep1.common.complete_data,ep1.fetched);
+ ep1.fetched = 0;
+ //D("+USBDBGMSG:bd->bytes_transfered %d\n",bd->bytes_transfered);
+ set_status_bulk_buffer((cyg_uint32)(ep1.common.complete_data), BUFFER_FREED);
+ ep1.common.buffer = (unsigned char *)get_free_bulk_buffer();
+ ep1.common.buffer_size = BULK_TD_BUFFER_TOTAL_SIZE;
+ ep1_start_rx(&(ep1.common));
+ usbs_imx_otg_base->endptprime |= ( EPOUT_PRIME << EP1 );//prime ep1 td
+ status = USB_SUCCESS;
+ }
+
+ else
+ status = USB_FAILURE;
+ }
+ return status;
+}
+
+static usb_status_t usb_bulk_transmit_data(usb_buffer_descriptor_t * bd)
+{
+ //usb_state_t status;
+
+ while(bd->size)
+ {
+ ep2.common.buffer = (unsigned char *)get_free_bulk_buffer();
+ set_status_bulk_buffer((cyg_uint32)(ep2.common.buffer), BUFFER_ALLOCATED);
+ ep2.common.buffer_size = (BULK_TD_BUFFER_TOTAL_SIZE<(bd->size))?BULK_TD_BUFFER_TOTAL_SIZE:(bd->size);
+ memcpy((ep2.common.buffer),(bd->buffer),(ep2.common.buffer_size));
+ ep2_start_tx(&(ep2.common));
+
+ bd->size -= (ep2.common.buffer_size);
+ }
+
+ return USB_SUCCESS;
+}
+static cyg_uint32 usb_rx_processing(cyg_uint8* read_ptr, usb_status_t* status, cyg_uint32 data_length)
+{
+ cyg_uint32 bytes_received = 0;
+ if ( (status != NULL) && (read_ptr != NULL) )
+ {
+ usb_status_t trans_status = USB_FAILURE;
+
+ usb_buffer_descriptor_t buf_desc;
+
+ /* Prepare the buffer descriptor for USB transfer */
+ //(cyg_uint8*)(buf_desc.buffer) = read_ptr;
+ buf_desc.buffer = (void *)read_ptr;
+ while(data_length != 0)
+ {
+ buf_desc.size = data_length;
+ buf_desc.bytes_transfered = 0;
+
+ /* Receive data from USB */
+ trans_status = (usb_status_t )usb_bulk_receive_data(&buf_desc);
+ if(trans_status == USB_SUCCESS)
+ {
+ data_length -= buf_desc.bytes_transfered;
+ bytes_received += buf_desc.bytes_transfered;
+ //(cyg_uint8*)
+ (buf_desc.buffer) += buf_desc.bytes_transfered;
+ }
+ else
+ {
+ *status = USB_FAILURE;
+ }
+
+ g_timeout_value++;
+ if(g_timeout_value%0x1000000==0) D("C");
+ if(g_timeout_value == USB_DOWNLOAD_TIMEOUT_LIMIT) return 0;
+ }
+ }
+
+ return ( bytes_received );
+}
+static usb_status_t usb_tx_processing(cyg_uint8* write_ptr, cyg_uint32 data_len)
+{
+ usb_status_t trans_status = USB_FAILURE;
+
+ /* Prepare the buffer descriptor for USB transfer */
+ usb_buffer_descriptor_t buf_desc;
+
+ /* Prepare transfer buffer descriptor*/
+ buf_desc.buffer = (void *)write_ptr;
+ buf_desc.size = data_len;
+ buf_desc.bytes_transfered = 0;
+
+ /* Send data over USB */
+ trans_status = usb_bulk_transmit_data(&buf_desc);
+
+ return trans_status;
+}
+static cyg_bool pl_get_command(void)
+{
+ cyg_uint8 i = 0;
+ usb_status_t status;
+ cyg_uint32 bytes_recvd = 0;
+ cyg_uint8 start_command = 0xFF;
+
+ while(start_command == 0xFF)
+ {
+ //g_timeout_value++;
+ //if(g_timeout_value%1000==0) D("C");
+ //D("%d\n",g_timeout_value);
+ bytes_recvd = usb_rx_processing(sdp_payload_data, &status, SDP_CMD_MAX_LEN);
+ start_command = pl_command_start();
+ if(g_timeout_value == USB_DOWNLOAD_TIMEOUT_LIMIT) return false;
+ }
+ //D("+USBDBGMSG: start_command = 0x%02X\n",start_command);
+ if(start_command == 0xF0)
+ {
+ //copy rest of the bytes
+ for(i=1; i < SDP_CMD_MAX_LEN; i++)
+ {
+ sdp_command[i] = sdp_payload_data[i-1];
+ }
+ }
+ else
+ {
+ //copy starting bytes
+ for(i=0; i < (SDP_CMD_MAX_LEN - start_command) ; i++)
+ {
+ sdp_command[i] = sdp_payload_data[i + start_command];
+ }
+
+ if(start_command != 0)
+ {
+ //receive rest of the bytes
+ bytes_recvd = usb_rx_processing(sdp_payload_data, &status, start_command);
+
+ if(bytes_recvd == start_command)
+ {
+ for(i=0; i <start_command; i++)
+ {
+ sdp_command[SDP_CMD_MAX_LEN - start_command + i] = sdp_payload_data[i];
+ }
+ }
+ }
+ }
+
+ return true;
+}
+static cyg_uint8 pl_command_start(void)
+{
+ cyg_uint8 i=0;
+ static cyg_uint8 last_byte = 0;
+
+ if(last_byte != 0x0)
+ {
+ if(last_byte == sdp_payload_data[0])
+ {
+ sdp_command[0] = last_byte;
+ last_byte = sdp_payload_data[SDP_CMD_MAX_LEN -1];
+ return 0xF0;
+ }
+ }
+
+ for(i=0; i < SDP_CMD_MAX_LEN -1; i++)
+ {
+ if((sdp_payload_data[i] == 0x01) && (sdp_payload_data[i+1] == 0x01) ||
+ (sdp_payload_data[i] == 0x02) && (sdp_payload_data[i+1] == 0x02) ||
+ (sdp_payload_data[i] == 0x03) && (sdp_payload_data[i+1] == 0x03) ||
+ (sdp_payload_data[i] == 0x04) && (sdp_payload_data[i+1] == 0x04) ||
+ (sdp_payload_data[i] == 0x05) && (sdp_payload_data[i+1] == 0x05) ||
+ (sdp_payload_data[i] == 0x06) && (sdp_payload_data[i+1] == 0x06) ||
+ (sdp_payload_data[i] == 0x07) && (sdp_payload_data[i+1] == 0x07) ||
+ (sdp_payload_data[i] == 0x08) && (sdp_payload_data[i+1] == 0x08) ||
+ (sdp_payload_data[i] == 0x09) && (sdp_payload_data[i+1] == 0x09) ||
+ (sdp_payload_data[i] == 0x0A) && (sdp_payload_data[i+1] == 0x0A))
+ {
+ return i;
+ }
+ }
+
+ //handle last byte
+ last_byte = sdp_payload_data[SDP_CMD_MAX_LEN -1];
+ if(!(last_byte == 0x1 || last_byte == 0x2 || last_byte == 0x3 || last_byte == 0x4 ||
+ last_byte == 0x5 || last_byte == 0x6 || last_byte == 0x7 || last_byte == 0x8 || last_byte == 0x8 ||
+ last_byte == 0x9))
+ {
+ last_byte = 0;
+ }
+
+ return 0xFF;
+}
+static cyg_uint8 pl_handle_command(cyg_uint8 g_error_status)
+{
+ cyg_uint16 Header = 0;
+ cyg_uint32 Address = 0;
+ cyg_uint32 ByteCount = 0;
+ cyg_uint32 g_error_statusAck = 0;
+ cyg_uint8 status = 0;
+ //int i;
+ /* Command Packet Format: Header(2)+Address(4)+Format(1)+ByteCount(4)+Data(4)+Execute(1) */
+ Header = ((sdp_command[0]<<8) | (sdp_command[1]));
+ Address = ((sdp_command[2]<<24) | (sdp_command[3]<<16) | (sdp_command[4] << 8) | (sdp_command[5]));
+ ByteCount = ((sdp_command[7]<<24) | (sdp_command[8]<<16) | (sdp_command[9] << 8) | (sdp_command[10]));
+
+ /* Save g_error_status ack */
+ g_error_statusAck = (cyg_uint32)((g_error_status<<24) | (g_error_status <<16) | (g_error_status<<8) | (g_error_status));
+ //D("+USBDBGMSG: Command Header 0x%04X\n",Header);
+ switch (Header)
+ {
+ case WRITE_FILE:
+ //D("+USBDBGMSG: usb download file to address 0x%08X, length %d\n",usb_download_address,ByteCount);
+ pl_handle_write_file(usb_download_address, ByteCount);
+ //pl_handle_write_file(Address, ByteCount);
+ //if(g_load_cycle==0) usb_download_address=Address;
+ //g_load_cycle ++;
+ usb_download_address += ByteCount;
+ usb_download_length +=ByteCount;
+ D(".");
+ if(ByteCount<BULK_TD_BUFFER_TOTAL_SIZE)
+ {
+ status = COMPLETE;
+ }
+ break;
+ case ERROR_STATUS_HEADER:
+ pl_command_ack(g_error_statusAck);
+ status = COMPLETE;
+ break;
+ case READ_FILE:
+ case WRITE_HEADER:
+ case READ_HEADER:
+ default:
+ break;
+ }
+
+ return status;
+
+}
+static void pl_handle_write_file(cyg_uint32 address, cyg_uint32 total_bytes)
+{
+ usb_status_t status;
+ usb_rx_processing((cyg_uint8*)address, &status, total_bytes);
+}
+
+static void pl_command_ack(cyg_uint32 ack)
+{
+ usb_tx_processing((cyg_uint8*)&ack, SDP_CMD_ACK_LEN);
+}
+
+void
+usbs_imx_otg_download(unsigned char * buffer, unsigned int length)
+{
+ cyg_bool bytes_recvd = false;
+ //D("+usbdownload: enter usbs_imx_otg_download\n");
+ //D("+USBDBGMSG: re-enumerate USB device\n");
+ /*enumeration*/
+ /*TODO*/
+ while(g_usb_dev_state!=USB_DEV_CONFIGURED_STATE)
+ {
+
+ /* Check if Bus Reset Received */
+ if((usbs_imx_otg_base->usbsts) & IMX_USB_STS_RESET)
+ {
+ /* Handle Bus Reset */
+ usbs_imx_otg_dev_handle_bus_reset();
+ }
+ /* Check if Reset is already received and Setup Token Received */
+ if((g_usb_dev_state != USB_DEV_DUMMY_STATE) && (usbs_imx_otg_base->endptsetupstat & BIT0))
+ {
+ /* Handle Setup Token */
+ usbs_imx_otg_dev_ep0_dsr();
+ }
+ }
+
+ if(g_usb_dev_state==USB_DEV_CONFIGURED_STATE)
+ {
+ //D("+USBDBGMSG: enumeration done\n");
+ /*file download*/
+ D("USB file download start\n");
+ g_timeout_value = 0;
+ usb_download_length = 0;
+ //usb_download_address = 0;
+ //g_load_cycle = 0;
+ while(1)
+ {
+
+ bytes_recvd = pl_get_command();
+ if(bytes_recvd == true)
+ {
+ g_usb_download_state = pl_handle_command(g_error_status);
+ }
+
+ if((g_usb_download_state==COMPLETE)||(g_timeout_value == USB_DOWNLOAD_TIMEOUT_LIMIT))
+ break;
+
+ }
+ diag_printf("\n");
+ if(g_timeout_value == USB_DOWNLOAD_TIMEOUT_LIMIT) //timeout value
+ D("USB download timeout to wait none file to download\n");
+ else
+ {
+ D("USB file download complete\n");
+ //D("+usbdownload: image base 0x%08X, length %d\n",usb_download_address,usb_download_length);
+ }
+
+ }
+}
+#endif
+
+//EOF
--- /dev/null
+# ====================================================================
+#
+# diagnosis.cdl
+#
+# diagnosis configuration data.
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2008 Freescale
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): Fred.Fan
+# Original data: Fred.Fan
+# Contributors:
+# Date: 2008-03-15
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DIAGNOSIS {
+ display "Diagnostic tools"
+ include_dir cyg/diagnosis
+# doc ref/services-diagnosis.html
+
+ description "
+ This package provides support for hardware diagnosis."
+
+ compile -library=libextras.a core.c
+
+ cdl_component CYGPKG_MEMORY_DIAGNOSIS {
+ display "memory diagnosis"
+ flavor bool
+
+ description "This option includes memory test cases."
+
+ compile -library=libextras.a memory/routine.S
+ cdl_option CYGSEM_RAM_RW_DIAGNOSIS {
+ display "perform ram read/write diagnosis"
+ flavor bool
+ default_value 1
+
+ description "
+ This option is overriden by the configuration in hal."
+
+ compile memory/ram_rw.c
+ }
+
+ cdl_option CYGSEM_RAM_PM_DIAGNOSIS {
+ display "perform ram performance diagnosis"
+ flavor bool
+ default_value 1
+
+ description "
+ This option is overriden by the configuration in hal."
+
+ compile memory/ram_pm.c
+ }
+ }
+
+ cdl_component CYGPKG_WDT_DIAGNOSIS {
+ display "watchdog diagnosis"
+ flavor bool
+
+ description "This option includes watchdog test cases."
+
+ compile -library=libextras.a
+ cdl_option CYGSEM_WDT_DIAGNOSIS {
+ display "perform watchdog diagnosis"
+ flavor bool
+ default_value 1
+
+ description "
+ This option is overriden by the configuration in hal."
+
+ compile wdt/wdt.c
+ }
+ }
+}
+
+
--- /dev/null
+#ifndef _DIAGNOSIS_H_
+#define _DIAGNOSIS_H_
+
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_cache.h>
+#include <redboot.h>
+#include <stdlib.h>
+
+#include <pkgconf/diagnosis.h>
+
+#ifdef CYGPKG_MEMORY_DIAGNOSIS
+#include <cyg/diagnosis/memory.h>
+#endif
+
+extern struct cmd __DIAGNOSIS_cmds_TAB__[], __DIAGNOSIS_cmds_TAB_END__;
+extern void diagnosis_usage(char *why);
+
+#endif /* _DIAGNOSIS_H_ */
--- /dev/null
+#ifndef __DIAGNOSIS_MEMORY_H_
+#define __DIAGNOSIS_MEMORY_H_
+
+extern void diagnosis_mem_read_block(unsigned long start, int size);
+extern void diagnosis_mem_write_block(unsigned long start, int size);
+extern int diagnosis_mem_copy_block(unsigned long start, unsigned long dest, int size);
+
+#ifdef CYGSEM_RAM_RW_DIAGNOSIS
+
+enum {
+DIAGNOSIS_MEM_RAM_RD = 0,
+};
+#endif
+
+#endif /* __DIAGNOSIS_MEMORY_H_ */
--- /dev/null
+#include <redboot.h>
+#include <stdlib.h>
+#include <cyg/diagnosis/diagnosis.h>
+
+#include CYGHWR_MEMORY_LAYOUT_H
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __DIAGNOSIS_cmds_TAB__, DIAGNOSIS_cmds);
+CYG_HAL_TABLE_END( __DIAGNOSIS_cmds_TAB_END__, DIAGNOSIS_cmds);
+
+// CLI function
+static cmd_fun do_diagnosis_cmds;
+RedBoot_nested_cmd("diag",
+ "Tools for system diagnostics",
+ "{cmds}",
+ do_diagnosis_cmds,
+ __DIAGNOSIS_cmds_TAB__, &__DIAGNOSIS_cmds_TAB_END__
+ );
+
+void diagnosis_usage(char *why)
+{
+ diag_printf("*** invalid 'diag' command: %s\n", why);
+ cmd_usage(__DIAGNOSIS_cmds_TAB__, &__DIAGNOSIS_cmds_TAB_END__, "diag ");
+}
+
+static void do_diagnosis_cmds(int argc, char *argv[])
+{
+ struct cmd * cmd;
+ if (argc < 2) {
+ diagnosis_usage("too few arguments");
+ return;
+ }
+ if ((cmd = cmd_search(__DIAGNOSIS_cmds_TAB__,
+ &__DIAGNOSIS_cmds_TAB_END__,
+ argv[1])) != (struct cmd *)0) {
+ (cmd->fun)(argc, argv);
+ return;
+ }
+ diagnosis_usage("unrecognized command");
+}
--- /dev/null
+#include <redboot.h>
+#include <stdlib.h>
+#include <cyg/diagnosis/diagnosis.h>
+#include <cyg/hal/plf_io.h>
+
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#define DEFAULT_TEST_TIME 2
+#define MIN_TEST_TIME 1
+#define MAX_TEST_TIME 20
+
+#define DEFAULT_BLOCK_SIZE 4096
+#define MAX_BLOCK_SIZE 32768
+#define MIN_BLOCK_SIZE 1024
+
+local_cmd_entry("ram_pm",
+ "ram performance test",
+ "-t time -b size [-m mode]\n"
+ " -t time: set test time\n"
+ " -b size: set block size < 8192\n"
+ " -m mode: set 0:read, 1:write, 2:copy\n",
+ ram_pm_test,
+ DIAGNOSIS_cmds
+);
+
+enum {
+ RAM_PM_READ = 0,
+ RAM_PM_WRITE,
+ RAM_PM_COPY,
+ RAM_PM_MAX,
+};
+
+static char * mode_str[RAM_PM_MAX] =
+{
+ "read",
+ "write",
+ "copy"
+};
+
+static inline void start_timer(int second)
+{
+ unsigned int reg;
+ reg = readl(CCM_BASE_ADDR + CLKCTL_CGR1);
+ writel(reg | 0x30, CCM_BASE_ADDR + CLKCTL_CGR1);
+
+ reg = readl(GPT_BASE_ADDR + GPTCR) | 0x8002;
+ writel(reg&(~1), GPT_BASE_ADDR + GPTCR);
+ while(readl(GPT_BASE_ADDR + GPTCR) & 0x8000);
+
+ reg = second * 1000;
+ writel(reg, GPT_BASE_ADDR + GPTOCR1);
+ writel(0, GPT_BASE_ADDR + GPTIR);
+ writel(0, GPT_BASE_ADDR + GPTCNT);
+ writel(31, GPT_BASE_ADDR + GPTPR);
+ writel(0x3F, GPT_BASE_ADDR + GPTSR);
+
+ reg = readl(GPT_BASE_ADDR + GPTCR) | 0x303;
+ writel(reg, GPT_BASE_ADDR + GPTCR);
+}
+
+static inline int get_time(int * cycles)
+{
+ *cycles = readl(GPT_BASE_ADDR + GPTCNT);
+ if (readl(GPT_BASE_ADDR + GPTSR)& 1)
+ *cycles -= readl(GPT_BASE_ADDR + GPTOCR1);
+ return readl(GPT_BASE_ADDR + GPTSR) & 1;
+}
+
+static inline void stop_timer(void)
+{
+ unsigned int reg;
+ reg = readl(GPT_BASE_ADDR + GPTCR) | 0x8000;
+ writel(reg&(~1), GPT_BASE_ADDR + GPTCR);
+}
+
+static int performance_read_write(int time, int bsize, int read)
+{
+ unsigned long start = CYGMEM_REGION_ram + 1*1024*1024;
+ int size = CYGMEM_REGION_ram_SIZE / 2;
+ int cycles;
+ long long i;
+
+ if ( (bsize % 32) || (size % bsize) || size < (1*1024*1024)) {
+ diag_printf("size is illegal(size=%d)\n", size);
+ }
+
+ size = (size / bsize) * bsize;
+ diag_printf("%s:size=%d, bsize=%d\n", read?"READ":"WRITE", size, bsize);
+ start_timer(time);
+ for (i=0; !get_time(&cycles); i += bsize) {
+ if (read)
+ diagnosis_mem_read_block(start + (i % size), bsize);
+ else
+ diagnosis_mem_write_block(start + (i % size), bsize);
+ }
+ stop_timer();
+ diag_printf("Finished size=%ld ", i);
+ diag_printf("time=%d", time);
+ diag_printf(" %d(ms)\n", cycles);
+ i = (i * 1000) / ((time * 1000) + cycles);
+ return i / 1024;
+}
+
+static int performance_copy(int time, int bsize)
+{
+ unsigned long start = CYGMEM_REGION_ram + 1 * 1024 * 1024;
+ unsigned long dest = start + 1 * 1024 * 1024;
+ int size = CYGMEM_REGION_ram_SIZE / 4;
+ int cycles;
+ long long i;
+
+ dest += size;
+
+ if ( (bsize % 32) || (size % bsize) || size < (1 * 1024 * 1024)) {
+ diag_printf("size is illegal(size=%d)\n", size);
+ }
+
+ start_timer(time);
+
+ size = (size / bsize) * bsize;
+ for (i = 0; !get_time(&cycles); i += bsize) {
+ if (diagnosis_mem_copy_block(start + (i % size),
+ dest + (i % size), bsize)
+ < 0) {
+ diag_printf("verify data fail\n");
+ break;
+ }
+ }
+ stop_timer();
+ i = (i * 1000) / ((time * 1000) + cycles);
+ return i / 1024;
+}
+
+static void ram_pm_test(int argc, char * argv[])
+{
+ int opts_map[3];
+ struct option_info opts[3];
+ int time, mode, result, bsize;
+
+ memset(opts_map, 0, sizeof(int)*2);
+ init_opts(&opts[0], 't', true, OPTION_ARG_TYPE_NUM,
+ (void *)&time, (bool *)&opts_map[0], "test time");
+ init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&bsize, (bool *)&opts_map[1], "block size");
+ init_opts(&opts[2], 'm', true, OPTION_ARG_TYPE_NUM,
+ (void *)&mode, (bool *)&opts_map[2], "operate mode");
+
+ if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0)) {
+ diagnosis_usage("invalid arguments");
+ return;
+ }
+
+ if (!opts_map[0] || time < MIN_TEST_TIME || time > MAX_TEST_TIME)
+ time = DEFAULT_TEST_TIME;
+
+ if(!opts_map[1] || bsize < MIN_BLOCK_SIZE || bsize > MAX_BLOCK_SIZE)
+ bsize = DEFAULT_BLOCK_SIZE;
+
+ if (!opts_map[2] || mode >= RAM_PM_MAX)
+ mode = RAM_PM_READ;
+
+ diag_printf("Start memory performance test (%s)...\n",
+ mode_str[mode]);
+ switch(mode) {
+ case RAM_PM_READ:
+ result = performance_read_write(time, bsize, 1);
+ break;
+ case RAM_PM_WRITE:
+ result = performance_read_write(time, bsize, 0);
+ break;
+ case RAM_PM_COPY:
+ result = performance_copy(time, bsize);
+ break;
+ default:
+ result = -1;
+ }
+ if (result < 0) {
+ diag_printf("memory performance test fails\n");
+ } else {
+ diag_printf("memory performance test success:%d.%d(MB/s)\n",
+ result / 1024, (result % 1024));
+ }
+}
--- /dev/null
+#include <redboot.h>
+#include <stdlib.h>
+#include <cyg/diagnosis/diagnosis.h>
+#include <cyg/hal/plf_io.h>
+
+#include CYGHWR_MEMORY_LAYOUT_H
+
+static int loops1;
+static unsigned int pattern1, pattern2;
+static unsigned int start;
+static int length;
+static int burst = 0;
+
+local_cmd_entry("ram_rw",
+ "ram read/write accessing",
+ "-c iterators -b <base address> -l <length> "\
+ "-p pattern -m case [-s]\n",
+ ram_rw_test,
+ DIAGNOSIS_cmds
+);
+
+local_cmd_entry("memcpybm",
+ "ram memory copy benchmarking",
+ "-c <loops> -s <start size KB> -e <end size KB> -a <source align Byte> -b <dest align Byte>\n",
+ memcpybm,
+ DIAGNOSIS_cmds
+);
+
+static void raw_rw_case1(void)
+{
+ unsigned int * current_write;
+ unsigned int * current_read;
+ int round = 0;
+ diag_printf("RAM diagnostical pattern from David.Young of freescale\n");
+ diag_printf("burst is %s\n", burst?"enabled":"disabled");
+ while( (round++) < loops1) {
+ if (_rb_break(0))
+ return;
+ if(burst) {
+ current_write =(unsigned int *)start;
+ memset(current_write, (pattern1&0xFF000000)>>24, length);
+ } else {
+ for(current_write=(unsigned int *)start; current_write<(unsigned int *)(start + length); current_write += 2) {
+ *current_write = ((unsigned int)current_write & 0x0000FFFF)|(0xFFFF0000 & pattern1);
+ }
+ for(current_write=(unsigned int *)start + 1; current_write<(unsigned int *)(start + length); current_write += 2) {
+ *current_write = ((unsigned int)current_write & 0x0000FFFF)|(0xFFFF0000 & pattern2);
+ }
+ }
+ for(current_read=(unsigned int *)start; current_read<(unsigned int *)(start + length); current_read ++) {
+ if(burst) {
+ if((*current_read) != pattern2) {
+ diag_printf("\tround %d::[0x%08x]=0x%08x:0x%08x\n", round, current_read, pattern2, *current_read);
+ goto fail;
+ }
+ } else {
+ if((current_read - (unsigned int *)start) & 1) {
+ if(((*current_read)&0xFFFF0000) != (pattern2&0xFFFF0000)) {
+ diag_printf("\tround %d::[0x%08x]=0x%08x:0x%08x\n", round, current_read, (pattern2&0xFFFF0000)|((unsigned int)current_read)&0xFFFF, *current_read);
+ goto fail;
+ }
+ } else {
+ if(((*current_read)&0xFFFF0000) != (pattern1&0xFFFF0000)) {
+ diag_printf("\tround %d::[0x%08x]=0x%08x:0x%08x\n", round, current_read, (pattern1&0xFFFF0000)|((unsigned int)current_read)&0xFFFF, *current_read);
+ goto fail;
+ }
+ }
+ }
+ }
+ }
+ diag_printf("Diagnosis is successful!\n");
+ return;
+fail:
+ diag_printf("Diagnosis is failure !\n");
+}
+
+static void ram_rw_test(int argc, char * argv[])
+{
+ int opts_map[6];
+ struct option_info opts[6];
+ int mode;
+
+ memset(opts_map, 0, sizeof(int)*6);
+
+ init_opts(&opts[0], 'c', true, OPTION_ARG_TYPE_NUM,
+ (void *)&loops1, (bool *)&opts_map[0], "the rounds of test");
+ init_opts(&opts[1], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&start, (bool *)&opts_map[1], "accessing start address");
+ init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&opts_map[2], "accessing size(bytes)");
+ init_opts(&opts[3], 'p', true, OPTION_ARG_TYPE_NUM,
+ (void *)&pattern1, (bool *)&opts_map[3], "High 16bit is valid");
+ init_opts(&opts[4], 'm', true, OPTION_ARG_TYPE_NUM,
+ (void *)&mode, (bool *)&opts_map[4], "Test case number");
+ init_opts(&opts[5], 's', false, OPTION_ARG_TYPE_FLG,
+ (void *)&burst, (bool *)0, "enable bust mode(based on memset)");
+
+ if (!scan_opts(argc, argv, 2, opts, 6, 0, 0, 0)) {
+ diagnosis_usage("invalid arguments");
+ return;
+ }
+
+ if(!opts_map[0]) {
+ loops1 = 32;
+ }
+
+ if(!opts_map[1]) {
+ start = 0x80000;
+ }
+
+ if(!opts_map[2]) {
+ length = 8192;
+ }
+
+ if(!opts_map[3]) {
+ pattern1 = 0x55550000;
+ }
+
+ if(!opts_map[4]) {
+ mode = DIAGNOSIS_MEM_RAM_RD;
+ }
+
+ if(burst) {
+ pattern2 = (pattern1&0xFF000000);
+ pattern2 |= pattern2>>8;
+ pattern2 |= pattern2>>16;
+ } else {
+ pattern2 = (~pattern1)&0xFFFF0000;
+ }
+
+ if(!valid_address((unsigned char *)start)) {
+ if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)start))
+ return;
+ }
+
+ switch(mode) {
+ case DIAGNOSIS_MEM_RAM_RD:
+ raw_rw_case1();
+ break;
+ default:
+ diag_printf("Invalid memory diagnosis case!\n");
+ }
+}
+
+/* Defines */
+#define SIZE_1K 1024
+#define SIZE_4K (4*SIZE_1K)
+#define SIZE_1M (1024*1024)
+#define START_SIZE (2*SIZE_1K)
+#define END_SIZE SIZE_1M
+#define ALIGN SIZE_4K
+#define START_LOOPS 200000
+
+#define OPT_SIZE 5
+#define printf diag_printf
+#define CLOCKS_PER_SEC 32768
+extern unsigned int hal_timer_count(void);
+#define clock() hal_timer_count()
+
+//#define memcpy diagnosis_mem_copy_block
+static void memcpybm(int argc, char * argv[])
+{
+ int opts_map[OPT_SIZE];
+ struct option_info opts[OPT_SIZE];
+ int mode;
+ int size = START_SIZE / SIZE_1K;
+ int end_size = END_SIZE / SIZE_1K;
+ int salign = ALIGN;
+ int dalign = ALIGN;
+ int loops = START_LOOPS / 1000;
+ int src, dst, asrc, adst;
+
+
+ memset(opts_map, 0, sizeof(int)*OPT_SIZE);
+
+ init_opts(&opts[0], 'c', true, OPTION_ARG_TYPE_NUM,
+ (void *)&loops, (bool *)&opts_map[0], "the rounds of test in thousands");
+ init_opts(&opts[1], 's', true, OPTION_ARG_TYPE_NUM,
+ (void *)&size, (bool *)&opts_map[1], "start size in KB");
+ init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
+ (void *)&end_size, (bool *)&opts_map[2], "end size in KB");
+ init_opts(&opts[3], 'a', true, OPTION_ARG_TYPE_NUM,
+ (void *)&salign, (bool *)&opts_map[3], "source align in byte");
+ init_opts(&opts[4], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&dalign, (bool *)&opts_map[4], "destination align in byte");
+
+ if (!scan_opts(argc, argv, 2, opts, OPT_SIZE, 0, 0, 0)) {
+ diagnosis_usage("invalid arguments");
+ return;
+ }
+
+ loops *= 1000;
+ size *= SIZE_1K;
+ end_size *= SIZE_1K;
+ /* Allocate buffers */
+ if ((src = (int) malloc(end_size + salign + SIZE_4K)) == 0) {
+ printf("%s: insufficient memory\n", argv[0]);
+ return;
+ }
+ memset((void*)src, 0xaa, end_size + salign + SIZE_4K);
+ if ((dst = (int) malloc(end_size + dalign + SIZE_4K)) == 0) {
+ free((void*)src);
+ printf("%s: insuficient memory\n", argv[0]);
+ return;
+ }
+ memset((void*)dst, 0x55, end_size + dalign + SIZE_4K);
+
+ /* Align buffers */
+ if (src % SIZE_4K == 0)
+ asrc = src + salign;
+ else
+ asrc = src + SIZE_4K - (src % SIZE_4K) + salign;
+ if (dst % SIZE_4K == 0)
+ adst = dst + dalign;
+ else
+ adst = dst + SIZE_4K - (dst % SIZE_4K) + dalign;
+
+ /* Print Banner */
+ printf("\nMEMCPY Benchmark\n\n");
+ printf("Src Buffer 0x%08x\n", asrc);
+ printf("Dst Buffer 0x%08x\n\n", adst);
+ printf("%10s %10s\n", "Cached", "Bandwidth");
+ printf("%10s %10s\n", "(KBytes)", "(MB/sec)");
+
+ /* Loop over copy sizes */
+ while (size <= end_size)
+ {
+ unsigned int start_time;
+ unsigned int elapsed_time;
+ int loop;
+ unsigned long long sz;
+
+ printf("%10d", size / SIZE_1K);
+
+ /* Do data copies */
+ start_time = clock();
+ for (loop = 0; loop < loops; loop++)
+ memcpy((void*)adst, (void*)asrc, size);
+ elapsed_time = (clock() - start_time);
+
+ sz = size *loops * 2;
+ printf(" %d", sz*CLOCKS_PER_SEC/elapsed_time/SIZE_1M);
+ printf("\t elapsed=%d", elapsed_time);
+ printf("\tsize=%d, loops=%d, sz=%d", size, loops, sz);
+ printf("\n");
+
+/*
+ printf(" %10.0f\n", ((float)size*loops*2)/elapsed_time/SIZE_1M);
+ printf(" %d.%d.%d\n", elapsed_time / CLOCKS_PER_SEC,
+ (elapsed_time % CLOCKS_PER_SEC) * 1000 / CLOCKS_PER_SEC,
+ (((elapsed_time % CLOCKS_PER_SEC) * 1000) % CLOCKS_PER_SEC) * 1000 / CLOCKS_PER_SEC);
+*/
+ /* Adjust for next test */
+ size *= 2;
+ loops /= 2;
+ }
+
+ /* Free buffers */
+ free((void*)src);
+ free((void*)dst);
+}
+
--- /dev/null
+ .text
+/*
+ * void diagnosis_mem_read_block(unsigned long start, int size)
+ */
+ .global diagnosis_mem_read_block
+diagnosis_mem_read_block:
+ stmdb sp!, {r2 - r9}
+ add r1, r1, r0
+1: cmp r0, r1
+ ldmloia r0!, {r2-r9}
+ blo 1b
+ ldmia sp!, {r2 - r9}
+ mov pc, lr
+/*
+ * void diagnosis_mem_write_block(unsigned long start, int size)
+ */
+ .global diagnosis_mem_write_block
+diagnosis_mem_write_block:
+ stmdb sp!, {r2 - r9}
+ add r1, r1, r0
+1: cmp r0, r1
+ stmloia r0!, {r2 - r9}
+ blo 1b
+ ldmia sp!, {r2 - r9}
+ mov pc, lr
+/*
+ * int diagnosis_mem_copy_block(unsigned long start, unsigned long dest, int size)
+ */
+ .global diagnosis_mem_copy_block
+diagnosis_mem_copy_block:
+ stmdb sp!, {r3 - r11}
+ stmdb sp!, {r0, r1}
+ add r11, r1, r2
+1: cmp r1, r11
+ ldmloia r0!, {r3-r10}
+ stmloia r1!, {r3-r10}
+ blo 1b
+ ldmia sp!, {r0, r1}
+1: cmp r1, r11
+ movhs r0, #0
+ bhs 2f
+ ldrlo r3, [r0], #4
+ ldrlo r4, [r1], #4
+ cmp r3, r4
+ beq 1b
+ mov r0, #-1
+2: ldmia sp!, {r3 - r11}
+ mov pc, lr
--- /dev/null
+#include <redboot.h>
+#include <stdlib.h>
+#include <cyg/diagnosis/diagnosis.h>
+#include <cyg/hal/plf_io.h>
+
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#define WDT_WCR 0x00
+#define WDT_WSR 0x02
+
+#define WDT_CNT_MASK 0xFF00
+#define WDT_WCR_MASK 0xFF
+#define WDT_CNT_OFF 8
+
+#define WDT_WCR_WDW (1 << 7)
+#define WDT_WCR_WOE (1 << 6)
+#define WDT_WCR_WDA (1 << 5)
+#define WDT_WCR_SRS (1 << 4)
+#define WDT_WCR_WDT (1 << 3)
+#define WDT_WCR_WDE (1 << 2)
+#define WDT_WCR_WDBG (1 << 1)
+#define WDT_WCR_WDZST (1)
+
+#define WDT_MAGIC_1 (0x5555)
+#define WDT_MAGIC_2 (0xAAAA)
+
+local_cmd_entry("wdt",
+ "watchdog test:Warning after run test, please reboot",
+ "-s sleep_time -t timeout [-c ctrl_bits] -b\n"
+ "-b:Insert memory access during ping operation\n",
+ wdt_test,
+ DIAGNOSIS_cmds
+);
+
+static unsigned char wdt_wcr;
+
+static unsigned int wdt_ping_mode;
+
+static inline void wdt_setup(unsigned int timeout)
+{
+ unsigned short int reg;
+ reg = readw(WDOG_BASE_ADDR + WDT_WCR) & WDT_WCR_MASK;
+ reg |= (timeout * 2 << WDT_CNT_OFF) & WDT_CNT_MASK;
+
+ if (wdt_wcr)
+ reg |= wdt_wcr & WDT_WCR_MASK;
+ else
+ reg |= WDT_WCR_WOE | WDT_WCR_WDA | WDT_WCR_SRS|
+ WDT_WCR_WDBG | WDT_WCR_WDZST;
+
+ diag_printf("WCR=%x\n", reg | WDT_WCR_WDE);
+ writew(reg | WDT_WCR_WDE, WDOG_BASE_ADDR + WDT_WCR);
+}
+
+static inline void wdt_stop(void)
+{
+ unsigned short int reg;
+ reg = readw(WDOG_BASE_ADDR + WDT_WCR) & (~WDT_WCR_WDE);
+ reg |= WDT_CNT_MASK;
+ writew(reg, WDOG_BASE_ADDR + WDT_WCR);
+}
+
+static inline void wdt_keepalive(void)
+{
+ int j;
+ volatile unsigned int i;
+
+ if (wdt_ping_mode) {
+ writew(WDT_MAGIC_1, WDOG_BASE_ADDR + WDT_WSR);
+ for (i = 0, j &= 0x7; i <= j; i++)
+ asm("nop");
+ } else {
+ writew(WDT_MAGIC_1, WDOG_BASE_ADDR + WDT_WSR);
+ }
+ writew(WDT_MAGIC_2, WDOG_BASE_ADDR + WDT_WSR);
+}
+
+static void wdt_sleep(int second)
+{
+ int i;
+ unsigned int delayCount = 32000;
+
+ for ( i = 0; i < second; i++) {
+ writel(0x01, EPIT_BASE_ADDR + EPITSR);
+ writel(delayCount, EPIT_BASE_ADDR + EPITLR);
+ while ((0x1 & readl(EPIT_BASE_ADDR + EPITSR)) == 0);
+ }
+}
+
+static void wdt_test(int argc, char * argv[])
+{
+ int opts_map[4];
+ struct option_info opts[4];
+ unsigned int sleep_timeout;
+ unsigned int wdt_timeout;
+
+ memset(opts_map, 0, sizeof(int)*4);
+
+ init_opts(&opts[0], 's', true, OPTION_ARG_TYPE_NUM,
+ (void *)&sleep_timeout, (bool *)&opts_map[0], "sleep time");
+ init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM,
+ (void *)&wdt_timeout, (bool *)&opts_map[1], "watchdog timeout");
+ init_opts(&opts[2], 'c', true, OPTION_ARG_TYPE_NUM,
+ (void *)&wdt_wcr, (bool *)&opts_map[2], "watchdog control bits");
+ init_opts(&opts[3], 'b', false, OPTION_ARG_TYPE_FLG,
+ (void *)&wdt_ping_mode, (bool *)0, "Add nop between ping operation");
+
+ if (!scan_opts(argc, argv, 2, opts, 4, 0, 0, 0)) {
+ diagnosis_usage("invalid arguments");
+ return;
+ }
+
+ if(!opts_map[0]) {
+ sleep_timeout = 1;
+ }
+
+ if(!opts_map[1]) {
+ wdt_timeout = 2;
+ }
+
+ if(!opts_map[2]) {
+ wdt_wcr = 0;
+ }
+
+ diag_printf("Watchdog sleeptime=%d timeout=%d %s in ping",
+ sleep_timeout, wdt_timeout,
+ wdt_ping_mode?"Add memory access":"No memory access");
+ wdt_setup(wdt_timeout);
+
+ while(1) {
+ if(_rb_break(0)) {
+ diag_printf("break Watchdog test\n");
+ wdt_sleep(wdt_timeout*2);
+ break;
+ }
+ wdt_keepalive();
+ wdt_sleep(sleep_timeout);
+ }
+ wdt_stop();
+ diag_printf("Exit Watchdog test\n");
+}