summaryrefslogtreecommitdiffstats
path: root/board/siemens
diff options
context:
space:
mode:
Diffstat (limited to 'board/siemens')
-rw-r--r--board/siemens/CCM/ccm.c440
-rw-r--r--board/siemens/CCM/fpga_ccm.c170
-rw-r--r--board/siemens/SCM/fpga_scm.c104
-rw-r--r--board/siemens/common/README27
-rw-r--r--board/siemens/common/fpga.c358
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 0000000000..079f38f7ec
--- /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 0000000000..292387b524
--- /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 0000000000..3b93794adc
--- /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 0000000000..d781903840
--- /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 0000000000..a17de5ad65
--- /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;
+}
OpenPOWER on IntegriCloud