From: lothar Date: Fri, 13 Feb 2009 19:19:53 +0000 (+0000) Subject: Initial revision X-Git-Tag: v1.5.3~61 X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-redboot.git;a=commitdiff_plain;h=0f7b702a94a73bd594f31ef97f2a4d36d9ef4a66 Initial revision --- diff --git a/packages/devs/eth/arm/imx_3stack/v2_0/cdl/board_eth_drivers.cdl b/packages/devs/eth/arm/imx_3stack/v2_0/cdl/board_eth_drivers.cdl new file mode 100644 index 00000000..886425f2 --- /dev/null +++ b/packages/devs/eth/arm/imx_3stack/v2_0/cdl/board_eth_drivers.cdl @@ -0,0 +1,95 @@ +# ==================================================================== +# +# 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 " + puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_SMSC_LAN92XX_CFG " + 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" + } + } + } +} diff --git a/packages/devs/eth/arm/imx_3stack/v2_0/include/devs_eth_arm_board.inl b/packages/devs/eth/arm/imx_3stack/v2_0/include/devs_eth_arm_board.inl new file mode 100644 index 00000000..3820473d --- /dev/null +++ b/packages/devs/eth/arm/imx_3stack/v2_0/include/devs_eth_arm_board.inl @@ -0,0 +1,101 @@ +//========================================================================== +// +// 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 // CYGNUM_HAL_INTERRUPT_ETHR +#include + +#ifdef CYGPKG_REDBOOT +#include +#ifdef CYGSEM_REDBOOT_FLASH_CONFIG +#include +#include +#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 + +#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 diff --git a/packages/devs/eth/smsc/lan92xx/v2_0/cdl/smsc_lan92xx_eth_drivers.cdl b/packages/devs/eth/smsc/lan92xx/v2_0/cdl/smsc_lan92xx_eth_drivers.cdl new file mode 100644 index 00000000..fcbeb5c9 --- /dev/null +++ b/packages/devs/eth/smsc/lan92xx/v2_0/cdl/smsc_lan92xx_eth_drivers.cdl @@ -0,0 +1,88 @@ +# ==================================================================== +# +# 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 "; + 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." + } + } +} diff --git a/packages/devs/eth/smsc/lan92xx/v2_0/include/smsc_lan92xx.h b/packages/devs/eth/smsc/lan92xx/v2_0/include/smsc_lan92xx.h new file mode 100644 index 00000000..edab0b4e --- /dev/null +++ b/packages/devs/eth/smsc/lan92xx/v2_0/include/smsc_lan92xx.h @@ -0,0 +1,187 @@ +#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 +#include + +#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 diff --git a/packages/devs/eth/smsc/lan92xx/v2_0/src/if_lan92xx.c b/packages/devs/eth/smsc/lan92xx/v2_0/src/if_lan92xx.c new file mode 100644 index 00000000..9b0de148 --- /dev/null +++ b/packages/devs/eth/smsc/lan92xx/v2_0/src/if_lan92xx.c @@ -0,0 +1,702 @@ +//========================================================================== +// +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CYGPKG_NET +#include +#include +#include /* 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; jtx_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 + ); diff --git a/packages/devs/flash/arm/imx_3stack/v2_0/cdl/flash_board_spansion.cdl b/packages/devs/flash/arm/imx_3stack/v2_0/cdl/flash_board_spansion.cdl new file mode 100644 index 00000000..6f2a22c8 --- /dev/null +++ b/packages/devs/flash/arm/imx_3stack/v2_0/cdl/flash_board_spansion.cdl @@ -0,0 +1,71 @@ +# ==================================================================== +# +# 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 +} diff --git a/packages/devs/flash/arm/imx_3stack/v2_0/src/board_spansionflash.c b/packages/devs/flash/arm/imx_3stack/v2_0/src/board_spansionflash.c new file mode 100644 index 00000000..9743dbf8 --- /dev/null +++ b/packages/devs/flash/arm/imx_3stack/v2_0/src/board_spansionflash.c @@ -0,0 +1,73 @@ +//========================================================================== +// +// 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 +// Contributors: Patrick Doyle +// Date: 2002-11-26 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include + +//-------------------------------------------------------------------------- +// 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" diff --git a/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_spansion.cdl b/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_spansion.cdl new file mode 100644 index 00000000..6b039032 --- /dev/null +++ b/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_spansion.cdl @@ -0,0 +1,71 @@ +# ==================================================================== +# +# 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 +} diff --git a/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_strata.cdl b/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_strata.cdl new file mode 100644 index 00000000..070f8b38 --- /dev/null +++ b/packages/devs/flash/arm/mx35evb/v2_0/cdl/flash_board_strata.cdl @@ -0,0 +1,80 @@ +# ==================================================================== +# +# 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 " + puts $::cdl_system_header "#define CYGDAT_DEVS_FLASH_STRATA_CFG " + puts $::cdl_system_header "/***** strataflash driver proc output end *****/" + } +} + diff --git a/packages/devs/flash/arm/mx35evb/v2_0/include/board_strataflash.inl b/packages/devs/flash/arm/mx35evb/v2_0/include/board_strataflash.inl new file mode 100644 index 00000000..ee8a1c56 --- /dev/null +++ b/packages/devs/flash/arm/mx35evb/v2_0/include/board_strataflash.inl @@ -0,0 +1,64 @@ +#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 diff --git a/packages/devs/flash/arm/mx35evb/v2_0/src/board_spansionflash.c b/packages/devs/flash/arm/mx35evb/v2_0/src/board_spansionflash.c new file mode 100644 index 00000000..9743dbf8 --- /dev/null +++ b/packages/devs/flash/arm/mx35evb/v2_0/src/board_spansionflash.c @@ -0,0 +1,73 @@ +//========================================================================== +// +// 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 +// Contributors: Patrick Doyle +// Date: 2002-11-26 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include + +//-------------------------------------------------------------------------- +// 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" diff --git a/packages/devs/flash/arm/mxc/v2_0/include/card_mx32.h b/packages/devs/flash/arm/mxc/v2_0/include/card_mx32.h new file mode 100644 index 00000000..0da935da --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/card_mx32.h @@ -0,0 +1,314 @@ +#ifndef CARD_MX32_H +#define CARD_MX32_H + +#include + +/*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 diff --git a/packages/devs/flash/arm/mxc/v2_0/include/imx_nfc.h b/packages/devs/flash/arm/mxc/v2_0/include/imx_nfc.h new file mode 100644 index 00000000..d8f5704b --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/imx_nfc.h @@ -0,0 +1,105 @@ +#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 +// Contributors: Kevin Zhang +// 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_ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/imx_spi_nor.h b/packages/devs/flash/arm/mxc/v2_0/include/imx_spi_nor.h new file mode 100644 index 00000000..a6433b35 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/imx_spi_nor.h @@ -0,0 +1,99 @@ +#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 +// Contributors: Kevin Zhang +// 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_ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxc_ata.h b/packages/devs/flash/arm/mxc/v2_0/include/mxc_ata.h new file mode 100644 index 00000000..fe475447 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxc_ata.h @@ -0,0 +1,130 @@ +#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 +// Contributors: Mahesh Mahadevan +// 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_ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxc_mmc.h b/packages/devs/flash/arm/mxc/v2_0/include/mxc_mmc.h new file mode 100644 index 00000000..42dc3319 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxc_mmc.h @@ -0,0 +1,47 @@ +/*================================================================================= + + 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 + +#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__ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h b/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h new file mode 100644 index 00000000..cacf665a --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxc_nfc_v3.h @@ -0,0 +1,318 @@ +#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 +// Contributors: Kevin Zhang +// Date: 2008-06-02 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#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_ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_core.h b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_core.h new file mode 100644 index 00000000..04774da3 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_core.h @@ -0,0 +1,154 @@ +#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_ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_host.h b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_host.h new file mode 100644 index 00000000..20060484 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_host.h @@ -0,0 +1,257 @@ +#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 +// Contributors: Lewis Liu +// Date: 2008-05-13 Initial version +// Purpose: +// Description: +// +// +//####DESCRIPTIONEND#### +//==================================================================================================== + +#include + + +#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_ */ diff --git a/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_mmc.h b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_mmc.h new file mode 100644 index 00000000..697aa3d6 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/mxcmci_mmc.h @@ -0,0 +1,94 @@ +#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 +// Contributors: Lewis Liu +// 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_ */ + diff --git a/packages/devs/flash/arm/mxc/v2_0/include/spi_nor_parts.inl b/packages/devs/flash/arm/mxc/v2_0/include/spi_nor_parts.inl new file mode 100644 index 00000000..cbae3bdc --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/include/spi_nor_parts.inl @@ -0,0 +1,60 @@ +#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 +// Contributors: Kevin Zhang +// 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 diff --git a/packages/devs/flash/arm/mxc/v2_0/src/card_mx32.c b/packages/devs/flash/arm/mxc/v2_0/src/card_mx32.c new file mode 100644 index 00000000..d9dd0c3e --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/card_mx32.c @@ -0,0 +1,1092 @@ +// ========================================================================== +// +// 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 +// Contributors: Ivan Xu +// 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 +#include +#include +#include + +//#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; +} + + diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxc_ata.c b/packages/devs/flash/arm/mxc/v2_0/src/mxc_ata.c new file mode 100644 index 00000000..fea3e93d --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxc_ata.c @@ -0,0 +1,490 @@ +//========================================================================== +// +// 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 +// Contributors: Mahesh Mahadevan +// Date: 2008-11-18 Initial version +// +//========================================================================== +// + +#include +#include +#include +#include + +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 -b -l ", + ata_read_buf + ); + +static void ata_program_buf(int argc, char *argv[]); +RedBoot_cmd("ata_write", + "Write Ata", + "-f -b -l ", + 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); +} + diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxc_mmc.c b/packages/devs/flash/arm/mxc/v2_0/src/mxc_mmc.c new file mode 100644 index 00000000..9ecd22ee --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxc_mmc.c @@ -0,0 +1,252 @@ +// ========================================================================== +// +// 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 +// Contributors: Lewis Liu +// 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 +#include +#include +#ifdef CYGPKG_REDBOOT_HAL_OPTIONS + #include +#endif +#include +#define _FLASH_PRIVATE_ +#include +#include + +#if defined(CYGPKG_HAL_ARM_MX31ADS) || defined(CYGPKG_HAL_ARM_MX31_3STACK) + #include +#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 +#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"); +} diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_core.c b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_core.c new file mode 100644 index 00000000..56b7e41f --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_core.c @@ -0,0 +1,481 @@ +// ========================================================================== +// +// 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 +// Contributors: Lewis Liu +// Date: 2008-05-13 Initial version +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include +#include +#include + +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; + } +} diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_host.c b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_host.c new file mode 100644 index 00000000..04b5ea1d --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_host.c @@ -0,0 +1,491 @@ +// ========================================================================== +// +// 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 +// Contributors: Lewis Liu +// Date: 2008-05-13 Initial version +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include +#include +#include + +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; +} diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_mmc.c b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_mmc.c new file mode 100644 index 00000000..11c33a9e --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_mmc.c @@ -0,0 +1,694 @@ +// ========================================================================== +// +// 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 +// Contributors: Lewis Liu +// Date: 2008-05-13 Initial version +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include +#include + +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 */ diff --git a/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_sd.c b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_sd.c new file mode 100644 index 00000000..e2fa4710 --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/mxcmci_sd.c @@ -0,0 +1,588 @@ +// ========================================================================== +// +// 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 +// Contributors: Lewis Liu +// Date: 2008-05-13 Initial version +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include + +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 */ diff --git a/packages/devs/flash/arm/mxc/v2_0/src/spi_nor.c b/packages/devs/flash/arm/mxc/v2_0/src/spi_nor.c new file mode 100644 index 00000000..323f569c --- /dev/null +++ b/packages/devs/flash/arm/mxc/v2_0/src/spi_nor.c @@ -0,0 +1,598 @@ +//========================================================================== +// +// 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 +#include +#include +#include CYGHWR_MEMORY_LAYOUT_H +#include +#define _FLASH_PRIVATE_ +#include + +#include +#include + +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 + +// 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 +}; + +#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", + " ", + 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 \n"); + diag_printf("\tWrite: spiflash \n"); + diag_printf("\tErase: spiflash \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; +} diff --git a/packages/devs/i2c/arm/mxc/v2_0/cdl/mxc_i2c.cdl b/packages/devs/i2c/arm/mxc/v2_0/cdl/mxc_i2c.cdl new file mode 100644 index 00000000..5d4fffa9 --- /dev/null +++ b/packages/devs/i2c/arm/mxc/v2_0/cdl/mxc_i2c.cdl @@ -0,0 +1,55 @@ +# ==================================================================== +# +# 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 +} diff --git a/packages/devs/i2c/arm/mxc/v2_0/include/mxc_i2c.h b/packages/devs/i2c/arm/mxc/v2_0/include/mxc_i2c.h new file mode 100644 index 00000000..2c76ef79 --- /dev/null +++ b/packages/devs/i2c/arm/mxc/v2_0/include/mxc_i2c.h @@ -0,0 +1,83 @@ +//========================================================================== +// +// 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__ */ diff --git a/packages/devs/i2c/arm/mxc/v2_0/src/mxc_i2c.c b/packages/devs/i2c/arm/mxc/v2_0/src/mxc_i2c.c new file mode 100644 index 00000000..88c3d1d8 --- /dev/null +++ b/packages/devs/i2c/arm/mxc/v2_0/src/mxc_i2c.c @@ -0,0 +1,480 @@ +//========================================================================== +// +// 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 +#include +#include +#include +#include +#include + +#include +#include + +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", + " []]", + 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 \n"); + diag_printf("\tWrite: i2c \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)", + " ", + do_i2c_init + ); + +static void do_i2c_init(int argc,char *argv[]) +{ + unsigned freq; + + if (argc == 1 || argc != 5) { + diag_printf("\ni2c_init \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); +} diff --git a/packages/devs/pmic/arm/mx25_3stack/v2_0/cdl/mc34704.cdl b/packages/devs/pmic/arm/mx25_3stack/v2_0/cdl/mc34704.cdl new file mode 100644 index 00000000..260db5b7 --- /dev/null +++ b/packages/devs/pmic/arm/mx25_3stack/v2_0/cdl/mc34704.cdl @@ -0,0 +1,85 @@ +# ==================================================================== +# +# 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 "; + } + + 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 + } +} diff --git a/packages/devs/pmic/arm/mx25_3stack/v2_0/include/mc34704.h b/packages/devs/pmic/arm/mx25_3stack/v2_0/include/mc34704.h new file mode 100644 index 00000000..cb1d2f5b --- /dev/null +++ b/packages/devs/pmic/arm/mx25_3stack/v2_0/include/mc34704.h @@ -0,0 +1,47 @@ +//========================================================================== +// +// 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__ */ diff --git a/packages/devs/pmic/arm/mx25_3stack/v2_0/src/mc34704.c b/packages/devs/pmic/arm/mx25_3stack/v2_0/src/mc34704.c new file mode 100644 index 00000000..459b643b --- /dev/null +++ b/packages/devs/pmic/arm/mx25_3stack/v2_0/src/mc34704.c @@ -0,0 +1,137 @@ +//========================================================================== +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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", + " [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 \n"); + diag_printf("\tWrite: pmic \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(" = %d is invalid. Should be less than %d\n", + reg, MC34704_REG_MAX); + return 0; + } + return pmic_reg_i2c(reg, val, write); +} diff --git a/packages/devs/pmic/arm/mx35_3stack/v2_0/cdl/mc9s08dz.cdl b/packages/devs/pmic/arm/mx35_3stack/v2_0/cdl/mc9s08dz.cdl new file mode 100644 index 00000000..d3594124 --- /dev/null +++ b/packages/devs/pmic/arm/mx35_3stack/v2_0/cdl/mc9s08dz.cdl @@ -0,0 +1,105 @@ +# ==================================================================== +# +# 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 "; + } + + 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 + } +} diff --git a/packages/devs/pmic/arm/mx35_3stack/v2_0/include/mc9s08dz.h b/packages/devs/pmic/arm/mx35_3stack/v2_0/include/mc9s08dz.h new file mode 100644 index 00000000..f581a1e9 --- /dev/null +++ b/packages/devs/pmic/arm/mx35_3stack/v2_0/include/mc9s08dz.h @@ -0,0 +1,49 @@ +//========================================================================== +// +// 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__ */ diff --git a/packages/devs/pmic/arm/mx35_3stack/v2_0/src/mc9s08dz.c b/packages/devs/pmic/arm/mx35_3stack/v2_0/src/mc9s08dz.c new file mode 100644 index 00000000..c325fa15 --- /dev/null +++ b/packages/devs/pmic/arm/mx35_3stack/v2_0/src/mc9s08dz.c @@ -0,0 +1,212 @@ +//========================================================================== +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef MXC_PMIC_I2C_ENABLED +#include +#endif // MXC_PMIC_I2C_ENABLED +#include + +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", + " [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 \n"); + diag_printf("\tWrite: pmic \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(" = %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)); diff --git a/packages/devs/spi/arm/imx/v2_0/cdl/spi.cdl b/packages/devs/spi/arm/imx/v2_0/cdl/spi.cdl new file mode 100644 index 00000000..56a474da --- /dev/null +++ b/packages/devs/spi/arm/imx/v2_0/cdl/spi.cdl @@ -0,0 +1,56 @@ +# ==================================================================== +# +# 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 + +} diff --git a/packages/devs/spi/arm/imx/v2_0/include/imx_spi.h b/packages/devs/spi/arm/imx/v2_0/include/imx_spi.h new file mode 100644 index 00000000..a6e1e576 --- /dev/null +++ b/packages/devs/spi/arm/imx/v2_0/include/imx_spi.h @@ -0,0 +1,59 @@ +#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__ diff --git a/packages/devs/spi/arm/imx/v2_0/src/imx_spi.c b/packages/devs/spi/arm/imx/v2_0/src/imx_spi.c new file mode 100644 index 00000000..a064cf27 --- /dev/null +++ b/packages/devs/spi/arm/imx/v2_0/src/imx_spi.c @@ -0,0 +1,452 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +/*! + * 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", + " [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 \n"); + diag_printf("\tWrite: pmic \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(" = %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", + " [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 \n"); + diag_printf("\tWrite: spi_cpld \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(" = %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 diff --git a/packages/devs/usb/imx/v2_0/cdl/usbs_imx.cdl b/packages/devs/usb/imx/v2_0/cdl/usbs_imx.cdl new file mode 100644 index 00000000..033bdaae --- /dev/null +++ b/packages/devs/usb/imx/v2_0/cdl/usbs_imx.cdl @@ -0,0 +1,107 @@ +# ==================================================================== +# +# 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 diff --git a/packages/devs/usb/imx/v2_0/include/usbs_imx.h b/packages/devs/usb/imx/v2_0/include/usbs_imx.h new file mode 100644 index 00000000..11d9fd56 --- /dev/null +++ b/packages/devs/usb/imx/v2_0/include/usbs_imx.h @@ -0,0 +1,837 @@ +//========================================================================== +// +// 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 + +#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 */ diff --git a/packages/devs/usb/imx/v2_0/src/usbs_imx.c b/packages/devs/usb/imx/v2_0/src/usbs_imx.c new file mode 100644 index 00000000..9c93da33 --- /dev/null +++ b/packages/devs/usb/imx/v2_0/src/usbs_imx.c @@ -0,0 +1,3440 @@ +//========================================================================== +// +// 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 //use memset() of C run-time library +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(CYGHWR_IMX_USB_DOWNLOAD_SUPPORT) +#include +#endif +#include +#include +#include + +#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<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 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 diff --git a/packages/services/diagnosis/v2_0/cdl/diagnosis.cdl b/packages/services/diagnosis/v2_0/cdl/diagnosis.cdl new file mode 100644 index 00000000..11028061 --- /dev/null +++ b/packages/services/diagnosis/v2_0/cdl/diagnosis.cdl @@ -0,0 +1,112 @@ +# ==================================================================== +# +# 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 + } + } +} + + diff --git a/packages/services/diagnosis/v2_0/include/diagnosis.h b/packages/services/diagnosis/v2_0/include/diagnosis.h new file mode 100644 index 00000000..e76b350a --- /dev/null +++ b/packages/services/diagnosis/v2_0/include/diagnosis.h @@ -0,0 +1,19 @@ +#ifndef _DIAGNOSIS_H_ +#define _DIAGNOSIS_H_ + +#include +#include +#include +#include +#include + +#include + +#ifdef CYGPKG_MEMORY_DIAGNOSIS +#include +#endif + +extern struct cmd __DIAGNOSIS_cmds_TAB__[], __DIAGNOSIS_cmds_TAB_END__; +extern void diagnosis_usage(char *why); + +#endif /* _DIAGNOSIS_H_ */ diff --git a/packages/services/diagnosis/v2_0/include/memory.h b/packages/services/diagnosis/v2_0/include/memory.h new file mode 100644 index 00000000..c747d88a --- /dev/null +++ b/packages/services/diagnosis/v2_0/include/memory.h @@ -0,0 +1,15 @@ +#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_ */ diff --git a/packages/services/diagnosis/v2_0/src/core.c b/packages/services/diagnosis/v2_0/src/core.c new file mode 100644 index 00000000..27a22a49 --- /dev/null +++ b/packages/services/diagnosis/v2_0/src/core.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#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"); +} diff --git a/packages/services/diagnosis/v2_0/src/memory/ram_pm.c b/packages/services/diagnosis/v2_0/src/memory/ram_pm.c new file mode 100644 index 00000000..91cacffb --- /dev/null +++ b/packages/services/diagnosis/v2_0/src/memory/ram_pm.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include + +#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)); + } +} diff --git a/packages/services/diagnosis/v2_0/src/memory/ram_rw.c b/packages/services/diagnosis/v2_0/src/memory/ram_rw.c new file mode 100644 index 00000000..b27bd167 --- /dev/null +++ b/packages/services/diagnosis/v2_0/src/memory/ram_rw.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include + +#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 -l "\ + "-p pattern -m case [-s]\n", + ram_rw_test, + DIAGNOSIS_cmds +); + +local_cmd_entry("memcpybm", + "ram memory copy benchmarking", + "-c -s -e -a -b \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); +} + diff --git a/packages/services/diagnosis/v2_0/src/memory/routine.S b/packages/services/diagnosis/v2_0/src/memory/routine.S new file mode 100644 index 00000000..5474051b --- /dev/null +++ b/packages/services/diagnosis/v2_0/src/memory/routine.S @@ -0,0 +1,48 @@ + .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 diff --git a/packages/services/diagnosis/v2_0/src/wdt/wdt.c b/packages/services/diagnosis/v2_0/src/wdt/wdt.c new file mode 100644 index 00000000..79b581c1 --- /dev/null +++ b/packages/services/diagnosis/v2_0/src/wdt/wdt.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +#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"); +}