diff options
Diffstat (limited to 'roms/u-boot/board/prodrive/alpr')
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/Makefile | 9 | ||||
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/alpr.c | 215 | ||||
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/config.mk | 16 | ||||
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/fpga.c | 239 | ||||
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/init.S | 53 | ||||
-rw-r--r-- | roms/u-boot/board/prodrive/alpr/nand.c | 136 |
6 files changed, 668 insertions, 0 deletions
diff --git a/roms/u-boot/board/prodrive/alpr/Makefile b/roms/u-boot/board/prodrive/alpr/Makefile new file mode 100644 index 00000000..812d041e --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = alpr.o fpga.o nand.o +extra-y += init.o diff --git a/roms/u-boot/board/prodrive/alpr/alpr.c b/roms/u-boot/board/prodrive/alpr/alpr.c new file mode 100644 index 00000000..31c1ab5d --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/alpr.c @@ -0,0 +1,215 @@ +/* + * (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + +#include <common.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <spd_sdram.h> +#include <asm/ppc4xx-emac.h> +#include <miiphy.h> +#include <asm/processor.h> +#include <asm/4xx_pci.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern int alpr_fpga_init(void); + +int board_early_init_f (void) +{ + /*------------------------------------------------------------------------- + * Initialize EBC CONFIG + *-------------------------------------------------------------------------*/ + mtebc(EBC0_CFG, EBC_CFG_LE_UNLOCK | + EBC_CFG_PTD_DISABLE | EBC_CFG_RTC_64PERCLK | + EBC_CFG_ATC_PREVIOUS | EBC_CFG_DTC_PREVIOUS | + EBC_CFG_CTC_PREVIOUS | EBC_CFG_EMC_NONDEFAULT | + EBC_CFG_PME_DISABLE | EBC_CFG_PR_32); + + /*-------------------------------------------------------------------- + * Setup the interrupt controller polarities, triggers, etc. + *-------------------------------------------------------------------*/ + /* + * Because of the interrupt handling rework to handle 440GX interrupts + * with the common code, we needed to change names of the UIC registers. + * Here the new relationship: + * + * U-Boot name 440GX name + * ----------------------- + * UIC0 UICB0 + * UIC1 UIC0 + * UIC2 UIC1 + * UIC3 UIC2 + */ + mtdcr (UIC1SR, 0xffffffff); /* clear all */ + mtdcr (UIC1ER, 0x00000000); /* disable all */ + mtdcr (UIC1CR, 0x00000009); /* SMI & UIC1 crit are critical */ + mtdcr (UIC1PR, 0xfffffe03); /* per manual */ + mtdcr (UIC1TR, 0x01c00000); /* per manual */ + mtdcr (UIC1VR, 0x00000001); /* int31 highest, base=0x000 */ + mtdcr (UIC1SR, 0xffffffff); /* clear all */ + + mtdcr (UIC2SR, 0xffffffff); /* clear all */ + mtdcr (UIC2ER, 0x00000000); /* disable all */ + mtdcr (UIC2CR, 0x00000000); /* all non-critical */ + mtdcr (UIC2PR, 0xffffe0ff); /* per ref-board manual */ + mtdcr (UIC2TR, 0x00ffc000); /* per ref-board manual */ + mtdcr (UIC2VR, 0x00000001); /* int31 highest, base=0x000 */ + mtdcr (UIC2SR, 0xffffffff); /* clear all */ + + mtdcr (UIC3SR, 0xffffffff); /* clear all */ + mtdcr (UIC3ER, 0x00000000); /* disable all */ + mtdcr (UIC3CR, 0x00000000); /* all non-critical */ + mtdcr (UIC3PR, 0xffffffff); /* per ref-board manual */ + mtdcr (UIC3TR, 0x00ff8c0f); /* per ref-board manual */ + mtdcr (UIC3VR, 0x00000001); /* int31 highest, base=0x000 */ + mtdcr (UIC3SR, 0xffffffff); /* clear all */ + + mtdcr (UIC0SR, 0xfc000000); /* clear all */ + mtdcr (UIC0ER, 0x00000000); /* disable all */ + mtdcr (UIC0CR, 0x00000000); /* all non-critical */ + mtdcr (UIC0PR, 0xfc000000); /* */ + mtdcr (UIC0TR, 0x00000000); /* */ + mtdcr (UIC0VR, 0x00000001); /* */ + + /* Setup shutdown/SSD empty interrupt as inputs */ + out32(GPIO0_TCR, in32(GPIO0_TCR) & ~(CONFIG_SYS_GPIO_SHUTDOWN | CONFIG_SYS_GPIO_SSD_EMPTY)); + out32(GPIO0_ODR, in32(GPIO0_ODR) & ~(CONFIG_SYS_GPIO_SHUTDOWN | CONFIG_SYS_GPIO_SSD_EMPTY)); + + /* Setup GPIO/IRQ multiplexing */ + mtsdr(SDR0_PFC0, 0x01a33e00); + + return 0; +} + +int last_stage_init(void) +{ + unsigned short reg; + + /* + * Configure LED's of both Marvell 88E1111 PHY's + * + * This has to be done after the 4xx ethernet driver is loaded, + * so "last_stage_init()" is the right place. + */ + miiphy_read("ppc_4xx_eth2", CONFIG_PHY2_ADDR, 0x18, ®); + reg |= 0x0001; + miiphy_write("ppc_4xx_eth2", CONFIG_PHY2_ADDR, 0x18, reg); + miiphy_read("ppc_4xx_eth3", CONFIG_PHY3_ADDR, 0x18, ®); + reg |= 0x0001; + miiphy_write("ppc_4xx_eth3", CONFIG_PHY3_ADDR, 0x18, reg); + + return 0; +} + +static int board_rev(void) +{ + /* Setup as input */ + out32(GPIO0_TCR, in32(GPIO0_TCR) & ~(CONFIG_SYS_GPIO_REV0 | CONFIG_SYS_GPIO_REV1)); + out32(GPIO0_ODR, in32(GPIO0_ODR) & ~(CONFIG_SYS_GPIO_REV0 | CONFIG_SYS_GPIO_REV1)); + + return (in32(GPIO0_IR) >> 16) & 0x3; +} + +int checkboard (void) +{ + char buf[64]; + int i = getenv_f("serial#", buf, sizeof(buf)); + + printf ("Board: ALPR"); + if (i > 0) { + puts(", serial# "); + puts(buf); + } + printf(" (Rev. %d)\n", board_rev()); + + return (0); +} + +#if defined(CONFIG_PCI) +/* + * Override weak pci_pre_init() + */ +int pci_pre_init(struct pci_controller *hose) +{ + if (__pci_pre_init(hose) == 0) + return 0; + + /* FPGA Init */ + alpr_fpga_init(); + + return 1; +} + +/************************************************************************* + * Override 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. + * + * Rather than hard-code a bad assumption in the general 440 code, the + * 440 pci code requires the board to decide at runtime. + * + * Return 0 for adapter mode, non-zero for host (monarch) mode. + * + * + ************************************************************************/ +static void wait_for_pci_ready(void) +{ + /* + * Configure EREADY as input + */ + out32(GPIO0_TCR, in32(GPIO0_TCR) & ~CONFIG_SYS_GPIO_EREADY); + udelay(1000); + + for (;;) { + if (in32(GPIO0_IR) & CONFIG_SYS_GPIO_EREADY) + return; + } + +} + +int is_pci_host(struct pci_controller *hose) +{ + wait_for_pci_ready(); + return 1; /* return 1 for host controller */ +} +#endif /* defined(CONFIG_PCI) */ + +/************************************************************************* + * pci_master_init + * + ************************************************************************/ +#if defined(CONFIG_PCI) && defined(CONFIG_SYS_PCI_MASTER_INIT) +void pci_master_init(struct pci_controller *hose) +{ + /*--------------------------------------------------------------------------+ + | PowerPC440 PCI Master configuration. + | Map PLB/processor addresses to PCI memory space. + | PLB address 0xA0000000-0xCFFFFFFF ==> PCI address 0x80000000-0xCFFFFFFF + | Use byte reversed out routines to handle endianess. + | Make this region non-prefetchable. + +--------------------------------------------------------------------------*/ + out32r( PCIL0_POM0SA, 0 ); /* disable */ + out32r( PCIL0_POM1SA, 0 ); /* disable */ + out32r( PCIL0_POM2SA, 0 ); /* disable */ + + out32r(PCIL0_POM0LAL, CONFIG_SYS_PCI_MEMBASE); /* PMM0 Local Address */ + out32r(PCIL0_POM0LAH, 0x00000003); /* PMM0 Local Address */ + out32r(PCIL0_POM0PCIAL, CONFIG_SYS_PCI_MEMBASE); /* PMM0 PCI Low Address */ + out32r(PCIL0_POM0PCIAH, 0x00000000); /* PMM0 PCI High Address */ + out32r(PCIL0_POM0SA, ~(0x10000000 - 1) | 1); /* 256MB + enable region */ + + out32r(PCIL0_POM1LAL, CONFIG_SYS_PCI_MEMBASE2); /* PMM0 Local Address */ + out32r(PCIL0_POM1LAH, 0x00000003); /* PMM0 Local Address */ + out32r(PCIL0_POM1PCIAL, CONFIG_SYS_PCI_MEMBASE2); /* PMM0 PCI Low Address */ + out32r(PCIL0_POM1PCIAH, 0x00000000); /* PMM0 PCI High Address */ + out32r(PCIL0_POM1SA, ~(0x10000000 - 1) | 1); /* 256MB + enable region */ +} +#endif /* defined(CONFIG_PCI) && defined(CONFIG_SYS_PCI_MASTER_INIT) */ diff --git a/roms/u-boot/board/prodrive/alpr/config.mk b/roms/u-boot/board/prodrive/alpr/config.mk new file mode 100644 index 00000000..0ccb2e66 --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/config.mk @@ -0,0 +1,16 @@ +# +# (C) Copyright 2004 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -DCONFIG_440=1 + +ifeq ($(debug),1) +PLATFORM_CPPFLAGS += -DDEBUG +endif + +ifeq ($(dbcr),1) +PLATFORM_CPPFLAGS += -DCONFIG_SYS_INIT_DBCR=0x8cff0000 +endif diff --git a/roms/u-boot/board/prodrive/alpr/fpga.c b/roms/u-boot/board/prodrive/alpr/fpga.c new file mode 100644 index 00000000..3133f942 --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/fpga.c @@ -0,0 +1,239 @@ +/* + * (C) Copyright 2006 + * Heiko Schocher, DENX Software Engineering, hs@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Altera FPGA configuration support for the ALPR computer from prodrive + */ + +#include <common.h> +#include <altera.h> +#include <ACEX1K.h> +#include <command.h> +#include <asm/processor.h> +#include <asm/ppc440.h> +#include "fpga.h" + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_FPGA) + +#ifdef FPGA_DEBUG +#define PRINTF(fmt, args...) printf(fmt , ##args) +#else +#define PRINTF(fmt, args...) +#endif + +static unsigned long regval; + +#define SET_GPIO_REG_0(reg, bit) do { \ + regval = in32(reg); \ + regval &= ~(0x80000000 >> bit); \ + out32(reg, regval); \ + } while (0) + +#define SET_GPIO_REG_1(reg, bit) do { \ + regval = in32(reg); \ + regval |= (0x80000000 >> bit); \ + out32(reg, regval); \ + } while (0) + +#define SET_GPIO_0(bit) SET_GPIO_REG_0(GPIO0_OR, bit) +#define SET_GPIO_1(bit) SET_GPIO_REG_1(GPIO0_OR, bit) + +#define FPGA_PRG (0x80000000 >> CONFIG_SYS_GPIO_PROG_EN) +#define FPGA_CONFIG (0x80000000 >> CONFIG_SYS_GPIO_CONFIG) +#define FPGA_DATA (0x80000000 >> CONFIG_SYS_GPIO_DATA) +#define FPGA_CLK (0x80000000 >> CONFIG_SYS_GPIO_CLK) +#define OLD_VAL (FPGA_PRG | FPGA_CONFIG) + +#define SET_FPGA(data) out32(GPIO0_OR, data) + +#define FPGA_WRITE_1 do { \ + SET_FPGA(OLD_VAL | 0 | FPGA_DATA); /* set data to 1 */ \ + SET_FPGA(OLD_VAL | FPGA_CLK | FPGA_DATA); /* set data to 1 */ \ +} while (0) + +#define FPGA_WRITE_0 do { \ + SET_FPGA(OLD_VAL | 0 | 0); /* set data to 0 */ \ + SET_FPGA(OLD_VAL | FPGA_CLK | 0); /* set data to 1 */ \ +} while (0) + +/* Plattforminitializations */ +/* Here we have to set the FPGA Chain */ +/* PROGRAM_PROG_EN = HIGH */ +/* PROGRAM_SEL_DPR = LOW */ +int fpga_pre_fn(int cookie) +{ + /* Enable the FPGA Chain */ + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_PROG_EN); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_PROG_EN); + SET_GPIO_1(CONFIG_SYS_GPIO_PROG_EN); + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_SEL_DPR); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_SEL_DPR); + SET_GPIO_0((CONFIG_SYS_GPIO_SEL_DPR)); + + /* initialize the GPIO Pins */ + /* output */ + SET_GPIO_0(CONFIG_SYS_GPIO_CLK); + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_CLK); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CLK); + + /* output */ + SET_GPIO_0(CONFIG_SYS_GPIO_DATA); + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_DATA); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_DATA); + + /* First we set STATUS to 0 then as an input */ + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_STATUS); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_STATUS); + SET_GPIO_0(CONFIG_SYS_GPIO_STATUS); + SET_GPIO_REG_0(GPIO0_TCR, CONFIG_SYS_GPIO_STATUS); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_STATUS); + + /* output */ + SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_CONFIG); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CONFIG); + SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG); + + /* input */ + SET_GPIO_0(CONFIG_SYS_GPIO_CON_DON); + SET_GPIO_REG_0(GPIO0_TCR, CONFIG_SYS_GPIO_CON_DON); + SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CON_DON); + + /* CONFIG = 0 STATUS = 0 -> FPGA in reset state */ + SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG); + return FPGA_SUCCESS; +} + +/* Set the state of CONFIG Pin */ +int fpga_config_fn(int assert_config, int flush, int cookie) +{ + if (assert_config) + SET_GPIO_1(CONFIG_SYS_GPIO_CONFIG); + else + SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG); + + return FPGA_SUCCESS; +} + +/* Returns the state of STATUS Pin */ +int fpga_status_fn(int cookie) +{ + unsigned long reg; + + reg = in32(GPIO0_IR); + if (reg & (0x80000000 >> CONFIG_SYS_GPIO_STATUS)) { + PRINTF("STATUS = HIGH\n"); + return FPGA_FAIL; + } + PRINTF("STATUS = LOW\n"); + return FPGA_SUCCESS; +} + +/* Returns the state of CONF_DONE Pin */ +int fpga_done_fn(int cookie) +{ + unsigned long reg; + reg = in32(GPIO0_IR); + if (reg & (0x80000000 >> CONFIG_SYS_GPIO_CON_DON)) { + PRINTF("CONF_DON = HIGH\n"); + return FPGA_FAIL; + } + PRINTF("CONF_DON = LOW\n"); + return FPGA_SUCCESS; +} + +/* writes the complete buffer to the FPGA + writing the complete buffer in one function is much faster, + then calling it for every bit */ +int fpga_write_fn(const void *buf, size_t len, int flush, int cookie) +{ + size_t bytecount = 0; + unsigned char *data = (unsigned char *) buf; + unsigned char val = 0; + int i; + int len_40 = len / 40; + + while (bytecount < len) { + val = data[bytecount++]; + i = 8; + do { + if (val & 0x01) + FPGA_WRITE_1; + else + FPGA_WRITE_0; + + val >>= 1; + i--; + } while (i > 0); + +#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK + if (bytecount % len_40 == 0) { + putc('.'); /* let them know we are alive */ +#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC + if (ctrlc()) + return FPGA_FAIL; +#endif + } +#endif + } + return FPGA_SUCCESS; +} + +/* called, when programming is aborted */ +int fpga_abort_fn(int cookie) +{ + SET_GPIO_1((CONFIG_SYS_GPIO_SEL_DPR)); + return FPGA_SUCCESS; +} + +/* called, when programming was succesful */ +int fpga_post_fn(int cookie) +{ + return fpga_abort_fn(cookie); +} + +/* Note that these are pointers to code that is in Flash. They will be + * relocated at runtime. + */ +Altera_CYC2_Passive_Serial_fns fpga_fns = { + fpga_pre_fn, + fpga_config_fn, + fpga_status_fn, + fpga_done_fn, + fpga_write_fn, + fpga_abort_fn, + fpga_post_fn +}; + +Altera_desc fpga[CONFIG_FPGA_COUNT] = { + {Altera_CYC2, + passive_serial, + Altera_EP2C35_SIZE, + (void *) &fpga_fns, + NULL, + 0} +}; + +/* + * Initialize the fpga. Return 1 on success, 0 on failure. + */ +int alpr_fpga_init(void) +{ + int i; + + PRINTF("%s:%d: Initialize FPGA interface\n", __func__, __LINE__); + fpga_init(); + + for (i = 0; i < CONFIG_FPGA_COUNT; i++) { + PRINTF("%s:%d: Adding fpga %d\n", __func__, __LINE__, i); + fpga_add(fpga_altera, &fpga[i]); + } + return 1; +} + +#endif diff --git a/roms/u-boot/board/prodrive/alpr/init.S b/roms/u-boot/board/prodrive/alpr/init.S new file mode 100644 index 00000000..7ff7a591 --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/init.S @@ -0,0 +1,53 @@ +/* + * (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <ppc_asm.tmpl> +#include <asm/mmu.h> +#include <config.h> +#include <asm/ppc4xx.h> + +/************************************************************************** + * TLB TABLE + * + * This table is used by the cpu boot code to setup the initial tlb + * entries. Rather than make broad assumptions in the cpu source tree, + * this table lets each board set things up however they like. + * + * Pointer to the table is returned in r1 + * + *************************************************************************/ + + .section .bootpg,"ax" + .globl tlbtab + +tlbtab: + tlbtab_start + tlbentry(0xff000000, SZ_16M, 0xff000000, 1, AC_RWX | SA_IG ) + tlbentry(CONFIG_SYS_PERIPHERAL_BASE, SZ_256M, 0x40000000, 1, AC_RW | SA_IG) + tlbentry(CONFIG_SYS_ISRAM_BASE, SZ_4K, 0x80000000, 0, AC_RWX) + tlbentry(CONFIG_SYS_ISRAM_BASE + 0x1000, SZ_4K, 0x80001000, 0, AC_RWX) +#ifdef CONFIG_4xx_DCACHE + tlbentry(CONFIG_SYS_SDRAM_BASE, SZ_256M, 0x00000000, 0, AC_RWX | SA_G) +#else + tlbentry(CONFIG_SYS_SDRAM_BASE, SZ_256M, 0x00000000, 0, AC_RWX | SA_IG) +#endif + +#ifdef CONFIG_SYS_INIT_RAM_DCACHE + /* TLB-entry for init-ram in dcache (SA_I must be turned off!) */ + tlbentry(CONFIG_SYS_INIT_RAM_ADDR, SZ_64K, CONFIG_SYS_INIT_RAM_ADDR, 0, AC_RWX | SA_G) +#endif + tlbentry(CONFIG_SYS_PCI_BASE, SZ_256M, 0x00000000, 2, AC_RW | SA_IG) + + /* PCI */ + tlbentry(CONFIG_SYS_PCI_MEMBASE, SZ_256M, CONFIG_SYS_PCI_MEMBASE, 3, AC_RW | SA_IG) + tlbentry(CONFIG_SYS_PCI_MEMBASE1, SZ_256M, CONFIG_SYS_PCI_MEMBASE1, 3, AC_RW | SA_IG) + tlbentry(CONFIG_SYS_PCI_MEMBASE2, SZ_256M, CONFIG_SYS_PCI_MEMBASE2, 3, AC_RW | SA_IG) + + /* NAND */ + tlbentry(CONFIG_SYS_NAND_BASE, SZ_4K, CONFIG_SYS_NAND_BASE, 1, AC_RWX | SA_IG) + tlbtab_end diff --git a/roms/u-boot/board/prodrive/alpr/nand.c b/roms/u-boot/board/prodrive/alpr/nand.c new file mode 100644 index 00000000..50e8d82b --- /dev/null +++ b/roms/u-boot/board/prodrive/alpr/nand.c @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2006 + * Heiko Schocher, DENX Software Engineering, hs@denx.de + * + * (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#if defined(CONFIG_CMD_NAND) + +#include <asm/processor.h> +#include <nand.h> + +struct alpr_ndfc_regs { + u8 cmd[4]; + u8 addr_wait; + u8 term; + u8 dummy; + u8 dummy2; + u8 data; +}; + +static u8 hwctl; +static struct alpr_ndfc_regs *alpr_ndfc = NULL; + +#define readb(addr) (u8)(*(volatile u8 *)(addr)) +#define writeb(d,addr) *(volatile u8 *)(addr) = ((u8)(d)) + +/* + * The ALPR has a NAND Flash Controller (NDFC) that handles all accesses to + * the NAND devices. The NDFC has command, address and data registers that + * when accessed will set up the NAND flash pins appropriately. We'll use the + * hwcontrol function to save the configuration in a global variable. + * We can then use this information in the read and write functions to + * determine which NDFC register to access. + * + * There are 2 NAND devices on the board, a Hynix HY27US08561A (1 GByte). + */ +static void alpr_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if ( ctrl & NAND_CLE ) + hwctl |= 0x1; + else + hwctl &= ~0x1; + if ( ctrl & NAND_ALE ) + hwctl |= 0x2; + else + hwctl &= ~0x2; + if ( (ctrl & NAND_NCE) != NAND_NCE) + writeb(0x00, &(alpr_ndfc->term)); + } + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +static u_char alpr_nand_read_byte(struct mtd_info *mtd) +{ + return readb(&(alpr_ndfc->data)); +} + +static void alpr_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct nand_chip *nand = mtd->priv; + int i; + + for (i = 0; i < len; i++) { + if (hwctl & 0x1) + /* + * IO_ADDR_W used as CMD[i] reg to support multiple NAND + * chips. + */ + writeb(buf[i], nand->IO_ADDR_W); + else if (hwctl & 0x2) + writeb(buf[i], &(alpr_ndfc->addr_wait)); + else + writeb(buf[i], &(alpr_ndfc->data)); + } +} + +static void alpr_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + buf[i] = readb(&(alpr_ndfc->data)); + } +} + +static int alpr_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (buf[i] != readb(&(alpr_ndfc->data))) + return i; + + return 0; +} + +static int alpr_nand_dev_ready(struct mtd_info *mtd) +{ + /* + * Blocking read to wait for NAND to be ready + */ + (void)readb(&(alpr_ndfc->addr_wait)); + + /* + * Return always true + */ + return 1; +} + +int board_nand_init(struct nand_chip *nand) +{ + alpr_ndfc = (struct alpr_ndfc_regs *)CONFIG_SYS_NAND_BASE; + + nand->ecc.mode = NAND_ECC_SOFT; + + /* Reference hardware control function */ + nand->cmd_ctrl = alpr_nand_hwcontrol; + nand->read_byte = alpr_nand_read_byte; + nand->write_buf = alpr_nand_write_buf; + nand->read_buf = alpr_nand_read_buf; + nand->verify_buf = alpr_nand_verify_buf; + nand->dev_ready = alpr_nand_dev_ready; + + return 0; +} +#endif |