diff options
author | wdenk <wdenk> | 2002-11-03 00:24:07 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2002-11-03 00:24:07 +0000 |
commit | c609719b8d1b2dca590e0ed499016d041203e403 (patch) | |
tree | 7ea1755d80903ff972f312a249eb856061d40e15 /board/siemens | |
parent | 5b1d713721c3ea02549940133f09236783dda1f9 (diff) |
Initial revision
Diffstat (limited to 'board/siemens')
-rw-r--r-- | board/siemens/CCM/ccm.c | 440 | ||||
-rw-r--r-- | board/siemens/CCM/fpga_ccm.c | 170 | ||||
-rw-r--r-- | board/siemens/SCM/fpga_scm.c | 104 | ||||
-rw-r--r-- | board/siemens/common/README | 27 | ||||
-rw-r--r-- | board/siemens/common/fpga.c | 358 |
5 files changed, 1099 insertions, 0 deletions
diff --git a/board/siemens/CCM/ccm.c b/board/siemens/CCM/ccm.c new file mode 100644 index 00000000000..079f38f7ec9 --- /dev/null +++ b/board/siemens/CCM/ccm.c @@ -0,0 +1,440 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc8xx.h> +#include <commproc.h> +#include <command.h> + +/* ------------------------------------------------------------------------- */ + +static long int dram_size (long int, long int *, long int); +void can_driver_enable (void); +void can_driver_disable (void); + +int fpga_init(void); + +/* ------------------------------------------------------------------------- */ + +#define _NOT_USED_ 0xFFFFFFFF + +const uint sdram_table[] = +{ + /* + * Single Read. (Offset 0 in UPMA RAM) + */ + 0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBAFC00, + 0x1FF5FC47, /* last */ + /* + * SDRAM Initialization (offset 5 in UPMA RAM) + * + * This is no UPM entry point. The following definition uses + * the remaining space to establish an initialization + * sequence, which is executed by a RUN command. + * + */ + 0x1FF5FC34, 0xEFEABC34, 0x1FB57C35, /* last */ + /* + * Burst Read. (Offset 8 in UPMA RAM) + */ + 0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00, + 0xF0AFFC00, 0xF1AFFC00, 0xEFBAFC00, 0x1FF5FC47, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Single Write. (Offset 18 in UPMA RAM) + */ + 0x1F0DFC04, 0xEEABBC00, 0x01B27C04, 0x1FF5FC47, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Burst Write. (Offset 20 in UPMA RAM) + */ + 0x1F0DFC04, 0xEEABBC00, 0x10A77C00, 0xF0AFFC00, + 0xF0AFFC00, 0xE1BAFC04, 0x1FF5FC47, /* last */ + _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Refresh (Offset 30 in UPMA RAM) + */ + 0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, + 0xFFFFFC84, 0xFFFFFC07, /* last */ + _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Exception. (Offset 3c in UPMA RAM) + */ + 0x7FFFFC07, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, +}; + +/* ------------------------------------------------------------------------- */ + + +/* + * Check Board Identity: + * + * Always return 1 (no second DRAM bank since based on TQM8xxL module) + */ + +int checkboard (void) +{ + unsigned char *s; + unsigned char buf[64]; + + s = (getenv_r ("serial#", buf, sizeof(buf)) > 0) ? buf : NULL; + + puts ("Board: Siemens CCM"); + + if (s) { + puts (" ("); + + for (; *s; ++s) { + if (*s == ' ') + break; + putc (*s); + } + putc (')'); + } + + putc ('\n'); + + return (0); +} + +/* ------------------------------------------------------------------------- */ + +/* + * If Power-On-Reset switch off the Red and Green LED: At reset, the + * data direction registers are cleared and must therefore be restored. + */ +#define RSR_CSRS 0x08000000 + +int power_on_reset(void) +{ + /* Test Reset Status Register */ + return ((volatile immap_t *)CFG_IMMR)->im_clkrst.car_rsr & RSR_CSRS ? 0:1; +} + +#define PB_LED_GREEN 0x10000 /* red LED is on PB.15 */ +#define PB_LED_RED 0x20000 /* red LED is on PB.14 */ +#define PB_LEDS (PB_LED_GREEN | PB_LED_RED); + +static void init_leds (void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpm.cp_pbpar &= ~PB_LEDS; + immap->im_cpm.cp_pbodr &= ~PB_LEDS; + immap->im_cpm.cp_pbdir |= PB_LEDS; + /* Check stop reset status */ + if (power_on_reset()) { + immap->im_cpm.cp_pbdat &= ~PB_LEDS; + } +} + +/* ------------------------------------------------------------------------- */ + +long int initdram (int board_type) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + long int size8, size9; + long int size = 0; + unsigned long reg; + + upmconfig(UPMA, (uint *)sdram_table, sizeof(sdram_table)/sizeof(uint)); + + /* + * Preliminary prescaler for refresh (depends on number of + * banks): This value is selected for four cycles every 62.4 us + * with two SDRAM banks or four cycles every 31.2 us with one + * bank. It will be adjusted after memory sizing. + */ + memctl->memc_mptpr = CFG_MPTPR_2BK_8K; + + memctl->memc_mar = 0x00000088; + + /* + * Map controller banks 2 and 3 to the SDRAM banks 2 and 3 at + * preliminary addresses - these have to be modified after the + * SDRAM size has been determined. + */ + memctl->memc_or2 = CFG_OR2_PRELIM; + memctl->memc_br2 = CFG_BR2_PRELIM; + + memctl->memc_mamr = CFG_MAMR_8COL & (~(MAMR_PTAE)); /* no refresh yet */ + + udelay(200); + + /* perform SDRAM initializsation sequence */ + + memctl->memc_mcr = 0x80004105; /* SDRAM bank 0 */ + udelay(1); + memctl->memc_mcr = 0x80004230; /* SDRAM bank 0 - execute twice */ + udelay(1); + + memctl->memc_mamr |= MAMR_PTAE; /* enable refresh */ + + udelay (1000); + + /* + * Check Bank 0 Memory Size for re-configuration + * + * try 8 column mode + */ + size8 = dram_size (CFG_MAMR_8COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE); + + udelay (1000); + + /* + * try 9 column mode + */ + size9 = dram_size (CFG_MAMR_9COL, (ulong *)SDRAM_BASE2_PRELIM, SDRAM_MAX_SIZE); + + if (size8 < size9) { /* leave configuration at 9 columns */ + size = size9; +/* debug ("SDRAM in 9 column mode: %ld MB\n", size >> 20); */ + } else { /* back to 8 columns */ + size = size8; + memctl->memc_mamr = CFG_MAMR_8COL; + udelay(500); +/* debug ("SDRAM in 8 column mode: %ld MB\n", size >> 20); */ + } + + udelay (1000); + + /* + * Adjust refresh rate depending on SDRAM type + * For types > 128 MBit leave it at the current (fast) rate + */ + if (size < 0x02000000) { + /* reduce to 15.6 us (62.4 us / quad) */ + memctl->memc_mptpr = CFG_MPTPR_2BK_4K; + udelay(1000); + } + + /* + * Final mapping + */ + + memctl->memc_or2 = ((-size) & 0xFFFF0000) | CFG_OR_TIMING_SDRAM; + memctl->memc_br2 = (CFG_SDRAM_BASE & BR_BA_MSK) | BR_MS_UPMA | BR_V; + + + /* adjust refresh rate depending on SDRAM type, one bank */ + reg = memctl->memc_mptpr; + reg >>= 1; /* reduce to CFG_MPTPR_1BK_8K / _4K */ + memctl->memc_mptpr = reg; + + can_driver_enable (); + init_leds (); + + udelay(10000); + + return (size); +} + +/* ------------------------------------------------------------------------- */ + +/* + * Warning - both the PUMA load mode and the CAN driver use UPM B, + * so make sure only one of both is active. + */ +void can_driver_enable (void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + + /* Initialize MBMR */ + memctl->memc_mbmr = MAMR_GPL_B4DIS; /* GPL_B4 ouput line Disable */ + + /* Initialize UPMB for CAN: single read */ + memctl->memc_mdr = 0xFFFFC004; + memctl->memc_mcr = 0x0100 | UPMB; + + memctl->memc_mdr = 0x0FFFD004; + memctl->memc_mcr = 0x0101 | UPMB; + + memctl->memc_mdr = 0x0FFFC000; + memctl->memc_mcr = 0x0102 | UPMB; + + memctl->memc_mdr = 0x3FFFC004; + memctl->memc_mcr = 0x0103 | UPMB; + + memctl->memc_mdr = 0xFFFFDC05; + memctl->memc_mcr = 0x0104 | UPMB; + + /* Initialize UPMB for CAN: single write */ + memctl->memc_mdr = 0xFFFCC004; + memctl->memc_mcr = 0x0118 | UPMB; + + memctl->memc_mdr = 0xCFFCD004; + memctl->memc_mcr = 0x0119 | UPMB; + + memctl->memc_mdr = 0x0FFCC000; + memctl->memc_mcr = 0x011A | UPMB; + + memctl->memc_mdr = 0x7FFCC004; + memctl->memc_mcr = 0x011B | UPMB; + + memctl->memc_mdr = 0xFFFDCC05; + memctl->memc_mcr = 0x011C | UPMB; + + /* Initialize OR3 / BR3 for CAN Bus Controller */ + memctl->memc_or3 = CFG_OR3_CAN; + memctl->memc_br3 = CFG_BR3_CAN; +} + +void can_driver_disable (void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + + /* Reset OR3 / BR3 to disable CAN Bus Controller */ + memctl->memc_br3 = 0; + memctl->memc_or3 = 0; + + memctl->memc_mbmr = 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 + */ + +static long int dram_size (long int mamr_value, long int *base, long int maxsize) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + volatile long int *addr; + ulong cnt, val; + ulong save[32]; /* to make test non-destructive */ + unsigned char i = 0; + + memctl->memc_mamr = mamr_value; + + for (cnt = maxsize/sizeof(long); cnt > 0; cnt >>= 1) { + addr = base + cnt; /* pointer arith! */ + + save[i++] = *addr; + *addr = ~cnt; + } + + /* write 0 to base address */ + addr = base; + save[i] = *addr; + *addr = 0; + + /* check at base address */ + if ((val = *addr) != 0) { + *addr = save[i]; + return (0); + } + + for (cnt = 1; cnt <= maxsize/sizeof(long); cnt <<= 1) { + addr = base + cnt; /* pointer arith! */ + + val = *addr; + *addr = save[--i]; + + if (val != (~cnt)) { + return (cnt * sizeof(long)); + } + } + return (maxsize); +} + +/* ------------------------------------------------------------------------- */ + +#define ETH_CFG_BITS (CFG_PB_ETH_CFG1 | CFG_PB_ETH_CFG2 | CFG_PB_ETH_CFG3 ) + +#define ETH_ALL_BITS (ETH_CFG_BITS | CFG_PB_ETH_POWERDOWN) + +void reset_phy(void) +{ + immap_t *immr = (immap_t *)CFG_IMMR; + ulong value; + + /* Configure all needed port pins for GPIO */ +#if CFG_ETH_MDDIS_VALUE + immr->im_ioport.iop_padat |= CFG_PA_ETH_MDDIS; +#else + immr->im_ioport.iop_padat &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET); /* Set low */ +#endif + immr->im_ioport.iop_papar &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET); /* GPIO */ + immr->im_ioport.iop_paodr &= ~(CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET); /* active output */ + immr->im_ioport.iop_padir |= CFG_PA_ETH_MDDIS | CFG_PA_ETH_RESET; /* output */ + + immr->im_cpm.cp_pbpar &= ~(ETH_ALL_BITS); /* GPIO */ + immr->im_cpm.cp_pbodr &= ~(ETH_ALL_BITS); /* active output */ + + value = immr->im_cpm.cp_pbdat; + + /* Assert Powerdown and Reset signals */ + value |= CFG_PB_ETH_POWERDOWN; + + /* PHY configuration includes MDDIS and CFG1 ... CFG3 */ +#if CFG_ETH_CFG1_VALUE + value |= CFG_PB_ETH_CFG1; +#else + value &= ~(CFG_PB_ETH_CFG1); +#endif +#if CFG_ETH_CFG2_VALUE + value |= CFG_PB_ETH_CFG2; +#else + value &= ~(CFG_PB_ETH_CFG2); +#endif +#if CFG_ETH_CFG3_VALUE + value |= CFG_PB_ETH_CFG3; +#else + value &= ~(CFG_PB_ETH_CFG3); +#endif + + /* Drive output signals to initial state */ + immr->im_cpm.cp_pbdat = value; + immr->im_cpm.cp_pbdir |= ETH_ALL_BITS; + udelay (10000); + + /* De-assert Ethernet Powerdown */ + immr->im_cpm.cp_pbdat &= ~(CFG_PB_ETH_POWERDOWN); /* Enable PHY power */ + udelay (10000); + + /* de-assert RESET signal of PHY */ + immr->im_ioport.iop_padat |= CFG_PA_ETH_RESET; + udelay (1000); +} + + +int misc_init_r (void) +{ + fpga_init(); + return (0); +} +/* ------------------------------------------------------------------------- */ diff --git a/board/siemens/CCM/fpga_ccm.c b/board/siemens/CCM/fpga_ccm.c new file mode 100644 index 00000000000..292387b524b --- /dev/null +++ b/board/siemens/CCM/fpga_ccm.c @@ -0,0 +1,170 @@ +/* + * (C) Copyright 2002 + * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <mpc8xx.h> +#include <commproc.h> +#include <common.h> + +#include "../common/fpga.h" + +fpga_t fpga_list[] = { + { "PUMA" , PUMA_CONF_BASE , + CFG_PC_PUMA_INIT , CFG_PC_PUMA_PROG , CFG_PC_PUMA_DONE } +}; +int fpga_count = sizeof(fpga_list) / sizeof(fpga_t); + +void can_driver_enable (void); +void can_driver_disable (void); + +#define _NOT_USED_ 0xFFFFFFFF + +/* + * PUMA access using UPM B + */ +const uint puma_table[] = +{ + /* + * Single Read. (Offset 0 in UPM RAM) + */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, + /* + * Precharge and MRS + */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Burst Read. (Offset 8 in UPM RAM) + */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Single Write. (Offset 18 in UPM RAM) + */ + 0x0FFCF804, 0x0FFCF400, 0x3FFDFC47, /* last */ + _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Burst Write. (Offset 20 in UPM RAM) + */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Refresh (Offset 30 in UPM RAM) + */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + _NOT_USED_, _NOT_USED_, _NOT_USED_, _NOT_USED_, + /* + * Exception. (Offset 3c in UPM RAM) + */ + 0x7FFFFC07, /* last */ + _NOT_USED_, _NOT_USED_, _NOT_USED_, +}; + + +ulong fpga_control (fpga_t* fpga, int cmd) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + volatile memctl8xx_t *memctl = &immr->im_memctl; + + switch (cmd) { + case FPGA_INIT_IS_HIGH: + immr->im_ioport.iop_pcdir &= ~fpga->init_mask; /* input */ + return (immr->im_ioport.iop_pcdat & fpga->init_mask) ? 1:0; + + case FPGA_INIT_SET_LOW: + immr->im_ioport.iop_pcdir |= fpga->init_mask; /* output */ + immr->im_ioport.iop_pcdat &= ~fpga->init_mask; + break; + + case FPGA_INIT_SET_HIGH: + immr->im_ioport.iop_pcdir |= fpga->init_mask; /* output */ + immr->im_ioport.iop_pcdat |= fpga->init_mask; + break; + + case FPGA_PROG_SET_LOW: + immr->im_ioport.iop_pcdat &= ~fpga->prog_mask; + break; + + case FPGA_PROG_SET_HIGH: + immr->im_ioport.iop_pcdat |= fpga->prog_mask; + break; + + case FPGA_DONE_IS_HIGH: + return (immr->im_ioport.iop_pcdat & fpga->done_mask) ? 1:0; + + case FPGA_READ_MODE: + /* disable FPGA in memory controller */ + memctl->memc_br4 = 0; + memctl->memc_or4 = PUMA_CONF_OR_READ; + memctl->memc_br4 = PUMA_CONF_BR_READ; + + /* (re-) enable CAN drivers */ + can_driver_enable (); + + break; + + case FPGA_LOAD_MODE: + /* disable FPGA in memory controller */ + memctl->memc_br4 = 0; + /* + * We must disable the CAN drivers first because + * they use UPM B, too. + */ + can_driver_disable (); + /* + * Configure UPMB for FPGA + */ + upmconfig(UPMB,(uint *)puma_table,sizeof(puma_table)/sizeof(uint)); + memctl->memc_or4 = PUMA_CONF_OR_LOAD; + memctl->memc_br4 = PUMA_CONF_BR_LOAD; + break; + + case FPGA_GET_ID: + return *(volatile ulong *)fpga->conf_base; + + case FPGA_INIT_PORTS: + immr->im_ioport.iop_pcpar &= ~fpga->init_mask; /* INIT I/O */ + immr->im_ioport.iop_pcso &= ~fpga->init_mask; + immr->im_ioport.iop_pcdir &= ~fpga->init_mask; + + immr->im_ioport.iop_pcpar &= ~fpga->prog_mask; /* PROG Output */ + immr->im_ioport.iop_pcso &= ~fpga->prog_mask; + immr->im_ioport.iop_pcdir |= fpga->prog_mask; + + immr->im_ioport.iop_pcpar &= ~fpga->done_mask; /* DONE Input */ + immr->im_ioport.iop_pcso &= ~fpga->done_mask; + immr->im_ioport.iop_pcdir &= ~fpga->done_mask; + + break; + + } + return 0; +} + diff --git a/board/siemens/SCM/fpga_scm.c b/board/siemens/SCM/fpga_scm.c new file mode 100644 index 00000000000..3b93794adcc --- /dev/null +++ b/board/siemens/SCM/fpga_scm.c @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2002 + * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <mpc8260.h> +#include <common.h> +#include "../common/fpga.h" + +fpga_t fpga_list[] = { + { "FIOX" , CFG_FIOX_BASE , + CFG_PD_FIOX_INIT , CFG_PD_FIOX_PROG , CFG_PD_FIOX_DONE }, + { "FDOHM", CFG_FDOHM_BASE, + CFG_PD_FDOHM_INIT, CFG_PD_FDOHM_PROG, CFG_PD_FDOHM_DONE } +}; +int fpga_count = sizeof(fpga_list) / sizeof(fpga_t); + + +ulong fpga_control (fpga_t* fpga, int cmd) +{ + volatile immap_t *immr = (immap_t *)CFG_IMMR; + + switch (cmd) { + case FPGA_INIT_IS_HIGH: + immr->im_ioport.iop_pdird &= ~fpga->init_mask; /* input */ + return (immr->im_ioport.iop_pdatd & fpga->init_mask) ? 1:0; + + case FPGA_INIT_SET_LOW: + immr->im_ioport.iop_pdird |= fpga->init_mask; /* output */ + immr->im_ioport.iop_pdatd &= ~fpga->init_mask; + break; + + case FPGA_INIT_SET_HIGH: + immr->im_ioport.iop_pdird |= fpga->init_mask; /* output */ + immr->im_ioport.iop_pdatd |= fpga->init_mask; + break; + + case FPGA_PROG_SET_LOW: + immr->im_ioport.iop_pdatd &= ~fpga->prog_mask; + break; + + case FPGA_PROG_SET_HIGH: + immr->im_ioport.iop_pdatd |= fpga->prog_mask; + break; + + case FPGA_DONE_IS_HIGH: + return (immr->im_ioport.iop_pdatd & fpga->done_mask) ? 1:0; + + case FPGA_READ_MODE: + break; + + case FPGA_LOAD_MODE: + break; + + case FPGA_GET_ID: + if (fpga->conf_base == CFG_FIOX_BASE) { + ulong ver = *(volatile ulong *)(fpga->conf_base + 0x10); + return ((ver >> 10) & 0xf) + ((ver >> 2) & 0xf0); + } + else if (fpga->conf_base == CFG_FDOHM_BASE) { + return (*(volatile ushort *)fpga->conf_base) & 0xff; + } + else { + return *(volatile ulong *)fpga->conf_base; + } + + case FPGA_INIT_PORTS: + immr->im_ioport.iop_ppard &= ~fpga->init_mask; /* INIT I/O */ + immr->im_ioport.iop_psord &= ~fpga->init_mask; + immr->im_ioport.iop_pdird &= ~fpga->init_mask; + + immr->im_ioport.iop_ppard &= ~fpga->prog_mask; /* PROG Output */ + immr->im_ioport.iop_psord &= ~fpga->prog_mask; + immr->im_ioport.iop_pdird |= fpga->prog_mask; + + immr->im_ioport.iop_ppard &= ~fpga->done_mask; /* DONE Input */ + immr->im_ioport.iop_psord &= ~fpga->done_mask; + immr->im_ioport.iop_pdird &= ~fpga->done_mask; + + break; + + } + return 0; +} diff --git a/board/siemens/common/README b/board/siemens/common/README new file mode 100644 index 00000000000..d7819038404 --- /dev/null +++ b/board/siemens/common/README @@ -0,0 +1,27 @@ +CCM/SCM-Ergaenzungen fuer U-Boot und Linux: +------------------------------------------- + +Es gibt nun ein gemeinsames Kommando zum Laden der FPGAs: + + => help fpga + fpga fpga status [name] - print FPGA status + fpga reset [name] - reset FPGA + fpga load [name] addr - load FPGA configuration data + +Der Name kann beim CCM-Module auch weggelassen werden. +Die Laengenangabe und damit "puma_len" ist nicht mehr +noetig: + + => fpga load puma 40600000 + FPGA load PUMA: addr 40600000: (00000005)... done + +Die MTD-Partitionierung kann nun mittels "bootargs" ueber- +geben werden: + + => printenv addmtd + addmtd=setenv bootargs $(bootargs) + mtdparts=0:256k(U-Boot)ro,768k(Kernel),-(Rest)\;1:-(myJFFS2) + +Die Portierung auf SMC ist natuerlich noch nicht getestet. + +Wolfgang Grandegger (04.06.2002) diff --git a/board/siemens/common/fpga.c b/board/siemens/common/fpga.c new file mode 100644 index 00000000000..a17de5ad653 --- /dev/null +++ b/board/siemens/common/fpga.c @@ -0,0 +1,358 @@ +/* + * (C) Copyright 2002 + * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#include <common.h> +#include <command.h> +#include <linux/ctype.h> +#include <common.h> +#include <cmd_boot.h> +#include <cmd_bsp.h> + +#include "fpga.h" + +int power_on_reset(void); + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + + +static int fpga_get_version(fpga_t* fpga, char* name) +{ + char vname[12]; + /* + * Net-list string format: + * "vvvvvvvvddddddddn...". + * Version Date Name + * "0000000322042002PUMA" = PUMA version 3 from 22.04.2002. + */ + if (strlen(name) < (16 + strlen(fpga->name))) + goto failure; + /* Check FPGA name */ + if (strcmp(&name[16], fpga->name) != 0) + goto failure; + /* Get version number */ + memcpy(vname, name, 8); + vname[8] = '\0'; + return simple_strtoul(vname, NULL, 16); + + failure: + printf("Image name %s is invalid\n", name); + return -1; +} + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +static fpga_t* fpga_get(char* fpga_name) +{ + char name[FPGA_NAME_LEN]; + int i; + + if (strlen(fpga_name) >= FPGA_NAME_LEN) + goto failure; + for (i = 0; i < strlen(fpga_name); i++) + name[i] = toupper(fpga_name[i]); + name[i] = '\0'; + for (i = 0; i < fpga_count; i++) { + if (strcmp(name, fpga_list[i].name) == 0) + return &fpga_list[i]; + } + failure: + printf("FPGA: name %s is invalid\n", fpga_name); + return NULL; +} + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +static void fpga_status (fpga_t* fpga) +{ + /* Check state */ + if (fpga_control(fpga, FPGA_DONE_IS_HIGH)) + printf ("%s is loaded (%08lx)\n", + fpga->name, fpga_control(fpga, FPGA_GET_ID)); + else + printf ("%s is NOT loaded\n", fpga->name); +} + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +#define FPGA_RESET_TIMEOUT 100 /* = 10 ms */ + +static int fpga_reset (fpga_t* fpga) +{ + int i; + + /* Set PROG to low and wait til INIT goes low */ + fpga_control(fpga, FPGA_PROG_SET_LOW); + for (i = 0; i < FPGA_RESET_TIMEOUT; i++) { + udelay (100); + if (!fpga_control(fpga, FPGA_INIT_IS_HIGH)) + break; + } + if (i == FPGA_RESET_TIMEOUT) + goto failure; + + /* Set PROG to high and wait til INIT goes high */ + fpga_control(fpga, FPGA_PROG_SET_HIGH); + for (i = 0; i < FPGA_RESET_TIMEOUT; i++) { + udelay (100); + if (fpga_control(fpga, FPGA_INIT_IS_HIGH)) + break; + } + if (i == FPGA_RESET_TIMEOUT) + goto failure; + + return 0; + failure: + return 1; +} + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +#define FPGA_LOAD_TIMEOUT 100 /* = 10 ms */ + +static int fpga_load (fpga_t* fpga, ulong addr, int checkall) +{ + volatile uchar *fpga_addr = (volatile uchar *)fpga->conf_base; + image_header_t hdr; + ulong len, checksum; + uchar *data = (uchar *)&hdr; + char *s, msg[32]; + int verify, i; + + /* + * Check the image header and data of the net-list + */ + memcpy (&hdr, (char *)addr, sizeof(image_header_t)); + + if (hdr.ih_magic != IH_MAGIC) { + strcpy (msg, "Bad Image Magic Number"); + goto failure; + } + + len = sizeof(image_header_t); + + checksum = hdr.ih_hcrc; + hdr.ih_hcrc = 0; + + if (crc32 (0, data, len) != checksum) { + strcpy (msg, "Bad Image Header CRC"); + goto failure; + } + + data = (uchar*)(addr + sizeof(image_header_t)); + len = hdr.ih_size; + + s = getenv ("verify"); + verify = (s && (*s == 'n')) ? 0 : 1; + if (verify) { + if (crc32 (0, data, len) != hdr.ih_dcrc) { + strcpy (msg, "Bad Image Data CRC"); + goto failure; + } + } + + if (checkall && fpga_get_version(fpga, hdr.ih_name) < 0) + return 1; + + /* align length */ + if (len & 1) + ++len; + + /* + * Reset FPGA and wait for completion + */ + if (fpga_reset(fpga)) { + strcpy (msg, "Reset Timeout"); + goto failure; + } + + printf ("(%s)... ", hdr.ih_name); + /* + * Copy data to FPGA + */ + fpga_control (fpga, FPGA_LOAD_MODE); + while (len--) { + *fpga_addr = *data++; + } + fpga_control (fpga, FPGA_READ_MODE); + + /* + * Wait for completion and check error status if timeout + */ + for (i = 0; i < FPGA_LOAD_TIMEOUT; i++) { + udelay (100); + if (fpga_control (fpga, FPGA_DONE_IS_HIGH)) + break; + } + if (i == FPGA_LOAD_TIMEOUT) { + if (fpga_control(fpga, FPGA_INIT_IS_HIGH)) + strcpy(msg, "Invalid Size"); + else + strcpy(msg, "CRC Error"); + goto failure; + } + + printf("done\n"); + return 0; + + failure: + + printf("ERROR: %s\n", msg); + return 1; +} + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +int do_fpga (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr = 0; + int i; + fpga_t* fpga; + + if (argc < 2) + goto failure; + + if (strncmp(argv[1], "stat", 4) == 0) { /* status */ + if (argc == 2) { + for (i = 0; i < fpga_count; i++) { + fpga_status (&fpga_list[i]); + } + } + else if (argc == 3) { + if ((fpga = fpga_get(argv[2])) == 0) + goto failure; + fpga_status (fpga); + } + else + goto failure; + } + else if (strcmp(argv[1],"load") == 0) { /* load */ + if (argc == 3 && fpga_count == 1) { + fpga = &fpga_list[0]; + } + else if (argc == 4) { + if ((fpga = fpga_get(argv[2])) == 0) + goto failure; + } + else + goto failure; + + addr = simple_strtoul(argv[argc-1], NULL, 16); + + printf ("FPGA load %s: addr %08lx: ", + fpga->name, addr); + fpga_load (fpga, addr, 1); + + } + else if (strncmp(argv[1], "rese", 4) == 0) { /* reset */ + if (argc == 2 && fpga_count == 1) { + fpga = &fpga_list[0]; + } + else if (argc == 3) { + if ((fpga = fpga_get(argv[2])) == 0) + goto failure; + } + else + goto failure; + + printf ("FPGA reset %s: ", fpga->name); + if (fpga_reset(fpga)) + printf ("ERROR: Timeout\n"); + else + printf ("done\n"); + } + else + goto failure; + + return 0; + + failure: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +#endif /* CONFIG_COMMANDS & CFG_CMD_BSP */ + +/* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ + +int fpga_init (void) +{ + ulong addr; + ulong new_id, old_id = 0; + image_header_t *hdr; + fpga_t* fpga; + int do_load, i, j; + char name[16], *s; + + /* + * Port setup for FPGA control + */ + for (i = 0; i < fpga_count; i++) { + fpga_control(&fpga_list[i], FPGA_INIT_PORTS); + } + + /* + * Load FPGA(s): a new net-list is loaded if the FPGA is + * empty, Power-on-Reset or the old one is not up-to-date + */ + for (i = 0; i < fpga_count; i++) { + fpga = &fpga_list[i]; + printf ("%s: ", fpga->name); + + for (j = 0; j < strlen(fpga->name); j++) + name[j] = tolower(fpga->name[j]); + name[j] = '\0'; + sprintf(name, "%s_addr", name); + addr = 0; + if ((s = getenv(name)) != NULL) + addr = simple_strtoul(s, NULL, 16); + + if (!addr) { + printf ("env. variable %s undefined\n", name); + return 1; + } + + hdr = (image_header_t *)addr; + if ((new_id = fpga_get_version(fpga, hdr->ih_name)) == -1) + return 1; + + do_load = 1; + + if (!power_on_reset() && fpga_control(fpga, FPGA_DONE_IS_HIGH)) { + old_id = fpga_control(fpga, FPGA_GET_ID); + if (new_id == old_id) + do_load = 0; + } + + if (do_load) { + printf ("loading "); + fpga_load (fpga, addr, 0); + } else { + printf ("loaded (%08lx)\n", old_id); + } + } + + return 0; +} |