--- /dev/null
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=1.1.5
+PKG_RELEASE:=1
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=ftp://ftp.denx.de/pub/u-boot
+PKG_MD5SUM:=579707c8ecbf1ab4127285d2aac2a9ee
+PKG_CAT:=bzcat
+PKG_TARGETS:=bin
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/uboot-ifxmips
+ SECTION:=boot
+ CATEGORY:=Boot Loaders
+ DEPENDS:=@TARGET_ifxmips
+ TITLE:=U-Boot for Infineon MIPS boards
+ URL:=http://www.denx.de/wiki/UBoot/WebHome
+endef
+
+define Build/Prepare
+ $(call Build/Prepare/Default)
+ cp -r ./files/* $(PKG_BUILD_DIR)
+ find $(PKG_BUILD_DIR) -name .svn | $(XARGS) rm -rf
+endef
+
+define Build/Compile
+ cd $(PKG_BUILD_DIR);chmod a+x build_danube.sh;./build_danube.sh
+endef
+
+define Package/uboot-ifxmips/install
+ mkdir -p $(1)
+ dd if=$(PKG_BUILD_DIR)/u-boot.ifx of=$(1)/u-boot.ifx bs=64k conv=sync
+endef
+
+$(eval $(call BuildPackage,uboot-ifxmips))
--- /dev/null
+#
+# (C) Copyright 2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = lib$(BOARD).a
+
+OBJS = $(BOARD).o flash.o
+SOBJS = lowlevel_init.o pmuenable.o
+
+$(LIB): .depend $(OBJS) $(SOBJS)
+ $(AR) crv $@ $^
+
+#########################################################################
+
+.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
--- /dev/null
+/*
+** Copyright (C) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+To build a u-boot for danube board, user need to do the following things:
+To configure u-boot for a proper board, user need to modify two files accordingly.
+
+To configure u-boot for evaluation board, in danube-uboot/include/configs/danube.h, set
+#define USE_EVALUATION_BOARD
+#undef USE_REFERENCE_BOARD
+and vice-versa.
+
+To let u-boot boot from ebu(flash,e.g), in danube-uboot/include/configus/danube.h, set
+#define DANUBE_BOOT_FROM_EBU
+Otherwise u-boot will be compiled for booting from RAM.
+
+To use DDR RAM running at 111M, in danube-uboot/include/configus/danube.
+h, set
+#define DANUBE_DDR_RAM_111M
+#undef DANUBE_DDR_RAM_166M
+and vice-versa.
+
+To define RAM size of RAM, in danube-uboot/include/configus/danube.
+h, set
+#define RAM_SIZE 0x2000000 /*32M ram*/
+This is an example for a 32M RAM.
+
+
+Besides above settings, user need to change danube-uboot/board/danube/config.mk to set the loading address of u-boot.
+If U-Boot is to boot from EBU(flash), user needs to set
+TEXT_BASE=0xB0000000
+If u-boot is to boot from RAM, user needs to set
+TEXT_BASE=0xa0400000
+
+Use the script gct to build a uart downloadable u-boot image:
+./gct danube_ref_ddr166.conf u-boot.srec u-boot.asc
+
+
+
+
+
--- /dev/null
+#
+# (C) Copyright 2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+#
+# Danube board with MIPS 24Kec CPU core
+#boot from ebu
+TEXT_BASE = 0xB0000000
+BOOTSTRAP_TEXT_BASE = 0xB0000000
+
+#boot from ram
+#TEXT_BASE = 0xa0400000
+#TEXT_BASE = 0x807c0000
+
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/addrspace.h>
+#include <asm/danube.h>
+
+#ifdef DANUBE_USE_DDR_RAM
+long int initdram(int board_type)
+{
+ return (1024*1024*DANUBE_DDR_RAM_SIZE);
+}
+#else
+extern uint danube_get_cpuclk(void);
+
+static ulong max_sdram_size(void) /* per Chip Select */
+{
+ /* The only supported SDRAM data width is 16bit.
+ */
+#define CFG_DW 4
+
+ /* The only supported number of SDRAM banks is 4.
+ */
+#define CFG_NB 4
+
+ ulong cfgpb0 = *DANUBE_SDRAM_MC_CFGPB0;
+ int cols = cfgpb0 & 0xF;
+ int rows = (cfgpb0 & 0xF0) >> 4;
+ ulong size = (1 << (rows + cols)) * CFG_DW * CFG_NB;
+
+ return size;
+}
+
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'.
+ */
+
+static long int dram_size(long int *base, long int maxsize)
+{
+ volatile long int *addr;
+ ulong cnt, val;
+ ulong save[32]; /* to make test non-destructive */
+ unsigned char i = 0;
+
+ for (cnt = (maxsize / sizeof (long)) >> 1; cnt > 0; cnt >>= 1) {
+ addr = base + cnt; /* pointer arith! */
+
+ save[i++] = *addr;
+ *addr = ~cnt;
+ }
+
+ /* write 0 to base address */
+ addr = base;
+ save[i] = *addr;
+ *addr = 0;
+
+ /* check at base address */
+ if ((val = *addr) != 0) {
+ *addr = save[i];
+ return (0);
+ }
+
+ for (cnt = 1; cnt < maxsize / sizeof (long); cnt <<= 1) {
+ addr = base + cnt; /* pointer arith! */
+
+ val = *addr;
+ *addr = save[--i];
+
+ if (val != (~cnt)) {
+ return (cnt * sizeof (long));
+ }
+ }
+ return (maxsize);
+}
+
+long int initdram(int board_type)
+{
+ int rows, cols, best_val = *DANUBE_SDRAM_MC_CFGPB0;
+ ulong size, max_size = 0;
+ ulong our_address;
+
+ /* load t9 into our_address */
+ asm volatile ("move %0, $25" : "=r" (our_address) :);
+
+ /* Can't probe for RAM size unless we are running from Flash.
+ * find out whether running from DRAM or Flash.
+ */
+ if (PHYSADDR(our_address) < PHYSADDR(PHYS_FLASH_1))
+ {
+ return max_sdram_size();
+ }
+
+ for (cols = 0x8; cols <= 0xC; cols++)
+ {
+ for (rows = 0xB; rows <= 0xD; rows++)
+ {
+ *DANUBE_SDRAM_MC_CFGPB0 = (0x14 << 8) |
+ (rows << 4) | cols;
+ size = dram_size((ulong *)CFG_SDRAM_BASE,
+ max_sdram_size());
+
+ if (size > max_size)
+ {
+ best_val = *DANUBE_SDRAM_MC_CFGPB0;
+ max_size = size;
+ }
+ }
+ }
+
+ *DANUBE_SDRAM_MC_CFGPB0 = best_val;
+ return max_size;
+}
+#endif
+
+int checkboard (void)
+{
+ /* No such register in Amazon */
+#if 0
+ unsigned long chipid = *AMAZON_MCD_CHIPID;
+ int part_num;
+
+ puts ("Board: AMAZON ");
+ part_num = AMAZON_MCD_CHIPID_PART_NUMBER_GET(chipid);
+ switch (part_num) {
+ case AMAZON_CHIPID_STANDARD:
+ printf ("Standard Version, ");
+ break;
+ case AMAZON_CHIPID_YANGTSE:
+ printf ("Yangtse Version, ");
+ break;
+ default:
+ printf ("Unknown Part Number 0x%x ", part_num);
+ break;
+ }
+
+ printf ("Chip V1.%ld, ", AMAZON_MCD_CHIPID_VERSION_GET(chipid));
+
+
+ printf("CPU Speed %d MHz\n", danube_get_cpuclk()/1000000);
+
+#endif
+ return 0;
+}
+
+
+/*
+ * Disk On Chip (NAND) Millenium initialization.
+ * The NAND lives in the CS2* space
+ */
+#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+extern void
+nand_probe(ulong physadr);
+
+#define AT91_SMARTMEDIA_BASE 0x40000000 /* physical address to access memory on NCS3 */
+void
+nand_init(void)
+{
+ int devtype;
+ /* Configure EBU */
+//TODO: should we keep this?
+ //Set GPIO23 to be Flash CS1;
+ *DANUBE_GPIO_P1_ALTSEL0 = *DANUBE_GPIO_P1_ALTSEL0 | (1<<7);
+ *DANUBE_GPIO_P1_ALTSEL1 = *DANUBE_GPIO_P1_ALTSEL1 & ~(1<<7);
+ *DANUBE_GPIO_P1_DIR = *DANUBE_GPIO_P1_DIR | (1<<7) ;
+ *DANUBE_GPIO_P1_OD = *DANUBE_GPIO_P1_OD | (1<<7) ;
+
+ *EBU_ADDR_SEL_1 = (NAND_BASE_ADDRESS&0x1fffff00)|0x31;
+ /* byte swap;minimum delay*/
+ *EBU_CON_1 = 0x40C155;
+ *EBU_NAND_CON = 0x000005F3;
+
+ /* Set bus signals to inactive */
+ NAND_READY_CLEAR;
+
+ NAND_CE_CLEAR;
+ nand_probe(NAND_BASE_ADDRESS);
+
+
+
+ //nand_probe(AT91_SMARTMEDIA_BASE);
+}
+#endif
+
+
+
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */\r
+/* Optimise for Danube Eval Board DDR 167 Mhz - by Ng Aik Ann 29th April */\r
+#define MC_DC0_VALUE 0x1B1B\r
+#define MC_DC1_VALUE 0x0\r
+#define MC_DC2_VALUE 0x0\r
+#define MC_DC3_VALUE 0x0\r
+#define MC_DC4_VALUE 0x0\r
+#define MC_DC5_VALUE 0x200\r
+#define MC_DC6_VALUE 0x605\r
+#define MC_DC7_VALUE 0x303\r
+#define MC_DC8_VALUE 0x102\r
+#define MC_DC9_VALUE 0x70a\r
+#define MC_DC10_VALUE 0x203\r
+#define MC_DC11_VALUE 0xc02\r
+#define MC_DC12_VALUE 0x1C8\r
+#define MC_DC13_VALUE 0x1\r
+#define MC_DC14_VALUE 0x0\r
+#define MC_DC15_VALUE 0xf3c\r
+#define MC_DC16_VALUE 0xC800\r
+#define MC_DC17_VALUE 0xd\r
+#define MC_DC18_VALUE 0x300\r
+#define MC_DC19_VALUE 0x200\r
+#define MC_DC20_VALUE 0xA03\r
+#define MC_DC21_VALUE 0x1d00\r
+#define MC_DC22_VALUE 0x1d1d\r
+#define MC_DC23_VALUE 0x0\r
+#define MC_DC24_VALUE 0x5e /* was 0x7f */\r
+#define MC_DC25_VALUE 0x0\r
+#define MC_DC26_VALUE 0x0\r
+#define MC_DC27_VALUE 0x0\r
+#define MC_DC28_VALUE 0x510\r
+#define MC_DC29_VALUE 0x2d89\r
+#define MC_DC30_VALUE 0x8300\r
+#define MC_DC31_VALUE 0x0\r
+#define MC_DC32_VALUE 0x0\r
+#define MC_DC33_VALUE 0x0\r
+#define MC_DC34_VALUE 0x0\r
+#define MC_DC35_VALUE 0x0\r
+#define MC_DC36_VALUE 0x0\r
+#define MC_DC37_VALUE 0x0\r
+#define MC_DC38_VALUE 0x0\r
+#define MC_DC39_VALUE 0x0\r
+#define MC_DC40_VALUE 0x0\r
+#define MC_DC41_VALUE 0x0\r
+#define MC_DC42_VALUE 0x0\r
+#define MC_DC43_VALUE 0x0\r
+#define MC_DC44_VALUE 0x0\r
+#define MC_DC45_VALUE 0x500\r
+//#define MC_DC45_VALUE 0x400\r
+#define MC_DC46_VALUE 0x0\r
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Eval Board DDR 167 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA03 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1800
+#define MC_DC22_VALUE 0x1818
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x5e /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d89
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Eval Board DDR 167 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA03 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1800
+#define MC_DC22_VALUE 0x1818
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x5e /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d89
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Ref Board DDR 166 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xa02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x0
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA04 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1200
+#define MC_DC22_VALUE 0x1212
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x62 /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x4e20
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Samsung DDR K4H561638H Danube Ref Board DDR 166 Mhz - by Ng Aik Ann 27th Nov 2006 */
+
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0x120 /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x301
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA04 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1400
+#define MC_DC22_VALUE 0x1414
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x4e /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d93
+#define MC_DC30_VALUE 0x8235
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Eval Board DDR 167 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA03 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1800
+#define MC_DC22_VALUE 0x1818
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x5e /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d89
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Eval Board DDR 167 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA03 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1800
+#define MC_DC22_VALUE 0x1818
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x5e /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d89
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for PSC DDR A2S56D40CTP for Danube Ref Board DDR 166 Mhz - by Ng Aik Ann 27th Nov 2006 */
+
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0x120 /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x301
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA04 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0x1700
+#define MC_DC22_VALUE 0x1717
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x52 /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x4e20
+#define MC_DC30_VALUE 0x8235
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */\r
+/* Optimise for Danube Ref Board DDR 166 Mhz - by Ng Aik Ann 29th April */\r
+#define MC_DC0_VALUE 0x1B1B\r
+#define MC_DC1_VALUE 0x0\r
+#define MC_DC2_VALUE 0x0\r
+#define MC_DC3_VALUE 0x0\r
+#define MC_DC4_VALUE 0x0\r
+#define MC_DC5_VALUE 0x200\r
+#define MC_DC6_VALUE 0x605\r
+#define MC_DC7_VALUE 0x303\r
+#define MC_DC8_VALUE 0x102\r
+#define MC_DC9_VALUE 0x70a\r
+#define MC_DC10_VALUE 0x203\r
+#define MC_DC11_VALUE 0xc02\r
+#define MC_DC12_VALUE 0x1C8\r
+#define MC_DC13_VALUE 0x1\r
+#define MC_DC14_VALUE 0x0\r
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/\r
+#define MC_DC16_VALUE 0xC800\r
+#define MC_DC17_VALUE 0xd\r
+#define MC_DC18_VALUE 0x300\r
+#define MC_DC19_VALUE 0x200\r
+#define MC_DC20_VALUE 0xA04 /* A04 for reference board, A03 for Eval board */\r
+#define MC_DC21_VALUE 0x1200\r
+#define MC_DC22_VALUE 0x1212\r
+#define MC_DC23_VALUE 0x0\r
+#define MC_DC24_VALUE 0x5e /* WDQS Tuning for DQS */\r
+#define MC_DC25_VALUE 0x0\r
+#define MC_DC26_VALUE 0x0\r
+#define MC_DC27_VALUE 0x0\r
+#define MC_DC28_VALUE 0x510\r
+#define MC_DC29_VALUE 0x2d89\r
+#define MC_DC30_VALUE 0x8300\r
+#define MC_DC31_VALUE 0x0\r
+#define MC_DC32_VALUE 0x0\r
+#define MC_DC33_VALUE 0x0\r
+#define MC_DC34_VALUE 0x0\r
+#define MC_DC35_VALUE 0x0\r
+#define MC_DC36_VALUE 0x0\r
+#define MC_DC37_VALUE 0x0\r
+#define MC_DC38_VALUE 0x0\r
+#define MC_DC39_VALUE 0x0\r
+#define MC_DC40_VALUE 0x0\r
+#define MC_DC41_VALUE 0x0\r
+#define MC_DC42_VALUE 0x0\r
+#define MC_DC43_VALUE 0x0\r
+#define MC_DC44_VALUE 0x0\r
+#define MC_DC45_VALUE 0x500\r
+//#define MC_DC45_VALUE 0x400\r
+#define MC_DC46_VALUE 0x0\r
--- /dev/null
+/* Settings for Denali DDR SDRAM controller */
+/* Optimise for Danube Ref Board DDR 166 Mhz - by Ng Aik Ann 29th April */
+#define MC_DC0_VALUE 0x1B1B
+#define MC_DC1_VALUE 0x0
+#define MC_DC2_VALUE 0x0
+#define MC_DC3_VALUE 0x0
+#define MC_DC4_VALUE 0x0
+#define MC_DC5_VALUE 0x200
+#define MC_DC6_VALUE 0x605
+#define MC_DC7_VALUE 0x303
+#define MC_DC8_VALUE 0x102
+#define MC_DC9_VALUE 0x70a
+#define MC_DC10_VALUE 0x203
+#define MC_DC11_VALUE 0xc02
+#define MC_DC12_VALUE 0x1C8
+#define MC_DC13_VALUE 0x1
+#define MC_DC14_VALUE 0x0
+#define MC_DC15_VALUE 0xf3c /* WDQS tuning for clk_wr*/
+#define MC_DC16_VALUE 0xC800
+#define MC_DC17_VALUE 0xd
+#define MC_DC18_VALUE 0x300
+#define MC_DC19_VALUE 0x200
+#define MC_DC20_VALUE 0xA04 /* A04 for reference board, A03 for Eval board */
+#define MC_DC21_VALUE 0xd00
+#define MC_DC22_VALUE 0xd0d
+#define MC_DC23_VALUE 0x0
+#define MC_DC24_VALUE 0x62 /* WDQS Tuning for DQS */
+#define MC_DC25_VALUE 0x0
+#define MC_DC26_VALUE 0x0
+#define MC_DC27_VALUE 0x0
+#define MC_DC28_VALUE 0x510
+#define MC_DC29_VALUE 0x2d89
+#define MC_DC30_VALUE 0x8300
+#define MC_DC31_VALUE 0x0
+#define MC_DC32_VALUE 0x0
+#define MC_DC33_VALUE 0x0
+#define MC_DC34_VALUE 0x0
+#define MC_DC35_VALUE 0x0
+#define MC_DC36_VALUE 0x0
+#define MC_DC37_VALUE 0x0
+#define MC_DC38_VALUE 0x0
+#define MC_DC39_VALUE 0x0
+#define MC_DC40_VALUE 0x0
+#define MC_DC41_VALUE 0x0
+#define MC_DC42_VALUE 0x0
+#define MC_DC43_VALUE 0x0
+#define MC_DC44_VALUE 0x0
+#define MC_DC45_VALUE 0x500
+//#define MC_DC45_VALUE 0x400
+#define MC_DC46_VALUE 0x0
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+//joelin 10/07/2004 for MXIC MX29LV320ABTC-90
+#include <common.h>
+#include <asm/danube.h>
+
+/*
+#ifdef CONFIG_AMAZON
+ #define FLASH_DELAY {int i; \
+ for(i=0;i<800;i++) \
+ *((volatile u32 *)CFG_SDRAM_BASE_UNCACHE); \
+ }
+#else
+ #define FLASH_DELAY
+#endif
+*/
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/* NOTE - CONFIG_FLASH_16BIT means the CPU interface is 16-bit, it
+ * has nothing to do with the flash chip being 8-bit or 16-bit.
+ */
+#ifdef CONFIG_FLASH_16BIT
+typedef unsigned short FLASH_PORT_WIDTH;
+typedef volatile unsigned short FLASH_PORT_WIDTHV;
+#define FLASH_ID_MASK 0xFFFF
+#else
+typedef unsigned long FLASH_PORT_WIDTH;
+typedef volatile unsigned long FLASH_PORT_WIDTHV;
+#define FLASH_ID_MASK 0xFFFFFFFF
+#endif
+
+#define FPW FLASH_PORT_WIDTH
+#define FPWV FLASH_PORT_WIDTHV
+
+#define ORMASK(size) ((-size) & OR_AM_MSK) // 0xffff8000
+
+#if 0
+#define FLASH_CYCLE1 0x0555
+#define FLASH_CYCLE2 0x02aa
+#else
+#define FLASH_CYCLE1 0x0554 //joelin for MX29LV320AT/B 0x0555
+#define FLASH_CYCLE2 0x02ab //joelin for MX29LV320AT/B 0x02aa
+#endif
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size(FPWV *addr, flash_info_t *info);
+static void flash_reset(flash_info_t *info);
+static int write_word_intel(flash_info_t *info, FPWV *dest, FPW data);
+static int write_word_amd(flash_info_t *info, FPWV *dest, FPW data);
+static void flash_get_offsets(ulong base, flash_info_t *info);
+static flash_info_t *flash_get_info(ulong base);
+
+/*-----------------------------------------------------------------------
+ * flash_init()
+ *
+ * sets up flash_info and returns size of FLASH (bytes)
+ */
+unsigned long flash_init (void)
+{
+ unsigned long size = 0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i) { // 1 bank
+ ulong flashbase = (i == 0) ? PHYS_FLASH_1 : PHYS_FLASH_2; // 0xb0000000, 0xb4000000
+
+ volatile ulong * buscon = (ulong *)
+ ((i == 0) ? DANUBE_EBU_BUSCON0 : DANUBE_EBU_BUSCON1);
+
+ /* Disable write protection */
+// *buscon &= ~AMAZON_EBU_BUSCON0_WRDIS;
+ /* Enable write protection */
+ *buscon |= DANUBE_EBU_BUSCON0_WRDIS;
+
+#if 1
+ memset(&flash_info[i], 0, sizeof(flash_info_t));
+#endif
+
+ flash_info[i].size =
+ flash_get_size((FPW *)flashbase, &flash_info[i]);
+
+ if (flash_info[i].flash_id == FLASH_UNKNOWN) {
+ printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx\n",
+ i, flash_info[i].size);
+ }
+
+ size += flash_info[i].size;
+ }
+
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE // TEXT_BASE >= 0xB3000000
+ /* monitor protection ON by default */ /* only use software protection, info->protect[i]=0/1 */
+/* flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ flash_get_info(CFG_MONITOR_BASE));
+*/
+ flash_protect(FLAG_PROTECT_CLEAR, // clear protect
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
+ flash_get_info(CFG_MONITOR_BASE));
+
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH /* 1 */
+ /* ENV protection ON by default */
+/* flash_protect(FLAG_PROTECT_SET,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ flash_get_info(CFG_ENV_ADDR));
+*/
+ flash_protect(FLAG_PROTECT_CLEAR,
+ CFG_ENV_ADDR,
+ CFG_ENV_ADDR+CFG_ENV_SIZE-1,
+ flash_get_info(CFG_ENV_ADDR));
+
+#endif
+
+
+ return size;
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_reset(flash_info_t *info)
+{
+ FPWV *base = (FPWV *)(info->start[0]);
+
+ (*DANUBE_EBU_BUSCON0)&=(~0x80000000); // enable writing
+ (*DANUBE_EBU_BUSCON1)&=(~0x80000000); // enable writing
+ (*EBU_NAND_CON)=0;
+ /* Put FLASH back in read mode */
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL){
+ *base = (FPW)0x00FF00FF; /* Intel Read Mode */
+ asm("SYNC");
+ }
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD){
+ *base = (FPW)0x00F000F0; /* AMD Read Mode */
+ asm("SYNC"); //joelin
+ }
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_MX){
+ *base = (FPW)0x00F000F0; /* MXIC Read Mode */
+ asm("SYNC"); //joelin
+ }
+
+ (*DANUBE_EBU_BUSCON0)|=0x80000000; // disable writing
+ (*DANUBE_EBU_BUSCON1)|=0x80000000; // disable writing
+
+}
+
+/*-----------------------------------------------------------------------
+ */
+static void flash_get_offsets (ulong base, flash_info_t *info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL
+ && (info->flash_id & FLASH_BTYPE)) {
+ int bootsect_size; /* number of bytes/boot sector */
+ int sect_size; /* number of bytes/regular sector */
+
+ bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < 8; ++i) {
+ info->start[i] = base + (i * bootsect_size);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + ((i - 7) * sect_size);
+ }
+ }
+ else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD
+ && (info->flash_id & FLASH_TYPEMASK) == FLASH_AM640U) {
+
+ int sect_size; /* number of bytes/sector */
+
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set up sector start address table (uniform sector type) */
+ for( i = 0; i < info->sector_count; i++ )
+ info->start[i] = base + (i * sect_size);
+ }
+ else if(((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+ && ((info->flash_id & FLASH_TYPEMASK)==FLASH_28F128J3A)){
+ int sect_size;
+ sect_size = 0x20000;
+ for(i=0;i < info->sector_count; i++)
+ info->start[i]= base + (i*sect_size);
+ }
+ else if(((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)
+ && ((info->flash_id & FLASH_TYPEMASK)==FLASH_28F320J3A)){
+ int sect_size;
+ sect_size = 0x20000;
+ for(i=0;i < info->sector_count; i++)
+ info->start[i]= base + (i*sect_size);
+ }
+//joelin add for MX29LV320AB-- SA0~SA7:sector size=8K bytes ,SA9~SA70 :sector size=64k bytes
+ else if(((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_MX)
+ && ((info->flash_id & FLASH_TYPEMASK)==FLASH_29LV320AB)){
+ int bootsect_size; /* number of bytes/boot sector */
+ int sect_size; /* number of bytes/regular sector */
+
+ bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < 8; ++i) {
+ info->start[i] = base + (i * bootsect_size);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + ((i - 7) * sect_size);
+ }
+ }
+//joelin add for MX29LV160BB-- SA0=16K,SA1,SA2=8K,SA3=32K bytes ,SA4~SA34 :sector size=64k bytes
+ else if(((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_MX)
+ && ((info->flash_id & FLASH_TYPEMASK)==FLASH_29LV160BB)){
+ int bootsect_size; /* number of bytes/boot sector */
+ int sect_size; /* number of bytes/regular sector */
+
+ bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+/* set sector offsets for bottom boot block type */
+//MX29LV160BB
+ info->start[0] = base ; //SA0=16K bytes
+ info->start[1] = info->start[0] + (1 * 0x00004000 * (sizeof(FPW)/2)); //SA1=8K bytes
+ info->start[2] = info->start[1] + (1 * 0x00002000 * (sizeof(FPW)/2)); //SA2=8K bytes
+ info->start[3] = info->start[2] + (1 * 0x00002000 * (sizeof(FPW)/2)); //SA3=32K bytes
+
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] = base + ((i - 3) * sect_size);
+ }
+ }
+//liupeng add for MX29LV640BB-- SA0~SA7:sector size=8k bytes ,SA8~SA134 :sector size=64k bytes
+ else if(((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_MX)
+ && ((info->flash_id & FLASH_TYPEMASK)==FLASH_29LV640BB)){
+ int bootsect_size; /* number of bytes/boot sector */
+ int sect_size; /* number of bytes/regular sector */
+
+ bootsect_size = 0x00002000 * (sizeof(FPW)/2);
+ sect_size = 0x00010000 * (sizeof(FPW)/2);
+
+ /* set sector offsets for bottom boot block type */
+ for (i = 0; i < 8; ++i) {
+ info->start[i] = base + (i * bootsect_size);
+ }
+ for (i = 8; i < info->sector_count; i++) {
+ info->start[i] = base + ((i - 7) * sect_size);
+ }
+ }
+ else{
+ printf("flash get offsets fail\n");
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+static flash_info_t *flash_get_info(ulong base)
+{
+ int i;
+ flash_info_t * info;
+
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
+ info = & flash_info[i];
+ if (info->start[0] <= base && base < info->start[0] + info->size)
+ break;
+ }
+
+ return i == CFG_MAX_FLASH_BANKS ? 0 : info;
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+ uchar *boottype;
+ uchar *bootletter;
+ uchar *fmt;
+ uchar botbootletter[] = "B";
+ uchar topbootletter[] = "T";
+ uchar botboottype[] = "bottom boot sector";
+ uchar topboottype[] = "top boot sector";
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_SST: printf ("SST "); break;
+ case FLASH_MAN_STM: printf ("STM "); break;
+ case FLASH_MAN_INTEL: printf ("INTEL "); break;
+ case FLASH_MAN_MX: printf ("MXIC "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ /* check for top or bottom boot, if it applies */
+ if (info->flash_id & FLASH_BTYPE) {
+ boottype = botboottype;
+ bootletter = botbootletter;
+ }
+ else {
+ boottype = topboottype;
+ bootletter = topbootletter;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM640U:
+ fmt = "29LV641D (64 Mbit, uniform sectors)\n";
+ break;
+ case FLASH_28F800C3B:
+ case FLASH_28F800C3T:
+ fmt = "28F800C3%s (8 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL800B:
+ case FLASH_INTEL800T:
+ fmt = "28F800B3%s (8 Mbit, %s)\n";
+ break;
+ case FLASH_28F160C3B:
+ case FLASH_28F160C3T:
+ fmt = "28F160C3%s (16 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL160B:
+ case FLASH_INTEL160T:
+ fmt = "28F160B3%s (16 Mbit, %s)\n";
+ break;
+ case FLASH_28F320C3B:
+ case FLASH_28F320C3T:
+ fmt = "28F320C3%s (32 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL320B:
+ case FLASH_INTEL320T:
+ fmt = "28F320B3%s (32 Mbit, %s)\n";
+ break;
+ case FLASH_28F640C3B:
+ case FLASH_28F640C3T:
+ fmt = "28F640C3%s (64 Mbit, %s)\n";
+ break;
+ case FLASH_INTEL640B:
+ case FLASH_INTEL640T:
+ fmt = "28F640B3%s (64 Mbit, %s)\n";
+ break;
+ case FLASH_28F128J3A:
+ fmt = "28F128J3A (128 Mbit, 128 uniform sectors)\n";
+ break;
+ case FLASH_28F320J3A:
+ fmt = "28F320J3A (32 Mbit, 32 uniform sectors)\n";
+ break;
+ case FLASH_29LV640BB: //liupeng for MXIC FLASH_29LV640BB
+ fmt = "29LV640BB (64 Mbit, boot sector SA0~SA126 size 64k bytes,other sectors SA127~SA135 size 8k bytes)\n";
+ break;
+ case FLASH_29LV320AB: //joelin for MXIC FLASH_29LV320AB
+ fmt = "29LV320AB (32 Mbit, boot sector SA0~SA7 size 8K bytes,other sectors SA8~SA70 size 64K bytes)\n";
+ break;
+ case FLASH_29LV160BB: //joelin for MXIC FLASH_29LV160BB
+ fmt = "29LV160BB (16 Mbit, boot sector SA0 size 16K bytes,SA1,SA2 size 8K bytes,SA3 size 32k bytes,other sectors SA4~SA34 size 64K bytes)\n";
+ break;
+ default:
+ fmt = "Unknown Chip Type\n";
+ break;
+ }
+
+ printf (fmt, bootletter, boottype);
+
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size >> 20,
+ info->sector_count);
+
+ printf (" Sector Start Addresses:");
+
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0) {
+ printf ("\n ");
+ }
+
+ printf (" %08lX%s", info->start[i],
+ info->protect[i] ? " (RO)" : " ");
+ }
+
+ printf ("\n");
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+
+ulong flash_get_size (FPWV *addr, flash_info_t *info)
+{
+ (*DANUBE_EBU_BUSCON0)=0x1d7ff; //value from Aikann, should be used on the real chip
+ (*EBU_ADDR_SEL_0) = 0x10000031; //starting address from 0xb0000000
+ (*EBU_NAND_CON)=0;
+ (*DANUBE_EBU_BUSCON0)&=(~0x80000000); // enable writing
+ (*DANUBE_EBU_BUSCON1)&=(~0x80000000); // enable writing
+ /* Write auto select command: read Manufacturer ID */
+
+ /* Write auto select command sequence and test FLASH answer */
+ addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */
+ asm("SYNC");
+ addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */
+ asm("SYNC");
+ addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */
+ asm("SYNC");
+
+ /* The manufacturer codes are only 1 byte, so just use 1 byte.
+ * This works for any bus width and any FLASH device width.
+ */
+
+// printf("\n type is %08lx", addr[1] & 0xff); //joelin 10/06/2004 flash type
+// printf("\n type is %08lx", addr[0] & 0xff); //joelin 10/06/2004 flash type
+// asm("SYNC");
+ switch (addr[1] & 0xff) {
+ case (uchar)AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case (uchar)INTEL_MANUFACT: // 0x0089
+ info->flash_id = FLASH_MAN_INTEL; //0x00300000
+ break;
+
+//joelin for MXIC
+ case (uchar)MX_MANUFACT: // 0x00c2
+ info->flash_id = FLASH_MAN_MX ;//0x00030000
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ break;
+/* default:
+ info->flash_id = FLASH_MAN_INTEL; //0x00300000
+ break;*/
+ }
+
+ /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */
+ if (info->flash_id != FLASH_UNKNOWN) switch (addr[0]) {
+ case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */
+ info->flash_id += FLASH_AM640U;
+ info->sector_count = 128;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ case (FPW)INTEL_ID_28F800C3B:
+ info->flash_id += FLASH_28F800C3B;
+ info->sector_count = 23;
+ info->size = 0x00100000 * (sizeof(FPW)/2);
+ break; /* => 1 or 2 MB */
+
+ case (FPW)INTEL_ID_28F800B3B:
+ info->flash_id += FLASH_INTEL800B;
+ info->sector_count = 23;
+ info->size = 0x00100000 * (sizeof(FPW)/2);
+ break; /* => 1 or 2 MB */
+
+ case (FPW)INTEL_ID_28F160C3B:
+ info->flash_id += FLASH_28F160C3B;
+ info->sector_count = 39;
+ info->size = 0x00200000 * (sizeof(FPW)/2);
+ break; /* => 2 or 4 MB */
+
+ case (FPW)INTEL_ID_28F160B3B:
+ info->flash_id += FLASH_INTEL160B;
+ info->sector_count = 39;
+ info->size = 0x00200000 * (sizeof(FPW)/2);
+ break; /* => 2 or 4 MB */
+
+ case (FPW)INTEL_ID_28F320C3B:
+ info->flash_id += FLASH_28F320C3B;
+ info->sector_count = 71;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break; /* => 4 or 8 MB */
+
+ case (FPW)INTEL_ID_28F320B3B:
+ info->flash_id += FLASH_INTEL320B;
+ info->sector_count = 71;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break; /* => 4 or 8 MB */
+
+ case (FPW)INTEL_ID_28F640C3B:
+ info->flash_id += FLASH_28F640C3B;
+ info->sector_count = 135;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ case (FPW)INTEL_ID_28F640B3B:
+ info->flash_id += FLASH_INTEL640B;
+ info->sector_count = 135;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 8 or 16 MB */
+
+ case (FPW)INTEL_ID_28F128J3A:
+ info->flash_id +=FLASH_28F128J3A;
+ info->sector_count = 128;
+ info->size = 0x01000000 * (sizeof(FPW)/2);
+ break; /* => 16 MB */
+ case (FPW)INTEL_ID_28F320J3A:
+ info->flash_id += FLASH_28F320J3A;
+ info->sector_count = 32;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break;
+//joelin for MXIC
+ case (FPW)MX_ID_29LV320AB:
+ info->flash_id += FLASH_29LV320AB;
+ info->sector_count = 71;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break; /* => 4 MB */
+ /* => 4 MB */
+//joelin for MXIC
+ case (FPW)MX_ID_29LV160BB:
+ info->flash_id += FLASH_29LV160BB;
+ info->sector_count = 35;
+ info->size = 0x00200000 * (sizeof(FPW)/2);
+ break; /* => 2 MB */
+ /* => 2 MB */
+ /* liupeng*/
+ case (FPW)MX_ID_29LV640BB:
+ info->flash_id += FLASH_29LV640BB;
+ info->sector_count = 135;
+ info->size = 0x00800000 * (sizeof(FPW)/2);
+ break; /* => 2 MB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return (0); /* => no or unknown flash */
+/* default:
+ info->flash_id += FLASH_28F320J3A;
+ info->sector_count = 32;
+ info->size = 0x00400000 * (sizeof(FPW)/2);
+ break;*/
+ }
+
+
+ (*DANUBE_EBU_BUSCON0)|=0x80000000; // disable writing
+ (*DANUBE_EBU_BUSCON1)|=0x80000000; // disable writing
+
+ flash_get_offsets((ulong)addr, info);
+
+ /* Put FLASH back in read mode */
+ flash_reset(info);
+
+ return (info->size);
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ FPWV *addr;
+ int flag, prot, sect;
+ int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL;
+ ulong start, now, last;
+ int rcode = 0;
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_INTEL800B:
+ case FLASH_INTEL160B:
+ case FLASH_INTEL320B:
+ case FLASH_INTEL640B:
+ case FLASH_28F800C3B:
+ case FLASH_28F160C3B:
+ case FLASH_28F320C3B:
+ case FLASH_28F640C3B:
+ case FLASH_28F128J3A:
+ case FLASH_28F320J3A:
+ case FLASH_AM640U:
+ case FLASH_29LV640BB: //liupeng for MXIC MX29LV640BB
+ case FLASH_29LV320AB: //joelin for MXIC MX29LV320AB
+ case FLASH_29LV160BB: //joelin for MXIC MX29LV160BB
+ break;
+ case FLASH_UNKNOWN:
+ default:
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("\n");
+ }
+
+ last = get_timer(0);
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last && rcode == 0; sect++) {
+
+ if (info->protect[sect] != 0) /* protected, skip it */
+ continue;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ (*DANUBE_EBU_BUSCON0)&=(~0x80000000); // enable writing
+ (*DANUBE_EBU_BUSCON1)&=(~0x80000000); // enable writing
+ (*EBU_NAND_CON)=0;
+ addr = (FPWV *)(info->start[sect]);
+ if (intel) {
+ *addr = (FPW)0x00500050; /* clear status register */
+ *addr = (FPW)0x00200020; /* erase setup */
+ *addr = (FPW)0x00D000D0; /* erase confirm */
+ asm("SYNC");
+ }
+ else {
+ /* must be AMD style if not Intel */
+ FPWV *base; /* first address in bank */
+
+ base = (FPWV *)(info->start[0]);
+ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
+ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
+ base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */
+ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
+ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
+ *addr = (FPW)0x00300030; /* erase sector */
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer(0);
+
+ /* wait at least 50us for AMD, 80us for Intel.
+ * Let's wait 1 ms.
+ */
+ udelay (1000);
+
+ while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf ("Erase Timeout\n");
+
+ if (intel) {
+ /* suspend erase */
+ *addr = (FPW)0x00B000B0;
+ }
+
+ flash_reset(info); /* reset to read mode */
+ rcode = 1; /* failed */
+ break;
+ }
+
+ /* show that we're waiting */
+ if ((get_timer(last)) > CFG_HZ) {/* every second */
+ putc ('.');
+ last = get_timer(0);
+ }
+ }
+
+
+//joelin for MXIC
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_MX: //joelin for MXIC
+ break;
+ default:
+ if((*addr & (FPW)0x00200020) != (FPW)0x0)
+ printf("Erase Error\n");
+ break;
+ }
+
+
+
+ /* show that we're waiting */
+ if ((get_timer(last)) > CFG_HZ) { /* every second */
+ putc ('.');
+ last = get_timer(0);
+ }
+
+ //flash_reset(info); /* reset to read mode */
+ }
+
+ (*DANUBE_EBU_BUSCON0)|=0x80000000; // disable writing
+ (*DANUBE_EBU_BUSCON1)|=0x80000000; // disable writing
+
+ printf (" done\n");
+ return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */
+ int bytes; /* number of bytes to program in current word */
+ int left; /* number of bytes left to program */
+ int i, res;
+
+ for (left = cnt, res = 0;
+ left > 0 && res == 0;
+ addr += sizeof(data), left -= sizeof(data) - bytes) {
+
+ bytes = addr & (sizeof(data) - 1);
+ addr &= ~(sizeof(data) - 1);
+
+ /* combine source and destination data so can program
+ * an entire word of 16 or 32 bits
+ */
+ for (i = 0; i < sizeof(data); i++) {
+ data <<= 8;
+ if (i < bytes || i - bytes >= left )
+ data += *((uchar *)addr + i);
+ else
+ data += *src++;
+ }
+
+ /* write one word to the flash */
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD:
+ case FLASH_MAN_MX: //joelin for MXIC
+ res = write_word_amd(info, (FPWV *)addr, data);
+ break;
+ case FLASH_MAN_INTEL:
+ res = write_word_intel(info, (FPWV *)addr, data);
+ break;
+ default:
+ /* unknown flash type, error! */
+ printf ("missing or unknown FLASH type\n");
+ res = 1; /* not really a timeout, but gives error */
+ break;
+ }
+ }
+
+ return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for AMD FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_amd (flash_info_t *info, FPWV *dest, FPW data)
+{
+ ulong start;
+ int flag;
+ int res = 0; /* result, assume success */
+ FPWV *base; /* first address in flash bank */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*dest & data) != data) {
+ return (2);
+ }
+
+ base = (FPWV *)(info->start[0]);
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ (*DANUBE_EBU_BUSCON0)&=(~0x80000000); // enable writing
+ (*DANUBE_EBU_BUSCON1)&=(~0x80000000); // enable writing
+ (*EBU_NAND_CON)=0;
+
+ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */
+ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */
+ base[FLASH_CYCLE1] = (FPW)0x00A000A0; /* selects program mode */
+
+ *dest = data; /* start programming the data */
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ /* data polling for D7 */
+ while (res == 0 && (*dest & (FPW)0x00800080) != (data & (FPW)0x00800080)) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *dest = (FPW)0x00F000F0; /* reset bank */
+ res = 1;
+ }
+ }
+
+ (*DANUBE_EBU_BUSCON0)|=0x80000000; // disable writing
+ (*DANUBE_EBU_BUSCON1)|=0x80000000; // disable writing
+
+ return (res);
+}
+
+/*-----------------------------------------------------------------------
+ * Write a word to Flash for Intel FLASH
+ * A word is 16 or 32 bits, whichever the bus width of the flash bank
+ * (not an individual chip) is.
+ *
+ * returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word_intel (flash_info_t *info, FPWV *dest, FPW data)
+{
+ ulong start;
+ int flag;
+ int res = 0; /* result, assume success */
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*dest & data) != data) {
+ return (2);
+ }
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ (*DANUBE_EBU_BUSCON0)&=(~0x80000000); // enable writing
+ (*DANUBE_EBU_BUSCON1)&=(~0x80000000); // enable writing
+ (*EBU_NAND_CON)=0;
+ *dest = (FPW)0x00500050; /* clear status register */
+ *dest = (FPW)0x00FF00FF; /* make sure in read mode */
+ *dest = (FPW)0x00400040; /* program setup */
+ *dest = data; /* start programming the data */
+ asm("SYNC");
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ start = get_timer (0);
+
+ while (res == 0 && (*dest & (FPW)0x00800080) != (FPW)0x00800080) {
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ *dest = (FPW)0x00B000B0; /* Suspend program */
+ res = 1;
+ }
+ }
+
+ if (res == 0 && (*dest & (FPW)0x00100010))
+ res = 1; /* write failed, time out error is close enough */
+
+ *dest = (FPW)0x00500050; /* clear status register */
+ flash_reset(info);
+
+ (*DANUBE_EBU_BUSCON0)|=0x80000000; // disable writing
+ (*DANUBE_EBU_BUSCON1)|=0x80000000; // disable writing
+
+ return (res);
+}
--- /dev/null
+
+/*
+ * Memory sub-system initialization code for INCA-IP2 development board.
+ * Andre Messerschmidt
+ * Copyright (c) 2005 Infineon Technologies AG
+ *
+ * Based on Inca-IP code
+ * Copyright (c) 2003 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+/* History:
+ peng liu May 25, 2006, for PLL setting after reset, 05252006
+ */
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <configs/danube.h>
+
+
+#ifdef USE_REFERENCE_BOARD
+#ifdef DANUBE_DDR_RAM_111M
+#include "ddr_settings_r111.h"
+#elif defined(PROMOSDDR400)
+#include "ddr_settings_PROMOSDDR400.h"
+#elif defined(DDR_SAMSUNG_166M)
+#include "ddr_settings_Samsung_166.h"
+#elif defined(DDR_PSC_166M)
+#include "ddr_settings_psc_166.h"
+#else
+#include "ddr_settings_r166.h"
+#endif
+#endif
+
+#ifdef USE_EVALUATION_BOARD
+#ifdef DANUBE_DDR_RAM_111M
+#include "ddr_settings_e111.h"
+#else
+#include "ddr_settings_e166.h"
+#endif
+#endif
+
+
+
+/*TODO: liupeng check !!! */
+#define EBU_MODUL_BASE 0xB4102000
+#define EBU_CLC(value) 0x0000(value)
+#define EBU_CON(value) 0x0010(value)
+#define EBU_ADDSEL0(value) 0x0020(value)
+#define EBU_ADDSEL1(value) 0x0024(value)
+#define EBU_ADDSEL2(value) 0x0028(value)
+#define EBU_ADDSEL3(value) 0x002C(value)
+#define EBU_BUSCON0(value) 0x0060(value)
+#define EBU_BUSCON1(value) 0x0064(value)
+#define EBU_BUSCON2(value) 0x0068(value)
+#define EBU_BUSCON3(value) 0x006C(value)
+
+#define MC_MODUL_BASE 0xBF800000
+#define MC_ERRCAUSE(value) 0x0010(value)
+#define MC_ERRADDR(value) 0x0020(value)
+#define MC_CON(value) 0x0060(value)
+
+#define MC_SRAM_ENABLE 0x00000004
+#define MC_SDRAM_ENABLE 0x00000002
+#define MC_DDRRAM_ENABLE 0x00000001
+
+#define MC_SDR_MODUL_BASE 0xBF800200
+#define MC_IOGP(value) 0x0000(value)
+#define MC_CTRLENA(value) 0x0010(value)
+#define MC_MRSCODE(value) 0x0020(value)
+#define MC_CFGDW(value) 0x0030(value)
+#define MC_CFGPB0(value) 0x0040(value)
+#define MC_LATENCY(value) 0x0080(value)
+#define MC_TREFRESH(value) 0x0090(value)
+#define MC_SELFRFSH(value) 0x00A0(value)
+
+#define MC_DDR_MODUL_BASE 0xBF801000
+#define MC_DC00(value) 0x0000(value)
+#define MC_DC01(value) 0x0010(value)
+#define MC_DC02(value) 0x0020(value)
+#define MC_DC03(value) 0x0030(value)
+#define MC_DC04(value) 0x0040(value)
+#define MC_DC05(value) 0x0050(value)
+#define MC_DC06(value) 0x0060(value)
+#define MC_DC07(value) 0x0070(value)
+#define MC_DC08(value) 0x0080(value)
+#define MC_DC09(value) 0x0090(value)
+#define MC_DC10(value) 0x00A0(value)
+#define MC_DC11(value) 0x00B0(value)
+#define MC_DC12(value) 0x00C0(value)
+#define MC_DC13(value) 0x00D0(value)
+#define MC_DC14(value) 0x00E0(value)
+#define MC_DC15(value) 0x00F0(value)
+#define MC_DC16(value) 0x0100(value)
+#define MC_DC17(value) 0x0110(value)
+#define MC_DC18(value) 0x0120(value)
+#define MC_DC19(value) 0x0130(value)
+#define MC_DC20(value) 0x0140(value)
+#define MC_DC21(value) 0x0150(value)
+#define MC_DC22(value) 0x0160(value)
+#define MC_DC23(value) 0x0170(value)
+#define MC_DC24(value) 0x0180(value)
+#define MC_DC25(value) 0x0190(value)
+#define MC_DC26(value) 0x01A0(value)
+#define MC_DC27(value) 0x01B0(value)
+#define MC_DC28(value) 0x01C0(value)
+#define MC_DC29(value) 0x01D0(value)
+#define MC_DC30(value) 0x01E0(value)
+#define MC_DC31(value) 0x01F0(value)
+#define MC_DC32(value) 0x0200(value)
+#define MC_DC33(value) 0x0210(value)
+#define MC_DC34(value) 0x0220(value)
+#define MC_DC35(value) 0x0230(value)
+#define MC_DC36(value) 0x0240(value)
+#define MC_DC37(value) 0x0250(value)
+#define MC_DC38(value) 0x0260(value)
+#define MC_DC39(value) 0x0270(value)
+#define MC_DC40(value) 0x0280(value)
+#define MC_DC41(value) 0x0290(value)
+#define MC_DC42(value) 0x02A0(value)
+#define MC_DC43(value) 0x02B0(value)
+#define MC_DC44(value) 0x02C0(value)
+#define MC_DC45(value) 0x02D0(value)
+#define MC_DC46(value) 0x02E0(value)
+
+#define RCU_OFFSET 0xBF203000
+#define RCU_RST_REQ (RCU_OFFSET + 0x0010)
+#define RCU_STS (RCU_OFFSET + 0x0014)
+
+#define CGU_OFFSET 0xBF103000
+#define PLL0_CFG (CGU_OFFSET + 0x0004)
+#define PLL1_CFG (CGU_OFFSET + 0x0008)
+#define PLL2_CFG (CGU_OFFSET + 0x000C)
+#define CGU_SYS (CGU_OFFSET + 0x0010)
+#define CGU_UPDATE (CGU_OFFSET + 0x0014)
+#define IF_CLK (CGU_OFFSET + 0x0018)
+#define CGU_SMD (CGU_OFFSET + 0x0020)
+#define CGU_CT1SR (CGU_OFFSET + 0x0028)
+#define CGU_CT2SR (CGU_OFFSET + 0x002C)
+#define CGU_PCMCR (CGU_OFFSET + 0x0030)
+#define PCI_CR_PCI (CGU_OFFSET + 0x0034)
+#define CGU_OSC_CTRL (CGU_OFFSET + 0x001C)
+#define CGU_MIPS_PWR_DWN (CGU_OFFSET + 0x0038)
+#define CLK_MEASURE (CGU_OFFSET + 0x003C)
+
+//05252006
+#define pll0_35MHz_CONFIG 0x9D861059
+#define pll1_35MHz_CONFIG 0x1A260CD9
+#define pll2_35MHz_CONFIG 0x8000f1e5
+#define pll0_36MHz_CONFIG 0x1000125D
+#define pll1_36MHz_CONFIG 0x1B1E0C99
+#define pll2_36MHz_CONFIG 0x8002f2a1
+//05252006
+
+//06063001-joelin disable the PCI CFRAME mask -start
+/*CFRAME is an I/O signal, in the chip, the output CFRAME is selected via GPIO altsel pins, so if you select MII1 RXD1, the CFRAME will not come out.
+But the CFRAME input still take the signal from the pad and not disabled when altsel choose other function. So when MII1_RXD1 is low from other device, the EBU interface will be disabled.
+
+The chip function in such a way that disable the CFRAME mask mean EBU not longer check CFRAME to be the device using the bus.
+The side effect is the entire PCI block will see CFRAME low all the time meaning PCI cannot use the bus at all so no more PCI function.
+*/
+#define PCI_CR_PR_OFFSET 0xBE105400
+#define PCI_CR_PCI_MOD_REG (PCI_CR_PR_OFFSET + 0x0030)
+#define PCI_CONFIG_SPACE 0xB7000000
+#define CS_CFM (PCI_CONFIG_SPACE + 0x6C)
+//06063001-joelin disable the PCI CFRAME mask -end
+ .set noreorder
+
+
+/*
+ * void ebu_init(long)
+ *
+ * a0 has the clock value we are going to run at
+ */
+ .globl ebu_init
+ .ent ebu_init
+ebu_init:
+/*TODO:liupeng */
+ j ra
+ nop
+
+ .end ebu_init
+
+
+/*
+ * void cgu_init(long)
+ *
+ * a0 has the clock value
+ */
+ .globl cgu_init
+ .ent cgu_init
+cgu_init:
+ li t2, CGU_SYS
+ lw t2,0(t2)
+ beq t2,a0,freq_up2date
+ nop
+
+ li t2, RCU_STS
+ lw t2, 0(t2)
+ and t2,0x00020000
+ beq t2,0x00020000,boot_36MHZ
+ nop
+//05252006
+ li t1, PLL0_CFG
+ li t2, pll0_35MHz_CONFIG
+ sw t2,0(t1)
+ li t1, PLL1_CFG
+ li t2, pll1_35MHz_CONFIG
+ sw t2,0(t1)
+ li t1, PLL2_CFG
+ li t2, pll2_35MHz_CONFIG
+ sw t2,0(t1)
+ li t1, CGU_SYS
+ sw a0,0(t1)
+ li t1, RCU_RST_REQ
+ li t2, 0x40000008
+ sw t2,0(t1)
+ b wait_reset
+ nop
+boot_36MHZ:
+ li t1, PLL0_CFG
+ li t2, pll0_36MHz_CONFIG
+ sw t2,0(t1)
+ li t1, PLL1_CFG
+ li t2, pll1_36MHz_CONFIG
+ sw t2,0(t1)
+ li t1, PLL2_CFG
+ li t2, pll2_36MHz_CONFIG
+ sw t2,0(t1)
+ li t1, CGU_SYS
+ sw a0,0(t1)
+ li t1, RCU_RST_REQ
+ li t2, 0x40000008
+ sw t2,0(t1)
+//05252006
+
+wait_reset:
+ b wait_reset
+ nop
+freq_up2date:
+ j ra
+ nop
+ .end cgu_init
+
+
+/*
+ * void sdram_init(long)
+ *
+ * a0 has the clock value
+ */
+ .globl sdram_init
+ .ent sdram_init
+sdram_init:
+
+ /* SDRAM Initialization
+ */
+ li t1, MC_MODUL_BASE
+
+ /* Clear Error log registers */
+ sw zero, MC_ERRCAUSE(t1)
+ sw zero, MC_ERRADDR(t1)
+
+ /* Enable SDRAM module in memory controller */
+ li t3, MC_SDRAM_ENABLE
+ lw t2, MC_CON(t1)
+ or t3, t2, t3
+ sw t3, MC_CON(t1)
+
+ li t1, MC_SDR_MODUL_BASE
+
+ /* disable the controller */
+ li t2, 0
+ sw t2, MC_CTRLENA(t1)
+
+ li t2, 0x822
+ sw t2, MC_IOGP(t1)
+
+ li t2, 0x2
+ sw t2, MC_CFGDW(t1)
+
+ /* Set CAS Latency */
+ li t2, 0x00000020
+ sw t2, MC_MRSCODE(t1)
+
+ /* Set CS0 to SDRAM parameters */
+ li t2, 0x000014d8
+ sw t2, MC_CFGPB0(t1)
+
+ /* Set SDRAM latency parameters */
+ li t2, 0x00036325; /* BC PC100 */
+ sw t2, MC_LATENCY(t1)
+
+ /* Set SDRAM refresh rate */
+ li t2, 0x00000C30
+ sw t2, MC_TREFRESH(t1)
+
+ /* Clear Power-down registers */
+ sw zero, MC_SELFRFSH(t1)
+
+ /* Finally enable the controller */
+ li t2, 1
+ sw t2, MC_CTRLENA(t1)
+
+
+ j ra
+ nop
+
+
+ .end sdram_init
+
+/*
+ * void ddrram_init(long)
+ *
+ * a0 has the clock value
+ */
+ .globl ddrram_init
+ .ent ddrram_init
+ddrram_init:
+
+ /* DDR-DRAM Initialization
+ */
+ li t1, MC_MODUL_BASE
+
+ /* Clear Error log registers */
+ sw zero, MC_ERRCAUSE(t1)
+ sw zero, MC_ERRADDR(t1)
+
+ /* Enable DDR module in memory controller */
+ li t3, MC_DDRRAM_ENABLE
+ lw t2, MC_CON(t1)
+ or t3, t2, t3
+ sw t3, MC_CON(t1)
+
+ li t1, MC_DDR_MODUL_BASE
+
+ /* Write configuration to DDR controller registers */
+ li t2, MC_DC0_VALUE
+ sw t2, MC_DC00(t1)
+
+ li t2, MC_DC1_VALUE
+ sw t2, MC_DC01(t1)
+
+ li t2, MC_DC2_VALUE
+ sw t2, MC_DC02(t1)
+
+ li t2, MC_DC3_VALUE
+ sw t2, MC_DC03(t1)
+
+ li t2, MC_DC4_VALUE
+ sw t2, MC_DC04(t1)
+
+ li t2, MC_DC5_VALUE
+ sw t2, MC_DC05(t1)
+
+ li t2, MC_DC6_VALUE
+ sw t2, MC_DC06(t1)
+
+ li t2, MC_DC7_VALUE
+ sw t2, MC_DC07(t1)
+
+ li t2, MC_DC8_VALUE
+ sw t2, MC_DC08(t1)
+
+ li t2, MC_DC9_VALUE
+ sw t2, MC_DC09(t1)
+
+ li t2, MC_DC10_VALUE
+ sw t2, MC_DC10(t1)
+
+ li t2, MC_DC11_VALUE
+ sw t2, MC_DC11(t1)
+
+ li t2, MC_DC12_VALUE
+ sw t2, MC_DC12(t1)
+
+ li t2, MC_DC13_VALUE
+ sw t2, MC_DC13(t1)
+
+ li t2, MC_DC14_VALUE
+ sw t2, MC_DC14(t1)
+
+ li t2, MC_DC15_VALUE
+ sw t2, MC_DC15(t1)
+
+ li t2, MC_DC16_VALUE
+ sw t2, MC_DC16(t1)
+
+ li t2, MC_DC17_VALUE
+ sw t2, MC_DC17(t1)
+
+ li t2, MC_DC18_VALUE
+ sw t2, MC_DC18(t1)
+
+ li t2, MC_DC19_VALUE
+ sw t2, MC_DC19(t1)
+
+ li t2, MC_DC20_VALUE
+ sw t2, MC_DC20(t1)
+
+ li t2, MC_DC21_VALUE
+ sw t2, MC_DC21(t1)
+
+ li t2, MC_DC22_VALUE
+ sw t2, MC_DC22(t1)
+
+ li t2, MC_DC23_VALUE
+ sw t2, MC_DC23(t1)
+
+ li t2, MC_DC24_VALUE
+ sw t2, MC_DC24(t1)
+
+ li t2, MC_DC25_VALUE
+ sw t2, MC_DC25(t1)
+
+ li t2, MC_DC26_VALUE
+ sw t2, MC_DC26(t1)
+
+ li t2, MC_DC27_VALUE
+ sw t2, MC_DC27(t1)
+
+ li t2, MC_DC28_VALUE
+ sw t2, MC_DC28(t1)
+
+ li t2, MC_DC29_VALUE
+ sw t2, MC_DC29(t1)
+
+ li t2, MC_DC30_VALUE
+ sw t2, MC_DC30(t1)
+
+ li t2, MC_DC31_VALUE
+ sw t2, MC_DC31(t1)
+
+ li t2, MC_DC32_VALUE
+ sw t2, MC_DC32(t1)
+
+ li t2, MC_DC33_VALUE
+ sw t2, MC_DC33(t1)
+
+ li t2, MC_DC34_VALUE
+ sw t2, MC_DC34(t1)
+
+ li t2, MC_DC35_VALUE
+ sw t2, MC_DC35(t1)
+
+ li t2, MC_DC36_VALUE
+ sw t2, MC_DC36(t1)
+
+ li t2, MC_DC37_VALUE
+ sw t2, MC_DC37(t1)
+
+ li t2, MC_DC38_VALUE
+ sw t2, MC_DC38(t1)
+
+ li t2, MC_DC39_VALUE
+ sw t2, MC_DC39(t1)
+
+ li t2, MC_DC40_VALUE
+ sw t2, MC_DC40(t1)
+
+ li t2, MC_DC41_VALUE
+ sw t2, MC_DC41(t1)
+
+ li t2, MC_DC42_VALUE
+ sw t2, MC_DC42(t1)
+
+ li t2, MC_DC43_VALUE
+ sw t2, MC_DC43(t1)
+
+ li t2, MC_DC44_VALUE
+ sw t2, MC_DC44(t1)
+
+ li t2, MC_DC45_VALUE
+ sw t2, MC_DC45(t1)
+
+ li t2, MC_DC46_VALUE
+ sw t2, MC_DC46(t1)
+
+ li t2, 0x00000100
+ sw t2, MC_DC03(t1)
+
+ j ra
+ nop
+
+
+ .end ddrram_init
+
+ .globl lowlevel_init
+ .ent lowlevel_init
+lowlevel_init:
+ /* EBU, CGU and SDRAM/DDR-RAM Initialization.
+ */
+ move t0, ra
+ /* We rely on the fact that neither cgu_init() nor sdram_init()
+ * modify t0
+ */
+#ifdef DANUBE_BOOT_FROM_EBU
+#ifdef DANUBE_DDR_RAM_166M
+//05252006
+ /* 0xe8 means CPU0/CPU1 333M, DDR 167M, FPI 83M, PPE 240M */
+ li a0,0xe8
+ bal cgu_init
+ nop
+#endif
+#ifdef PROMOSDDR400
+ li a0,0xe8
+ bal cgu_init
+ nop
+#endif
+#ifdef DDR_SAMSUNG_166M
+ li a0,0xe8
+ bal cgu_init
+ nop
+#endif
+#ifdef DDR_PSC_166M
+ li a0,0xe8
+ bal cgu_init
+ nop
+#endif
+#ifdef DANUBE_DDR_RAM_133M
+ li a0,0xe9
+//05252006
+ bal cgu_init
+ nop
+#endif
+#endif
+/*TODO:liupeng add this define !!!! */
+/*
+ #define DANUBE_BOOT_FROM_EBU
+ #define DANUBE_USE_DDR_RAM
+*/
+
+//06063001-joelin disable the PCI CFRAME mask-start
+#ifdef DISABLE_CFRAME
+ li t1, PCI_CR_PCI //mw bf103034 80000000
+ li t2, 0x80000000
+ sw t2,0(t1)
+
+ li t1, PCI_CR_PCI_MOD_REG //mw be105430 103
+ li t2, 0x103
+ sw t2,0(t1)
+
+ li t1, CS_CFM //mw b700006c 0
+ li t2, 0x00
+ sw t2, 0(t1)
+
+ li t1, PCI_CR_PCI_MOD_REG //mw be105430 103
+ li t2, 0x1000103
+ sw t2, 0(t1)
+#endif
+//06063001-joelin disable the PCI CFRAME mask-end
+
+#ifdef DANUBE_BOOT_FROM_EBU
+#ifdef DANUBE_USE_DDR_RAM
+ bal ddrram_init
+ nop
+#else
+ bal sdram_init
+ nop
+#endif
+#endif
+
+ move ra, t0
+ j ra
+ nop
+
+ .end lowlevel_init
--- /dev/null
+/*
+ * Power Management unit initialization code for AMAZON development board.
+ *
+ * Copyright (c) 2003 Ou Ke, Infineon.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+
+#define PMU_PWDCR 0xBF10201C
+#define PMU_SR 0xBF102020
+
+ .globl pmuenable
+
+pmuenable:
+ li t0, PMU_PWDCR
+ li t1, 0x2 /* enable everything */
+ sw t1, 0(t0)
+#if 0
+1:
+ li t0, PMU_SR
+ lw t2, 0(t0)
+ bne t1, t2, 1b
+ nop
+#endif
+ j ra
+ nop
+
+
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk Engineering, <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips")
+*/
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
+OUTPUT_ARCH(mips)
+ENTRY(_start_bootstrap)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(4);
+ .text :
+ {
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(4);
+ .data : { *(.data) }
+
+ . = ALIGN(4);
+ .sdata : { *(.sdata) }
+
+ _gp = ALIGN(16);
+
+ __got_start_bootstrap = .;
+ .got : { *(.got) }
+ __got_end_bootstrap = .;
+
+ .sdata : { *(.sdata) }
+
+ . = .;
+ __u_boot_cmd_start_bootstrap = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end_bootstrap = .;
+
+ uboot_end_data_bootstrap = .;
+ num_got_entries = (__got_end_bootstrap - __got_start_bootstrap) >> 2;
+
+ . = ALIGN(4);
+ .sbss : { *(.sbss) }
+ .bss : { *(.bss) }
+ uboot_end_bootstrap = .;
+}
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk Engineering, <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips")
+*/
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(4);
+ .text :
+ {
+ *(.text)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(.rodata) }
+
+ . = ALIGN(4);
+ .data : { *(.data) }
+
+ . = ALIGN(4);
+ .sdata : { *(.sdata) }
+
+ _gp = ALIGN(16);
+
+ __got_start = .;
+ .got : { *(.got) }
+ __got_end = .;
+
+ .sdata : { *(.sdata) }
+
+ . = .;
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+ uboot_end_data = .;
+ num_got_entries = (__got_end - __got_start) >> 2;
+
+ . = ALIGN(4);
+ .sbss : { *(.sbss) }
+ .bss : { *(.bss) }
+ uboot_end = .;
+}
--- /dev/null
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <flash.h>
+
+#if !defined(CFG_NO_FLASH)
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+ ulong b_end = info->start[0] + info->size - 1; /* bank end address */
+ short s_end = info->sector_count - 1; /* index of last sector */
+ int i;
+
+ debug ("flash_protect %s: from 0x%08lX to 0x%08lX\n",
+ (flag & FLAG_PROTECT_SET) ? "ON" :
+ (flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
+ from, to);
+
+ /* Do nothing if input data is bad. */
+ if (info->sector_count == 0 || info->size == 0 || to < from) {
+ return;
+ }
+
+ /* There is nothing to do if we have no data about the flash
+ * or the protect range and flash range don't overlap.
+ */
+ if (info->flash_id == FLASH_UNKNOWN ||
+ to < info->start[0] || from > b_end) {
+ return;
+ }
+
+ for (i=0; i<info->sector_count; ++i) {
+ ulong end; /* last address in current sect */
+
+ end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+ /* Update protection if any part of the sector
+ * is in the specified range.
+ */
+ if (from <= end && to >= info->start[i]) {
+ if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CFG_FLASH_PROTECTION)
+ flash_real_protect(info, i, 0);
+#else
+ info->protect[i] = 0;
+#endif /* CFG_FLASH_PROTECTION */
+ debug ("protect off %d\n", i);
+ }
+ else if (flag & FLAG_PROTECT_SET) {
+#if defined(CFG_FLASH_PROTECTION)
+ flash_real_protect(info, i, 1);
+#else
+ info->protect[i] = 1;
+#endif /* CFG_FLASH_PROTECTION */
+ debug ("protect on %d\n", i);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+ flash_info_t *info;
+ int i;
+
+ for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
+ if (info->flash_id != FLASH_UNKNOWN &&
+ addr >= info->start[0] &&
+ /* WARNING - The '- 1' is needed if the flash
+ * is at the end of the address space, since
+ * info->start[0] + info->size wraps back to 0.
+ * Please don't change this unless you understand this.
+ */
+ addr <= info->start[0] + info->size - 1) {
+ return (info);
+ }
+ }
+#endif /* CONFIG_SPD823TS */
+
+ return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK 0 - OK
+ * ERR_TIMOUT 1 - write timeout
+ * ERR_NOT_ERASED 2 - Flash not erased
+ * ERR_PROTECTED 4 - target range includes protected sectors
+ * ERR_INVAL 8 - target address not in Flash memory
+ * ERR_ALIGN 16 - target address not aligned on boundary
+ * (only some targets require alignment)
+ */
+int
+flash_write (char *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+ return (ERR_TIMOUT); /* any other error codes are possible as well */
+#else
+ int i;
+ ulong end = addr + cnt - 1;
+ flash_info_t *info_first = addr2info (addr);
+ flash_info_t *info_last = addr2info (end );
+ flash_info_t *info;
+
+ if (cnt == 0) {
+ return (ERR_OK);
+ }
+
+ if (!info_first || !info_last) {
+ return (ERR_INVAL);
+ }
+
+ for (info = info_first; info <= info_last; ++info) {
+ ulong b_end = info->start[0] + info->size; /* bank end addr */
+ short s_end = info->sector_count - 1;
+ for (i=0; i<info->sector_count; ++i) {
+ ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+ if ((end >= info->start[i]) && (addr < e_addr) &&
+ (info->protect[i] != 0) ) {
+ return (ERR_PROTECTED);
+ }
+ }
+ }
+
+ /* finally write data to flash */
+ for (info = info_first; info <= info_last && cnt>0; ++info) {
+ ulong len;
+
+ len = info->start[0] + info->size - addr;
+ if (len > cnt)
+ len = cnt;
+ if ((i = write_buff(info, (uchar *)src, addr, len)) != 0) {
+ return (i);
+ }
+ cnt -= len;
+ addr += len;
+ src += len;
+ }
+ return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+void flash_perror (int err)
+{
+ switch (err) {
+ case ERR_OK:
+ break;
+ case ERR_TIMOUT:
+ puts ("Timeout writing to Flash\n");
+ break;
+ case ERR_NOT_ERASED:
+ puts ("Flash not Erased\n");
+ break;
+ case ERR_PROTECTED:
+ puts ("Can't write to protected Flash sectors\n");
+ break;
+ case ERR_INVAL:
+ puts ("Outside available Flash\n");
+ break;
+ case ERR_ALIGN:
+ puts ("Start and/or end address not on sector boundary\n");
+ break;
+ case ERR_UNKNOWN_FLASH_VENDOR:
+ puts ("Unknown Vendor of Flash\n");
+ break;
+ case ERR_UNKNOWN_FLASH_TYPE:
+ puts ("Unknown Type of Flash\n");
+ break;
+ case ERR_PROG_ERROR:
+ puts ("General Flash Programming Error\n");
+ break;
+ default:
+ printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
+ break;
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+#endif /* !CFG_NO_FLASH */
--- /dev/null
+#
+# (C) Copyright 2003-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).a
+
+START = start.o
+COBJS = asc_serial.o au1x00_serial.o au1x00_eth.o au1x00_usb_ohci.o \
+ cpu.o interrupts.o incaip_clock.o ifx_asc.o ifx_clock.o
+SOBJS = incaip_wdt.o cache.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+/*
+ * (INCA) ASC UART support
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_PURPLE) || defined(CONFIG_INCA_IP)
+
+#ifdef CONFIG_PURPLE
+#define serial_init asc_serial_init
+#define serial_putc asc_serial_putc
+#define serial_puts asc_serial_puts
+#define serial_getc asc_serial_getc
+#define serial_tstc asc_serial_tstc
+#define serial_setbrg asc_serial_setbrg
+#endif
+
+#include <common.h>
+#include <asm/inca-ip.h>
+#include "asc_serial.h"
+
+#ifdef CONFIG_PURPLE
+
+#undef ASC_FIFO_PRESENT
+#define TOUT_LOOP 100000
+
+/* Set base address for second FPI interrupt control register bank */
+#define SFPI_INTCON_BASEADDR 0xBF0F0000
+
+/* Register offset from base address */
+#define FBS_ISR 0x00000000 /* Interrupt status register */
+#define FBS_IMR 0x00000008 /* Interrupt mask register */
+#define FBS_IDIS 0x00000010 /* Interrupt disable register */
+
+/* Interrupt status register bits */
+#define FBS_ISR_AT 0x00000040 /* ASC transmit interrupt */
+#define FBS_ISR_AR 0x00000020 /* ASC receive interrupt */
+#define FBS_ISR_AE 0x00000010 /* ASC error interrupt */
+#define FBS_ISR_AB 0x00000008 /* ASC transmit buffer interrupt */
+#define FBS_ISR_AS 0x00000004 /* ASC start of autobaud detection interrupt */
+#define FBS_ISR_AF 0x00000002 /* ASC end of autobaud detection interrupt */
+
+#else
+
+#define ASC_FIFO_PRESENT
+
+#endif
+
+
+#define SET_BIT(reg, mask) reg |= (mask)
+#define CLEAR_BIT(reg, mask) reg &= (~mask)
+#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
+#define SET_BITS(reg, mask) SET_BIT(reg, mask)
+#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
+
+extern uint incaip_get_fpiclk(void);
+
+static int serial_setopt (void);
+
+/* pointer to ASC register base address */
+static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
+
+/******************************************************************************
+*
+* serial_init - initialize a INCAASC channel
+*
+* This routine initializes the number of data bits, parity
+* and set the selected baud rate. Interrupts are disabled.
+* Set the modem control signals if the option is selected.
+*
+* RETURNS: N/A
+*/
+
+int serial_init (void)
+{
+#ifdef CONFIG_INCA_IP
+ /* we have to set PMU.EN13 bit to enable an ASC device*/
+ INCAASC_PMU_ENABLE(13);
+#endif
+
+ /* and we have to set CLC register*/
+ CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
+ SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
+
+ /* initialy we are in async mode */
+ pAsc->asc_con = ASCCON_M_8ASYNC;
+
+ /* select input port */
+ pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
+
+#ifdef ASC_FIFO_PRESENT
+ /* TXFIFO's filling level */
+ SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
+ ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
+ /* enable TXFIFO */
+ SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
+
+ /* RXFIFO's filling level */
+ SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
+ ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
+ /* enable RXFIFO */
+ SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
+#endif
+
+ /* enable error signals */
+ SET_BIT(pAsc->asc_con, ASCCON_FEN);
+ SET_BIT(pAsc->asc_con, ASCCON_OEN);
+
+#ifdef CONFIG_INCA_IP
+ /* acknowledge ASC interrupts */
+ ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
+
+ /* disable ASC interrupts */
+ ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
+#endif
+
+#ifdef ASC_FIFO_PRESENT
+ /* set FIFOs into the transparent mode */
+ SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
+ SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
+#endif
+
+ /* set baud rate */
+ serial_setbrg();
+
+ /* set the options */
+ serial_setopt();
+
+ return 0;
+}
+
+void serial_setbrg (void)
+{
+ ulong uiReloadValue, fdv;
+ ulong f_ASC;
+
+#ifdef CONFIG_INCA_IP
+ f_ASC = incaip_get_fpiclk();
+#else
+ f_ASC = ASC_CLOCK_RATE;
+#endif
+
+#ifndef INCAASC_USE_FDV
+ fdv = 2;
+ uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
+#else
+ fdv = INCAASC_FDV_HIGH_BAUDRATE;
+ uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
+#endif /* INCAASC_USE_FDV */
+
+ if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
+ {
+#ifndef INCAASC_USE_FDV
+ fdv = 3;
+ uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
+#else
+ fdv = INCAASC_FDV_LOW_BAUDRATE;
+ uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
+#endif /* INCAASC_USE_FDV */
+
+ if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
+ {
+ return; /* can't impossibly generate that baud rate */
+ }
+ }
+
+ /* Disable Baud Rate Generator; BG should only be written when R=0 */
+ CLEAR_BIT(pAsc->asc_con, ASCCON_R);
+
+#ifndef INCAASC_USE_FDV
+ /*
+ * Disable Fractional Divider (FDE)
+ * Divide clock by reload-value + constant (BRS)
+ */
+ /* FDE = 0 */
+ CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
+
+ if ( fdv == 2 )
+ CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
+ else
+ SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
+
+#else /* INCAASC_USE_FDV */
+
+ /* Enable Fractional Divider */
+ SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
+
+ /* Set fractional divider value */
+ pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
+
+#endif /* INCAASC_USE_FDV */
+
+ /* Set reload value in BG */
+ pAsc->asc_bg = uiReloadValue;
+
+ /* Enable Baud Rate Generator */
+ SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
+}
+
+/*******************************************************************************
+*
+* serial_setopt - set the serial options
+*
+* Set the channel operating mode to that specified. Following options
+* are supported: CREAD, CSIZE, PARENB, and PARODD.
+*
+* Note, this routine disables the transmitter. The calling routine
+* may have to re-enable it.
+*
+* RETURNS:
+* Returns 0 to indicate success, otherwise -1 is returned
+*/
+
+static int serial_setopt (void)
+{
+ ulong con;
+
+ switch ( ASC_OPTIONS & ASCOPT_CSIZE )
+ {
+ /* 7-bit-data */
+ case ASCOPT_CS7:
+ con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
+ break;
+
+ /* 8-bit-data */
+ case ASCOPT_CS8:
+ if ( ASC_OPTIONS & ASCOPT_PARENB )
+ con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */
+ else
+ con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */
+ break;
+
+ /*
+ * only 7 and 8-bit frames are supported
+ * if we don't use IOCTL extensions
+ */
+ default:
+ return -1;
+ }
+
+ if ( ASC_OPTIONS & ASCOPT_STOPB )
+ SET_BIT(con, ASCCON_STP); /* 2 stop bits */
+ else
+ CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
+
+ if ( ASC_OPTIONS & ASCOPT_PARENB )
+ SET_BIT(con, ASCCON_PEN); /* enable parity checking */
+ else
+ CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
+
+ if ( ASC_OPTIONS & ASCOPT_PARODD )
+ SET_BIT(con, ASCCON_ODD); /* odd parity */
+ else
+ CLEAR_BIT(con, ASCCON_ODD); /* even parity */
+
+ if ( ASC_OPTIONS & ASCOPT_CREAD )
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
+
+ pAsc->asc_con |= con;
+
+ return 0;
+}
+
+void serial_putc (const char c)
+{
+#ifdef ASC_FIFO_PRESENT
+ uint txFl = 0;
+#else
+ uint timeout = 0;
+#endif
+
+ if (c == '\n') serial_putc ('\r');
+
+#ifdef ASC_FIFO_PRESENT
+ /* check do we have a free space in the TX FIFO */
+ /* get current filling level */
+ do
+ {
+ txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
+ }
+ while ( txFl == INCAASC_TXFIFO_FULL );
+#else
+
+ while(!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
+ FBS_ISR_AB))
+ {
+ if (timeout++ > TOUT_LOOP)
+ {
+ break;
+ }
+ }
+#endif
+
+ pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
+
+#ifndef ASC_FIFO_PRESENT
+ *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AB |
+ FBS_ISR_AT;
+#endif
+
+ /* check for errors */
+ if ( pAsc->asc_con & ASCCON_OE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
+ return;
+ }
+}
+
+void serial_puts (const char *s)
+{
+ while (*s)
+ {
+ serial_putc (*s++);
+ }
+}
+
+int serial_getc (void)
+{
+ ulong symbol_mask;
+ char c;
+
+ while (!serial_tstc());
+
+ symbol_mask =
+ ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
+
+ c = (char)(pAsc->asc_rbuf & symbol_mask);
+
+#ifndef ASC_FIFO_PRESENT
+ *(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) = FBS_ISR_AR;
+#endif
+
+ return c;
+}
+
+int serial_tstc (void)
+{
+ int res = 1;
+
+#ifdef ASC_FIFO_PRESENT
+ if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
+ {
+ res = 0;
+ }
+#else
+ if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
+ FBS_ISR_AR))
+
+ {
+ res = 0;
+ }
+#endif
+ else if ( pAsc->asc_con & ASCCON_FE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
+ res = 0;
+ }
+ else if ( pAsc->asc_con & ASCCON_PE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
+ res = 0;
+ }
+ else if ( pAsc->asc_con & ASCCON_OE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
+ res = 0;
+ }
+
+ return res;
+}
+#endif /* CONFIG_PURPLE || CONFIG_INCA_IP */
--- /dev/null
+/* incaAscSio.h - (INCA) ASC UART tty driver header */
+
+#ifndef __INCincaAscSioh
+#define __INCincaAscSioh
+
+#include <asm/inca-ip.h>
+
+/* channel operating modes */
+#define ASCOPT_CSIZE 0x00000003
+#define ASCOPT_CS7 0x00000001
+#define ASCOPT_CS8 0x00000002
+#define ASCOPT_PARENB 0x00000004
+#define ASCOPT_STOPB 0x00000008
+#define ASCOPT_PARODD 0x00000010
+#define ASCOPT_CREAD 0x00000020
+
+#define ASC_OPTIONS (ASCOPT_CREAD | ASCOPT_CS8)
+
+/* ASC input select (0 or 1) */
+#define CONSOLE_TTY 0
+
+/* use fractional divider for baudrate settings */
+#define INCAASC_USE_FDV
+
+#ifdef INCAASC_USE_FDV
+ #define INCAASC_FDV_LOW_BAUDRATE 71
+ #define INCAASC_FDV_HIGH_BAUDRATE 453
+#endif /*INCAASC_USE_FDV*/
+
+
+#define INCAASC_TXFIFO_FL 1
+#define INCAASC_RXFIFO_FL 1
+#define INCAASC_TXFIFO_FULL 16
+
+/* interrupt lines masks for the ASC device interrupts*/
+/* change these macroses if it's necessary */
+#define INCAASC_IRQ_LINE_ALL 0x000F0000 /* all IRQs */
+
+#define INCAASC_IRQ_LINE_TIR 0x00010000 /* TIR - Tx */
+#define INCAASC_IRQ_LINE_RIR 0x00020000 /* RIR - Rx */
+#define INCAASC_IRQ_LINE_EIR 0x00040000 /* EIR - Err */
+#define INCAASC_IRQ_LINE_TBIR 0x00080000 /* TBIR - Tx Buf*/
+
+/* interrupt controller access macros */
+#define ASC_INTERRUPTS_ENABLE(X) \
+ *((volatile unsigned int*) INCA_IP_ICU_IM2_IER) |= X;
+#define ASC_INTERRUPTS_DISABLE(X) \
+ *((volatile unsigned int*) INCA_IP_ICU_IM2_IER) &= ~X;
+#define ASC_INTERRUPTS_CLEAR(X) \
+ *((volatile unsigned int*) INCA_IP_ICU_IM2_ISR) = X;
+
+/* CLC register's bits and bitfields */
+#define ASCCLC_DISR 0x00000001
+#define ASCCLC_DISS 0x00000002
+#define ASCCLC_RMCMASK 0x0000FF00
+#define ASCCLC_RMCOFFSET 8
+
+/* CON register's bits and bitfields */
+#define ASCCON_MODEMASK 0x0007
+ #define ASCCON_M_8SYNC 0x0
+ #define ASCCON_M_8ASYNC 0x1
+ #define ASCCON_M_8IRDAASYNC 0x2
+ #define ASCCON_M_7ASYNCPAR 0x3
+ #define ASCCON_M_9ASYNC 0x4
+ #define ASCCON_M_8WAKEUPASYNC 0x5
+ #define ASCCON_M_8ASYNCPAR 0x7
+#define ASCCON_STP 0x0008
+#define ASCCON_REN 0x0010
+#define ASCCON_PEN 0x0020
+#define ASCCON_FEN 0x0040
+#define ASCCON_OEN 0x0080
+#define ASCCON_PE 0x0100
+#define ASCCON_FE 0x0200
+#define ASCCON_OE 0x0400
+#define ASCCON_FDE 0x0800
+#define ASCCON_ODD 0x1000
+#define ASCCON_BRS 0x2000
+#define ASCCON_LB 0x4000
+#define ASCCON_R 0x8000
+
+/* WHBCON register's bits and bitfields */
+#define ASCWHBCON_CLRREN 0x0010
+#define ASCWHBCON_SETREN 0x0020
+#define ASCWHBCON_CLRPE 0x0100
+#define ASCWHBCON_CLRFE 0x0200
+#define ASCWHBCON_CLROE 0x0400
+#define ASCWHBCON_SETPE 0x0800
+#define ASCWHBCON_SETFE 0x1000
+#define ASCWHBCON_SETOE 0x2000
+
+/* ABCON register's bits and bitfields */
+#define ASCABCON_ABEN 0x0001
+#define ASCABCON_AUREN 0x0002
+#define ASCABCON_ABSTEN 0x0004
+#define ASCABCON_ABDETEN 0x0008
+#define ASCABCON_FCDETEN 0x0010
+#define ASCABCON_EMMASK 0x0300
+ #define ASCABCON_EMOFF 8
+ #define ASCABCON_EM_DISAB 0x0
+ #define ASCABCON_EM_DURAB 0x1
+ #define ASCABCON_EM_ALWAYS 0x2
+#define ASCABCON_TXINV 0x0400
+#define ASCABCON_RXINV 0x0800
+
+/* FDV register mask, offset and bitfields*/
+#define ASCFDV_VALUE_MASK 0x000001FF
+
+/* WHBABCON register's bits and bitfields */
+#define ASCWHBABCON_SETABEN 0x0001
+#define ASCWHBABCON_CLRABEN 0x0002
+
+/* ABSTAT register's bits and bitfields */
+#define ASCABSTAT_FCSDET 0x0001
+#define ASCABSTAT_FCCDET 0x0002
+#define ASCABSTAT_SCSDET 0x0004
+#define ASCABSTAT_SCCDET 0x0008
+#define ASCABSTAT_DETWAIT 0x0010
+
+/* WHBABSTAT register's bits and bitfields */
+#define ASCWHBABSTAT_CLRFCSDET 0x0001
+#define ASCWHBABSTAT_SETFCSDET 0x0002
+#define ASCWHBABSTAT_CLRFCCDET 0x0004
+#define ASCWHBABSTAT_SETFCCDET 0x0008
+#define ASCWHBABSTAT_CLRSCSDET 0x0010
+#define ASCWHBABSTAT_SETSCSDET 0x0020
+#define ASCWHBABSTAT_SETSCCDET 0x0040
+#define ASCWHBABSTAT_CLRSCCDET 0x0080
+#define ASCWHBABSTAT_CLRDETWAIT 0x0100
+#define ASCWHBABSTAT_SETDETWAIT 0x0200
+
+/* TXFCON register's bits and bitfields */
+#define ASCTXFCON_TXFEN 0x0001
+#define ASCTXFCON_TXFFLU 0x0002
+#define ASCTXFCON_TXTMEN 0x0004
+#define ASCTXFCON_TXFITLMASK 0x3F00
+#define ASCTXFCON_TXFITLOFF 8
+
+/* RXFCON register's bits and bitfields */
+#define ASCRXFCON_RXFEN 0x0001
+#define ASCRXFCON_RXFFLU 0x0002
+#define ASCRXFCON_RXTMEN 0x0004
+#define ASCRXFCON_RXFITLMASK 0x3F00
+#define ASCRXFCON_RXFITLOFF 8
+
+/* FSTAT register's bits and bitfields */
+#define ASCFSTAT_RXFFLMASK 0x003F
+#define ASCFSTAT_TXFFLMASK 0x3F00
+#define ASCFSTAT_TXFFLOFF 8
+
+#define INCAASC_PMU_ENABLE(BIT) *((volatile ulong*)0xBF102000) |= (0x1 << BIT);
+
+typedef struct /* incaAsc_t */
+{
+ volatile unsigned long asc_clc; /*0x0000*/
+ volatile unsigned long asc_pisel; /*0x0004*/
+ volatile unsigned long asc_rsvd1[2]; /* for mapping */ /*0x0008*/
+ volatile unsigned long asc_con; /*0x0010*/
+ volatile unsigned long asc_bg; /*0x0014*/
+ volatile unsigned long asc_fdv; /*0x0018*/
+ volatile unsigned long asc_pmw; /* not used */ /*0x001C*/
+ volatile unsigned long asc_tbuf; /*0x0020*/
+ volatile unsigned long asc_rbuf; /*0x0024*/
+ volatile unsigned long asc_rsvd2[2]; /* for mapping */ /*0x0028*/
+ volatile unsigned long asc_abcon; /*0x0030*/
+ volatile unsigned long asc_abstat; /* not used */ /*0x0034*/
+ volatile unsigned long asc_rsvd3[2]; /* for mapping */ /*0x0038*/
+ volatile unsigned long asc_rxfcon; /*0x0040*/
+ volatile unsigned long asc_txfcon; /*0x0044*/
+ volatile unsigned long asc_fstat; /*0x0048*/
+ volatile unsigned long asc_rsvd4; /* for mapping */ /*0x004C*/
+ volatile unsigned long asc_whbcon; /*0x0050*/
+ volatile unsigned long asc_whbabcon; /*0x0054*/
+ volatile unsigned long asc_whbabstat; /* not used */ /*0x0058*/
+
+} incaAsc_t;
+
+#endif /* __INCincaAscSioh */
--- /dev/null
+/* Only eth0 supported for now
+ *
+ * (C) Copyright 2003
+ * Thomas.Lange@corelatus.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <config.h>
+
+#ifdef CONFIG_AU1X00
+
+#if defined(CFG_DISCOVER_PHY)
+#error "PHY not supported yet"
+/* We just assume that we are running 100FD for now */
+/* We all use switches, right? ;-) */
+#endif
+
+/* I assume ethernet behaves like au1000 */
+
+#ifdef CONFIG_AU1000
+/* Base address differ between cpu:s */
+#define ETH0_BASE AU1000_ETH0_BASE
+#define MAC0_ENABLE AU1000_MAC0_ENABLE
+#else
+#ifdef CONFIG_AU1100
+#define ETH0_BASE AU1100_ETH0_BASE
+#define MAC0_ENABLE AU1100_MAC0_ENABLE
+#else
+#ifdef CONFIG_AU1500
+#define ETH0_BASE AU1500_ETH0_BASE
+#define MAC0_ENABLE AU1500_MAC0_ENABLE
+#else
+#ifdef CONFIG_AU1550
+#define ETH0_BASE AU1550_ETH0_BASE
+#define MAC0_ENABLE AU1550_MAC0_ENABLE
+#else
+#error "No valid cpu set"
+#endif
+#endif
+#endif
+#endif
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/au1x00.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+/* Ethernet Transmit and Receive Buffers */
+#define DBUF_LENGTH 1520
+#define PKT_MAXBUF_SIZE 1518
+
+static char txbuf[DBUF_LENGTH];
+
+static int next_tx;
+static int next_rx;
+
+/* 4 rx and 4 tx fifos */
+#define NO_OF_FIFOS 4
+
+typedef struct{
+ u32 status;
+ u32 addr;
+ u32 len; /* Only used for tx */
+ u32 not_used;
+} mac_fifo_t;
+
+mac_fifo_t mac_fifo[NO_OF_FIFOS];
+
+#define MAX_WAIT 1000
+
+static int au1x00_send(struct eth_device* dev, volatile void *packet, int length){
+ volatile mac_fifo_t *fifo_tx =
+ (volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
+ int i;
+ int res;
+
+ /* tx fifo should always be idle */
+ fifo_tx[next_tx].len = length;
+ fifo_tx[next_tx].addr = (virt_to_phys(packet))|TX_DMA_ENABLE;
+ au_sync();
+
+ udelay(1);
+ i=0;
+ while(!(fifo_tx[next_tx].addr&TX_T_DONE)){
+ if(i>MAX_WAIT){
+ printf("TX timeout\n");
+ break;
+ }
+ udelay(1);
+ i++;
+ }
+
+ /* Clear done bit */
+ fifo_tx[next_tx].addr = 0;
+ fifo_tx[next_tx].len = 0;
+ au_sync();
+
+ res = fifo_tx[next_tx].status;
+
+ next_tx++;
+ if(next_tx>=NO_OF_FIFOS){
+ next_tx=0;
+ }
+ return(res);
+}
+
+static int au1x00_recv(struct eth_device* dev){
+ volatile mac_fifo_t *fifo_rx =
+ (volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
+
+ int length;
+ u32 status;
+
+ for(;;){
+ if(!(fifo_rx[next_rx].addr&RX_T_DONE)){
+ /* Nothing has been received */
+ return(-1);
+ }
+
+ status = fifo_rx[next_rx].status;
+
+ length = status&0x3FFF;
+
+ if(status&RX_ERROR){
+ printf("Rx error 0x%x\n", status);
+ }
+ else{
+ /* Pass the packet up to the protocol layers. */
+ NetReceive(NetRxPackets[next_rx], length - 4);
+ }
+
+ fifo_rx[next_rx].addr = (virt_to_phys(NetRxPackets[next_rx]))|RX_DMA_ENABLE;
+
+ next_rx++;
+ if(next_rx>=NO_OF_FIFOS){
+ next_rx=0;
+ }
+ } /* for */
+
+ return(0); /* Does anyone use this? */
+}
+
+static int au1x00_init(struct eth_device* dev, bd_t * bd){
+
+ volatile u32 *macen = (volatile u32*)MAC0_ENABLE;
+ volatile u32 *mac_ctrl = (volatile u32*)(ETH0_BASE+MAC_CONTROL);
+ volatile u32 *mac_addr_high = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_HIGH);
+ volatile u32 *mac_addr_low = (volatile u32*)(ETH0_BASE+MAC_ADDRESS_LOW);
+ volatile u32 *mac_mcast_high = (volatile u32*)(ETH0_BASE+MAC_MCAST_HIGH);
+ volatile u32 *mac_mcast_low = (volatile u32*)(ETH0_BASE+MAC_MCAST_LOW);
+ volatile mac_fifo_t *fifo_tx =
+ (volatile mac_fifo_t*)(MAC0_TX_DMA_ADDR+MAC_TX_BUFF0_STATUS);
+ volatile mac_fifo_t *fifo_rx =
+ (volatile mac_fifo_t*)(MAC0_RX_DMA_ADDR+MAC_RX_BUFF0_STATUS);
+ int i;
+
+ next_tx = TX_GET_DMA_BUFFER(fifo_tx[0].addr);
+ next_rx = RX_GET_DMA_BUFFER(fifo_rx[0].addr);
+
+ /* We have to enable clocks before releasing reset */
+ *macen = MAC_EN_CLOCK_ENABLE;
+ udelay(10);
+
+ /* Enable MAC0 */
+ /* We have to release reset before accessing registers */
+ *macen = MAC_EN_CLOCK_ENABLE|MAC_EN_RESET0|
+ MAC_EN_RESET1|MAC_EN_RESET2;
+ udelay(10);
+
+ for(i=0;i<NO_OF_FIFOS;i++){
+ fifo_tx[i].len = 0;
+ fifo_tx[i].addr = virt_to_phys(&txbuf[0]);
+ fifo_rx[i].addr = (virt_to_phys(NetRxPackets[i]))|RX_DMA_ENABLE;
+ }
+
+ /* Put mac addr in little endian */
+#define ea eth_get_dev()->enetaddr
+ *mac_addr_high = (ea[5] << 8) | (ea[4] ) ;
+ *mac_addr_low = (ea[3] << 24) | (ea[2] << 16) |
+ (ea[1] << 8) | (ea[0] ) ;
+#undef ea
+ *mac_mcast_low = 0;
+ *mac_mcast_high = 0;
+
+ /* Make sure the MAC buffer is in the correct endian mode */
+#ifdef __LITTLE_ENDIAN
+ *mac_ctrl = MAC_FULL_DUPLEX;
+ udelay(1);
+ *mac_ctrl = MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
+#else
+ *mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX;
+ udelay(1);
+ *mac_ctrl = MAC_BIG_ENDIAN|MAC_FULL_DUPLEX|MAC_RX_ENABLE|MAC_TX_ENABLE;
+#endif
+
+ return(1);
+}
+
+static void au1x00_halt(struct eth_device* dev){
+}
+
+int au1x00_enet_initialize(bd_t *bis){
+ struct eth_device* dev;
+
+ if ((dev = (struct eth_device*)malloc(sizeof *dev)) == NULL) {
+ puts ("malloc failed\n");
+ return 0;
+ }
+
+ memset(dev, 0, sizeof *dev);
+
+ sprintf(dev->name, "Au1X00 ethernet");
+ dev->iobase = 0;
+ dev->priv = 0;
+ dev->init = au1x00_init;
+ dev->halt = au1x00_halt;
+ dev->send = au1x00_send;
+ dev->recv = au1x00_recv;
+
+ eth_register(dev);
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII)
+ miiphy_register(dev->name,
+ au1x00_miiphy_read, au1x00_miiphy_write);
+#endif
+
+ return 1;
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_MII)
+int au1x00_miiphy_read(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short * value)
+{
+ volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
+ volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
+ u32 mii_control;
+ unsigned int timedout = 20;
+
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ udelay(1000);
+ if (--timedout == 0) {
+ printf("au1x00_eth: miiphy_read busy timeout!!\n");
+ return -1;
+ }
+ }
+
+ mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_READ;
+
+ *mii_control_reg = mii_control;
+
+ timedout = 20;
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ udelay(1000);
+ if (--timedout == 0) {
+ printf("au1x00_eth: miiphy_read busy timeout!!\n");
+ return -1;
+ }
+ }
+ *value = *mii_data_reg;
+ return 0;
+}
+
+int au1x00_miiphy_write(char *devname, unsigned char addr,
+ unsigned char reg, unsigned short value)
+{
+ volatile u32 *mii_control_reg = (volatile u32*)(ETH0_BASE+MAC_MII_CNTRL);
+ volatile u32 *mii_data_reg = (volatile u32*)(ETH0_BASE+MAC_MII_DATA);
+ u32 mii_control;
+ unsigned int timedout = 20;
+
+ while (*mii_control_reg & MAC_MII_BUSY) {
+ udelay(1000);
+ if (--timedout == 0) {
+ printf("au1x00_eth: miiphy_write busy timeout!!\n");
+ return;
+ }
+ }
+
+ mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ MAC_SET_MII_SELECT_PHY(addr) | MAC_MII_WRITE;
+
+ *mii_data_reg = value;
+ *mii_control_reg = mii_control;
+ return 0;
+}
+#endif /* CONFIG_COMMANDS & CFG_CMD_MII */
+
+#endif /* CONFIG_AU1X00 */
--- /dev/null
+/*
+ * AU1X00 UART support
+ *
+ * Hardcoded to UART 0 for now
+ * Speed and options also hardcoded to 115200 8N1
+ *
+ * Copyright (c) 2003 Thomas.Lange@corelatus.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef CONFIG_AU1X00
+
+#include <common.h>
+#include <asm/au1x00.h>
+
+/******************************************************************************
+*
+* serial_init - initialize a channel
+*
+* This routine initializes the number of data bits, parity
+* and set the selected baud rate. Interrupts are disabled.
+* Set the modem control signals if the option is selected.
+*
+* RETURNS: N/A
+*/
+
+int serial_init (void)
+{
+ volatile u32 *uart_fifoctl = (volatile u32*)(UART0_ADDR+UART_FCR);
+ volatile u32 *uart_enable = (volatile u32*)(UART0_ADDR+UART_ENABLE);
+
+ /* Enable clocks first */
+ *uart_enable = UART_EN_CE;
+
+ /* Then release reset */
+ /* Must release reset before setting other regs */
+ *uart_enable = UART_EN_CE|UART_EN_E;
+
+ /* Activate fifos, reset tx and rx */
+ /* Set tx trigger level to 12 */
+ *uart_fifoctl = UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|
+ UART_FCR_CLEAR_XMIT|UART_FCR_T_TRIGGER_12;
+
+ serial_setbrg();
+
+ return 0;
+}
+
+
+void serial_setbrg (void)
+{
+ volatile u32 *uart_clk = (volatile u32*)(UART0_ADDR+UART_CLK);
+ volatile u32 *uart_lcr = (volatile u32*)(UART0_ADDR+UART_LCR);
+ volatile u32 *sys_powerctrl = (u32 *)SYS_POWERCTRL;
+ int sd;
+ int divisorx2;
+
+ /* sd is system clock divisor */
+ /* see section 10.4.5 in au1550 datasheet */
+ sd = (*sys_powerctrl & 0x03) + 2;
+
+ /* calulate 2x baudrate and round */
+ divisorx2 = ((CFG_HZ/(sd * 16 * CONFIG_BAUDRATE)));
+
+ if (divisorx2 & 0x01)
+ divisorx2 = divisorx2 + 1;
+
+ *uart_clk = divisorx2 / 2;
+
+ /* Set parity, stop bits and word length to 8N1 */
+ *uart_lcr = UART_LCR_WLEN8;
+}
+
+void serial_putc (const char c)
+{
+ volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR);
+ volatile u32 *uart_tx = (volatile u32*)(UART0_ADDR+UART_TX);
+
+ if (c == '\n') serial_putc ('\r');
+
+ /* Wait for fifo to shift out some bytes */
+ while((*uart_lsr&UART_LSR_THRE)==0);
+
+ *uart_tx = (u32)c;
+}
+
+void serial_puts (const char *s)
+{
+ while (*s)
+ {
+ serial_putc (*s++);
+ }
+}
+
+int serial_getc (void)
+{
+ volatile u32 *uart_rx = (volatile u32*)(UART0_ADDR+UART_RX);
+ char c;
+
+ while (!serial_tstc());
+
+ c = (*uart_rx&0xFF);
+ return c;
+}
+
+int serial_tstc (void)
+{
+ volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR);
+
+ if(*uart_lsr&UART_LSR_DR){
+ /* Data in rfifo */
+ return(1);
+ }
+ return 0;
+}
+#endif /* CONFIG_SERIAL_AU1X00 */
--- /dev/null
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Note: Part of this code has been derived from linux
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - you MUST define LITTLEENDIAN in the configuration file for the
+ * board or this driver will NOT work!
+ * 2 - this driver is intended for use with USB Mass Storage Devices
+ * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
+ */
+
+#include <config.h>
+
+#if defined(CONFIG_AU1X00) && defined(CONFIG_USB_OHCI)
+
+/* #include <pci.h> no PCI on the AU1x00 */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/au1x00.h>
+#include <usb.h>
+#include "au1x00_usb_ohci.h"
+
+#define OHCI_USE_NPS /* force NoPowerSwitching mode */
+#define OHCI_VERBOSE_DEBUG /* not always helpful */
+#define OHCI_FILL_TRACE
+
+#define USBH_ENABLE_BE (1<<0)
+#define USBH_ENABLE_C (1<<1)
+#define USBH_ENABLE_E (1<<2)
+#define USBH_ENABLE_CE (1<<3)
+#define USBH_ENABLE_RD (1<<4)
+
+#ifdef LITTLEENDIAN
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
+#else
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
+#endif
+
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#undef readl
+#undef writel
+
+#define readl(a) au_readl((long)(a))
+#define writel(v,a) au_writel((v),(int)(a))
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#define DEBUG
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#define SHOW_INFO
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#define m16_swap(x) swap_16(x)
+#define m32_swap(x) swap_32(x)
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* urb_priv */
+urb_priv_t urb_priv;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect. AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+ u32 temp = readl (&hc->regs->roothub.register); \
+ if (hc->flags & OHCI_QUIRK_AMD756) \
+ while (temp & mask) \
+ temp = readl (&hc->regs->roothub.register); \
+ temp; })
+
+static u32 roothub_a (struct ohci *hc)
+ { return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+ { return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+ { return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+ { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+ int i;
+ int last;
+ struct td * td;
+
+ last = urb->length - 1;
+ if (last >= 0) {
+ for (i = 0; i <= last; i++) {
+ td = urb->td[i];
+ if (td) {
+ td->usb_dev = NULL;
+ urb->td[i] = NULL;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
+ int transfer_len, struct devrequest * setup, char * str, int small)
+{
+ urb_priv_t * purb = &urb_priv;
+
+ dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+ str,
+ sohci_get_current_frame_number (dev),
+ usb_pipedevice (pipe),
+ usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)? 'O': 'I',
+ usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+ (usb_pipecontrol (pipe)? "CTRL": "BULK"),
+ purb->actual_length,
+ transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol (pipe)) {
+ printf (__FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printf (" %02x", ((__u8 *) setup) [i]);
+ printf ("\n");
+ }
+ if (transfer_len > 0 && buffer) {
+ printf (__FILE__ ": data(%d/%d):",
+ purb->actual_length,
+ transfer_len);
+ len = usb_pipeout (pipe)?
+ transfer_len: purb->actual_length;
+ for (i = 0; i < 16 && i < len; i++)
+ printf (" %02x", ((__u8 *) buffer) [i]);
+ printf ("%s\n", i < len? "...": "");
+ }
+ }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+ int i, j;
+ __u32 * ed_p;
+ for (i= 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ while (*ed_p != 0 && j--) {
+ ed_t *ed = (ed_t *)m32_swap(ed_p);
+ printf (" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printf ("\n");
+ }
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ ed_t *edp = (ed_t *)value;
+
+ if (value) {
+ dbg ("%s %08x", label, value);
+ dbg ("%08x", edp->hwINFO);
+ dbg ("%08x", edp->hwTailP);
+ dbg ("%08x", edp->hwHeadP);
+ dbg ("%08x", edp->hwNextED);
+ }
+}
+
+static char * hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (®s->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (®s->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (®s->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (®s->intrenable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (®s->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b (controller);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status (controller);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+ /* dumps some of the state we know about */
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ ohci_t *ohci;
+ ed_t * ed;
+ urb_priv_t *purb_priv;
+ int i, size = 0;
+
+ ohci = &gohci;
+
+ /* when controller's hung, permit only roothub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled) {
+ err("sohci_submit_job: EPIPE");
+ return -1;
+ }
+
+ /* every endpoint has a ed, locate and fill it */
+ if (!(ed = ep_add_ed (dev, pipe))) {
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ }
+
+ if (size >= (N_URB_TD - 1)) {
+ err("need %d TDs, only have %d", size, N_URB_TD);
+ return -1;
+ }
+ purb_priv = &urb_priv;
+ purb_priv->pipe = pipe;
+
+ /* fill the private part of the URB */
+ purb_priv->length = size;
+ purb_priv->ed = ed;
+ purb_priv->actual_length = 0;
+
+ /* allocate the TDs */
+ /* note that td[0] was allocated in ep_add_ed */
+ for (i = 0; i < size; i++) {
+ purb_priv->td[i] = td_alloc (dev);
+ if (!purb_priv->td[i]) {
+ purb_priv->length = i;
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+ }
+
+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+ urb_free_priv (purb_priv);
+ err("sohci_submit_job: EINVAL");
+ return -1;
+ }
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link (ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+ ohci_t *ohci = &gohci;
+
+ return m16_swap (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+
+ ed->state = ED_OPER;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL) {
+ writel ((long)ed, &ohci->regs->ed_controlhead);
+ } else {
+ ohci->ed_controltail->hwNextED = m32_swap (ed);
+ }
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL) {
+ writel ((long)ed, &ohci->regs->ed_bulkhead);
+ } else {
+ ohci->ed_bulktail->hwNextED = m32_swap (ed);
+ }
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *ed)
+{
+ ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
+ writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
+{
+ td_t *td;
+ ed_t *ed_ret;
+ volatile ed_t *ed;
+
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+ (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+ err("ep_add_ed: pending delete");
+ /* pending delete request */
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
+ /* dummy td; end of td list for ed */
+ td = td_alloc (usb_dev);
+ ed->hwTailP = m32_swap (td);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype (pipe);
+ ohci_dev.ed_cnt++;
+ }
+
+ ed->hwINFO = m32_swap (usb_pipedevice (pipe)
+ | usb_pipeendpoint (pipe) << 7
+ | (usb_pipeisoc (pipe)? 0x8000: 0)
+ | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+ | usb_pipeslow (pipe) << 13
+ | usb_maxpacket (usb_dev, pipe) << 16);
+
+ return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+ void *data, int len,
+ struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+ volatile td_t *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+ int i;
+#endif
+
+ if (index > urb_priv->length) {
+ err("index > length");
+ return;
+ }
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+ if (1 || ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe))) {
+ for (i = 0; i < len; i++)
+ printf("td->data[%d] %#2x\n",i, ((unsigned char *)(td->data+0x80000000))[i]);
+ }
+#endif
+ if (!len)
+ data = 0;
+
+ td->hwINFO = m32_swap (info);
+ td->hwCBP = m32_swap (data);
+ if (data)
+ td->hwBE = m32_swap (data + len - 1);
+ else
+ td->hwBE = 0;
+ td->hwNextTD = m32_swap (td_pt);
+ td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+#define kseg_to_phys(x) ((void *)((__u32)(x) - 0x80000000))
+
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+ ohci_t *ohci = &gohci;
+ int data_len = transfer_len;
+ void *data;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+ if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+ }
+ urb->td_cnt = 0;
+ if (data_len)
+ data = kseg_to_phys(buffer);
+ else
+ data = 0;
+
+ switch (usb_pipetype (pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+ while(data_len > 4096) {
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+ cnt++;
+
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ break;
+
+ case PIPE_CONTROL:
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill (ohci, info, kseg_to_phys(setup), 8, dev, cnt++, urb);
+ if (data_len > 0) {
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+ }
+ info = usb_pipeout (pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill (ohci, info, data, 0, dev, cnt++, urb);
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ break;
+ }
+ if (urb->length != cnt)
+ dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ urb_priv_t *lurb_priv = &urb_priv;
+
+ tdINFO = m32_swap (td->hwINFO);
+ tdBE = m32_swap (td->hwBE);
+ tdCBP = m32_swap (td->hwCBP);
+
+
+ if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
+ ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ lurb_priv->actual_length += tdBE - td->data + 1;
+ else
+ lurb_priv->actual_length += tdCBP - td->data;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+ __u32 td_list_hc;
+ td_t *td_rev = NULL;
+ td_t *td_list = NULL;
+ urb_priv_t *lurb_priv = NULL;
+
+ td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = (td_t *)td_list_hc;
+
+ if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
+ lurb_priv = &urb_priv;
+ dbg(" USB-error/status: %x : %p",
+ TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
+ if (td_list->ed->hwHeadP & m32_swap (0x1)) {
+ if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+ td_list->ed->hwHeadP =
+ (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
+ (td_list->ed->hwHeadP & m32_swap (0x2));
+ lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+ } else
+ td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
+ }
+ }
+
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
+ }
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+ td_t *td_list_next = NULL;
+ ed_t *ed;
+ int cc = 0;
+ int stat = 0;
+ /* urb_t *urb; */
+ urb_priv_t *lurb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ while (td_list) {
+ td_list_next = td_list->next_dl_td;
+
+ lurb_priv = &urb_priv;
+ tdINFO = m32_swap (td_list->hwINFO);
+
+ ed = td_list->ed;
+
+ dl_transfer_length(td_list);
+
+ /* error code of transfer */
+ cc = TD_CC_GET (tdINFO);
+ if (cc != 0) {
+ dbg("ConditionCode %#x", cc);
+ stat = cc_to_error[cc];
+ }
+
+ if (ed->state != ED_NEW) {
+ edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
+ edTailP = m32_swap (ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink (ohci, ed);
+ }
+
+ td_list = td_list_next;
+ }
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'O', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT roothub_status(&gohci)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+ __u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = roothub_a (controller);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus (controller, i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) &&
+ ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ void * data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u32 datab[4];
+ __u8 *data_buf = (__u8 *)datab;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+#ifdef DEBUG
+urb_priv.actual_length = 0;
+pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ info("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = m16_swap (cmd->value);
+ wIndex = m16_swap (cmd->index);
+ wLength = m16_swap (cmd->length);
+
+ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+ dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *) data_buf = m16_swap (1); OK (2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *) data_buf = m16_swap (0); OK (2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL): OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC); OK (0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+ case (RH_C_PORT_CONNECTION):
+ WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+ case (RH_C_PORT_ENABLE):
+ WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+ case (RH_C_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+ case (RH_C_PORT_OVER_CURRENT):
+ WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+ case (RH_C_PORT_RESET):
+ WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
+ }
+ break;
+
+ case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if(wValue==0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
+ }
+ if(wValue==0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof (root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = roothub_a (&gohci);
+
+ data_buf [0] = 9; /* min length; */
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ /* corresponds to data_buf[4-7] */
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = roothub_b (&gohci);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf [0], wLength));
+ OK (len);
+ }
+
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
+
+ case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
+
+ default:
+ dbg ("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#else
+ wait_ms(1);
+#endif
+
+ len = min_t(int, len, leni);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
+ dev->act_len = len;
+ dev->status = stat;
+
+#ifdef DEBUG
+ if (transfer_len)
+ urb_priv.actual_length = transfer_len;
+ pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#else
+ wait_ms(1);
+#endif
+
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ int stat = 0;
+ int maxsize = usb_maxpacket(dev, pipe);
+ int timeout;
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if (!maxsize) {
+ err("submit_common_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+
+ if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
+ err("sohci_submit_job failed");
+ return -1;
+ }
+
+ wait_ms(10);
+ /* ohci_dump_status(&gohci); */
+
+ /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO 5000 /* timeout in milliseconds */
+ if (usb_pipetype (pipe) == PIPE_BULK)
+ timeout = BULK_TO;
+ else
+ timeout = 100;
+
+ timeout *= 4;
+ /* wait for it to complete */
+ for (;;) {
+ /* check whether the controller is done */
+ stat = hc_interrupt();
+ if (stat < 0) {
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+ if (stat >= 0 && stat != 0xff) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+ if (--timeout) {
+ udelay(250); /* wait_ms(1); */
+ } else {
+ err("CTL:TIMEOUT ");
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+ }
+ /* we got an Root Hub Status Change interrupt */
+ if (got_rhsc) {
+#ifdef DEBUG
+ ohci_dump_roothub (&gohci, 1);
+#endif
+ got_rhsc = 0;
+ /* abuse timeout */
+ timeout = rh_check_port_status(&gohci);
+ if (timeout >= 0) {
+#if 0 /* this does nothing useful, but leave it here in case that changes */
+ /* the called routine adds 1 to the passed value */
+ usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
+#endif
+ /*
+ * XXX
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+
+ dev->status = stat;
+ dev->act_len = transfer_len;
+
+#ifdef DEBUG
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+
+ /* free TDs in urb_priv */
+ urb_free_priv (&urb_priv);
+ return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ info("submit_bulk_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup)
+{
+ int maxsize = usb_maxpacket(dev, pipe);
+
+ info("submit_control_msg");
+#ifdef DEBUG
+ urb_priv.actual_length = 0;
+ pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if (!maxsize) {
+ err("submit_control_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+ if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+ gohci.rh.dev = dev;
+ /* root hub - redirect */
+ return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+ }
+
+ return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ info("submit_int_msg");
+ return -1;
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+ info("USB HC TakeOver from SMM");
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+ wait_ms (10);
+ if (--smm_timeout == 0) {
+ err("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+ ohci->slot_name,
+ readl (&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ writel (0, &ohci->regs->control);
+
+ /* HC Reset requires max 10 us delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err("USB HC reset timed out!");
+ return -1;
+ }
+ udelay (1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+
+ ohci->disabled = 1;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel (0, &ohci->regs->ed_controlhead);
+ writel (0, &ohci->regs->ed_bulkhead);
+
+ writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+ fminterval = 0x2edf;
+ writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel (fminterval, &ohci->regs->fminterval);
+ writel (0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel (ohci->hc_control, &ohci->regs->control);
+
+ /* disable all interrupts */
+ mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+ OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+ OHCI_INTR_OC | OHCI_INTR_MIE);
+ writel (mask, &ohci->regs->intrdisable);
+ /* clear all interrupts */
+ mask &= ~OHCI_INTR_MIE;
+ writel (mask, &ohci->regs->intrstatus);
+ /* Choose the interrupts we care about now - but w/o MIE */
+ mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel (mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+ /* POTPGT delay is bits 24-31, in 2 ms units. */
+ mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->rh.devnum = 0;
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static int
+hc_interrupt (void)
+{
+ ohci_t *ohci = &gohci;
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+ int stat = -1;
+
+ if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+ ints = OHCI_INTR_WDH;
+ } else {
+ ints = readl (®s->intrstatus);
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC) {
+ got_rhsc = 1;
+ }
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+ ohci->slot_name);
+ /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#else
+ wait_ms(1);
+#endif
+ /* FIXME: be optimistic, hope that bug won't repeat often. */
+ /* Make some non-interrupt context restart the controller. */
+ /* Count and limit the retries though; either hardware or */
+ /* software errors can go forever... */
+ hc_reset (ohci);
+ return -1;
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ wait_ms(1);
+ writel (OHCI_INTR_WDH, ®s->intrdisable);
+ stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+ writel (OHCI_INTR_WDH, ®s->intrenable);
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg("USB Schedule overrun\n");
+ writel (OHCI_INTR_SO, ®s->intrenable);
+ stat = -1;
+ }
+
+ /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
+ wait_ms(1);
+ writel (OHCI_INTR_SF, ®s->intrdisable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel (OHCI_INTR_SF, ®s->intrenable);
+ stat = 0xff;
+ }
+
+ writel (ints, ®s->intrstatus);
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+ dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+ if (!ohci->disabled)
+ hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define __read_32bit_c0_register(source, sel) \
+({ int __res; \
+ if (sel == 0) \
+ __asm__ __volatile__( \
+ "mfc0\t%0, " #source "\n\t" \
+ : "=r" (__res)); \
+ else \
+ __asm__ __volatile__( \
+ ".set\tmips32\n\t" \
+ "mfc0\t%0, " #source ", " #sel "\n\t" \
+ ".set\tmips0\n\t" \
+ : "=r" (__res)); \
+ __res; \
+})
+
+#define read_c0_prid() __read_32bit_c0_register($15, 0)
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+ u32 pin_func;
+ u32 sys_freqctrl, sys_clksrc;
+ u32 prid = read_c0_prid();
+
+ dbg("in usb_lowlevel_init\n");
+
+ /* zero and disable FREQ2 */
+ sys_freqctrl = au_readl(SYS_FREQCTRL0);
+ sys_freqctrl &= ~0xFFF00000;
+ au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+ /* zero and disable USBH/USBD clocks */
+ sys_clksrc = au_readl(SYS_CLKSRC);
+ sys_clksrc &= ~0x00007FE0;
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ sys_freqctrl = au_readl(SYS_FREQCTRL0);
+ sys_freqctrl &= ~0xFFF00000;
+
+ sys_clksrc = au_readl(SYS_CLKSRC);
+ sys_clksrc &= ~0x00007FE0;
+
+ switch (prid & 0x000000FF) {
+ case 0x00: /* DA */
+ case 0x01: /* HA */
+ case 0x02: /* HB */
+ /* CPU core freq to 48MHz to slow it way down... */
+ au_writel(4, SYS_CPUPLL);
+
+ /*
+ * Setup 48MHz FREQ2 from CPUPLL for USB Host
+ */
+ /* FRDIV2=3 -> div by 8 of 384MHz -> 48MHz */
+ sys_freqctrl |= ((3<<22) | (1<<21) | (0<<20));
+ au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+ /* CPU core freq to 384MHz */
+ au_writel(0x20, SYS_CPUPLL);
+
+ printf("Au1000: 48MHz OHCI workaround enabled\n");
+ break;
+
+ default: /* HC and newer */
+ /* FREQ2 = aux/2 = 48 MHz */
+ sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
+ au_writel(sys_freqctrl, SYS_FREQCTRL0);
+ break;
+ }
+
+ /*
+ * Route 48MHz FREQ2 into USB Host and/or Device
+ */
+ sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ /* configure pins GPIO[14:9] as GPIO */
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080);
+
+ au_writel(pin_func, SYS_PINFUNC);
+ au_writel(0x2800, SYS_TRIOUTCLR);
+ au_writel(0x0030, SYS_OUTPUTCLR);
+
+ dbg("OHCI board setup complete\n");
+
+ /* enable host controller */
+ au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
+ udelay(1000);
+ au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
+ udelay(1000);
+
+ /* wait for reset complete (read register twice; see au1500 errata) */
+ while (au_readl(USB_HOST_CONFIG),
+ !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+ udelay(1000);
+
+ dbg("OHCI clock running\n");
+
+ memset (&gohci, 0, sizeof (ohci_t));
+ memset (&urb_priv, 0, sizeof (urb_priv_t));
+
+ /* align the storage */
+ if ((__u32)&ghcca[0] & 0xff) {
+ err("HCCA not aligned!!");
+ return -1;
+ }
+ phcca = &ghcca[0];
+ info("aligned ghcca %p", phcca);
+ memset(&ohci_dev, 0, sizeof(struct ohci_device));
+ if ((__u32)&ohci_dev.ed[0] & 0x7) {
+ err("EDs not aligned!!");
+ return -1;
+ }
+ memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+ if ((__u32)gtd & 0x7) {
+ err("TDs not aligned!!");
+ return -1;
+ }
+ ptd = gtd;
+ gohci.hcca = phcca;
+ memset (phcca, 0, sizeof (struct ohci_hcca));
+
+ gohci.disabled = 1;
+ gohci.sleeping = 0;
+ gohci.irq = -1;
+ gohci.regs = (struct ohci_regs *)(USB_OHCI_BASE | 0xA0000000);
+
+ gohci.flags = 0;
+ gohci.slot_name = "au1x00";
+
+ dbg("OHCI revision: 0x%08x\n"
+ " RH: a: 0x%08x b: 0x%08x\n",
+ readl(&gohci.regs->revision),
+ readl(&gohci.regs->roothub.a), readl(&gohci.regs->roothub.b));
+
+ if (hc_reset (&gohci) < 0)
+ goto errout;
+
+ /* FIXME this is a second HC reset; why?? */
+ writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
+ wait_ms (10);
+
+ if (hc_start (&gohci) < 0)
+ goto errout;
+
+#ifdef DEBUG
+ ohci_dump (&gohci, 1);
+#else
+ wait_ms(1);
+#endif
+ ohci_inited = 1;
+ return 0;
+
+ errout:
+ err("OHCI initialization error\n");
+ hc_release_ohci (&gohci);
+ /* Initialization failed */
+ au_writel(readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+ return -1;
+}
+
+int usb_lowlevel_stop(void)
+{
+ /* this gets called really early - before the controller has */
+ /* even been initialized! */
+ if (!ohci_inited)
+ return 0;
+ /* TODO release any interrupts, etc. */
+ /* call hc_release_ohci() here ? */
+ hc_reset (&gohci);
+ /* may not want to do this */
+ /* Disable clock */
+ au_writel(readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+ return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
--- /dev/null
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+ /* No Error */ 0,
+ /* CRC Error */ USB_ST_CRC_ERR,
+ /* Bit Stuff */ USB_ST_BIT_ERR,
+ /* Data Togg */ USB_ST_CRC_ERR,
+ /* Stall */ USB_ST_STALLED,
+ /* DevNotResp */ -1,
+ /* PIDCheck */ USB_ST_BIT_ERR,
+ /* UnExpPID */ USB_ST_BIT_ERR,
+ /* DataOver */ USB_ST_BUF_ERR,
+ /* DataUnder */ USB_ST_BUF_ERR,
+ /* reservd */ -1,
+ /* reservd */ -1,
+ /* BufferOver */ USB_ST_BUF_ERR,
+ /* BuffUnder */ USB_ST_BUF_ERR,
+ /* Not Access */ -1,
+ /* Not Access */ -1
+};
+
+/* ED States */
+
+#define ED_NEW 0x00
+#define ED_UNLINK 0x01
+#define ED_OPER 0x02
+#define ED_DEL 0x04
+#define ED_URB_DEL 0x08
+
+/* usb_ohci_ed */
+struct ed {
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed *ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state;
+ __u8 type;
+ __u16 last_iso;
+ struct ed *ed_rm_list;
+
+ struct usb_device *usb_dev;
+ __u32 unused[3];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_NOTACCESSED 0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+ __u16 hwPSW[MAXPSW];
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct usb_device *usb_dev;
+ int transfer_len;
+ __u32 data;
+
+ __u32 unused2[2];
+} __attribute((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of. It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table[NUM_INTS]; /* Interrupt ED table */
+ __u16 frame_no; /* current frame number */
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus[MAX_ROOT_PORTS];
+ } roothub;
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *dev; /* was urb */
+ void *int_addr;
+ int send;
+ int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+ ed_t *ed;
+ __u16 length; /* number of tds associated with this request */
+ __u16 td_cnt; /* number of tds already serviced */
+ int state;
+ unsigned long pipe;
+ int actual_length;
+ td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+ struct ohci_hcca *hcca; /* hcca */
+ /*dma_addr_t hcca_dma;*/
+
+ int irq;
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ unsigned long flags; /* for HC bugs */
+
+ struct ohci_regs *regs; /* OHCI controller's memory */
+
+ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
+ ed_t *ed_bulktail; /* last endpoint of bulk list */
+ ed_t *ed_controltail; /* last endpoint of control list */
+ int intrstatus;
+ __u32 hc_control; /* copy of the hc control reg */
+ struct usb_device *dev[32];
+ struct virt_root_hub rh;
+
+ const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+ ed_t ed[NUM_EDS];
+ int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+ int i;
+ struct td *td;
+
+ td = NULL;
+ for (i = 0; i < NUM_TD; i++) {
+ if (ptd[i].usb_dev == NULL) {
+ td = &ptd[i];
+ td->usb_dev = usb_dev;
+ break;
+ }
+ }
+ return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+ ed->usb_dev = NULL;
+}
--- /dev/null
+/*
+ * Cache-handling routined for MIPS 4K CPUs
+ *
+ * Copyright (c) 2003 Wolfgang Denk <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+#if defined(CONFIG_IFX_MIPS)
+# include "ifx_cache.S"
+#endif
+
+ /* 16KB is the maximum size of instruction and data caches on
+ * MIPS 4K.
+ */
+#define MIPS_MAX_CACHE_SIZE 0x4000
+
+
+/*
+ * cacheop macro to automate cache operations
+ * first some helpers...
+ */
+#define _mincache(size, maxsize) \
+ bltu size,maxsize,9f ; \
+ move size,maxsize ; \
+9:
+
+#define _align(minaddr, maxaddr, linesize) \
+ .set noat ; \
+ subu AT,linesize,1 ; \
+ not AT ; \
+ and minaddr,AT ; \
+ addu maxaddr,-1 ; \
+ and maxaddr,AT ; \
+ .set at
+
+/* general operations */
+#define doop1(op1) \
+ cache op1,0(a0)
+#define doop2(op1, op2) \
+ cache op1,0(a0) ; \
+ nop ; \
+ cache op2,0(a0)
+
+/* specials for cache initialisation */
+#define doop1lw(op1) \
+ lw zero,0(a0)
+#define doop1lw1(op1) \
+ cache op1,0(a0) ; \
+ lw zero,0(a0) ; \
+ cache op1,0(a0)
+#define doop121(op1,op2) \
+ cache op1,0(a0) ; \
+ nop; \
+ cache op2,0(a0) ; \
+ nop; \
+ cache op1,0(a0)
+
+#define _oploopn(minaddr, maxaddr, linesize, tag, ops) \
+ .set noreorder ; \
+10: doop##tag##ops ; \
+ bne minaddr,maxaddr,10b ; \
+ add minaddr,linesize ; \
+ .set reorder
+
+/* finally the cache operation macros */
+#define vcacheopn(kva, n, cacheSize, cacheLineSize, tag, ops) \
+ blez n,11f ; \
+ addu n,kva ; \
+ _align(kva, n, cacheLineSize) ; \
+ _oploopn(kva, n, cacheLineSize, tag, ops) ; \
+11:
+
+#define icacheopn(kva, n, cacheSize, cacheLineSize, tag, ops) \
+ _mincache(n, cacheSize); \
+ blez n,11f ; \
+ addu n,kva ; \
+ _align(kva, n, cacheLineSize) ; \
+ _oploopn(kva, n, cacheLineSize, tag, ops) ; \
+11:
+
+#define vcacheop(kva, n, cacheSize, cacheLineSize, op) \
+ vcacheopn(kva, n, cacheSize, cacheLineSize, 1, (op))
+
+#define icacheop(kva, n, cacheSize, cacheLineSize, op) \
+ icacheopn(kva, n, cacheSize, cacheLineSize, 1, (op))
+
+/*******************************************************************************
+*
+* mips_cache_reset - low level initialisation of the primary caches
+*
+* This routine initialises the primary caches to ensure that they
+* have good parity. It must be called by the ROM before any cached locations
+* are used to prevent the possibility of data with bad parity being written to
+* memory.
+* To initialise the instruction cache it is essential that a source of data
+* with good parity is available. This routine
+* will initialise an area of memory starting at location zero to be used as
+* a source of parity.
+*
+* RETURNS: N/A
+*
+*/
+ .globl mips_cache_reset
+ .ent mips_cache_reset
+mips_cache_reset:
+
+ li t2, CFG_ICACHE_SIZE
+ li t3, CFG_DCACHE_SIZE
+ li t4, CFG_CACHELINE_SIZE
+ move t5, t4
+
+
+ li v0, MIPS_MAX_CACHE_SIZE
+
+ /* Now clear that much memory starting from zero.
+ */
+
+ li a0, KSEG1
+ addu a1, a0, v0
+
+2: sw zero, 0(a0)
+ sw zero, 4(a0)
+ sw zero, 8(a0)
+ sw zero, 12(a0)
+ sw zero, 16(a0)
+ sw zero, 20(a0)
+ sw zero, 24(a0)
+ sw zero, 28(a0)
+ addu a0, 32
+ bltu a0, a1, 2b
+
+ /* Set invalid tag.
+ */
+
+ mtc0 zero, CP0_TAGLO
+#if defined(CONFIG_IFX_MIPS) && defined(IFX_CACHE_EXTRA_INVALID_TAG)
+ IFX_CACHE_EXTRA_INVALID_TAG
+#endif
+
+ /*
+ * The caches are probably in an indeterminate state,
+ * so we force good parity into them by doing an
+ * invalidate, load/fill, invalidate for each line.
+ */
+
+ /* Assume bottom of RAM will generate good parity for the cache.
+ */
+
+ li a0, K0BASE
+ move a2, t2 # icacheSize
+ move a3, t4 # icacheLineSize
+ move a1, a2
+ icacheopn(a0,a1,a2,a3,121,(Index_Store_Tag_I,Fill))
+
+#if defined(CONFIG_IFX_MIPS) && defined(IFX_CACHE_EXTRA_OPERATION)
+ IFX_CACHE_EXTRA_OPERATION
+#else
+ /* To support Orion/R4600, we initialise the data cache in 3 passes.
+ */
+
+ /* 1: initialise dcache tags.
+ */
+
+ li a0, K0BASE
+ move a2, t3 # dcacheSize
+ move a3, t5 # dcacheLineSize
+ move a1, a2
+ icacheop(a0,a1,a2,a3,Index_Store_Tag_D)
+
+ /* 2: fill dcache.
+ */
+
+ li a0, K0BASE
+ move a2, t3 # dcacheSize
+ move a3, t5 # dcacheLineSize
+ move a1, a2
+ icacheopn(a0,a1,a2,a3,1lw,(dummy))
+
+ /* 3: clear dcache tags.
+ */
+
+ li a0, K0BASE
+ move a2, t3 # dcacheSize
+ move a3, t5 # dcacheLineSize
+ move a1, a2
+ icacheop(a0,a1,a2,a3,Index_Store_Tag_D)
+#endif
+
+ j ra
+ .end mips_cache_reset
+
+
+/*******************************************************************************
+*
+* dcache_status - get cache status
+*
+* RETURNS: 0 - cache disabled; 1 - cache enabled
+*
+*/
+ .globl dcache_status
+ .ent dcache_status
+dcache_status:
+
+ mfc0 v0, CP0_CONFIG
+ andi v0, v0, 1
+ j ra
+
+ .end dcache_status
+
+/*******************************************************************************
+*
+* dcache_disable - disable cache
+*
+* RETURNS: N/A
+*
+*/
+ .globl dcache_disable
+ .ent dcache_disable
+dcache_disable:
+
+ mfc0 t0, CP0_CONFIG
+ li t1, -8
+ and t0, t0, t1
+ ori t0, t0, CONF_CM_UNCACHED
+ mtc0 t0, CP0_CONFIG
+ j ra
+
+ .end dcache_disable
+
+
+/*******************************************************************************
+*
+* mips_cache_lock - lock RAM area pointed to by a0 in cache.
+*
+* RETURNS: N/A
+*
+*/
+#if defined(CONFIG_PURPLE)
+# define CACHE_LOCK_SIZE (CFG_DCACHE_SIZE/2)
+#else
+# define CACHE_LOCK_SIZE (CFG_DCACHE_SIZE)
+#endif
+ .globl mips_cache_lock
+ .ent mips_cache_lock
+mips_cache_lock:
+ li a1, K0BASE - CACHE_LOCK_SIZE
+ addu a0, a1
+ li a2, CACHE_LOCK_SIZE
+ li a3, CFG_CACHELINE_SIZE
+ move a1, a2
+ icacheop(a0,a1,a2,a3,0x1d)
+
+ j ra
+ .end mips_cache_lock
--- /dev/null
+#
+# (C) Copyright 2003
+# Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+v=$(shell \
+$(CROSS_COMPILE)as --version|grep "GNU assembler"|awk '{print $$3}'|awk -F . '{print $$2}')
+
+ifndef PLATFORM_CPU
+PLATFORM_CPU = mips32r2
+endif
+
+MIPSFLAGS=$(shell \
+if [ "$v" -lt "14" ]; then \
+ echo "-mcpu=$(PLATFORM_CPU)"; \
+else \
+ echo "-march=$(PLATFORM_CPU) -mtune=$(PLATFORM_CPU)"; \
+fi)
+
+ifeq ($(CROSS_COMPILE_UCLIBC),1)
+ifneq (,$(findstring mipsel,$(CROSS_COMIPLE)))
+ENDIANNESS = -el
+else
+ENDIANNESS = -eb
+endif
+else
+ifneq (,$(findstring 4KCle,$(CROSS_COMPILE)))
+ENDIANNESS = -EL
+else
+ENDIANNESS = -EB
+endif
+endif
+
+MIPSFLAGS += $(ENDIANNESS) -mabicalls
+
+PLATFORM_CPPFLAGS += $(MIPSFLAGS)
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#if defined(CONFIG_INCA_IP)
+# include <asm/inca-ip.h>
+#elif defined(CONFIG_IFX_MIPS)
+# include <asm/danube.h>
+# include "ifx_cpu.c"
+#endif
+#include <asm/mipsregs.h>
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+#if defined(CONFIG_INCA_IP)
+ *INCA_IP_WDT_RST_REQ = 0x3f;
+#elif defined(CONFIG_PURPLE) || defined(CONFIG_TB0229)
+ void (*f)(void) = (void *) 0xbfc00000;
+
+ f();
+#elif defined(CONFIG_IFX_MIPS)
+ IFX_CPU_RESET;
+#endif
+ fprintf(stderr, "*** reset failed ***\n");
+ return 0;
+}
+
+void flush_cache (ulong start_addr, ulong size)
+{
+
+}
+
+void write_one_tlb( int index, u32 pagemask, u32 hi, u32 low0, u32 low1 ){
+ write_32bit_cp0_register(CP0_ENTRYLO0, low0);
+ write_32bit_cp0_register(CP0_PAGEMASK, pagemask);
+ write_32bit_cp0_register(CP0_ENTRYLO1, low1);
+ write_32bit_cp0_register(CP0_ENTRYHI, hi);
+ write_32bit_cp0_register(CP0_INDEX, index);
+ tlb_write_indexed();
+}
--- /dev/null
+/*****************************************************************************
+ * DANUBE BootROM
+ * Copyright (c) 2005, Infineon Technologies AG, All rights reserved
+ * IFAP DC COM SD
+ *****************************************************************************/
+
+#include <config.h>
+//#include <lib.h>
+#include <asm/danube.h>
+#include <asm/addrspace.h>
+#include <asm/ifx_asc.h>
+
+
+#define ASC_FIFO_PRESENT
+#define SET_BIT(reg, mask) reg |= (mask)
+#define CLEAR_BIT(reg, mask) reg &= (~mask)
+#define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
+#define SET_BITS(reg, mask) SET_BIT(reg, mask)
+#define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
+
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef signed long s32;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef volatile unsigned short vuint;
+
+
+
+void serial_setbrg (void);
+
+/*TODO: undefine this !!!*/
+#undef DEBUG_ASC_RAW
+#ifdef DEBUG_ASC_RAW
+#define DEBUG_ASC_RAW_RX_BUF 0xA0800000
+#define DEBUG_ASC_RAW_TX_BUF 0xA0900000
+#endif
+
+static volatile DanubeAsc_t *pAsc = (DanubeAsc_t *)DANUBE_ASC1;
+
+typedef struct{
+ u16 fdv; /* 0~511 fractional divider value*/
+ u16 reload; /* 13 bit reload value*/
+} ifx_asc_baud_reg_t;
+
+#ifdef ON_VENUS
+/*9600 @1.25M rel 00.08*/
+//#define FDV 503
+//#define RELOAD 7
+/*9600 @0.625M rel final00.01 & rtl_freeze*/
+#define FDV 503
+#define RELOAD 3
+/* first index is DDR_SEL, second index is FPI_SEL */
+#endif
+static ifx_asc_baud_reg_t g_danube_asc_baud[4][2] =
+{
+#ifdef ON_VENUS
+ {{503,3},{503,3}}, /* 1152000 @ 166.67M and half*/
+ {{503,3},{503,3}}, /* 1152000 @ 133.3M and half*/
+ {{503,3},{503,3}}, /* 1152000 @ 111.11M and half*/
+ {{503.3},{503,3}} /* 1152000 @ 83.33M and half*/
+#else
+/* TAPEOUT table */
+ {{436,76},{419,36}}, /* 1152000 @ 166.67M and half*/
+ {{453,63},{453,31}}, /* 1152000 @ 133.3M and half*/
+ {{501,58},{510,29}}, /* 1152000 @ 111.11M and half*/
+ {{419.36},{453,19}} /* 1152000 @ 83.33M and half*/
+#endif
+};
+/******************************************************************************
+*
+* asc_init - initialize a Danube ASC channel
+*
+* This routine initializes the number of data bits, parity
+* and set the selected baud rate. Interrupts are disabled.
+* Set the modem control signals if the option is selected.
+*
+* RETURNS: N/A
+*/
+
+int serial_init (void)
+{
+
+ /* and we have to set CLC register*/
+ CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
+ SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
+
+ /* initialy we are in async mode */
+ pAsc->asc_con = ASCCON_M_8ASYNC;
+
+ /* select input port */
+ pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
+
+ /* TXFIFO's filling level */
+ SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
+ ASCTXFCON_TXFITLOFF, DANUBEASC_TXFIFO_FL);
+ /* enable TXFIFO */
+ SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
+
+ /* RXFIFO's filling level */
+ SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
+ ASCRXFCON_RXFITLOFF, DANUBEASC_RXFIFO_FL);
+ /* enable RXFIFO */
+ SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
+
+ /* set baud rate */
+ serial_setbrg();
+
+ /* enable error signals & Receiver enable */
+ SET_BIT(pAsc->asc_whbstate, ASCWHBSTATE_SETREN|ASCCON_FEN|ASCCON_TOEN|ASCCON_ROEN);
+
+ return 0;
+}
+
+void serial_setbrg (void)
+{
+ u32 uiReloadValue, fdv;
+
+#if defined(ON_IKOS)
+ /*1200 @77K */
+ fdv=472;
+ uiReloadValue=5;
+#else
+ /*venus & tapeout */
+ u32 ddr_sel,fpi_sel;
+ ddr_sel = (* DANUBE_CGU_SYS) & 0x3;
+ fpi_sel = ((* DANUBE_CGU_SYS) & 0x40)?1:0;
+ fdv= g_danube_asc_baud[ddr_sel][fpi_sel].fdv;
+ uiReloadValue=g_danube_asc_baud[ddr_sel][fpi_sel].reload;
+#endif //ON_IKOS
+ /* Disable Baud Rate Generator; BG should only be written when R=0 */
+ CLEAR_BIT(pAsc->asc_con, ASCCON_R);
+
+ /* Enable Fractional Divider */
+ SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
+
+ /* Set fractional divider value */
+ pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
+
+ /* Set reload value in BG */
+ pAsc->asc_bg = uiReloadValue;
+
+ /* Enable Baud Rate Generator */
+ SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
+}
+
+
+void serial_putc (const char c)
+{
+ u32 txFl = 0;
+#ifdef DEBUG_ASC_RAW
+ static u8 * debug = (u8 *) DEBUG_ASC_RAW_TX_BUF;
+ *debug++=c;
+#endif
+ if (c == '\n')
+ serial_putc ('\r');
+ /* check do we have a free space in the TX FIFO */
+ /* get current filling level */
+ do
+ {
+ txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
+ }
+ while ( txFl == DANUBEASC_TXFIFO_FULL );
+
+ pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
+
+ /* check for errors */
+ if ( pAsc->asc_state & ASCSTATE_TOE )
+ {
+ SET_BIT(pAsc->asc_whbstate, ASCWHBSTATE_CLRTOE);
+ return;
+ }
+}
+
+void serial_puts (const char *s)
+{
+ while (*s)
+ {
+ serial_putc (*s++);
+ }
+}
+
+int asc_inb(int timeout)
+{
+ u32 symbol_mask;
+ char c;
+ while ((pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 ) {
+ }
+ symbol_mask = ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
+ c = (char)(pAsc->asc_rbuf & symbol_mask);
+ return (c);
+}
+
+int serial_getc (void)
+{
+ char c;
+ while ((pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 );
+ c = (char)(pAsc->asc_rbuf & 0xff);
+
+#ifdef DEBUG_ASC_RAW
+ static u8* debug=(u8*)(DEBUG_ASC_RAW_RX_BUF);
+ *debug++=c;
+#endif
+ return c;
+}
+
+
+
+int serial_tstc (void)
+{
+ int res = 1;
+
+#ifdef ASC_FIFO_PRESENT
+ if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
+ {
+ res = 0;
+ }
+#else
+ if (!(*(volatile unsigned long*)(SFPI_INTCON_BASEADDR + FBS_ISR) &
+ FBS_ISR_AR))
+
+ {
+ res = 0;
+ }
+#endif
+#if 0
+ else if ( pAsc->asc_con & ASCCON_FE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
+ res = 0;
+ }
+ else if ( pAsc->asc_con & ASCCON_PE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
+ res = 0;
+ }
+ else if ( pAsc->asc_con & ASCCON_OE )
+ {
+ SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
+ res = 0;
+ }
+#endif
+ return res;
+}
+
+
+int serial_start(void)
+{
+ return 1;
+}
+
+int serial_stop(void)
+{
+ return 1;
+}
--- /dev/null
+
+#define IFX_CACHE_EXTRA_INVALID_TAG \
+ mtc0 zero, CP0_TAGLO, 1; \
+ mtc0 zero, CP0_TAGLO, 2; \
+ mtc0 zero, CP0_TAGLO, 3; \
+ mtc0 zero, CP0_TAGLO, 4;
+
+#define IFX_CACHE_EXTRA_OPERATION \
+ /* set WST bit */ \
+ mfc0 a0, CP0_ECC; \
+ li a1, ECCF_WST; \
+ or a0, a1; \
+ mtc0 a0, CP0_ECC; \
+ \
+ li a0, K0BASE; \
+ move a2, t2; /* icacheSize */ \
+ move a3, t4; /* icacheLineSize */ \
+ move a1, a2; \
+ icacheop(a0,a1,a2,a3,(Index_Store_Tag_I)); \
+ \
+ /* clear WST bit */ \
+ mfc0 a0, CP0_ECC; \
+ li a1, ~ECCF_WST; \
+ and a0, a1; \
+ mtc0 a0, CP0_ECC; \
+ \
+ /* 1: initialise dcache tags. */ \
+ \
+ /* cache line size */ \
+ li a2, CFG_CACHELINE_SIZE; \
+ /* kseg0 mem address */ \
+ li a1, 0; \
+ li a3, CFG_CACHE_SETS * CFG_CACHE_WAYS; \
+1: \
+ /* store tag (invalid, not locked) */ \
+ cache 0x8, 0(a1); \
+ cache 0x9, 0(a1); \
+ \
+ add a3, -1; \
+ bne a3, zero, 1b; \
+ add a1, a2; \
+ \
+ /* set WST bit */ \
+ mfc0 a0, CP0_ECC; \
+ li a1, ECCF_WST; \
+ or a0, a1; \
+ mtc0 a0, CP0_ECC; \
+ \
+ li a0, K0BASE; \
+ move a2, t3; /* dcacheSize */ \
+ move a3, t5; /* dcacheLineSize */ \
+ move a1, a2; \
+ icacheop(a0,a1,a2,a3,(Index_Store_Tag_D)); \
+ \
+ /* clear WST bit */ \
+ mfc0 a0, CP0_ECC; \
+ li a1, ~ECCF_WST; \
+ and a0, a1; \
+ mtc0 a0, CP0_ECC;
+
--- /dev/null
+/*\r
+ * ########################################################################\r
+ *\r
+ * This program is free software; you can distribute it and/or modify it\r
+ * under the terms of the GNU General Public License (Version 2) as\r
+ * published by the Free Software Foundation.\r
+ *\r
+ * This program is distributed in the hope it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\r
+ * for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.\r
+ *\r
+ * ########################################################################\r
+ *\r
+ * danube_cgu.c\r
+ *\r
+ * Description:\r
+ * device driver of clock generation unit of Danube chip\r
+ * Author:\r
+ * Samuels Xu Liang\r
+ * Created:\r
+ * 19 Jul 2005\r
+ * History & Modification Tag:\r
+ * ___________________________________________________________________________\r
+ * | Tag | Comments | Modifier & Time |\r
+ * |--------+---------------------------------------------+------------------|\r
+ * | S0.0 | First version of this driver and the tag is | Samuels Xu Liang |\r
+ * | | implied. | 19 Jul 2005 |\r
+ * ---------------------------------------------------------------------------\r
+ *\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Head File\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ * Common Head File\r
+ */\r
+#include <linux/config.h>\r
+#include <linux/kernel.h>\r
+#include <linux/module.h>\r
+#include <linux/version.h>\r
+#include <linux/types.h>\r
+#include <linux/fs.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/init.h>\r
+#include <asm/uaccess.h>\r
+#include <asm/unistd.h>\r
+#include <asm/irq.h>\r
+#include <linux/errno.h>\r
+\r
+/*\r
+ * Chip Specific Head File\r
+ */\r
+#include "ifx_cgu.h"\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Definition\r
+ * ####################################\r
+ */\r
+\r
+#define DEBUG_ON_AMAZON 1\r
+#define DEBUG_PRINT_INFO 1\r
+\r
+/*\r
+ * Frequency of Clock Direct Feed from The Analog Line Driver Chip\r
+ */\r
+#define BASIC_INPUT_CLOCK_FREQUENCY 35328000\r
+\r
+/*\r
+ * Bits Operation\r
+ */\r
+#define GET_BITS(x, msb, lsb) (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))\r
+#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))\r
+\r
+/*\r
+ * CGU Register Mapping\r
+ */\r
+#define DANUBE_CGU (KSEG1 + 0x1F103000)\r
+#define DANUBE_CGU_DIV ((volatile u32*)(DANUBE_CGU + 0x0000))\r
+#define DANUBE_CGU_PLL_NMK0 ((volatile u32*)(DANUBE_CGU + 0x0004))\r
+#define DANUBE_CGU_PLL_SR0 ((volatile u32*)(DANUBE_CGU + 0x0008))\r
+#define DANUBE_CGU_PLL_NMK1 ((volatile u32*)(DANUBE_CGU + 0x000C))\r
+#define DANUBE_CGU_PLL_SR1 ((volatile u32*)(DANUBE_CGU + 0x0010))\r
+#define DANUBE_CGU_PLL_SR2 ((volatile u32*)(DANUBE_CGU + 0x0014))\r
+#define DANUBE_CGU_IF_CLK ((volatile u32*)(DANUBE_CGU + 0x0018))\r
+#define DANUBE_CGU_OSC_CTRL ((volatile u32*)(DANUBE_CGU + 0x001C))\r
+#define DANUBE_CGU_SMD ((volatile u32*)(DANUBE_CGU + 0x0020))\r
+#define DANUBE_CGU_CRD ((volatile u32*)(DANUBE_CGU + 0x0024))\r
+#define DANUBE_CGU_CT1SR ((volatile u32*)(DANUBE_CGU + 0x0028))\r
+#define DANUBE_CGU_CT2SR ((volatile u32*)(DANUBE_CGU + 0x002C))\r
+#define DANUBE_CGU_PCMCR ((volatile u32*)(DANUBE_CGU + 0x0030))\r
+#define DANUBE_CGU_MUX ((volatile u32*)(DANUBE_CGU + 0x0034))\r
+\r
+/*\r
+ * CGU Divider Register\r
+ */\r
+#define CGU_DIV_SFTR (*DANUBE_CGU_DIV & (1 << 31))\r
+#define CGU_DIV_DIVE (*DANUBE_CGU_DIV & (1 << 16))\r
+#define CGU_DIV_IOR GET_BITS(*DANUBE_CGU_DIV, 5, 4)\r
+#define CGU_DIV_FKS GET_BITS(*DANUBE_CGU_DIV, 3, 2)\r
+#define CGU_DIV_FBS GET_BITS(*DANUBE_CGU_DIV, 1, 0)\r
+\r
+/*\r
+ * CGU PLL0 NMK Register\r
+ */\r
+#define CGU_PLL_NMK0_PLLN ((*DANUBE_CGU_PLL_NMK0 & (0xFFFFFFFF ^ ((1 << 24) - 1))) >> 24)\r
+#define CGU_PLL_NMK0_PLLM GET_BITS(*DANUBE_CGU_PLL_NMK0, 23, 20)\r
+#define CGU_PLL_NMK0_PLLK GET_BITS(*DANUBE_CGU_PLL_NMK0, 19, 0)\r
+\r
+/*\r
+ * CGU PLL0 Status Register\r
+ */\r
+#define CGU_PLL_SR0_PLLDIV ((*DANUBE_CGU_PLL_SR0 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR0_PLLDEN (*DANUBE_CGU_PLL_SR0 & (1 << 26))\r
+#define CGU_PLL_SR0_PLLPSE GET_BITS(*DANUBE_CGU_PLL_SR0, 5, 4)\r
+#define CGU_PLL_SR0_PLLB (*DANUBE_CGU_PLL_SR0 & (1 << 2))\r
+#define CGU_PLL_SR0_PLLL (*DANUBE_CGU_PLL_SR0 & (1 << 1))\r
+#define CGU_PLL_SR0_PLLEN (*DANUBE_CGU_PLL_SR0 & (1 << 0))\r
+\r
+#define CGU_PLL_SR0_DSMSEL 1\r
+#define CGU_PLL_SR0_PHASE_DIV_EN 1\r
+\r
+/*\r
+ * CGU PLL1 NMK Register\r
+ */\r
+#define CGU_PLL_NMK1_PLLN ((*DANUBE_CGU_PLL_NMK1 & (0xFFFFFFFF ^ ((1 << 24) - 1))) >> 24)\r
+#define CGU_PLL_NMK1_PLLM GET_BITS(*DANUBE_CGU_PLL_NMK1, 23, 20)\r
+#define CGU_PLL_NMK1_PLLK GET_BITS(*DANUBE_CGU_PLL_NMK1, 19, 0)\r
+\r
+/*\r
+ * CGU PLL1 Status Register\r
+ */\r
+#define CGU_PLL_SR1_PLLDIV ((*DANUBE_CGU_PLL_SR1 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR1_PLLDEN (*DANUBE_CGU_PLL_SR1 & (1 << 26))\r
+#define CGU_PLL_SR1_PLLPSE GET_BITS(*DANUBE_CGU_PLL_SR1, 5, 4)\r
+#define CGU_PLL_SR1_PLLB (*DANUBE_CGU_PLL_SR1 & (1 << 2))\r
+#define CGU_PLL_SR1_PLLL (*DANUBE_CGU_PLL_SR1 & (1 << 1))\r
+#define CGU_PLL_SR1_PLLEN (*DANUBE_CGU_PLL_SR1 & (1 << 0))\r
+\r
+#define CGU_PLL_SR1_DSMSEL 1\r
+#define CGU_PLL_SR1_PHASE_DIV_EN 1\r
+\r
+/*\r
+ * CGU PLL2 Status Register\r
+ */\r
+#define CGU_PLL_SR2_PLLDIV ((*DANUBE_CGU_PLL_SR2 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR2_PLLDEN (*DANUBE_CGU_PLL_SR2 & (1 << 27))\r
+#define CGU_PLL_SR2_PLLN GET_BITS(*DANUBE_CGU_PLL_SR2, 25, 20)\r
+#define CGU_PLL_SR2_PLLM GET_BITS(*DANUBE_CGU_PLL_SR2, 19, 16)\r
+#define CGU_PLL_SR2_PLLPS (*DANUBE_CGU_PLL_SR2 & (1 << 5))\r
+#define CGU_PLL_SR2_PLLPE (*DANUBE_CGU_PLL_SR2 & (1 << 4))\r
+#define CGU_PLL_SR2_PLLB (*DANUBE_CGU_PLL_SR2 & (1 << 2))\r
+#define CGU_PLL_SR2_PLLL (*DANUBE_CGU_PLL_SR2 & (1 << 1))\r
+#define CGU_PLL_SR2_PLLEN (*DANUBE_CGU_PLL_SR2 & (1 << 0))\r
+\r
+/*\r
+ * CGU Interface Clock Register\r
+ */\r
+#define CGU_IF_CLK_CLKOD0 GET_BITS(*DANUBE_CGU_IF_CLK, 27, 26)\r
+#define CGU_IF_CLK_CLKOD1 GET_BITS(*DANUBE_CGU_IF_CLK, 25, 24)\r
+#define CGU_IF_CLK_CLKOD2 GET_BITS(*DANUBE_CGU_IF_CLK, 23, 22)\r
+#define CGU_IF_CLK_CLKOD3 GET_BITS(*DANUBE_CGU_IF_CLK, 21, 20)\r
+#define CGU_IF_CLK_PDA (*DANUBE_CGU_IF_CLK & (1 << 18))\r
+#define CGU_IF_CLK_PCI_B (*DANUBE_CGU_IF_CLK & (1 << 17))\r
+#define CGU_IF_CLK_PCIBM (*DANUBE_CGU_IF_CLK & (1 << 16))\r
+#define CGU_IF_CLK_MIICS (*DANUBE_CGU_IF_CLK & (1 << 3))\r
+#define CGU_IF_CLK_USBCS (*DANUBE_CGU_IF_CLK & (1 << 2))\r
+#define CGU_IF_CLK_PCIF (*DANUBE_CGU_IF_CLK & (1 << 1))\r
+#define CGU_IF_CLK_PCIS (*DANUBE_CGU_IF_CLK & (1 << 0))\r
+\r
+/*\r
+ * CGU Oscillator Control Register\r
+ */\r
+#define CGU_OSC_CTRL GET_BITS(*DANUBE_CGU_OSC_CTRL, 1, 0)\r
+\r
+/*\r
+ * CGU SDRAM Memory Delay Register\r
+ */\r
+#define CGU_SMD_CLKI (*DANUBE_CGU_SMD & (1 << 31))\r
+#define CGU_SMD_MIDS GET_BITS(*DANUBE_CGU_SMD, 17, 12)\r
+#define CGU_SMD_MODS GET_BITS(*DANUBE_CGU_SMD, 11, 6)\r
+#define CGU_SMD_MDSEL GET_BITS(*DANUBE_CGU_SMD, 5, 0)\r
+\r
+/*\r
+ * CGU CPU Clock Reduction Register\r
+ */\r
+#define CGU_CRD_SFTR (*DANUBE_CGU_CRD & (1 << 31))\r
+#define CGU_CRD_DIVE (*DANUBE_CGU_CRD & (1 << 16))\r
+#define CGU_CRD_CRD1 GET_BITS(*DANUBE_CGU_CRD, 3, 2)\r
+#define CGU_CRD_CRD GET_BITS(*DANUBE_CGU_CRD, 1, 0)\r
+\r
+/*\r
+ * CGU CT Status Register 1\r
+ */\r
+#define CGU_CT1SR_PDOUT GET_BITS(*DANUBE_CGU_CT1SR, 13, 0)\r
+\r
+/*\r
+ * CGU CT Status Register 2\r
+ */\r
+#define CGU_CT2SR_PLL1K GET_BITS(*DANUBE_CGU_CT2SR, 9, 0)\r
+\r
+/*\r
+ * CGU PCM Control Register\r
+ */\r
+#define CGU_PCMCR_DCL1 GET_BITS(*DANUBE_CGU_PCMCR, 27, 25)\r
+#define CGU_PCMCR_MUXDCL (*DANUBE_CGU_PCMCR & (1 << 22))\r
+#define CGU_PCMCR_MUXFSC (*DANUBE_CGU_PCMCR & (1 << 18))\r
+#define CGU_PCMCR_PCM_SL (*DANUBE_CGU_PCMCR & (1 << 13))\r
+#define CGU_PCMCR_DNTR (*DANUBE_CGU_PCMCR & (1 << 12))\r
+\r
+/*\r
+ * CGU Clock Mux Register\r
+ */\r
+#define CGU_MUX_MII_CLK (*DANUBE_CGU_MUX & (1 << 6))\r
+#define CGU_MUX_SUB_SYS GET_BITS(*DANUBE_CGU_MUX, 5, 3)\r
+#define CGU_MUX_PP32 GET_BITS(*DANUBE_CGU_MUX, 1, 0)\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Preparation of Debug on Amazon Chip\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ * If try module on Amazon chip, prepare some tricks to prevent invalid memory write.\r
+ */\r
+#if defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+ u32 g_pFakeRegisters[0x0100];\r
+\r
+ #undef DANUBE_CGU\r
+ #define DANUBE_CGU ((u32)g_pFakeRegisters)\r
+#endif // defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Data Type\r
+ * ####################################\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Declaration\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ * Pre-declaration of File Operations\r
+ */\r
+static ssize_t cgu_read(struct file *, char *, size_t, loff_t *);\r
+static ssize_t cgu_write(struct file *, const char *, size_t, loff_t *);\r
+static int cgu_ioctl(struct inode *, struct file *, unsigned int, unsigned long);\r
+static int cgu_open(struct inode *, struct file *);\r
+static int cgu_release(struct inode *, struct file *);\r
+\r
+/*\r
+ * Pre-declaration of 64-bit Unsigned Integer Operation\r
+ */\r
+static inline void uint64_multiply(unsigned int, unsigned int, unsigned int *);\r
+static inline void uint64_divide(unsigned int *, unsigned int, unsigned int *, unsigned int *);\r
+\r
+/*\r
+ * Calculate PLL Frequency\r
+ */\r
+static inline u32 cal_dsm(u32, u32);\r
+static inline u32 mash_dsm(u32, u32, u32);\r
+static inline u32 ssff_dsm_1(u32, u32, u32);\r
+static inline u32 ssff_dsm_2(u32, u32, u32);\r
+static inline u32 dsm(u32 M, u32, u32, int, int);\r
+static inline u32 cgu_get_pll0_fosc(void);\r
+static inline u32 cgu_get_pll0_fps(void);\r
+static inline u32 cgu_get_pll0_fdiv(void);\r
+static inline u32 cgu_get_pll1_fosc(void);\r
+static inline u32 cgu_get_pll1_fps(void);\r
+static inline u32 cgu_get_pll1_fdiv(void);\r
+static inline u32 cgu_get_pll2_fosc(void);\r
+static inline u32 cgu_get_pll2_fps(void);\r
+\r
+/*\r
+ * Export Functions\r
+ */\r
+u32 cgu_get_mips_clock(int);\r
+u32 cgu_get_cpu_clock(void);\r
+u32 cgu_get_io_region_clock(void);\r
+u32 cgu_get_fpi_bus_clock(int);\r
+u32 cgu_get_pp32_clock(void);\r
+u32 cgu_get_pci_clock(void);\r
+u32 cgu_get_ethernet_clock(void);\r
+u32 cgu_get_usb_clock(void);\r
+u32 cgu_get_clockout(int);\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Local Variable\r
+ * ####################################\r
+ */\r
+\r
+static struct file_operations cgu_fops = {\r
+ owner: THIS_MODULE,\r
+ llseek: no_llseek,\r
+ read: cgu_read,\r
+ write: cgu_write,\r
+ ioctl: cgu_ioctl,\r
+ open: cgu_open,\r
+ release: cgu_release\r
+};\r
+\r
+static struct miscdevice cgu_miscdev = {\r
+ MISC_DYNAMIC_MINOR,\r
+ "danube_cgu_dev",\r
+ &cgu_fops\r
+};\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Global Variable\r
+ * ####################################\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Local Function\r
+ * ####################################\r
+ */\r
+\r
+static ssize_t cgu_read(struct file *file, char *buf, size_t count, loff_t *ppos)\r
+{\r
+ return -EPERM;\r
+}\r
+\r
+static ssize_t cgu_write(struct file *file, const char *buf, size_t count, loff_t *ppos)\r
+{\r
+ return -EPERM;\r
+}\r
+\r
+static int cgu_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+ int ret = 0;\r
+ struct cgu_clock_rates rates;\r
+\r
+ if ( _IOC_TYPE(cmd) != CGU_IOC_MAGIC\r
+ || _IOC_NR(cmd) >= CGU_IOC_MAXNR )\r
+ return -ENOTTY;\r
+\r
+ if ( _IOC_DIR(cmd) & _IOC_READ )\r
+ ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));\r
+ else if ( _IOC_DIR(cmd) & _IOC_WRITE )\r
+ ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));\r
+ if ( ret )\r
+ return -EFAULT;\r
+\r
+ switch ( cmd )\r
+ {\r
+ case CGU_GET_CLOCK_RATES:\r
+ /* Calculate Clock Rates */\r
+ rates.mips0 = cgu_get_mips_clock(0);\r
+ rates.mips1 = cgu_get_mips_clock(1);\r
+ rates.cpu = cgu_get_cpu_clock();\r
+ rates.io_region = cgu_get_io_region_clock();\r
+ rates.fpi_bus1 = cgu_get_fpi_bus_clock(1);\r
+ rates.fpi_bus2 = cgu_get_fpi_bus_clock(2);\r
+ rates.pp32 = cgu_get_pp32_clock();\r
+ rates.pci = cgu_get_pci_clock();\r
+ rates.ethernet = cgu_get_ethernet_clock();\r
+ rates.usb = cgu_get_usb_clock();\r
+ rates.clockout0 = cgu_get_clockout(0);\r
+ rates.clockout1 = cgu_get_clockout(1);\r
+ rates.clockout2 = cgu_get_clockout(2);\r
+ rates.clockout3 = cgu_get_clockout(3);\r
+ /* Copy to User Space */\r
+ copy_to_user((char*)arg, (char*)&rates, sizeof(rates));\r
+\r
+ ret = 0;\r
+ break;\r
+ default:\r
+ ret = -ENOTTY;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static int cgu_open(struct inode *inode, struct file *file)\r
+{\r
+ return 0;\r
+}\r
+\r
+static int cgu_release(struct inode *inode, struct file *file)\r
+{\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * calculate 64-bit multiplication result of two 32-bit unsigned integer\r
+ * Input:\r
+ * u32Multiplier1 --- u32 (32-bit), one of the multipliers\r
+ * u32Multiplier2 --- u32 (32-bit), the other multiplier\r
+ * u32Result --- u32[2], array to retrieve the multiplication result,\r
+ * index 0 is high word, index 1 is low word\r
+ * Output:\r
+* none\r
+ */\r
+static inline void uint64_multiply(u32 u32Multiplier1, u32 u32Multiplier2, u32 u32Result[2])\r
+{\r
+ u32 u32Multiplier1LowWord = u32Multiplier1 & 0xFFFF;\r
+ u32 u32Multiplier1HighWord = u32Multiplier1 >> 16;\r
+ u32 u32Multiplier2LowWord = u32Multiplier2 & 0xFFFF;\r
+ u32 u32Multiplier2HighWord = u32Multiplier2 >> 16;\r
+ u32 u32Combo1, u32Combo2, u32Combo3, u32Combo4;\r
+ u32 u32Word1, u32Word2, u32Word3, u32Word4;\r
+\r
+ u32Combo1 = u32Multiplier1LowWord * u32Multiplier2LowWord;\r
+ u32Combo2 = u32Multiplier1HighWord * u32Multiplier2LowWord;\r
+ u32Combo3 = u32Multiplier1LowWord * u32Multiplier2HighWord;\r
+ u32Combo4 = u32Multiplier1HighWord * u32Multiplier2HighWord;\r
+\r
+ u32Word1 = u32Combo1 & 0xFFFF;\r
+ u32Word2 = (u32Combo1 >> 16) + (u32Combo2 & 0xFFFF) + (u32Combo3 & 0xFFFF);\r
+ u32Word3 = (u32Combo2 >> 16) + (u32Combo3 >> 16) + (u32Combo4 & 0xFFFF) + (u32Word2 >> 16);\r
+ u32Word4 = (u32Combo4 >> 16) + (u32Word3 >> 16);\r
+\r
+ u32Result[0] = (u32Word4 << 16) | u32Word3;\r
+ u32Result[1] = (u32Word2 << 16) | u32Word1;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * divide 64-bit unsigned integer with 32-bit unsigned integer\r
+ * Input:\r
+ * u32Numerator --- u32[2], index 0 is high word of numerator, while\r
+ * index 1 is low word of numerator\r
+ * u32Denominator --- u32 (32-bit), the denominator in division, this\r
+ * parameter can not be zero, or lead to unpredictable\r
+ * result\r
+ * pu32Quotient --- u32 *, the pointer to retrieve 32-bit quotient, null\r
+ * pointer means ignore quotient\r
+ * pu32Residue --- u32 *, the pointer to retrieve 32-bit residue null\r
+ * pointer means ignore residue\r
+ * Output:\r
+ * none\r
+ */\r
+static inline void uint64_divide(u32 u32Numerator[2], u32 u32Denominator, u32 *pu32Quotient, u32 *pu32Residue)\r
+{\r
+ u32 u32DWord1, u32DWord2, u32DWord3;\r
+ u32 u32Quotient;\r
+ int i;\r
+\r
+ u32DWord3 = 0;\r
+ u32DWord2 = u32Numerator[0];\r
+ u32DWord1 = u32Numerator[1];\r
+\r
+ u32Quotient = 0;\r
+\r
+ for ( i = 0; i < 64; i++ )\r
+ {\r
+ u32DWord3 = (u32DWord3 << 1) | (u32DWord2 >> 31);\r
+ u32DWord2 = (u32DWord2 << 1) | (u32DWord1 >> 31);\r
+ u32DWord1 <<= 1;\r
+ u32Quotient <<= 1;\r
+ if ( u32DWord3 >= u32Denominator )\r
+ {\r
+ u32DWord3 -= u32Denominator;\r
+ u32Quotient |= 1;\r
+ }\r
+ }\r
+ if ( pu32Quotient )\r
+ *pu32Quotient = u32Quotient;\r
+ if ( pu32Residue )\r
+ *pu32Residue = u32DWord3;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * common routine to calculate PLL frequency\r
+ * Input:\r
+ * num --- u32, numerator\r
+ * den --- u32, denominator\r
+ * Output:\r
+ * u32 --- frequency the PLL output\r
+ */\r
+static inline u32 cal_dsm(u32 num, u32 den)\r
+{\r
+ u32 ret;\r
+ u32 temp[2];\r
+ u32 residue;\r
+\r
+ uint64_multiply(num, BASIC_INPUT_CLOCK_FREQUENCY, temp);\r
+ uint64_divide(temp, den, &ret, &residue);\r
+ if ( (residue << 1) >= den )\r
+ ret++;\r
+\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * calculate PLL frequency following MASH-DSM\r
+ * Input:\r
+ * M --- u32, denominator coefficient\r
+ * N --- u32, numerator integer coefficient\r
+ * K --- u32, numerator fraction coefficient\r
+ * Output:\r
+ * u32 --- frequency the PLL output\r
+ */\r
+static inline u32 mash_dsm(u32 M, u32 N, u32 K)\r
+{\r
+ u32 num = ((N + 1) << 10) + K;\r
+ u32 den = (M + 1) << 10;\r
+\r
+ return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * calculate PLL frequency following SSFF-DSM (0.25 < fraction < 0.75)\r
+ * Input:\r
+ * M --- u32, denominator coefficient\r
+ * N --- u32, numerator integer coefficient\r
+ * K --- u32, numerator fraction coefficient\r
+ * Output:\r
+ * u32 --- frequency the PLL output\r
+ */\r
+static inline u32 ssff_dsm_1(u32 M, u32 N, u32 K)\r
+{\r
+ u32 num = ((N + 1) << 11) + K + 512;\r
+ u32 den = (M + 1) << 11;\r
+\r
+ return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * calculate PLL frequency following SSFF-DSM\r
+ * (fraction < 0.125 || fraction > 0.875)\r
+ * Input:\r
+ * M --- u32, denominator coefficient\r
+ * N --- u32, numerator integer coefficient\r
+ * K --- u32, numerator fraction coefficient\r
+ * Output:\r
+ * u32 --- frequency the PLL output\r
+ */\r
+static inline u32 ssff_dsm_2(u32 M, u32 N, u32 K)\r
+{\r
+ u32 num = K >= 512 ? ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;\r
+ u32 den = (M + 1) << 12;\r
+\r
+ return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * calculate PLL frequency\r
+ * Input:\r
+ * M --- u32, denominator coefficient\r
+ * N --- u32, numerator integer coefficient\r
+ * K --- u32, numerator fraction coefficient\r
+ * dsmsel --- int, 0: MASH-DSM, 1: SSFF-DSM\r
+ * phase_div_en --- int, 0: 0.25 < fraction < 0.75\r
+ * 1: fraction < 0.125 || fraction > 0.875\r
+ * Output:\r
+ * u32 --- frequency the PLL output\r
+ */\r
+static inline u32 dsm(u32 M, u32 N, u32 K, int dsmsel, int phase_div_en)\r
+{\r
+ if ( !dsmsel )\r
+ return mash_dsm(M, N, K);\r
+ else\r
+ if ( !phase_div_en )\r
+ return ssff_dsm_1(M, N, K);\r
+ else\r
+ return ssff_dsm_2(M, N, K);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get oscillate frequency of PLL0\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL0 Fosc\r
+ */\r
+static inline u32 cgu_get_pll0_fosc(void)\r
+{\r
+ return CGU_PLL_SR0_PLLB ? BASIC_INPUT_CLOCK_FREQUENCY : dsm(CGU_PLL_NMK0_PLLM, CGU_PLL_NMK0_PLLN, CGU_PLL_NMK0_PLLK, CGU_PLL_SR0_DSMSEL, CGU_PLL_SR0_PHASE_DIV_EN);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get output frequency of PLL0 phase shifter\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL0 Fps\r
+ */\r
+static inline u32 cgu_get_pll0_fps(void)\r
+{\r
+ register u32 fps = cgu_get_pll0_fosc();\r
+\r
+ switch ( CGU_PLL_SR0_PLLPSE )\r
+ {\r
+ case 1:\r
+ /* 1.5 */\r
+ fps = ((fps << 1) + 1) / 3; break;\r
+ case 2:\r
+ /* 1.25 */\r
+ fps = ((fps << 2) + 2) / 5; break;\r
+ case 3:\r
+ /* 3.5 */\r
+ fps = ((fps << 1) + 3) / 7;\r
+ }\r
+ return fps;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get output frequency of PLL0 output divider\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL0 Fdiv\r
+ */\r
+static inline u32 cgu_get_pll0_fdiv(void)\r
+{\r
+ register u32 fdiv = cgu_get_pll0_fosc();\r
+\r
+ if ( CGU_PLL_SR0_PLLDEN )\r
+ fdiv = (fdiv + (CGU_PLL_SR0_PLLDIV + 1) / 2) / (CGU_PLL_SR0_PLLDIV + 1);\r
+ return fdiv;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get oscillate frequency of PLL1\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL1 Fosc\r
+ */\r
+static inline u32 cgu_get_pll1_fosc(void)\r
+{\r
+ return CGU_PLL_SR1_PLLB ? BASIC_INPUT_CLOCK_FREQUENCY : dsm(CGU_PLL_NMK1_PLLM, CGU_PLL_NMK1_PLLN, CGU_PLL_NMK1_PLLK, CGU_PLL_SR1_DSMSEL, CGU_PLL_SR1_PHASE_DIV_EN);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get output frequency of PLL1 phase shifter\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL1 Fps\r
+ */\r
+static inline u32 cgu_get_pll1_fps(void)\r
+{\r
+ register u32 fps = cgu_get_pll1_fosc();\r
+\r
+ switch ( CGU_PLL_SR1_PLLPSE )\r
+ {\r
+ case 1:\r
+ /* 1.5 */\r
+ fps = ((fps << 1) + 1) / 3; break;\r
+ case 2:\r
+ /* 1.25 */\r
+ fps = ((fps << 2) + 2) / 5; break;\r
+ case 3:\r
+ /* 3.5 */\r
+ fps = ((fps << 1) + 3) / 7;\r
+ }\r
+ return fps;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get output frequency of PLL1 output divider\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL1 Fdiv\r
+ */\r
+static inline u32 cgu_get_pll1_fdiv(void)\r
+{\r
+ register u32 fdiv = cgu_get_pll1_fosc();\r
+\r
+ if ( CGU_PLL_SR1_PLLDEN )\r
+ fdiv = (fdiv + (CGU_PLL_SR1_PLLDIV + 1) / 2) / (CGU_PLL_SR1_PLLDIV + 1);\r
+ return fdiv;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get oscillate frequency of PLL2\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL2 Fosc\r
+ */\r
+static inline u32 cgu_get_pll2_fosc(void)\r
+{\r
+ u32 ret;\r
+ u32 temp[2];\r
+ u32 residue;\r
+\r
+ uint64_multiply((CGU_PLL_SR2_PLLN + 1) * 8, cgu_get_pll0_fdiv(), temp);\r
+ uint64_divide(temp, CGU_PLL_SR2_PLLM + 1, &ret, &residue);\r
+ if ( (residue << 1) >= CGU_PLL_SR2_PLLM )\r
+ ret++;\r
+\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get output frequency of PLL2 phase shifter\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PLL2 Fps\r
+ */\r
+static inline u32 cgu_get_pll2_fps(void)\r
+{\r
+ register u32 fps = cgu_get_pll2_fosc();\r
+\r
+ if ( CGU_PLL_SR2_PLLPE )\r
+ {\r
+ if ( CGU_PLL_SR2_PLLPS )\r
+ /* 1.25 */\r
+ fps = ((fps << 3) + 4) / 9;\r
+ else\r
+ /* 1.125 */\r
+ fps = ((fps << 2) + 2) / 5;\r
+ }\r
+\r
+ return fps;\r
+}\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Global Function\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of MIPS (0: core, 1: DSP)\r
+ * Input:\r
+ * cpu --- int, 0: core, 1: DSP\r
+ * Output:\r
+ * u32 --- frequency of MIPS coprocessor (0: core, 1: DSP)\r
+ */\r
+u32 cgu_get_mips_clock(int cpu)\r
+{\r
+ register u32 ret = cgu_get_pll0_fosc();\r
+\r
+ if ( CGU_CRD_CRD )\r
+ ret = (ret + (CGU_CRD_CRD >> 1)) / (CGU_CRD_CRD + 1);\r
+ if ( cpu == 0 && CGU_CRD_CRD1 )\r
+ ret >>= CGU_CRD_CRD1;\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of MIPS core\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of MIPS core\r
+ */\r
+u32 cgu_get_cpu_clock(void)\r
+{\r
+ return cgu_get_mips_clock(0);\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of sub-system and memory controller\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of sub-system and memory controller\r
+ */\r
+u32 cgu_get_io_region_clock(void)\r
+{\r
+ register u32 ret = (CGU_MUX_SUB_SYS > 4) ? cgu_get_pll0_fosc() : cgu_get_mips_clock(1);\r
+\r
+ switch ( CGU_MUX_SUB_SYS )\r
+ {\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ default:\r
+ ret = (ret + 1) >> 1; break;\r
+ case 2:\r
+ ret = (ret + 1) / 3; break;\r
+ case 3:\r
+ ret = (ret + 2) >> 2; break;\r
+ case 5:\r
+ ret = ((ret << 1) + 1) / 3; break;\r
+ case 6:\r
+ ret = ((ret << 1) + 2) / 5;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of FPI bus\r
+ * Input:\r
+ * fpi --- int, 1: FPI bus 1 (FBS1/Fast FPI Bus), 2: FPI bus 2 (FBS2)\r
+ * Output:\r
+ * u32 --- frequency of FPI bus\r
+ */\r
+u32 cgu_get_fpi_bus_clock(int fpi)\r
+{\r
+ register u32 ret = cgu_get_io_region_clock();\r
+\r
+ if ( fpi == 2 )\r
+ ret >>= 1;\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of PP32 processor\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PP32 processor\r
+ */\r
+u32 cgu_get_pp32_clock(void)\r
+{\r
+ register u32 ret;\r
+\r
+ switch ( CGU_MUX_PP32 )\r
+ {\r
+ case 0:\r
+ default:\r
+ ret = ((cgu_get_pll2_fosc() << 2) + 2) / 5; break;\r
+ case 1:\r
+ ret = ((cgu_get_pll2_fosc() << 3) + 4) / 9; break;\r
+ case 2:\r
+ ret = cgu_get_fpi_bus_clock(1); break;\r
+ case 3:\r
+ ret = cgu_get_mips_clock(1);\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of PCI bus\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of PCI bus\r
+ */\r
+u32 cgu_get_pci_clock(void)\r
+{\r
+ register u32 ret = 0;\r
+\r
+ if ( !CGU_IF_CLK_PCIS )\r
+ {\r
+ ret = cgu_get_pll2_fosc();\r
+ if ( CGU_IF_CLK_PCIF )\r
+ ret = (ret + 2) / 5;\r
+ else\r
+ ret = (ret + 4) / 9;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+/*\r
+ * Description:\r
+ * get frequency of ethernet module (MII)\r
+ * Input:\r
+ * none\r
+ * Output:\r
+ * u32 --- frequency of ethernet module\r
+ */\r
+u32 cgu_get_ethernet_clock(void)\r
+{\r
+ register u32 ret = 0;\r
+\r
+ if ( !CGU_IF_CLK_MIICS )\r
+ {\r
+ ret = cgu_get_pll2_fosc();\r
+ if ( CGU_MUX_MII_CLK )\r
+ ret = (ret + 3) / 6;\r
+ else\r
+ &nbs