| /* |
| * (C) Copyright 2007-2008 |
| * Matthias Fuchs, esd Gmbh, matthias.fuchs@esd-electronics.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 <common.h> |
| #include <command.h> |
| #include <asm/io.h> |
| #include <asm/cache.h> |
| #include <asm/processor.h> |
| #if defined(CONFIG_LOGBUFFER) |
| #include <logbuff.h> |
| #endif |
| |
| #include "pmc440.h" |
| |
| int is_monarch(void); |
| int bootstrap_eeprom_write(unsigned dev_addr, unsigned offset, |
| uchar *buffer, unsigned cnt); |
| int eeprom_write_enable(unsigned dev_addr, int state); |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| #if defined(CONFIG_CMD_BSP) |
| |
| static int got_fifoirq; |
| static int got_hcirq; |
| |
| int fpga_interrupt(u32 arg) |
| { |
| pmc440_fpga_t *fpga = (pmc440_fpga_t *)arg; |
| int rc = -1; /* not for us */ |
| u32 status = FPGA_IN32(&fpga->status); |
| |
| /* check for interrupt from fifo module */ |
| if (status & STATUS_FIFO_ISF) { |
| /* disable this int source */ |
| FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_FIFOIE_GATE); |
| rc = 0; |
| got_fifoirq = 1; /* trigger backend */ |
| } |
| |
| if (status & STATUS_HOST_ISF) { |
| FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_HCINT_GATE); |
| rc = 0; |
| got_hcirq = 1; |
| } |
| |
| return rc; |
| } |
| |
| int do_waithci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA; |
| |
| got_hcirq = 0; |
| |
| FPGA_CLRBITS(&fpga->ctrla, CTRL_HOST_IE); |
| FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_HCINT_GATE); |
| |
| irq_install_handler(IRQ0_FPGA, |
| (interrupt_handler_t *)fpga_interrupt, |
| fpga); |
| |
| FPGA_SETBITS(&fpga->ctrla, CTRL_HOST_IE); |
| |
| while (!got_hcirq) { |
| /* Abort if ctrl-c was pressed */ |
| if (ctrlc()) { |
| puts("\nAbort\n"); |
| break; |
| } |
| } |
| if (got_hcirq) |
| printf("Got interrupt!\n"); |
| |
| FPGA_CLRBITS(&fpga->ctrla, CTRL_HOST_IE); |
| irq_free_handler(IRQ0_FPGA); |
| return 0; |
| } |
| U_BOOT_CMD( |
| waithci, 1, 1, do_waithci, |
| "Wait for host control interrupt", |
| "" |
| ); |
| |
| void dump_fifo(pmc440_fpga_t *fpga, int f, int *n) |
| { |
| u32 ctrl; |
| |
| while (!((ctrl = FPGA_IN32(&fpga->fifo[f].ctrl)) & FIFO_EMPTY)) { |
| printf("%5d %d %3d %08x", |
| (*n)++, f, ctrl & (FIFO_LEVEL_MASK | FIFO_FULL), |
| FPGA_IN32(&fpga->fifo[f].data)); |
| if (ctrl & FIFO_OVERFLOW) { |
| printf(" OVERFLOW\n"); |
| FPGA_CLRBITS(&fpga->fifo[f].ctrl, FIFO_OVERFLOW); |
| } else |
| printf("\n"); |
| } |
| } |
| |
| int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA; |
| int i; |
| int n = 0; |
| u32 ctrl, data, f; |
| char str[] = "\\|/-"; |
| int abort = 0; |
| int count = 0; |
| int count2 = 0; |
| |
| switch (argc) { |
| case 1: |
| /* print all fifos status information */ |
| printf("fifo level status\n"); |
| printf("______________________________\n"); |
| for (i=0; i<FIFO_COUNT; i++) { |
| ctrl = FPGA_IN32(&fpga->fifo[i].ctrl); |
| printf(" %d %3d %s%s%s %s\n", |
| i, ctrl & (FIFO_LEVEL_MASK | FIFO_FULL), |
| ctrl & FIFO_FULL ? "FULL " : "", |
| ctrl & FIFO_EMPTY ? "EMPTY " : "", |
| ctrl & (FIFO_FULL|FIFO_EMPTY) ? "" : "NOT EMPTY", |
| ctrl & FIFO_OVERFLOW ? "OVERFLOW" : ""); |
| } |
| break; |
| |
| case 2: |
| /* completely read out fifo 'n' */ |
| if (!strcmp(argv[1],"read")) { |
| printf(" # fifo level data\n"); |
| printf("______________________________\n"); |
| |
| for (i=0; i<FIFO_COUNT; i++) |
| dump_fifo(fpga, i, &n); |
| |
| } else if (!strcmp(argv[1],"wait")) { |
| got_fifoirq = 0; |
| |
| irq_install_handler(IRQ0_FPGA, |
| (interrupt_handler_t *)fpga_interrupt, |
| fpga); |
| |
| printf(" # fifo level data\n"); |
| printf("______________________________\n"); |
| |
| /* enable all fifo interrupts */ |
| FPGA_OUT32(&fpga->hostctrl, |
| HOSTCTRL_FIFOIE_GATE | HOSTCTRL_FIFOIE_FLAG); |
| for (i=0; i<FIFO_COUNT; i++) { |
| /* enable interrupts from all fifos */ |
| FPGA_SETBITS(&fpga->fifo[i].ctrl, FIFO_IE); |
| } |
| |
| while (1) { |
| /* wait loop */ |
| while (!got_fifoirq) { |
| count++; |
| if (!(count % 100)) { |
| count2++; |
| putc(0x08); /* backspace */ |
| putc(str[count2 % 4]); |
| } |
| |
| /* Abort if ctrl-c was pressed */ |
| if ((abort = ctrlc())) { |
| puts("\nAbort\n"); |
| break; |
| } |
| udelay(1000); |
| } |
| if (abort) |
| break; |
| |
| /* simple fifo backend */ |
| if (got_fifoirq) { |
| for (i=0; i<FIFO_COUNT; i++) |
| dump_fifo(fpga, i, &n); |
| |
| got_fifoirq = 0; |
| /* unmask global fifo irq */ |
| FPGA_OUT32(&fpga->hostctrl, |
| HOSTCTRL_FIFOIE_GATE | |
| HOSTCTRL_FIFOIE_FLAG); |
| } |
| } |
| |
| /* disable all fifo interrupts */ |
| FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_FIFOIE_GATE); |
| for (i=0; i<FIFO_COUNT; i++) |
| FPGA_CLRBITS(&fpga->fifo[i].ctrl, FIFO_IE); |
| |
| irq_free_handler(IRQ0_FPGA); |
| |
| } else { |
| printf("Usage:\nfifo %s\n", cmdtp->help); |
| return 1; |
| } |
| break; |
| |
| case 4: |
| case 5: |
| if (!strcmp(argv[1],"write")) { |
| /* get fifo number or fifo address */ |
| f = simple_strtoul(argv[2], NULL, 16); |
| |
| /* data paramter */ |
| data = simple_strtoul(argv[3], NULL, 16); |
| |
| /* get optional count parameter */ |
| n = 1; |
| if (argc >= 5) |
| n = (int)simple_strtoul(argv[4], NULL, 10); |
| |
| if (f < FIFO_COUNT) { |
| printf("writing %d x %08x to fifo %d\n", |
| n, data, f); |
| for (i=0; i<n; i++) |
| FPGA_OUT32(&fpga->fifo[f].data, data); |
| } else { |
| printf("writing %d x %08x to fifo port at " |
| "address %08x\n", |
| n, data, f); |
| for (i=0; i<n; i++) |
| out_be32((void *)f, data); |
| } |
| } else { |
| printf("Usage:\nfifo %s\n", cmdtp->help); |
| return 1; |
| } |
| break; |
| |
| default: |
| printf("Usage:\nfifo %s\n", cmdtp->help); |
| return 1; |
| } |
| return 0; |
| } |
| U_BOOT_CMD( |
| fifo, 5, 1, do_fifo, |
| "Fifo module operations", |
| "wait\nfifo read\n" |
| "fifo write fifo(0..3) data [cnt=1]\n" |
| "fifo write address(>=4) data [cnt=1]\n" |
| " - without arguments: print all fifo's status\n" |
| " - with 'wait' argument: interrupt driven read from all fifos\n" |
| " - with 'read' argument: read current contents from all fifos\n" |
| " - with 'write' argument: write 'data' 'cnt' times to " |
| "'fifo' or 'address'" |
| ); |
| |
| int do_setup_bootstrap_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| ulong sdsdp[5]; |
| ulong delay; |
| int count=16; |
| |
| if (argc < 2) { |
| printf("Usage:\nsbe %s\n", cmdtp->help); |
| return -1; |
| } |
| |
| if (argc > 1) { |
| if (!strcmp(argv[1], "400")) { |
| /* PLB=133MHz, PLB/PCI=3 */ |
| printf("Bootstrapping for 400MHz\n"); |
| sdsdp[0]=0x8678624e; |
| sdsdp[1]=0x095fa030; |
| sdsdp[2]=0x40082350; |
| sdsdp[3]=0x0d050000; |
| } else if (!strcmp(argv[1], "533")) { |
| /* PLB=133MHz, PLB/PCI=3 */ |
| printf("Bootstrapping for 533MHz\n"); |
| sdsdp[0]=0x87788252; |
| sdsdp[1]=0x095fa030; |
| sdsdp[2]=0x40082350; |
| sdsdp[3]=0x0d050000; |
| } else if (!strcmp(argv[1], "667")) { |
| /* PLB=133MHz, PLB/PCI=3 */ |
| printf("Bootstrapping for 667MHz\n"); |
| sdsdp[0]=0x8778a256; |
| sdsdp[1]=0x095fa030; |
| sdsdp[2]=0x40082350; |
| sdsdp[3]=0x0d050000; |
| } else { |
| printf("Usage:\nsbe %s\n", cmdtp->help); |
| return -1; |
| } |
| } |
| |
| if (argc > 2) { |
| sdsdp[4] = 0; |
| if (argv[2][0]=='1') |
| sdsdp[4]=0x19750100; |
| else if (argv[2][0]=='0') |
| sdsdp[4]=0x19750000; |
| if (sdsdp[4]) |
| count += 4; |
| } |
| |
| if (argc > 3) { |
| delay = simple_strtoul(argv[3], NULL, 10); |
| if (delay > 20) |
| delay = 20; |
| sdsdp[4] |= delay; |
| } |
| |
| printf("Writing boot EEPROM ...\n"); |
| if (bootstrap_eeprom_write(CONFIG_SYS_I2C_BOOT_EEPROM_ADDR, |
| 0, (uchar*)sdsdp, count) != 0) |
| printf("bootstrap_eeprom_write failed\n"); |
| else |
| printf("done (dump via 'i2c md 52 0.1 14')\n"); |
| |
| return 0; |
| } |
| U_BOOT_CMD( |
| sbe, 4, 0, do_setup_bootstrap_eeprom, |
| "setup bootstrap eeprom", |
| "<cpufreq:400|533|667> [<console-uart:0|1> [<bringup delay (0..20s)>]]" |
| ); |
| |
| #if defined(CONFIG_PRAM) |
| #include <environment.h> |
| #include <search.h> |
| #include <errno.h> |
| |
| int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| u32 pram, nextbase, base; |
| char *v; |
| u32 param; |
| ulong *lptr; |
| |
| env_t *envp; |
| char *res; |
| int len; |
| |
| 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_MEM_TOP_HIDE |
| */ |
| param = base - (pram << 10); |
| printf("PARAM: @%08x\n", param); |
| debug("memsize=0x%08x, base=0x%08x\n", (u32)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)); |
| envp = (env_t *)nextbase; |
| res = (char *)envp->data; |
| len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); |
| if (len < 0) { |
| error("Cannot export environment: errno = %d\n", errno); |
| return 1; |
| } |
| envp->crc = crc32(0, envp->data, 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 * const argv[]) |
| { |
| in_be32((void*)CONFIG_SYS_RESET_BASE); |
| 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 * const argv[]) |
| { |
| pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA; |
| |
| /* requiers bootet FPGA and PLD_IOEN_N active */ |
| if (in_be32((void*)GPIO1_OR) & GPIO1_IOEN_N) { |
| printf("Error: resetout requires a bootet FPGA\n"); |
| return -1; |
| } |
| |
| if (argc > 1) { |
| if (argv[1][0] == '0') { |
| /* assert */ |
| printf("PMC-RESETOUT# asserted\n"); |
| FPGA_OUT32(&fpga->hostctrl, |
| HOSTCTRL_PMCRSTOUT_GATE); |
| } else { |
| /* deassert */ |
| printf("PMC-RESETOUT# deasserted\n"); |
| FPGA_OUT32(&fpga->hostctrl, |
| HOSTCTRL_PMCRSTOUT_GATE | |
| HOSTCTRL_PMCRSTOUT_FLAG); |
| } |
| } else { |
| printf("PMC-RESETOUT# is %s\n", |
| FPGA_IN32(&fpga->hostctrl) & HOSTCTRL_PMCRSTOUT_FLAG ? |
| "inactive" : "active"); |
| } |
| |
| return 0; |
| } |
| U_BOOT_CMD( |
| resetout, 2, 1, do_resetout, |
| "assert PMC-RESETOUT# signal", |
| "" |
| ); |
| |
| int do_inta(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| if (is_monarch()) { |
| printf("This command is only supported in non-monarch mode\n"); |
| return -1; |
| } |
| |
| if (argc > 1) { |
| if (argv[1][0] == '0') { |
| /* assert */ |
| printf("inta# asserted\n"); |
| out_be32((void*)GPIO1_TCR, |
| in_be32((void*)GPIO1_TCR) | GPIO1_INTA_FAKE); |
| } else { |
| /* deassert */ |
| printf("inta# deasserted\n"); |
| out_be32((void*)GPIO1_TCR, |
| in_be32((void*)GPIO1_TCR) & ~GPIO1_INTA_FAKE); |
| } |
| } else { |
| printf("inta# is %s\n", |
| in_be32((void*)GPIO1_TCR) & GPIO1_INTA_FAKE ? |
| "active" : "inactive"); |
| } |
| return 0; |
| } |
| U_BOOT_CMD( |
| inta, 2, 1, do_inta, |
| "Assert/Deassert or query INTA# state in non-monarch mode", |
| "" |
| ); |
| |
| /* test-only */ |
| int do_pmm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
| { |
| ulong pciaddr; |
| |
| if (argc > 1) { |
| pciaddr = simple_strtoul(argv[1], NULL, 16); |
| |
| pciaddr &= 0xf0000000; |
| |
| /* map PCI address at 0xc0000000 in PLB space */ |
| |
| /* PMM1 Mask/Attribute - disabled b4 setting */ |
| out32r(PCIL0_PMM1MA, 0x00000000); |
| /* PMM1 Local Address */ |
| out32r(PCIL0_PMM1LA, 0xc0000000); |
| /* PMM1 PCI Low Address */ |
| out32r(PCIL0_PMM1PCILA, pciaddr); |
| /* PMM1 PCI High Address */ |
| out32r(PCIL0_PMM1PCIHA, 0x00000000); |
| /* 256MB + No prefetching, and enable region */ |
| out32r(PCIL0_PMM1MA, 0xf0000001); |
| } else { |
| printf("Usage:\npmm %s\n", cmdtp->help); |
| } |
| return 0; |
| } |
| U_BOOT_CMD( |
| pmm, 2, 1, do_pmm, |
| "Setup pmm[1] registers", |
| "<pciaddr> (pciaddr will be aligned to 256MB)" |
| ); |
| |
| #if defined(CONFIG_SYS_EEPROM_WREN) |
| int do_eep_wren(cmd_tbl_t *cmdtp, int flag, int argc, char * const 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) */ |
| |
| #endif /* CONFIG_CMD_BSP */ |