From: stroese Date: Thu, 16 Dec 2004 18:21:17 +0000 (+0000) Subject: CPCI750 board support added X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=771e05be07589ca159d361142387e03fd26d2f6d;p=u-boot.git CPCI750 board support added --- diff --git a/board/esd/cpci750/64360.h b/board/esd/cpci750/64360.h new file mode 100644 index 0000000000..262abf3e99 --- /dev/null +++ b/board/esd/cpci750/64360.h @@ -0,0 +1,53 @@ +/* + * (C) Copyright 2003 + * Ingo Assmus + * for cpci750 Reinhard Arlt + * + * 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 + */ + +/* + * main board support/init for the cpci750. + */ + +#ifndef __64360_H__ +#define __64360_H__ + +/* CPU Configuration bits */ +#define CPU_CONF_ADDR_MISS_EN (1 << 8) +#define CPU_CONF_SINGLE_CPU (1 << 11) +#define CPU_CONF_ENDIANESS (1 << 12) +#define CPU_CONF_PIPELINE (1 << 13) +#define CPU_CONF_STOP_RETRY (1 << 17) +#define CPU_CONF_MULTI_DECODE (1 << 18) +#define CPU_CONF_DP_VALID (1 << 19) +#define CPU_CONF_PERR_PROP (1 << 22) +#define CPU_CONF_AACK_DELAY_2 (1 << 25) +#define CPU_CONF_AP_VALID (1 << 26) +#define CPU_CONF_REMAP_WR_DIS (1 << 27) + +/* CPU Master Control bits */ +#define CPU_MAST_CTL_ARB_EN (1 << 8) +#define CPU_MAST_CTL_MASK_BR_1 (1 << 9) +#define CPU_MAST_CTL_M_WR_TRIG (1 << 10) +#define CPU_MAST_CTL_M_RD_TRIG (1 << 11) +#define CPU_MAST_CTL_CLEAN_BLK (1 << 12) +#define CPU_MAST_CTL_FLUSH_BLK (1 << 13) + +#endif /* __64360_H__ */ diff --git a/board/esd/cpci750/Makefile b/board/esd/cpci750/Makefile new file mode 100644 index 0000000000..04867295cc --- /dev/null +++ b/board/esd/cpci750/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2001 +# Josh Huber , Mission Critical Linux, Inc. +# +# 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 + +SOBJS = misc.o + +OBJS = $(BOARD).o serial.o ../../Marvell/common/memory.o pci.o \ + mv_eth.o mpsc.o i2c.o \ + sdram_init.o strataflash.o ide.o + +$(LIB): .depend $(OBJS) $(SOBJS) + $(AR) crv $@ $(OBJS) $(SOBJS) + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/board/esd/cpci750/config.mk b/board/esd/cpci750/config.mk new file mode 100644 index 0000000000..7795dfa813 --- /dev/null +++ b/board/esd/cpci750/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2004 +# Reinhard Arlt +# +# 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 +# + +# +# cpci750 board +# + +TEXT_BASE = 0xfff00000 diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c new file mode 100644 index 0000000000..56c12d7317 --- /dev/null +++ b/board/esd/cpci750/cpci750.c @@ -0,0 +1,885 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * 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 + * + * modifications for the DB64360 eval board based by Ingo.Assmus@keymile.com + * modifications for the cpci750 by reinhard.arlt@esd-electronics.com + */ + +/* + * cpci750.c - main board support/init for the esd cpci750. + */ + +#include +#include <74xx_7xx.h> +#include "../../Marvell/include/memory.h" +#include "../../Marvell/include/pci.h" +#include "../../Marvell/include/mv_gen_reg.h" +#include + +#include "eth.h" +#include "mpsc.h" +#include "i2c.h" +#include "64360.h" +#include "mv_regs.h" + +#undef DEBUG +/*#define DEBUG */ + +#ifdef CONFIG_PCI +#define MAP_PCI +#endif /* of CONFIG_PCI */ + +#ifdef DEBUG +#define DP(x) x +#else +#define DP(x) +#endif + +extern void flush_data_cache (void); +extern void invalidate_l1_instruction_cache (void); + +/* ------------------------------------------------------------------------- */ + +/* this is the current GT register space location */ +/* it starts at CFG_DFL_GT_REGS but moves later to CFG_GT_REGS */ + +/* Unfortunately, we cant change it while we are in flash, so we initialize it + * to the "final" value. This means that any debug_led calls before + * board_early_init_f wont work right (like in cpu_init_f). + * See also my_remap_gt_regs below. (NTL) + */ + +void board_prebootm_init (void); +unsigned int INTERNAL_REG_BASE_ADDR = CFG_GT_REGS; +int display_mem_map (void); + +/* ------------------------------------------------------------------------- */ + +/* + * This is a version of the GT register space remapping function that + * doesn't touch globals (meaning, it's ok to run from flash.) + * + * Unfortunately, this has the side effect that a writable + * INTERNAL_REG_BASE_ADDR is impossible. Oh well. + */ + +void my_remap_gt_regs (u32 cur_loc, u32 new_loc) +{ + u32 temp; + + /* check and see if it's already moved */ + +/* original ppcboot 1.1.6 source + + temp = in_le32((u32 *)(new_loc + INTERNAL_SPACE_DECODE)); + if ((temp & 0xffff) == new_loc >> 20) + return; + + temp = (in_le32((u32 *)(cur_loc + INTERNAL_SPACE_DECODE)) & + 0xffff0000) | (new_loc >> 20); + + out_le32((u32 *)(cur_loc + INTERNAL_SPACE_DECODE), temp); + + while (GTREGREAD(INTERNAL_SPACE_DECODE) != temp); +original ppcboot 1.1.6 source end */ + + temp = in_le32 ((u32 *) (new_loc + INTERNAL_SPACE_DECODE)); + if ((temp & 0xffff) == new_loc >> 16) + return; + + temp = (in_le32 ((u32 *) (cur_loc + INTERNAL_SPACE_DECODE)) & + 0xffff0000) | (new_loc >> 16); + + out_le32 ((u32 *) (cur_loc + INTERNAL_SPACE_DECODE), temp); + + while (GTREGREAD (INTERNAL_SPACE_DECODE) != temp); +} + +#ifdef CONFIG_PCI + +static void gt_pci_config (void) +{ + unsigned int stat; + unsigned int val = 0x00fff864; /* DINK32: BusNum 23:16, DevNum 15:11, FuncNum 10:8, RegNum 7:2 */ + + /* In PCIX mode devices provide their own bus and device numbers. We query the Discovery II's + * config registers by writing ones to the bus and device. + * We then update the Virtual register with the correct value for the bus and device. + */ + if ((GTREGREAD (PCI_0_MODE) & (BIT4 | BIT5)) != 0) { /*if PCI-X */ + GT_REG_WRITE (PCI_0_CONFIG_ADDR, BIT31 | val); + + GT_REG_READ (PCI_0_CONFIG_DATA_VIRTUAL_REG, &stat); + + GT_REG_WRITE (PCI_0_CONFIG_ADDR, BIT31 | val); + GT_REG_WRITE (PCI_0_CONFIG_DATA_VIRTUAL_REG, + (stat & 0xffff0000) | CFG_PCI_IDSEL); + + } + if ((GTREGREAD (PCI_1_MODE) & (BIT4 | BIT5)) != 0) { /*if PCI-X */ + GT_REG_WRITE (PCI_1_CONFIG_ADDR, BIT31 | val); + GT_REG_READ (PCI_1_CONFIG_DATA_VIRTUAL_REG, &stat); + + GT_REG_WRITE (PCI_1_CONFIG_ADDR, BIT31 | val); + GT_REG_WRITE (PCI_1_CONFIG_DATA_VIRTUAL_REG, + (stat & 0xffff0000) | CFG_PCI_IDSEL); + } + + /* Enable master */ + PCI_MASTER_ENABLE (0, SELF); + PCI_MASTER_ENABLE (1, SELF); + + /* Enable PCI0/1 Mem0 and IO 0 disable all others */ + GT_REG_READ (BASE_ADDR_ENABLE, &stat); + stat |= (1 << 11) | (1 << 12) | (1 << 13) | (1 << 16) | (1 << 17) | (1 + << + 18); + stat &= ~((1 << 9) | (1 << 10) | (1 << 14) | (1 << 15)); + GT_REG_WRITE (BASE_ADDR_ENABLE, stat); + + /* ronen- add write to pci remap registers for 64460. + in 64360 when writing to pci base go and overide remap automaticaly, + in 64460 it doesn't */ + GT_REG_WRITE (PCI_0_IO_BASE_ADDR, CFG_PCI0_IO_SPACE >> 16); + GT_REG_WRITE (PCI_0I_O_ADDRESS_REMAP, CFG_PCI0_IO_SPACE_PCI >> 16); + GT_REG_WRITE (PCI_0_IO_SIZE, (CFG_PCI0_IO_SIZE - 1) >> 16); + + GT_REG_WRITE (PCI_0_MEMORY0_BASE_ADDR, CFG_PCI0_MEM_BASE >> 16); + GT_REG_WRITE (PCI_0MEMORY0_ADDRESS_REMAP, CFG_PCI0_MEM_BASE >> 16); + GT_REG_WRITE (PCI_0_MEMORY0_SIZE, (CFG_PCI0_MEM_SIZE - 1) >> 16); + + GT_REG_WRITE (PCI_1_IO_BASE_ADDR, CFG_PCI1_IO_SPACE >> 16); + GT_REG_WRITE (PCI_1I_O_ADDRESS_REMAP, CFG_PCI1_IO_SPACE_PCI >> 16); + GT_REG_WRITE (PCI_1_IO_SIZE, (CFG_PCI1_IO_SIZE - 1) >> 16); + + GT_REG_WRITE (PCI_1_MEMORY0_BASE_ADDR, CFG_PCI1_MEM_BASE >> 16); + GT_REG_WRITE (PCI_1MEMORY0_ADDRESS_REMAP, CFG_PCI1_MEM_BASE >> 16); + GT_REG_WRITE (PCI_1_MEMORY0_SIZE, (CFG_PCI1_MEM_SIZE - 1) >> 16); + + /* PCI interface settings */ + /* Timeout set to retry forever */ + GT_REG_WRITE (PCI_0TIMEOUT_RETRY, 0x0); + GT_REG_WRITE (PCI_1TIMEOUT_RETRY, 0x0); + + /* ronen - enable only CS0 and Internal reg!! */ + GT_REG_WRITE (PCI_0BASE_ADDRESS_REGISTERS_ENABLE, 0xfffffdfe); + GT_REG_WRITE (PCI_1BASE_ADDRESS_REGISTERS_ENABLE, 0xfffffdfe); + +/*ronen update the pci internal registers base address.*/ +#ifdef MAP_PCI + for (stat = 0; stat <= PCI_HOST1; stat++) + pciWriteConfigReg (stat, + PCI_INTERNAL_REGISTERS_MEMORY_MAPPED_BASE_ADDRESS, + SELF, CFG_GT_REGS); +#endif + +} +#endif + +/* Setup CPU interface paramaters */ +static void gt_cpu_config (void) +{ + cpu_t cpu = get_cpu_type (); + ulong tmp; + + /* cpu configuration register */ + tmp = GTREGREAD (CPU_CONFIGURATION); + + /* set the SINGLE_CPU bit see MV64360 P.399 */ +#ifndef CFG_GT_DUAL_CPU /* SINGLE_CPU seems to cause JTAG problems */ + tmp |= CPU_CONF_SINGLE_CPU; +#endif + + tmp &= ~CPU_CONF_AACK_DELAY_2; + + tmp |= CPU_CONF_DP_VALID; + tmp |= CPU_CONF_AP_VALID; + + tmp |= CPU_CONF_PIPELINE; + + GT_REG_WRITE (CPU_CONFIGURATION, tmp); /* Marvell (VXWorks) writes 0x20220FF */ + + /* CPU master control register */ + tmp = GTREGREAD (CPU_MASTER_CONTROL); + + tmp |= CPU_MAST_CTL_ARB_EN; + + if ((cpu == CPU_7400) || + (cpu == CPU_7410) || (cpu == CPU_7455) || (cpu == CPU_7450)) { + + tmp |= CPU_MAST_CTL_CLEAN_BLK; + tmp |= CPU_MAST_CTL_FLUSH_BLK; + + } else { + /* cleanblock must be cleared for CPUs + * that do not support this command (603e, 750) + * see Res#1 */ + tmp &= ~CPU_MAST_CTL_CLEAN_BLK; + tmp &= ~CPU_MAST_CTL_FLUSH_BLK; + } + GT_REG_WRITE (CPU_MASTER_CONTROL, tmp); +} + +/* + * board_early_init_f. + * + * set up gal. device mappings, etc. + */ +int board_early_init_f (void) +{ + + /* + * set up the GT the way the kernel wants it + * the call to move the GT register space will obviously + * fail if it has already been done, but we're going to assume + * that if it's not at the power-on location, it's where we put + * it last time. (huber) + */ + + my_remap_gt_regs (CFG_DFL_GT_REGS, CFG_GT_REGS); + + /* No PCI in first release of Port To_do: enable it. */ +#ifdef CONFIG_PCI + gt_pci_config (); +#endif + /* mask all external interrupt sources */ + GT_REG_WRITE (CPU_INTERRUPT_MASK_REGISTER_LOW, 0); + GT_REG_WRITE (CPU_INTERRUPT_MASK_REGISTER_HIGH, 0); + /* new in MV6436x */ + GT_REG_WRITE (CPU_INTERRUPT_1_MASK_REGISTER_LOW, 0); + GT_REG_WRITE (CPU_INTERRUPT_1_MASK_REGISTER_HIGH, 0); + /* --------------------- */ + GT_REG_WRITE (PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0); + GT_REG_WRITE (PCI_0INTERRUPT_CAUSE_MASK_REGISTER_HIGH, 0); + GT_REG_WRITE (PCI_1INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0); + GT_REG_WRITE (PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, 0); + /* does not exist in MV6436x + GT_REG_WRITE(CPU_INT_0_MASK, 0); + GT_REG_WRITE(CPU_INT_1_MASK, 0); + GT_REG_WRITE(CPU_INT_2_MASK, 0); + GT_REG_WRITE(CPU_INT_3_MASK, 0); + --------------------- */ + + + /* ----- DEVICE BUS SETTINGS ------ */ + + /* + * EVB + * 0 - SRAM ???? + * 1 - RTC ???? + * 2 - UART ???? + * 3 - Flash checked 32Bit Intel Strata + * boot - BootCS checked 8Bit 29LV040B + * + */ + + /* + * the dual 7450 module requires burst access to the boot + * device, so the serial rom copies the boot device to the + * on-board sram on the eval board, and updates the correct + * registers to boot from the sram. (device0) + */ + + memoryMapDeviceSpace (DEVICE0, CFG_DEV0_SPACE, CFG_DEV0_SIZE); + memoryMapDeviceSpace (DEVICE1, CFG_DEV1_SPACE, CFG_DEV1_SIZE); + memoryMapDeviceSpace (DEVICE2, CFG_DEV2_SPACE, CFG_DEV2_SIZE); + memoryMapDeviceSpace (DEVICE3, CFG_DEV3_SPACE, CFG_DEV3_SIZE); + + + /* configure device timing */ + GT_REG_WRITE (DEVICE_BANK0PARAMETERS, CFG_DEV0_PAR); + GT_REG_WRITE (DEVICE_BANK1PARAMETERS, CFG_DEV1_PAR); + GT_REG_WRITE (DEVICE_BANK2PARAMETERS, CFG_DEV2_PAR); + GT_REG_WRITE (DEVICE_BANK3PARAMETERS, CFG_DEV3_PAR); + +#ifdef CFG_32BIT_BOOT_PAR /* set port parameters for Flash device module access */ + /* detect if we are booting from the 32 bit flash */ + if (GTREGREAD (DEVICE_BOOT_BANK_PARAMETERS) & (0x3 << 20)) { + /* 32 bit boot flash */ + GT_REG_WRITE (DEVICE_BANK3PARAMETERS, CFG_8BIT_BOOT_PAR); + GT_REG_WRITE (DEVICE_BOOT_BANK_PARAMETERS, + CFG_32BIT_BOOT_PAR); + } else { + /* 8 bit boot flash */ + GT_REG_WRITE (DEVICE_BANK3PARAMETERS, CFG_32BIT_BOOT_PAR); + GT_REG_WRITE (DEVICE_BOOT_BANK_PARAMETERS, CFG_8BIT_BOOT_PAR); + } +#else + /* 8 bit boot flash only */ +/* GT_REG_WRITE(DEVICE_BOOT_BANK_PARAMETERS, CFG_8BIT_BOOT_PAR);*/ +#endif + + + gt_cpu_config (); + + /* MPP setup */ + GT_REG_WRITE (MPP_CONTROL0, CFG_MPP_CONTROL_0); + GT_REG_WRITE (MPP_CONTROL1, CFG_MPP_CONTROL_1); + GT_REG_WRITE (MPP_CONTROL2, CFG_MPP_CONTROL_2); + GT_REG_WRITE (MPP_CONTROL3, CFG_MPP_CONTROL_3); + + GT_REG_WRITE (GPP_LEVEL_CONTROL, CFG_GPP_LEVEL_CONTROL); + DEBUG_LED0_ON (); + DEBUG_LED1_ON (); + DEBUG_LED2_ON (); + + return 0; +} + +/* various things to do after relocation */ + +int misc_init_r () +{ + icache_enable (); +#ifdef CFG_L2 + l2cache_enable (); +#endif +#ifdef CONFIG_MPSC + + mpsc_sdma_init (); + mpsc_init2 (); +#endif + +#if 0 + /* disable the dcache and MMU */ + dcache_lock (); +#endif + return 0; +} + +void after_reloc (ulong dest_addr, gd_t * gd) +{ + + memoryMapDeviceSpace (BOOT_DEVICE, CFG_BOOT_SPACE, CFG_BOOT_SIZE); + + display_mem_map (); + /* now, jump to the main ppcboot board init code */ + board_init_r (gd, dest_addr); + /* NOTREACHED */ +} + +/* ------------------------------------------------------------------------- */ + +/* + * Check Board Identity: + * + * right now, assume borad type. (there is just one...after all) + */ + +int checkboard (void) +{ + int l_type = 0; + + printf ("BOARD: %s\n", CFG_BOARD_NAME); + return (l_type); +} + +/* utility functions */ +void debug_led (int led, int mode) +{ +} + +int display_mem_map (void) +{ + int i, j; + unsigned int base, size, width; + + /* SDRAM */ + printf ("SD (DDR) RAM\n"); + for (i = 0; i <= BANK3; i++) { + base = memoryGetBankBaseAddress (i); + size = memoryGetBankSize (i); + if (size != 0) { + printf ("BANK%d: base - 0x%08x\tsize - %dM bytes\n", + i, base, size >> 20); + } + } +#ifdef CONFIG_PCI + /* CPU's PCI windows */ + for (i = 0; i <= PCI_HOST1; i++) { + printf ("\nCPU's PCI %d windows\n", i); + base = pciGetSpaceBase (i, PCI_IO); + size = pciGetSpaceSize (i, PCI_IO); + printf (" IO: base - 0x%08x\tsize - %dM bytes\n", base, + size >> 20); + for (j = 0; + j <= + PCI_REGION0 + /*ronen currently only first PCI MEM is used 3 */ ; + j++) { + base = pciGetSpaceBase (i, j); + size = pciGetSpaceSize (i, j); + printf ("MEMORY %d: base - 0x%08x\tsize - %dM bytes\n", j, base, size >> 20); + } + } +#endif /* of CONFIG_PCI */ + /* Devices */ + printf ("\nDEVICES\n"); + for (i = 0; i <= DEVICE3; i++) { + base = memoryGetDeviceBaseAddress (i); + size = memoryGetDeviceSize (i); + width = memoryGetDeviceWidth (i) * 8; + printf ("DEV %d: base - 0x%08x size - %dM bytes\twidth - %d bits", i, base, size >> 20, width); + if (i == 0) + printf ("\t- FLASH\n"); + else if (i == 1) + printf ("\t- FLASH\n"); + else if (i == 2) + printf ("\t- FLASH\n"); + else + printf ("\t- RTC/REGS/CAN\n"); + } + + /* Bootrom */ + base = memoryGetDeviceBaseAddress (BOOT_DEVICE); /* Boot */ + size = memoryGetDeviceSize (BOOT_DEVICE); + width = memoryGetDeviceWidth (BOOT_DEVICE) * 8; + printf (" BOOT: base - 0x%08x size - %dM bytes\twidth - %d bits\t- FLASH\n", + base, size >> 20, width); + return (0); +} + +/* DRAM check routines copied from gw8260 */ + +#if defined (CFG_DRAM_TEST) + +/*********************************************************************/ +/* NAME: move64() - moves a double word (64-bit) */ +/* */ +/* DESCRIPTION: */ +/* this function performs a double word move from the data at */ +/* the source pointer to the location at the destination pointer. */ +/* */ +/* INPUTS: */ +/* unsigned long long *src - pointer to data to move */ +/* */ +/* OUTPUTS: */ +/* unsigned long long *dest - pointer to locate to move data */ +/* */ +/* RETURNS: */ +/* None */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* May cloober fr0. */ +/* */ +/*********************************************************************/ +static void move64 (unsigned long long *src, unsigned long long *dest) +{ + asm ("lfd 0, 0(3)\n\t" /* fpr0 = *scr */ + "stfd 0, 0(4)" /* *dest = fpr0 */ + : : : "fr0"); /* Clobbers fr0 */ + return; +} + + +#if defined (CFG_DRAM_TEST_DATA) + +unsigned long long pattern[] = { + 0xaaaaaaaaaaaaaaaa, + 0xcccccccccccccccc, + 0xf0f0f0f0f0f0f0f0, + 0xff00ff00ff00ff00, + 0xffff0000ffff0000, + 0xffffffff00000000, + 0x00000000ffffffff, + 0x0000ffff0000ffff, + 0x00ff00ff00ff00ff, + 0x0f0f0f0f0f0f0f0f, + 0x3333333333333333, + 0x5555555555555555 +}; + +/*********************************************************************/ +/* NAME: mem_test_data() - test data lines for shorts and opens */ +/* */ +/* DESCRIPTION: */ +/* Tests data lines for shorts and opens by forcing adjacent data */ +/* to opposite states. Because the data lines could be routed in */ +/* an arbitrary manner the must ensure test patterns ensure that */ +/* every case is tested. By using the following series of binary */ +/* patterns every combination of adjacent bits is test regardless */ +/* of routing. */ +/* */ +/* ...101010101010101010101010 */ +/* ...110011001100110011001100 */ +/* ...111100001111000011110000 */ +/* ...111111110000000011111111 */ +/* */ +/* Carrying this out, gives us six hex patterns as follows: */ +/* */ +/* 0xaaaaaaaaaaaaaaaa */ +/* 0xcccccccccccccccc */ +/* 0xf0f0f0f0f0f0f0f0 */ +/* 0xff00ff00ff00ff00 */ +/* 0xffff0000ffff0000 */ +/* 0xffffffff00000000 */ +/* */ +/* The number test patterns will always be given by: */ +/* */ +/* log(base 2)(number data bits) = log2 (64) = 6 */ +/* */ +/* To test for short and opens to other signals on our boards. we */ +/* simply */ +/* test with the 1's complemnt of the paterns as well. */ +/* */ +/* OUTPUTS: */ +/* Displays failing test pattern */ +/* */ +/* RETURNS: */ +/* 0 - Passed test */ +/* 1 - Failed test */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* Assumes only one one SDRAM bank */ +/* */ +/*********************************************************************/ +int mem_test_data (void) +{ + unsigned long long *pmem = (unsigned long long *) CFG_MEMTEST_START; + unsigned long long temp64; + int num_patterns = sizeof (pattern) / sizeof (pattern[0]); + int i; + unsigned int hi, lo; + + for (i = 0; i < num_patterns; i++) { + move64 (&(pattern[i]), pmem); + move64 (pmem, &temp64); + + /* hi = (temp64>>32) & 0xffffffff; */ + /* lo = temp64 & 0xffffffff; */ + /* printf("\ntemp64 = 0x%08x%08x", hi, lo); */ + + hi = (pattern[i] >> 32) & 0xffffffff; + lo = pattern[i] & 0xffffffff; + /* printf("\npattern[%d] = 0x%08x%08x", i, hi, lo); */ + + if (temp64 != pattern[i]) { + printf ("\n Data Test Failed, pattern 0x%08x%08x", + hi, lo); + return 1; + } + } + + return 0; +} +#endif /* CFG_DRAM_TEST_DATA */ + +#if defined (CFG_DRAM_TEST_ADDRESS) +/*********************************************************************/ +/* NAME: mem_test_address() - test address lines */ +/* */ +/* DESCRIPTION: */ +/* This function performs a test to verify that each word im */ +/* memory is uniquly addressable. The test sequence is as follows: */ +/* */ +/* 1) write the address of each word to each word. */ +/* 2) verify that each location equals its address */ +/* */ +/* OUTPUTS: */ +/* Displays failing test pattern and address */ +/* */ +/* RETURNS: */ +/* 0 - Passed test */ +/* 1 - Failed test */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* */ +/* */ +/*********************************************************************/ +int mem_test_address (void) +{ + volatile unsigned int *pmem = + (volatile unsigned int *) CFG_MEMTEST_START; + const unsigned int size = (CFG_MEMTEST_END - CFG_MEMTEST_START) / 4; + unsigned int i; + + /* write address to each location */ + for (i = 0; i < size; i++) { + pmem[i] = i; + } + + /* verify each loaction */ + for (i = 0; i < size; i++) { + if (pmem[i] != i) { + printf ("\n Address Test Failed at 0x%x", i); + return 1; + } + } + return 0; +} +#endif /* CFG_DRAM_TEST_ADDRESS */ + +#if defined (CFG_DRAM_TEST_WALK) +/*********************************************************************/ +/* NAME: mem_march() - memory march */ +/* */ +/* DESCRIPTION: */ +/* Marches up through memory. At each location verifies rmask if */ +/* read = 1. At each location write wmask if write = 1. Displays */ +/* failing address and pattern. */ +/* */ +/* INPUTS: */ +/* volatile unsigned long long * base - start address of test */ +/* unsigned int size - number of dwords(64-bit) to test */ +/* unsigned long long rmask - read verify mask */ +/* unsigned long long wmask - wrtie verify mask */ +/* short read - verifies rmask if read = 1 */ +/* short write - writes wmask if write = 1 */ +/* */ +/* OUTPUTS: */ +/* Displays failing test pattern and address */ +/* */ +/* RETURNS: */ +/* 0 - Passed test */ +/* 1 - Failed test */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* */ +/* */ +/*********************************************************************/ +int mem_march (volatile unsigned long long *base, + unsigned int size, + unsigned long long rmask, + unsigned long long wmask, short read, short write) +{ + unsigned int i; + unsigned long long temp; + unsigned int hitemp, lotemp, himask, lomask; + + for (i = 0; i < size; i++) { + if (read != 0) { + /* temp = base[i]; */ + move64 ((unsigned long long *) &(base[i]), &temp); + if (rmask != temp) { + hitemp = (temp >> 32) & 0xffffffff; + lotemp = temp & 0xffffffff; + himask = (rmask >> 32) & 0xffffffff; + lomask = rmask & 0xffffffff; + + printf ("\n Walking one's test failed: address = 0x%08x," "\n\texpected 0x%08x%08x, found 0x%08x%08x", i << 3, himask, lomask, hitemp, lotemp); + return 1; + } + } + if (write != 0) { + /* base[i] = wmask; */ + move64 (&wmask, (unsigned long long *) &(base[i])); + } + } + return 0; +} +#endif /* CFG_DRAM_TEST_WALK */ + +/*********************************************************************/ +/* NAME: mem_test_walk() - a simple walking ones test */ +/* */ +/* DESCRIPTION: */ +/* Performs a walking ones through entire physical memory. The */ +/* test uses as series of memory marches, mem_march(), to verify */ +/* and write the test patterns to memory. The test sequence is as */ +/* follows: */ +/* 1) march writing 0000...0001 */ +/* 2) march verifying 0000...0001 , writing 0000...0010 */ +/* 3) repeat step 2 shifting masks left 1 bit each time unitl */ +/* the write mask equals 1000...0000 */ +/* 4) march verifying 1000...0000 */ +/* The test fails if any of the memory marches return a failure. */ +/* */ +/* OUTPUTS: */ +/* Displays which pass on the memory test is executing */ +/* */ +/* RETURNS: */ +/* 0 - Passed test */ +/* 1 - Failed test */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* */ +/* */ +/*********************************************************************/ +int mem_test_walk (void) +{ + unsigned long long mask; + volatile unsigned long long *pmem = + (volatile unsigned long long *) CFG_MEMTEST_START; + const unsigned long size = (CFG_MEMTEST_END - CFG_MEMTEST_START) / 8; + + unsigned int i; + + mask = 0x01; + + printf ("Initial Pass"); + mem_march (pmem, size, 0x0, 0x1, 0, 1); + + printf ("\b\b\b\b\b\b\b\b\b\b\b\b"); + printf (" "); + printf (" "); + printf ("\b\b\b\b\b\b\b\b\b\b\b\b"); + + for (i = 0; i < 63; i++) { + printf ("Pass %2d", i + 2); + if (mem_march (pmem, size, mask, mask << 1, 1, 1) != 0) { + /*printf("mask: 0x%x, pass: %d, ", mask, i); */ + return 1; + } + mask = mask << 1; + printf ("\b\b\b\b\b\b\b"); + } + + printf ("Last Pass"); + if (mem_march (pmem, size, 0, mask, 0, 1) != 0) { + /* printf("mask: 0x%x", mask); */ + return 1; + } + printf ("\b\b\b\b\b\b\b\b\b"); + printf (" "); + printf ("\b\b\b\b\b\b\b\b\b"); + + return 0; +} + +/*********************************************************************/ +/* NAME: testdram() - calls any enabled memory tests */ +/* */ +/* DESCRIPTION: */ +/* Runs memory tests if the environment test variables are set to */ +/* 'y'. */ +/* */ +/* INPUTS: */ +/* testdramdata - If set to 'y', data test is run. */ +/* testdramaddress - If set to 'y', address test is run. */ +/* testdramwalk - If set to 'y', walking ones test is run */ +/* */ +/* OUTPUTS: */ +/* None */ +/* */ +/* RETURNS: */ +/* 0 - Passed test */ +/* 1 - Failed test */ +/* */ +/* RESTRICTIONS/LIMITATIONS: */ +/* */ +/* */ +/*********************************************************************/ +int testdram (void) +{ + char *s; + int rundata = 0; + int runaddress = 0; + int runwalk = 0; + +#ifdef CFG_DRAM_TEST_DATA + s = getenv ("testdramdata"); + rundata = (s && (*s == 'y')) ? 1 : 0; +#endif +#ifdef CFG_DRAM_TEST_ADDRESS + s = getenv ("testdramaddress"); + runaddress = (s && (*s == 'y')) ? 1 : 0; +#endif +#ifdef CFG_DRAM_TEST_WALK + s = getenv ("testdramwalk"); + runwalk = (s && (*s == 'y')) ? 1 : 0; +#endif + + if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) { + printf ("Testing RAM from 0x%08x to 0x%08x ... (don't panic... that will take a moment !!!!)\n", CFG_MEMTEST_START, CFG_MEMTEST_END); + } +#ifdef CFG_DRAM_TEST_DATA + if (rundata == 1) { + printf ("Test DATA ... "); + if (mem_test_data () == 1) { + printf ("failed \n"); + return 1; + } else + printf ("ok \n"); + } +#endif +#ifdef CFG_DRAM_TEST_ADDRESS + if (runaddress == 1) { + printf ("Test ADDRESS ... "); + if (mem_test_address () == 1) { + printf ("failed \n"); + return 1; + } else + printf ("ok \n"); + } +#endif +#ifdef CFG_DRAM_TEST_WALK + if (runwalk == 1) { + printf ("Test WALKING ONEs ... "); + if (mem_test_walk () == 1) { + printf ("failed \n"); + return 1; + } else + printf ("ok \n"); + } +#endif + if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) { + printf ("passed\n"); + } + return 0; + +} +#endif /* CFG_DRAM_TEST */ + +/* ronen - the below functions are used by the bootm function */ +/* - we map the base register to fbe00000 (same mapping as in the LSP) */ +/* - we turn off the RX gig dmas - to prevent the dma from overunning */ +/* the kernel data areas. */ +/* - we diable and invalidate the icache and dcache. */ +void my_remap_gt_regs_bootm (u32 cur_loc, u32 new_loc) +{ + u32 temp; + + temp = in_le32 ((u32 *) (new_loc + INTERNAL_SPACE_DECODE)); + if ((temp & 0xffff) == new_loc >> 16) + return; + + temp = (in_le32 ((u32 *) (cur_loc + INTERNAL_SPACE_DECODE)) & + 0xffff0000) | (new_loc >> 16); + + out_le32 ((u32 *) (cur_loc + INTERNAL_SPACE_DECODE), temp); + + while ((WORD_SWAP (*((volatile unsigned int *) (NONE_CACHEABLE | + new_loc | + (INTERNAL_SPACE_DECODE))))) + != temp); + +} + +void board_prebootm_init () +{ + +/* change window size of PCI1 IO in order tp prevent overlaping with REG BASE. */ + GT_REG_WRITE (PCI_1_IO_SIZE, (_64K - 1) >> 16); + +/* Stop GigE Rx DMA engines */ + GT_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (0), 0x0000ff00); +/* GT_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (1), 0x0000ff00); */ +/* GV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (2), 0x0000ff00); */ + +/* Relocate MV64360 internal regs */ + my_remap_gt_regs_bootm (CFG_GT_REGS, CFG_DFL_GT_REGS); + + icache_disable (); + invalidate_l1_instruction_cache (); + flush_data_cache (); + dcache_disable (); +} diff --git a/board/esd/cpci750/eth.h b/board/esd/cpci750/eth.h new file mode 100644 index 0000000000..aab32d2a5a --- /dev/null +++ b/board/esd/cpci750/eth.h @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * 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 + */ + +/* + * eth.h - header file for the polled mode GT ethernet driver + */ + +#ifndef __EVB64360_ETH_H__ +#define __EVB64360_ETH_H__ + +#include +#include +#include +#include + + +int db64360_eth0_poll(void); +int db64360_eth0_transmit(unsigned int s, volatile char *p); +void db64360_eth0_disable(void); +bool network_start(bd_t *bis); + + +#endif /* __EVB64360_ETH_H__ */ diff --git a/board/esd/cpci750/i2c.c b/board/esd/cpci750/i2c.c new file mode 100644 index 0000000000..fcec78eac6 --- /dev/null +++ b/board/esd/cpci750/i2c.c @@ -0,0 +1,487 @@ +/* + * (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 + * + * Hacked for the DB64360 board by Ingo.Assmus@keymile.com + * extra improvments by Brain Waite + * for cpci750 by reinhard.arlt@esd-electronics.com + */ +#include +#include +#include +#include "../../Marvell/include/mv_gen_reg.h" +#include "../../Marvell/include/core.h" + +#define I2C_DELAY 100 +#undef DEBUG_I2C + +#ifdef DEBUG_I2C +#define DP(x) x +#else +#define DP(x) +#endif + +/* Assuming that there is only one master on the bus (us) */ + +static void i2c_init (int speed, int slaveaddr) +{ + unsigned int n, m, freq, margin, power; + unsigned int actualN = 0, actualM = 0; + unsigned int minMargin = 0xffffffff; + unsigned int tclk = CFG_TCLK; + unsigned int i2cFreq = speed; /* 100000 max. Fast mode not supported */ + + DP (puts ("i2c_init\n")); +/* gtI2cMasterInit */ + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + power = 2 << n; /* power = 2^(n+1) */ + freq = tclk / (10 * (m + 1) * power); + if (i2cFreq > freq) + margin = i2cFreq - freq; + else + margin = freq - i2cFreq; + if (margin < minMargin) { + minMargin = margin; + actualN = n; + actualM = m; + } + } + } + + DP (puts ("setup i2c bus\n")); + + /* Setup bus */ + /* gtI2cReset */ + GT_REG_WRITE (I2C_SOFT_RESET, 0); + asm(" sync"); + GT_REG_WRITE (I2C_CONTROL, 0); + asm(" sync"); + + DP (puts ("set baudrate\n")); + + GT_REG_WRITE (I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); + asm(" sync"); + + DP (puts ("udelay...\n")); + + udelay (I2C_DELAY); + + GT_REG_WRITE (I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); + asm(" sync"); +} + + +static uchar i2c_select_device (uchar dev_addr, uchar read, int ten_bit) +{ + unsigned int status, data, bits = 7; + unsigned int control; + int count = 0; + + DP (puts ("i2c_select_device\n")); + + /* Output slave address */ + + if (ten_bit) { + bits = 10; + } + + GT_REG_READ (I2C_CONTROL, &control); + control |= (0x1 << 2); + GT_REG_WRITE (I2C_CONTROL, control); + asm(" sync"); + + GT_REG_READ (I2C_CONTROL, &control); + control |= (0x1 << 5); /* generate the I2C_START_BIT */ + GT_REG_WRITE (I2C_CONTROL, control); + asm(" sync"); + RESET_REG_BITS (I2C_CONTROL, (0x01 << 3)); + asm(" sync"); + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + + count = 0; + + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + while (((status & 0xff) != 0x08) && ((status & 0xff) != 0x10)){ + if (count > 200) { +#ifdef DEBUG_I2C + printf ("Failed to set startbit: 0x%02x\n", status); +#endif + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + asm(" sync"); + return (status); + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + } + + DP (puts ("i2c_select_device:write addr byte\n")); + + /* assert the address */ + + data = (dev_addr << 1); + /* set the read bit */ + data |= read; + GT_REG_WRITE (I2C_DATA, data); + asm(" sync"); + RESET_REG_BITS (I2C_CONTROL, BIT3); + asm(" sync"); + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count = 0; + while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { + if (count > 200) { +#ifdef DEBUG_I2C + printf ("Failed to write address: 0x%02x\n", status); +#endif + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + return (status); + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + asm(" sync"); + count++; + } + + if (bits == 10) { + printf ("10 bit I2C addressing not yet implemented\n"); + return (0xff); + } + + return (0); +} + +static uchar i2c_get_data (uchar * return_data, int len) +{ + + unsigned int data, status; + int count = 0; + + DP (puts ("i2c_get_data\n")); + + while (len) { + + RESET_REG_BITS (I2C_CONTROL, BIT3); + asm(" sync"); + + /* Get and return the data */ + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x50) { + if (count > 20) { +#ifdef DEBUG_I2C + printf ("Failed to get data len status: 0x%02x\n", status); +#endif + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + asm(" sync"); + return 0; + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_READ (I2C_DATA, &data); + len--; + *return_data = (uchar) data; + return_data++; + + } + RESET_REG_BITS (I2C_CONTROL, BIT2 | BIT3); + asm(" sync"); + count = 0; + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + while ((status & 0xff) != 0x58) { + if (count > 2000) { + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + return (status); + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /* stop */ + asm(" sync"); + RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); + asm(" sync"); + + return (0); +} + + +static uchar i2c_write_data (unsigned int *data, int len) +{ + unsigned int status; + int count; + unsigned int temp; + unsigned int *temp_ptr = data; + + DP (puts ("i2c_write_data\n")); + + while (len) { + count = 0; + temp = (unsigned int) (*temp_ptr); + GT_REG_WRITE (I2C_DATA, temp); + asm(" sync"); + RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); + asm(" sync"); + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x28) { + if (count > 200) { + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + asm(" sync"); + return (status); + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + } + len--; + temp_ptr++; + } + return (0); +} + + +static uchar i2c_write_byte (unsigned char *data, int len) +{ + unsigned int status; + int count; + unsigned int temp; + unsigned char *temp_ptr = data; + + DP (puts ("i2c_write_byte\n")); + + while (len) { + count = 0; + /* Set and assert the data */ + temp = *temp_ptr; + GT_REG_WRITE (I2C_DATA, temp); + asm(" sync"); + RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); + asm(" sync"); + + + GT_REG_READ (I2C_CONTROL, &status); + while ((status & 0x08) != 0x08) { + GT_REG_READ (I2C_CONTROL, &status); + } + + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x28) { + if (count > 200) { + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ + asm(" sync"); + return (status); + } + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); + count++; + } + len--; + temp_ptr++; + } + return (0); +} + +static uchar +i2c_set_dev_offset (uchar dev_addr, unsigned int offset, int ten_bit, + int alen) +{ + uchar status; + unsigned int table[2]; + + table[1] = (offset ) & 0x0ff; /* low byte */ + table[0] = (offset >> 8) & 0x0ff; /* high byte */ + + DP (puts ("i2c_set_dev_offset\n")); + + status = i2c_select_device (dev_addr, 0, ten_bit); + if (status) { +#ifdef DEBUG_I2C +22 printf ("Failed to select device setting offset: 0x%02x\n", + status); +#endif + return status; + } +/* check the address offset length */ + if (alen == 0) + /* no address offset */ + return (0); + else if (alen == 1) { + /* 1 byte address offset */ + status = i2c_write_data (&offset, 1); + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to write data: 0x%02x\n", status); +#endif + return status; + } + } else if (alen == 2) { + /* 2 bytes address offset */ + status = i2c_write_data (table, 2); + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to write data: 0x%02x\n", status); +#endif + return status; + } + } else { + /* address offset unknown or not supported */ + printf ("Address length offset %d is not supported\n", alen); + return 1; + } + return 0; /* sucessful completion */ +} + +uchar +i2c_read (uchar dev_addr, unsigned int offset, int alen, uchar * data, + int len) +{ + uchar status = 0; + unsigned int i2cFreq = CFG_I2C_SPEED; + + DP (puts ("i2c_read\n")); + + i2c_init (i2cFreq, 0); /* set the i2c frequency */ + + status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to set slave address & offset: 0x%02x\n", + status); +#endif + return status; + } + + status = i2c_select_device (dev_addr, 1, 0); + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to select device for data read: 0x%02x\n", + status); +#endif + return status; + } + + status = i2c_get_data (data, len); + if (status) { +#ifdef DEBUG_I2C + printf ("Data not read: 0x%02x\n", status); +#endif + return status; + } + + return 0; +} + + +void i2c_stop (void) +{ + GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); + asm(" sync"); +} + + +uchar +i2c_write (uchar dev_addr, unsigned int offset, int alen, uchar * data, + int len) +{ + uchar status = 0; + unsigned int i2cFreq = CFG_I2C_SPEED; + + DP (puts ("i2c_write\n")); + + i2c_init (i2cFreq, 0); /* set the i2c frequency */ + + status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to set slave address & offset: 0x%02x\n", + status); +#endif + return status; + } + + + status = i2c_write_byte (data, len); /* write the data */ + if (status) { +#ifdef DEBUG_I2C + printf ("Data not written: 0x%02x\n", status); +#endif + return status; + } + /* issue a stop bit */ + i2c_stop (); + return 0; +} + + +int i2c_probe (uchar chip) +{ + +#ifdef DEBUG_I2C + unsigned int i2c_status; +#endif + uchar status = 0; + unsigned int i2cFreq = CFG_I2C_SPEED; + + DP (puts ("i2c_probe\n")); + + i2c_init (i2cFreq, 0); /* set the i2c frequency */ + + status = i2c_set_dev_offset (chip, 0, 0, 0); /* send the slave address + no offset */ + if (status) { +#ifdef DEBUG_I2C + printf ("Failed to set slave address: 0x%02x\n", status); +#endif + return (int) status; + } +#ifdef DEBUG_I2C + GT_REG_READ (I2C_STATUS_BAUDE_RATE, &i2c_status); + printf ("address %#x returned %#x\n", chip, i2c_status); +#endif + /* issue a stop bit */ + i2c_stop (); + return 0; /* successful completion */ +} diff --git a/board/esd/cpci750/i2c.h b/board/esd/cpci750/i2c.h new file mode 100644 index 0000000000..b669ff0031 --- /dev/null +++ b/board/esd/cpci750/i2c.h @@ -0,0 +1,32 @@ +/* + * (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 + * + * Hacked for the DB64360 board by Ingo.Assmus@keymile.com + */ + +#ifndef __I2C_H__ +#define __I2C_H__ + +/* function declarations */ +uchar i2c_read(uchar, unsigned int, int, uchar*, int); + +#endif diff --git a/board/esd/cpci750/ide.c b/board/esd/cpci750/ide.c new file mode 100644 index 0000000000..7400e8dc52 --- /dev/null +++ b/board/esd/cpci750/ide.c @@ -0,0 +1,72 @@ +/* + * (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 + * + */ +/* ide.c - ide support functions */ + + +#include +#ifdef CFG_CMD_IDE +#include +#include +#include + +extern ulong ide_bus_offset[CFG_IDE_MAXBUS]; + +int ide_preinit + ( + void + ) + { + int status; + pci_dev_t devbusfn; + int l; + + status = 1; + for(l=0;l + * + * 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/local.h - local configuration options, board specific + */ + +#ifndef __LOCAL_H +#define __LOCAL_H + +/* + * High Level Configuration Options + * (easy to change) + */ + +/* This tells PPCBoot that the config options are compiled in */ +/* #undef ENV_IS_EMBEDDED */ +/* Don't touch this! PPCBOOT figures this out based on other + * magic. */ + +/* Uncomment and define any of the below options */ + +/* #define CONFIG_750CX */ /* The 750CX doesn't support as many things in L2CR */ +#define CONFIG_750FX /* The 750FX doesn't support as many things in L2CR like 750CX*/ + +/* These want string arguments */ +/* #define CONFIG_BOOTARGS */ +/* #define CONFIG_BOOTCOMMAND */ +/* #define CONFIG_RAMBOOTCOMMAND */ +/* #define CONFIG_NFSBOOTCOMMAND */ +/* #define CFG_AUTOLOAD */ +/* #define CONFIG_PREBOOT */ + +/* These don't */ + +/* #define CONFIG_BOOTDELAY */ +/* #define CONFIG_BAUDRATE */ +/* #define CONFIG_LOADS_ECHO */ +/* #define CONFIG_ETHADDR */ +/* #define CONFIG_ETH2ADDR */ +/* #define CONFIG_ETH3ADDR */ +/* #define CONFIG_IPADDR */ +/* #define CONFIG_SERVERIP */ +/* #define CONFIG_ROOTPATH */ +/* #define CONFIG_GATEWAYIP */ +/* #define CONFIG_NETMASK */ +/* #define CONFIG_HOSTNAME */ +/* #define CONFIG_BOOTFILE */ +/* #define CONFIG_LOADADDR */ + +/* these hardware addresses are pretty bogus, please change them to + suit your needs */ + +/* first ethernet */ +/* #define CONFIG_ETHADDR 86:06:2d:7e:c6:53 */ +#define CONFIG_ETHADDR 64:36:00:00:00:01 + +/* next two ethernet hwaddrs */ +#define CONFIG_ETH1ADDR 86:06:2d:7e:c6:54 +#define CONFIG_ETH2ADDR 86:06:2d:7e:c6:55 + +#define CONFIG_ENV_OVERWRITE +#endif /* __CONFIG_H */ diff --git a/board/esd/cpci750/misc.S b/board/esd/cpci750/misc.S new file mode 100644 index 0000000000..ec5d9ecc48 --- /dev/null +++ b/board/esd/cpci750/misc.S @@ -0,0 +1,245 @@ +#include +#include <74xx_7xx.h> +#include "version.h" + +#include +#include + +#include +#include + +#include "../../Marvell/include/mv_gen_reg.h" + +#ifdef CONFIG_ECC + /* Galileo specific asm code for initializing ECC */ + .globl board_relocate_rom +board_relocate_rom: + mflr r7 + /* update the location of the GT registers */ + lis r11, CFG_GT_REGS@h + /* if we're using ECC, we must use the DMA engine to copy ourselves */ + bl start_idma_transfer_0 + bl wait_for_idma_0 + bl stop_idma_engine_0 + + mtlr r7 + blr + + .globl board_init_ecc +board_init_ecc: + mflr r7 + /* NOTE: r10 still contains the location we've been relocated to + * which happens to be TOP_OF_RAM - CFG_MONITOR_LEN */ + + /* now that we're running from ram, init the rest of main memory + * for ECC use */ + lis r8, CFG_MONITOR_LEN@h + ori r8, r8, CFG_MONITOR_LEN@l + + divw r3, r10, r8 + + /* set up the counter, and init the starting address */ + mtctr r3 + li r12, 0 + + /* bytes per transfer */ + mr r5, r8 +about_to_init_ecc: +1: mr r3, r12 + mr r4, r12 + bl start_idma_transfer_0 + bl wait_for_idma_0 + bl stop_idma_engine_0 + add r12, r12, r8 + bdnz 1b + + mtlr r7 + blr + + /* r3: dest addr + * r4: source addr + * r5: byte count + * r11: gt regbase + * trashes: r6, r5 + */ +start_idma_transfer_0: + /* set the byte count, including the OWN bit */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_BYTE_COUNT + stwbrx r5, 0, (r6) + + /* set the source address */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_SOURCE_ADDRESS + stwbrx r4, 0, (r6) + + /* set the dest address */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_DESTINATION_ADDRESS + stwbrx r3, 0, (r6) + + /* set the next record pointer */ + li r5, 0 + mr r6, r11 + ori r6, r6, CHANNEL0NEXT_RECORD_POINTER + stwbrx r5, 0, (r6) + + /* set the low control register */ + /* bit 9 is NON chained mode, bit 31 is new style descriptors. + bit 12 is channel enable */ + ori r5, r5, (1 << 12) | (1 << 12) | (1 << 11) + /* 15 shifted by 16 (oris) == bit 31 */ + oris r5, r5, (1 << 15) + mr r6, r11 + ori r6, r6, CHANNEL0CONTROL + stwbrx r5, 0, (r6) + + blr + + /* this waits for the bytecount to return to zero, indicating + * that the trasfer is complete */ +wait_for_idma_0: + mr r5, r11 + lis r6, 0xff + ori r6, r6, 0xffff + ori r5, r5, CHANNEL0_DMA_BYTE_COUNT +1: lwbrx r4, 0, (r5) + and. r4, r4, r6 + bne 1b + + blr + + /* this turns off channel 0 of the idma engine */ +stop_idma_engine_0: + /* shut off the DMA engine */ + li r5, 0 + mr r6, r11 + ori r6, r6, CHANNEL0CONTROL + stwbrx r5, 0, (r6) + + blr +#endif + +#ifdef CFG_BOARD_ASM_INIT + /* NOTE: trashes r3-r7 */ + .globl board_asm_init +board_asm_init: + /* just move the GT registers to where they belong */ + lis r3, CFG_DFL_GT_REGS@h + ori r3, r3, CFG_DFL_GT_REGS@l + lis r4, CFG_GT_REGS@h + ori r4, r4, CFG_GT_REGS@l + li r5, INTERNAL_SPACE_DECODE + + /* test to see if we've already moved */ + lwbrx r6, r5, r4 + andi. r6, r6, 0xffff + /* check loading of R7 is: 0x0F80 should: 0xf800: DONE */ +/* rlwinm r7, r4, 8, 16, 31 + rlwinm r7, r4, 12, 16, 31 */ /* original */ + rlwinm r7, r4, 16, 16, 31 + /* -----------------------------------------------------*/ + cmp cr0, r7, r6 + beqlr + + /* nope, have to move the registers */ + lwbrx r6, r5, r3 + andis. r6, r6, 0xffff + or r6, r6, r7 + stwbrx r6, r5, r3 + + /* now, poll for the change */ +1: lwbrx r7, r5, r4 + cmp cr0, r7, r6 + bne 1b + + lis r3, CFG_INT_SRAM_BASE@h + ori r3, r3, CFG_INT_SRAM_BASE@l + rlwinm r3, r3, 16, 16, 31 + lis r4, CFG_GT_REGS@h + ori r4, r4, CFG_GT_REGS@l + li r5, INTEGRATED_SRAM_BASE_ADDR + stwbrx r3, r5, r4 + +2: lwbrx r6, r5, r4 + cmp cr0, r3, r6 + bne 2b + + /* done! */ + blr +#endif + +/* For use of the debug LEDs */ + .global led_on0_relocated +led_on0_relocated: + xor r21, r21, r21 + xor r18, r18, r18 + lis r18, 0xFC80 + ori r18, r18, 0x8000 +/* stw r21, 0x0(r18) */ + sync + blr + + .global led_off0_relocated +led_off0_relocated: + xor r21, r21, r21 + xor r18, r18, r18 + lis r18, 0xFC81 + ori r18, r18, 0x4000 +/* stw r21, 0x0(r18) */ + sync + blr + + .global led_on0 +led_on0: + xor r18, r18, r18 + lis r18, 0x1c80 + ori r18, r18, 0x8000 +/* stw r18, 0x0(r18) */ + sync + blr + + .global led_off0 +led_off0: + xor r18, r18, r18 + lis r18, 0x1c81 + ori r18, r18, 0x4000 +/* stw r18, 0x0(r18) */ + sync + blr + + .global led_on1 +led_on1: + xor r18, r18, r18 + lis r18, 0x1c80 + ori r18, r18, 0xc000 +/* stw r18, 0x0(r18) */ + sync + blr + + .global led_off1 +led_off1: + xor r18, r18, r18 + lis r18, 0x1c81 + ori r18, r18, 0x8000 +/* stw r18, 0x0(r18) */ + sync + blr + + .global led_on2 +led_on2: + xor r18, r18, r18 + lis r18, 0x1c81 + ori r18, r18, 0x0000 +/* stw r18, 0x0(r18) */ + sync + blr + + .global led_off2 +led_off2: + xor r18, r18, r18 + lis r18, 0x1c81 + ori r18, r18, 0xc000 +/* stw r18, 0x0(r18) */ + sync + blr diff --git a/board/esd/cpci750/mpsc.c b/board/esd/cpci750/mpsc.c new file mode 100644 index 0000000000..52398b24ea --- /dev/null +++ b/board/esd/cpci750/mpsc.c @@ -0,0 +1,1018 @@ +/* + * (C) Copyright 2001 + * John Clemens , Mission Critical Linux, Inc. + * + * 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 + */ + +/************************************************************************* + * changes for Marvell DB64360 eval board 2003 by Ingo Assmus + * + ************************************************************************/ + +/* + * mpsc.c - driver for console over the MPSC. + */ + + +#include +#include +#include + +#include +#include "mpsc.h" + +#include "mv_regs.h" + +#include "../../Marvell/include/memory.h" + +/* Define this if you wish to use the MPSC as a register based UART. + * This will force the serial port to not use the SDMA engine at all. + */ + +#undef CONFIG_MPSC_DEBUG_PORT + + +int (*mpsc_putchar) (char ch) = mpsc_putchar_early; +char (*mpsc_getchar) (void) = mpsc_getchar_debug; +int (*mpsc_test_char) (void) = mpsc_test_char_debug; + + +static volatile unsigned int *rx_desc_base = NULL; +static unsigned int rx_desc_index = 0; +static volatile unsigned int *tx_desc_base = NULL; +static unsigned int tx_desc_index = 0; + +/* local function declarations */ +static int galmpsc_connect (int channel, int connect); +static int galmpsc_route_rx_clock (int channel, int brg); +static int galmpsc_route_tx_clock (int channel, int brg); +static int galmpsc_write_config_regs (int mpsc, int mode); +static int galmpsc_config_channel_regs (int mpsc); +static int galmpsc_set_char_length (int mpsc, int value); +static int galmpsc_set_stop_bit_length (int mpsc, int value); +static int galmpsc_set_parity (int mpsc, int value); +static int galmpsc_enter_hunt (int mpsc); +static int galmpsc_set_brkcnt (int mpsc, int value); +static int galmpsc_set_tcschar (int mpsc, int value); +static int galmpsc_set_snoop (int mpsc, int value); +static int galmpsc_shutdown (int mpsc); + +static int galsdma_set_RFT (int channel); +static int galsdma_set_SFM (int channel); +static int galsdma_set_rxle (int channel); +static int galsdma_set_txle (int channel); +static int galsdma_set_burstsize (int channel, unsigned int value); +static int galsdma_set_RC (int channel, unsigned int value); + +static int galbrg_set_CDV (int channel, int value); +static int galbrg_enable (int channel); +static int galbrg_disable (int channel); +static int galbrg_set_clksrc (int channel, int value); +static int galbrg_set_CUV (int channel, int value); + +static void galsdma_enable_rx (void); +static int galsdma_set_mem_space (unsigned int memSpace, + unsigned int memSpaceTarget, + unsigned int memSpaceAttr, + unsigned int baseAddress, + unsigned int size); + + +#define SOFTWARE_CACHE_MANAGEMENT + +#ifdef SOFTWARE_CACHE_MANAGEMENT +#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));} +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) if(dcache_status()){flush_dcache_range((u32)(a),(u32)(b));} +#define INVALIDATE_DCACHE(a,b) if(dcache_status()){invalidate_dcache_range((u32)(a),(u32)(b));} +#else +#define FLUSH_DCACHE(a,b) +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) +#define INVALIDATE_DCACHE(a,b) +#endif + +#ifdef CONFIG_MPSC_DEBUG_PORT +static void mpsc_debug_init (void) +{ + + volatile unsigned int temp; + + /* Clear the CFR (CHR4) */ + /* Write random 'Z' bit (bit 29) of CHR4 to enable debug uart *UNDOCUMENTED FEATURE* */ + temp = GTREGREAD (GALMPSC_CHANNELREG_4 + (CHANNEL * GALMPSC_REG_GAP)); + temp &= 0xffffff00; + temp |= BIT29; + GT_REG_WRITE (GALMPSC_CHANNELREG_4 + (CHANNEL * GALMPSC_REG_GAP), + temp); + + /* Set the Valid bit 'V' (bit 12) and int generation bit 'INT' (bit 15) */ + temp = GTREGREAD (GALMPSC_CHANNELREG_5 + (CHANNEL * GALMPSC_REG_GAP)); + temp |= (BIT12 | BIT15); + GT_REG_WRITE (GALMPSC_CHANNELREG_5 + (CHANNEL * GALMPSC_REG_GAP), + temp); + + /* Set int mask */ + temp = GTREGREAD (GALMPSC_0_INT_MASK); + temp |= BIT6; + GT_REG_WRITE (GALMPSC_0_INT_MASK, temp); +} +#endif + +char mpsc_getchar_debug (void) +{ + volatile int temp; + volatile unsigned int cause; + + cause = GTREGREAD (GALMPSC_0_INT_CAUSE); + while ((cause & BIT6) == 0) { + cause = GTREGREAD (GALMPSC_0_INT_CAUSE); + } + + temp = GTREGREAD (GALMPSC_CHANNELREG_10 + + (CHANNEL * GALMPSC_REG_GAP)); + /* By writing 1's to the set bits, the register is cleared */ + GT_REG_WRITE (GALMPSC_CHANNELREG_10 + (CHANNEL * GALMPSC_REG_GAP), + temp); + GT_REG_WRITE (GALMPSC_0_INT_CAUSE, cause & ~BIT6); + return (temp >> 16) & 0xff; +} + +/* special function for running out of flash. doesn't modify any + * global variables [josh] */ +int mpsc_putchar_early (char ch) +{ + DECLARE_GLOBAL_DATA_PTR; + int mpsc = CHANNEL; + int temp = + GTREGREAD (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP)); + galmpsc_set_tcschar (mpsc, ch); + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP), + temp | 0x200); + +#define MAGIC_FACTOR (10*1000000) + + udelay (MAGIC_FACTOR / gd->baudrate); + return 0; +} + +/* This is used after relocation, see serial.c and mpsc_init2 */ +static int mpsc_putchar_sdma (char ch) +{ + volatile unsigned int *p; + unsigned int temp; + + + /* align the descriptor */ + p = tx_desc_base; + memset ((void *) p, 0, 8 * sizeof (unsigned int)); + + /* fill one 64 bit buffer */ + /* word swap, pad with 0 */ + p[4] = 0; /* x */ + p[5] = (unsigned int) ch; /* x */ + + /* CHANGED completely according to GT64260A dox - NTL */ + p[0] = 0x00010001; /* 0 */ + p[1] = DESC_OWNER_BIT | DESC_FIRST | DESC_LAST; /* 4 */ + p[2] = 0; /* 8 */ + p[3] = (unsigned int) &p[4]; /* c */ + +#if 0 + p[9] = DESC_FIRST | DESC_LAST; + p[10] = (unsigned int) &p[0]; + p[11] = (unsigned int) &p[12]; +#endif + + FLUSH_DCACHE (&p[0], &p[8]); + + GT_REG_WRITE (GALSDMA_0_CUR_TX_PTR + (CHANNEL * GALSDMA_REG_DIFF), + (unsigned int) &p[0]); + GT_REG_WRITE (GALSDMA_0_FIR_TX_PTR + (CHANNEL * GALSDMA_REG_DIFF), + (unsigned int) &p[0]); + + temp = GTREGREAD (GALSDMA_0_COM_REG + (CHANNEL * GALSDMA_REG_DIFF)); + temp |= (TX_DEMAND | TX_STOP); + GT_REG_WRITE (GALSDMA_0_COM_REG + (CHANNEL * GALSDMA_REG_DIFF), temp); + + INVALIDATE_DCACHE (&p[1], &p[2]); + + while (p[1] & DESC_OWNER_BIT) { + udelay (100); + INVALIDATE_DCACHE (&p[1], &p[2]); + } + return 0; +} + +char mpsc_getchar_sdma (void) +{ + static unsigned int done = 0; + volatile char ch; + unsigned int len = 0, idx = 0, temp; + + volatile unsigned int *p; + + + do { + p = &rx_desc_base[rx_desc_index * 8]; + + INVALIDATE_DCACHE (&p[0], &p[1]); + /* Wait for character */ + while (p[1] & DESC_OWNER_BIT) { + udelay (100); + INVALIDATE_DCACHE (&p[0], &p[1]); + } + + /* Handle error case */ + if (p[1] & (1 << 15)) { + printf ("oops, error: %08x\n", p[1]); + + temp = GTREGREAD (GALMPSC_CHANNELREG_2 + + (CHANNEL * GALMPSC_REG_GAP)); + temp |= (1 << 23); + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + + (CHANNEL * GALMPSC_REG_GAP), temp); + + /* Can't poll on abort bit, so we just wait. */ + udelay (100); + + galsdma_enable_rx (); + } + + /* Number of bytes left in this descriptor */ + len = p[0] & 0xffff; + + if (len) { + /* Where to look */ + idx = 5; + if (done > 3) + idx = 4; + if (done > 7) + idx = 7; + if (done > 11) + idx = 6; + + INVALIDATE_DCACHE (&p[idx], &p[idx + 1]); + ch = p[idx] & 0xff; + done++; + } + + if (done < len) { + /* this descriptor has more bytes still + * shift down the char we just read, and leave the + * buffer in place for the next time around + */ + p[idx] = p[idx] >> 8; + FLUSH_DCACHE (&p[idx], &p[idx + 1]); + } + + if (done == len) { + /* nothing left in this descriptor. + * go to next one + */ + p[1] = DESC_OWNER_BIT | DESC_FIRST | DESC_LAST; + p[0] = 0x00100000; + FLUSH_DCACHE (&p[0], &p[1]); + /* Next descriptor */ + rx_desc_index = (rx_desc_index + 1) % RX_DESC; + done = 0; + } + } while (len == 0); /* galileo bug.. len might be zero */ + + return ch; +} + + +int mpsc_test_char_debug (void) +{ + if ((GTREGREAD (GALMPSC_0_INT_CAUSE) & BIT6) == 0) + return 0; + else { + return 1; + } +} + + +int mpsc_test_char_sdma (void) +{ + volatile unsigned int *p = &rx_desc_base[rx_desc_index * 8]; + + INVALIDATE_DCACHE (&p[1], &p[2]); + + if (p[1] & DESC_OWNER_BIT) + return 0; + else + return 1; +} + +int mpsc_init (int baud) +{ + /* BRG CONFIG */ + galbrg_set_baudrate (CHANNEL, baud); + galbrg_set_clksrc (CHANNEL, 8); /* set source=Tclk */ + galbrg_set_CUV (CHANNEL, 0); /* set up CountUpValue */ + galbrg_enable (CHANNEL); /* Enable BRG */ + + /* Set up clock routing */ + galmpsc_connect (CHANNEL, GALMPSC_CONNECT); /* connect it */ + + galmpsc_route_rx_clock (CHANNEL, CHANNEL); /* chosse BRG0 for Rx */ + galmpsc_route_tx_clock (CHANNEL, CHANNEL); /* chose BRG0 for Tx */ + + /* reset MPSC state */ + galmpsc_shutdown (CHANNEL); + + /* SDMA CONFIG */ + galsdma_set_burstsize (CHANNEL, L1_CACHE_BYTES / 8); /* in 64 bit words (8 bytes) */ + galsdma_set_txle (CHANNEL); + galsdma_set_rxle (CHANNEL); + galsdma_set_RC (CHANNEL, 0xf); + galsdma_set_SFM (CHANNEL); + galsdma_set_RFT (CHANNEL); + + /* MPSC CONFIG */ + galmpsc_write_config_regs (CHANNEL, GALMPSC_UART); + galmpsc_config_channel_regs (CHANNEL); + galmpsc_set_char_length (CHANNEL, GALMPSC_CHAR_LENGTH_8); /* 8 */ + galmpsc_set_parity (CHANNEL, GALMPSC_PARITY_NONE); /* N */ + galmpsc_set_stop_bit_length (CHANNEL, GALMPSC_STOP_BITS_1); /* 1 */ + +#ifdef CONFIG_MPSC_DEBUG_PORT + mpsc_debug_init (); +#endif + + /* COMM_MPSC CONFIG */ +#ifdef SOFTWARE_CACHE_MANAGEMENT + galmpsc_set_snoop (CHANNEL, 0); /* disable snoop */ +#else + galmpsc_set_snoop (CHANNEL, 1); /* enable snoop */ +#endif + + return 0; +} + + +void mpsc_sdma_init (void) +{ +/* Setup SDMA channel0 SDMA_CONFIG_REG*/ + GT_REG_WRITE (SDMA_CONFIG_REG (0), 0x000020ff); + +/* Enable MPSC-Window0 for DRAM Bank0 */ + if (galsdma_set_mem_space (MV64360_CUNIT_BASE_ADDR_WIN_0_BIT, + MV64360_SDMA_DRAM_CS_0_TARGET, + 0, + memoryGetBankBaseAddress + (CS_0_LOW_DECODE_ADDRESS), + memoryGetBankSize (BANK0)) != true) + printf ("%s: SDMA_Window0 memory setup failed !!! \n", + __FUNCTION__); + + +/* Disable MPSC-Window1 */ + if (galsdma_set_mem_space (MV64360_CUNIT_BASE_ADDR_WIN_1_BIT, + MV64360_SDMA_DRAM_CS_0_TARGET, + 0, + memoryGetBankBaseAddress + (CS_1_LOW_DECODE_ADDRESS), + memoryGetBankSize (BANK3)) != true) + printf ("%s: SDMA_Window1 memory setup failed !!! \n", + __FUNCTION__); + + +/* Disable MPSC-Window2 */ + if (galsdma_set_mem_space (MV64360_CUNIT_BASE_ADDR_WIN_2_BIT, + MV64360_SDMA_DRAM_CS_0_TARGET, + 0, + memoryGetBankBaseAddress + (CS_2_LOW_DECODE_ADDRESS), + memoryGetBankSize (BANK3)) != true) + printf ("%s: SDMA_Window2 memory setup failed !!! \n", + __FUNCTION__); + + +/* Disable MPSC-Window3 */ + if (galsdma_set_mem_space (MV64360_CUNIT_BASE_ADDR_WIN_3_BIT, + MV64360_SDMA_DRAM_CS_0_TARGET, + 0, + memoryGetBankBaseAddress + (CS_3_LOW_DECODE_ADDRESS), + memoryGetBankSize (BANK3)) != true) + printf ("%s: SDMA_Window3 memory setup failed !!! \n", + __FUNCTION__); + +/* Setup MPSC0 access mode Window0 full access */ + GT_SET_REG_BITS (MPSC0_ACCESS_PROTECTION_REG, + (MV64360_SDMA_WIN_ACCESS_FULL << + (MV64360_CUNIT_BASE_ADDR_WIN_0_BIT * 2))); + +/* Setup MPSC1 access mode Window1 full access */ + GT_SET_REG_BITS (MPSC1_ACCESS_PROTECTION_REG, + (MV64360_SDMA_WIN_ACCESS_FULL << + (MV64360_CUNIT_BASE_ADDR_WIN_0_BIT * 2))); + +/* Setup MPSC internal address space base address */ + GT_REG_WRITE (CUNIT_INTERNAL_SPACE_BASE_ADDR_REG, CFG_GT_REGS); + +/* no high address remap*/ + GT_REG_WRITE (CUNIT_HIGH_ADDR_REMAP_REG0, 0x00); + GT_REG_WRITE (CUNIT_HIGH_ADDR_REMAP_REG1, 0x00); + +/* clear interrupt cause register for MPSC (fault register)*/ + GT_REG_WRITE (CUNIT_INTERRUPT_CAUSE_REG, 0x00); +} + + +void mpsc_init2 (void) +{ + int i; + +#ifndef CONFIG_MPSC_DEBUG_PORT + mpsc_putchar = mpsc_putchar_sdma; + mpsc_getchar = mpsc_getchar_sdma; + mpsc_test_char = mpsc_test_char_sdma; +#endif + /* RX descriptors */ + rx_desc_base = (unsigned int *) malloc (((RX_DESC + 1) * 8) * + sizeof (unsigned int)); + + /* align descriptors */ + rx_desc_base = (unsigned int *) + (((unsigned int) rx_desc_base + 32) & 0xFFFFFFF0); + + rx_desc_index = 0; + + memset ((void *) rx_desc_base, 0, + (RX_DESC * 8) * sizeof (unsigned int)); + + for (i = 0; i < RX_DESC; i++) { + rx_desc_base[i * 8 + 3] = (unsigned int) &rx_desc_base[i * 8 + 4]; /* Buffer */ + rx_desc_base[i * 8 + 2] = (unsigned int) &rx_desc_base[(i + 1) * 8]; /* Next descriptor */ + rx_desc_base[i * 8 + 1] = DESC_OWNER_BIT | DESC_FIRST | DESC_LAST; /* Command & control */ + rx_desc_base[i * 8] = 0x00100000; + } + rx_desc_base[(i - 1) * 8 + 2] = (unsigned int) &rx_desc_base[0]; + + FLUSH_DCACHE (&rx_desc_base[0], &rx_desc_base[RX_DESC * 8]); + GT_REG_WRITE (GALSDMA_0_CUR_RX_PTR + (CHANNEL * GALSDMA_REG_DIFF), + (unsigned int) &rx_desc_base[0]); + + /* TX descriptors */ + tx_desc_base = (unsigned int *) malloc (((TX_DESC + 1) * 8) * + sizeof (unsigned int)); + + /* align descriptors */ + tx_desc_base = (unsigned int *) + (((unsigned int) tx_desc_base + 32) & 0xFFFFFFF0); + + tx_desc_index = -1; + + memset ((void *) tx_desc_base, 0, + (TX_DESC * 8) * sizeof (unsigned int)); + + for (i = 0; i < TX_DESC; i++) { + tx_desc_base[i * 8 + 5] = (unsigned int) 0x23232323; + tx_desc_base[i * 8 + 4] = (unsigned int) 0x23232323; + tx_desc_base[i * 8 + 3] = + (unsigned int) &tx_desc_base[i * 8 + 4]; + tx_desc_base[i * 8 + 2] = + (unsigned int) &tx_desc_base[(i + 1) * 8]; + tx_desc_base[i * 8 + 1] = + DESC_OWNER_BIT | DESC_FIRST | DESC_LAST; + + /* set sbytecnt and shadow byte cnt to 1 */ + tx_desc_base[i * 8] = 0x00010001; + } + tx_desc_base[(i - 1) * 8 + 2] = (unsigned int) &tx_desc_base[0]; + + FLUSH_DCACHE (&tx_desc_base[0], &tx_desc_base[TX_DESC * 8]); + + udelay (100); + + galsdma_enable_rx (); + + return; +} + +int galbrg_set_baudrate (int channel, int rate) +{ + DECLARE_GLOBAL_DATA_PTR; + int clock; + + galbrg_disable (channel); /*ok */ + +#ifdef ZUMA_NTL + /* from tclk */ + clock = (CFG_TCLK / (16 * rate)) - 1; +#else + clock = (CFG_TCLK / (16 * rate)) - 1; +#endif + + galbrg_set_CDV (channel, clock); /* set timer Reg. for BRG */ + + galbrg_enable (channel); + + gd->baudrate = rate; + + return 0; +} + +/* ------------------------------------------------------------------ */ + +/* Below are all the private functions that no one else needs */ + +static int galbrg_set_CDV (int channel, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp &= 0xFFFF0000; + temp |= (value & 0x0000FFFF); + GT_REG_WRITE (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + + return 0; +} + +static int galbrg_enable (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp |= 0x00010000; + GT_REG_WRITE (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + + return 0; +} + +static int galbrg_disable (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp &= 0xFFFEFFFF; + GT_REG_WRITE (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + + return 0; +} + +static int galbrg_set_clksrc (int channel, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp &= 0xFFC3FFFF; /* Bit 18 - 21 (MV 64260 18-22) */ + temp |= (value << 18); + GT_REG_WRITE (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + return 0; +} + +static int galbrg_set_CUV (int channel, int value) +{ + /* set CountUpValue */ + GT_REG_WRITE (GALBRG_0_BTREG + (channel * GALBRG_REG_GAP), value); + + return 0; +} + +#if 0 +static int galbrg_reset (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp |= 0x20000; + GT_REG_WRITE (GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + + return 0; +} +#endif + +static int galsdma_set_RFT (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp |= 0x00000001; + GT_REG_WRITE (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF), + temp); + + return 0; +} + +static int galsdma_set_SFM (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp |= 0x00000002; + GT_REG_WRITE (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF), + temp); + + return 0; +} + +static int galsdma_set_rxle (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp |= 0x00000040; + GT_REG_WRITE (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF), + temp); + + return 0; +} + +static int galsdma_set_txle (int channel) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp |= 0x00000080; + GT_REG_WRITE (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF), + temp); + + return 0; +} + +static int galsdma_set_RC (int channel, unsigned int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp &= ~0x0000003c; + temp |= (value << 2); + GT_REG_WRITE (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF), + temp); + + return 0; +} + +static int galsdma_set_burstsize (int channel, unsigned int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALSDMA_0_CONF_REG + (channel * GALSDMA_REG_DIFF)); + temp &= 0xFFFFCFFF; + switch (value) { + case 8: + GT_REG_WRITE (GALSDMA_0_CONF_REG + + (channel * GALSDMA_REG_DIFF), + (temp | (0x3 << 12))); + break; + + case 4: + GT_REG_WRITE (GALSDMA_0_CONF_REG + + (channel * GALSDMA_REG_DIFF), + (temp | (0x2 << 12))); + break; + + case 2: + GT_REG_WRITE (GALSDMA_0_CONF_REG + + (channel * GALSDMA_REG_DIFF), + (temp | (0x1 << 12))); + break; + + case 1: + GT_REG_WRITE (GALSDMA_0_CONF_REG + + (channel * GALSDMA_REG_DIFF), + (temp | (0x0 << 12))); + break; + + default: + return -1; + break; + } + + return 0; +} + +static int galmpsc_connect (int channel, int connect) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_ROUTING_REGISTER); + + if ((channel == 0) && connect) + temp &= ~0x00000007; + else if ((channel == 1) && connect) + temp &= ~(0x00000007 << 6); + else if ((channel == 0) && !connect) + temp |= 0x00000007; + else + temp |= (0x00000007 << 6); + + /* Just in case... */ + temp &= 0x3fffffff; + + GT_REG_WRITE (GALMPSC_ROUTING_REGISTER, temp); + + return 0; +} + +static int galmpsc_route_rx_clock (int channel, int brg) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_RxC_ROUTE); + + if (channel == 0) { + temp &= ~0x0000000F; + temp |= brg; + } else { + temp &= ~0x00000F00; + temp |= (brg << 8); + } + + GT_REG_WRITE (GALMPSC_RxC_ROUTE, temp); + + return 0; +} + +static int galmpsc_route_tx_clock (int channel, int brg) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_TxC_ROUTE); + + if (channel == 0) { + temp &= ~0x0000000F; + temp |= brg; + } else { + temp &= ~0x00000F00; + temp |= (brg << 8); + } + + GT_REG_WRITE (GALMPSC_TxC_ROUTE, temp); + + return 0; +} + +static int galmpsc_write_config_regs (int mpsc, int mode) +{ + if (mode == GALMPSC_UART) { + /* Main config reg Low (Null modem, Enable Tx/Rx, UART mode) */ + GT_REG_WRITE (GALMPSC_MCONF_LOW + (mpsc * GALMPSC_REG_GAP), + 0x000004c4); + + /* Main config reg High (32x Rx/Tx clock mode, width=8bits */ + GT_REG_WRITE (GALMPSC_MCONF_HIGH + (mpsc * GALMPSC_REG_GAP), + 0x024003f8); + /* 22 2222 1111 */ + /* 54 3210 9876 */ + /* 0000 0010 0000 0000 */ + /* 1 */ + /* 098 7654 3210 */ + /* 0000 0011 1111 1000 */ + } else + return -1; + + return 0; +} + +static int galmpsc_config_channel_regs (int mpsc) +{ + GT_REG_WRITE (GALMPSC_CHANNELREG_1 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_3 + (mpsc * GALMPSC_REG_GAP), 1); + GT_REG_WRITE (GALMPSC_CHANNELREG_4 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_5 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_6 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_7 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_8 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_9 + (mpsc * GALMPSC_REG_GAP), 0); + GT_REG_WRITE (GALMPSC_CHANNELREG_10 + (mpsc * GALMPSC_REG_GAP), 0); + + galmpsc_set_brkcnt (mpsc, 0x3); + galmpsc_set_tcschar (mpsc, 0xab); + + return 0; +} + +static int galmpsc_set_brkcnt (int mpsc, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_CHANNELREG_1 + (mpsc * GALMPSC_REG_GAP)); + temp &= 0x0000FFFF; + temp |= (value << 16); + GT_REG_WRITE (GALMPSC_CHANNELREG_1 + (mpsc * GALMPSC_REG_GAP), temp); + + return 0; +} + +static int galmpsc_set_tcschar (int mpsc, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_CHANNELREG_1 + (mpsc * GALMPSC_REG_GAP)); + temp &= 0xFFFF0000; + temp |= value; + GT_REG_WRITE (GALMPSC_CHANNELREG_1 + (mpsc * GALMPSC_REG_GAP), temp); + + return 0; +} + +static int galmpsc_set_char_length (int mpsc, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_PROTOCONF_REG + (mpsc * GALMPSC_REG_GAP)); + temp &= 0xFFFFCFFF; + temp |= (value << 12); + GT_REG_WRITE (GALMPSC_PROTOCONF_REG + (mpsc * GALMPSC_REG_GAP), temp); + + return 0; +} + +static int galmpsc_set_stop_bit_length (int mpsc, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_PROTOCONF_REG + (mpsc * GALMPSC_REG_GAP)); + temp &= 0xFFFFBFFF; + temp |= (value << 14); + GT_REG_WRITE (GALMPSC_PROTOCONF_REG + (mpsc * GALMPSC_REG_GAP), temp); + + return 0; +} + +static int galmpsc_set_parity (int mpsc, int value) +{ + unsigned int temp; + + temp = GTREGREAD (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP)); + if (value != -1) { + temp &= 0xFFF3FFF3; + temp |= ((value << 18) | (value << 2)); + temp |= ((value << 17) | (value << 1)); + } else { + temp &= 0xFFF1FFF1; + } + + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP), temp); + + return 0; +} + +static int galmpsc_enter_hunt (int mpsc) +{ + int temp; + + temp = GTREGREAD (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP)); + temp |= 0x80000000; + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP), temp); + + while (GTREGREAD (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP)) & + MPSC_ENTER_HUNT) { + udelay (1); + } + return 0; +} + + +static int galmpsc_shutdown (int mpsc) +{ + unsigned int temp; + + /* cause RX abort (clears RX) */ + temp = GTREGREAD (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP)); + temp |= MPSC_RX_ABORT | MPSC_TX_ABORT; + temp &= ~MPSC_ENTER_HUNT; + GT_REG_WRITE (GALMPSC_CHANNELREG_2 + (mpsc * GALMPSC_REG_GAP), temp); + + GT_REG_WRITE (GALSDMA_0_COM_REG, 0); + GT_REG_WRITE (GALSDMA_0_COM_REG, SDMA_TX_ABORT | SDMA_RX_ABORT); + + /* shut down the MPSC */ + GT_REG_WRITE (GALMPSC_MCONF_LOW, 0); + GT_REG_WRITE (GALMPSC_MCONF_HIGH, 0); + GT_REG_WRITE (GALMPSC_PROTOCONF_REG + (mpsc * GALMPSC_REG_GAP), 0); + + udelay (100); + + /* shut down the sdma engines. */ + /* reset config to default */ + GT_REG_WRITE (GALSDMA_0_CONF_REG, 0x000000fc); + + udelay (100); + + /* clear the SDMA current and first TX and RX pointers */ + GT_REG_WRITE (GALSDMA_0_CUR_RX_PTR, 0); + GT_REG_WRITE (GALSDMA_0_CUR_TX_PTR, 0); + GT_REG_WRITE (GALSDMA_0_FIR_TX_PTR, 0); + + udelay (100); + + return 0; +} + +static void galsdma_enable_rx (void) +{ + int temp; + + /* Enable RX processing */ + temp = GTREGREAD (GALSDMA_0_COM_REG + (CHANNEL * GALSDMA_REG_DIFF)); + temp |= RX_ENABLE; + GT_REG_WRITE (GALSDMA_0_COM_REG + (CHANNEL * GALSDMA_REG_DIFF), temp); + + galmpsc_enter_hunt (CHANNEL); +} + +static int galmpsc_set_snoop (int mpsc, int value) +{ + int reg = + mpsc ? MPSC_1_ADDRESS_CONTROL_LOW : + MPSC_0_ADDRESS_CONTROL_LOW; + int temp = GTREGREAD (reg); + + if (value) + temp |= (1 << 6) | (1 << 14) | (1 << 22) | (1 << 30); + else + temp &= ~((1 << 6) | (1 << 14) | (1 << 22) | (1 << 30)); + GT_REG_WRITE (reg, temp); + return 0; +} + +/******************************************************************************* +* galsdma_set_mem_space - Set MV64360 IDMA memory decoding map. +* +* DESCRIPTION: +* the MV64360 SDMA has its own address decoding map that is de-coupled +* from the CPU interface address decoding windows. The SDMA channels +* share four address windows. Each region can be individually configured +* by this function by associating it to a target interface and setting +* base and size values. +* +* NOTE!!! +* The size must be in 64Kbyte granularity. +* The base address must be aligned to the size. +* The size must be a series of 1s followed by a series of zeros +* +* OUTPUT: +* None. +* +* RETURN: +* True for success, false otherwise. +* +*******************************************************************************/ + +static int galsdma_set_mem_space (unsigned int memSpace, + unsigned int memSpaceTarget, + unsigned int memSpaceAttr, + unsigned int baseAddress, unsigned int size) +{ + unsigned int temp; + + if (size == 0) { + GT_RESET_REG_BITS (MV64360_CUNIT_BASE_ADDR_ENABLE_REG, + 1 << memSpace); + return true; + } + + /* The base address must be aligned to the size. */ + if (baseAddress % size != 0) { + return false; + } + if (size < 0x10000) { + return false; + } + + /* Align size and base to 64K */ + baseAddress &= 0xffff0000; + size &= 0xffff0000; + temp = size >> 16; + + /* Checking that the size is a sequence of '1' followed by a + sequence of '0' starting from LSB to MSB. */ + while ((temp > 0) && (temp & 0x1)) { + temp = temp >> 1; + } + + if (temp != 0) { + GT_REG_WRITE (MV64360_CUNIT_BASE_ADDR_REG0 + memSpace * 8, + (baseAddress | memSpaceTarget | memSpaceAttr)); + GT_REG_WRITE ((MV64360_CUNIT_SIZE0 + memSpace * 8), + (size - 1) & 0xffff0000); + GT_RESET_REG_BITS (MV64360_CUNIT_BASE_ADDR_ENABLE_REG, + 1 << memSpace); + } else { + /* An invalid size was specified */ + return false; + } + return true; +} diff --git a/board/esd/cpci750/mpsc.h b/board/esd/cpci750/mpsc.h new file mode 100644 index 0000000000..a03d1cc0f8 --- /dev/null +++ b/board/esd/cpci750/mpsc.h @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2001 + * John Clemens , Mission Critical Linux, Inc. + * + * 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 + */ + +/************************************************************************* + * changes for Marvell DB64360 eval board 2003 by Ingo Assmus + * + ************************************************************************/ + + +/* + * mpsc.h - header file for MPSC in uart mode (console driver) + */ + +#ifndef __MPSC_H__ +#define __MPSC_H__ + +/* include actual Galileo defines */ +#include "../../Marvell/include/mv_gen_reg.h" + +/* driver related defines */ + +int mpsc_init(int baud); +void mpsc_sdma_init(void); +void mpsc_init2(void); +int galbrg_set_baudrate(int channel, int rate); + +int mpsc_putchar_early(char ch); +char mpsc_getchar_debug(void); +int mpsc_test_char_debug(void); + +int mpsc_test_char_sdma(void); + +extern int (*mpsc_putchar)(char ch); +extern char (*mpsc_getchar)(void); +extern int (*mpsc_test_char)(void); + +#define CHANNEL CONFIG_MPSC_PORT + +#define TX_DESC 5 +#define RX_DESC 20 + +#define DESC_FIRST 0x00010000 +#define DESC_LAST 0x00020000 +#define DESC_OWNER_BIT 0x80000000 + +#define TX_DEMAND 0x00800000 +#define TX_STOP 0x00010000 +#define RX_ENABLE 0x00000080 + +#define SDMA_RX_ABORT (1 << 15) +#define SDMA_TX_ABORT (1 << 31) +#define MPSC_TX_ABORT (1 << 7) +#define MPSC_RX_ABORT (1 << 23) +#define MPSC_ENTER_HUNT (1 << 31) + +/* MPSC defines */ + +#define GALMPSC_CONNECT 0x1 +#define GALMPSC_DISCONNECT 0x0 + +#define GALMPSC_UART 0x1 + +#define GALMPSC_STOP_BITS_1 0x0 +#define GALMPSC_STOP_BITS_2 0x1 +#define GALMPSC_CHAR_LENGTH_8 0x3 +#define GALMPSC_CHAR_LENGTH_7 0x2 + +#define GALMPSC_PARITY_ODD 0x0 +#define GALMPSC_PARITY_EVEN 0x2 +#define GALMPSC_PARITY_MARK 0x3 +#define GALMPSC_PARITY_SPACE 0x1 +#define GALMPSC_PARITY_NONE -1 + +#define GALMPSC_SERIAL_MULTIPLEX SERIAL_PORT_MULTIPLEX /* 0xf010 */ +#define GALMPSC_ROUTING_REGISTER MAIN_ROUTING_REGISTER /* 0xb400 */ +#define GALMPSC_RxC_ROUTE RECEIVE_CLOCK_ROUTING_REGISTER /* 0xb404 */ +#define GALMPSC_TxC_ROUTE TRANSMIT_CLOCK_ROUTING_REGISTER /* 0xb408 */ +#define GALMPSC_MCONF_LOW MPSC0_MAIN_CONFIGURATION_LOW /* 0x8000 */ +#define GALMPSC_MCONF_HIGH MPSC0_MAIN_CONFIGURATION_HIGH /* 0x8004 */ +#define GALMPSC_PROTOCONF_REG MPSC0_PROTOCOL_CONFIGURATION /* 0x8008 */ + +#define GALMPSC_REG_GAP 0x1000 + +#define GALMPSC_MCONF_CHREG_BASE CHANNEL0_REGISTER1 /* 0x800c */ +#define GALMPSC_CHANNELREG_1 CHANNEL0_REGISTER1 /* 0x800c */ +#define GALMPSC_CHANNELREG_2 CHANNEL0_REGISTER2 /* 0x8010 */ +#define GALMPSC_CHANNELREG_3 CHANNEL0_REGISTER3 /* 0x8014 */ +#define GALMPSC_CHANNELREG_4 CHANNEL0_REGISTER4 /* 0x8018 */ +#define GALMPSC_CHANNELREG_5 CHANNEL0_REGISTER5 /* 0x801c */ +#define GALMPSC_CHANNELREG_6 CHANNEL0_REGISTER6 /* 0x8020 */ +#define GALMPSC_CHANNELREG_7 CHANNEL0_REGISTER7 /* 0x8024 */ +#define GALMPSC_CHANNELREG_8 CHANNEL0_REGISTER8 /* 0x8028 */ +#define GALMPSC_CHANNELREG_9 CHANNEL0_REGISTER9 /* 0x802c */ +#define GALMPSC_CHANNELREG_10 CHANNEL0_REGISTER10 /* 0x8030 */ +#define GALMPSC_CHANNELREG_11 CHANNEL0_REGISTER11 /* 0x8034 */ + +#define GALSDMA_COMMAND_FIRST (1 << 16) +#define GALSDMA_COMMAND_LAST (1 << 17) +#define GALSDMA_COMMAND_ENABLEINT (1 << 23) +#define GALSDMA_COMMAND_AUTO (1 << 30) +#define GALSDMA_COMMAND_OWNER (1 << 31) + +#define GALSDMA_RX 0 +#define GALSDMA_TX 1 + +/* CHANNEL2 should be CHANNEL1, according to documentation, + * but to work with the current GTREGS file... + */ +#define GALSDMA_0_CONF_REG CHANNEL0_CONFIGURATION_REGISTER /* 0x4000 */ +#define GALSDMA_1_CONF_REG CHANNEL2_CONFIGURATION_REGISTER /* 0x6000 */ +#define GALSDMA_0_COM_REG CHANNEL0_COMMAND_REGISTER /* 0x4008 */ +#define GALSDMA_1_COM_REG CHANNEL2_COMMAND_REGISTER /* 0x6008 */ +#define GALSDMA_0_CUR_RX_PTR CHANNEL0_CURRENT_RX_DESCRIPTOR_POINTER /* 0x4810 */ +#define GALSDMA_0_CUR_TX_PTR CHANNEL0_CURRENT_TX_DESCRIPTOR_POINTER /* 0x4c10 */ +#define GALSDMA_0_FIR_TX_PTR CHANNEL0_FIRST_TX_DESCRIPTOR_POINTER /* 0x4c14 */ +#define GALSDMA_1_CUR_RX_PTR CHANNEL2_CURRENT_RX_DESCRIPTOR_POINTER /* 0x6810 */ +#define GALSDMA_1_CUR_TX_PTR CHANNEL2_CURRENT_TX_DESCRIPTOR_POINTER /* 0x6c10 */ +#define GALSDMA_1_FIR_TX_PTR CHANNEL2_FIRST_TX_DESCRIPTOR_POINTER /* 0x6c14 */ +#define GALSDMA_REG_DIFF 0x2000 + +/* WRONG in gt64260R.h */ +#define GALSDMA_INT_CAUSE 0xb800 /* SDMA_CAUSE */ +#define GALSDMA_INT_MASK 0xb880 /* SDMA_MASK */ +#define GALMPSC_0_INT_CAUSE 0xb804 +#define GALMPSC_0_INT_MASK 0xb884 + +#define GALSDMA_MODE_UART 0 +#define GALSDMA_MODE_BISYNC 1 +#define GALSDMA_MODE_HDLC 2 +#define GALSDMA_MODE_TRANSPARENT 3 + +#define GALBRG_0_CONFREG BRG0_CONFIGURATION_REGISTER /* 0xb200 */ +#define GALBRG_REG_GAP 0x0008 +#define GALBRG_0_BTREG BRG0_BAUDE_TUNING_REGISTER /* 0xb204 */ + +#endif /* __MPSC_H__ */ diff --git a/board/esd/cpci750/mv_eth.c b/board/esd/cpci750/mv_eth.c new file mode 100644 index 0000000000..e2719b99d1 --- /dev/null +++ b/board/esd/cpci750/mv_eth.c @@ -0,0 +1,3182 @@ +/* + * (C) Copyright 2003 + * Ingo Assmus + * + * based on - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * 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 + */ + +/* + * mv_eth.c - header file for the polled mode GT ethernet driver + */ +#include +#include +#include + +#include "mv_eth.h" + +/* enable Debug outputs */ + +#undef DEBUG_MV_ETH + +#ifdef DEBUG_MV_ETH +#define DEBUG +#define DP(x) x +#else +#define DP(x) +#endif + +#undef MV64360_CHECKSUM_OFFLOAD +/************************************************************************* +************************************************************************** +************************************************************************** +* The first part is the high level driver of the gigE ethernet ports. * +************************************************************************** +************************************************************************** +*************************************************************************/ + +/* Definition for configuring driver */ +/* #define UPDATE_STATS_BY_SOFTWARE */ +#undef MV64360_RX_QUEUE_FILL_ON_TASK + + +/* Constants */ +#define MAGIC_ETH_RUNNING 8031971 +#define MV64360_INTERNAL_SRAM_SIZE _256K +#define EXTRA_BYTES 32 +#define WRAP ETH_HLEN + 2 + 4 + 16 +#define BUFFER_MTU dev->mtu + WRAP +#define INT_CAUSE_UNMASK_ALL 0x0007ffff +#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff +#ifdef MV64360_RX_FILL_ON_TASK +#define INT_CAUSE_MASK_ALL 0x00000000 +#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL +#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT +#endif + +/* Read/Write to/from MV64360 internal registers */ +#define MV_REG_READ(offset) my_le32_to_cpu(* (volatile unsigned int *) (INTERNAL_REG_BASE_ADDR + offset)) +#define MV_REG_WRITE(offset,data) *(volatile unsigned int *) (INTERNAL_REG_BASE_ADDR + offset) = my_cpu_to_le32 (data) +#define MV_SET_REG_BITS(regOffset,bits) ((*((volatile unsigned int*)((INTERNAL_REG_BASE_ADDR) + (regOffset)))) |= ((unsigned int)my_cpu_to_le32(bits))) +#define MV_RESET_REG_BITS(regOffset,bits) ((*((volatile unsigned int*)((INTERNAL_REG_BASE_ADDR) + (regOffset)))) &= ~((unsigned int)my_cpu_to_le32(bits))) + +/* Static function declarations */ +static int mv64360_eth_real_open (struct eth_device *eth); +static int mv64360_eth_real_stop (struct eth_device *eth); +static struct net_device_stats *mv64360_eth_get_stats (struct eth_device + *dev); +static void eth_port_init_mac_tables (ETH_PORT eth_port_num); +static void mv64360_eth_update_stat (struct eth_device *dev); +bool db64360_eth_start (struct eth_device *eth); +unsigned int eth_read_mib_counter (ETH_PORT eth_port_num, + unsigned int mib_offset); +int mv64360_eth_receive (struct eth_device *dev); + +int mv64360_eth_xmit (struct eth_device *, volatile void *packet, int length); + +#ifndef UPDATE_STATS_BY_SOFTWARE +static void mv64360_eth_print_stat (struct eth_device *dev); +#endif +/* Processes a received packet */ +extern void NetReceive (volatile uchar *, int); + +extern unsigned int INTERNAL_REG_BASE_ADDR; + +/************************************************* + *Helper functions - used inside the driver only * + *************************************************/ +#ifdef DEBUG_MV_ETH +void print_globals (struct eth_device *dev) +{ + printf ("Ethernet PRINT_Globals-Debug function\n"); + printf ("Base Address for ETH_PORT_INFO: %08x\n", + (unsigned int) dev->priv); + printf ("Base Address for mv64360_eth_priv: %08x\n", + (unsigned int) &(((ETH_PORT_INFO *) dev->priv)-> + port_private)); + + printf ("GT Internal Base Address: %08x\n", + INTERNAL_REG_BASE_ADDR); + printf ("Base Address for TX-DESCs: %08x Number of allocated Buffers %d\n", (unsigned int) ((ETH_PORT_INFO *) dev->priv)->p_tx_desc_area_base[0], MV64360_TX_QUEUE_SIZE); + printf ("Base Address for RX-DESCs: %08x Number of allocated Buffers %d\n", (unsigned int) ((ETH_PORT_INFO *) dev->priv)->p_rx_desc_area_base[0], MV64360_RX_QUEUE_SIZE); + printf ("Base Address for RX-Buffer: %08x allocated Bytes %d\n", + (unsigned int) ((ETH_PORT_INFO *) dev->priv)-> + p_rx_buffer_base[0], + (MV64360_RX_QUEUE_SIZE * MV64360_RX_BUFFER_SIZE) + 32); + printf ("Base Address for TX-Buffer: %08x allocated Bytes %d\n", + (unsigned int) ((ETH_PORT_INFO *) dev->priv)-> + p_tx_buffer_base[0], + (MV64360_TX_QUEUE_SIZE * MV64360_TX_BUFFER_SIZE) + 32); +} +#endif + +#define my_cpu_to_le32(x) my_le32_to_cpu((x)) + +unsigned long my_le32_to_cpu (unsigned long x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | ((x & 0xff000000U) >> 24)); +} + + +/********************************************************************** + * mv64360_eth_print_phy_status + * + * Prints gigabit ethenret phy status + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + **********************************************************************/ + +static void mv64360_eth_print_phy_status (struct eth_device *dev) +{ + struct mv64360_eth_priv *port_private; + unsigned int port_num; + ETH_PORT_INFO *ethernet_private = (ETH_PORT_INFO *) dev->priv; + unsigned int port_status, phy_reg_data; + + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + /* Check Link status on phy */ + eth_port_read_smi_reg (port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + printf ("Ethernet port changed link status to DOWN\n"); + } else { + port_status = + MV_REG_READ (MV64360_ETH_PORT_STATUS_REG (port_num)); + printf ("Ethernet status port %d: Link up", port_num); + printf (", %s", + (port_status & BIT2) ? "Full Duplex" : "Half Duplex"); + if (port_status & BIT4) + printf (", Speed 1 Gbps"); + else + printf (", %s", + (port_status & BIT5) ? "Speed 100 Mbps" : + "Speed 10 Mbps"); + printf ("\n"); + } +} + +/********************************************************************** + * u-boot entry functions for mv64360_eth + * + **********************************************************************/ +int db64360_eth_probe (struct eth_device *dev) +{ + return ((int) db64360_eth_start (dev)); +} + +int db64360_eth_poll (struct eth_device *dev) +{ + return mv64360_eth_receive (dev); +} + +int db64360_eth_transmit (struct eth_device *dev, volatile void *packet, + int length) +{ + mv64360_eth_xmit (dev, packet, length); + return 0; +} + +void db64360_eth_disable (struct eth_device *dev) +{ + mv64360_eth_stop (dev); +} + + +void mv6436x_eth_initialize (bd_t * bis) +{ + struct eth_device *dev; + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + int devnum, x, temp; + char *s, *e, buf[64]; + + for (devnum = 0; devnum < MV_ETH_DEVS; devnum++) { + dev = calloc (sizeof (*dev), 1); + if (!dev) { + printf ("%s: mv_enet%d allocation failure, %s\n", + __FUNCTION__, devnum, "eth_device structure"); + return; + } + + /* must be less than NAMESIZE (16) */ + sprintf (dev->name, "mv_enet%d", devnum); + +#ifdef DEBUG + printf ("Initializing %s\n", dev->name); +#endif + + /* Extract the MAC address from the environment */ + switch (devnum) { + case 0: + s = "ethaddr"; + break; + + case 1: + s = "eth1addr"; + break; + + case 2: + s = "eth2addr"; + break; + + default: /* this should never happen */ + printf ("%s: Invalid device number %d\n", + __FUNCTION__, devnum); + return; + } + + temp = getenv_r (s, buf, sizeof (buf)); + s = (temp > 0) ? buf : NULL; + +#ifdef DEBUG + printf ("Setting MAC %d to %s\n", devnum, s); +#endif + for (x = 0; x < 6; ++x) { + dev->enetaddr[x] = s ? simple_strtoul (s, &e, 16) : 0; + if (s) + s = (*e) ? e + 1 : e; + } + /* ronen - set the MAC addr in the HW */ + eth_port_uc_addr_set (devnum, dev->enetaddr, 0); + + dev->init = (void *) db64360_eth_probe; + dev->halt = (void *) ethernet_phy_reset; + dev->send = (void *) db64360_eth_transmit; + dev->recv = (void *) db64360_eth_poll; + + dev->priv = (void *) ethernet_private = + calloc (sizeof (*ethernet_private), 1); + if (!ethernet_private) { + printf ("%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, + "Private Device Structure"); + free (dev); + return; + } + /* start with an zeroed ETH_PORT_INFO */ + memset (ethernet_private, 0, sizeof (ETH_PORT_INFO)); + memcpy (ethernet_private->port_mac_addr, dev->enetaddr, 6); + + /* set pointer to memory for stats data structure etc... */ + ethernet_private->port_private = (void *) port_private = + calloc (sizeof (*ethernet_private), 1); + if (!port_private) { + printf ("%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, + "Port Private Device Structure"); + + free (ethernet_private); + free (dev); + return; + } + + port_private->stats = + calloc (sizeof (struct net_device_stats), 1); + if (!port_private->stats) { + printf ("%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, + "Net stat Structure"); + + free (port_private); + free (ethernet_private); + free (dev); + return; + } + memset (ethernet_private->port_private, 0, + sizeof (struct mv64360_eth_priv)); + switch (devnum) { + case 0: + ethernet_private->port_num = ETH_0; + break; + case 1: + ethernet_private->port_num = ETH_1; + break; + case 2: + ethernet_private->port_num = ETH_2; + break; + default: + printf ("Invalid device number %d\n", devnum); + break; + }; + + port_private->port_num = devnum; + /* + * Read MIB counter on the GT in order to reset them, + * then zero all the stats fields in memory + */ + mv64360_eth_update_stat (dev); + memset (port_private->stats, 0, + sizeof (struct net_device_stats)); + /* Extract the MAC address from the environment */ + switch (devnum) { + case 0: + s = "ethaddr"; + break; + + case 1: + s = "eth1addr"; + break; + + case 2: + s = "eth2addr"; + break; + + default: /* this should never happen */ + printf ("%s: Invalid device number %d\n", + __FUNCTION__, devnum); + return; + } + + temp = getenv_r (s, buf, sizeof (buf)); + s = (temp > 0) ? buf : NULL; + +#ifdef DEBUG + printf ("Setting MAC %d to %s\n", devnum, s); +#endif + for (x = 0; x < 6; ++x) { + dev->enetaddr[x] = s ? simple_strtoul (s, &e, 16) : 0; + if (s) + s = (*e) ? e + 1 : e; + } + + DP (printf ("Allocating descriptor and buffer rings\n")); + + ethernet_private->p_rx_desc_area_base[0] = + (ETH_RX_DESC *) memalign (16, + RX_DESC_ALIGNED_SIZE * + MV64360_RX_QUEUE_SIZE + 1); + ethernet_private->p_tx_desc_area_base[0] = + (ETH_TX_DESC *) memalign (16, + TX_DESC_ALIGNED_SIZE * + MV64360_TX_QUEUE_SIZE + 1); + + ethernet_private->p_rx_buffer_base[0] = + (char *) memalign (16, + MV64360_RX_QUEUE_SIZE * + MV64360_TX_BUFFER_SIZE + 1); + ethernet_private->p_tx_buffer_base[0] = + (char *) memalign (16, + MV64360_RX_QUEUE_SIZE * + MV64360_TX_BUFFER_SIZE + 1); + +#ifdef DEBUG_MV_ETH + /* DEBUG OUTPUT prints adresses of globals */ + print_globals (dev); +#endif + eth_register (dev); + + } + DP (printf ("%s: exit\n", __FUNCTION__)); + +} + +/********************************************************************** + * mv64360_eth_open + * + * This function is called when openning the network device. The function + * should initialize all the hardware, initialize cyclic Rx/Tx + * descriptors chain and buffers and allocate an IRQ to the network + * device. + * + * Input : a pointer to the network device structure + * / / ronen - changed the output to match net/eth.c needs + * Output : nonzero of success , zero if fails. + * under construction + **********************************************************************/ + +int mv64360_eth_open (struct eth_device *dev) +{ + return (mv64360_eth_real_open (dev)); +} + +/* Helper function for mv64360_eth_open */ +static int mv64360_eth_real_open (struct eth_device *dev) +{ + + unsigned int queue; + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + u32 port_status, phy_reg_data; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + /* ronen - when we update the MAC env params we only update dev->enetaddr + see ./net/eth.c eth_set_enetaddr() */ + memcpy (ethernet_private->port_mac_addr, dev->enetaddr, 6); + + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + /* Stop RX Queues */ + MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num), + 0x0000ff00); + + /* Clear the ethernet port interrupts */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_REG (port_num), 0); + MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0); + + /* Unmask RX buffer and TX end interrupt */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_MASK_REG (port_num), + INT_CAUSE_UNMASK_ALL); + + /* Unmask phy and link status changes interrupts */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_EXTEND_MASK_REG (port_num), + INT_CAUSE_UNMASK_ALL_EXT); + + /* Set phy address of the port */ + ethernet_private->port_phy_addr = 0x8 + port_num; + + /* Activate the DMA channels etc */ + eth_port_init (ethernet_private); + + + /* "Allocate" setup TX rings */ + + for (queue = 0; queue < MV64360_TX_QUEUE_NUM; queue++) { + unsigned int size; + + port_private->tx_ring_size[queue] = MV64360_TX_QUEUE_SIZE; + size = (port_private->tx_ring_size[queue] * TX_DESC_ALIGNED_SIZE); /*size = no of DESCs times DESC-size */ + ethernet_private->tx_desc_area_size[queue] = size; + + /* first clear desc area completely */ + memset ((void *) ethernet_private->p_tx_desc_area_base[queue], + 0, ethernet_private->tx_desc_area_size[queue]); + + /* initialize tx desc ring with low level driver */ + if (ether_init_tx_desc_ring + (ethernet_private, ETH_Q0, + port_private->tx_ring_size[queue], + MV64360_TX_BUFFER_SIZE /* Each Buffer is 1600 Byte */ , + (unsigned int) ethernet_private-> + p_tx_desc_area_base[queue], + (unsigned int) ethernet_private-> + p_tx_buffer_base[queue]) == false) + printf ("### Error initializing TX Ring\n"); + } + + /* "Allocate" setup RX rings */ + for (queue = 0; queue < MV64360_RX_QUEUE_NUM; queue++) { + unsigned int size; + + /* Meantime RX Ring are fixed - but must be configurable by user */ + port_private->rx_ring_size[queue] = MV64360_RX_QUEUE_SIZE; + size = (port_private->rx_ring_size[queue] * + RX_DESC_ALIGNED_SIZE); + ethernet_private->rx_desc_area_size[queue] = size; + + /* first clear desc area completely */ + memset ((void *) ethernet_private->p_rx_desc_area_base[queue], + 0, ethernet_private->rx_desc_area_size[queue]); + if ((ether_init_rx_desc_ring + (ethernet_private, ETH_Q0, + port_private->rx_ring_size[queue], + MV64360_RX_BUFFER_SIZE /* Each Buffer is 1600 Byte */ , + (unsigned int) ethernet_private-> + p_rx_desc_area_base[queue], + (unsigned int) ethernet_private-> + p_rx_buffer_base[queue])) == false) + printf ("### Error initializing RX Ring\n"); + } + + eth_port_start (ethernet_private); + + /* Set maximum receive buffer to 9700 bytes */ + MV_REG_WRITE (MV64360_ETH_PORT_SERIAL_CONTROL_REG (port_num), + (0x5 << 17) | + (MV_REG_READ + (MV64360_ETH_PORT_SERIAL_CONTROL_REG (port_num)) + & 0xfff1ffff)); + + /* + * Set ethernet MTU for leaky bucket mechanism to 0 - this will + * disable the leaky bucket mechanism . + */ + + MV_REG_WRITE (MV64360_ETH_MAXIMUM_TRANSMIT_UNIT (port_num), 0); + port_status = MV_REG_READ (MV64360_ETH_PORT_STATUS_REG (port_num)); + + /* Check Link status on phy */ + eth_port_read_smi_reg (port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + /* Reset PHY */ + if ((ethernet_phy_reset (port_num)) != true) { + printf ("$$ Warnning: No link on port %d \n", + port_num); + return 0; + } else { + eth_port_read_smi_reg (port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + printf ("### Error: Phy is not active\n"); + return 0; + } + } + } else { + mv64360_eth_print_phy_status (dev); + } + port_private->eth_running = MAGIC_ETH_RUNNING; + return 1; +} + + +static int mv64360_eth_free_tx_rings (struct eth_device *dev) +{ + unsigned int queue; + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + volatile ETH_TX_DESC *p_tx_curr_desc; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + /* Stop Tx Queues */ + MV_REG_WRITE (MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG (port_num), + 0x0000ff00); + + /* Free TX rings */ + DP (printf ("Clearing previously allocated TX queues... ")); + for (queue = 0; queue < MV64360_TX_QUEUE_NUM; queue++) { + /* Free on TX rings */ + for (p_tx_curr_desc = + ethernet_private->p_tx_desc_area_base[queue]; + ((unsigned int) p_tx_curr_desc <= (unsigned int) + ethernet_private->p_tx_desc_area_base[queue] + + ethernet_private->tx_desc_area_size[queue]); + p_tx_curr_desc = + (ETH_TX_DESC *) ((unsigned int) p_tx_curr_desc + + TX_DESC_ALIGNED_SIZE)) { + /* this is inside for loop */ + if (p_tx_curr_desc->return_info != 0) { + p_tx_curr_desc->return_info = 0; + DP (printf ("freed\n")); + } + } + DP (printf ("Done\n")); + } + return 0; +} + +static int mv64360_eth_free_rx_rings (struct eth_device *dev) +{ + unsigned int queue; + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + volatile ETH_RX_DESC *p_rx_curr_desc; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + + /* Stop RX Queues */ + MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num), + 0x0000ff00); + + /* Free RX rings */ + DP (printf ("Clearing previously allocated RX queues... ")); + for (queue = 0; queue < MV64360_RX_QUEUE_NUM; queue++) { + /* Free preallocated skb's on RX rings */ + for (p_rx_curr_desc = + ethernet_private->p_rx_desc_area_base[queue]; + (((unsigned int) p_rx_curr_desc < + ((unsigned int) ethernet_private-> + p_rx_desc_area_base[queue] + + ethernet_private->rx_desc_area_size[queue]))); + p_rx_curr_desc = + (ETH_RX_DESC *) ((unsigned int) p_rx_curr_desc + + RX_DESC_ALIGNED_SIZE)) { + if (p_rx_curr_desc->return_info != 0) { + p_rx_curr_desc->return_info = 0; + DP (printf ("freed\n")); + } + } + DP (printf ("Done\n")); + } + return 0; +} + +/********************************************************************** + * mv64360_eth_stop + * + * This function is used when closing the network device. + * It updates the hardware, + * release all memory that holds buffers and descriptors and release the IRQ. + * Input : a pointer to the device structure + * Output : zero if success , nonzero if fails + *********************************************************************/ + +int mv64360_eth_stop (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + /* Disable all gigE address decoder */ + MV_REG_WRITE (MV64360_ETH_BASE_ADDR_ENABLE_REG, 0x3f); + DP (printf ("%s Ethernet stop called ... \n", __FUNCTION__)); + mv64360_eth_real_stop (dev); + + return 0; +}; + +/* Helper function for mv64360_eth_stop */ + +static int mv64360_eth_real_stop (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + + mv64360_eth_free_tx_rings (dev); + mv64360_eth_free_rx_rings (dev); + + eth_port_reset (ethernet_private->port_num); + /* Disable ethernet port interrupts */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_REG (port_num), 0); + MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0); + /* Mask RX buffer and TX end interrupt */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_MASK_REG (port_num), 0); + /* Mask phy and link status changes interrupts */ + MV_REG_WRITE (MV64360_ETH_INTERRUPT_EXTEND_MASK_REG (port_num), 0); + MV_RESET_REG_BITS (MV64360_CPU_INTERRUPT0_MASK_HIGH, + BIT0 << port_num); + /* Print Network statistics */ +#ifndef UPDATE_STATS_BY_SOFTWARE + /* + * Print statistics (only if ethernet is running), + * then zero all the stats fields in memory + */ + if (port_private->eth_running == MAGIC_ETH_RUNNING) { + port_private->eth_running = 0; + mv64360_eth_print_stat (dev); + } + memset (port_private->stats, 0, sizeof (struct net_device_stats)); +#endif + DP (printf ("\nEthernet stopped ... \n")); + return 0; +} + + +/********************************************************************** + * mv64360_eth_start_xmit + * + * This function is queues a packet in the Tx descriptor for + * required port. + * + * Input : skb - a pointer to socket buffer + * dev - a pointer to the required port + * + * Output : zero upon success + **********************************************************************/ + +int mv64360_eth_xmit (struct eth_device *dev, volatile void *dataPtr, + int dataSize) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + PKT_INFO pkt_info; + ETH_FUNC_RET_STATUS status; + struct net_device_stats *stats; + ETH_FUNC_RET_STATUS release_result; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + stats = port_private->stats; + + /* Update packet info data structure */ + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; /* DMA owned, first last */ + pkt_info.byte_cnt = dataSize; + pkt_info.buf_ptr = (unsigned int) dataPtr; + + status = eth_port_send (ethernet_private, ETH_Q0, &pkt_info); + if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) { + printf ("Error on transmitting packet .."); + if (status == ETH_QUEUE_FULL) + printf ("ETH Queue is full. \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printf ("ETH Queue: using last available resource. \n"); + goto error; + } + + /* Update statistics and start of transmittion time */ + stats->tx_bytes += dataSize; + stats->tx_packets++; + + /* Check if packet(s) is(are) transmitted correctly (release everything) */ + do { + release_result = + eth_tx_return_desc (ethernet_private, ETH_Q0, + &pkt_info); + switch (release_result) { + case ETH_OK: + DP (printf ("descriptor released\n")); + if (pkt_info.cmd_sts & BIT0) { + printf ("Error in TX\n"); + stats->tx_errors++; + + } + break; + case ETH_RETRY: + DP (printf ("transmission still in process\n")); + break; + + case ETH_ERROR: + printf ("routine can not access Tx desc ring\n"); + break; + + case ETH_END_OF_JOB: + DP (printf ("the routine has nothing to release\n")); + break; + default: /* should not happen */ + break; + } + } while (release_result == ETH_OK); + + + return 0; /* success */ + error: + return 1; /* Failed - higher layers will free the skb */ +} + +/********************************************************************** + * mv64360_eth_receive + * + * This function is forward packets that are received from the port's + * queues toward kernel core or FastRoute them to another interface. + * + * Input : dev - a pointer to the required interface + * max - maximum number to receive (0 means unlimted) + * + * Output : number of served packets + **********************************************************************/ + +int mv64360_eth_receive (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + PKT_INFO pkt_info; + struct net_device_stats *stats; + + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + stats = port_private->stats; + + while ((eth_port_receive (ethernet_private, ETH_Q0, &pkt_info) == + ETH_OK)) { + +#ifdef DEBUG_MV_ETH + if (pkt_info.byte_cnt != 0) { + printf ("%s: Received %d byte Packet @ 0x%x\n", + __FUNCTION__, pkt_info.byte_cnt, + pkt_info.buf_ptr); + } +#endif + /* Update statistics. Note byte count includes 4 byte CRC count */ + stats->rx_packets++; + stats->rx_bytes += pkt_info.byte_cnt; + + /* + * In case received a packet without first / last bits on OR the error + * summary bit is on, the packets needs to be dropeed. + */ + if (((pkt_info. + cmd_sts & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) + || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + stats->rx_dropped++; + + printf ("Received packet spread on multiple descriptors\n"); + + /* Is this caused by an error ? */ + if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) { + stats->rx_errors++; + } + + /* free these descriptors again without forwarding them to the higher layers */ + pkt_info.buf_ptr &= ~0x7; /* realign buffer again */ + pkt_info.byte_cnt = 0x0000; /* Reset Byte count */ + + if (eth_rx_return_buff + (ethernet_private, ETH_Q0, &pkt_info) != ETH_OK) { + printf ("Error while returning the RX Desc to Ring\n"); + } else { + DP (printf ("RX Desc returned to Ring\n")); + } + /* /free these descriptors again */ + } else { + +/* !!! call higher layer processing */ +#ifdef DEBUG_MV_ETH + printf ("\nNow send it to upper layer protocols (NetReceive) ...\n"); +#endif + /* let the upper layer handle the packet */ + NetReceive ((uchar *) pkt_info.buf_ptr, + (int) pkt_info.byte_cnt); + +/* **************************************************************** */ +/* free descriptor */ + pkt_info.buf_ptr &= ~0x7; /* realign buffer again */ + pkt_info.byte_cnt = 0x0000; /* Reset Byte count */ + DP (printf + ("RX: pkt_info.buf_ptr = %x\n", + pkt_info.buf_ptr)); + if (eth_rx_return_buff + (ethernet_private, ETH_Q0, &pkt_info) != ETH_OK) { + printf ("Error while returning the RX Desc to Ring\n"); + } else { + DP (printf ("RX Desc returned to Ring\n")); + } + +/* **************************************************************** */ + + } + } + mv64360_eth_get_stats (dev); /* update statistics */ + return 1; +} + +/********************************************************************** + * mv64360_eth_get_stats + * + * Returns a pointer to the interface statistics. + * + * Input : dev - a pointer to the required interface + * + * Output : a pointer to the interface's statistics + **********************************************************************/ + +static struct net_device_stats *mv64360_eth_get_stats (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + unsigned int port_num; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + + mv64360_eth_update_stat (dev); + + return port_private->stats; +} + + +/********************************************************************** + * mv64360_eth_update_stat + * + * Update the statistics structure in the private data structure + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + **********************************************************************/ + +static void mv64360_eth_update_stat (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + struct net_device_stats *stats; + unsigned int port_num; + volatile unsigned int dummy; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + stats = port_private->stats; + + /* These are false updates */ + stats->rx_packets += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_FRAMES_RECEIVED); + stats->tx_packets += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_FRAMES_SENT); + stats->rx_bytes += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_OCTETS_RECEIVED_LOW); + /* + * Ideally this should be as follows - + * + * stats->rx_bytes += stats->rx_bytes + + * ((unsigned long) ethReadMibCounter (ethernet_private->port_num , + * ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH) << 32); + * + * But the unsigned long in PowerPC and MIPS are 32bit. So the next read + * is just a dummy read for proper work of the GigE port + */ + dummy = eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH); + stats->tx_bytes += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_OCTETS_SENT_LOW); + dummy = eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_GOOD_OCTETS_SENT_HIGH); + stats->rx_errors += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_MAC_RECEIVE_ERROR); + + /* Rx dropped is for received packet with CRC error */ + stats->rx_dropped += + (unsigned long) eth_read_mib_counter (ethernet_private-> + port_num, + ETH_MIB_BAD_CRC_EVENT); + stats->multicast += (unsigned long) + eth_read_mib_counter (ethernet_private->port_num, + ETH_MIB_MULTICAST_FRAMES_RECEIVED); + stats->collisions += + (unsigned long) eth_read_mib_counter (ethernet_private-> + port_num, + ETH_MIB_COLLISION) + + (unsigned long) eth_read_mib_counter (ethernet_private-> + port_num, + ETH_MIB_LATE_COLLISION); + /* detailed rx errors */ + stats->rx_length_errors += + (unsigned long) eth_read_mib_counter (ethernet_private-> + port_num, + ETH_MIB_UNDERSIZE_RECEIVED) + + + (unsigned long) eth_read_mib_counter (ethernet_private-> + port_num, + ETH_MIB_OVERSIZE_RECEIVED); + /* detailed tx errors */ +} + +#ifndef UPDATE_STATS_BY_SOFTWARE +/********************************************************************** + * mv64360_eth_print_stat + * + * Update the statistics structure in the private data structure + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + **********************************************************************/ + +static void mv64360_eth_print_stat (struct eth_device *dev) +{ + ETH_PORT_INFO *ethernet_private; + struct mv64360_eth_priv *port_private; + struct net_device_stats *stats; + unsigned int port_num; + + ethernet_private = (ETH_PORT_INFO *) dev->priv; + port_private = + (struct mv64360_eth_priv *) ethernet_private->port_private; + port_num = port_private->port_num; + stats = port_private->stats; + + /* These are false updates */ + printf ("\n### Network statistics: ###\n"); + printf ("--------------------------\n"); + printf (" Packets received: %ld\n", stats->rx_packets); + printf (" Packets send: %ld\n", stats->tx_packets); + printf (" Received bytes: %ld\n", stats->rx_bytes); + printf (" Send bytes: %ld\n", stats->tx_bytes); + if (stats->rx_errors != 0) + printf (" Rx Errors: %ld\n", + stats->rx_errors); + if (stats->rx_dropped != 0) + printf (" Rx dropped (CRC Errors): %ld\n", + stats->rx_dropped); + if (stats->multicast != 0) + printf (" Rx mulicast frames: %ld\n", + stats->multicast); + if (stats->collisions != 0) + printf (" No. of collisions: %ld\n", + stats->collisions); + if (stats->rx_length_errors != 0) + printf (" Rx length errors: %ld\n", + stats->rx_length_errors); +} +#endif + +/************************************************************************** + *network_start - Network Kick Off Routine UBoot + *Inputs : + *Outputs : + **************************************************************************/ + +bool db64360_eth_start (struct eth_device *dev) +{ + return (mv64360_eth_open (dev)); /* calls real open */ +} + +/************************************************************************* +************************************************************************** +************************************************************************** +* The second part is the low level driver of the gigE ethernet ports. * +************************************************************************** +************************************************************************** +*************************************************************************/ +/* + * based on Linux code + * arch/ppc/galileo/EVB64360/mv64360_eth.c - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + + * 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. + * + */ + +/******************************************************************************** + * Marvell's Gigabit Ethernet controller low level driver + * + * DESCRIPTION: + * This file introduce low level API to Marvell's Gigabit Ethernet + * controller. This Gigabit Ethernet Controller driver API controls + * 1) Operations (i.e. port init, start, reset etc'). + * 2) Data flow (i.e. port send, receive etc'). + * Each Gigabit Ethernet port is controlled via ETH_PORT_INFO + * struct. + * This struct includes user configuration information as well as + * driver internal data needed for its operations. + * + * Supported Features: + * - This low level driver is OS independent. Allocating memory for + * the descriptor rings and buffers are not within the scope of + * this driver. + * - The user is free from Rx/Tx queue managing. + * - This low level driver introduce functionality API that enable + * the to operate Marvell's Gigabit Ethernet Controller in a + * convenient way. + * - Simple Gigabit Ethernet port operation API. + * - Simple Gigabit Ethernet port data flow API. + * - Data flow and operation API support per queue functionality. + * - Support cached descriptors for better performance. + * - Enable access to all four DRAM banks and internal SRAM memory + * spaces. + * - PHY access and control API. + * - Port control register configuration API. + * - Full control over Unicast and Multicast MAC configurations. + * + * Operation flow: + * + * Initialization phase + * This phase complete the initialization of the ETH_PORT_INFO + * struct. + * User information regarding port configuration has to be set + * prior to calling the port initialization routine. For example, + * the user has to assign the port_phy_addr field which is board + * depended parameter. + * In this phase any port Tx/Rx activity is halted, MIB counters + * are cleared, PHY address is set according to user parameter and + * access to DRAM and internal SRAM memory spaces. + * + * Driver ring initialization + * Allocating memory for the descriptor rings and buffers is not + * within the scope of this driver. Thus, the user is required to + * allocate memory for the descriptors ring and buffers. Those + * memory parameters are used by the Rx and Tx ring initialization + * routines in order to curve the descriptor linked list in a form + * of a ring. + * Note: Pay special attention to alignment issues when using + * cached descriptors/buffers. In this phase the driver store + * information in the ETH_PORT_INFO struct regarding each queue + * ring. + * + * Driver start + * This phase prepares the Ethernet port for Rx and Tx activity. + * It uses the information stored in the ETH_PORT_INFO struct to + * initialize the various port registers. + * + * Data flow: + * All packet references to/from the driver are done using PKT_INFO + * struct. + * This struct is a unified struct used with Rx and Tx operations. + * This way the user is not required to be familiar with neither + * Tx nor Rx descriptors structures. + * The driver's descriptors rings are management by indexes. + * Those indexes controls the ring resources and used to indicate + * a SW resource error: + * 'current' + * This index points to the current available resource for use. For + * example in Rx process this index will point to the descriptor + * that will be passed to the user upon calling the receive routine. + * In Tx process, this index will point to the descriptor + * that will be assigned with the user packet info and transmitted. + * 'used' + * This index points to the descriptor that need to restore its + * resources. For example in Rx process, using the Rx buffer return + * API will attach the buffer returned in packet info to the + * descriptor pointed by 'used'. In Tx process, using the Tx + * descriptor return will merely return the user packet info with + * the command status of the transmitted buffer pointed by the + * 'used' index. Nevertheless, it is essential to use this routine + * to update the 'used' index. + * 'first' + * This index supports Tx Scatter-Gather. It points to the first + * descriptor of a packet assembled of multiple buffers. For example + * when in middle of Such packet we have a Tx resource error the + * 'curr' index get the value of 'first' to indicate that the ring + * returned to its state before trying to transmit this packet. + * + * Receive operation: + * The eth_port_receive API set the packet information struct, + * passed by the caller, with received information from the + * 'current' SDMA descriptor. + * It is the user responsibility to return this resource back + * to the Rx descriptor ring to enable the reuse of this source. + * Return Rx resource is done using the eth_rx_return_buff API. + * + * Transmit operation: + * The eth_port_send API supports Scatter-Gather which enables to + * send a packet spanned over multiple buffers. This means that + * for each packet info structure given by the user and put into + * the Tx descriptors ring, will be transmitted only if the 'LAST' + * bit will be set in the packet info command status field. This + * API also consider restriction regarding buffer alignments and + * sizes. + * The user must return a Tx resource after ensuring the buffer + * has been transmitted to enable the Tx ring indexes to update. + * + * BOARD LAYOUT + * This device is on-board. No jumper diagram is necessary. + * + * EXTERNAL INTERFACE + * + * Prior to calling the initialization routine eth_port_init() the user + * must set the following fields under ETH_PORT_INFO struct: + * port_num User Ethernet port number. + * port_phy_addr User PHY address of Ethernet port. + * port_mac_addr[6] User defined port MAC address. + * port_config User port configuration value. + * port_config_extend User port config extend value. + * port_sdma_config User port SDMA config value. + * port_serial_control User port serial control value. + * *port_virt_to_phys () User function to cast virtual addr to CPU bus addr. + * *port_private User scratch pad for user specific data structures. + * + * This driver introduce a set of default values: + * PORT_CONFIG_VALUE Default port configuration value + * PORT_CONFIG_EXTEND_VALUE Default port extend configuration value + * PORT_SDMA_CONFIG_VALUE Default sdma control value + * PORT_SERIAL_CONTROL_VALUE Default port serial control value + * + * This driver data flow is done using the PKT_INFO struct which is + * a unified struct for Rx and Tx operations: + * byte_cnt Tx/Rx descriptor buffer byte count. + * l4i_chk CPU provided TCP Checksum. For Tx operation only. + * cmd_sts Tx/Rx descriptor command status. + * buf_ptr Tx/Rx descriptor buffer pointer. + * return_info Tx/Rx user resource return information. + * + * + * EXTERNAL SUPPORT REQUIREMENTS + * + * This driver requires the following external support: + * + * D_CACHE_FLUSH_LINE (address, address offset) + * + * This macro applies assembly code to flush and invalidate cache + * line. + * address - address base. + * address offset - address offset + * + * + * CPU_PIPE_FLUSH + * + * This macro applies assembly code to flush the CPU pipeline. + * + *******************************************************************************/ +/* includes */ + +/* defines */ +/* SDMA command macros */ +#define ETH_ENABLE_TX_QUEUE(tx_queue, eth_port) \ + MV_REG_WRITE(MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), (1 << tx_queue)) + +#define ETH_DISABLE_TX_QUEUE(tx_queue, eth_port) \ + MV_REG_WRITE(MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port),\ + (1 << (8 + tx_queue))) + +#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \ +MV_REG_WRITE(MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << rx_queue)) + +#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \ +MV_REG_WRITE(MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << (8 + rx_queue))) + +#define CURR_RFD_GET(p_curr_desc, queue) \ + ((p_curr_desc) = p_eth_port_ctrl->p_rx_curr_desc_q[queue]) + +#define CURR_RFD_SET(p_curr_desc, queue) \ + (p_eth_port_ctrl->p_rx_curr_desc_q[queue] = (p_curr_desc)) + +#define USED_RFD_GET(p_used_desc, queue) \ + ((p_used_desc) = p_eth_port_ctrl->p_rx_used_desc_q[queue]) + +#define USED_RFD_SET(p_used_desc, queue)\ +(p_eth_port_ctrl->p_rx_used_desc_q[queue] = (p_used_desc)) + + +#define CURR_TFD_GET(p_curr_desc, queue) \ + ((p_curr_desc) = p_eth_port_ctrl->p_tx_curr_desc_q[queue]) + +#define CURR_TFD_SET(p_curr_desc, queue) \ + (p_eth_port_ctrl->p_tx_curr_desc_q[queue] = (p_curr_desc)) + +#define USED_TFD_GET(p_used_desc, queue) \ + ((p_used_desc) = p_eth_port_ctrl->p_tx_used_desc_q[queue]) + +#define USED_TFD_SET(p_used_desc, queue) \ + (p_eth_port_ctrl->p_tx_used_desc_q[queue] = (p_used_desc)) + +#define FIRST_TFD_GET(p_first_desc, queue) \ + ((p_first_desc) = p_eth_port_ctrl->p_tx_first_desc_q[queue]) + +#define FIRST_TFD_SET(p_first_desc, queue) \ + (p_eth_port_ctrl->p_tx_first_desc_q[queue] = (p_first_desc)) + + +/* Macros that save access to desc in order to find next desc pointer */ +#define RX_NEXT_DESC_PTR(p_rx_desc, queue) (ETH_RX_DESC*)(((((unsigned int)p_rx_desc - (unsigned int)p_eth_port_ctrl->p_rx_desc_area_base[queue]) + RX_DESC_ALIGNED_SIZE) % p_eth_port_ctrl->rx_desc_area_size[queue]) + (unsigned int)p_eth_port_ctrl->p_rx_desc_area_base[queue]) + +#define TX_NEXT_DESC_PTR(p_tx_desc, queue) (ETH_TX_DESC*)(((((unsigned int)p_tx_desc - (unsigned int)p_eth_port_ctrl->p_tx_desc_area_base[queue]) + TX_DESC_ALIGNED_SIZE) % p_eth_port_ctrl->tx_desc_area_size[queue]) + (unsigned int)p_eth_port_ctrl->p_tx_desc_area_base[queue]) + +#define LINK_UP_TIMEOUT 100000 +#define PHY_BUSY_TIMEOUT 10000000 + +/* locals */ + +/* PHY routines */ +static void ethernet_phy_set (ETH_PORT eth_port_num, int phy_addr); +static int ethernet_phy_get (ETH_PORT eth_port_num); + +/* Ethernet Port routines */ +static void eth_set_access_control (ETH_PORT eth_port_num, + ETH_WIN_PARAM * param); +static bool eth_port_uc_addr (ETH_PORT eth_port_num, unsigned char uc_nibble, + ETH_QUEUE queue, int option); +#if 0 /* FIXME */ +static bool eth_port_smc_addr (ETH_PORT eth_port_num, + unsigned char mc_byte, + ETH_QUEUE queue, int option); +static bool eth_port_omc_addr (ETH_PORT eth_port_num, + unsigned char crc8, + ETH_QUEUE queue, int option); +#endif + +static void eth_b_copy (unsigned int src_addr, unsigned int dst_addr, + int byte_count); + +void eth_dbg (ETH_PORT_INFO * p_eth_port_ctrl); + + +typedef enum _memory_bank { BANK0, BANK1, BANK2, BANK3 } MEMORY_BANK; +u32 mv_get_dram_bank_base_addr (MEMORY_BANK bank) +{ + u32 result = 0; + u32 enable = MV_REG_READ (MV64360_BASE_ADDR_ENABLE); + + if (enable & (1 << bank)) + return 0; + if (bank == BANK0) + result = MV_REG_READ (MV64360_CS_0_BASE_ADDR); + if (bank == BANK1) + result = MV_REG_READ (MV64360_CS_1_BASE_ADDR); + if (bank == BANK2) + result = MV_REG_READ (MV64360_CS_2_BASE_ADDR); + if (bank == BANK3) + result = MV_REG_READ (MV64360_CS_3_BASE_ADDR); + result &= 0x0000ffff; + result = result << 16; + return result; +} + +u32 mv_get_dram_bank_size (MEMORY_BANK bank) +{ + u32 result = 0; + u32 enable = MV_REG_READ (MV64360_BASE_ADDR_ENABLE); + + if (enable & (1 << bank)) + return 0; + if (bank == BANK0) + result = MV_REG_READ (MV64360_CS_0_SIZE); + if (bank == BANK1) + result = MV_REG_READ (MV64360_CS_1_SIZE); + if (bank == BANK2) + result = MV_REG_READ (MV64360_CS_2_SIZE); + if (bank == BANK3) + result = MV_REG_READ (MV64360_CS_3_SIZE); + result += 1; + result &= 0x0000ffff; + result = result << 16; + return result; +} + +u32 mv_get_internal_sram_base (void) +{ + u32 result; + + result = MV_REG_READ (MV64360_INTEGRATED_SRAM_BASE_ADDR); + result &= 0x0000ffff; + result = result << 16; + return result; +} + +/******************************************************************************* +* eth_port_init - Initialize the Ethernet port driver +* +* DESCRIPTION: +* This function prepares the ethernet port to start its activity: +* 1) Completes the ethernet port driver struct initialization toward port +* start routine. +* 2) Resets the device to a quiescent state in case of warm reboot. +* 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. +* 4) Clean MAC tables. The reset status of those tables is unknown. +* 5) Set PHY address. +* Note: Call this routine prior to eth_port_start routine and after setting +* user values in the user fields of Ethernet port control struct (i.e. +* port_phy_addr). +* +* INPUT: +* ETH_PORT_INFO *p_eth_port_ctrl Ethernet port control struct +* +* OUTPUT: +* See description. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void eth_port_init (ETH_PORT_INFO * p_eth_port_ctrl) +{ + int queue; + ETH_WIN_PARAM win_param; + + p_eth_port_ctrl->port_config = PORT_CONFIG_VALUE; + p_eth_port_ctrl->port_config_extend = PORT_CONFIG_EXTEND_VALUE; + p_eth_port_ctrl->port_sdma_config = PORT_SDMA_CONFIG_VALUE; + p_eth_port_ctrl->port_serial_control = PORT_SERIAL_CONTROL_VALUE; + + p_eth_port_ctrl->port_rx_queue_command = 0; + p_eth_port_ctrl->port_tx_queue_command = 0; + + /* Zero out SW structs */ + for (queue = 0; queue < MAX_RX_QUEUE_NUM; queue++) { + CURR_RFD_SET ((ETH_RX_DESC *) 0x00000000, queue); + USED_RFD_SET ((ETH_RX_DESC *) 0x00000000, queue); + p_eth_port_ctrl->rx_resource_err[queue] = false; + } + + for (queue = 0; queue < MAX_TX_QUEUE_NUM; queue++) { + CURR_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue); + USED_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue); + FIRST_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue); + p_eth_port_ctrl->tx_resource_err[queue] = false; + } + + eth_port_reset (p_eth_port_ctrl->port_num); + + /* Set access parameters for DRAM bank 0 */ + win_param.win = ETH_WIN0; /* Use Ethernet window 0 */ + win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */ + win_param.attributes = EBAR_ATTR_DRAM_CS0; /* Enable DRAM bank */ +#ifndef CONFIG_NOT_COHERENT_CACHE + win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB; +#endif + win_param.high_addr = 0; + /* Get bank base */ + win_param.base_addr = mv_get_dram_bank_base_addr (BANK0); + win_param.size = mv_get_dram_bank_size (BANK0); /* Get bank size */ + if (win_param.size == 0) + win_param.enable = 0; + else + win_param.enable = 1; /* Enable the access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */ + + /* Set the access control for address window (EPAPR) READ & WRITE */ + eth_set_access_control (p_eth_port_ctrl->port_num, &win_param); + + /* Set access parameters for DRAM bank 1 */ + win_param.win = ETH_WIN1; /* Use Ethernet window 1 */ + win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */ + win_param.attributes = EBAR_ATTR_DRAM_CS1; /* Enable DRAM bank */ +#ifndef CONFIG_NOT_COHERENT_CACHE + win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB; +#endif + win_param.high_addr = 0; + /* Get bank base */ + win_param.base_addr = mv_get_dram_bank_base_addr (BANK1); + win_param.size = mv_get_dram_bank_size (BANK1); /* Get bank size */ + if (win_param.size == 0) + win_param.enable = 0; + else + win_param.enable = 1; /* Enable the access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */ + + /* Set the access control for address window (EPAPR) READ & WRITE */ + eth_set_access_control (p_eth_port_ctrl->port_num, &win_param); + + /* Set access parameters for DRAM bank 2 */ + win_param.win = ETH_WIN2; /* Use Ethernet window 2 */ + win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */ + win_param.attributes = EBAR_ATTR_DRAM_CS2; /* Enable DRAM bank */ +#ifndef CONFIG_NOT_COHERENT_CACHE + win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB; +#endif + win_param.high_addr = 0; + /* Get bank base */ + win_param.base_addr = mv_get_dram_bank_base_addr (BANK2); + win_param.size = mv_get_dram_bank_size (BANK2); /* Get bank size */ + if (win_param.size == 0) + win_param.enable = 0; + else + win_param.enable = 1; /* Enable the access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */ + + /* Set the access control for address window (EPAPR) READ & WRITE */ + eth_set_access_control (p_eth_port_ctrl->port_num, &win_param); + + /* Set access parameters for DRAM bank 3 */ + win_param.win = ETH_WIN3; /* Use Ethernet window 3 */ + win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */ + win_param.attributes = EBAR_ATTR_DRAM_CS3; /* Enable DRAM bank */ +#ifndef CONFIG_NOT_COHERENT_CACHE + win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB; +#endif + win_param.high_addr = 0; + /* Get bank base */ + win_param.base_addr = mv_get_dram_bank_base_addr (BANK3); + win_param.size = mv_get_dram_bank_size (BANK3); /* Get bank size */ + if (win_param.size == 0) + win_param.enable = 0; + else + win_param.enable = 1; /* Enable the access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */ + + /* Set the access control for address window (EPAPR) READ & WRITE */ + eth_set_access_control (p_eth_port_ctrl->port_num, &win_param); + + /* Set access parameters for Internal SRAM */ + win_param.win = ETH_WIN4; /* Use Ethernet window 0 */ + win_param.target = EBAR_TARGET_CBS; /* Target - Internal SRAM */ + win_param.attributes = EBAR_ATTR_CBS_SRAM | EBAR_ATTR_CBS_SRAM_BLOCK0; + win_param.high_addr = 0; + win_param.base_addr = mv_get_internal_sram_base (); /* Get base addr */ + win_param.size = MV64360_INTERNAL_SRAM_SIZE; /* Get bank size */ + win_param.enable = 1; /* Enable the access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */ + + /* Set the access control for address window (EPAPR) READ & WRITE */ + eth_set_access_control (p_eth_port_ctrl->port_num, &win_param); + + eth_port_init_mac_tables (p_eth_port_ctrl->port_num); + + ethernet_phy_set (p_eth_port_ctrl->port_num, + p_eth_port_ctrl->port_phy_addr); + + return; + +} + +/******************************************************************************* +* eth_port_start - Start the Ethernet port activity. +* +* DESCRIPTION: +* This routine prepares the Ethernet port for Rx and Tx activity: +* 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that +* has been initialized a descriptor's ring (using ether_init_tx_desc_ring +* for Tx and ether_init_rx_desc_ring for Rx) +* 2. Initialize and enable the Ethernet configuration port by writing to +* the port's configuration and command registers. +* 3. Initialize and enable the SDMA by writing to the SDMA's +* configuration and command registers. +* After completing these steps, the ethernet port SDMA can starts to +* perform Rx and Tx activities. +* +* Note: Each Rx and Tx queue descriptor's list must be initialized prior +* to calling this function (use ether_init_tx_desc_ring for Tx queues and +* ether_init_rx_desc_ring for Rx queues). +* +* INPUT: +* ETH_PORT_INFO *p_eth_port_ctrl Ethernet port control struct +* +* OUTPUT: +* Ethernet port is ready to receive and transmit. +* +* RETURN: +* false if the port PHY is not up. +* true otherwise. +* +*******************************************************************************/ +static bool eth_port_start (ETH_PORT_INFO * p_eth_port_ctrl) +{ + int queue; + volatile ETH_TX_DESC *p_tx_curr_desc; + volatile ETH_RX_DESC *p_rx_curr_desc; + unsigned int phy_reg_data; + ETH_PORT eth_port_num = p_eth_port_ctrl->port_num; + + + /* Assignment of Tx CTRP of given queue */ + for (queue = 0; queue < MAX_TX_QUEUE_NUM; queue++) { + CURR_TFD_GET (p_tx_curr_desc, queue); + MV_REG_WRITE ((MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_0 + (eth_port_num) + + (4 * queue)), + ((unsigned int) p_tx_curr_desc)); + + } + + /* Assignment of Rx CRDP of given queue */ + for (queue = 0; queue < MAX_RX_QUEUE_NUM; queue++) { + CURR_RFD_GET (p_rx_curr_desc, queue); + MV_REG_WRITE ((MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_0 + (eth_port_num) + + (4 * queue)), + ((unsigned int) p_rx_curr_desc)); + + if (p_rx_curr_desc != NULL) + /* Add the assigned Ethernet address to the port's address table */ + eth_port_uc_addr_set (p_eth_port_ctrl->port_num, + p_eth_port_ctrl->port_mac_addr, + queue); + } + + /* Assign port configuration and command. */ + MV_REG_WRITE (MV64360_ETH_PORT_CONFIG_REG (eth_port_num), + p_eth_port_ctrl->port_config); + + MV_REG_WRITE (MV64360_ETH_PORT_CONFIG_EXTEND_REG (eth_port_num), + p_eth_port_ctrl->port_config_extend); + + MV_REG_WRITE (MV64360_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num), + p_eth_port_ctrl->port_serial_control); + + MV_SET_REG_BITS (MV64360_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num), + ETH_SERIAL_PORT_ENABLE); + + /* Assign port SDMA configuration */ + MV_REG_WRITE (MV64360_ETH_SDMA_CONFIG_REG (eth_port_num), + p_eth_port_ctrl->port_sdma_config); + + MV_REG_WRITE (MV64360_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT + (eth_port_num), 0x3fffffff); + MV_REG_WRITE (MV64360_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG + (eth_port_num), 0x03fffcff); + /* Turn off the port/queue bandwidth limitation */ + MV_REG_WRITE (MV64360_ETH_MAXIMUM_TRANSMIT_UNIT (eth_port_num), 0x0); + + /* Enable port Rx. */ + MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (eth_port_num), + p_eth_port_ctrl->port_rx_queue_command); + + /* Check if link is up */ + eth_port_read_smi_reg (eth_port_num, 1, &phy_reg_data); + + if (!(phy_reg_data & 0x20)) + return false; + + return true; +} + +/******************************************************************************* +* eth_port_uc_addr_set - This function Set the port Unicast address. +* +* DESCRIPTION: +* This function Set the port Ethernet MAC address. +* +* INPUT: +* ETH_PORT eth_port_num Port number. +* char * p_addr Address to be set +* ETH_QUEUE queue Rx queue number for this MAC address. +* +* OUTPUT: +* Set MAC address low and high registers. also calls eth_port_uc_addr() +* To set the unicast table with the proper information. +* +* RETURN: +* N/A. +* +*******************************************************************************/ +static void eth_port_uc_addr_set (ETH_PORT eth_port_num, + unsigned char *p_addr, ETH_QUEUE queue) +{ + unsigned int mac_h; + unsigned int mac_l; + + mac_l = (p_addr[4] << 8) | (p_addr[5]); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | + (p_addr[2] << 8) | (p_addr[3] << 0); + + MV_REG_WRITE (MV64360_ETH_MAC_ADDR_LOW (eth_port_num), mac_l); + MV_REG_WRITE (MV64360_ETH_MAC_ADDR_HIGH (eth_port_num), mac_h); + + /* Accept frames of this address */ + eth_port_uc_addr (eth_port_num, p_addr[5], queue, ACCEPT_MAC_ADDR); + + return; +} + +/******************************************************************************* +* eth_port_uc_addr - This function Set the port unicast address table +* +* DESCRIPTION: +* This function locates the proper entry in the Unicast table for the +* specified MAC nibble and sets its properties according to function +* parameters. +* +* INPUT: +* ETH_PORT eth_port_num Port number. +* unsigned char uc_nibble Unicast MAC Address last nibble. +* ETH_QUEUE queue Rx queue number for this MAC address. +* int option 0 = Add, 1 = remove address. +* +* OUTPUT: +* This function add/removes MAC addresses from the port unicast address +* table. +* +* RETURN: +* true is output succeeded. +* false if option parameter is invalid. +* +*******************************************************************************/ +static bool eth_port_uc_addr (ETH_PORT eth_port_num, + unsigned char uc_nibble, + ETH_QUEUE queue, int option) +{ + unsigned int unicast_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the Unicast table entry */ + uc_nibble = (0xf & uc_nibble); + tbl_offset = (uc_nibble / 4) * 4; /* Register offset from unicast table base */ + reg_offset = uc_nibble % 4; /* Entry offset within the above register */ + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified unicast DA table entry */ + unicast_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + + tbl_offset)); + + unicast_reg &= (0x0E << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + + tbl_offset), unicast_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at unicast DA filter table entry */ + unicast_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + + tbl_offset)); + + unicast_reg |= ((0x01 | queue) << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + + tbl_offset), unicast_reg); + + break; + + default: + return false; + } + return true; +} + +#if 0 /* FIXME */ +/******************************************************************************* +* eth_port_mc_addr - Multicast address settings. +* +* DESCRIPTION: +* This API controls the MV device MAC multicast support. +* The MV device supports multicast using two tables: +* 1) Special Multicast Table for MAC addresses of the form +* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0x_fF). +* The MAC DA[7:0] bits are used as a pointer to the Special Multicast +* Table entries in the DA-Filter table. +* In this case, the function calls eth_port_smc_addr() routine to set the +* Special Multicast Table. +* 2) Other Multicast Table for multicast of another type. A CRC-8bit +* is used as an index to the Other Multicast Table entries in the +* DA-Filter table. +* In this case, the function calculates the CRC-8bit value and calls +* eth_port_omc_addr() routine to set the Other Multicast Table. +* INPUT: +* ETH_PORT eth_port_num Port number. +* unsigned char *p_addr Unicast MAC Address. +* ETH_QUEUE queue Rx queue number for this MAC address. +* int option 0 = Add, 1 = remove address. +* +* OUTPUT: +* See description. +* +* RETURN: +* true is output succeeded. +* false if add_address_table_entry( ) failed. +* +*******************************************************************************/ +static void eth_port_mc_addr (ETH_PORT eth_port_num, + unsigned char *p_addr, + ETH_QUEUE queue, int option) +{ + unsigned int mac_h; + unsigned int mac_l; + unsigned char crc_result = 0; + int mac_array[48]; + int crc[8]; + int i; + + + if ((p_addr[0] == 0x01) && + (p_addr[1] == 0x00) && + (p_addr[2] == 0x5E) && (p_addr[3] == 0x00) && (p_addr[4] == 0x00)) + + eth_port_smc_addr (eth_port_num, p_addr[5], queue, option); + else { + /* Calculate CRC-8 out of the given address */ + mac_h = (p_addr[0] << 8) | (p_addr[1]); + mac_l = (p_addr[2] << 24) | (p_addr[3] << 16) | + (p_addr[4] << 8) | (p_addr[5] << 0); + + for (i = 0; i < 32; i++) + mac_array[i] = (mac_l >> i) & 0x1; + for (i = 32; i < 48; i++) + mac_array[i] = (mac_h >> (i - 32)) & 0x1; + + + crc[0] = mac_array[45] ^ mac_array[43] ^ mac_array[40] ^ + mac_array[39] ^ mac_array[35] ^ mac_array[34] ^ + mac_array[31] ^ mac_array[30] ^ mac_array[28] ^ + mac_array[23] ^ mac_array[21] ^ mac_array[19] ^ + mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ + mac_array[12] ^ mac_array[8] ^ mac_array[7] ^ + mac_array[6] ^ mac_array[0]; + + crc[1] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ + mac_array[43] ^ mac_array[41] ^ mac_array[39] ^ + mac_array[36] ^ mac_array[34] ^ mac_array[32] ^ + mac_array[30] ^ mac_array[29] ^ mac_array[28] ^ + mac_array[24] ^ mac_array[23] ^ mac_array[22] ^ + mac_array[21] ^ mac_array[20] ^ mac_array[18] ^ + mac_array[17] ^ mac_array[16] ^ mac_array[15] ^ + mac_array[14] ^ mac_array[13] ^ mac_array[12] ^ + mac_array[9] ^ mac_array[6] ^ mac_array[1] ^ + mac_array[0]; + + crc[2] = mac_array[47] ^ mac_array[46] ^ mac_array[44] ^ + mac_array[43] ^ mac_array[42] ^ mac_array[39] ^ + mac_array[37] ^ mac_array[34] ^ mac_array[33] ^ + mac_array[29] ^ mac_array[28] ^ mac_array[25] ^ + mac_array[24] ^ mac_array[22] ^ mac_array[17] ^ + mac_array[15] ^ mac_array[13] ^ mac_array[12] ^ + mac_array[10] ^ mac_array[8] ^ mac_array[6] ^ + mac_array[2] ^ mac_array[1] ^ mac_array[0]; + + crc[3] = mac_array[47] ^ mac_array[45] ^ mac_array[44] ^ + mac_array[43] ^ mac_array[40] ^ mac_array[38] ^ + mac_array[35] ^ mac_array[34] ^ mac_array[30] ^ + mac_array[29] ^ mac_array[26] ^ mac_array[25] ^ + mac_array[23] ^ mac_array[18] ^ mac_array[16] ^ + mac_array[14] ^ mac_array[13] ^ mac_array[11] ^ + mac_array[9] ^ mac_array[7] ^ mac_array[3] ^ + mac_array[2] ^ mac_array[1]; + + crc[4] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ + mac_array[41] ^ mac_array[39] ^ mac_array[36] ^ + mac_array[35] ^ mac_array[31] ^ mac_array[30] ^ + mac_array[27] ^ mac_array[26] ^ mac_array[24] ^ + mac_array[19] ^ mac_array[17] ^ mac_array[15] ^ + mac_array[14] ^ mac_array[12] ^ mac_array[10] ^ + mac_array[8] ^ mac_array[4] ^ mac_array[3] ^ + mac_array[2]; + + crc[5] = mac_array[47] ^ mac_array[46] ^ mac_array[45] ^ + mac_array[42] ^ mac_array[40] ^ mac_array[37] ^ + mac_array[36] ^ mac_array[32] ^ mac_array[31] ^ + mac_array[28] ^ mac_array[27] ^ mac_array[25] ^ + mac_array[20] ^ mac_array[18] ^ mac_array[16] ^ + mac_array[15] ^ mac_array[13] ^ mac_array[11] ^ + mac_array[9] ^ mac_array[5] ^ mac_array[4] ^ + mac_array[3]; + + crc[6] = mac_array[47] ^ mac_array[46] ^ mac_array[43] ^ + mac_array[41] ^ mac_array[38] ^ mac_array[37] ^ + mac_array[33] ^ mac_array[32] ^ mac_array[29] ^ + mac_array[28] ^ mac_array[26] ^ mac_array[21] ^ + mac_array[19] ^ mac_array[17] ^ mac_array[16] ^ + mac_array[14] ^ mac_array[12] ^ mac_array[10] ^ + mac_array[6] ^ mac_array[5] ^ mac_array[4]; + + crc[7] = mac_array[47] ^ mac_array[44] ^ mac_array[42] ^ + mac_array[39] ^ mac_array[38] ^ mac_array[34] ^ + mac_array[33] ^ mac_array[30] ^ mac_array[29] ^ + mac_array[27] ^ mac_array[22] ^ mac_array[20] ^ + mac_array[18] ^ mac_array[17] ^ mac_array[15] ^ + mac_array[13] ^ mac_array[11] ^ mac_array[7] ^ + mac_array[6] ^ mac_array[5]; + + for (i = 0; i < 8; i++) + crc_result = crc_result | (crc[i] << i); + + eth_port_omc_addr (eth_port_num, crc_result, queue, option); + } + return; +} + +/******************************************************************************* +* eth_port_smc_addr - Special Multicast address settings. +* +* DESCRIPTION: +* This routine controls the MV device special MAC multicast support. +* The Special Multicast Table for MAC addresses supports MAC of the form +* 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0x_fF). +* The MAC DA[7:0] bits are used as a pointer to the Special Multicast +* Table entries in the DA-Filter table. +* This function set the Special Multicast Table appropriate entry +* according to the argument given. +* +* INPUT: +* ETH_PORT eth_port_num Port number. +* unsigned char mc_byte Multicast addr last byte (MAC DA[7:0] bits). +* ETH_QUEUE queue Rx queue number for this MAC address. +* int option 0 = Add, 1 = remove address. +* +* OUTPUT: +* See description. +* +* RETURN: +* true is output succeeded. +* false if option parameter is invalid. +* +*******************************************************************************/ +static bool eth_port_smc_addr (ETH_PORT eth_port_num, + unsigned char mc_byte, + ETH_QUEUE queue, int option) +{ + unsigned int smc_table_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the SMC table entry */ + tbl_offset = (mc_byte / 4) * 4; /* Register offset from SMC table base */ + reg_offset = mc_byte % 4; /* Entry offset within the above register */ + queue &= 0x7; + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified Special DA table entry */ + smc_table_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset)); + smc_table_reg &= (0x0E << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset), smc_table_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at specified Special DA table entry */ + smc_table_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset)); + smc_table_reg |= ((0x01 | queue) << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset), smc_table_reg); + break; + + default: + return false; + } + return true; +} + +/******************************************************************************* +* eth_port_omc_addr - Multicast address settings. +* +* DESCRIPTION: +* This routine controls the MV device Other MAC multicast support. +* The Other Multicast Table is used for multicast of another type. +* A CRC-8bit is used as an index to the Other Multicast Table entries +* in the DA-Filter table. +* The function gets the CRC-8bit value from the calling routine and +* set the Other Multicast Table appropriate entry according to the +* CRC-8 argument given. +* +* INPUT: +* ETH_PORT eth_port_num Port number. +* unsigned char crc8 A CRC-8bit (Polynomial: x^8+x^2+x^1+1). +* ETH_QUEUE queue Rx queue number for this MAC address. +* int option 0 = Add, 1 = remove address. +* +* OUTPUT: +* See description. +* +* RETURN: +* true is output succeeded. +* false if option parameter is invalid. +* +*******************************************************************************/ +static bool eth_port_omc_addr (ETH_PORT eth_port_num, + unsigned char crc8, + ETH_QUEUE queue, int option) +{ + unsigned int omc_table_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the OMC table entry */ + tbl_offset = (crc8 / 4) * 4; /* Register offset from OMC table base */ + reg_offset = crc8 % 4; /* Entry offset within the above register */ + queue &= 0x7; + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified Other DA table entry */ + omc_table_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset)); + omc_table_reg &= (0x0E << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset), omc_table_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at specified Other DA table entry */ + omc_table_reg = + MV_REG_READ ((MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset)); + omc_table_reg |= ((0x01 | queue) << (8 * reg_offset)); + + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE (eth_port_num) + tbl_offset), omc_table_reg); + break; + + default: + return false; + } + return true; +} +#endif + +/******************************************************************************* +* eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables +* +* DESCRIPTION: +* Go through all the DA filter tables (Unicast, Special Multicast & Other +* Multicast) and set each entry to 0. +* +* INPUT: +* ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. +* +* OUTPUT: +* Multicast and Unicast packets are rejected. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void eth_port_init_mac_tables (ETH_PORT eth_port_num) +{ + int table_index; + + /* Clear DA filter unicast table (Ex_dFUT) */ + for (table_index = 0; table_index <= 0xC; table_index += 4) + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE (eth_port_num) + table_index), 0); + /* Clear DA filter other multicast table (Ex_dFOMT) */ + MV_REG_WRITE ((MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE (eth_port_num) + table_index), 0); + } +} + +/******************************************************************************* +* eth_clear_mib_counters - Clear all MIB counters +* +* DESCRIPTION: +* This function clears all MIB counters of a specific ethernet port. +* A read from the MIB counter will reset the counter. +* +* INPUT: +* ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. +* +* OUTPUT: +* After reading all MIB counters, the counters resets. +* +* RETURN: +* MIB counter value. +* +*******************************************************************************/ +static void eth_clear_mib_counters (ETH_PORT eth_port_num) +{ + int i; + unsigned int dummy; + + /* Perform dummy reads from MIB counters */ + for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; + i += 4) + dummy = MV_REG_READ ((MV64360_ETH_MIB_COUNTERS_BASE + (eth_port_num) + i)); + + return; +} + +/******************************************************************************* +* eth_read_mib_counter - Read a MIB counter +* +* DESCRIPTION: +* This function reads a MIB counter of a specific ethernet port. +* NOTE - If read from ETH_MIB_GOOD_OCTETS_RECEIVED_LOW, then the +* following read must be from ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH +* register. The same applies for ETH_MIB_GOOD_OCTETS_SENT_LOW and +* ETH_MIB_GOOD_OCTETS_SENT_HIGH +* +* INPUT: +* ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. +* unsigned int mib_offset MIB counter offset (use ETH_MIB_... macros). +* +* OUTPUT: +* After reading the MIB counter, the counter resets. +* +* RETURN: +* MIB counter value. +* +*******************************************************************************/ +unsigned int eth_read_mib_counter (ETH_PORT eth_port_num, + unsigned int mib_offset) +{ + return (MV_REG_READ (MV64360_ETH_MIB_COUNTERS_BASE (eth_port_num) + + mib_offset)); +} + +/******************************************************************************* +* ethernet_phy_set - Set the ethernet port PHY address. +* +* DESCRIPTION: +* This routine set the ethernet port PHY address according to given +* parameter. +* +* INPUT: +* ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. +* +* OUTPUT: +* Set PHY Address Register with given PHY address parameter. +* +* RETURN: +* None. +* +*******************************************************************************/ +static void ethernet_phy_set (ETH_PORT eth_port_num, int phy_addr) +{ + unsigned int reg_data; + + reg_data = MV_REG_READ (MV64360_ETH_PHY_ADDR_REG); + + reg_data &= ~(0x1F << (5 * eth_port_num)); + reg_data |= (phy_addr << (5 * eth_port_num)); + + MV_REG_WRITE (MV64360_ETH_PHY_ADDR_REG, reg_data); + + return; +} + +/******************************************************************************* + * ethernet_phy_get - Get the ethernet port PHY address. + * + * DESCRIPTION: + * This routine returns the given ethernet port PHY address. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * + * OUTPUT: + * None. + * + * RETURN: + * PHY address. + * + *******************************************************************************/ +static int ethernet_phy_get (ETH_PORT eth_port_num) +{ + unsigned int reg_data; + + reg_data = MV_REG_READ (MV64360_ETH_PHY_ADDR_REG); + + return ((reg_data >> (5 * eth_port_num)) & 0x1f); +} + +/******************************************************************************* + * ethernet_phy_reset - Reset Ethernet port PHY. + * + * DESCRIPTION: + * This routine utilize the SMI interface to reset the ethernet port PHY. + * The routine waits until the link is up again or link up is timeout. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * + * OUTPUT: + * The ethernet port PHY renew its link. + * + * RETURN: + * None. + * +*******************************************************************************/ +static bool ethernet_phy_reset (ETH_PORT eth_port_num) +{ + unsigned int time_out = 50; + unsigned int phy_reg_data; + + /* Reset the PHY */ + eth_port_read_smi_reg (eth_port_num, 0, &phy_reg_data); + phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ + eth_port_write_smi_reg (eth_port_num, 0, phy_reg_data); + + /* Poll on the PHY LINK */ + do { + eth_port_read_smi_reg (eth_port_num, 1, &phy_reg_data); + + if (time_out-- == 0) + return false; + } + while (!(phy_reg_data & 0x20)); + + return true; +} + +/******************************************************************************* + * eth_port_reset - Reset Ethernet port + * + * DESCRIPTION: + * This routine resets the chip by aborting any SDMA engine activity and + * clearing the MIB counters. The Receiver and the Transmit unit are in + * idle state after this command is performed and the port is disabled. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * + * OUTPUT: + * Channel activity is halted. + * + * RETURN: + * None. + * + *******************************************************************************/ +static void eth_port_reset (ETH_PORT eth_port_num) +{ + unsigned int reg_data; + + /* Stop Tx port activity. Check port Tx activity. */ + reg_data = + MV_REG_READ (MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_REG_WRITE (MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Tx activity to terminate. */ + do { + /* Check port cause register that all Tx queues are stopped */ + reg_data = + MV_REG_READ + (MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + /* Stop Rx port activity. Check port Rx activity. */ + reg_data = + MV_REG_READ (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Rx activity to terminate. */ + do { + /* Check port cause register that all Rx queues are stopped */ + reg_data = + MV_REG_READ + (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + + /* Clear all MIB counters */ + eth_clear_mib_counters (eth_port_num); + + /* Reset the Enable bit in the Configuration Register */ + reg_data = + MV_REG_READ (MV64360_ETH_PORT_SERIAL_CONTROL_REG + (eth_port_num)); + reg_data &= ~ETH_SERIAL_PORT_ENABLE; + MV_REG_WRITE (MV64360_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num), + reg_data); + + return; +} + +#if 0 /* Not needed here */ +/******************************************************************************* + * ethernet_set_config_reg - Set specified bits in configuration register. + * + * DESCRIPTION: + * This function sets specified bits in the given ethernet + * configuration register. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * unsigned int value 32 bit value. + * + * OUTPUT: + * The set bits in the value parameter are set in the configuration + * register. + * + * RETURN: + * None. + * + *******************************************************************************/ +static void ethernet_set_config_reg (ETH_PORT eth_port_num, + unsigned int value) +{ + unsigned int eth_config_reg; + + eth_config_reg = + MV_REG_READ (MV64360_ETH_PORT_CONFIG_REG (eth_port_num)); + eth_config_reg |= value; + MV_REG_WRITE (MV64360_ETH_PORT_CONFIG_REG (eth_port_num), + eth_config_reg); + + return; +} +#endif + +#if 0 /* FIXME */ +/******************************************************************************* + * ethernet_reset_config_reg - Reset specified bits in configuration register. + * + * DESCRIPTION: + * This function resets specified bits in the given Ethernet + * configuration register. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * unsigned int value 32 bit value. + * + * OUTPUT: + * The set bits in the value parameter are reset in the configuration + * register. + * + * RETURN: + * None. + * + *******************************************************************************/ +static void ethernet_reset_config_reg (ETH_PORT eth_port_num, + unsigned int value) +{ + unsigned int eth_config_reg; + + eth_config_reg = MV_REG_READ (MV64360_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); + eth_config_reg &= ~value; + MV_REG_WRITE (MV64360_ETH_PORT_CONFIG_EXTEND_REG (eth_port_num), + eth_config_reg); + + return; +} +#endif + +#if 0 /* Not needed here */ +/******************************************************************************* + * ethernet_get_config_reg - Get the port configuration register + * + * DESCRIPTION: + * This function returns the configuration register value of the given + * ethernet port. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * + * OUTPUT: + * None. + * + * RETURN: + * Port configuration register value. + * + *******************************************************************************/ +static unsigned int ethernet_get_config_reg (ETH_PORT eth_port_num) +{ + unsigned int eth_config_reg; + + eth_config_reg = MV_REG_READ (MV64360_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); + return eth_config_reg; +} + +#endif + +/******************************************************************************* + * eth_port_read_smi_reg - Read PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform PHY register read. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * unsigned int phy_reg PHY register address offset. + * unsigned int *value Register value buffer. + * + * OUTPUT: + * Write the value of a specified PHY register into given buffer. + * + * RETURN: + * false if the PHY is busy or read data is not in valid state. + * true otherwise. + * + *******************************************************************************/ +static bool eth_port_read_smi_reg (ETH_PORT eth_port_num, + unsigned int phy_reg, unsigned int *value) +{ + unsigned int reg_value; + unsigned int time_out = PHY_BUSY_TIMEOUT; + int phy_addr; + + phy_addr = ethernet_phy_get (eth_port_num); +/* printf(" Phy-Port %d has addess %d \n",eth_port_num, phy_addr );*/ + + /* first check that it is not busy */ + do { + reg_value = MV_REG_READ (MV64360_ETH_SMI_REG); + if (time_out-- == 0) { + return false; + } + } + while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + + MV_REG_WRITE (MV64360_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_READ); + + time_out = PHY_BUSY_TIMEOUT; /* initialize the time out var again */ + + do { + reg_value = MV_REG_READ (MV64360_ETH_SMI_REG); + if (time_out-- == 0) { + return false; + } + } + while ((reg_value & ETH_SMI_READ_VALID) != ETH_SMI_READ_VALID); /* Bit set equ operation done */ + + /* Wait for the data to update in the SMI register */ +#define PHY_UPDATE_TIMEOUT 10000 + for (time_out = 0; time_out < PHY_UPDATE_TIMEOUT; time_out++); + + reg_value = MV_REG_READ (MV64360_ETH_SMI_REG); + + *value = reg_value & 0xffff; + + return true; +} + +/******************************************************************************* + * eth_port_write_smi_reg - Write to PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform writes to PHY registers. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * unsigned int phy_reg PHY register address offset. + * unsigned int value Register value. + * + * OUTPUT: + * Write the given value to the specified PHY register. + * + * RETURN: + * false if the PHY is busy. + * true otherwise. + * + *******************************************************************************/ +static bool eth_port_write_smi_reg (ETH_PORT eth_port_num, + unsigned int phy_reg, unsigned int value) +{ + unsigned int reg_value; + unsigned int time_out = PHY_BUSY_TIMEOUT; + int phy_addr; + + phy_addr = ethernet_phy_get (eth_port_num); + + /* first check that it is not busy */ + do { + reg_value = MV_REG_READ (MV64360_ETH_SMI_REG); + if (time_out-- == 0) { + return false; + } + } + while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + MV_REG_WRITE (MV64360_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_WRITE | (value & 0xffff)); + return true; +} + +/******************************************************************************* + * eth_set_access_control - Config address decode parameters for Ethernet unit + * + * DESCRIPTION: + * This function configures the address decode parameters for the Gigabit + * Ethernet Controller according the given parameters struct. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet Port number. See ETH_PORT enum. + * ETH_WIN_PARAM *param Address decode parameter struct. + * + * OUTPUT: + * An access window is opened using the given access parameters. + * + * RETURN: + * None. + * + *******************************************************************************/ +static void eth_set_access_control (ETH_PORT eth_port_num, + ETH_WIN_PARAM * param) +{ + unsigned int access_prot_reg; + + /* Set access control register */ + access_prot_reg = MV_REG_READ (MV64360_ETH_ACCESS_PROTECTION_REG + (eth_port_num)); + access_prot_reg &= (~(3 << (param->win * 2))); /* clear window permission */ + access_prot_reg |= (param->access_ctrl << (param->win * 2)); + MV_REG_WRITE (MV64360_ETH_ACCESS_PROTECTION_REG (eth_port_num), + access_prot_reg); + + /* Set window Size reg (SR) */ + MV_REG_WRITE ((MV64360_ETH_SIZE_REG_0 + + (ETH_SIZE_REG_GAP * param->win)), + (((param->size / 0x10000) - 1) << 16)); + + /* Set window Base address reg (BA) */ + MV_REG_WRITE ((MV64360_ETH_BAR_0 + (ETH_BAR_GAP * param->win)), + (param->target | param->attributes | param->base_addr)); + /* High address remap reg (HARR) */ + if (param->win < 4) + MV_REG_WRITE ((MV64360_ETH_HIGH_ADDR_REMAP_REG_0 + + (ETH_HIGH_ADDR_REMAP_REG_GAP * param->win)), + param->high_addr); + + /* Base address enable reg (BARER) */ + if (param->enable == 1) + MV_RESET_REG_BITS (MV64360_ETH_BASE_ADDR_ENABLE_REG, + (1 << param->win)); + else + MV_SET_REG_BITS (MV64360_ETH_BASE_ADDR_ENABLE_REG, + (1 << param->win)); +} + +/******************************************************************************* + * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Rx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE rx_queue Number of Rx queue. + * int rx_desc_num Number of Rx descriptors + * int rx_buff_size Size of Rx buffer + * unsigned int rx_desc_base_addr Rx descriptors memory area base addr. + * unsigned int rx_buff_base_addr Rx buffer memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Rx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + * + *******************************************************************************/ +static bool ether_init_rx_desc_ring (ETH_PORT_INFO * p_eth_port_ctrl, + ETH_QUEUE rx_queue, + int rx_desc_num, + int rx_buff_size, + unsigned int rx_desc_base_addr, + unsigned int rx_buff_base_addr) +{ + ETH_RX_DESC *p_rx_desc; + ETH_RX_DESC *p_rx_prev_desc; /* pointer to link with the last descriptor */ + unsigned int buffer_addr; + int ix; /* a counter */ + + + p_rx_desc = (ETH_RX_DESC *) rx_desc_base_addr; + p_rx_prev_desc = p_rx_desc; + buffer_addr = rx_buff_base_addr; + + /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (rx_buff_base_addr & 0xF) + return false; + + /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes */ + if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE)) + return false; + + /* Rx buffers must be 64-bit aligned. */ + if ((rx_buff_base_addr + rx_buff_size) & 0x7) + return false; + + /* initialize the Rx descriptors ring */ + for (ix = 0; ix < rx_desc_num; ix++) { + p_rx_desc->buf_size = rx_buff_size; + p_rx_desc->byte_cnt = 0x0000; + p_rx_desc->cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + p_rx_desc->next_desc_ptr = + ((unsigned int) p_rx_desc) + RX_DESC_ALIGNED_SIZE; + p_rx_desc->buf_ptr = buffer_addr; + p_rx_desc->return_info = 0x00000000; + D_CACHE_FLUSH_LINE (p_rx_desc, 0); + buffer_addr += rx_buff_size; + p_rx_prev_desc = p_rx_desc; + p_rx_desc = (ETH_RX_DESC *) + ((unsigned int) p_rx_desc + RX_DESC_ALIGNED_SIZE); + } + + /* Closing Rx descriptors ring */ + p_rx_prev_desc->next_desc_ptr = (rx_desc_base_addr); + D_CACHE_FLUSH_LINE (p_rx_prev_desc, 0); + + /* Save Rx desc pointer to driver struct. */ + CURR_RFD_SET ((ETH_RX_DESC *) rx_desc_base_addr, rx_queue); + USED_RFD_SET ((ETH_RX_DESC *) rx_desc_base_addr, rx_queue); + + p_eth_port_ctrl->p_rx_desc_area_base[rx_queue] = + (ETH_RX_DESC *) rx_desc_base_addr; + p_eth_port_ctrl->rx_desc_area_size[rx_queue] = + rx_desc_num * RX_DESC_ALIGNED_SIZE; + + p_eth_port_ctrl->port_rx_queue_command |= (1 << rx_queue); + + return true; +} + +/******************************************************************************* + * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Tx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE tx_queue Number of Tx queue. + * int tx_desc_num Number of Tx descriptors + * int tx_buff_size Size of Tx buffer + * unsigned int tx_desc_base_addr Tx descriptors memory area base addr. + * unsigned int tx_buff_base_addr Tx buffer memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Tx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + * + *******************************************************************************/ +static bool ether_init_tx_desc_ring (ETH_PORT_INFO * p_eth_port_ctrl, + ETH_QUEUE tx_queue, + int tx_desc_num, + int tx_buff_size, + unsigned int tx_desc_base_addr, + unsigned int tx_buff_base_addr) +{ + + ETH_TX_DESC *p_tx_desc; + ETH_TX_DESC *p_tx_prev_desc; + unsigned int buffer_addr; + int ix; /* a counter */ + + + /* save the first desc pointer to link with the last descriptor */ + p_tx_desc = (ETH_TX_DESC *) tx_desc_base_addr; + p_tx_prev_desc = p_tx_desc; + buffer_addr = tx_buff_base_addr; + + /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (tx_buff_base_addr & 0xF) + return false; + + /* Tx buffers are limited to 64K bytes and Minimum size is 8 bytes */ + if ((tx_buff_size > TX_BUFFER_MAX_SIZE) + || (tx_buff_size < TX_BUFFER_MIN_SIZE)) + return false; + + /* Initialize the Tx descriptors ring */ + for (ix = 0; ix < tx_desc_num; ix++) { + p_tx_desc->byte_cnt = 0x0000; + p_tx_desc->l4i_chk = 0x0000; + p_tx_desc->cmd_sts = 0x00000000; + p_tx_desc->next_desc_ptr = + ((unsigned int) p_tx_desc) + TX_DESC_ALIGNED_SIZE; + + p_tx_desc->buf_ptr = buffer_addr; + p_tx_desc->return_info = 0x00000000; + D_CACHE_FLUSH_LINE (p_tx_desc, 0); + buffer_addr += tx_buff_size; + p_tx_prev_desc = p_tx_desc; + p_tx_desc = (ETH_TX_DESC *) + ((unsigned int) p_tx_desc + TX_DESC_ALIGNED_SIZE); + + } + /* Closing Tx descriptors ring */ + p_tx_prev_desc->next_desc_ptr = tx_desc_base_addr; + D_CACHE_FLUSH_LINE (p_tx_prev_desc, 0); + /* Set Tx desc pointer in driver struct. */ + CURR_TFD_SET ((ETH_TX_DESC *) tx_desc_base_addr, tx_queue); + USED_TFD_SET ((ETH_TX_DESC *) tx_desc_base_addr, tx_queue); + + /* Init Tx ring base and size parameters */ + p_eth_port_ctrl->p_tx_desc_area_base[tx_queue] = + (ETH_TX_DESC *) tx_desc_base_addr; + p_eth_port_ctrl->tx_desc_area_size[tx_queue] = + (tx_desc_num * TX_DESC_ALIGNED_SIZE); + + /* Add the queue to the list of Tx queues of this port */ + p_eth_port_ctrl->port_tx_queue_command |= (1 << tx_queue); + + return true; +} + +/******************************************************************************* + * eth_port_send - Send an Ethernet packet + * + * DESCRIPTION: + * This routine send a given packet described by p_pktinfo parameter. It + * supports transmitting of a packet spaned over multiple buffers. The + * routine updates 'curr' and 'first' indexes according to the packet + * segment passed to the routine. In case the packet segment is first, + * the 'first' index is update. In any case, the 'curr' index is updated. + * If the routine get into Tx resource error it assigns 'curr' index as + * 'first'. This way the function can abort Tx process of multiple + * descriptors per packet. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE tx_queue Number of Tx queue. + * PKT_INFO *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'curr' and 'first' indexes are updated. + * + * RETURN: + * ETH_QUEUE_FULL in case of Tx resource error. + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. + * ETH_OK otherwise. + * + *******************************************************************************/ +static ETH_FUNC_RET_STATUS eth_port_send (ETH_PORT_INFO * p_eth_port_ctrl, + ETH_QUEUE tx_queue, + PKT_INFO * p_pkt_info) +{ + volatile ETH_TX_DESC *p_tx_desc_first; + volatile ETH_TX_DESC *p_tx_desc_curr; + volatile ETH_TX_DESC *p_tx_next_desc_curr; + volatile ETH_TX_DESC *p_tx_desc_used; + unsigned int command_status; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (p_eth_port_ctrl->tx_resource_err[tx_queue] == true) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + CURR_TFD_GET (p_tx_desc_curr, tx_queue); + USED_TFD_GET (p_tx_desc_used, tx_queue); + + if (p_tx_desc_curr == NULL) + return ETH_ERROR; + + /* The following parameters are used to save readings from memory */ + p_tx_next_desc_curr = TX_NEXT_DESC_PTR (p_tx_desc_curr, tx_queue); + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + + if (command_status & (ETH_TX_FIRST_DESC)) { + /* Update first desc */ + FIRST_TFD_SET (p_tx_desc_curr, tx_queue); + p_tx_desc_first = p_tx_desc_curr; + } else { + FIRST_TFD_GET (p_tx_desc_first, tx_queue); + command_status |= ETH_BUFFER_OWNED_BY_DMA; + } + + /* Buffers with a payload smaller than 8 bytes must be aligned to 64-bit */ + /* boundary. We use the memory allocated for Tx descriptor. This memory */ + /* located in TX_BUF_OFFSET_IN_DESC offset within the Tx descriptor. */ + if (p_pkt_info->byte_cnt <= 8) { + printf ("You have failed in the < 8 bytes errata - fixme\n"); /* RABEEH - TBD */ + return ETH_ERROR; + + p_tx_desc_curr->buf_ptr = + (unsigned int) p_tx_desc_curr + TX_BUF_OFFSET_IN_DESC; + eth_b_copy (p_pkt_info->buf_ptr, p_tx_desc_curr->buf_ptr, + p_pkt_info->byte_cnt); + } else + p_tx_desc_curr->buf_ptr = p_pkt_info->buf_ptr; + + p_tx_desc_curr->byte_cnt = p_pkt_info->byte_cnt; + p_tx_desc_curr->return_info = p_pkt_info->return_info; + + if (p_pkt_info->cmd_sts & (ETH_TX_LAST_DESC)) { + /* Set last desc with DMA ownership and interrupt enable. */ + p_tx_desc_curr->cmd_sts = command_status | + ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; + + if (p_tx_desc_curr != p_tx_desc_first) + p_tx_desc_first->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA; + + /* Flush CPU pipe */ + + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_curr, 0); + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_first, 0); + CPU_PIPE_FLUSH; + + /* Apply send command */ + ETH_ENABLE_TX_QUEUE (tx_queue, p_eth_port_ctrl->port_num); + + /* Finish Tx packet. Update first desc in case of Tx resource error */ + p_tx_desc_first = p_tx_next_desc_curr; + FIRST_TFD_SET (p_tx_desc_first, tx_queue); + + } else { + p_tx_desc_curr->cmd_sts = command_status; + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_curr, 0); + } + + /* Check for ring index overlap in the Tx desc ring */ + if (p_tx_next_desc_curr == p_tx_desc_used) { + /* Update the current descriptor */ + CURR_TFD_SET (p_tx_desc_first, tx_queue); + + p_eth_port_ctrl->tx_resource_err[tx_queue] = true; + return ETH_QUEUE_LAST_RESOURCE; + } else { + /* Update the current descriptor */ + CURR_TFD_SET (p_tx_next_desc_curr, tx_queue); + return ETH_OK; + } +} + +/******************************************************************************* + * eth_tx_return_desc - Free all used Tx descriptors + * + * DESCRIPTION: + * This routine returns the transmitted packet information to the caller. + * It uses the 'first' index to support Tx desc return in case a transmit + * of a packet spanned over multiple buffer still in process. + * In case the Tx queue was in "resource error" condition, where there are + * no available Tx resources, the function resets the resource error flag. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE tx_queue Number of Tx queue. + * PKT_INFO *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'first' and 'used' indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_RETRY in case there is transmission in process. + * ETH_END_OF_JOB if the routine has nothing to release. + * ETH_OK otherwise. + * + *******************************************************************************/ +static ETH_FUNC_RET_STATUS eth_tx_return_desc (ETH_PORT_INFO * + p_eth_port_ctrl, + ETH_QUEUE tx_queue, + PKT_INFO * p_pkt_info) +{ + volatile ETH_TX_DESC *p_tx_desc_used = NULL; + volatile ETH_TX_DESC *p_tx_desc_first = NULL; + unsigned int command_status; + + + /* Get the Tx Desc ring indexes */ + USED_TFD_GET (p_tx_desc_used, tx_queue); + FIRST_TFD_GET (p_tx_desc_first, tx_queue); + + + /* Sanity check */ + if (p_tx_desc_used == NULL) + return ETH_ERROR; + + command_status = p_tx_desc_used->cmd_sts; + + /* Still transmitting... */ + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_used, 0); + return ETH_RETRY; + } + + /* Stop release. About to overlap the current available Tx descriptor */ + if ((p_tx_desc_used == p_tx_desc_first) && + (p_eth_port_ctrl->tx_resource_err[tx_queue] == false)) { + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_used, 0); + return ETH_END_OF_JOB; + } + + /* Pass the packet information to the caller */ + p_pkt_info->cmd_sts = command_status; + p_pkt_info->return_info = p_tx_desc_used->return_info; + p_tx_desc_used->return_info = 0; + + /* Update the next descriptor to release. */ + USED_TFD_SET (TX_NEXT_DESC_PTR (p_tx_desc_used, tx_queue), tx_queue); + + /* Any Tx return cancels the Tx resource error status */ + if (p_eth_port_ctrl->tx_resource_err[tx_queue] == true) + p_eth_port_ctrl->tx_resource_err[tx_queue] = false; + + D_CACHE_FLUSH_LINE ((unsigned int) p_tx_desc_used, 0); + + return ETH_OK; + +} + +/******************************************************************************* + * eth_port_receive - Get received information from Rx ring. + * + * DESCRIPTION: + * This routine returns the received data to the caller. There is no + * data copying during routine operation. All information is returned + * using pointer to packet information struct passed from the caller. + * If the routine exhausts Rx ring resources then the resource error flag + * is set. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE rx_queue Number of Rx queue. + * PKT_INFO *p_pkt_info User packet buffer. + * + * OUTPUT: + * Rx ring current and used indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_QUEUE_FULL if Rx ring resources are exhausted. + * ETH_END_OF_JOB if there is no received data. + * ETH_OK otherwise. + * + *******************************************************************************/ +static ETH_FUNC_RET_STATUS eth_port_receive (ETH_PORT_INFO * p_eth_port_ctrl, + ETH_QUEUE rx_queue, + PKT_INFO * p_pkt_info) +{ + volatile ETH_RX_DESC *p_rx_curr_desc; + volatile ETH_RX_DESC *p_rx_next_curr_desc; + volatile ETH_RX_DESC *p_rx_used_desc; + unsigned int command_status; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (p_eth_port_ctrl->rx_resource_err[rx_queue] == true) { + printf ("\nRx Queue is full ...\n"); + return ETH_QUEUE_FULL; + } + + /* Get the Rx Desc ring 'curr and 'used' indexes */ + CURR_RFD_GET (p_rx_curr_desc, rx_queue); + USED_RFD_GET (p_rx_used_desc, rx_queue); + + /* Sanity check */ + if (p_rx_curr_desc == NULL) + return ETH_ERROR; + + /* The following parameters are used to save readings from memory */ + p_rx_next_curr_desc = RX_NEXT_DESC_PTR (p_rx_curr_desc, rx_queue); + command_status = p_rx_curr_desc->cmd_sts; + + /* Nothing to receive... */ + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { +/* DP(printf("Rx: command_status: %08x\n", command_status)); */ + D_CACHE_FLUSH_LINE ((unsigned int) p_rx_curr_desc, 0); +/* DP(printf("\nETH_END_OF_JOB ...\n"));*/ + return ETH_END_OF_JOB; + } + + p_pkt_info->byte_cnt = (p_rx_curr_desc->byte_cnt) - RX_BUF_OFFSET; + p_pkt_info->cmd_sts = command_status; + p_pkt_info->buf_ptr = (p_rx_curr_desc->buf_ptr) + RX_BUF_OFFSET; + p_pkt_info->return_info = p_rx_curr_desc->return_info; + p_pkt_info->l4i_chk = p_rx_curr_desc->buf_size; /* IP fragment indicator */ + + /* Clean the return info field to indicate that the packet has been */ + /* moved to the upper layers */ + p_rx_curr_desc->return_info = 0; + + /* Update 'curr' in data structure */ + CURR_RFD_SET (p_rx_next_curr_desc, rx_queue); + + /* Rx descriptors resource exhausted. Set the Rx ring resource error flag */ + if (p_rx_next_curr_desc == p_rx_used_desc) + p_eth_port_ctrl->rx_resource_err[rx_queue] = true; + + D_CACHE_FLUSH_LINE ((unsigned int) p_rx_curr_desc, 0); + CPU_PIPE_FLUSH; + return ETH_OK; +} + +/******************************************************************************* + * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. + * + * DESCRIPTION: + * This routine returns a Rx buffer back to the Rx ring. It retrieves the + * next 'used' descriptor and attached the returned buffer to it. + * In case the Rx ring was in "resource error" condition, where there are + * no available Rx resources, the function resets the resource error flag. + * + * INPUT: + * ETH_PORT_INFO *p_eth_port_ctrl Ethernet Port Control srtuct. + * ETH_QUEUE rx_queue Number of Rx queue. + * PKT_INFO *p_pkt_info Information on the returned buffer. + * + * OUTPUT: + * New available Rx resource in Rx descriptor ring. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_OK otherwise. + * + *******************************************************************************/ +static ETH_FUNC_RET_STATUS eth_rx_return_buff (ETH_PORT_INFO * + p_eth_port_ctrl, + ETH_QUEUE rx_queue, + PKT_INFO * p_pkt_info) +{ + volatile ETH_RX_DESC *p_used_rx_desc; /* Where to return Rx resource */ + + /* Get 'used' Rx descriptor */ + USED_RFD_GET (p_used_rx_desc, rx_queue); + + /* Sanity check */ + if (p_used_rx_desc == NULL) + return ETH_ERROR; + + p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr; + p_used_rx_desc->return_info = p_pkt_info->return_info; + p_used_rx_desc->byte_cnt = p_pkt_info->byte_cnt; + p_used_rx_desc->buf_size = MV64360_RX_BUFFER_SIZE; /* Reset Buffer size */ + + /* Flush the write pipe */ + CPU_PIPE_FLUSH; + + /* Return the descriptor to DMA ownership */ + p_used_rx_desc->cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + + /* Flush descriptor and CPU pipe */ + D_CACHE_FLUSH_LINE ((unsigned int) p_used_rx_desc, 0); + CPU_PIPE_FLUSH; + + /* Move the used descriptor pointer to the next descriptor */ + USED_RFD_SET (RX_NEXT_DESC_PTR (p_used_rx_desc, rx_queue), rx_queue); + + /* Any Rx return cancels the Rx resource error status */ + if (p_eth_port_ctrl->rx_resource_err[rx_queue] == true) + p_eth_port_ctrl->rx_resource_err[rx_queue] = false; + + return ETH_OK; +} + +/******************************************************************************* + * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path + * + * DESCRIPTION: + * This routine sets the RX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the tClk of the MV-643xx chip + * , and the required delay of the interrupt in usec. + * + * INPUT: + * ETH_PORT eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in usec + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + *******************************************************************************/ +#if 0 /* FIXME */ +static unsigned int eth_port_set_rx_coal (ETH_PORT eth_port_num, + unsigned int t_clk, + unsigned int delay) +{ + unsigned int coal; + + coal = ((t_clk / 1000000) * delay) / 64; + /* Set RX Coalescing mechanism */ + MV_REG_WRITE (MV64360_ETH_SDMA_CONFIG_REG (eth_port_num), + ((coal & 0x3fff) << 8) | + (MV_REG_READ + (MV64360_ETH_SDMA_CONFIG_REG (eth_port_num)) + & 0xffc000ff)); + return coal; +} + +#endif +/******************************************************************************* + * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path + * + * DESCRIPTION: + * This routine sets the TX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the t_cLK frequency of the + * MV-643xx chip and the required delay in the interrupt in uSec + * + * INPUT: + * ETH_PORT eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in uSeconds + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + *******************************************************************************/ +#if 0 /* FIXME */ +static unsigned int eth_port_set_tx_coal (ETH_PORT eth_port_num, + unsigned int t_clk, + unsigned int delay) +{ + unsigned int coal; + + coal = ((t_clk / 1000000) * delay) / 64; + /* Set TX Coalescing mechanism */ + MV_REG_WRITE (MV64360_ETH_TX_FIFO_URGENT_THRESHOLD_REG (eth_port_num), + coal << 4); + return coal; +} +#endif + +/******************************************************************************* + * eth_b_copy - Copy bytes from source to destination + * + * DESCRIPTION: + * This function supports the eight bytes limitation on Tx buffer size. + * The routine will zero eight bytes starting from the destination address + * followed by copying bytes from the source address to the destination. + * + * INPUT: + * unsigned int src_addr 32 bit source address. + * unsigned int dst_addr 32 bit destination address. + * int byte_count Number of bytes to copy. + * + * OUTPUT: + * See description. + * + * RETURN: + * None. + * + *******************************************************************************/ +static void eth_b_copy (unsigned int src_addr, unsigned int dst_addr, + int byte_count) +{ + /* Zero the dst_addr area */ + *(unsigned int *) dst_addr = 0x0; + + while (byte_count != 0) { + *(char *) dst_addr = *(char *) src_addr; + dst_addr++; + src_addr++; + byte_count--; + } +} diff --git a/board/esd/cpci750/mv_eth.h b/board/esd/cpci750/mv_eth.h new file mode 100644 index 0000000000..c57e6796cc --- /dev/null +++ b/board/esd/cpci750/mv_eth.h @@ -0,0 +1,844 @@ +/* + * (C) Copyright 2003 + * Ingo Assmus + * + * based on - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * 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 + */ + +/* + * mv_eth.h - header file for the polled mode GT ethernet driver + */ + +#ifndef __DB64360_ETH_H__ +#define __DB64360_ETH_H__ + +#include +#include +#include +#include +#include +#include "mv_regs.h" +#include "../../Marvell/common/ppc_error_no.h" + + +/************************************************************************* +************************************************************************** +************************************************************************** +* The first part is the high level driver of the gigE ethernet ports. * +************************************************************************** +************************************************************************** +*************************************************************************/ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* In case not using SG on Tx, define MAX_SKB_FRAGS as 0 */ +#ifndef MAX_SKB_FRAGS +#define MAX_SKB_FRAGS 0 +#endif + +/* Port attributes */ +/*#define MAX_RX_QUEUE_NUM 8*/ +/*#define MAX_TX_QUEUE_NUM 8*/ +#define MAX_RX_QUEUE_NUM 1 +#define MAX_TX_QUEUE_NUM 1 + + +/* Use one TX queue and one RX queue */ +#define MV64360_TX_QUEUE_NUM 1 +#define MV64360_RX_QUEUE_NUM 1 + +/* + * Number of RX / TX descriptors on RX / TX rings. + * Note that allocating RX descriptors is done by allocating the RX + * ring AND a preallocated RX buffers (skb's) for each descriptor. + * The TX descriptors only allocates the TX descriptors ring, + * with no pre allocated TX buffers (skb's are allocated by higher layers. + */ + +/* Default TX ring size is 10 descriptors */ +#ifdef CONFIG_MV64360_ETH_TXQUEUE_SIZE +#define MV64360_TX_QUEUE_SIZE CONFIG_MV64360_ETH_TXQUEUE_SIZE +#else +#define MV64360_TX_QUEUE_SIZE 4 +#endif + +/* Default RX ring size is 4 descriptors */ +#ifdef CONFIG_MV64360_ETH_RXQUEUE_SIZE +#define MV64360_RX_QUEUE_SIZE CONFIG_MV64360_ETH_RXQUEUE_SIZE +#else +#define MV64360_RX_QUEUE_SIZE 4 +#endif + +#ifdef CONFIG_RX_BUFFER_SIZE +#define MV64360_RX_BUFFER_SIZE CONFIG_RX_BUFFER_SIZE +#else +#define MV64360_RX_BUFFER_SIZE 1600 +#endif + +#ifdef CONFIG_TX_BUFFER_SIZE +#define MV64360_TX_BUFFER_SIZE CONFIG_TX_BUFFER_SIZE +#else +#define MV64360_TX_BUFFER_SIZE 1600 +#endif + + +/* + * Network device statistics. Akin to the 2.0 ether stats but + * with byte counters. + */ + +struct net_device_stats +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; +}; + + +/* Private data structure used for ethernet device */ +struct mv64360_eth_priv { + unsigned int port_num; + struct net_device_stats *stats; + +/* to buffer area aligned */ + char * p_eth_tx_buffer[MV64360_TX_QUEUE_SIZE+1]; /*pointers to alligned tx buffs in memory space */ + char * p_eth_rx_buffer[MV64360_RX_QUEUE_SIZE+1]; /*pointers to allinged rx buffs in memory space */ + + /* Size of Tx Ring per queue */ + unsigned int tx_ring_size [MAX_TX_QUEUE_NUM]; + + + /* Size of Rx Ring per queue */ + unsigned int rx_ring_size [MAX_RX_QUEUE_NUM]; + + /* Magic Number for Ethernet running */ + unsigned int eth_running; + +}; + + +int mv64360_eth_init (struct eth_device *dev); +int mv64360_eth_stop (struct eth_device *dev); +int mv64360_eth_start_xmit (struct eth_device*, volatile void* packet, int length); +/* return db64360_eth0_poll(); */ + +int mv64360_eth_open (struct eth_device *dev); + + +/************************************************************************* +************************************************************************** +************************************************************************** +* The second part is the low level driver of the gigE ethernet ports. * +************************************************************************** +************************************************************************** +*************************************************************************/ + + +/******************************************************************************** + * Header File for : MV-643xx network interface header + * + * DESCRIPTION: + * This header file contains macros typedefs and function declaration for + * the Marvell Gig Bit Ethernet Controller. + * + * DEPENDENCIES: + * None. + * + *******************************************************************************/ + + +#ifdef CONFIG_SPECIAL_CONSISTENT_MEMORY +#ifdef CONFIG_MV64360_SRAM_CACHEABLE +/* In case SRAM is cacheable but not cache coherent */ +#define D_CACHE_FLUSH_LINE(addr, offset) \ +{ \ + __asm__ __volatile__ ("dcbf %0,%1" : : "r" (addr), "r" (offset)); \ +} +#else +/* In case SRAM is cache coherent or non-cacheable */ +#define D_CACHE_FLUSH_LINE(addr, offset) ; +#endif +#else +#ifdef CONFIG_NOT_COHERENT_CACHE +/* In case of descriptors on DDR but not cache coherent */ +#define D_CACHE_FLUSH_LINE(addr, offset) \ +{ \ + __asm__ __volatile__ ("dcbf %0,%1" : : "r" (addr), "r" (offset)); \ +} +#else +/* In case of descriptors on DDR and cache coherent */ +#define D_CACHE_FLUSH_LINE(addr, offset) ; +#endif /* CONFIG_NOT_COHERENT_CACHE */ +#endif /* CONFIG_SPECIAL_CONSISTENT_MEMORY */ + + +#define CPU_PIPE_FLUSH \ +{ \ + __asm__ __volatile__ ("eieio"); \ +} + + +/* defines */ + +/* Default port configuration value */ +#define PORT_CONFIG_VALUE \ + ETH_UNICAST_NORMAL_MODE | \ + ETH_DEFAULT_RX_QUEUE_0 | \ + ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + ETH_RECEIVE_BC_IF_IP | \ + ETH_RECEIVE_BC_IF_ARP | \ + ETH_CAPTURE_TCP_FRAMES_DIS | \ + ETH_CAPTURE_UDP_FRAMES_DIS | \ + ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + ETH_DEFAULT_RX_BPDU_QUEUE_0 + +/* Default port extend configuration value */ +#define PORT_CONFIG_EXTEND_VALUE \ + ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + ETH_PARTITION_DISABLE + + +/* Default sdma control value */ +#ifdef CONFIG_NOT_COHERENT_CACHE +#define PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_16_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_16_64BIT; +#else +#define PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_4_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_4_64BIT; +#endif + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +/* Default port serial control value */ +#define PORT_SERIAL_CONTROL_VALUE \ + ETH_FORCE_LINK_PASS | \ + ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + ETH_FORCE_BP_MODE_NO_JAM | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL | \ + ETH_RETRANSMIT_16_ETTEMPTS | \ + ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + ETH_DTE_ADV_0 | \ + ETH_DISABLE_AUTO_NEG_BYPASS | \ + ETH_AUTO_NEG_NO_CHANGE | \ + ETH_MAX_RX_PACKET_1552BYTE | \ + ETH_CLR_EXT_LOOPBACK | \ + ETH_SET_FULL_DUPLEX_MODE | \ + ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX; + +#define RX_BUFFER_MAX_SIZE 0xFFFF +#define TX_BUFFER_MAX_SIZE 0xFFFF /* Buffer are limited to 64k */ + +#define RX_BUFFER_MIN_SIZE 0x8 +#define TX_BUFFER_MIN_SIZE 0x8 + +/* Tx WRR confoguration macros */ +#define PORT_MAX_TRAN_UNIT 0x24 /* MTU register (default) 9KByte */ +#define PORT_MAX_TOKEN_BUCKET_SIZE 0x_fFFF /* PMTBS register (default) */ +#define PORT_TOKEN_RATE 1023 /* PTTBRC register (default) */ + +/* MAC accepet/reject macros */ +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 + +/* Size of a Tx/Rx descriptor used in chain list data structure */ +#define RX_DESC_ALIGNED_SIZE 0x20 +#define TX_DESC_ALIGNED_SIZE 0x20 + +/* An offest in Tx descriptors to store data for buffers less than 8 Bytes */ +#define TX_BUF_OFFSET_IN_DESC 0x18 +/* Buffer offset from buffer pointer */ +#define RX_BUF_OFFSET 0x2 + +/* Gap define */ +#define ETH_BAR_GAP 0x8 +#define ETH_SIZE_REG_GAP 0x8 +#define ETH_HIGH_ADDR_REMAP_REG_GAP 0x4 +#define ETH_PORT_ACCESS_CTRL_GAP 0x4 + +/* Gigabit Ethernet Unit Global Registers */ + +/* MIB Counters register definitions */ +#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 +#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 +#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 +#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc +#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 +#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 +#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 +#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c +#define ETH_MIB_FRAMES_64_OCTETS 0x20 +#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 +#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 +#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c +#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 +#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 +#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 +#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c +#define ETH_MIB_GOOD_FRAMES_SENT 0x40 +#define ETH_MIB_EXCESSIVE_COLLISION 0x44 +#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 +#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c +#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 +#define ETH_MIB_FC_SENT 0x54 +#define ETH_MIB_GOOD_FC_RECEIVED 0x58 +#define ETH_MIB_BAD_FC_RECEIVED 0x5c +#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 +#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 +#define ETH_MIB_OVERSIZE_RECEIVED 0x68 +#define ETH_MIB_JABBER_RECEIVED 0x6c +#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 +#define ETH_MIB_BAD_CRC_EVENT 0x74 +#define ETH_MIB_COLLISION 0x78 +#define ETH_MIB_LATE_COLLISION 0x7c + +/* Port serial status reg (PSR) */ +#define ETH_INTERFACE_GMII_MII 0 +#define ETH_INTERFACE_PCM BIT0 +#define ETH_LINK_IS_DOWN 0 +#define ETH_LINK_IS_UP BIT1 +#define ETH_PORT_AT_HALF_DUPLEX 0 +#define ETH_PORT_AT_FULL_DUPLEX BIT2 +#define ETH_RX_FLOW_CTRL_DISABLED 0 +#define ETH_RX_FLOW_CTRL_ENBALED BIT3 +#define ETH_GMII_SPEED_100_10 0 +#define ETH_GMII_SPEED_1000 BIT4 +#define ETH_MII_SPEED_10 0 +#define ETH_MII_SPEED_100 BIT5 +#define ETH_NO_TX 0 +#define ETH_TX_IN_PROGRESS BIT7 +#define ETH_BYPASS_NO_ACTIVE 0 +#define ETH_BYPASS_ACTIVE BIT8 +#define ETH_PORT_NOT_AT_PARTITION_STATE 0 +#define ETH_PORT_AT_PARTITION_STATE BIT9 +#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 +#define ETH_PORT_TX_FIFO_EMPTY BIT10 + + +/* These macros describes the Port configuration reg (Px_cR) bits */ +#define ETH_UNICAST_NORMAL_MODE 0 +#define ETH_UNICAST_PROMISCUOUS_MODE BIT0 +#define ETH_DEFAULT_RX_QUEUE_0 0 +#define ETH_DEFAULT_RX_QUEUE_1 BIT1 +#define ETH_DEFAULT_RX_QUEUE_2 BIT2 +#define ETH_DEFAULT_RX_QUEUE_3 (BIT2 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_4 BIT3 +#define ETH_DEFAULT_RX_QUEUE_5 (BIT3 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_6 (BIT3 | BIT2) +#define ETH_DEFAULT_RX_QUEUE_7 (BIT3 | BIT2 | BIT1) +#define ETH_DEFAULT_RX_ARP_QUEUE_0 0 +#define ETH_DEFAULT_RX_ARP_QUEUE_1 BIT4 +#define ETH_DEFAULT_RX_ARP_QUEUE_2 BIT5 +#define ETH_DEFAULT_RX_ARP_QUEUE_3 (BIT5 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_4 BIT6 +#define ETH_DEFAULT_RX_ARP_QUEUE_5 (BIT6 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_6 (BIT6 | BIT5) +#define ETH_DEFAULT_RX_ARP_QUEUE_7 (BIT6 | BIT5 | BIT4) +#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 +#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP BIT7 +#define ETH_RECEIVE_BC_IF_IP 0 +#define ETH_REJECT_BC_IF_IP BIT8 +#define ETH_RECEIVE_BC_IF_ARP 0 +#define ETH_REJECT_BC_IF_ARP BIT9 +#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY BIT12 +#define ETH_CAPTURE_TCP_FRAMES_DIS 0 +#define ETH_CAPTURE_TCP_FRAMES_EN BIT14 +#define ETH_CAPTURE_UDP_FRAMES_DIS 0 +#define ETH_CAPTURE_UDP_FRAMES_EN BIT15 +#define ETH_DEFAULT_RX_TCP_QUEUE_0 0 +#define ETH_DEFAULT_RX_TCP_QUEUE_1 BIT16 +#define ETH_DEFAULT_RX_TCP_QUEUE_2 BIT17 +#define ETH_DEFAULT_RX_TCP_QUEUE_3 (BIT17 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_4 BIT18 +#define ETH_DEFAULT_RX_TCP_QUEUE_5 (BIT18 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_6 (BIT18 | BIT17) +#define ETH_DEFAULT_RX_TCP_QUEUE_7 (BIT18 | BIT17 | BIT16) +#define ETH_DEFAULT_RX_UDP_QUEUE_0 0 +#define ETH_DEFAULT_RX_UDP_QUEUE_1 BIT19 +#define ETH_DEFAULT_RX_UDP_QUEUE_2 BIT20 +#define ETH_DEFAULT_RX_UDP_QUEUE_3 (BIT20 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_4 (BIT21 +#define ETH_DEFAULT_RX_UDP_QUEUE_5 (BIT21 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_6 (BIT21 | BIT20) +#define ETH_DEFAULT_RX_UDP_QUEUE_7 (BIT21 | BIT20 | BIT19) +#define ETH_DEFAULT_RX_BPDU_QUEUE_0 0 +#define ETH_DEFAULT_RX_BPDU_QUEUE_1 BIT22 +#define ETH_DEFAULT_RX_BPDU_QUEUE_2 BIT23 +#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 +#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) +#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) + + +/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ +#define ETH_CLASSIFY_EN BIT0 +#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 BIT1 +#define ETH_PARTITION_DISABLE 0 +#define ETH_PARTITION_ENABLE BIT2 + + +/* Tx/Rx queue command reg (RQCR/TQCR)*/ +#define ETH_QUEUE_0_ENABLE BIT0 +#define ETH_QUEUE_1_ENABLE BIT1 +#define ETH_QUEUE_2_ENABLE BIT2 +#define ETH_QUEUE_3_ENABLE BIT3 +#define ETH_QUEUE_4_ENABLE BIT4 +#define ETH_QUEUE_5_ENABLE BIT5 +#define ETH_QUEUE_6_ENABLE BIT6 +#define ETH_QUEUE_7_ENABLE BIT7 +#define ETH_QUEUE_0_DISABLE BIT8 +#define ETH_QUEUE_1_DISABLE BIT9 +#define ETH_QUEUE_2_DISABLE BIT10 +#define ETH_QUEUE_3_DISABLE BIT11 +#define ETH_QUEUE_4_DISABLE BIT12 +#define ETH_QUEUE_5_DISABLE BIT13 +#define ETH_QUEUE_6_DISABLE BIT14 +#define ETH_QUEUE_7_DISABLE BIT15 + + +/* These macros describes the Port Sdma configuration reg (SDCR) bits */ +#define ETH_RIFB BIT0 +#define ETH_RX_BURST_SIZE_1_64BIT 0 +#define ETH_RX_BURST_SIZE_2_64BIT BIT1 +#define ETH_RX_BURST_SIZE_4_64BIT BIT2 +#define ETH_RX_BURST_SIZE_8_64BIT (BIT2 | BIT1) +#define ETH_RX_BURST_SIZE_16_64BIT BIT3 +#define ETH_BLM_RX_NO_SWAP BIT4 +#define ETH_BLM_RX_BYTE_SWAP 0 +#define ETH_BLM_TX_NO_SWAP BIT5 +#define ETH_BLM_TX_BYTE_SWAP 0 +#define ETH_DESCRIPTORS_BYTE_SWAP BIT6 +#define ETH_DESCRIPTORS_NO_SWAP 0 +#define ETH_TX_BURST_SIZE_1_64BIT 0 +#define ETH_TX_BURST_SIZE_2_64BIT BIT22 +#define ETH_TX_BURST_SIZE_4_64BIT BIT23 +#define ETH_TX_BURST_SIZE_8_64BIT (BIT23 | BIT22) +#define ETH_TX_BURST_SIZE_16_64BIT BIT24 + + +/* These macros describes the Port serial control reg (PSCR) bits */ +#define ETH_SERIAL_PORT_DISABLE 0 +#define ETH_SERIAL_PORT_ENABLE BIT0 +#define ETH_FORCE_LINK_PASS BIT1 +#define ETH_DO_NOT_FORCE_LINK_PASS 0 +#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 +#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX BIT2 +#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 +#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL BIT3 +#define ETH_ADV_NO_FLOW_CTRL 0 +#define ETH_ADV_SYMMETRIC_FLOW_CTRL BIT4 +#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS BIT5 +#define ETH_FORCE_BP_MODE_NO_JAM 0 +#define ETH_FORCE_BP_MODE_JAM_TX BIT7 +#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR BIT8 +#define ETH_FORCE_LINK_FAIL 0 +#define ETH_DO_NOT_FORCE_LINK_FAIL BIT10 +#define ETH_RETRANSMIT_16_ETTEMPTS 0 +#define ETH_RETRANSMIT_FOREVER BIT11 +#define ETH_DISABLE_AUTO_NEG_SPEED_GMII BIT13 +#define ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 +#define ETH_DTE_ADV_0 0 +#define ETH_DTE_ADV_1 BIT14 +#define ETH_DISABLE_AUTO_NEG_BYPASS 0 +#define ETH_ENABLE_AUTO_NEG_BYPASS BIT15 +#define ETH_AUTO_NEG_NO_CHANGE 0 +#define ETH_RESTART_AUTO_NEG BIT16 +#define ETH_MAX_RX_PACKET_1518BYTE 0 +#define ETH_MAX_RX_PACKET_1522BYTE BIT17 +#define ETH_MAX_RX_PACKET_1552BYTE BIT18 +#define ETH_MAX_RX_PACKET_9022BYTE (BIT18 | BIT17) +#define ETH_MAX_RX_PACKET_9192BYTE BIT19 +#define ETH_MAX_RX_PACKET_9700BYTE (BIT19 | BIT17) +#define ETH_SET_EXT_LOOPBACK BIT20 +#define ETH_CLR_EXT_LOOPBACK 0 +#define ETH_SET_FULL_DUPLEX_MODE BIT21 +#define ETH_SET_HALF_DUPLEX_MODE 0 +#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX BIT22 +#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define ETH_SET_GMII_SPEED_TO_10_100 0 +#define ETH_SET_GMII_SPEED_TO_1000 BIT23 +#define ETH_SET_MII_SPEED_TO_10 0 +#define ETH_SET_MII_SPEED_TO_100 BIT24 + + +/* SMI reg */ +#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ +#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ +#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ + +/* SDMA command status fields macros */ + +/* Tx & Rx descriptors status */ +#define ETH_ERROR_SUMMARY (BIT0) + +/* Tx & Rx descriptors command */ +#define ETH_BUFFER_OWNED_BY_DMA (BIT31) + +/* Tx descriptors status */ +#define ETH_LC_ERROR (0 ) +#define ETH_UR_ERROR (BIT1 ) +#define ETH_RL_ERROR (BIT2 ) +#define ETH_LLC_SNAP_FORMAT (BIT9 ) + +/* Rx descriptors status */ +#define ETH_CRC_ERROR (0 ) +#define ETH_OVERRUN_ERROR (BIT1 ) +#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) +#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) +#define ETH_VLAN_TAGGED (BIT19) +#define ETH_BPDU_FRAME (BIT20) +#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) +#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) +#define ETH_OTHER_FRAME_TYPE (BIT22) +#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) +#define ETH_FRAME_TYPE_IP_V_4 (BIT24) +#define ETH_FRAME_HEADER_OK (BIT25) +#define ETH_RX_LAST_DESC (BIT26) +#define ETH_RX_FIRST_DESC (BIT27) +#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) +#define ETH_RX_ENABLE_INTERRUPT (BIT29) +#define ETH_LAYER_4_CHECKSUM_OK (BIT30) + +/* Rx descriptors byte count */ +#define ETH_FRAME_FRAGMENTED (BIT2) + +/* Tx descriptors command */ +#define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) +#define ETH_FRAME_SET_TO_VLAN (BIT15) +#define ETH_TCP_FRAME (0 ) +#define ETH_UDP_FRAME (BIT16) +#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) +#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) +#define ETH_ZERO_PADDING (BIT19) +#define ETH_TX_LAST_DESC (BIT20) +#define ETH_TX_FIRST_DESC (BIT21) +#define ETH_GEN_CRC (BIT22) +#define ETH_TX_ENABLE_INTERRUPT (BIT23) +#define ETH_AUTO_MODE (BIT30) + +/* Address decode parameters */ +/* Ethernet Base Address Register bits */ +#define EBAR_TARGET_DRAM 0x00000000 +#define EBAR_TARGET_DEVICE 0x00000001 +#define EBAR_TARGET_CBS 0x00000002 +#define EBAR_TARGET_PCI0 0x00000003 +#define EBAR_TARGET_PCI1 0x00000004 +#define EBAR_TARGET_CUNIT 0x00000005 +#define EBAR_TARGET_AUNIT 0x00000006 +#define EBAR_TARGET_GUNIT 0x00000007 + +/* Window attributes */ +#define EBAR_ATTR_DRAM_CS0 0x00000E00 +#define EBAR_ATTR_DRAM_CS1 0x00000D00 +#define EBAR_ATTR_DRAM_CS2 0x00000B00 +#define EBAR_ATTR_DRAM_CS3 0x00000700 + +/* DRAM Target interface */ +#define EBAR_ATTR_DRAM_NO_CACHE_COHERENCY 0x00000000 +#define EBAR_ATTR_DRAM_CACHE_COHERENCY_WT 0x00001000 +#define EBAR_ATTR_DRAM_CACHE_COHERENCY_WB 0x00002000 + +/* Device Bus Target interface */ +#define EBAR_ATTR_DEVICE_DEVCS0 0x00001E00 +#define EBAR_ATTR_DEVICE_DEVCS1 0x00001D00 +#define EBAR_ATTR_DEVICE_DEVCS2 0x00001B00 +#define EBAR_ATTR_DEVICE_DEVCS3 0x00001700 +#define EBAR_ATTR_DEVICE_BOOTCS3 0x00000F00 + +/* PCI Target interface */ +#define EBAR_ATTR_PCI_BYTE_SWAP 0x00000000 +#define EBAR_ATTR_PCI_NO_SWAP 0x00000100 +#define EBAR_ATTR_PCI_BYTE_WORD_SWAP 0x00000200 +#define EBAR_ATTR_PCI_WORD_SWAP 0x00000300 +#define EBAR_ATTR_PCI_NO_SNOOP_NOT_ASSERT 0x00000000 +#define EBAR_ATTR_PCI_NO_SNOOP_ASSERT 0x00000400 +#define EBAR_ATTR_PCI_IO_SPACE 0x00000000 +#define EBAR_ATTR_PCI_MEMORY_SPACE 0x00000800 +#define EBAR_ATTR_PCI_REQ64_FORCE 0x00000000 +#define EBAR_ATTR_PCI_REQ64_SIZE 0x00001000 + +/* CPU 60x bus or internal SRAM interface */ +#define EBAR_ATTR_CBS_SRAM_BLOCK0 0x00000000 +#define EBAR_ATTR_CBS_SRAM_BLOCK1 0x00000100 +#define EBAR_ATTR_CBS_SRAM 0x00000000 +#define EBAR_ATTR_CBS_CPU_BUS 0x00000800 + +/* Window access control */ +#define EWIN_ACCESS_NOT_ALLOWED 0 +#define EWIN_ACCESS_READ_ONLY BIT0 +#define EWIN_ACCESS_FULL (BIT1 | BIT0) +#define EWIN0_ACCESS_MASK 0x0003 +#define EWIN1_ACCESS_MASK 0x000C +#define EWIN2_ACCESS_MASK 0x0030 +#define EWIN3_ACCESS_MASK 0x00C0 + +/* typedefs */ + +typedef enum _eth_port +{ + ETH_0 = 0, + ETH_1 = 1, + ETH_2 = 2 +}ETH_PORT; + +typedef enum _eth_func_ret_status +{ + ETH_OK, /* Returned as expected. */ + ETH_ERROR, /* Fundamental error. */ + ETH_RETRY, /* Could not process request. Try later. */ + ETH_END_OF_JOB, /* Ring has nothing to process. */ + ETH_QUEUE_FULL, /* Ring resource error. */ + ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ +}ETH_FUNC_RET_STATUS; + +typedef enum _eth_queue +{ + ETH_Q0 = 0, + ETH_Q1 = 1, + ETH_Q2 = 2, + ETH_Q3 = 3, + ETH_Q4 = 4, + ETH_Q5 = 5, + ETH_Q6 = 6, + ETH_Q7 = 7 +} ETH_QUEUE; + +typedef enum _addr_win +{ + ETH_WIN0, + ETH_WIN1, + ETH_WIN2, + ETH_WIN3, + ETH_WIN4, + ETH_WIN5 +} ETH_ADDR_WIN; + +typedef enum _eth_target +{ + ETH_TARGET_DRAM , + ETH_TARGET_DEVICE, + ETH_TARGET_CBS , + ETH_TARGET_PCI0 , + ETH_TARGET_PCI1 +}ETH_TARGET; + +typedef struct _eth_rx_desc +{ + unsigned short byte_cnt ; /* Descriptor buffer byte count */ + unsigned short buf_size ; /* Buffer size */ + unsigned int cmd_sts ; /* Descriptor command status */ + unsigned int next_desc_ptr; /* Next descriptor pointer */ + unsigned int buf_ptr ; /* Descriptor buffer pointer */ + unsigned int return_info ; /* User resource return information */ +} ETH_RX_DESC; + + +typedef struct _eth_tx_desc +{ + unsigned short byte_cnt ; /* Descriptor buffer byte count */ + unsigned short l4i_chk ; /* CPU provided TCP Checksum */ + unsigned int cmd_sts ; /* Descriptor command status */ + unsigned int next_desc_ptr; /* Next descriptor pointer */ + unsigned int buf_ptr ; /* Descriptor buffer pointer */ + unsigned int return_info ; /* User resource return information */ +} ETH_TX_DESC; + +/* Unified struct for Rx and Tx operations. The user is not required to */ +/* be familier with neither Tx nor Rx descriptors. */ +typedef struct _pkt_info +{ + unsigned short byte_cnt ; /* Descriptor buffer byte count */ + unsigned short l4i_chk ; /* Tx CPU provided TCP Checksum */ + unsigned int cmd_sts ; /* Descriptor command status */ + unsigned int buf_ptr ; /* Descriptor buffer pointer */ + unsigned int return_info ; /* User resource return information */ +} PKT_INFO; + + +typedef struct _eth_win_param +{ + ETH_ADDR_WIN win; /* Window number. See ETH_ADDR_WIN enum */ + ETH_TARGET target; /* System targets. See ETH_TARGET enum */ + unsigned short attributes; /* BAR attributes. See above macros. */ + unsigned int base_addr; /* Window base address in unsigned int form */ + unsigned int high_addr; /* Window high address in unsigned int form */ + unsigned int size; /* Size in MBytes. Must be % 64Kbyte. */ + bool enable; /* Enable/disable access to the window. */ + unsigned short access_ctrl; /* Access ctrl register. see above macros */ +} ETH_WIN_PARAM; + + +/* Ethernet port specific infomation */ + +typedef struct _eth_port_ctrl +{ + ETH_PORT port_num; /* User Ethernet port number */ + int port_phy_addr; /* User phy address of Ethrnet port */ + unsigned char port_mac_addr[6]; /* User defined port MAC address. */ + unsigned int port_config; /* User port configuration value */ + unsigned int port_config_extend; /* User port config extend value */ + unsigned int port_sdma_config; /* User port SDMA config value */ + unsigned int port_serial_control; /* User port serial control value */ + unsigned int port_tx_queue_command; /* Port active Tx queues summary */ + unsigned int port_rx_queue_command; /* Port active Rx queues summary */ + + /* User function to cast virtual address to CPU bus address */ + unsigned int (*port_virt_to_phys)(unsigned int addr); + /* User scratch pad for user specific data structures */ + void *port_private; + + bool rx_resource_err[MAX_RX_QUEUE_NUM]; /* Rx ring resource error flag */ + bool tx_resource_err[MAX_TX_QUEUE_NUM]; /* Tx ring resource error flag */ + + /* Tx/Rx rings managment indexes fields. For driver use */ + + /* Next available Rx resource */ + volatile ETH_RX_DESC *p_rx_curr_desc_q[MAX_RX_QUEUE_NUM]; + /* Returning Rx resource */ + volatile ETH_RX_DESC *p_rx_used_desc_q[MAX_RX_QUEUE_NUM]; + + /* Next available Tx resource */ + volatile ETH_TX_DESC *p_tx_curr_desc_q[MAX_TX_QUEUE_NUM]; + /* Returning Tx resource */ + volatile ETH_TX_DESC *p_tx_used_desc_q[MAX_TX_QUEUE_NUM]; + /* An extra Tx index to support transmit of multiple buffers per packet */ + volatile ETH_TX_DESC *p_tx_first_desc_q[MAX_TX_QUEUE_NUM]; + + /* Tx/Rx rings size and base variables fields. For driver use */ + + volatile ETH_RX_DESC *p_rx_desc_area_base[MAX_RX_QUEUE_NUM]; + unsigned int rx_desc_area_size[MAX_RX_QUEUE_NUM]; + char *p_rx_buffer_base[MAX_RX_QUEUE_NUM]; + + volatile ETH_TX_DESC *p_tx_desc_area_base[MAX_TX_QUEUE_NUM]; + unsigned int tx_desc_area_size[MAX_TX_QUEUE_NUM]; + char *p_tx_buffer_base[MAX_TX_QUEUE_NUM]; + +} ETH_PORT_INFO; + + +/* ethernet.h API list */ + +/* Port operation control routines */ +static void eth_port_init (ETH_PORT_INFO *p_eth_port_ctrl); +static void eth_port_reset(ETH_PORT eth_port_num); +static bool eth_port_start(ETH_PORT_INFO *p_eth_port_ctrl); + + +/* Port MAC address routines */ +static void eth_port_uc_addr_set (ETH_PORT eth_port_num, + unsigned char *p_addr, + ETH_QUEUE queue); +#if 0 /* FIXME */ +static void eth_port_mc_addr (ETH_PORT eth_port_num, + unsigned char *p_addr, + ETH_QUEUE queue, + int option); +#endif + +/* PHY and MIB routines */ +static bool ethernet_phy_reset(ETH_PORT eth_port_num); + +static bool eth_port_write_smi_reg(ETH_PORT eth_port_num, + unsigned int phy_reg, + unsigned int value); + +static bool eth_port_read_smi_reg(ETH_PORT eth_port_num, + unsigned int phy_reg, + unsigned int* value); + +static void eth_clear_mib_counters(ETH_PORT eth_port_num); + +/* Port data flow control routines */ +static ETH_FUNC_RET_STATUS eth_port_send (ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE tx_queue, + PKT_INFO *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_tx_return_desc(ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE tx_queue, + PKT_INFO *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_receive (ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE rx_queue, + PKT_INFO *p_pkt_info); +static ETH_FUNC_RET_STATUS eth_rx_return_buff(ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE rx_queue, + PKT_INFO *p_pkt_info); + + +static bool ether_init_tx_desc_ring(ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE tx_queue, + int tx_desc_num, + int tx_buff_size, + unsigned int tx_desc_base_addr, + unsigned int tx_buff_base_addr); + +static bool ether_init_rx_desc_ring(ETH_PORT_INFO *p_eth_port_ctrl, + ETH_QUEUE rx_queue, + int rx_desc_num, + int rx_buff_size, + unsigned int rx_desc_base_addr, + unsigned int rx_buff_base_addr); + +#endif /* MV64360_ETH_ */ diff --git a/board/esd/cpci750/mv_regs.h b/board/esd/cpci750/mv_regs.h new file mode 100644 index 0000000000..0d6370b52c --- /dev/null +++ b/board/esd/cpci750/mv_regs.h @@ -0,0 +1,1124 @@ +/* + * (C) Copyright 2003 + * Ingo Assmus + * + * based on - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * 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 + */ + +/******************************************************************************** +* gt64360r.h - GT-64360 Internal registers definition file. +* +* DESCRIPTION: +* None. +* +* DEPENDENCIES: +* None. +* +*******************************************************************************/ + +#ifndef __INCmv_regsh +#define __INCmv_regsh + +#define MV64360 + +/* Supported by the Atlantis */ +#define MV64360_INCLUDE_PCI_1 +#define MV64360_INCLUDE_PCI_0_ARBITER +#define MV64360_INCLUDE_PCI_1_ARBITER +#define MV64360_INCLUDE_SNOOP_SUPPORT +#define MV64360_INCLUDE_P2P +#define MV64360_INCLUDE_ETH_PORT_2 +#define MV64360_INCLUDE_CPU_MAPPING +#define MV64360_INCLUDE_MPSC + +/* Not supported features */ +#undef INCLUDE_CNTMR_4_7 +#undef INCLUDE_DMA_4_7 + +/****************************************/ +/* Processor Address Space */ +/****************************************/ + +/* DDR SDRAM BAR and size registers */ + +#define MV64360_CS_0_BASE_ADDR 0x008 +#define MV64360_CS_0_SIZE 0x010 +#define MV64360_CS_1_BASE_ADDR 0x208 +#define MV64360_CS_1_SIZE 0x210 +#define MV64360_CS_2_BASE_ADDR 0x018 +#define MV64360_CS_2_SIZE 0x020 +#define MV64360_CS_3_BASE_ADDR 0x218 +#define MV64360_CS_3_SIZE 0x220 + +/* Devices BAR and size registers */ + +#define MV64360_DEV_CS0_BASE_ADDR 0x028 +#define MV64360_DEV_CS0_SIZE 0x030 +#define MV64360_DEV_CS1_BASE_ADDR 0x228 +#define MV64360_DEV_CS1_SIZE 0x230 +#define MV64360_DEV_CS2_BASE_ADDR 0x248 +#define MV64360_DEV_CS2_SIZE 0x250 +#define MV64360_DEV_CS3_BASE_ADDR 0x038 +#define MV64360_DEV_CS3_SIZE 0x040 +#define MV64360_BOOTCS_BASE_ADDR 0x238 +#define MV64360_BOOTCS_SIZE 0x240 + +/* PCI 0 BAR and size registers */ + +#define MV64360_PCI_0_IO_BASE_ADDR 0x048 +#define MV64360_PCI_0_IO_SIZE 0x050 +#define MV64360_PCI_0_MEMORY0_BASE_ADDR 0x058 +#define MV64360_PCI_0_MEMORY0_SIZE 0x060 +#define MV64360_PCI_0_MEMORY1_BASE_ADDR 0x080 +#define MV64360_PCI_0_MEMORY1_SIZE 0x088 +#define MV64360_PCI_0_MEMORY2_BASE_ADDR 0x258 +#define MV64360_PCI_0_MEMORY2_SIZE 0x260 +#define MV64360_PCI_0_MEMORY3_BASE_ADDR 0x280 +#define MV64360_PCI_0_MEMORY3_SIZE 0x288 + +/* PCI 1 BAR and size registers */ +#define MV64360_PCI_1_IO_BASE_ADDR 0x090 +#define MV64360_PCI_1_IO_SIZE 0x098 +#define MV64360_PCI_1_MEMORY0_BASE_ADDR 0x0a0 +#define MV64360_PCI_1_MEMORY0_SIZE 0x0a8 +#define MV64360_PCI_1_MEMORY1_BASE_ADDR 0x0b0 +#define MV64360_PCI_1_MEMORY1_SIZE 0x0b8 +#define MV64360_PCI_1_MEMORY2_BASE_ADDR 0x2a0 +#define MV64360_PCI_1_MEMORY2_SIZE 0x2a8 +#define MV64360_PCI_1_MEMORY3_BASE_ADDR 0x2b0 +#define MV64360_PCI_1_MEMORY3_SIZE 0x2b8 + +/* SRAM base address */ +#define MV64360_INTEGRATED_SRAM_BASE_ADDR 0x268 + +/* internal registers space base address */ +#define MV64360_INTERNAL_SPACE_BASE_ADDR 0x068 + +/* Enables the CS , DEV_CS , PCI 0 and PCI 1 + windows above */ +#define MV64360_BASE_ADDR_ENABLE 0x278 + +/****************************************/ +/* PCI remap registers */ +/****************************************/ + /* PCI 0 */ +#define MV64360_PCI_0_IO_ADDR_REMAP 0x0f0 +#define MV64360_PCI_0_MEMORY0_LOW_ADDR_REMAP 0x0f8 +#define MV64360_PCI_0_MEMORY0_HIGH_ADDR_REMAP 0x320 +#define MV64360_PCI_0_MEMORY1_LOW_ADDR_REMAP 0x100 +#define MV64360_PCI_0_MEMORY1_HIGH_ADDR_REMAP 0x328 +#define MV64360_PCI_0_MEMORY2_LOW_ADDR_REMAP 0x2f8 +#define MV64360_PCI_0_MEMORY2_HIGH_ADDR_REMAP 0x330 +#define MV64360_PCI_0_MEMORY3_LOW_ADDR_REMAP 0x300 +#define MV64360_PCI_0_MEMORY3_HIGH_ADDR_REMAP 0x338 + /* PCI 1 */ +#define MV64360_PCI_1_IO_ADDR_REMAP 0x108 +#define MV64360_PCI_1_MEMORY0_LOW_ADDR_REMAP 0x110 +#define MV64360_PCI_1_MEMORY0_HIGH_ADDR_REMAP 0x340 +#define MV64360_PCI_1_MEMORY1_LOW_ADDR_REMAP 0x118 +#define MV64360_PCI_1_MEMORY1_HIGH_ADDR_REMAP 0x348 +#define MV64360_PCI_1_MEMORY2_LOW_ADDR_REMAP 0x310 +#define MV64360_PCI_1_MEMORY2_HIGH_ADDR_REMAP 0x350 +#define MV64360_PCI_1_MEMORY3_LOW_ADDR_REMAP 0x318 +#define MV64360_PCI_1_MEMORY3_HIGH_ADDR_REMAP 0x358 + +#define MV64360_CPU_PCI_0_HEADERS_RETARGET_CONTROL 0x3b0 +#define MV64360_CPU_PCI_0_HEADERS_RETARGET_BASE 0x3b8 +#define MV64360_CPU_PCI_1_HEADERS_RETARGET_CONTROL 0x3c0 +#define MV64360_CPU_PCI_1_HEADERS_RETARGET_BASE 0x3c8 +#define MV64360_CPU_GE_HEADERS_RETARGET_CONTROL 0x3d0 +#define MV64360_CPU_GE_HEADERS_RETARGET_BASE 0x3d8 +#define MV64360_CPU_IDMA_HEADERS_RETARGET_CONTROL 0x3e0 +#define MV64360_CPU_IDMA_HEADERS_RETARGET_BASE 0x3e8 + +/****************************************/ +/* CPU Control Registers */ +/****************************************/ + +#define MV64360_CPU_CONFIG 0x000 +#define MV64360_CPU_MODE 0x120 +#define MV64360_CPU_MASTER_CONTROL 0x160 +#define MV64360_CPU_CROSS_BAR_CONTROL_LOW 0x150 +#define MV64360_CPU_CROSS_BAR_CONTROL_HIGH 0x158 +#define MV64360_CPU_CROSS_BAR_TIMEOUT 0x168 + +/****************************************/ +/* SMP RegisterS */ +/****************************************/ + +#define MV64360_SMP_WHO_AM_I 0x200 +#define MV64360_SMP_CPU0_DOORBELL 0x214 +#define MV64360_SMP_CPU0_DOORBELL_CLEAR 0x21C +#define MV64360_SMP_CPU1_DOORBELL 0x224 +#define MV64360_SMP_CPU1_DOORBELL_CLEAR 0x22C +#define MV64360_SMP_CPU0_DOORBELL_MASK 0x234 +#define MV64360_SMP_CPU1_DOORBELL_MASK 0x23C +#define MV64360_SMP_SEMAPHOR0 0x244 +#define MV64360_SMP_SEMAPHOR1 0x24c +#define MV64360_SMP_SEMAPHOR2 0x254 +#define MV64360_SMP_SEMAPHOR3 0x25c +#define MV64360_SMP_SEMAPHOR4 0x264 +#define MV64360_SMP_SEMAPHOR5 0x26c +#define MV64360_SMP_SEMAPHOR6 0x274 +#define MV64360_SMP_SEMAPHOR7 0x27c + +/****************************************/ +/* CPU Sync Barrier Register */ +/****************************************/ + +#define MV64360_CPU_0_SYNC_BARRIER_TRIGGER 0x0c0 +#define MV64360_CPU_0_SYNC_BARRIER_VIRTUAL 0x0c8 +#define MV64360_CPU_1_SYNC_BARRIER_TRIGGER 0x0d0 +#define MV64360_CPU_1_SYNC_BARRIER_VIRTUAL 0x0d8 + +/****************************************/ +/* CPU Access Protect */ +/****************************************/ + +#define MV64360_CPU_PROTECT_WINDOW_0_BASE_ADDR 0x180 +#define MV64360_CPU_PROTECT_WINDOW_0_SIZE 0x188 +#define MV64360_CPU_PROTECT_WINDOW_1_BASE_ADDR 0x190 +#define MV64360_CPU_PROTECT_WINDOW_1_SIZE 0x198 +#define MV64360_CPU_PROTECT_WINDOW_2_BASE_ADDR 0x1a0 +#define MV64360_CPU_PROTECT_WINDOW_2_SIZE 0x1a8 +#define MV64360_CPU_PROTECT_WINDOW_3_BASE_ADDR 0x1b0 +#define MV64360_CPU_PROTECT_WINDOW_3_SIZE 0x1b8 + + +/****************************************/ +/* CPU Error Report */ +/****************************************/ + +#define MV64360_CPU_ERROR_ADDR_LOW 0x070 +#define MV64360_CPU_ERROR_ADDR_HIGH 0x078 +#define MV64360_CPU_ERROR_DATA_LOW 0x128 +#define MV64360_CPU_ERROR_DATA_HIGH 0x130 +#define MV64360_CPU_ERROR_PARITY 0x138 +#define MV64360_CPU_ERROR_CAUSE 0x140 +#define MV64360_CPU_ERROR_MASK 0x148 + +/****************************************/ +/* CPU Interface Debug Registers */ +/****************************************/ + +#define MV64360_PUNIT_SLAVE_DEBUG_LOW 0x360 +#define MV64360_PUNIT_SLAVE_DEBUG_HIGH 0x368 +#define MV64360_PUNIT_MASTER_DEBUG_LOW 0x370 +#define MV64360_PUNIT_MASTER_DEBUG_HIGH 0x378 +#define MV64360_PUNIT_MMASK 0x3e4 + +/****************************************/ +/* Integrated SRAM Registers */ +/****************************************/ + +#define MV64360_SRAM_CONFIG 0x380 +#define MV64360_SRAM_TEST_MODE 0X3F4 +#define MV64360_SRAM_ERROR_CAUSE 0x388 +#define MV64360_SRAM_ERROR_ADDR 0x390 +#define MV64360_SRAM_ERROR_ADDR_HIGH 0X3F8 +#define MV64360_SRAM_ERROR_DATA_LOW 0x398 +#define MV64360_SRAM_ERROR_DATA_HIGH 0x3a0 +#define MV64360_SRAM_ERROR_DATA_PARITY 0x3a8 + +/****************************************/ +/* SDRAM Configuration */ +/****************************************/ + +#define MV64360_SDRAM_CONFIG 0x1400 +#define MV64360_D_UNIT_CONTROL_LOW 0x1404 +#define MV64360_D_UNIT_CONTROL_HIGH 0x1424 +#define MV64360_SDRAM_TIMING_CONTROL_LOW 0x1408 +#define MV64360_SDRAM_TIMING_CONTROL_HIGH 0x140c +#define MV64360_SDRAM_ADDR_CONTROL 0x1410 +#define MV64360_SDRAM_OPEN_PAGES_CONTROL 0x1414 +#define MV64360_SDRAM_OPERATION 0x1418 +#define MV64360_SDRAM_MODE 0x141c +#define MV64360_EXTENDED_DRAM_MODE 0x1420 +#define MV64360_SDRAM_CROSS_BAR_CONTROL_LOW 0x1430 +#define MV64360_SDRAM_CROSS_BAR_CONTROL_HIGH 0x1434 +#define MV64360_SDRAM_CROSS_BAR_TIMEOUT 0x1438 +#define MV64360_SDRAM_ADDR_CTRL_PADS_CALIBRATION 0x14c0 +#define MV64360_SDRAM_DATA_PADS_CALIBRATION 0x14c4 + +/****************************************/ +/* SDRAM Error Report */ +/****************************************/ + +#define MV64360_SDRAM_ERROR_DATA_LOW 0x1444 +#define MV64360_SDRAM_ERROR_DATA_HIGH 0x1440 +#define MV64360_SDRAM_ERROR_ADDR 0x1450 +#define MV64360_SDRAM_RECEIVED_ECC 0x1448 +#define MV64360_SDRAM_CALCULATED_ECC 0x144c +#define MV64360_SDRAM_ECC_CONTROL 0x1454 +#define MV64360_SDRAM_ECC_ERROR_COUNTER 0x1458 + +/******************************************/ +/* Controlled Delay Line (CDL) Registers */ +/******************************************/ + +#define MV64360_DFCDL_CONFIG0 0x1480 +#define MV64360_DFCDL_CONFIG1 0x1484 +#define MV64360_DLL_WRITE 0x1488 +#define MV64360_DLL_READ 0x148c +#define MV64360_SRAM_ADDR 0x1490 +#define MV64360_SRAM_DATA0 0x1494 +#define MV64360_SRAM_DATA1 0x1498 +#define MV64360_SRAM_DATA2 0x149c +#define MV64360_DFCL_PROBE 0x14a0 + +/******************************************/ +/* Debug Registers */ +/******************************************/ + +#define MV64360_DUNIT_DEBUG_LOW 0x1460 +#define MV64360_DUNIT_DEBUG_HIGH 0x1464 +#define MV64360_DUNIT_MMASK 0X1b40 + +/****************************************/ +/* Device Parameters */ +/****************************************/ + +#define MV64360_DEVICE_BANK0_PARAMETERS 0x45c +#define MV64360_DEVICE_BANK1_PARAMETERS 0x460 +#define MV64360_DEVICE_BANK2_PARAMETERS 0x464 +#define MV64360_DEVICE_BANK3_PARAMETERS 0x468 +#define MV64360_DEVICE_BOOT_BANK_PARAMETERS 0x46c +#define MV64360_DEVICE_INTERFACE_CONTROL 0x4c0 +#define MV64360_DEVICE_INTERFACE_CROSS_BAR_CONTROL_LOW 0x4c8 +#define MV64360_DEVICE_INTERFACE_CROSS_BAR_CONTROL_HIGH 0x4cc +#define MV64360_DEVICE_INTERFACE_CROSS_BAR_TIMEOUT 0x4c4 + +/****************************************/ +/* Device interrupt registers */ +/****************************************/ + +#define MV64360_DEVICE_INTERRUPT_CAUSE 0x4d0 +#define MV64360_DEVICE_INTERRUPT_MASK 0x4d4 +#define MV64360_DEVICE_ERROR_ADDR 0x4d8 +#define MV64360_DEVICE_ERROR_DATA 0x4dc +#define MV64360_DEVICE_ERROR_PARITY 0x4e0 + +/****************************************/ +/* Device debug registers */ +/****************************************/ + +#define MV64360_DEVICE_DEBUG_LOW 0x4e4 +#define MV64360_DEVICE_DEBUG_HIGH 0x4e8 +#define MV64360_RUNIT_MMASK 0x4f0 + +/****************************************/ +/* PCI Slave Address Decoding registers */ +/****************************************/ + +#define MV64360_PCI_0_CS_0_BANK_SIZE 0xc08 +#define MV64360_PCI_1_CS_0_BANK_SIZE 0xc88 +#define MV64360_PCI_0_CS_1_BANK_SIZE 0xd08 +#define MV64360_PCI_1_CS_1_BANK_SIZE 0xd88 +#define MV64360_PCI_0_CS_2_BANK_SIZE 0xc0c +#define MV64360_PCI_1_CS_2_BANK_SIZE 0xc8c +#define MV64360_PCI_0_CS_3_BANK_SIZE 0xd0c +#define MV64360_PCI_1_CS_3_BANK_SIZE 0xd8c +#define MV64360_PCI_0_DEVCS_0_BANK_SIZE 0xc10 +#define MV64360_PCI_1_DEVCS_0_BANK_SIZE 0xc90 +#define MV64360_PCI_0_DEVCS_1_BANK_SIZE 0xd10 +#define MV64360_PCI_1_DEVCS_1_BANK_SIZE 0xd90 +#define MV64360_PCI_0_DEVCS_2_BANK_SIZE 0xd18 +#define MV64360_PCI_1_DEVCS_2_BANK_SIZE 0xd98 +#define MV64360_PCI_0_DEVCS_3_BANK_SIZE 0xc14 +#define MV64360_PCI_1_DEVCS_3_BANK_SIZE 0xc94 +#define MV64360_PCI_0_DEVCS_BOOT_BANK_SIZE 0xd14 +#define MV64360_PCI_1_DEVCS_BOOT_BANK_SIZE 0xd94 +#define MV64360_PCI_0_P2P_MEM0_BAR_SIZE 0xd1c +#define MV64360_PCI_1_P2P_MEM0_BAR_SIZE 0xd9c +#define MV64360_PCI_0_P2P_MEM1_BAR_SIZE 0xd20 +#define MV64360_PCI_1_P2P_MEM1_BAR_SIZE 0xda0 +#define MV64360_PCI_0_P2P_I_O_BAR_SIZE 0xd24 +#define MV64360_PCI_1_P2P_I_O_BAR_SIZE 0xda4 +#define MV64360_PCI_0_CPU_BAR_SIZE 0xd28 +#define MV64360_PCI_1_CPU_BAR_SIZE 0xda8 +#define MV64360_PCI_0_INTERNAL_SRAM_BAR_SIZE 0xe00 +#define MV64360_PCI_1_INTERNAL_SRAM_BAR_SIZE 0xe80 +#define MV64360_PCI_0_EXPANSION_ROM_BAR_SIZE 0xd2c +#define MV64360_PCI_1_EXPANSION_ROM_BAR_SIZE 0xd9c +#define MV64360_PCI_0_BASE_ADDR_REG_ENABLE 0xc3c +#define MV64360_PCI_1_BASE_ADDR_REG_ENABLE 0xcbc +#define MV64360_PCI_0_CS_0_BASE_ADDR_REMAP 0xc48 +#define MV64360_PCI_1_CS_0_BASE_ADDR_REMAP 0xcc8 +#define MV64360_PCI_0_CS_1_BASE_ADDR_REMAP 0xd48 +#define MV64360_PCI_1_CS_1_BASE_ADDR_REMAP 0xdc8 +#define MV64360_PCI_0_CS_2_BASE_ADDR_REMAP 0xc4c +#define MV64360_PCI_1_CS_2_BASE_ADDR_REMAP 0xccc +#define MV64360_PCI_0_CS_3_BASE_ADDR_REMAP 0xd4c +#define MV64360_PCI_1_CS_3_BASE_ADDR_REMAP 0xdcc +#define MV64360_PCI_0_CS_0_BASE_HIGH_ADDR_REMAP 0xF04 +#define MV64360_PCI_1_CS_0_BASE_HIGH_ADDR_REMAP 0xF84 +#define MV64360_PCI_0_CS_1_BASE_HIGH_ADDR_REMAP 0xF08 +#define MV64360_PCI_1_CS_1_BASE_HIGH_ADDR_REMAP 0xF88 +#define MV64360_PCI_0_CS_2_BASE_HIGH_ADDR_REMAP 0xF0C +#define MV64360_PCI_1_CS_2_BASE_HIGH_ADDR_REMAP 0xF8C +#define MV64360_PCI_0_CS_3_BASE_HIGH_ADDR_REMAP 0xF10 +#define MV64360_PCI_1_CS_3_BASE_HIGH_ADDR_REMAP 0xF90 +#define MV64360_PCI_0_DEVCS_0_BASE_ADDR_REMAP 0xc50 +#define MV64360_PCI_1_DEVCS_0_BASE_ADDR_REMAP 0xcd0 +#define MV64360_PCI_0_DEVCS_1_BASE_ADDR_REMAP 0xd50 +#define MV64360_PCI_1_DEVCS_1_BASE_ADDR_REMAP 0xdd0 +#define MV64360_PCI_0_DEVCS_2_BASE_ADDR_REMAP 0xd58 +#define MV64360_PCI_1_DEVCS_2_BASE_ADDR_REMAP 0xdd8 +#define MV64360_PCI_0_DEVCS_3_BASE_ADDR_REMAP 0xc54 +#define MV64360_PCI_1_DEVCS_3_BASE_ADDR_REMAP 0xcd4 +#define MV64360_PCI_0_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xd54 +#define MV64360_PCI_1_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xdd4 +#define MV64360_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xd5c +#define MV64360_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xddc +#define MV64360_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xd60 +#define MV64360_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xde0 +#define MV64360_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xd64 +#define MV64360_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xde4 +#define MV64360_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xd68 +#define MV64360_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xde8 +#define MV64360_PCI_0_P2P_I_O_BASE_ADDR_REMAP 0xd6c +#define MV64360_PCI_1_P2P_I_O_BASE_ADDR_REMAP 0xdec +#define MV64360_PCI_0_CPU_BASE_ADDR_REMAP_LOW 0xd70 +#define MV64360_PCI_1_CPU_BASE_ADDR_REMAP_LOW 0xdf0 +#define MV64360_PCI_0_CPU_BASE_ADDR_REMAP_HIGH 0xd74 +#define MV64360_PCI_1_CPU_BASE_ADDR_REMAP_HIGH 0xdf4 +#define MV64360_PCI_0_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf00 +#define MV64360_PCI_1_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf80 +#define MV64360_PCI_0_EXPANSION_ROM_BASE_ADDR_REMAP 0xf38 +#define MV64360_PCI_1_EXPANSION_ROM_BASE_ADDR_REMAP 0xfb8 +#define MV64360_PCI_0_ADDR_DECODE_CONTROL 0xd3c +#define MV64360_PCI_1_ADDR_DECODE_CONTROL 0xdbc +#define MV64360_PCI_0_HEADERS_RETARGET_CONTROL 0xF40 +#define MV64360_PCI_1_HEADERS_RETARGET_CONTROL 0xFc0 +#define MV64360_PCI_0_HEADERS_RETARGET_BASE 0xF44 +#define MV64360_PCI_1_HEADERS_RETARGET_BASE 0xFc4 +#define MV64360_PCI_0_HEADERS_RETARGET_HIGH 0xF48 +#define MV64360_PCI_1_HEADERS_RETARGET_HIGH 0xFc8 + +/***********************************/ +/* PCI Control Register Map */ +/***********************************/ + +#define MV64360_PCI_0_DLL_STATUS_AND_COMMAND 0x1d20 +#define MV64360_PCI_1_DLL_STATUS_AND_COMMAND 0x1da0 +#define MV64360_PCI_0_MPP_PADS_DRIVE_CONTROL 0x1d1C +#define MV64360_PCI_1_MPP_PADS_DRIVE_CONTROL 0x1d9C +#define MV64360_PCI_0_COMMAND 0xc00 +#define MV64360_PCI_1_COMMAND 0xc80 +#define MV64360_PCI_0_MODE 0xd00 +#define MV64360_PCI_1_MODE 0xd80 +#define MV64360_PCI_0_RETRY 0xc04 +#define MV64360_PCI_1_RETRY 0xc84 +#define MV64360_PCI_0_READ_BUFFER_DISCARD_TIMER 0xd04 +#define MV64360_PCI_1_READ_BUFFER_DISCARD_TIMER 0xd84 +#define MV64360_PCI_0_MSI_TRIGGER_TIMER 0xc38 +#define MV64360_PCI_1_MSI_TRIGGER_TIMER 0xcb8 +#define MV64360_PCI_0_ARBITER_CONTROL 0x1d00 +#define MV64360_PCI_1_ARBITER_CONTROL 0x1d80 +#define MV64360_PCI_0_CROSS_BAR_CONTROL_LOW 0x1d08 +#define MV64360_PCI_1_CROSS_BAR_CONTROL_LOW 0x1d88 +#define MV64360_PCI_0_CROSS_BAR_CONTROL_HIGH 0x1d0c +#define MV64360_PCI_1_CROSS_BAR_CONTROL_HIGH 0x1d8c +#define MV64360_PCI_0_CROSS_BAR_TIMEOUT 0x1d04 +#define MV64360_PCI_1_CROSS_BAR_TIMEOUT 0x1d84 +#define MV64360_PCI_0_SYNC_BARRIER_TRIGGER_REG 0x1D18 +#define MV64360_PCI_1_SYNC_BARRIER_TRIGGER_REG 0x1D98 +#define MV64360_PCI_0_SYNC_BARRIER_VIRTUAL_REG 0x1d10 +#define MV64360_PCI_1_SYNC_BARRIER_VIRTUAL_REG 0x1d90 +#define MV64360_PCI_0_P2P_CONFIG 0x1d14 +#define MV64360_PCI_1_P2P_CONFIG 0x1d94 + +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_0_LOW 0x1e00 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_0_HIGH 0x1e04 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_0 0x1e08 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_1_LOW 0x1e10 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_1_HIGH 0x1e14 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_1 0x1e18 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_2_LOW 0x1e20 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_2_HIGH 0x1e24 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_2 0x1e28 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_3_LOW 0x1e30 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_3_HIGH 0x1e34 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_3 0x1e38 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_4_LOW 0x1e40 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_4_HIGH 0x1e44 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_4 0x1e48 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_5_LOW 0x1e50 +#define MV64360_PCI_0_ACCESS_CONTROL_BASE_5_HIGH 0x1e54 +#define MV64360_PCI_0_ACCESS_CONTROL_SIZE_5 0x1e58 + +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_0_LOW 0x1e80 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_0_HIGH 0x1e84 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_0 0x1e88 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_1_LOW 0x1e90 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_1_HIGH 0x1e94 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_1 0x1e98 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_2_LOW 0x1ea0 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_2_HIGH 0x1ea4 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_2 0x1ea8 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_3_LOW 0x1eb0 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_3_HIGH 0x1eb4 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_3 0x1eb8 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_4_LOW 0x1ec0 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_4_HIGH 0x1ec4 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_4 0x1ec8 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_5_LOW 0x1ed0 +#define MV64360_PCI_1_ACCESS_CONTROL_BASE_5_HIGH 0x1ed4 +#define MV64360_PCI_1_ACCESS_CONTROL_SIZE_5 0x1ed8 + +/****************************************/ +/* PCI Configuration Access Registers */ +/****************************************/ + +#define MV64360_PCI_0_CONFIG_ADDR 0xcf8 +#define MV64360_PCI_0_CONFIG_DATA_VIRTUAL_REG 0xcfc +#define MV64360_PCI_1_CONFIG_ADDR 0xc78 +#define MV64360_PCI_1_CONFIG_DATA_VIRTUAL_REG 0xc7c +#define MV64360_PCI_0_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xc34 +#define MV64360_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xcb4 + +/****************************************/ +/* PCI Error Report Registers */ +/****************************************/ + +#define MV64360_PCI_0_SERR_MASK 0xc28 +#define MV64360_PCI_1_SERR_MASK 0xca8 +#define MV64360_PCI_0_ERROR_ADDR_LOW 0x1d40 +#define MV64360_PCI_1_ERROR_ADDR_LOW 0x1dc0 +#define MV64360_PCI_0_ERROR_ADDR_HIGH 0x1d44 +#define MV64360_PCI_1_ERROR_ADDR_HIGH 0x1dc4 +#define MV64360_PCI_0_ERROR_ATTRIBUTE 0x1d48 +#define MV64360_PCI_1_ERROR_ATTRIBUTE 0x1dc8 +#define MV64360_PCI_0_ERROR_COMMAND 0x1d50 +#define MV64360_PCI_1_ERROR_COMMAND 0x1dd0 +#define MV64360_PCI_0_ERROR_CAUSE 0x1d58 +#define MV64360_PCI_1_ERROR_CAUSE 0x1dd8 +#define MV64360_PCI_0_ERROR_MASK 0x1d5c +#define MV64360_PCI_1_ERROR_MASK 0x1ddc + +/****************************************/ +/* PCI Debug Registers */ +/****************************************/ + +#define MV64360_PCI_0_MMASK 0X1D24 +#define MV64360_PCI_1_MMASK 0X1DA4 + +/*********************************************/ +/* PCI Configuration, Function 0, Registers */ +/*********************************************/ + +#define MV64360_PCI_DEVICE_AND_VENDOR_ID 0x000 +#define MV64360_PCI_STATUS_AND_COMMAND 0x004 +#define MV64360_PCI_CLASS_CODE_AND_REVISION_ID 0x008 +#define MV64360_PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE 0x00C + +#define MV64360_PCI_SCS_0_BASE_ADDR_LOW 0x010 +#define MV64360_PCI_SCS_0_BASE_ADDR_HIGH 0x014 +#define MV64360_PCI_SCS_1_BASE_ADDR_LOW 0x018 +#define MV64360_PCI_SCS_1_BASE_ADDR_HIGH 0x01C +#define MV64360_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_LOW 0x020 +#define MV64360_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_HIGH 0x024 +#define MV64360_PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID 0x02c +#define MV64360_PCI_EXPANSION_ROM_BASE_ADDR_REG 0x030 +#define MV64360_PCI_CAPABILTY_LIST_POINTER 0x034 +#define MV64360_PCI_INTERRUPT_PIN_AND_LINE 0x03C + /* capability list */ +#define MV64360_PCI_POWER_MANAGEMENT_CAPABILITY 0x040 +#define MV64360_PCI_POWER_MANAGEMENT_STATUS_AND_CONTROL 0x044 +#define MV64360_PCI_VPD_ADDR 0x048 +#define MV64360_PCI_VPD_DATA 0x04c +#define MV64360_PCI_MSI_MESSAGE_CONTROL 0x050 +#define MV64360_PCI_MSI_MESSAGE_ADDR 0x054 +#define MV64360_PCI_MSI_MESSAGE_UPPER_ADDR 0x058 +#define MV64360_PCI_MSI_MESSAGE_DATA 0x05c +#define MV64360_PCI_X_COMMAND 0x060 +#define MV64360_PCI_X_STATUS 0x064 +#define MV64360_PCI_COMPACT_PCI_HOT_SWAP 0x068 + +/***********************************************/ +/* PCI Configuration, Function 1, Registers */ +/***********************************************/ + +#define MV64360_PCI_SCS_2_BASE_ADDR_LOW 0x110 +#define MV64360_PCI_SCS_2_BASE_ADDR_HIGH 0x114 +#define MV64360_PCI_SCS_3_BASE_ADDR_LOW 0x118 +#define MV64360_PCI_SCS_3_BASE_ADDR_HIGH 0x11c +#define MV64360_PCI_INTERNAL_SRAM_BASE_ADDR_LOW 0x120 +#define MV64360_PCI_INTERNAL_SRAM_BASE_ADDR_HIGH 0x124 + +/***********************************************/ +/* PCI Configuration, Function 2, Registers */ +/***********************************************/ + +#define MV64360_PCI_DEVCS_0_BASE_ADDR_LOW 0x210 +#define MV64360_PCI_DEVCS_0_BASE_ADDR_HIGH 0x214 +#define MV64360_PCI_DEVCS_1_BASE_ADDR_LOW 0x218 +#define MV64360_PCI_DEVCS_1_BASE_ADDR_HIGH 0x21c +#define MV64360_PCI_DEVCS_2_BASE_ADDR_LOW 0x220 +#define MV64360_PCI_DEVCS_2_BASE_ADDR_HIGH 0x224 + +/***********************************************/ +/* PCI Configuration, Function 3, Registers */ +/***********************************************/ + +#define MV64360_PCI_DEVCS_3_BASE_ADDR_LOW 0x310 +#define MV64360_PCI_DEVCS_3_BASE_ADDR_HIGH 0x314 +#define MV64360_PCI_BOOT_CS_BASE_ADDR_LOW 0x318 +#define MV64360_PCI_BOOT_CS_BASE_ADDR_HIGH 0x31c +#define MV64360_PCI_CPU_BASE_ADDR_LOW 0x220 +#define MV64360_PCI_CPU_BASE_ADDR_HIGH 0x224 + +/***********************************************/ +/* PCI Configuration, Function 4, Registers */ +/***********************************************/ + +#define MV64360_PCI_P2P_MEM0_BASE_ADDR_LOW 0x410 +#define MV64360_PCI_P2P_MEM0_BASE_ADDR_HIGH 0x414 +#define MV64360_PCI_P2P_MEM1_BASE_ADDR_LOW 0x418 +#define MV64360_PCI_P2P_MEM1_BASE_ADDR_HIGH 0x41c +#define MV64360_PCI_P2P_I_O_BASE_ADDR 0x420 +#define MV64360_PCI_INTERNAL_REGS_I_O_MAPPED_BASE_ADDR 0x424 + +/****************************************/ +/* Messaging Unit Registers (I20) */ +/****************************************/ + +#define MV64360_I2O_INBOUND_MESSAGE_REG0_PCI_0_SIDE 0x010 +#define MV64360_I2O_INBOUND_MESSAGE_REG1_PCI_0_SIDE 0x014 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG0_PCI_0_SIDE 0x018 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG1_PCI_0_SIDE 0x01C +#define MV64360_I2O_INBOUND_DOORBELL_REG_PCI_0_SIDE 0x020 +#define MV64360_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x024 +#define MV64360_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x028 +#define MV64360_I2O_OUTBOUND_DOORBELL_REG_PCI_0_SIDE 0x02C +#define MV64360_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x030 +#define MV64360_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x034 +#define MV64360_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x040 +#define MV64360_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x044 +#define MV64360_I2O_QUEUE_CONTROL_REG_PCI_0_SIDE 0x050 +#define MV64360_I2O_QUEUE_BASE_ADDR_REG_PCI_0_SIDE 0x054 +#define MV64360_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x060 +#define MV64360_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x064 +#define MV64360_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x068 +#define MV64360_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x06C +#define MV64360_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x070 +#define MV64360_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x074 +#define MV64360_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x0F8 +#define MV64360_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x0FC + +#define MV64360_I2O_INBOUND_MESSAGE_REG0_PCI_1_SIDE 0x090 +#define MV64360_I2O_INBOUND_MESSAGE_REG1_PCI_1_SIDE 0x094 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG0_PCI_1_SIDE 0x098 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG1_PCI_1_SIDE 0x09C +#define MV64360_I2O_INBOUND_DOORBELL_REG_PCI_1_SIDE 0x0A0 +#define MV64360_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0A4 +#define MV64360_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0A8 +#define MV64360_I2O_OUTBOUND_DOORBELL_REG_PCI_1_SIDE 0x0AC +#define MV64360_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0B0 +#define MV64360_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0B4 +#define MV64360_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C0 +#define MV64360_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C4 +#define MV64360_I2O_QUEUE_CONTROL_REG_PCI_1_SIDE 0x0D0 +#define MV64360_I2O_QUEUE_BASE_ADDR_REG_PCI_1_SIDE 0x0D4 +#define MV64360_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0E0 +#define MV64360_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0E4 +#define MV64360_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x0E8 +#define MV64360_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x0EC +#define MV64360_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0F0 +#define MV64360_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0F4 +#define MV64360_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x078 +#define MV64360_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x07C + +#define MV64360_I2O_INBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C10 +#define MV64360_I2O_INBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C14 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C18 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C1C +#define MV64360_I2O_INBOUND_DOORBELL_REG_CPU0_SIDE 0x1C20 +#define MV64360_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C24 +#define MV64360_I2O_INBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C28 +#define MV64360_I2O_OUTBOUND_DOORBELL_REG_CPU0_SIDE 0x1C2C +#define MV64360_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C30 +#define MV64360_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C34 +#define MV64360_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C40 +#define MV64360_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C44 +#define MV64360_I2O_QUEUE_CONTROL_REG_CPU0_SIDE 0x1C50 +#define MV64360_I2O_QUEUE_BASE_ADDR_REG_CPU0_SIDE 0x1C54 +#define MV64360_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C60 +#define MV64360_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C64 +#define MV64360_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1C68 +#define MV64360_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1C6C +#define MV64360_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C70 +#define MV64360_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C74 +#define MV64360_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1CF8 +#define MV64360_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1CFC +#define MV64360_I2O_INBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C90 +#define MV64360_I2O_INBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C94 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C98 +#define MV64360_I2O_OUTBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C9C +#define MV64360_I2O_INBOUND_DOORBELL_REG_CPU1_SIDE 0x1CA0 +#define MV64360_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CA4 +#define MV64360_I2O_INBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CA8 +#define MV64360_I2O_OUTBOUND_DOORBELL_REG_CPU1_SIDE 0x1CAC +#define MV64360_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CB0 +#define MV64360_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CB4 +#define MV64360_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC0 +#define MV64360_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC4 +#define MV64360_I2O_QUEUE_CONTROL_REG_CPU1_SIDE 0x1CD0 +#define MV64360_I2O_QUEUE_BASE_ADDR_REG_CPU1_SIDE 0x1CD4 +#define MV64360_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CE0 +#define MV64360_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CE4 +#define MV64360_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1CE8 +#define MV64360_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1CEC +#define MV64360_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CF0 +#define MV64360_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CF4 +#define MV64360_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1C78 +#define MV64360_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1C7C + +/****************************************/ +/* Ethernet Unit Registers */ +/****************************************/ + +#define MV64360_ETH_PHY_ADDR_REG 0x2000 +#define MV64360_ETH_SMI_REG 0x2004 +#define MV64360_ETH_UNIT_DEFAULT_ADDR_REG 0x2008 +#define MV64360_ETH_UNIT_DEFAULTID_REG 0x200c +#define MV64360_ETH_UNIT_INTERRUPT_CAUSE_REG 0x2080 +#define MV64360_ETH_UNIT_INTERRUPT_MASK_REG 0x2084 +#define MV64360_ETH_UNIT_INTERNAL_USE_REG 0x24fc +#define MV64360_ETH_UNIT_ERROR_ADDR_REG 0x2094 +#define MV64360_ETH_BAR_0 0x2200 +#define MV64360_ETH_BAR_1 0x2208 +#define MV64360_ETH_BAR_2 0x2210 +#define MV64360_ETH_BAR_3 0x2218 +#define MV64360_ETH_BAR_4 0x2220 +#define MV64360_ETH_BAR_5 0x2228 +#define MV64360_ETH_SIZE_REG_0 0x2204 +#define MV64360_ETH_SIZE_REG_1 0x220c +#define MV64360_ETH_SIZE_REG_2 0x2214 +#define MV64360_ETH_SIZE_REG_3 0x221c +#define MV64360_ETH_SIZE_REG_4 0x2224 +#define MV64360_ETH_SIZE_REG_5 0x222c +#define MV64360_ETH_HEADERS_RETARGET_BASE_REG 0x2230 +#define MV64360_ETH_HEADERS_RETARGET_CONTROL_REG 0x2234 +#define MV64360_ETH_HIGH_ADDR_REMAP_REG_0 0x2280 +#define MV64360_ETH_HIGH_ADDR_REMAP_REG_1 0x2284 +#define MV64360_ETH_HIGH_ADDR_REMAP_REG_2 0x2288 +#define MV64360_ETH_HIGH_ADDR_REMAP_REG_3 0x228c +#define MV64360_ETH_BASE_ADDR_ENABLE_REG 0x2290 +#define MV64360_ETH_ACCESS_PROTECTION_REG(port) (0x2294 + (port<<2)) +#define MV64360_ETH_MIB_COUNTERS_BASE(port) (0x3000 + (port<<7)) +#define MV64360_ETH_PORT_CONFIG_REG(port) (0x2400 + (port<<10)) +#define MV64360_ETH_PORT_CONFIG_EXTEND_REG(port) (0x2404 + (port<<10)) +#define MV64360_ETH_MII_SERIAL_PARAMETRS_REG(port) (0x2408 + (port<<10)) +#define MV64360_ETH_GMII_SERIAL_PARAMETRS_REG(port) (0x240c + (port<<10)) +#define MV64360_ETH_VLAN_ETHERTYPE_REG(port) (0x2410 + (port<<10)) +#define MV64360_ETH_MAC_ADDR_LOW(port) (0x2414 + (port<<10)) +#define MV64360_ETH_MAC_ADDR_HIGH(port) (0x2418 + (port<<10)) +#define MV64360_ETH_SDMA_CONFIG_REG(port) (0x241c + (port<<10)) +#define MV64360_ETH_DSCP_0(port) (0x2420 + (port<<10)) +#define MV64360_ETH_DSCP_1(port) (0x2424 + (port<<10)) +#define MV64360_ETH_DSCP_2(port) (0x2428 + (port<<10)) +#define MV64360_ETH_DSCP_3(port) (0x242c + (port<<10)) +#define MV64360_ETH_DSCP_4(port) (0x2430 + (port<<10)) +#define MV64360_ETH_DSCP_5(port) (0x2434 + (port<<10)) +#define MV64360_ETH_DSCP_6(port) (0x2438 + (port<<10)) +#define MV64360_ETH_PORT_SERIAL_CONTROL_REG(port) (0x243c + (port<<10)) +#define MV64360_ETH_VLAN_PRIORITY_TAG_TO_PRIORITY(port) (0x2440 + (port<<10)) +#define MV64360_ETH_PORT_STATUS_REG(port) (0x2444 + (port<<10)) +#define MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG(port) (0x2448 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_FIXED_PRIORITY(port) (0x244c + (port<<10)) +#define MV64360_ETH_PORT_TX_TOKEN_BUCKET_RATE_CONFIG(port) (0x2450 + (port<<10)) +#define MV64360_ETH_MAXIMUM_TRANSMIT_UNIT(port) (0x2458 + (port<<10)) +#define MV64360_ETH_PORT_MAXIMUM_TOKEN_BUCKET_SIZE(port) (0x245c + (port<<10)) +#define MV64360_ETH_INTERRUPT_CAUSE_REG(port) (0x2460 + (port<<10)) +#define MV64360_ETH_INTERRUPT_CAUSE_EXTEND_REG(port) (0x2464 + (port<<10)) +#define MV64360_ETH_INTERRUPT_MASK_REG(port) (0x2468 + (port<<10)) +#define MV64360_ETH_INTERRUPT_EXTEND_MASK_REG(port) (0x246c + (port<<10)) +#define MV64360_ETH_RX_FIFO_URGENT_THRESHOLD_REG(port) (0x2470 + (port<<10)) +#define MV64360_ETH_TX_FIFO_URGENT_THRESHOLD_REG(port) (0x2474 + (port<<10)) +#define MV64360_ETH_RX_MINIMAL_FRAME_SIZE_REG(port) (0x247c + (port<<10)) +#define MV64360_ETH_RX_DISCARDED_FRAMES_COUNTER(port) (0x2484 + (port<<10) +#define MV64360_ETH_PORT_DEBUG_0_REG(port) (0x248c + (port<<10)) +#define MV64360_ETH_PORT_DEBUG_1_REG(port) (0x2490 + (port<<10)) +#define MV64360_ETH_PORT_INTERNAL_ADDR_ERROR_REG(port) (0x2494 + (port<<10)) +#define MV64360_ETH_INTERNAL_USE_REG(port) (0x24fc + (port<<10)) +#define MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG(port) (0x2680 + (port<<10)) +#define MV64360_ETH_CURRENT_SERVED_TX_DESC_PTR(port) (0x2684 + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port) (0x260c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_1(port) (0x261c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_2(port) (0x262c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_3(port) (0x263c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_4(port) (0x264c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_5(port) (0x265c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_6(port) (0x266c + (port<<10)) +#define MV64360_ETH_RX_CURRENT_QUEUE_DESC_PTR_7(port) (0x267c + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port) (0x26c0 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_1(port) (0x26c4 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_2(port) (0x26c8 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_3(port) (0x26cc + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_4(port) (0x26d0 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_5(port) (0x26d4 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_6(port) (0x26d8 + (port<<10)) +#define MV64360_ETH_TX_CURRENT_QUEUE_DESC_PTR_7(port) (0x26dc + (port<<10)) +#define MV64360_ETH_TX_QUEUE_0_TOKEN_BUCKET_COUNT(port) (0x2700 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_1_TOKEN_BUCKET_COUNT(port) (0x2710 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_2_TOKEN_BUCKET_COUNT(port) (0x2720 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_3_TOKEN_BUCKET_COUNT(port) (0x2730 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_4_TOKEN_BUCKET_COUNT(port) (0x2740 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_5_TOKEN_BUCKET_COUNT(port) (0x2750 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_6_TOKEN_BUCKET_COUNT(port) (0x2760 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_7_TOKEN_BUCKET_COUNT(port) (0x2770 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_0_TOKEN_BUCKET_CONFIG(port) (0x2704 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_1_TOKEN_BUCKET_CONFIG(port) (0x2714 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_2_TOKEN_BUCKET_CONFIG(port) (0x2724 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_3_TOKEN_BUCKET_CONFIG(port) (0x2734 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_4_TOKEN_BUCKET_CONFIG(port) (0x2744 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_5_TOKEN_BUCKET_CONFIG(port) (0x2754 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_6_TOKEN_BUCKET_CONFIG(port) (0x2764 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_7_TOKEN_BUCKET_CONFIG(port) (0x2774 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_0_ARBITER_CONFIG(port) (0x2708 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_1_ARBITER_CONFIG(port) (0x2718 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_2_ARBITER_CONFIG(port) (0x2728 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_3_ARBITER_CONFIG(port) (0x2738 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_4_ARBITER_CONFIG(port) (0x2748 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_5_ARBITER_CONFIG(port) (0x2758 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_6_ARBITER_CONFIG(port) (0x2768 + (port<<10)) +#define MV64360_ETH_TX_QUEUE_7_ARBITER_CONFIG(port) (0x2778 + (port<<10)) +#define MV64360_ETH_PORT_TX_TOKEN_BUCKET_COUNT(port) (0x2780 + (port<<10)) +#define MV64360_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(port) (0x3400 + (port<<10)) +#define MV64360_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(port) (0x3500 + (port<<10)) +#define MV64360_ETH_DA_FILTER_UNICAST_TABLE_BASE(port) (0x3600 + (port<<10)) + +/*******************************************/ +/* CUNIT Registers */ +/*******************************************/ + + /* Address Decoding Register Map */ + +#define MV64360_CUNIT_BASE_ADDR_REG0 0xf200 +#define MV64360_CUNIT_BASE_ADDR_REG1 0xf208 +#define MV64360_CUNIT_BASE_ADDR_REG2 0xf210 +#define MV64360_CUNIT_BASE_ADDR_REG3 0xf218 +#define MV64360_CUNIT_SIZE0 0xf204 +#define MV64360_CUNIT_SIZE1 0xf20c +#define MV64360_CUNIT_SIZE2 0xf214 +#define MV64360_CUNIT_SIZE3 0xf21c +#define MV64360_CUNIT_HIGH_ADDR_REMAP_REG0 0xf240 +#define MV64360_CUNIT_HIGH_ADDR_REMAP_REG1 0xf244 +#define MV64360_CUNIT_BASE_ADDR_ENABLE_REG 0xf250 +#define MV64360_MPSC0_ACCESS_PROTECTION_REG 0xf254 +#define MV64360_MPSC1_ACCESS_PROTECTION_REG 0xf258 +#define MV64360_CUNIT_INTERNAL_SPACE_BASE_ADDR_REG 0xf25C + + /* Error Report Registers */ + +#define MV64360_CUNIT_INTERRUPT_CAUSE_REG 0xf310 +#define MV64360_CUNIT_INTERRUPT_MASK_REG 0xf314 +#define MV64360_CUNIT_ERROR_ADDR 0xf318 + + /* Cunit Control Registers */ + +#define MV64360_CUNIT_ARBITER_CONTROL_REG 0xf300 +#define MV64360_CUNIT_CONFIG_REG 0xb40c +#define MV64360_CUNIT_CRROSBAR_TIMEOUT_REG 0xf304 + + /* Cunit Debug Registers */ + +#define MV64360_CUNIT_DEBUG_LOW 0xf340 +#define MV64360_CUNIT_DEBUG_HIGH 0xf344 +#define MV64360_CUNIT_MMASK 0xf380 + + /* Cunit Base Address Enable Window Bits*/ +#define MV64360_CUNIT_BASE_ADDR_WIN_0_BIT 0x0 +#define MV64360_CUNIT_BASE_ADDR_WIN_1_BIT 0x1 +#define MV64360_CUNIT_BASE_ADDR_WIN_2_BIT 0x2 +#define MV64360_CUNIT_BASE_ADDR_WIN_3_BIT 0x3 + + /* MPSCs Clocks Routing Registers */ + +#define MV64360_MPSC_ROUTING_REG 0xb400 +#define MV64360_MPSC_RX_CLOCK_ROUTING_REG 0xb404 +#define MV64360_MPSC_TX_CLOCK_ROUTING_REG 0xb408 + + /* MPSCs Interrupts Registers */ + +#define MV64360_MPSC_CAUSE_REG(port) (0xb804 + (port<<3)) +#define MV64360_MPSC_MASK_REG(port) (0xb884 + (port<<3)) + +#define MV64360_MPSC_MAIN_CONFIG_LOW(port) (0x8000 + (port<<12)) +#define MV64360_MPSC_MAIN_CONFIG_HIGH(port) (0x8004 + (port<<12)) +#define MV64360_MPSC_PROTOCOL_CONFIG(port) (0x8008 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG1(port) (0x800c + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG2(port) (0x8010 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG3(port) (0x8014 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG4(port) (0x8018 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG5(port) (0x801c + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG6(port) (0x8020 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG7(port) (0x8024 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG8(port) (0x8028 + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG9(port) (0x802c + (port<<12)) +#define MV64360_MPSC_CHANNEL_REG10(port) (0x8030 + (port<<12)) + + /* MPSC0 Registers */ + + +/***************************************/ +/* SDMA Registers */ +/***************************************/ + +#define MV64360_SDMA_CONFIG_REG(channel) (0x4000 + (channel<<13)) +#define MV64360_SDMA_COMMAND_REG(channel) (0x4008 + (channel<<13)) +#define MV64360_SDMA_CURRENT_RX_DESCRIPTOR_POINTER(channel) (0x4810 + (channel<<13)) +#define MV64360_SDMA_CURRENT_TX_DESCRIPTOR_POINTER(channel) (0x4c10 + (channel<<13)) +#define MV64360_SDMA_FIRST_TX_DESCRIPTOR_POINTER(channel) (0x4c14 + (channel<<13)) + +#define MV64360_SDMA_CAUSE_REG 0xb800 +#define MV64360_SDMA_MASK_REG 0xb880 + + +/****************************************/ +/* SDMA Address Space Targets */ +/****************************************/ + +#define MV64360_SDMA_DRAM_CS_0_TARGET 0x0e00 +#define MV64360_SDMA_DRAM_CS_1_TARGET 0x0d00 +#define MV64360_SDMA_DRAM_CS_2_TARGET 0x0b00 +#define MV64360_SDMA_DRAM_CS_3_TARGET 0x0700 + +#define MV64360_SDMA_DEV_CS_0_TARGET 0x1e01 +#define MV64360_SDMA_DEV_CS_1_TARGET 0x1d01 +#define MV64360_SDMA_DEV_CS_2_TARGET 0x1b01 +#define MV64360_SDMA_DEV_CS_3_TARGET 0x1701 + +#define MV64360_SDMA_BOOT_CS_TARGET 0x0f00 + +#define MV64360_SDMA_SRAM_TARGET 0x0003 +#define MV64360_SDMA_60X_BUS_TARGET 0x4003 + +#define MV64360_PCI_0_TARGET 0x0003 +#define MV64360_PCI_1_TARGET 0x0004 + + +/* Devices BAR and size registers */ + +#define MV64360_DEV_CS0_BASE_ADDR 0x028 +#define MV64360_DEV_CS0_SIZE 0x030 +#define MV64360_DEV_CS1_BASE_ADDR 0x228 +#define MV64360_DEV_CS1_SIZE 0x230 +#define MV64360_DEV_CS2_BASE_ADDR 0x248 +#define MV64360_DEV_CS2_SIZE 0x250 +#define MV64360_DEV_CS3_BASE_ADDR 0x038 +#define MV64360_DEV_CS3_SIZE 0x040 +#define MV64360_BOOTCS_BASE_ADDR 0x238 +#define MV64360_BOOTCS_SIZE 0x240 + +/* SDMA Window access protection */ +#define MV64360_SDMA_WIN_ACCESS_NOT_ALLOWED 0 +#define MV64360_SDMA_WIN_ACCESS_READ_ONLY 1 +#define MV64360_SDMA_WIN_ACCESS_FULL 2 + +/* BRG Interrupts */ + +#define MV64360_BRG_CONFIG_REG(brg) (0xb200 + (brg<<3)) +#define MV64360_BRG_BAUDE_TUNING_REG(brg) (0xb204 + (brg<<3)) +#define MV64360_BRG_CAUSE_REG 0xb834 +#define MV64360_BRG_MASK_REG 0xb8b4 + +/****************************************/ +/* DMA Channel Control */ +/****************************************/ + +#define MV64360_DMA_CHANNEL0_CONTROL 0x840 +#define MV64360_DMA_CHANNEL0_CONTROL_HIGH 0x880 +#define MV64360_DMA_CHANNEL1_CONTROL 0x844 +#define MV64360_DMA_CHANNEL1_CONTROL_HIGH 0x884 +#define MV64360_DMA_CHANNEL2_CONTROL 0x848 +#define MV64360_DMA_CHANNEL2_CONTROL_HIGH 0x888 +#define MV64360_DMA_CHANNEL3_CONTROL 0x84C +#define MV64360_DMA_CHANNEL3_CONTROL_HIGH 0x88C + + +/****************************************/ +/* IDMA Registers */ +/****************************************/ + +#define MV64360_DMA_CHANNEL0_BYTE_COUNT 0x800 +#define MV64360_DMA_CHANNEL1_BYTE_COUNT 0x804 +#define MV64360_DMA_CHANNEL2_BYTE_COUNT 0x808 +#define MV64360_DMA_CHANNEL3_BYTE_COUNT 0x80C +#define MV64360_DMA_CHANNEL0_SOURCE_ADDR 0x810 +#define MV64360_DMA_CHANNEL1_SOURCE_ADDR 0x814 +#define MV64360_DMA_CHANNEL2_SOURCE_ADDR 0x818 +#define MV64360_DMA_CHANNEL3_SOURCE_ADDR 0x81c +#define MV64360_DMA_CHANNEL0_DESTINATION_ADDR 0x820 +#define MV64360_DMA_CHANNEL1_DESTINATION_ADDR 0x824 +#define MV64360_DMA_CHANNEL2_DESTINATION_ADDR 0x828 +#define MV64360_DMA_CHANNEL3_DESTINATION_ADDR 0x82C +#define MV64360_DMA_CHANNEL0_NEXT_DESCRIPTOR_POINTER 0x830 +#define MV64360_DMA_CHANNEL1_NEXT_DESCRIPTOR_POINTER 0x834 +#define MV64360_DMA_CHANNEL2_NEXT_DESCRIPTOR_POINTER 0x838 +#define MV64360_DMA_CHANNEL3_NEXT_DESCRIPTOR_POINTER 0x83C +#define MV64360_DMA_CHANNEL0_CURRENT_DESCRIPTOR_POINTER 0x870 +#define MV64360_DMA_CHANNEL1_CURRENT_DESCRIPTOR_POINTER 0x874 +#define MV64360_DMA_CHANNEL2_CURRENT_DESCRIPTOR_POINTER 0x878 +#define MV64360_DMA_CHANNEL3_CURRENT_DESCRIPTOR_POINTER 0x87C + + /* IDMA Address Decoding Base Address Registers */ + +#define MV64360_DMA_BASE_ADDR_REG0 0xa00 +#define MV64360_DMA_BASE_ADDR_REG1 0xa08 +#define MV64360_DMA_BASE_ADDR_REG2 0xa10 +#define MV64360_DMA_BASE_ADDR_REG3 0xa18 +#define MV64360_DMA_BASE_ADDR_REG4 0xa20 +#define MV64360_DMA_BASE_ADDR_REG5 0xa28 +#define MV64360_DMA_BASE_ADDR_REG6 0xa30 +#define MV64360_DMA_BASE_ADDR_REG7 0xa38 + + /* IDMA Address Decoding Size Address Register */ + +#define MV64360_DMA_SIZE_REG0 0xa04 +#define MV64360_DMA_SIZE_REG1 0xa0c +#define MV64360_DMA_SIZE_REG2 0xa14 +#define MV64360_DMA_SIZE_REG3 0xa1c +#define MV64360_DMA_SIZE_REG4 0xa24 +#define MV64360_DMA_SIZE_REG5 0xa2c +#define MV64360_DMA_SIZE_REG6 0xa34 +#define MV64360_DMA_SIZE_REG7 0xa3C + + /* IDMA Address Decoding High Address Remap and Access + Protection Registers */ + +#define MV64360_DMA_HIGH_ADDR_REMAP_REG0 0xa60 +#define MV64360_DMA_HIGH_ADDR_REMAP_REG1 0xa64 +#define MV64360_DMA_HIGH_ADDR_REMAP_REG2 0xa68 +#define MV64360_DMA_HIGH_ADDR_REMAP_REG3 0xa6C +#define MV64360_DMA_BASE_ADDR_ENABLE_REG 0xa80 +#define MV64360_DMA_CHANNEL0_ACCESS_PROTECTION_REG 0xa70 +#define MV64360_DMA_CHANNEL1_ACCESS_PROTECTION_REG 0xa74 +#define MV64360_DMA_CHANNEL2_ACCESS_PROTECTION_REG 0xa78 +#define MV64360_DMA_CHANNEL3_ACCESS_PROTECTION_REG 0xa7c +#define MV64360_DMA_ARBITER_CONTROL 0x860 +#define MV64360_DMA_CROSS_BAR_TIMEOUT 0x8d0 + + /* IDMA Headers Retarget Registers */ + +#define MV64360_DMA_HEADERS_RETARGET_CONTROL 0xa84 +#define MV64360_DMA_HEADERS_RETARGET_BASE 0xa88 + + /* IDMA Interrupt Register */ + +#define MV64360_DMA_INTERRUPT_CAUSE_REG 0x8c0 +#define MV64360_DMA_INTERRUPT_CAUSE_MASK 0x8c4 +#define MV64360_DMA_ERROR_ADDR 0x8c8 +#define MV64360_DMA_ERROR_SELECT 0x8cc + + /* IDMA Debug Register ( for internal use ) */ + +#define MV64360_DMA_DEBUG_LOW 0x8e0 +#define MV64360_DMA_DEBUG_HIGH 0x8e4 +#define MV64360_DMA_SPARE 0xA8C + +/****************************************/ +/* Timer_Counter */ +/****************************************/ + +#define MV64360_TIMER_COUNTER0 0x850 +#define MV64360_TIMER_COUNTER1 0x854 +#define MV64360_TIMER_COUNTER2 0x858 +#define MV64360_TIMER_COUNTER3 0x85C +#define MV64360_TIMER_COUNTER_0_3_CONTROL 0x864 +#define MV64360_TIMER_COUNTER_0_3_INTERRUPT_CAUSE 0x868 +#define MV64360_TIMER_COUNTER_0_3_INTERRUPT_MASK 0x86c + +/****************************************/ +/* Watchdog registers */ +/****************************************/ + +#define MV64360_WATCHDOG_CONFIG_REG 0xb410 +#define MV64360_WATCHDOG_VALUE_REG 0xb414 + +/****************************************/ +/* I2C Registers */ +/****************************************/ + +#define MV64360_I2C_SLAVE_ADDR 0xc000 +#define MV64360_I2C_EXTENDED_SLAVE_ADDR 0xc010 +#define MV64360_I2C_DATA 0xc004 +#define MV64360_I2C_CONTROL 0xc008 +#define MV64360_I2C_STATUS_BAUDE_RATE 0xc00C +#define MV64360_I2C_SOFT_RESET 0xc01c + +/****************************************/ +/* GPP Interface Registers */ +/****************************************/ + +#define MV64360_GPP_IO_CONTROL 0xf100 +#define MV64360_GPP_LEVEL_CONTROL 0xf110 +#define MV64360_GPP_VALUE 0xf104 +#define MV64360_GPP_INTERRUPT_CAUSE 0xf108 +#define MV64360_GPP_INTERRUPT_MASK0 0xf10c +#define MV64360_GPP_INTERRUPT_MASK1 0xf114 +#define MV64360_GPP_VALUE_SET 0xf118 +#define MV64360_GPP_VALUE_CLEAR 0xf11c + +/****************************************/ +/* Interrupt Controller Registers */ +/****************************************/ + +/****************************************/ +/* Interrupts */ +/****************************************/ + +#define MV64360_MAIN_INTERRUPT_CAUSE_LOW 0x004 +#define MV64360_MAIN_INTERRUPT_CAUSE_HIGH 0x00c +#define MV64360_CPU_INTERRUPT0_MASK_LOW 0x014 +#define MV64360_CPU_INTERRUPT0_MASK_HIGH 0x01c +#define MV64360_CPU_INTERRUPT0_SELECT_CAUSE 0x024 +#define MV64360_CPU_INTERRUPT1_MASK_LOW 0x034 +#define MV64360_CPU_INTERRUPT1_MASK_HIGH 0x03c +#define MV64360_CPU_INTERRUPT1_SELECT_CAUSE 0x044 +#define MV64360_INTERRUPT0_MASK_0_LOW 0x054 +#define MV64360_INTERRUPT0_MASK_0_HIGH 0x05c +#define MV64360_INTERRUPT0_SELECT_CAUSE 0x064 +#define MV64360_INTERRUPT1_MASK_0_LOW 0x074 +#define MV64360_INTERRUPT1_MASK_0_HIGH 0x07c +#define MV64360_INTERRUPT1_SELECT_CAUSE 0x084 + +/****************************************/ +/* MPP Interface Registers */ +/****************************************/ + +#define MV64360_MPP_CONTROL0 0xf000 +#define MV64360_MPP_CONTROL1 0xf004 +#define MV64360_MPP_CONTROL2 0xf008 +#define MV64360_MPP_CONTROL3 0xf00c + +/****************************************/ +/* Serial Initialization registers */ +/****************************************/ + +#define MV64360_SERIAL_INIT_LAST_DATA 0xf324 +#define MV64360_SERIAL_INIT_CONTROL 0xf328 +#define MV64360_SERIAL_INIT_STATUS 0xf32c + + +#endif /* __INCgt64360rh */ diff --git a/board/esd/cpci750/pci.c b/board/esd/cpci750/pci.c new file mode 100644 index 0000000000..3e44fb9737 --- /dev/null +++ b/board/esd/cpci750/pci.c @@ -0,0 +1,961 @@ +/* + * (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 + * + */ +/* PCI.c - PCI functions */ + + +#include +#ifdef CONFIG_PCI +#include + +#ifdef CONFIG_PCI_PNP +void pciauto_config_init(struct pci_controller *hose); +int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned int *bar); +#endif + +#include "../../Marvell/include/pci.h" + +#undef DEBUG +#undef IDE_SET_NATIVE_MODE +static unsigned int local_buses[] = { 0, 0 }; + +static const unsigned char pci_irq_swizzle[2][PCI_MAX_DEVICES] = { + {0, 0, 0, 0, 0, 0, 0, 27, 27, [9 ... PCI_MAX_DEVICES - 1] = 0 }, + {0, 0, 0, 0, 0, 0, 0, 29, 29, [9 ... PCI_MAX_DEVICES - 1] = 0 }, +}; + + +#ifdef DEBUG +static const unsigned int pci_bus_list[] = { PCI_0_MODE, PCI_1_MODE }; +static void gt_pci_bus_mode_display (PCI_HOST host) +{ + unsigned int mode; + + + mode = (GTREGREAD (pci_bus_list[host]) & (BIT4 | BIT5)) >> 4; + switch (mode) { + case 0: + printf ("PCI %d bus mode: Conventional PCI\n", host); + break; + case 1: + printf ("PCI %d bus mode: 66 Mhz PCIX\n", host); + break; + case 2: + printf ("PCI %d bus mode: 100 Mhz PCIX\n", host); + break; + case 3: + printf ("PCI %d bus mode: 133 Mhz PCIX\n", host); + break; + default: + printf ("Unknown BUS %d\n", mode); + } +} +#endif + +static const unsigned int pci_p2p_configuration_reg[] = { + PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION +}; + +static const unsigned int pci_configuration_address[] = { + PCI_0CONFIGURATION_ADDRESS, PCI_1CONFIGURATION_ADDRESS +}; + +static const unsigned int pci_configuration_data[] = { + PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER +}; + +static const unsigned int pci_error_cause_reg[] = { + PCI_0ERROR_CAUSE, PCI_1ERROR_CAUSE +}; + +static const unsigned int pci_arbiter_control[] = { + PCI_0ARBITER_CONTROL, PCI_1ARBITER_CONTROL +}; + +static const unsigned int pci_address_space_en[] = { + PCI_0_BASE_ADDR_REG_ENABLE, PCI_1_BASE_ADDR_REG_ENABLE +}; + +static const unsigned int pci_snoop_control_base_0_low[] = { + PCI_0SNOOP_CONTROL_BASE_0_LOW, PCI_1SNOOP_CONTROL_BASE_0_LOW +}; +static const unsigned int pci_snoop_control_top_0[] = { + PCI_0SNOOP_CONTROL_TOP_0, PCI_1SNOOP_CONTROL_TOP_0 +}; + +static const unsigned int pci_access_control_base_0_low[] = { + PCI_0ACCESS_CONTROL_BASE_0_LOW, PCI_1ACCESS_CONTROL_BASE_0_LOW +}; +static const unsigned int pci_access_control_top_0[] = { + PCI_0ACCESS_CONTROL_TOP_0, PCI_1ACCESS_CONTROL_TOP_0 +}; + +static const unsigned int pci_scs_bank_size[2][4] = { + {PCI_0SCS_0_BANK_SIZE, PCI_0SCS_1_BANK_SIZE, + PCI_0SCS_2_BANK_SIZE, PCI_0SCS_3_BANK_SIZE}, + {PCI_1SCS_0_BANK_SIZE, PCI_1SCS_1_BANK_SIZE, + PCI_1SCS_2_BANK_SIZE, PCI_1SCS_3_BANK_SIZE} +}; + +static const unsigned int pci_p2p_configuration[] = { + PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION +}; + + +/******************************************************************** +* pciWriteConfigReg - Write to a PCI configuration register +* - Make sure the GT is configured as a master before writing +* to another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* +* +* Inputs: unsigned int regOffset: The register offset as it apears in the GT spec +* (or any other PCI device spec) +* pciDevNum: The device number needs to be addressed. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +void pciWriteConfigReg (PCI_HOST host, unsigned int regOffset, + unsigned int pciDevNum, unsigned int data) +{ + volatile unsigned int DataForAddrReg; + unsigned int functionNum; + unsigned int busNum = 0; + unsigned int addr; + + if (pciDevNum > 32) /* illegal device Number */ + return; + if (pciDevNum == SELF) { /* configure our configuration space. */ + pciDevNum = + (GTREGREAD (pci_p2p_configuration_reg[host]) >> 24) & + 0x1f; + busNum = GTREGREAD (pci_p2p_configuration_reg[host]) & + 0xff0000; + } + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xfc; + DataForAddrReg = + (regOffset | pciDevNum | functionNum | busNum) | BIT31; + GT_REG_WRITE (pci_configuration_address[host], DataForAddrReg); + GT_REG_READ (pci_configuration_address[host], &addr); + if (addr != DataForAddrReg) + return; + GT_REG_WRITE (pci_configuration_data[host], data); +} + +/******************************************************************** +* pciReadConfigReg - Read from a PCI0 configuration register +* - Make sure the GT is configured as a master before reading +* from another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec) +* pciDevNum: The device number needs to be addressed. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +unsigned int pciReadConfigReg (PCI_HOST host, unsigned int regOffset, + unsigned int pciDevNum) +{ + volatile unsigned int DataForAddrReg; + unsigned int data; + unsigned int functionNum; + unsigned int busNum = 0; + + if (pciDevNum > 32) /* illegal device Number */ + return 0xffffffff; + if (pciDevNum == SELF) { /* configure our configuration space. */ + pciDevNum = + (GTREGREAD (pci_p2p_configuration_reg[host]) >> 24) & + 0x1f; + busNum = GTREGREAD (pci_p2p_configuration_reg[host]) & + 0xff0000; + } + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xfc; + DataForAddrReg = + (regOffset | pciDevNum | functionNum | busNum) | BIT31; + GT_REG_WRITE (pci_configuration_address[host], DataForAddrReg); + GT_REG_READ (pci_configuration_address[host], &data); + if (data != DataForAddrReg) + return 0xffffffff; + GT_REG_READ (pci_configuration_data[host], &data); + return data; +} + +/******************************************************************** +* pciOverBridgeWriteConfigReg - Write to a PCI configuration register where +* the agent is placed on another Bus. For more +* information read P2P in the PCI spec. +* +* Inputs: unsigned int regOffset - The register offset as it apears in the +* GT spec (or any other PCI device spec). +* unsigned int pciDevNum - The device number needs to be addressed. +* unsigned int busNum - On which bus does the Target agent connect +* to. +* unsigned int data - data to be written. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|01| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +* The configuration Address is configure as type-I (bits[1:0] = '01') due to +* PCI spec referring to P2P. +* +*********************************************************************/ +void pciOverBridgeWriteConfigReg (PCI_HOST host, + unsigned int regOffset, + unsigned int pciDevNum, + unsigned int busNum, unsigned int data) +{ + unsigned int DataForReg; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xff; + busNum = busNum << 16; + if (pciDevNum == SELF) { /* This board */ + DataForReg = (regOffset | pciDevNum | functionNum) | BIT0; + } else { + DataForReg = (regOffset | pciDevNum | functionNum | busNum) | + BIT31 | BIT0; + } + GT_REG_WRITE (pci_configuration_address[host], DataForReg); + GT_REG_WRITE (pci_configuration_data[host], data); +} + + +/******************************************************************** +* pciOverBridgeReadConfigReg - Read from a PCIn configuration register where +* the agent target locate on another PCI bus. +* - Make sure the GT is configured as a master +* before reading from another device on the PCI. +* - The function takes care of Big/Little endian +* conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec). (configuration register offset.) +* pciDevNum: The device number needs to be addressed. +* busNum: the Bus number where the agent is place. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|01| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +unsigned int pciOverBridgeReadConfigReg (PCI_HOST host, + unsigned int regOffset, + unsigned int pciDevNum, + unsigned int busNum) +{ + unsigned int DataForReg; + unsigned int data; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xff; + busNum = busNum << 16; + if (pciDevNum == SELF) { /* This board */ + DataForReg = (regOffset | pciDevNum | functionNum) | BIT31; + } else { /* agent on another bus */ + + DataForReg = (regOffset | pciDevNum | functionNum | busNum) | + BIT0 | BIT31; + } + GT_REG_WRITE (pci_configuration_address[host], DataForReg); + GT_REG_READ (pci_configuration_data[host], &data); + return data; +} + + +/******************************************************************** +* pciGetRegOffset - Gets the register offset for this region config. +* +* INPUT: Bus, Region - The bus and region we ask for its base address. +* OUTPUT: N/A +* RETURNS: PCI register base address +*********************************************************************/ +static unsigned int pciGetRegOffset (PCI_HOST host, PCI_REGION region) +{ + switch (host) { + case PCI_HOST0: + switch (region) { + case PCI_IO: + return PCI_0I_O_LOW_DECODE_ADDRESS; + case PCI_REGION0: + return PCI_0MEMORY0_LOW_DECODE_ADDRESS; + case PCI_REGION1: + return PCI_0MEMORY1_LOW_DECODE_ADDRESS; + case PCI_REGION2: + return PCI_0MEMORY2_LOW_DECODE_ADDRESS; + case PCI_REGION3: + return PCI_0MEMORY3_LOW_DECODE_ADDRESS; + } + case PCI_HOST1: + switch (region) { + case PCI_IO: + return PCI_1I_O_LOW_DECODE_ADDRESS; + case PCI_REGION0: + return PCI_1MEMORY0_LOW_DECODE_ADDRESS; + case PCI_REGION1: + return PCI_1MEMORY1_LOW_DECODE_ADDRESS; + case PCI_REGION2: + return PCI_1MEMORY2_LOW_DECODE_ADDRESS; + case PCI_REGION3: + return PCI_1MEMORY3_LOW_DECODE_ADDRESS; + } + } + return PCI_0MEMORY0_LOW_DECODE_ADDRESS; +} + +static unsigned int pciGetRemapOffset (PCI_HOST host, PCI_REGION region) +{ + switch (host) { + case PCI_HOST0: + switch (region) { + case PCI_IO: + return PCI_0I_O_ADDRESS_REMAP; + case PCI_REGION0: + return PCI_0MEMORY0_ADDRESS_REMAP; + case PCI_REGION1: + return PCI_0MEMORY1_ADDRESS_REMAP; + case PCI_REGION2: + return PCI_0MEMORY2_ADDRESS_REMAP; + case PCI_REGION3: + return PCI_0MEMORY3_ADDRESS_REMAP; + } + case PCI_HOST1: + switch (region) { + case PCI_IO: + return PCI_1I_O_ADDRESS_REMAP; + case PCI_REGION0: + return PCI_1MEMORY0_ADDRESS_REMAP; + case PCI_REGION1: + return PCI_1MEMORY1_ADDRESS_REMAP; + case PCI_REGION2: + return PCI_1MEMORY2_ADDRESS_REMAP; + case PCI_REGION3: + return PCI_1MEMORY3_ADDRESS_REMAP; + } + } + return PCI_0MEMORY0_ADDRESS_REMAP; +} + +/******************************************************************** +* pciGetBaseAddress - Gets the base address of a PCI. +* - If the PCI size is 0 then this base address has no meaning!!! +* +* +* INPUT: Bus, Region - The bus and region we ask for its base address. +* OUTPUT: N/A +* RETURNS: PCI base address. +*********************************************************************/ +unsigned int pciGetBaseAddress (PCI_HOST host, PCI_REGION region) +{ + unsigned int regBase; + unsigned int regEnd; + unsigned int regOffset = pciGetRegOffset (host, region); + + GT_REG_READ (regOffset, ®Base); + GT_REG_READ (regOffset + 8, ®End); + + if (regEnd <= regBase) + return 0xffffffff; /* ERROR !!! */ + + regBase = regBase << 16; + return regBase; +} + +bool pciMapSpace (PCI_HOST host, PCI_REGION region, unsigned int remapBase, + unsigned int bankBase, unsigned int bankLength) +{ + unsigned int low = 0xfff; + unsigned int high = 0x0; + unsigned int regOffset = pciGetRegOffset (host, region); + unsigned int remapOffset = pciGetRemapOffset (host, region); + + if (bankLength != 0) { + low = (bankBase >> 16) & 0xffff; + high = ((bankBase + bankLength) >> 16) - 1; + } + + GT_REG_WRITE (regOffset, low | (1 << 24)); /* no swapping */ + GT_REG_WRITE (regOffset + 8, high); + + if (bankLength != 0) { /* must do AFTER writing maps */ + GT_REG_WRITE (remapOffset, remapBase >> 16); /* sorry, 32 bits only. + dont support upper 32 + in this driver */ + } + return true; +} + +unsigned int pciGetSpaceBase (PCI_HOST host, PCI_REGION region) +{ + unsigned int low; + unsigned int regOffset = pciGetRegOffset (host, region); + + GT_REG_READ (regOffset, &low); + return (low & 0xffff) << 16; +} + +unsigned int pciGetSpaceSize (PCI_HOST host, PCI_REGION region) +{ + unsigned int low, high; + unsigned int regOffset = pciGetRegOffset (host, region); + + GT_REG_READ (regOffset, &low); + GT_REG_READ (regOffset + 8, &high); + return ((high & 0xffff) + 1) << 16; +} + + +/* ronen - 7/Dec/03*/ +/******************************************************************** +* gtPciDisable/EnableInternalBAR - This function enable/disable PCI BARS. +* Inputs: one of the PCI BAR +*********************************************************************/ +void gtPciEnableInternalBAR (PCI_HOST host, PCI_INTERNAL_BAR pciBAR) +{ + RESET_REG_BITS (pci_address_space_en[host], BIT0 << pciBAR); +} + +void gtPciDisableInternalBAR (PCI_HOST host, PCI_INTERNAL_BAR pciBAR) +{ + SET_REG_BITS (pci_address_space_en[host], BIT0 << pciBAR); +} + +/******************************************************************** +* pciMapMemoryBank - Maps PCI_host memory bank "bank" for the slave. +* +* Inputs: base and size of PCI SCS +*********************************************************************/ +void pciMapMemoryBank (PCI_HOST host, MEMORY_BANK bank, + unsigned int pciDramBase, unsigned int pciDramSize) +{ + /*ronen different function for 3rd bank. */ + unsigned int offset = (bank < 2) ? bank * 8 : 0x100 + (bank - 2) * 8; + + pciDramBase = pciDramBase & 0xfffff000; + pciDramBase = pciDramBase | (pciReadConfigReg (host, + PCI_SCS_0_BASE_ADDRESS + + offset, + SELF) & 0x00000fff); + pciWriteConfigReg (host, PCI_SCS_0_BASE_ADDRESS + offset, SELF, + pciDramBase); + if (pciDramSize == 0) + pciDramSize++; + GT_REG_WRITE (pci_scs_bank_size[host][bank], pciDramSize - 1); + gtPciEnableInternalBAR (host, bank); +} + +/******************************************************************** +* pciSetRegionFeatures - This function modifys one of the 8 regions with +* feature bits given as an input. +* - Be advised to check the spec before modifying them. +* Inputs: PCI_PROTECT_REGION region - one of the eight regions. +* unsigned int features - See file: pci.h there are defintion for those +* region features. +* unsigned int baseAddress - The region base Address. +* unsigned int topAddress - The region top Address. +* Returns: false if one of the parameters is erroneous true otherwise. +*********************************************************************/ +bool pciSetRegionFeatures (PCI_HOST host, PCI_ACCESS_REGIONS region, + unsigned int features, unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int accessLow; + unsigned int accessHigh; + unsigned int accessTop = baseAddress + regionLength; + + if (regionLength == 0) { /* close the region. */ + pciDisableAccessRegion (host, region); + return true; + } + /* base Address is store is bits [11:0] */ + accessLow = (baseAddress & 0xfff00000) >> 20; + /* All the features are update according to the defines in pci.h (to be on + the safe side we disable bits: [11:0] */ + accessLow = accessLow | (features & 0xfffff000); + /* write to the Low Access Region register */ + GT_REG_WRITE (pci_access_control_base_0_low[host] + 0x10 * region, + accessLow); + + accessHigh = (accessTop & 0xfff00000) >> 20; + + /* write to the High Access Region register */ + GT_REG_WRITE (pci_access_control_top_0[host] + 0x10 * region, + accessHigh - 1); + return true; +} + +/******************************************************************** +* pciDisableAccessRegion - Disable The given Region by writing MAX size +* to its low Address and MIN size to its high Address. +* +* Inputs: PCI_ACCESS_REGIONS region - The region we to be Disabled. +* Returns: N/A. +*********************************************************************/ +void pciDisableAccessRegion (PCI_HOST host, PCI_ACCESS_REGIONS region) +{ + /* writing back the registers default values. */ + GT_REG_WRITE (pci_access_control_base_0_low[host] + 0x10 * region, + 0x01001fff); + GT_REG_WRITE (pci_access_control_top_0[host] + 0x10 * region, 0); +} + +/******************************************************************** +* pciArbiterEnable - Enables PCI-0`s Arbitration mechanism. +* +* Inputs: N/A +* Returns: true. +*********************************************************************/ +bool pciArbiterEnable (PCI_HOST host) +{ + unsigned int regData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + GT_REG_WRITE (pci_arbiter_control[host], regData | BIT31); + return true; +} + +/******************************************************************** +* pciArbiterDisable - Disable PCI-0`s Arbitration mechanism. +* +* Inputs: N/A +* Returns: true +*********************************************************************/ +bool pciArbiterDisable (PCI_HOST host) +{ + unsigned int regData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + GT_REG_WRITE (pci_arbiter_control[host], regData & 0x7fffffff); + return true; +} + +/******************************************************************** +* pciSetArbiterAgentsPriority - Priority setup for the PCI agents (Hi or Low) +* +* Inputs: PCI_AGENT_PRIO internalAgent - priotity for internal agent. +* PCI_AGENT_PRIO externalAgent0 - priotity for external#0 agent. +* PCI_AGENT_PRIO externalAgent1 - priotity for external#1 agent. +* PCI_AGENT_PRIO externalAgent2 - priotity for external#2 agent. +* PCI_AGENT_PRIO externalAgent3 - priotity for external#3 agent. +* PCI_AGENT_PRIO externalAgent4 - priotity for external#4 agent. +* PCI_AGENT_PRIO externalAgent5 - priotity for external#5 agent. +* Returns: true +*********************************************************************/ +bool pciSetArbiterAgentsPriority (PCI_HOST host, PCI_AGENT_PRIO internalAgent, + PCI_AGENT_PRIO externalAgent0, + PCI_AGENT_PRIO externalAgent1, + PCI_AGENT_PRIO externalAgent2, + PCI_AGENT_PRIO externalAgent3, + PCI_AGENT_PRIO externalAgent4, + PCI_AGENT_PRIO externalAgent5) +{ + unsigned int regData; + unsigned int writeData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + writeData = (internalAgent << 7) + (externalAgent0 << 8) + + (externalAgent1 << 9) + (externalAgent2 << 10) + + (externalAgent3 << 11) + (externalAgent4 << 12) + + (externalAgent5 << 13); + regData = (regData & 0xffffc07f) | writeData; + GT_REG_WRITE (pci_arbiter_control[host], regData & regData); + return true; +} + +/******************************************************************** +* pciParkingDisable - Park on last option disable, with this function you can +* disable the park on last mechanism for each agent. +* disabling this option for all agents results parking +* on the internal master. +* +* Inputs: PCI_AGENT_PARK internalAgent - parking Disable for internal agent. +* PCI_AGENT_PARK externalAgent0 - parking Disable for external#0 agent. +* PCI_AGENT_PARK externalAgent1 - parking Disable for external#1 agent. +* PCI_AGENT_PARK externalAgent2 - parking Disable for external#2 agent. +* PCI_AGENT_PARK externalAgent3 - parking Disable for external#3 agent. +* PCI_AGENT_PARK externalAgent4 - parking Disable for external#4 agent. +* PCI_AGENT_PARK externalAgent5 - parking Disable for external#5 agent. +* Returns: true +*********************************************************************/ +bool pciParkingDisable (PCI_HOST host, PCI_AGENT_PARK internalAgent, + PCI_AGENT_PARK externalAgent0, + PCI_AGENT_PARK externalAgent1, + PCI_AGENT_PARK externalAgent2, + PCI_AGENT_PARK externalAgent3, + PCI_AGENT_PARK externalAgent4, + PCI_AGENT_PARK externalAgent5) +{ + unsigned int regData; + unsigned int writeData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + writeData = (internalAgent << 14) + (externalAgent0 << 15) + + (externalAgent1 << 16) + (externalAgent2 << 17) + + (externalAgent3 << 18) + (externalAgent4 << 19) + + (externalAgent5 << 20); + regData = (regData & ~(0x7f << 14)) | writeData; + GT_REG_WRITE (pci_arbiter_control[host], regData); + return true; +} + +/******************************************************************** +* pciEnableBrokenAgentDetection - A master is said to be broken if it fails to +* respond to grant assertion within a window specified in +* the input value: 'brokenValue'. +* +* Inputs: unsigned char brokenValue - A value which limits the Master to hold the +* grant without asserting frame. +* Returns: Error for illegal broken value otherwise true. +*********************************************************************/ +bool pciEnableBrokenAgentDetection (PCI_HOST host, unsigned char brokenValue) +{ + unsigned int data; + unsigned int regData; + + if (brokenValue > 0xf) + return false; /* brokenValue must be 4 bit */ + data = brokenValue << 3; + GT_REG_READ (pci_arbiter_control[host], ®Data); + regData = (regData & 0xffffff87) | data; + GT_REG_WRITE (pci_arbiter_control[host], regData | BIT1); + return true; +} + +/******************************************************************** +* pciDisableBrokenAgentDetection - This function disable the Broken agent +* Detection mechanism. +* NOTE: This operation may cause a dead lock on the +* pci0 arbitration. +* +* Inputs: N/A +* Returns: true. +*********************************************************************/ +bool pciDisableBrokenAgentDetection (PCI_HOST host) +{ + unsigned int regData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + regData = regData & 0xfffffffd; + GT_REG_WRITE (pci_arbiter_control[host], regData); + return true; +} + +/******************************************************************** +* pciP2PConfig - This function set the PCI_n P2P configurate. +* For more information on the P2P read PCI spec. +* +* Inputs: unsigned int SecondBusLow - Secondery PCI interface Bus Range Lower +* Boundry. +* unsigned int SecondBusHigh - Secondry PCI interface Bus Range upper +* Boundry. +* unsigned int busNum - The CPI bus number to which the PCI interface +* is connected. +* unsigned int devNum - The PCI interface's device number. +* +* Returns: true. +*********************************************************************/ +bool pciP2PConfig (PCI_HOST host, unsigned int SecondBusLow, + unsigned int SecondBusHigh, + unsigned int busNum, unsigned int devNum) +{ + unsigned int regData; + + regData = (SecondBusLow & 0xff) | ((SecondBusHigh & 0xff) << 8) | + ((busNum & 0xff) << 16) | ((devNum & 0x1f) << 24); + GT_REG_WRITE (pci_p2p_configuration[host], regData); + return true; +} + +/******************************************************************** +* pciSetRegionSnoopMode - This function modifys one of the 4 regions which +* supports Cache Coherency in the PCI_n interface. +* Inputs: region - One of the four regions. +* snoopType - There is four optional Types: +* 1. No Snoop. +* 2. Snoop to WT region. +* 3. Snoop to WB region. +* 4. Snoop & Invalidate to WB region. +* baseAddress - Base Address of this region. +* regionLength - Region length. +* Returns: false if one of the parameters is wrong otherwise return true. +*********************************************************************/ +bool pciSetRegionSnoopMode (PCI_HOST host, PCI_SNOOP_REGION region, + PCI_SNOOP_TYPE snoopType, + unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int snoopXbaseAddress; + unsigned int snoopXtopAddress; + unsigned int data; + unsigned int snoopHigh = baseAddress + regionLength; + + if ((region > PCI_SNOOP_REGION3) || (snoopType > PCI_SNOOP_WB)) + return false; + snoopXbaseAddress = + pci_snoop_control_base_0_low[host] + 0x10 * region; + snoopXtopAddress = pci_snoop_control_top_0[host] + 0x10 * region; + if (regionLength == 0) { /* closing the region */ + GT_REG_WRITE (snoopXbaseAddress, 0x0000ffff); + GT_REG_WRITE (snoopXtopAddress, 0); + return true; + } + baseAddress = baseAddress & 0xfff00000; /* Granularity of 1MByte */ + data = (baseAddress >> 20) | snoopType << 12; + GT_REG_WRITE (snoopXbaseAddress, data); + snoopHigh = (snoopHigh & 0xfff00000) >> 20; + GT_REG_WRITE (snoopXtopAddress, snoopHigh - 1); + return true; +} + +static int gt_read_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 * value) +{ + int bus = PCI_BUS (dev); + + if ((bus == local_buses[0]) || (bus == local_buses[1])) { + *value = pciReadConfigReg ((PCI_HOST) hose->cfg_addr, offset, + PCI_DEV (dev)); + } else { + *value = pciOverBridgeReadConfigReg ((PCI_HOST) hose-> + cfg_addr, offset, + PCI_DEV (dev), bus); + } + + return 0; +} + +static int gt_write_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 value) +{ + int bus = PCI_BUS (dev); + + if ((bus == local_buses[0]) || (bus == local_buses[1])) { + pciWriteConfigReg ((PCI_HOST) hose->cfg_addr, offset, + PCI_DEV (dev), value); + } else { + pciOverBridgeWriteConfigReg ((PCI_HOST) hose->cfg_addr, + offset, PCI_DEV (dev), bus, + value); + } + return 0; +} + + +static void gt_setup_ide (struct pci_controller *hose, + pci_dev_t dev, struct pci_config_table *entry) +{ + static const int ide_bar[] = { 8, 4, 8, 4, 0, 0 }; + u32 bar_response, bar_value; + int bar; + + for (bar = 0; bar < 6; bar++) { + /*ronen different function for 3rd bank. */ + unsigned int offset = + (bar < 2) ? bar * 8 : 0x100 + (bar - 2) * 8; + + pci_write_config_dword (dev, PCI_BASE_ADDRESS_0 + offset, + 0x0); + pci_read_config_dword (dev, PCI_BASE_ADDRESS_0 + offset, + &bar_response); + + pciauto_region_allocate (bar_response & + PCI_BASE_ADDRESS_SPACE_IO ? hose-> + pci_io : hose->pci_mem, ide_bar[bar], + &bar_value); + + pci_write_config_dword (dev, PCI_BASE_ADDRESS_0 + bar * 4, + bar_value); + } +} + + +/* TODO BJW: Change this for DB64360. This was pulled from the EV64260 */ +/* and is curently not called *. */ +#if 0 +static void gt_fixup_irq (struct pci_controller *hose, pci_dev_t dev) +{ + unsigned char pin, irq; + + pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &pin); + + if (pin == 1) { /* only allow INT A */ + irq = pci_irq_swizzle[(PCI_HOST) hose-> + cfg_addr][PCI_DEV (dev)]; + if (irq) + pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq); + } +} +#endif + +struct pci_config_table gt_config_table[] = { + {PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, + PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, gt_setup_ide}, + + {} +}; + +struct pci_controller pci0_hose = { +/* fixup_irq: gt_fixup_irq, */ + config_table:gt_config_table, +}; + +struct pci_controller pci1_hose = { +/* fixup_irq: gt_fixup_irq, */ + config_table:gt_config_table, +}; + +void pci_init_board (void) +{ + unsigned int command; +#ifdef CONFIG_PCI_PNP + unsigned int bar; +#endif + +#ifdef DEBUG + gt_pci_bus_mode_display (PCI_HOST0); +#endif + + pci0_hose.first_busno = 0; + pci0_hose.last_busno = 0xff; + local_buses[0] = pci0_hose.first_busno; + + /* PCI memory space */ + pci_set_region (pci0_hose.regions + 0, + CFG_PCI0_0_MEM_SPACE, + CFG_PCI0_0_MEM_SPACE, + CFG_PCI0_MEM_SIZE, PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region (pci0_hose.regions + 1, + CFG_PCI0_IO_SPACE_PCI, + CFG_PCI0_IO_SPACE, CFG_PCI0_IO_SIZE, PCI_REGION_IO); + + pci_set_ops (&pci0_hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + gt_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + gt_write_config_dword); + pci0_hose.region_count = 2; + + pci0_hose.cfg_addr = (unsigned int *) PCI_HOST0; + + pci_register_hose (&pci0_hose); + pciArbiterEnable (PCI_HOST0); + pciParkingDisable (PCI_HOST0, 1, 1, 1, 1, 1, 1, 1); + command = pciReadConfigReg (PCI_HOST0, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MASTER; + pciWriteConfigReg (PCI_HOST0, PCI_COMMAND, SELF, command); + command = pciReadConfigReg (PCI_HOST0, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MEMORY; + pciWriteConfigReg (PCI_HOST0, PCI_COMMAND, SELF, command); + +#ifdef CONFIG_PCI_PNP + pciauto_config_init(&pci0_hose); + pciauto_region_allocate(pci0_hose.pci_io, 0x400, &bar); +#endif +#ifdef CONFIG_PCI_SCAN_SHOW + printf("PCI: Bus Dev VenId DevId Class Int\n"); +#endif + pci0_hose.last_busno = pci_hose_scan_bus (&pci0_hose, pci0_hose.first_busno); + +#ifdef DEBUG + gt_pci_bus_mode_display (PCI_HOST1); +#endif + pci1_hose.first_busno = pci0_hose.last_busno + 1; + pci1_hose.last_busno = 0xff; + pci1_hose.current_busno = pci1_hose.first_busno; + local_buses[1] = pci1_hose.first_busno; + + /* PCI memory space */ + pci_set_region (pci1_hose.regions + 0, + CFG_PCI1_0_MEM_SPACE, + CFG_PCI1_0_MEM_SPACE, + CFG_PCI1_MEM_SIZE, PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region (pci1_hose.regions + 1, + CFG_PCI1_IO_SPACE_PCI, + CFG_PCI1_IO_SPACE, CFG_PCI1_IO_SIZE, PCI_REGION_IO); + + pci_set_ops (&pci1_hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + gt_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + gt_write_config_dword); + + pci1_hose.region_count = 2; + + pci1_hose.cfg_addr = (unsigned int *) PCI_HOST1; + + pci_register_hose (&pci1_hose); + + pciArbiterEnable (PCI_HOST1); + pciParkingDisable (PCI_HOST1, 1, 1, 1, 1, 1, 1, 1); + + command = pciReadConfigReg (PCI_HOST1, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MASTER; + pciWriteConfigReg (PCI_HOST1, PCI_COMMAND, SELF, command); + +#ifdef CONFIG_PCI_PNP + pciauto_config_init(&pci1_hose); + pciauto_region_allocate(pci1_hose.pci_io, 0x400, &bar); +#endif + pci1_hose.last_busno = pci_hose_scan_bus (&pci1_hose, pci1_hose.first_busno); + + command = pciReadConfigReg (PCI_HOST1, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MEMORY; + pciWriteConfigReg (PCI_HOST1, PCI_COMMAND, SELF, command); + +} +#endif /* of CONFIG_PCI */ diff --git a/board/esd/cpci750/sdram_init.c b/board/esd/cpci750/sdram_init.c new file mode 100644 index 0000000000..d22ffe5179 --- /dev/null +++ b/board/esd/cpci750/sdram_init.c @@ -0,0 +1,1439 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * 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 + */ + +/************************************************************************* + * adaption for the Marvell DB64360 Board + * Ingo Assmus (ingo.assmus@keymile.com) + * + * adaption for the cpci750 Board + * Reinhard Arlt (reinhard.arlt@esd-electronics.com) + *************************************************************************/ + + +/* sdram_init.c - automatic memory sizing */ + +#include +#include <74xx_7xx.h> +#include "../../Marvell/include/memory.h" +#include "../../Marvell/include/pci.h" +#include "../../Marvell/include/mv_gen_reg.h" +#include + +#include "eth.h" +#include "mpsc.h" +#include "../../Marvell/common/i2c.h" +#include "64360.h" +#include "mv_regs.h" + + +#undef DEBUG +/* #define DEBUG */ +#ifdef CONFIG_PCI +#define MAP_PCI +#endif /* of CONFIG_PCI */ + +#ifdef DEBUG +#define DP(x) x +#else +#define DP(x) +#endif + +int set_dfcdlInit(void); /* setup delay line of Mv64360 */ + +/* ------------------------------------------------------------------------- */ + +int +memory_map_bank(unsigned int bankNo, + unsigned int bankBase, + unsigned int bankLength) +{ +#ifdef MAP_PCI + PCI_HOST host; +#endif + + +#ifdef DEBUG + if (bankLength > 0) { + printf("mapping bank %d at %08x - %08x\n", + bankNo, bankBase, bankBase + bankLength - 1); + } else { + printf("unmapping bank %d\n", bankNo); + } +#endif + + memoryMapBank(bankNo, bankBase, bankLength); + +#ifdef MAP_PCI + for (host=PCI_HOST0;host<=PCI_HOST1;host++) { + const int features= + PREFETCH_ENABLE | + DELAYED_READ_ENABLE | + AGGRESSIVE_PREFETCH | + READ_LINE_AGGRESSIVE_PREFETCH | + READ_MULTI_AGGRESSIVE_PREFETCH | + MAX_BURST_4 | + PCI_NO_SWAP; + + pciMapMemoryBank(host, bankNo, bankBase, bankLength); + + pciSetRegionSnoopMode(host, bankNo, PCI_SNOOP_WB, bankBase, + bankLength); + + pciSetRegionFeatures(host, bankNo, features, bankBase, bankLength); + } +#endif + return 0; +} + +#define GB (1 << 30) + +/* much of this code is based on (or is) the code in the pip405 port */ +/* thanks go to the authors of said port - Josh */ + +/* structure to store the relevant information about an sdram bank */ +typedef struct sdram_info { + uchar drb_size; + uchar registered, ecc; + uchar tpar; + uchar tras_clocks; + uchar burst_len; + uchar banks, slot; +} sdram_info_t; + +/* Typedefs for 'gtAuxilGetDIMMinfo' function */ + +typedef enum _memoryType {SDRAM, DDR} MEMORY_TYPE; + +typedef enum _voltageInterface {TTL_5V_TOLERANT, LVTTL, HSTL_1_5V, + SSTL_3_3V, SSTL_2_5V, VOLTAGE_UNKNOWN, + } VOLTAGE_INTERFACE; + +typedef enum _max_CL_supported_DDR {DDR_CL_1=1, DDR_CL_1_5=2, DDR_CL_2=4, DDR_CL_2_5=8, DDR_CL_3=16, DDR_CL_3_5=32, DDR_CL_FAULT} MAX_CL_SUPPORTED_DDR; +typedef enum _max_CL_supported_SD {SD_CL_1=1, SD_CL_2, SD_CL_3, SD_CL_4, SD_CL_5, SD_CL_6, SD_CL_7, SD_FAULT} MAX_CL_SUPPORTED_SD; + + +/* SDRAM/DDR information struct */ +typedef struct _gtMemoryDimmInfo +{ + MEMORY_TYPE memoryType; + unsigned int numOfRowAddresses; + unsigned int numOfColAddresses; + unsigned int numOfModuleBanks; + unsigned int dataWidth; + VOLTAGE_INTERFACE voltageInterface; + unsigned int errorCheckType; /* ECC , PARITY..*/ + unsigned int sdramWidth; /* 4,8,16 or 32 */; + unsigned int errorCheckDataWidth; /* 0 - no, 1 - Yes */ + unsigned int minClkDelay; + unsigned int burstLengthSupported; + unsigned int numOfBanksOnEachDevice; + unsigned int suportedCasLatencies; + unsigned int RefreshInterval; + unsigned int maxCASlatencySupported_LoP; /* LoP left of point (measured in ns) */ + unsigned int maxCASlatencySupported_RoP; /* RoP right of point (measured in ns)*/ + MAX_CL_SUPPORTED_DDR maxClSupported_DDR; + MAX_CL_SUPPORTED_SD maxClSupported_SD; + unsigned int moduleBankDensity; + /* module attributes (true for yes) */ + bool bufferedAddrAndControlInputs; + bool registeredAddrAndControlInputs; + bool onCardPLL; + bool bufferedDQMBinputs; + bool registeredDQMBinputs; + bool differentialClockInput; + bool redundantRowAddressing; + + /* module general attributes */ + bool suportedAutoPreCharge; + bool suportedPreChargeAll; + bool suportedEarlyRasPreCharge; + bool suportedWrite1ReadBurst; + bool suported5PercentLowVCC; + bool suported5PercentUpperVCC; + /* module timing parameters */ + unsigned int minRasToCasDelay; + unsigned int minRowActiveRowActiveDelay; + unsigned int minRasPulseWidth; + unsigned int minRowPrechargeTime; /* measured in ns */ + + int addrAndCommandHoldTime; /* LoP left of point (measured in ns) */ + int addrAndCommandSetupTime; /* (measured in ns/100) */ + int dataInputSetupTime; /* LoP left of point (measured in ns) */ + int dataInputHoldTime; /* LoP left of point (measured in ns) */ +/* tAC times for highest 2nd and 3rd highest CAS Latency values */ + unsigned int clockToDataOut_LoP; /* LoP left of point (measured in ns) */ + unsigned int clockToDataOut_RoP; /* RoP right of point (measured in ns)*/ + unsigned int clockToDataOutMinus1_LoP; /* LoP left of point (measured in ns) */ + unsigned int clockToDataOutMinus1_RoP; /* RoP right of point (measured in ns)*/ + unsigned int clockToDataOutMinus2_LoP; /* LoP left of point (measured in ns) */ + unsigned int clockToDataOutMinus2_RoP; /* RoP right of point (measured in ns)*/ + + unsigned int minimumCycleTimeAtMaxCasLatancy_LoP; /* LoP left of point (measured in ns) */ + unsigned int minimumCycleTimeAtMaxCasLatancy_RoP; /* RoP right of point (measured in ns)*/ + + unsigned int minimumCycleTimeAtMaxCasLatancyMinus1_LoP; /* LoP left of point (measured in ns) */ + unsigned int minimumCycleTimeAtMaxCasLatancyMinus1_RoP; /* RoP right of point (measured in ns)*/ + + unsigned int minimumCycleTimeAtMaxCasLatancyMinus2_LoP; /* LoP left of point (measured in ns) */ + unsigned int minimumCycleTimeAtMaxCasLatancyMinus2_RoP; /* RoP right of point (measured in ns)*/ + + /* Parameters calculated from + the extracted DIMM information */ + unsigned int size; + unsigned int deviceDensity; /* 16,64,128,256 or 512 Mbit */ + unsigned int numberOfDevices; + uchar drb_size; /* DRAM size in n*64Mbit */ + uchar slot; /* Slot Number this module is inserted in */ + uchar spd_raw_data[128]; /* Content of SPD-EEPROM copied 1:1 */ +#ifdef DEBUG + uchar manufactura[8]; /* Content of SPD-EEPROM Byte 64-71 */ + uchar modul_id[18]; /* Content of SPD-EEPROM Byte 73-90 */ + uchar vendor_data[27]; /* Content of SPD-EEPROM Byte 99-125 */ + unsigned long modul_serial_no; /* Content of SPD-EEPROM Byte 95-98 */ + unsigned int manufac_date; /* Content of SPD-EEPROM Byte 93-94 */ + unsigned int modul_revision; /* Content of SPD-EEPROM Byte 91-92 */ + uchar manufac_place; /* Content of SPD-EEPROM Byte 72 */ + +#endif +} AUX_MEM_DIMM_INFO; + + +/* + * translate ns.ns/10 coding of SPD timing values + * into 10 ps unit values + */ +static inline unsigned short +NS10to10PS(unsigned char spd_byte) +{ + unsigned short ns, ns10; + + /* isolate upper nibble */ + ns = (spd_byte >> 4) & 0x0F; + /* isolate lower nibble */ + ns10 = (spd_byte & 0x0F); + + return(ns*100 + ns10*10); +} + +/* + * translate ns coding of SPD timing values + * into 10 ps unit values + */ +static inline unsigned short +NSto10PS(unsigned char spd_byte) +{ + return(spd_byte*100); +} + +/* This code reads the SPD chip on the sdram and populates + * the array which is passed in with the relevant information */ +/* static int check_dimm(uchar slot, AUX_MEM_DIMM_INFO *info) */ +static int +check_dimm(uchar slot, AUX_MEM_DIMM_INFO *dimmInfo) + +{ + DECLARE_GLOBAL_DATA_PTR; + + unsigned long spd_checksum; + + uchar addr = slot == 0 ? DIMM0_I2C_ADDR : DIMM1_I2C_ADDR; + int ret; + unsigned int i,j,density = 1,devicesForErrCheck = 0; +#ifdef DEBUG + unsigned int k; +#endif + unsigned int rightOfPoint = 0,leftOfPoint = 0, mult, div, time_tmp; + int sign = 1,shift,maskLeftOfPoint,maskRightOfPoint; + uchar supp_cal, cal_val; + ulong memclk, tmemclk; + ulong tmp; + uchar trp_clocks=0, trcd_clocks, tras_clocks, trrd_clocks; + uchar data[128]; + + memclk = gd->bus_clk; + tmemclk = 1000000000 / (memclk / 100); /* in 10 ps units */ + + memset(data, 0, sizeof(data)); + + + ret = 0; + + DP(puts("before i2c read\n")); + + ret = i2c_read(addr, 0, 2, data, 128); + + DP(puts("after i2c read\n")); + + if ((data[64] != 'e') || (data[65] != 's') || (data[66] != 'd') || (data[67] != '-') || + (data[68] != 'g') || (data[69] != 'm') || (data[70] != 'b') || (data[71] != 'h')) + { + ret = -1; + } + + if ((ret != 0) && (slot == 0)) + { + memset(data, 0, sizeof(data)); + data[ 0] = 0x80; data[ 1] = 0x08; data[ 2] = 0x07; data[ 3] = 0x0c; + data[ 4] = 0x09; data[ 5] = 0x01; data[ 6] = 0x48; data[ 7] = 0x00; + data[ 8] = 0x04; data[ 9] = 0x75; data[10] = 0x80; data[11] = 0x02; + data[12] = 0x80; data[13] = 0x10; data[14] = 0x08; data[15] = 0x01; + data[16] = 0x0e; data[17] = 0x04; data[18] = 0x0c; data[19] = 0x01; + data[20] = 0x02; data[21] = 0x20; data[22] = 0x00; data[23] = 0xa0; + data[24] = 0x80; data[25] = 0x00; data[26] = 0x00; data[27] = 0x50; + data[28] = 0x3c; data[29] = 0x50; data[30] = 0x32; data[31] = 0x10; + data[32] = 0xb0; data[33] = 0xb0; data[34] = 0x60; data[35] = 0x60; + data[64] = 'e' ; data[65] = 's' ; data[66] = 'd' ; data[67] = '-' ; + data[68] = 'g' ; data[69] = 'm' ; data[70] = 'b' ; data[71] = 'h' ; + ret = 0; + } + + /* zero all the values */ + memset(dimmInfo, 0, sizeof(*dimmInfo)); + + /* copy the SPD content 1:1 into the dimmInfo structure*/ + for(i = 0 ; i <= 127 ; i++) + { + dimmInfo->spd_raw_data[i] = data[i]; + } + + if (ret) { + DP(printf("No DIMM in slot %d [err = %x]\n", slot, ret)); + return 0; + } + else + dimmInfo->slot = slot; /* start to fill up dimminfo for this "slot" */ + +#ifdef CFG_DISPLAY_DIMM_SPD_CONTENT + + for(i = 0 ; i <= 127 ; i++) + { + printf("SPD-EEPROM Byte %3d = %3x (%3d)\n", i, data[i], data[i]); + } + +#endif +#ifdef DEBUG +/* find Manufactura of Dimm Module */ + for(i = 0 ; i < sizeof(dimmInfo->manufactura) ; i++) + { + dimmInfo->manufactura[i] = data[64+i]; + } + printf("\nThis RAM-Module is produced by: %s\n", dimmInfo->manufactura); + +/* find Manul-ID of Dimm Module */ + for(i = 0 ; i < sizeof(dimmInfo->modul_id) ; i++) + { + dimmInfo->modul_id[i] = data[73+i]; + } + printf("The Module-ID of this RAM-Module is: %s\n", dimmInfo->modul_id); + +/* find Vendor-Data of Dimm Module */ + for(i = 0 ; i < sizeof(dimmInfo->vendor_data) ; i++) + { + dimmInfo->vendor_data[i] = data[99+i]; + } + printf("Vendor Data of this RAM-Module is: %s\n", dimmInfo->vendor_data); + +/* find modul_serial_no of Dimm Module */ + dimmInfo->modul_serial_no = (*((unsigned long *)(&data[95]))); + printf("Serial No. of this RAM-Module is: %ld (%lx)\n", dimmInfo->modul_serial_no, dimmInfo->modul_serial_no); + +/* find Manufac-Data of Dimm Module */ + dimmInfo->manufac_date = (*((unsigned int *)(&data[93]))); + printf("Manufactoring Date of this RAM-Module is: %d.%d\n", data[93], data [94]); /*dimmInfo->manufac_date*/ + +/* find modul_revision of Dimm Module */ + dimmInfo->modul_revision = (*((unsigned int *)(&data[91]))); + printf("Module Revision of this RAM-Module is: %d.%d\n", data[91], data [92]); /* dimmInfo->modul_revision*/ + +/* find manufac_place of Dimm Module */ + dimmInfo->manufac_place = (*((unsigned char *)(&data[72]))); + printf("manufac_place of this RAM-Module is: %d\n", dimmInfo->manufac_place); + +#endif +/*------------------------------------------------------------------------------------------------------------------------------*/ +/* calculate SPD checksum */ +/*------------------------------------------------------------------------------------------------------------------------------*/ + spd_checksum = 0; +#if 0 /* test-only */ + for(i = 0 ; i <= 62 ; i++) + { + spd_checksum += data[i]; + } + + if ((spd_checksum & 0xff) != data[63]) + { + printf("### Error in SPD Checksum !!! Is_value: %2x should value %2x\n", (unsigned int)(spd_checksum & 0xff), data[63]); + hang(); + } + + else + printf("SPD Checksum ok!\n"); +#endif /* test-only */ + +/*------------------------------------------------------------------------------------------------------------------------------*/ + for(i = 2 ; i <= 35 ; i++) + { + switch(i) + { + case 2: /* Memory type (DDR / SDRAM) */ + dimmInfo->memoryType = (data[i] == 0x7)? DDR:SDRAM; + #ifdef DEBUG + if (dimmInfo->memoryType == 0) + DP(printf("Dram_type in slot %d is: SDRAM\n", dimmInfo->slot)); + if (dimmInfo->memoryType == 1) + DP(printf("Dram_type in slot %d is: DDRAM\n", dimmInfo->slot)); + #endif + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 3: /* Number Of Row Addresses */ + dimmInfo->numOfRowAddresses = data[i]; + DP(printf("Module Number of row addresses: %d\n", dimmInfo->numOfRowAddresses)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 4: /* Number Of Column Addresses */ + dimmInfo->numOfColAddresses = data[i]; + DP(printf("Module Number of col addresses: %d\n", dimmInfo->numOfColAddresses)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 5: /* Number Of Module Banks */ + dimmInfo->numOfModuleBanks = data[i]; + DP(printf("Number of Banks on Mod. : %d\n", dimmInfo->numOfModuleBanks)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 6: /* Data Width */ + dimmInfo->dataWidth = data[i]; + DP(printf("Module Data Width: %d\n", dimmInfo->dataWidth)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 8: /* Voltage Interface */ + switch(data[i]) + { + case 0x0: + dimmInfo->voltageInterface = TTL_5V_TOLERANT; + DP(printf("Module is TTL_5V_TOLERANT\n")); + break; + case 0x1: + dimmInfo->voltageInterface = LVTTL; + DP(printf("Module is LVTTL\n")); + break; + case 0x2: + dimmInfo->voltageInterface = HSTL_1_5V; + DP(printf("Module is TTL_5V_TOLERANT\n")); + break; + case 0x3: + dimmInfo->voltageInterface = SSTL_3_3V; + DP(printf("Module is HSTL_1_5V\n")); + break; + case 0x4: + dimmInfo->voltageInterface = SSTL_2_5V; + DP(printf("Module is SSTL_2_5V\n")); + break; + default: + dimmInfo->voltageInterface = VOLTAGE_UNKNOWN; + DP(printf("Module is VOLTAGE_UNKNOWN\n")); + break; + } + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 9: /* Minimum Cycle Time At Max CasLatancy */ + shift = (dimmInfo->memoryType == DDR)? 4:2; + mult = (dimmInfo->memoryType == DDR)? 10:25; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xf0:0xfc; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0xf:0x03; + leftOfPoint = (data[i] & maskLeftOfPoint) >> shift; + rightOfPoint = (data[i] & maskRightOfPoint)* mult; + dimmInfo->minimumCycleTimeAtMaxCasLatancy_LoP = leftOfPoint; + dimmInfo->minimumCycleTimeAtMaxCasLatancy_RoP = rightOfPoint; + DP(printf("Minimum Cycle Time At Max CasLatancy: %d.%d [ns]\n",leftOfPoint, rightOfPoint)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 10: /* Clock To Data Out */ + div = (dimmInfo->memoryType == DDR)? 100:10; + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + dimmInfo->clockToDataOut_LoP = leftOfPoint; + dimmInfo->clockToDataOut_RoP = rightOfPoint; + DP(printf("Clock To Data Out: %d.%2d [ns]\n",leftOfPoint, rightOfPoint )); + /*dimmInfo->clockToDataOut*/ + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + +#ifdef CONFIG_ECC + case 11: /* Error Check Type */ + dimmInfo->errorCheckType = data[i]; + DP(printf("Error Check Type (0=NONE): %d\n", dimmInfo->errorCheckType)); + break; +#endif +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 12: /* Refresh Interval */ + dimmInfo->RefreshInterval = data[i]; + DP(printf("RefreshInterval (80= Self refresh Normal, 15.625us) : %x\n", dimmInfo->RefreshInterval)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 13: /* Sdram Width */ + dimmInfo->sdramWidth = data[i]; + DP(printf("Sdram Width: %d\n", dimmInfo->sdramWidth)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 14: /* Error Check Data Width */ + dimmInfo->errorCheckDataWidth = data[i]; + DP(printf("Error Check Data Width: %d\n", dimmInfo->errorCheckDataWidth)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 15: /* Minimum Clock Delay */ + dimmInfo->minClkDelay = data[i]; + DP(printf("Minimum Clock Delay: %d\n", dimmInfo->minClkDelay)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 16: /* Burst Length Supported */ + /******-******-******-******* + * bit3 | bit2 | bit1 | bit0 * + *******-******-******-******* + burst length = * 8 | 4 | 2 | 1 * + ***************************** + + If for example bit0 and bit2 are set, the burst + length supported are 1 and 4. */ + + dimmInfo->burstLengthSupported = data[i]; +#ifdef DEBUG + DP(printf("Burst Length Supported: ")); + if (dimmInfo->burstLengthSupported & 0x01) + DP(printf("1, ")); + if (dimmInfo->burstLengthSupported & 0x02) + DP(printf("2, ")); + if (dimmInfo->burstLengthSupported & 0x04) + DP(printf("4, ")); + if (dimmInfo->burstLengthSupported & 0x08) + DP(printf("8, ")); + DP(printf(" Bit \n")); +#endif + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 17: /* Number Of Banks On Each Device */ + dimmInfo->numOfBanksOnEachDevice = data[i]; + DP(printf("Number Of Banks On Each Chip: %d\n", dimmInfo->numOfBanksOnEachDevice)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 18: /* Suported Cas Latencies */ + + /* DDR: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | TBD | 3.5 | 3 | 2.5 | 2 | 1.5 | 1 * + ********************************************************* + SDRAM: + *******-******-******-******-******-******-******-******* + * bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * + *******-******-******-******-******-******-******-******* + CAS = * TBD | 7 | 6 | 5 | 4 | 3 | 2 | 1 * + ********************************************************/ + dimmInfo->suportedCasLatencies = data[i]; +#ifdef DEBUG + DP(printf("Suported Cas Latencies: (CL) ")); + if (dimmInfo->memoryType == 0) /* SDRAM*/ + { + for (k = 0; k <=7; k++) + { + if (dimmInfo->suportedCasLatencies & (1 << k)) + DP(printf("%d, ", k+1)); + } + + } + else /* DDR-RAM*/ + { + if (dimmInfo->suportedCasLatencies & 1) + DP(printf("1, ")); + if (dimmInfo->suportedCasLatencies & 2) + DP(printf("1.5, ")); + if (dimmInfo->suportedCasLatencies & 4) + DP(printf("2, ")); + if (dimmInfo->suportedCasLatencies & 8) + DP(printf("2.5, ")); + if (dimmInfo->suportedCasLatencies & 16) + DP(printf("3, ")); + if (dimmInfo->suportedCasLatencies & 32) + DP(printf("3.5, ")); + + } + DP(printf("\n")); +#endif + /* Calculating MAX CAS latency */ + for(j = 7 ; j > 0 ; j--) + { + if(((dimmInfo->suportedCasLatencies >> j) & 0x1) == 1) + { + switch(dimmInfo->memoryType) + { + case DDR: + /* CAS latency 1, 1.5, 2, 2.5, 3, 3.5 */ + switch (j) + { + case 7: + DP(printf("Max. Cas Latencies (DDR): ERROR !!!\n")); + dimmInfo->maxClSupported_DDR = DDR_CL_FAULT; + hang(); + break; + case 6: + DP(printf("Max. Cas Latencies (DDR): ERROR !!!\n")); + dimmInfo->maxClSupported_DDR = DDR_CL_FAULT; + hang(); + break; + case 5: + DP(printf("Max. Cas Latencies (DDR): 3.5 clk's\n")); + dimmInfo->maxClSupported_DDR = DDR_CL_3_5; + break; + case 4: + DP(printf("Max. Cas Latencies (DDR): 3 clk's \n")); + dimmInfo->maxClSupported_DDR = DDR_CL_3; + break; + case 3: + DP(printf("Max. Cas Latencies (DDR): 2.5 clk's \n")); + dimmInfo->maxClSupported_DDR = DDR_CL_2_5; + break; + case 2: + DP(printf("Max. Cas Latencies (DDR): 2 clk's \n")); + dimmInfo->maxClSupported_DDR = DDR_CL_2; + break; + case 1: + DP(printf("Max. Cas Latencies (DDR): 1.5 clk's \n")); + dimmInfo->maxClSupported_DDR = DDR_CL_1_5; + break; + } + dimmInfo->maxCASlatencySupported_LoP = 1 + (int) (5 * j /10); + if (((5*j) % 10) != 0) + dimmInfo->maxCASlatencySupported_RoP = 5; + else + dimmInfo->maxCASlatencySupported_RoP = 0; + DP(printf("Max. Cas Latencies (DDR LoP.RoP Notation): %d.%d \n", dimmInfo->maxCASlatencySupported_LoP, dimmInfo->maxCASlatencySupported_RoP)); + break; + case SDRAM: + /* CAS latency 1, 2, 3, 4, 5, 6, 7 */ + dimmInfo->maxClSupported_SD = j; /* Cas Latency DDR-RAM Coded */ + DP(printf("Max. Cas Latencies (SD): %d\n", dimmInfo->maxClSupported_SD)); + dimmInfo->maxCASlatencySupported_LoP = j ; + dimmInfo->maxCASlatencySupported_RoP = 0; + DP(printf("Max. Cas Latencies (DDR LoP.RoP Notation): %d.%d \n", dimmInfo->maxCASlatencySupported_LoP, dimmInfo->maxCASlatencySupported_RoP)); + break; + } + break; + } + } + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 21: /* Buffered Address And Control Inputs */ + DP(printf("\nModul Attributes (SPD Byte 21): \n")); + dimmInfo->bufferedAddrAndControlInputs = data[i] & BIT0; + dimmInfo->registeredAddrAndControlInputs = (data[i] & BIT1) >> 1; + dimmInfo->onCardPLL = (data[i] & BIT2) >> 2; + dimmInfo->bufferedDQMBinputs = (data[i] & BIT3) >> 3; + dimmInfo->registeredDQMBinputs = (data[i] & BIT4) >> 4; + dimmInfo->differentialClockInput = (data[i] & BIT5) >> 5; + dimmInfo->redundantRowAddressing = (data[i] & BIT6) >> 6; +#ifdef DEBUG + if (dimmInfo->bufferedAddrAndControlInputs == 1) + DP(printf(" - Buffered Address/Control Input: Yes \n")); + else + DP(printf(" - Buffered Address/Control Input: No \n")); + + if (dimmInfo->registeredAddrAndControlInputs == 1) + DP(printf(" - Registered Address/Control Input: Yes \n")); + else + DP(printf(" - Registered Address/Control Input: No \n")); + + if (dimmInfo->onCardPLL == 1) + DP(printf(" - On-Card PLL (clock): Yes \n")); + else + DP(printf(" - On-Card PLL (clock): No \n")); + + if (dimmInfo->bufferedDQMBinputs == 1) + DP(printf(" - Bufferd DQMB Inputs: Yes \n")); + else + DP(printf(" - Bufferd DQMB Inputs: No \n")); + + if (dimmInfo->registeredDQMBinputs == 1) + DP(printf(" - Registered DQMB Inputs: Yes \n")); + else + DP(printf(" - Registered DQMB Inputs: No \n")); + + if (dimmInfo->differentialClockInput == 1) + DP(printf(" - Differential Clock Input: Yes \n")); + else + DP(printf(" - Differential Clock Input: No \n")); + + if (dimmInfo->redundantRowAddressing == 1) + DP(printf(" - redundant Row Addressing: Yes \n")); + else + DP(printf(" - redundant Row Addressing: No \n")); + +#endif + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 22: /* Suported AutoPreCharge */ + DP(printf("\nModul Attributes (SPD Byte 22): \n")); + dimmInfo->suportedEarlyRasPreCharge= data[i] & BIT0; + dimmInfo->suportedAutoPreCharge = (data[i] & BIT1) >> 1; + dimmInfo->suportedPreChargeAll = (data[i] & BIT2) >> 2; + dimmInfo->suportedWrite1ReadBurst= (data[i] & BIT3) >> 3; + dimmInfo->suported5PercentLowVCC= (data[i] & BIT4) >> 4; + dimmInfo->suported5PercentUpperVCC= (data[i] & BIT5) >> 5; +#ifdef DEBUG + if (dimmInfo->suportedEarlyRasPreCharge == 1) + DP(printf(" - Early Ras Precharge: Yes \n")); + else + DP(printf(" - Early Ras Precharge: No \n")); + + if (dimmInfo->suportedAutoPreCharge == 1) + DP(printf(" - AutoPreCharge: Yes \n")); + else + DP(printf(" - AutoPreCharge: No \n")); + + if (dimmInfo->suportedPreChargeAll == 1) + DP(printf(" - Precharge All: Yes \n")); + else + DP(printf(" - Precharge All: No \n")); + + if (dimmInfo->suportedWrite1ReadBurst == 1) + DP(printf(" - Write 1/ReadBurst: Yes \n")); + else + DP(printf(" - Write 1/ReadBurst: No \n")); + + if (dimmInfo->suported5PercentLowVCC == 1) + DP(printf(" - lower VCC tolerance: 5 Percent \n")); + else + DP(printf(" - lower VCC tolerance: 10 Percent \n")); + + if (dimmInfo->suported5PercentUpperVCC == 1) + DP(printf(" - upper VCC tolerance: 5 Percent \n")); + else + DP(printf(" - upper VCC tolerance: 10 Percent \n")); + +#endif + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 23: /* Minimum Cycle Time At Maximum Cas Latancy Minus 1 (2nd highest CL) */ + shift = (dimmInfo->memoryType == DDR)? 4:2; + mult = (dimmInfo->memoryType == DDR)? 10:25; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xf0:0xfc; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0xf:0x03; + leftOfPoint = (data[i] & maskLeftOfPoint) >> shift; + rightOfPoint = (data[i] & maskRightOfPoint)* mult; + dimmInfo->minimumCycleTimeAtMaxCasLatancyMinus1_LoP = leftOfPoint; + dimmInfo->minimumCycleTimeAtMaxCasLatancyMinus1_RoP = rightOfPoint; + DP(printf("Minimum Cycle Time At 2nd highest CasLatancy (0 = Not supported): %d.%d [ns]\n",leftOfPoint, rightOfPoint )); + /*dimmInfo->minimumCycleTimeAtMaxCasLatancy*/ + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 24: /* Clock To Data Out 2nd highest Cas Latency Value*/ + div = (dimmInfo->memoryType == DDR)? 100:10; + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + dimmInfo->clockToDataOutMinus1_LoP = leftOfPoint; + dimmInfo->clockToDataOutMinus1_RoP = rightOfPoint; + DP(printf("Clock To Data Out (2nd CL value): %d.%2d [ns]\n",leftOfPoint, rightOfPoint )); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 25: /* Minimum Cycle Time At Maximum Cas Latancy Minus 2 (3rd highest CL) */ + shift = (dimmInfo->memoryType == DDR)? 4:2; + mult = (dimmInfo->memoryType == DDR)? 10:25; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xf0:0xfc; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0xf:0x03; + leftOfPoint = (data[i] & maskLeftOfPoint) >> shift; + rightOfPoint = (data[i] & maskRightOfPoint)* mult; + dimmInfo->minimumCycleTimeAtMaxCasLatancyMinus2_LoP = leftOfPoint; + dimmInfo->minimumCycleTimeAtMaxCasLatancyMinus2_RoP = rightOfPoint; + DP(printf("Minimum Cycle Time At 3rd highest CasLatancy (0 = Not supported): %d.%d [ns]\n",leftOfPoint, rightOfPoint )); + /*dimmInfo->minimumCycleTimeAtMaxCasLatancy*/ + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 26: /* Clock To Data Out 3rd highest Cas Latency Value*/ + div = (dimmInfo->memoryType == DDR)? 100:10; + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / div; + rightOfPoint = time_tmp % div; + dimmInfo->clockToDataOutMinus2_LoP = leftOfPoint; + dimmInfo->clockToDataOutMinus2_RoP = rightOfPoint; + DP(printf("Clock To Data Out (3rd CL value): %d.%2d [ns]\n",leftOfPoint, rightOfPoint )); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 27: /* Minimum Row Precharge Time */ + shift = (dimmInfo->memoryType == DDR)? 2:0; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xfc:0xff; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0x03:0x00; + leftOfPoint = ((data[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (data[i] & maskRightOfPoint)*25; + + dimmInfo->minRowPrechargeTime = ((leftOfPoint*100) + rightOfPoint); /* measured in n times 10ps Intervals */ + trp_clocks = (dimmInfo->minRowPrechargeTime + (tmemclk-1)) / tmemclk; + DP(printf("*** 1 clock cycle = %ld 10ps intervalls = %ld.%ld ns****\n", tmemclk, tmemclk/100, tmemclk%100 )); + DP(printf("Minimum Row Precharge Time [ns]: %d.%2d = in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 28: /* Minimum Row Active to Row Active Time */ + shift = (dimmInfo->memoryType == DDR)? 2:0; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xfc:0xff; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0x03:0x00; + leftOfPoint = ((data[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (data[i] & maskRightOfPoint)*25; + + dimmInfo->minRowActiveRowActiveDelay = ((leftOfPoint*100) + rightOfPoint); /* measured in 100ns Intervals */ + trrd_clocks = (dimmInfo->minRowActiveRowActiveDelay + (tmemclk-1)) / tmemclk; + DP(printf("Minimum Row Active -To- Row Active Delay [ns]: %d.%2d = in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 29: /* Minimum Ras-To-Cas Delay */ + shift = (dimmInfo->memoryType == DDR)? 2:0; + maskLeftOfPoint = (dimmInfo->memoryType == DDR)? 0xfc:0xff; + maskRightOfPoint = (dimmInfo->memoryType == DDR)? 0x03:0x00; + leftOfPoint = ((data[i] & maskLeftOfPoint) >> shift); + rightOfPoint = (data[i] & maskRightOfPoint)*25; + + dimmInfo->minRowActiveRowActiveDelay = ((leftOfPoint*100) + rightOfPoint); /* measured in 100ns Intervals */ + trcd_clocks = (dimmInfo->minRowActiveRowActiveDelay + (tmemclk-1) )/ tmemclk; + DP(printf("Minimum Ras-To-Cas Delay [ns]: %d.%2d = in Clk cycles %d\n", leftOfPoint, rightOfPoint, trp_clocks)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 30: /* Minimum Ras Pulse Width */ + dimmInfo->minRasPulseWidth = data[i]; + tras_clocks = (NSto10PS(data[i])+(tmemclk-1)) / tmemclk; + DP(printf("Minimum Ras Pulse Width [ns]: %d = in Clk cycles %d\n", dimmInfo->minRasPulseWidth, tras_clocks)); + + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 31: /* Module Bank Density */ + dimmInfo->moduleBankDensity = data[i]; + DP(printf("Module Bank Density: %d\n", dimmInfo->moduleBankDensity)); +#ifdef DEBUG + DP(printf("*** Offered Densities (more than 1 = Multisize-Module): ")); + { + if (dimmInfo->moduleBankDensity & 1) + DP(printf("4MB, ")); + if (dimmInfo->moduleBankDensity & 2) + DP(printf("8MB, ")); + if (dimmInfo->moduleBankDensity & 4) + DP(printf("16MB, ")); + if (dimmInfo->moduleBankDensity & 8) + DP(printf("32MB, ")); + if (dimmInfo->moduleBankDensity & 16) + DP(printf("64MB, ")); + if (dimmInfo->moduleBankDensity & 32) + DP(printf("128MB, ")); + if ((dimmInfo->moduleBankDensity & 64) || (dimmInfo->moduleBankDensity & 128)) { + DP(printf("ERROR, ")); + hang(); + } + } + DP(printf("\n")); +#endif + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 32: /* Address And Command Setup Time (measured in ns/1000) */ + sign = 1; + switch(dimmInfo->memoryType) + { + case DDR: + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + break; + case SDRAM: + leftOfPoint = (data[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint = data[i] & 0x70 >> 4; + sign = -1; + } + rightOfPoint = (data[i] & 0x0f); + break; + } + dimmInfo->addrAndCommandSetupTime = (leftOfPoint*100 + rightOfPoint) * sign; + DP(printf("Address And Command Setup Time [ns]: %d.%d\n", sign*leftOfPoint, rightOfPoint)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 33: /* Address And Command Hold Time */ + sign = 1; + switch(dimmInfo->memoryType) + { + case DDR: + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + break; + case SDRAM: + leftOfPoint = (data[i] & 0xf0) >> 4; + if(leftOfPoint > 7) + { + leftOfPoint = data[i] & 0x70 >> 4; + sign = -1; + } + rightOfPoint = (data[i] & 0x0f) ; + break; + } + dimmInfo->addrAndCommandHoldTime = (leftOfPoint * 100 + rightOfPoint) * sign; + DP(printf("Address And Command Hold Time [ns]: %d.%d\n", sign*leftOfPoint, rightOfPoint)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 34: /* Data Input Setup Time */ + sign = 1; + switch(dimmInfo->memoryType) + { + case DDR: + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + break; + case SDRAM: + leftOfPoint = (data[i] & 0xf0) >> 4; + if( leftOfPoint > 7) + { + leftOfPoint = data[i] & 0x70 >> 4; + sign = -1; + } + rightOfPoint = (data[i] & 0x0f ); + break; + } + dimmInfo->dataInputSetupTime = (leftOfPoint *100 + rightOfPoint) * sign; + DP(printf("Data Input Setup Time [ns]: %d.%d\n", sign*leftOfPoint, rightOfPoint)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + + case 35: /* Data Input Hold Time */ + sign = 1; + switch(dimmInfo->memoryType) + { + case DDR: + time_tmp = (((data[i] & 0xf0) >> 4)*10) + ((data[i] & 0x0f)); + leftOfPoint = time_tmp / 100; + rightOfPoint = time_tmp % 100; + break; + case SDRAM: + leftOfPoint = (data[i] & 0xf0) >> 4; + if( leftOfPoint > 7) + { + leftOfPoint = data[i] & 0x70 >> 4; + sign = -1; + } + rightOfPoint = (data[i] & 0x0f) ; + break; + } + dimmInfo->dataInputHoldTime = (leftOfPoint *100 + rightOfPoint) * sign; + DP(printf("Data Input Hold Time [ns]: %d.%d\n\n", sign*leftOfPoint, rightOfPoint)); + break; +/*------------------------------------------------------------------------------------------------------------------------------*/ + } + } + /* calculating the sdram density */ + for(i = 0;i < dimmInfo->numOfRowAddresses + dimmInfo->numOfColAddresses;i++) + { + density = density*2; + } + dimmInfo->deviceDensity = density*dimmInfo->numOfBanksOnEachDevice* + dimmInfo->sdramWidth; + dimmInfo->numberOfDevices = (dimmInfo->dataWidth / dimmInfo->sdramWidth)* + dimmInfo->numOfModuleBanks; + devicesForErrCheck = (dimmInfo->dataWidth - 64) / dimmInfo->sdramWidth ; + if((dimmInfo->errorCheckType == 0x1) || + (dimmInfo->errorCheckType == 0x2) || + (dimmInfo->errorCheckType == 0x3)) + { + dimmInfo->size = (dimmInfo->deviceDensity / 8)* + (dimmInfo->numberOfDevices - devicesForErrCheck); + } + else + { + dimmInfo->size = (dimmInfo->deviceDensity/8)*dimmInfo->numberOfDevices; + } + + /* compute the module DRB size */ + tmp = (1 << (dimmInfo->numOfRowAddresses + dimmInfo->numOfColAddresses)); + tmp *= dimmInfo->numOfModuleBanks; + tmp *= dimmInfo->sdramWidth; + tmp = tmp >> 24; /* div by 0x4000000 (64M) */ + dimmInfo->drb_size = (uchar)tmp; + DP(printf("Module DRB size (n*64Mbit): %d\n", dimmInfo->drb_size)); + + /* try a CAS latency of 3 first... */ + + /* bit 1 is CL2, bit 2 is CL3 */ + supp_cal = (dimmInfo->suportedCasLatencies & 0x1c) >> 1; + + cal_val = 0; + if (supp_cal & 8) { + if (NS10to10PS(data[9]) <= tmemclk) + cal_val = 6; + } + if (supp_cal & 4) { + if (NS10to10PS(data[9]) <= tmemclk) + cal_val = 5; + } + + /* then 2... */ + if (supp_cal & 2) { + if (NS10to10PS(data[23]) <= tmemclk) + cal_val = 4; + } + + DP(printf("cal_val = %d\n", cal_val*5)); + + /* bummer, did't work... */ + if (cal_val == 0) { + DP(printf("Couldn't find a good CAS latency\n")); + hang(); + return 0; + } + + return true; +} + +/* sets up the GT properly with information passed in */ +int +setup_sdram(AUX_MEM_DIMM_INFO *info) +{ + ulong tmp, check; + ulong tmp_sdram_mode=0; /* 0x141c*/ + ulong tmp_dunit_control_low=0; /* 0x1404*/ + int i; + + /* sanity checking */ + if (! info->numOfModuleBanks) { + printf("setup_sdram called with 0 banks\n"); + return 1; + } + + /* delay line */ + + /* Program the GT with the discovered data */ + if (info->registeredAddrAndControlInputs == true) + DP(printf("Module is registered, but we do not support registered Modules !!!\n")); + + + /* delay line */ + set_dfcdlInit(); /* may be its not needed */ + DP(printf("Delay line set done\n")); + + /* set SDRAM mode NOP*/ /* To_do check it*/ + GT_REG_WRITE(SDRAM_OPERATION, 0x5); + while (GTREGREAD(SDRAM_OPERATION) != 0) { + DP(printf("\n*** SDRAM_OPERATION 1418: Module still busy ... please wait... ***\n")); + } + + /* SDRAM configuration */ + GT_REG_WRITE(SDRAM_CONFIG, 0x58200400); + DP(printf("sdram_conf 0x1400: %08x\n", GTREGREAD(SDRAM_CONFIG))); + + /* SDRAM open pages controll keep open as much as I can*/ + GT_REG_WRITE(SDRAM_OPEN_PAGES_CONTROL, 0x0); + DP(printf("sdram_open_pages_controll 0x1414: %08x\n", GTREGREAD(SDRAM_OPEN_PAGES_CONTROL))); + + + /* SDRAM D_UNIT_CONTROL_LOW 0x1404 */ + tmp = (GTREGREAD(D_UNIT_CONTROL_LOW) & 0x01); /* Clock Domain Sync from power on reset*/ + if (tmp == 0) + DP(printf("Core Signals are sync (by HW-Setting)!!!\n")); + else + DP(printf("Core Signals syncs. are bypassed (by HW-Setting)!!!\n")); + + /* SDRAM set CAS Lentency according to SPD information*/ + switch(info->memoryType) + { + case SDRAM: + DP(printf("### SD-RAM not supported yet !!!\n")); + hang(); + /* ToDo fill SD-RAM if needed !!!!!*/ + break; + + case DDR: + DP(printf("### SET-CL for DDR-RAM\n")); + + switch (info->maxClSupported_DDR) + { + case DDR_CL_3: + tmp_dunit_control_low = 0x3c000000; /* Read-Data sampled on falling edge of Clk*/ + tmp_sdram_mode = 0x32; /* CL=3 Burstlength = 4*/ + DP(printf("Max. CL is 3 CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + break; + + case DDR_CL_2_5: + if (tmp == 1) /* clocks sync*/ + { + tmp_dunit_control_low = 0x24000000; /* Read-Data sampled on falling edge of Clk*/ + tmp_sdram_mode = 0x62; /* CL=2,5 Burstlength = 4*/ + DP(printf("Max. CL is 2,5s CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + else /* clk sync. bypassed */ + { + tmp_dunit_control_low = 0x03000000; /* Read-Data sampled on rising edge of Clk*/ + tmp_sdram_mode = 0x62; /* CL=2,5 Burstlength = 4*/ + DP(printf("Max. CL is 2,5 CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + break; + + case DDR_CL_2: + if (tmp == 1) /* Sync*/ + { + tmp_dunit_control_low = 0x03000000; /* Read-Data sampled on rising edge of Clk*/ + tmp_sdram_mode = 0x22; /* CL=2 Burstlength = 4*/ + DP(printf("Max. CL is 2s CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + else /* Not sync. */ + { + tmp_dunit_control_low = 0x3b000000; /* Read-Data sampled on rising edge of Clk*/ + tmp_sdram_mode = 0x22; /* CL=2 Burstlength = 4*/ + DP(printf("Max. CL is 2 CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + break; + + case DDR_CL_1_5: + if (tmp == 1) /* Sync*/ + { + tmp_dunit_control_low = 0x23000000; /* Read-Data sampled on falling edge of Clk*/ + tmp_sdram_mode = 0x52; /* CL=1,5 Burstlength = 4*/ + DP(printf("Max. CL is 1,5s CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + else /* not sync*/ + { + tmp_dunit_control_low = 0x1a000000; /* Read-Data sampled on rising edge of Clk*/ + tmp_sdram_mode = 0x52; /* CL=1,5 Burstlength = 4*/ + DP(printf("Max. CL is 1,5 CLKs 0x141c= %08lx, 0x1404 = %08lx\n",tmp_sdram_mode, tmp_dunit_control_low )); + } + break; + + default: + printf("Max. CL is out of range %d\n", info->maxClSupported_DDR); + hang(); + break; + } + break; + } + + /* Write results of CL detection procedure */ + GT_REG_WRITE(SDRAM_MODE, tmp_sdram_mode); + /* set SDRAM mode SetCommand 0x1418*/ + GT_REG_WRITE(SDRAM_OPERATION, 0x3); + while (GTREGREAD(SDRAM_OPERATION) != 0) { + DP(printf("\n*** SDRAM_OPERATION 1418 after SDRAM_MODE: Module still busy ... please wait... ***\n")); + } + + + /* SDRAM D_UNIT_CONTROL_LOW 0x1404 */ + tmp = (GTREGREAD(D_UNIT_CONTROL_LOW) & 0x01); /* Clock Domain Sync from power on reset*/ + if (tmp != 1) /*clocks are not sync*/ + { + /* asyncmode*/ + GT_REG_WRITE(D_UNIT_CONTROL_LOW , + (GTREGREAD(D_UNIT_CONTROL_LOW) & 0x7F) | 0x18110780 | tmp_dunit_control_low ); + } + else + { + /* syncmode*/ + GT_REG_WRITE(D_UNIT_CONTROL_LOW , + (GTREGREAD(D_UNIT_CONTROL_LOW) & 0x7F) | 0x00110000 | tmp_dunit_control_low ); + } + + /* set SDRAM mode SetCommand 0x1418*/ + GT_REG_WRITE(SDRAM_OPERATION, 0x3); + while (GTREGREAD(SDRAM_OPERATION) != 0) { + DP(printf("\n*** SDRAM_OPERATION 1418 after D_UNIT_CONTROL_LOW: Module still busy ... please wait... ***\n")); + } + +/*------------------------------------------------------------------------------ */ + + + /* bank parameters */ + /* SDRAM address decode register */ + /* program this with the default value */ + tmp = 0x02; + + + DP(printf("drb_size (n*64Mbit): %d\n", info->drb_size)); + switch (info->drb_size) { + case 1: /* 64 Mbit */ + case 2: /* 128 Mbit */ + DP(printf("RAM-Device_size 64Mbit or 128Mbit)\n")); + tmp |= (0x00 << 4); + break; + case 4: /* 256 Mbit */ + case 8: /* 512 Mbit */ + DP(printf("RAM-Device_size 256Mbit or 512Mbit)\n")); + tmp |= (0x01 << 4); + break; + case 16: /* 1 Gbit */ + case 32: /* 2 Gbit */ + DP(printf("RAM-Device_size 1Gbit or 2Gbit)\n")); + tmp |= (0x02 << 4); + break; + default: + printf("Error in dram size calculation\n"); + DP(printf("Assume: RAM-Device_size 1Gbit or 2Gbit)\n")); + tmp |= (0x02 << 4); + return 1; + } + + /* SDRAM bank parameters */ + /* the param registers for slot 1 (banks 2+3) are offset by 0x8 */ + DP(printf("setting up slot %d config with: %08lx \n", info->slot, tmp)); + GT_REG_WRITE(SDRAM_ADDR_CONTROL, tmp); + +/* ------------------------------------------------------------------------------ */ + + DP(printf("setting up sdram_timing_control_low with: %08x \n", 0x11511220)); + GT_REG_WRITE(SDRAM_TIMING_CONTROL_LOW, 0x11511220); + + +/* ------------------------------------------------------------------------------ */ + + /* SDRAM configuration */ + tmp = GTREGREAD(SDRAM_CONFIG); + + if (info->registeredAddrAndControlInputs || info->registeredDQMBinputs) { + tmp |= (1 << 17); + DP(printf("SPD says: registered Addr. and Cont.: %d; registered DQMBinputs: %d\n",info->registeredAddrAndControlInputs, info->registeredDQMBinputs)); + } + + /* Use buffer 1 to return read data to the CPU + * Page 426 MV64360 */ + tmp |= (1 << 26); + DP(printf("Before Buffer assignment - sdram_conf: %08x\n", GTREGREAD(SDRAM_CONFIG))); + DP(printf("After Buffer assignment - sdram_conf: %08x\n", GTREGREAD(SDRAM_CONFIG))); + + /* SDRAM timing To_do:*/ + + + tmp = GTREGREAD(SDRAM_TIMING_CONTROL_HIGH); + DP(printf("# sdram_timing_control_high is : %08lx \n", tmp)); + + /* SDRAM address decode register */ + /* program this with the default value */ + tmp = GTREGREAD(SDRAM_ADDR_CONTROL); + DP(printf("SDRAM address control (before: decode): %08x ", GTREGREAD(SDRAM_ADDR_CONTROL))); + GT_REG_WRITE(SDRAM_ADDR_CONTROL, (tmp | 0x2)); + DP(printf("SDRAM address control (after: decode): %08x\n", GTREGREAD(SDRAM_ADDR_CONTROL))); + + /* set the SDRAM configuration for each bank */ + +/* for (i = info->slot * 2; i < ((info->slot * 2) + info->banks); i++) */ + { + i = info->slot; + DP(printf("\n*** Running a MRS cycle for bank %d ***\n", i)); + + /* map the bank */ + memory_map_bank(i, 0, GB/4); +#if 1 /* test only */ + /* set SDRAM mode */ /* To_do check it*/ + GT_REG_WRITE(SDRAM_OPERATION, 0x3); + check = GTREGREAD(SDRAM_OPERATION); + DP(printf("\n*** SDRAM_OPERATION 1418 (0 = Normal Operation) = %08lx ***\n", check)); + + + /* switch back to normal operation mode */ + GT_REG_WRITE(SDRAM_OPERATION, 0); + check = GTREGREAD(SDRAM_OPERATION); + DP(printf("\n*** SDRAM_OPERATION 1418 (0 = Normal Operation) = %08lx ***\n", check)); +#endif /* test only */ + /* unmap the bank */ + memory_map_bank(i, 0, 0); + } + + return 0; +} + +/* + * Check memory range for valid RAM. A simple memory test determines + * the actually available RAM size between addresses `base' and + * `base + maxsize'. Some (not all) hardware errors are detected: + * - short between address lines + * - short between data lines + */ +long int +dram_size(long int *base, long int maxsize) +{ + volatile long int *addr, *b=base; + long int cnt, val, save1, save2; + +#define STARTVAL (1<<20) /* start test at 1M */ + for (cnt = STARTVAL/sizeof(long); cnt < maxsize/sizeof(long); cnt <<= 1) { + addr = base + cnt; /* pointer arith! */ + + save1=*addr; /* save contents of addr */ + save2=*b; /* save contents of base */ + + *addr=cnt; /* write cnt to addr */ + *b=0; /* put null at base */ + + /* check at base address */ + if ((*b) != 0) { + *addr=save1; /* restore *addr */ + *b=save2; /* restore *b */ + return (0); + } + val = *addr; /* read *addr */ + val = *addr; /* read *addr */ + + *addr=save1; + *b=save2; + + if (val != cnt) { + DP(printf("Found %08x at Address %08x (failure)\n", (unsigned int)val, (unsigned int) addr)); + /* fix boundary condition.. STARTVAL means zero */ + if(cnt==STARTVAL/sizeof(long)) cnt=0; + return (cnt * sizeof(long)); + } + } + return maxsize; +} + +/* ------------------------------------------------------------------------- */ + +/* ppcboot interface function to SDRAM init - this is where all the + * controlling logic happens */ +long int +initdram(int board_type) +{ + int s0 = 0, s1 = 0; + int checkbank[4] = { [0 ... 3] = 0 }; + ulong bank_no, realsize, total, check; + AUX_MEM_DIMM_INFO dimmInfo1; + AUX_MEM_DIMM_INFO dimmInfo2; + int nhr; + + /* first, use the SPD to get info about the SDRAM/ DDRRAM */ + + /* check the NHR bit and skip mem init if it's already done */ + nhr = get_hid0() & (1 << 16); + + if (nhr) { + printf("Skipping SD- DDRRAM setup due to NHR bit being set\n"); + } else { + /* DIMM0 */ + s0 = check_dimm(0, &dimmInfo1); + + /* DIMM1 */ + s1 = check_dimm(1, &dimmInfo2); + + memory_map_bank(0, 0, 0); + memory_map_bank(1, 0, 0); + memory_map_bank(2, 0, 0); + memory_map_bank(3, 0, 0); + + if (dimmInfo1.numOfModuleBanks && setup_sdram(&dimmInfo1)) { + printf("Setup for DIMM1 failed.\n"); + } + + if (dimmInfo2.numOfModuleBanks && setup_sdram(&dimmInfo2)) { + printf("Setup for DIMM2 failed.\n"); + } + + /* set the NHR bit */ + set_hid0(get_hid0() | (1 << 16)); + } + /* next, size the SDRAM banks */ + + realsize = total = 0; + check = GB/4; + if (dimmInfo1.numOfModuleBanks > 0) {checkbank[0] = 1; printf("-- DIMM1 has 1 bank\n");} + if (dimmInfo1.numOfModuleBanks > 1) {checkbank[1] = 1; printf("-- DIMM1 has 2 banks\n");} + if (dimmInfo1.numOfModuleBanks > 2) + printf("Error, SPD claims DIMM1 has >2 banks\n"); + + if (dimmInfo2.numOfModuleBanks > 0) {checkbank[2] = 1; printf("-- DIMM2 has 1 bank\n");} + if (dimmInfo2.numOfModuleBanks > 1) {checkbank[3] = 1; printf("-- DIMM2 has 2 banks\n");} + if (dimmInfo2.numOfModuleBanks > 2) + printf("Error, SPD claims DIMM2 has >2 banks\n"); + + for (bank_no = 0; bank_no < CFG_DRAM_BANKS; bank_no++) { + /* skip over banks that are not populated */ + if (! checkbank[bank_no]) + continue; + + if ((total + check) > CFG_GT_REGS) + check = CFG_GT_REGS - total; + + memory_map_bank(bank_no, total, check); + realsize = dram_size((long int *)total, check); + memory_map_bank(bank_no, total, realsize); + + total += realsize; + } + +/* Setup Ethernet DMA Adress window to DRAM Area */ + return(total); +} + +/* *************************************************************************************** +! * SDRAM INIT * +! * This procedure detect all Sdram types: 64, 128, 256, 512 Mbit, 1Gbit and 2Gb * +! * This procedure fits only the Atlantis * +! * * +! *************************************************************************************** */ + + +/* *************************************************************************************** +! * DFCDL initialize MV643xx Design Considerations * +! * * +! *************************************************************************************** */ +int +set_dfcdlInit(void) +{ + int i; + unsigned int dfcdl_word = 0x0000014f; + for (i=0 ; i < 64; i++) + { + GT_REG_WRITE(SRAM_DATA0, dfcdl_word); + } + GT_REG_WRITE(DFCDL_CONFIG0, 0x00300000); /* enable dynamic delay line updating */ + + + return (0); +} + diff --git a/board/esd/cpci750/serial.c b/board/esd/cpci750/serial.c new file mode 100644 index 0000000000..01adb33f9f --- /dev/null +++ b/board/esd/cpci750/serial.c @@ -0,0 +1,110 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * modified for marvell db64360 eval board by + * Ingo Assmus + * + * modified for cpci750 board by + * Reinhard Arlt + * + * 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 + */ + +/* + * serial.c - serial support for esd cpci750 board + */ + +/* supports the MPSC */ + +#include +#include +#include "../../Marvell/include/memory.h" +#include "serial.h" + + +#include "mpsc.h" + +int serial_init (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + mpsc_init (gd->baudrate); + + return (0); +} + +void serial_putc (const char c) +{ + if (c == '\n') + mpsc_putchar ('\r'); + + mpsc_putchar (c); +} + +int serial_getc (void) +{ + return mpsc_getchar (); +} + +int serial_tstc (void) +{ + return mpsc_test_char (); +} + +void serial_setbrg (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + galbrg_set_baudrate (CONFIG_MPSC_PORT, gd->baudrate); +} + + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +void kgdb_serial_init (void) +{ +} + +void putDebugChar (int c) +{ + serial_putc (c); +} + +void putDebugStr (const char *str) +{ + serial_puts (str); +} + +int getDebugChar (void) +{ + return serial_getc (); +} + +void kgdb_interruptible (int yes) +{ + return; +} +#endif /* CFG_CMD_KGDB */ diff --git a/board/esd/cpci750/serial.h b/board/esd/cpci750/serial.h new file mode 100644 index 0000000000..c7fc8c162d --- /dev/null +++ b/board/esd/cpci750/serial.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * modified for marvell db64360 eval board by + * Ingo Assmus + * + * 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 + */ + +/* serial.h - mostly useful for DUART serial_init in serial.c */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#if 0 + +#define B230400 1 +#define B115200 2 +#define B57600 4 +#define B38400 82 +#define B19200 163 +#define B9600 24 +#define B4800 651 +#define B2400 1302 +#define B1200 2604 +#define B600 5208 +#define B300 10417 +#define B150 20833 +#define B110 28409 +#define BDEFAULT B115200 + + /* this stuff is important to initialize + the DUART channels */ + +#define Scale 0x01L /* distance between port addresses */ +#define COM1 0x000003f8 /* Keyboard */ +#define COM2 0x000002f8 /* Host */ + + +/* Port Definitions relative to base COM port addresses */ +#define DataIn (0x00*Scale) /* data input port */ +#define DataOut (0x00*Scale) /* data output port */ +#define BaudLsb (0x00*Scale) /* baud rate divisor least significant byte */ +#define BaudMsb (0x01*Scale) /* baud rate divisor most significant byte */ +#define Ier (0x01*Scale) /* interrupt enable register */ +#define Iir (0x02*Scale) /* interrupt identification register */ +#define Lcr (0x03*Scale) /* line control register */ +#define Mcr (0x04*Scale) /* modem control register */ +#define Lsr (0x05*Scale) /* line status register */ +#define Msr (0x06*Scale) /* modem status register */ + +/* Bit Definitions for above ports */ +#define LcrDlab 0x80 /* b7: enable baud rate divisor registers */ +#define LcrDflt 0x03 /* b6-0: no parity, 1 stop, 8 data */ + +#define McrRts 0x02 /* b1: request to send (I am ready to xmit) */ +#define McrDtr 0x01 /* b0: data terminal ready (I am alive ready to rcv) */ +#define McrDflt (McrRts|McrDtr) + +#define LsrTxD 0x6000 /* b5: transmit holding register empty (i.e. xmit OK!)*/ + /* b6: transmitter empty */ +#define LsrRxD 0x0100 /* b0: received data ready (i.e. got a byte!) */ + +#define MsrRi 0x0040 /* b6: ring indicator (other guy is ready to rcv) */ +#define MsrDsr 0x0020 /* b5: data set ready (other guy is alive ready to rcv */ +#define MsrCts 0x0010 /* b4: clear to send (other guy is ready to rcv) */ + +#define IerRda 0xf /* b0: Enable received data available interrupt */ + +#endif + +#endif /* __SERIAL_H__ */ diff --git a/board/esd/cpci750/strataflash.c b/board/esd/cpci750/strataflash.c new file mode 100644 index 0000000000..c22fe5df1d --- /dev/null +++ b/board/esd/cpci750/strataflash.c @@ -0,0 +1,763 @@ +/* + * (C) Copyright 2002 + * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#undef DEBUG_FLASH +/* + * This file implements a Common Flash Interface (CFI) driver for U-Boot. + * The width of the port and the width of the chips are determined at initialization. + * These widths are used to calculate the address for access CFI data structures. + * It has been tested on an Intel Strataflash implementation. + * + * References + * JEDEC Standard JESD68 - Common Flash Interface (CFI) + * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes + * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets + * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet + * + * TODO + * Use Primary Extended Query table (PRI) and Alternate Algorithm Query Table (ALT) to determine if protection is available + * Add support for other command sets Use the PRI and ALT to determine command set + * Verify erase and program timeouts. + */ + +#define FLASH_CMD_CFI 0x98 +#define FLASH_CMD_READ_ID 0x90 +#define FLASH_CMD_RESET 0xff +#define FLASH_CMD_BLOCK_ERASE 0x20 +#define FLASH_CMD_ERASE_CONFIRM 0xD0 +#define FLASH_CMD_WRITE 0x40 +#define FLASH_CMD_PROTECT 0x60 +#define FLASH_CMD_PROTECT_SET 0x01 +#define FLASH_CMD_PROTECT_CLEAR 0xD0 +#define FLASH_CMD_CLEAR_STATUS 0x50 +#define FLASH_CMD_WRITE_TO_BUFFER 0xE8 +#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 + +#define FLASH_STATUS_DONE 0x80 +#define FLASH_STATUS_ESS 0x40 +#define FLASH_STATUS_ECLBS 0x20 +#define FLASH_STATUS_PSLBS 0x10 +#define FLASH_STATUS_VPENS 0x08 +#define FLASH_STATUS_PSS 0x04 +#define FLASH_STATUS_DPS 0x02 +#define FLASH_STATUS_R 0x01 +#define FLASH_STATUS_PROTECT 0x01 + +#define FLASH_OFFSET_CFI 0x55 +#define FLASH_OFFSET_CFI_RESP 0x10 +#define FLASH_OFFSET_WTOUT 0x1F +#define FLASH_OFFSET_WBTOUT 0x20 +#define FLASH_OFFSET_ETOUT 0x21 +#define FLASH_OFFSET_CETOUT 0x22 +#define FLASH_OFFSET_WMAX_TOUT 0x23 +#define FLASH_OFFSET_WBMAX_TOUT 0x24 +#define FLASH_OFFSET_EMAX_TOUT 0x25 +#define FLASH_OFFSET_CEMAX_TOUT 0x26 +#define FLASH_OFFSET_SIZE 0x27 +#define FLASH_OFFSET_INTERFACE 0x28 +#define FLASH_OFFSET_BUFFER_SIZE 0x2A +#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C +#define FLASH_OFFSET_ERASE_REGIONS 0x2D +#define FLASH_OFFSET_PROTECT 0x02 +#define FLASH_OFFSET_USER_PROTECTION 0x85 +#define FLASH_OFFSET_INTEL_PROTECTION 0x81 + + +#define FLASH_MAN_CFI 0x01000000 + + +typedef union { + unsigned char c; + unsigned short w; + unsigned long l; +} cfiword_t; + +typedef union { + unsigned char * cp; + unsigned short *wp; + unsigned long *lp; +} cfiptr_t; + +#define NUM_ERASE_REGIONS 4 + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + + +/*----------------------------------------------------------------------- + * Functions + */ + + +static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c); +static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf); +static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, uchar cmd); +static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd); +static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd); +static int flash_detect_cfi(flash_info_t * info); +static ulong flash_get_size (ulong base, int banknum); +static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword); +static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt); +#ifdef CFG_FLASH_USE_BUFFER_WRITE +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len); +#endif +/*----------------------------------------------------------------------- + * create an address based on the offset and the port width + */ +inline uchar * flash_make_addr(flash_info_t * info, int sect, int offset) +{ + return ((uchar *)(info->start[sect] + (offset * info->portwidth))); +} +/*----------------------------------------------------------------------- + * read a character at a port width address + */ +inline uchar flash_read_uchar(flash_info_t * info, uchar offset) +{ + uchar *cp; + cp = flash_make_addr(info, 0, offset); + return (cp[info->portwidth - 1]); +} + +/*----------------------------------------------------------------------- + * read a short word by swapping for ppc format. + */ +ushort flash_read_ushort(flash_info_t * info, int sect, uchar offset) +{ + uchar * addr; + + addr = flash_make_addr(info, sect, offset); + return ((addr[(2*info->portwidth) - 1] << 8) | addr[info->portwidth - 1]); + +} + +/*----------------------------------------------------------------------- + * read a long word by picking the least significant byte of each maiximum + * port size word. Swap for ppc format. + */ +ulong flash_read_long(flash_info_t * info, int sect, uchar offset) +{ + uchar * addr; + + addr = flash_make_addr(info, sect, offset); + return ( (addr[(2*info->portwidth) - 1] << 24 ) | (addr[(info->portwidth) -1] << 16) | + (addr[(4*info->portwidth) - 1] << 8) | addr[(3*info->portwidth) - 1]); + +} + +/*----------------------------------------------------------------------- + */ +unsigned long flash_init (void) +{ + unsigned long size; + int i; + unsigned long address; + + + /* The flash is positioned back to back, with the demultiplexing of the chip + * based on the A24 address line. + * + */ + + address = CFG_FLASH_BASE; + size = 0; + + /* Init: no FLASHes known */ + for (i=0; i= CFG_FLASH_BASE) + for(i=0; flash_info[0].start[i] < CFG_MONITOR_BASE+monitor_flash_len-1; i++) + (void)flash_real_protect(&flash_info[0], i, 1); +#endif +#endif + + return (size); +} + +/*----------------------------------------------------------------------- + */ +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + int rcode = 0; + int prot; + int sect; + + if( info->flash_id != FLASH_MAN_CFI) { + printf ("Can't erase unknown flash type - aborted\n"); + return 1; + } + if ((s_first < 0) || (s_first > s_last)) { + printf ("- no sectors to erase\n"); + 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"); + } + + + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE); + flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM); + + if(flash_full_status_check(info, sect, info->erase_blk_tout, "erase")) { + rcode = 1; + } else + printf("."); + } + } + printf (" done\n"); + return rcode; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t *info) +{ + int i; + + if (info->flash_id != FLASH_MAN_CFI) { + printf ("missing or unknown FLASH type\n"); + return; + } + + printf("CFI conformant FLASH (%d x %d)", + (info->portwidth << 3 ), (info->chipwidth << 3 )); + printf (" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + printf(" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n", + info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size); + + printf (" Sector Start Addresses:"); + for (i=0; isector_count; ++i) { + if ((i % 5) == 0) + printf ("\n"); + printf (" %08lX%5s", + info->start[i], + info->protect[i] ? " (RO)" : " " + ); + } + printf ("\n"); + return; +} + +/*----------------------------------------------------------------------- + * 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) +{ + ulong wp; + ulong cp; + int aln; + cfiword_t cword; + int i, rc; + + /* get lower aligned address */ + wp = (addr & ~(info->portwidth - 1)); + + /* handle unaligned start */ + if((aln = addr - wp) != 0) { + cword.l = 0; + cp = wp; + for(i=0;iportwidth) && (cnt > 0) ; i++) { + flash_add_byte(info, &cword, *src++); + cnt--; + cp++; + } + for(; (cnt == 0) && (i < info->portwidth); ++i, ++cp) + flash_add_byte(info, &cword, (*(uchar *)cp)); + if((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp = cp; + } + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + while(cnt >= info->portwidth) { + i = info->buffer_size > cnt? cnt: info->buffer_size; + if((rc = flash_write_cfibuffer(info, wp, src,i)) != ERR_OK) + return rc; + wp += i; + src += i; + cnt -=i; + } +#else + /* handle the aligned part */ + while(cnt >= info->portwidth) { + cword.l = 0; + for(i = 0; i < info->portwidth; i++) { + flash_add_byte(info, &cword, *src++); + } + if((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp += info->portwidth; + cnt -= info->portwidth; + } +#endif /* CFG_FLASH_USE_BUFFER_WRITE */ + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + cword.l = 0; + for (i=0, cp=wp; (iportwidth) && (cnt>0); ++i, ++cp) { + flash_add_byte(info, &cword, *src++); + --cnt; + } + for (; iportwidth; ++i, ++cp) { + flash_add_byte(info, & cword, (*(uchar *)cp)); + } + + return flash_write_cfiword(info, wp, cword); +} + +/*----------------------------------------------------------------------- + */ +int flash_real_protect(flash_info_t *info, long sector, int prot) +{ + int retcode = 0; + + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT); + if(prot) + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_SET); + else + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR); + + if((retcode = flash_full_status_check(info, sector, info->erase_blk_tout, + prot?"protect":"unprotect")) == 0) { + + info->protect[sector] = prot; + /* Intel's unprotect unprotects all locking */ + if(prot == 0) { + int i; + for(i = 0 ; isector_count; i++) { + if(info->protect[i]) + flash_real_protect(info, i, 1); + } + } + } + + return retcode; +} +/*----------------------------------------------------------------------- + * wait for XSR.7 to be set. Time out with an error if it does not. + * This routine does not set the flash to read-array mode. + */ +static int flash_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt) +{ + ulong start; + + /* Wait for command completion */ + start = get_timer (0); + while(!flash_isset(info, sector, 0, FLASH_STATUS_DONE)) { + if (get_timer(start) > info->erase_blk_tout) { + printf("Flash %s timeout at address %lx\n", prompt, info->start[sector]); + flash_write_cmd(info, sector, 0, FLASH_CMD_RESET); + return ERR_TIMOUT; + } + } + return ERR_OK; +} +/*----------------------------------------------------------------------- + * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. + * This routine sets the flash to read-array mode. + */ +static int flash_full_status_check(flash_info_t * info, ulong sector, ulong tout, char * prompt) +{ + int retcode; + retcode = flash_status_check(info, sector, tout, prompt); + if((retcode == ERR_OK) && !flash_isequal(info,sector, 0, FLASH_STATUS_DONE)) { + retcode = ERR_INVAL; + printf("Flash %s error at address %lx\n", prompt,info->start[sector]); + if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)){ + printf("Command Sequence Error.\n"); + } else if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS)){ + printf("Block Erase Error.\n"); + retcode = ERR_NOT_ERASED; + } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) { + printf("Locking Error\n"); + } + if(flash_isset(info, sector, 0, FLASH_STATUS_DPS)){ + printf("Block locked.\n"); + retcode = ERR_PROTECTED; + } + if(flash_isset(info, sector, 0, FLASH_STATUS_VPENS)) + printf("Vpp Low Error.\n"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_RESET); + return retcode; +} +/*----------------------------------------------------------------------- + */ +static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c) +{ + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cword->c = c; + break; + case FLASH_CFI_16BIT: + cword->w = (cword->w << 8) | c; + break; + case FLASH_CFI_32BIT: + cword->l = (cword->l << 8) | c; + } +} + + +/*----------------------------------------------------------------------- + * make a proper sized command based on the port and chip widths + */ +static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf) +{ + int i; + uchar *cp = (uchar *)cmdbuf; + for(i=0; i< info->portwidth; i++) + *cp++ = ((i+1) % info->chipwidth) ? '\0':cmd; +} + +/* + * Write a proper sized command to the correct address + */ +static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, uchar cmd) +{ + + volatile cfiptr_t addr; + cfiword_t cword; + addr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + *addr.cp = cword.c; + break; + case FLASH_CFI_16BIT: + *addr.wp = cword.w; + break; + case FLASH_CFI_32BIT: + *addr.lp = cword.l; + break; + } +} + +/*----------------------------------------------------------------------- + */ +static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + retval = (cptr.cp[0] == cword.c); + break; + case FLASH_CFI_16BIT: + retval = (cptr.wp[0] == cword.w); + break; + case FLASH_CFI_32BIT: + retval = (cptr.lp[0] == cword.l); + break; + default: + retval = 0; + break; + } + return retval; +} +/*----------------------------------------------------------------------- + */ +static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + retval = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + retval = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + retval = ((cptr.lp[0] & cword.l) == cword.l); + break; + default: + retval = 0; + break; + } + return retval; +} + +/*----------------------------------------------------------------------- + * detect if flash is compatible with the Common Flash Interface (CFI) + * http://www.jedec.org/download/search/jesd68.pdf + * + */ +static int flash_detect_cfi(flash_info_t * info) +{ + + for(info->portwidth=FLASH_CFI_8BIT; info->portwidth <= FLASH_CFI_32BIT; + info->portwidth <<= 1) { + for(info->chipwidth =FLASH_CFI_BY8; + info->chipwidth <= info->portwidth; + info->chipwidth <<= 1) { + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + flash_write_cmd(info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI); + if(flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP,'Q') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) + return 1; + } + } + return 0; +} +/* + * The following code cannot be run from FLASH! + * + */ +static ulong flash_get_size (ulong base, int banknum) +{ + flash_info_t * info = &flash_info[banknum]; + int i, j; + int sect_cnt; + unsigned long sector; + unsigned long tmp; + int size_ratio = 0; + uchar num_erase_regions; + int erase_region_size; + int erase_region_count; + + info->start[0] = base; + + invalidate_dcache_range(base, base+0x400); + + if(flash_detect_cfi(info)){ + + size_ratio = info->portwidth / info->chipwidth; + num_erase_regions = flash_read_uchar(info, FLASH_OFFSET_NUM_ERASE_REGIONS); + + sect_cnt = 0; + sector = base; + for(i = 0 ; i < num_erase_regions; i++) { + if(i > NUM_ERASE_REGIONS) { + printf("%d erase regions found, only %d used\n", + num_erase_regions, NUM_ERASE_REGIONS); + break; + } + tmp = flash_read_long(info, 0, FLASH_OFFSET_ERASE_REGIONS); + erase_region_size = (tmp & 0xffff)? ((tmp & 0xffff) * 256): 128; + tmp >>= 16; + erase_region_count = (tmp & 0xffff) +1; + for(j = 0; j< erase_region_count; j++) { + info->start[sect_cnt] = sector; + sector += (erase_region_size * size_ratio); + info->protect[sect_cnt] = flash_isset(info, sect_cnt, FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT); + sect_cnt++; + } + } + + info->sector_count = sect_cnt; + /* multiply the size by the number of chips */ + info->size = (1 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * size_ratio; + info->buffer_size = (1 << flash_read_ushort(info, 0, FLASH_OFFSET_BUFFER_SIZE)); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_ETOUT); + info->erase_blk_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_EMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WBTOUT); + info->buffer_write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WBMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WTOUT); + info->write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WMAX_TOUT)))/ 1000; + info->flash_id = FLASH_MAN_CFI; + } + + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +#ifdef DEBUG_FLASH + printf("portwidth=%d chipwidth=%d\n", info->portwidth, info->chipwidth); /* test-only */ +#endif +#ifdef DEBUG_FLASH + printf("found %d erase regions\n", num_erase_regions); +#endif +#ifdef DEBUG_FLASH + printf("size=%08x sectors=%08x \n", info->size, info->sector_count); +#endif + return(info->size); +} + + +/*----------------------------------------------------------------------- + */ +static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword) +{ + + cfiptr_t ctladdr; + cfiptr_t cptr; + int flag; + + ctladdr.cp = flash_make_addr(info, 0, 0); + cptr.cp = (uchar *)dest; + + + /* Check if Flash is (sufficiently) erased */ + switch(info->portwidth) { + case FLASH_CFI_8BIT: + flag = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + flag = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + flag = ((cptr.lp[0] & cword.l) == cword.l); + break; + default: + return 2; + } + if(!flag) + return 2; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE); + + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cptr.cp[0] = cword.c; + break; + case FLASH_CFI_16BIT: + cptr.wp[0] = cword.w; + break; + case FLASH_CFI_32BIT: + cptr.lp[0] = cword.l; + break; + } + + /* re-enable interrupts if necessary */ + if(flag) + enable_interrupts(); + + return flash_full_status_check(info, 0, info->write_tout, "write"); +} + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + +/* loop through the sectors from the highest address + * when the passed address is greater or equal to the sector address + * we have a match + */ +static int find_sector(flash_info_t *info, ulong addr) +{ + int sector; + for(sector = info->sector_count - 1; sector >= 0; sector--) { + if(addr >= info->start[sector]) + break; + } + return sector; +} + +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len) +{ + + int sector; + int cnt; + int retcode; + volatile cfiptr_t src; + volatile cfiptr_t dst; + + src.cp = cp; + dst.cp = (uchar *)dest; + sector = find_sector(info, dest); + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); + if((retcode = flash_status_check(info, sector, info->buffer_write_tout, + "write to buffer")) == ERR_OK) { + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cnt = len; + break; + case FLASH_CFI_16BIT: + cnt = len >> 1; + break; + case FLASH_CFI_32BIT: + cnt = len >> 2; + break; + default: + return ERR_INVAL; + break; + } + flash_write_cmd(info, sector, 0, (uchar)cnt-1); + while(cnt-- > 0) { + switch(info->portwidth) { + case FLASH_CFI_8BIT: + *dst.cp++ = *src.cp++; + break; + case FLASH_CFI_16BIT: + *dst.wp++ = *src.wp++; + break; + case FLASH_CFI_32BIT: + *dst.lp++ = *src.lp++; + break; + default: + return ERR_INVAL; + break; + } + } + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM); + retcode = flash_full_status_check(info, sector, info->buffer_write_tout, + "buffer write"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + return retcode; +} +#endif /* CFG_USE_FLASH_BUFFER_WRITE */ diff --git a/board/esd/cpci750/u-boot.lds b/board/esd/cpci750/u-boot.lds new file mode 100644 index 0000000000..0dfa8c0005 --- /dev/null +++ b/board/esd/cpci750/u-boot.lds @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2001 + * Josh Huber , Mission Critical Linux, Inc. + * + * 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 + */ + +/* + * u-boot.lds - linker script for U-Boot on the Galileo Eval Board. + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/74xx_7xx/start.o (.text) + +/* store the environment in a seperate sector in the boot flash */ +/* . = env_offset; */ +/* common/environment.o(.text) */ + + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2; + __fixup_entries = (. - _FIXUP_TABLE_)>>2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +}