diff options
author | Matthias Fuchs <matthias.fuchs@esd.eu> | 2009-07-22 13:56:21 +0200 |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2009-07-24 06:47:40 +0200 |
commit | 99d8b23bc7e2be04fcbf49c5cec9f5ae76df290c (patch) | |
tree | 6986c025a2a80bc7f474e73a3092d79c4fba3edd /board/esd/pmc405de/pmc405de.c | |
parent | da799f66ad1d4fc36dd20cc2d7e584493fda8546 (diff) | |
download | u-boot-imx-99d8b23bc7e2be04fcbf49c5cec9f5ae76df290c.zip u-boot-imx-99d8b23bc7e2be04fcbf49c5cec9f5ae76df290c.tar.gz u-boot-imx-99d8b23bc7e2be04fcbf49c5cec9f5ae76df290c.tar.bz2 |
ppc4xx: Add 405EP based PMC405DE board
Signed-off-by: Matthias Fuchs <matthias.fuchs@esd.eu>
Signed-off-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'board/esd/pmc405de/pmc405de.c')
-rw-r--r-- | board/esd/pmc405de/pmc405de.c | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/board/esd/pmc405de/pmc405de.c b/board/esd/pmc405de/pmc405de.c new file mode 100644 index 0000000..f68e1b5 --- /dev/null +++ b/board/esd/pmc405de/pmc405de.c @@ -0,0 +1,521 @@ +/* + * (C) Copyright 2009 + * Matthias Fuchs, esd gmbh germany, matthias.fuchs@esd.eu + * + * 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 <libfdt.h> +#include <fdt_support.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <asm/4xx_pci.h> +#include <command.h> +#include <malloc.h> + +/* + * PMC405-DE cpld registers + * - all registers are 8 bit + * - all registers are on 32 bit addesses + */ +struct pmc405de_cpld { + /* cpld design version */ + u8 version; + u8 reserved0[3]; + + /* misc. status lines */ + u8 status; + u8 reserved1[3]; + + /* + * gated control flags + * gate bit(s) must be written with '1' to + * access control flag + */ + u8 control; + u8 reserved2[3]; +}; + +#define CPLD_VERSION_MASK 0x0f +#define CPLD_CONTROL_POSTLED_N 0x01 +#define CPLD_CONTROL_POSTLED_GATE 0x02 +#define CPLD_CONTROL_RESETOUT_N 0x40 +#define CPLD_CONTROL_RESETOUT_N_GATE 0x80 + +DECLARE_GLOBAL_DATA_PTR; + +extern void __ft_board_setup(void *blob, bd_t *bd); +extern void pll_write(u32 a, u32 b); + +static int wait_for_pci_ready_done; + +static int is_monarch(void); +static int pci_is_66mhz(void); +static int board_revision(void); +static int cpld_revision(void); +static void upd_plb_pci_div(u32 pllmr0, u32 pllmr1, u32 div); + +int board_early_init_f(void) +{ + u32 pllmr0, pllmr1; + + /* + * check M66EN and patch PLB:PCI divider for 66MHz PCI + * + * fCPU==333MHz && fPCI==66MHz (PLBDiv==3 && M66EN==1): PLB/PCI=1 + * fCPU==333MHz && fPCI==33MHz (PLBDiv==3 && M66EN==0): PLB/PCI=2 + * fCPU==133|266MHz && fPCI==66MHz (PLBDiv==1|2 && M66EN==1): PLB/PCI=2 + * fCPU==133|266MHz && fPCI==33MHz (PLBDiv==1|2 && M66EN==0): PLB/PCI=3 + * + * calling upd_plb_pci_div() may end in calling pll_write() which will + * do a chip reset and never return. + */ + pllmr0 = mfdcr(CPC0_PLLMR0); + pllmr1 = mfdcr(CPC0_PLLMR1); + + if ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) == PLLMR0_CPU_PLB_DIV_3) { + /* fCPU=333MHz, fPLB=111MHz */ + if (pci_is_66mhz()) + upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_1); + else + upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_2); + } else { + /* fCPU=133|266MHz, fPLB=133MHz */ + if (pci_is_66mhz()) + upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_2); + else + upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_3); + } + + /* + * IRQ 25 (EXT IRQ 0) PCI-INTA#; active low; level sensitive + * IRQ 26 (EXT IRQ 1) PCI-INTB#; active low; level sensitive + * IRQ 27 (EXT IRQ 2) PCI-INTC#; active low; level sensitive + * IRQ 28 (EXT IRQ 3) PCI-INTD#; active low; level sensitive + * IRQ 29 (EXT IRQ 4) ETH0-PHY-IRQ#; active low; level sensitive + * IRQ 30 (EXT IRQ 5) ETH1-PHY-IRQ#; active low; level sensitive + * IRQ 31 (EXT IRQ 6) PLD-IRQ#; active low; level sensitive + */ + mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */ + mtdcr(uicer, 0x00000000); /* disable all ints */ + mtdcr(uiccr, 0x00000000); /* set all to be non-critical*/ + mtdcr(uicpr, 0xFFFFFF80); /* set int polarities */ + mtdcr(uictr, 0x10000000); /* set int trigger levels */ + mtdcr(uicvcr, 0x00000001); /* set vect base=0, INT0 highest prio */ + mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */ + + /* + * EBC Configuration Register: + * - set ready timeout to 512 ebc-clks -> ca. 15 us + * - EBC lines are always driven + */ + mtebc(epcr, 0xa8400000); + + return 0; +} + +static void upd_plb_pci_div(u32 pllmr0, u32 pllmr1, u32 div) +{ + if ((pllmr0 & PLLMR0_PCI_TO_PLB_MASK) != div) + pll_write((pllmr0 & ~PLLMR0_PCI_TO_PLB_MASK) | div, pllmr1); +} + +int misc_init_r(void) +{ + int i; + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + struct pmc405de_cpld *cpld = + (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; + + if (!is_monarch()) { + /* PCI configuration done: release EREADY */ + setbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EREADY); + setbits_be32(&gpio0->tcr, CONFIG_SYS_GPIO_EREADY); + } + + /* turn off POST LED */ + out_8(&cpld->control, + CPLD_CONTROL_POSTLED_N | CPLD_CONTROL_POSTLED_GATE); + + /* turn on LEDs: RUN, A, B */ + clrbits_be32(&gpio0->or, + CONFIG_SYS_GPIO_LEDRUN_N | + CONFIG_SYS_GPIO_LEDA_N | + CONFIG_SYS_GPIO_LEDB_N); + + for (i=0; i < 200; i++) + udelay(1000); + + /* turn off LEDs: A, B */ + setbits_be32(&gpio0->or, + CONFIG_SYS_GPIO_LEDA_N | + CONFIG_SYS_GPIO_LEDB_N); + + return (0); +} + +static int is_monarch(void) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + return (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_MONARCH_N) == 0; +} + +static int pci_is_66mhz(void) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + return (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_M66EN); +} + +static int board_revision(void) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + return ((in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_HWREV_MASK) >> + CONFIG_SYS_GPIO_HWREV_SHIFT); +} + +static int cpld_revision(void) +{ + struct pmc405de_cpld *cpld = + (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; + return ((in_8(&cpld->version) & CPLD_VERSION_MASK)); +} + +/* + * Check Board Identity + */ +int checkboard(void) +{ + puts("Board: esd GmbH - PMC-CPU/405-DE"); + + gd->board_type = board_revision(); + printf(", Rev 1.%ld, ", gd->board_type); + + if (!is_monarch()) + puts("non-"); + + printf("monarch, PCI=%s MHz, PLD-Rev 1.%d\n", + pci_is_66mhz() ? "66" : "33", cpld_revision()); + + return 0; +} + + +static void wait_for_pci_ready(void) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + int i; + char *s = getenv("pcidelay"); + + /* only wait once */ + if (wait_for_pci_ready_done) + return; + + /* + * We have our own handling of the pcidelay variable. + * Using CONFIG_PCI_BOOTDELAY enables pausing for host + * and adapter devices. For adapter devices we do not + * want this. + */ + if (s) { + int ms = simple_strtoul(s, NULL, 10); + printf("PCI: Waiting for %d ms\n", ms); + for (i=0; i<ms; i++) + udelay(1000); + } + + if (!(in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_EREADY)) { + printf("PCI: Waiting for EREADY (CTRL-C to skip) ... "); + while (1) { + if (ctrlc()) { + puts("abort\n"); + break; + } + if (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_EREADY) { + printf("done\n"); + break; + } + } + } + + wait_for_pci_ready_done = 1; +} + +/* + * Overwrite weak is_pci_host() + * + * This routine is called to determine if a pci scan should be + * performed. With various hardware environments (especially cPCI and + * PPMC) it's insufficient to depend on the state of the arbiter enable + * bit in the strap register, or generic host/adapter assumptions. + * + * Return 0 for adapter mode, non-zero for host (monarch) mode. + */ +int is_pci_host(struct pci_controller *hose) +{ + char *s; + + if (!is_monarch()) { + /* + * Overwrite PCI identification when running in + * non-monarch mode + * This should be moved into pci_target_init() + * when it is sometimes available for 405 CPUs + */ + pci_write_config_word(PCIDEVID_405GP, + PCI_SUBSYSTEM_ID, + CONFIG_SYS_PCI_SUBSYS_ID_NONMONARCH); + pci_write_config_word(PCIDEVID_405GP, + PCI_CLASS_SUB_CODE, + CONFIG_SYS_PCI_CLASSCODE_NONMONARCH); + } + + s = getenv("pciscan"); + if (s == NULL) { + if (is_monarch()) { + wait_for_pci_ready(); + return 1; + } else { + return 0; + } + } else { + if (!strcmp(s, "yes")) + return 1; + } + + return 0; +} + +/* + * Overwrite weak pci_pre_init() + * + * The default implementation enables the 405EP + * internal PCI arbiter. We do not want that + * on a PMC module. + */ +int pci_pre_init(struct pci_controller *hose) +{ + return 1; +} + +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) +void ft_board_setup(void *blob, bd_t *bd) +{ + int rc; + + __ft_board_setup(blob, bd); + + /* + * Disable PCI in non-monarch mode. + */ + if (!is_monarch()) { + rc = fdt_find_and_setprop(blob, "/plb/pci@ec000000", "status", + "disabled", sizeof("disabled"), 1); + if (rc) { + printf("Unable to update property status in PCI node, " + "err=%s\n", + fdt_strerror(rc)); + } + } +} +#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */ + +#if defined(CONFIG_SYS_EEPROM_WREN) +/* Input: <dev_addr> I2C address of EEPROM device to enable. + * <state> -1: deliver current state + * 0: disable write + * 1: enable write + * Returns: -1: wrong device address + * 0: dis-/en- able done + * 0/1: current state if <state> was -1. + */ +int eeprom_write_enable(unsigned dev_addr, int state) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + + if (CONFIG_SYS_I2C_EEPROM_ADDR != dev_addr) { + return -1; + } else { + switch (state) { + case 1: + /* Enable write access, clear bit GPIO0. */ + clrbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EEPROM_WP); + state = 0; + break; + case 0: + /* Disable write access, set bit GPIO0. */ + setbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EEPROM_WP); + state = 0; + break; + default: + /* Read current status back. */ + state = (0 == (in_be32(&gpio0->or) & + CONFIG_SYS_GPIO_EEPROM_WP)); + break; + } + } + return state; +} + +int do_eep_wren(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int query = argc == 1; + int state = 0; + + if (query) { + /* Query write access state. */ + state = eeprom_write_enable(CONFIG_SYS_I2C_EEPROM_ADDR, - 1); + if (state < 0) { + puts("Query of write access state failed.\n"); + } else { + printf("Write access for device 0x%0x is %sabled.\n", + CONFIG_SYS_I2C_EEPROM_ADDR, + state ? "en" : "dis"); + state = 0; + } + } else { + if ('0' == argv[1][0]) { + /* Disable write access. */ + state = eeprom_write_enable( + CONFIG_SYS_I2C_EEPROM_ADDR, 0); + } else { + /* Enable write access. */ + state = eeprom_write_enable( + CONFIG_SYS_I2C_EEPROM_ADDR, 1); + } + if (state < 0) + puts ("Setup of write access state failed.\n"); + } + + return state; +} + +U_BOOT_CMD(eepwren, 2, 0, do_eep_wren, + "Enable / disable / query EEPROM write access", + "" +); +#endif /* #if defined(CONFIG_SYS_EEPROM_WREN) */ + +#if defined(CONFIG_PRAM) +#include <environment.h> +extern env_t *env_ptr; + +int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + u32 pram, nextbase, base; + char *v; + u32 param; + ulong *lptr; + + v = getenv("pram"); + if (v) + pram = simple_strtoul(v, NULL, 10); + else { + printf("Error: pram undefined. Please define pram in KiB\n"); + return 1; + } + + base = gd->bd->bi_memsize; +#if defined(CONFIG_LOGBUFFER) + base -= LOGBUFF_LEN + LOGBUFF_OVERHEAD; +#endif + /* + * gd->bd->bi_memsize == physical ram size - CONFIG_SYS_MM_TOP_HIDE + */ + param = base - (pram << 10); + printf("PARAM: @%08x\n", param); + debug("memsize=0x%08x, base=0x%08x\n", gd->bd->bi_memsize, base); + + /* clear entire PA ram */ + memset((void*)param, 0, (pram << 10)); + + /* reserve 4k for pointer field */ + nextbase = base - 4096; + lptr = (ulong*)(base); + + /* + * *(--lptr) = item_size; + * *(--lptr) = base - item_base = distance from field top; + */ + + /* env is first (4k aligned) */ + nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1)); + memcpy((void*)nextbase, env_ptr, CONFIG_ENV_SIZE); + *(--lptr) = CONFIG_ENV_SIZE; /* size */ + *(--lptr) = base - nextbase; /* offset | type=0 */ + + /* free section */ + *(--lptr) = nextbase - param; /* size */ + *(--lptr) = (base - param) | 126; /* offset | type=126 */ + + /* terminate pointer field */ + *(--lptr) = crc32(0, (void*)(base - 0x10), 0x10); + *(--lptr) = 0; /* offset=0 -> terminator */ + return 0; +} +U_BOOT_CMD( + painit, 1, 1, do_painit, + "prepare PciAccess system", + "" +); +#endif /* CONFIG_PRAM */ + +int do_selfreset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; + setbits_be32(&gpio0->tcr, CONFIG_SYS_GPIO_SELFRST_N); + return 0; +} +U_BOOT_CMD( + selfreset, 1, 1, do_selfreset, + "assert self-reset# signal", + "" +); + +int do_resetout(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + struct pmc405de_cpld *cpld = + (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; + + if (argc > 1) { + if (argv[1][0] == '0') { + /* assert */ + printf("PMC-RESETOUT# asserted\n"); + out_8(&cpld->control, + CPLD_CONTROL_RESETOUT_N_GATE); + } else { + /* deassert */ + printf("PMC-RESETOUT# deasserted\n"); + out_8(&cpld->control, + CPLD_CONTROL_RESETOUT_N | + CPLD_CONTROL_RESETOUT_N_GATE); + } + } else { + printf("PMC-RESETOUT# is %s\n", + (in_8(&cpld->control) & CPLD_CONTROL_RESETOUT_N) ? + "inactive" : "active"); + } + return 0; +} +U_BOOT_CMD( + resetout, 2, 1, do_resetout, + "assert PMC-RESETOUT# signal", + "" +); |