diff options
author | Wolfgang Denk <wd@denx.de> | 2008-09-01 00:06:05 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2008-09-01 00:06:05 +0200 |
commit | a13b2d937941f6b525abfcfad96c034f94421188 (patch) | |
tree | 56e5bdaf62397b2f8cc2be9b17a035d9b059bf8a /drivers | |
parent | e155c9e00b5f21a6de28479259c440ba71289d00 (diff) | |
parent | d6e04258be8f2408845468d3cf722a4cf0433445 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-arm
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c64xx.c | 319 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/s3c64xx.c | 172 | ||||
-rw-r--r-- | drivers/usb/usb_ohci.c | 1 |
5 files changed, 494 insertions, 0 deletions
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 19233105a..b0abe6e52 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -37,6 +37,7 @@ endif COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o +COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o endif COBJS := $(COBJS-y) diff --git a/drivers/mtd/nand/s3c64xx.c b/drivers/mtd/nand/s3c64xx.c new file mode 100644 index 000000000..159fe76aa --- /dev/null +++ b/drivers/mtd/nand/s3c64xx.c @@ -0,0 +1,319 @@ +/* + * (C) Copyright 2006 DENX Software Engineering + * + * Implementation for U-Boot 1.1.6 by Samsung + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, <lg@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 <nand.h> +#include <s3c6400.h> + +#include <asm/io.h> +#include <asm/errno.h> + +#define MAX_CHIPS 2 +static int nand_cs[MAX_CHIPS] = {0, 1}; + +#ifdef CONFIG_NAND_SPL +#define printf(arg...) do {} while (0) +#endif + +/* Nand flash definition values by jsgood */ +#ifdef S3C_NAND_DEBUG +/* + * Function to print out oob buffer for debugging + * Written by jsgood + */ +static void print_oob(const char *header, struct mtd_info *mtd) +{ + int i; + struct nand_chip *chip = mtd->priv; + + printf("%s:\t", header); + + for (i = 0; i < 64; i++) + printf("%02x ", chip->oob_poi[i]); + + printf("\n"); +} +#endif /* S3C_NAND_DEBUG */ + +#ifdef CONFIG_NAND_SPL +static u_char nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + return readb(this->IO_ADDR_R); +} + +static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i = 0; i < len; i++) + writeb(buf[i], this->IO_ADDR_W); +} + +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + struct nand_chip *this = mtd->priv; + + for (i = 0; i < len; i++) + buf[i] = readb(this->IO_ADDR_R); +} +#endif + +static void s3c_nand_select_chip(struct mtd_info *mtd, int chip) +{ + int ctrl = readl(NFCONT); + + switch (chip) { + case -1: + ctrl |= 6; + break; + case 0: + ctrl &= ~2; + break; + case 1: + ctrl &= ~4; + break; + default: + return; + } + + writel(ctrl, NFCONT); +} + +/* + * Hardware specific access to control-lines function + * Written by jsgood + */ +static void s3c_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) + this->IO_ADDR_W = (void __iomem *)NFCMMD; + else if (ctrl & NAND_ALE) + this->IO_ADDR_W = (void __iomem *)NFADDR; + else + this->IO_ADDR_W = (void __iomem *)NFDATA; + if (ctrl & NAND_NCE) + s3c_nand_select_chip(mtd, *(int *)this->priv); + else + s3c_nand_select_chip(mtd, -1); + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); +} + +/* + * Function for checking device ready pin + * Written by jsgood + */ +static int s3c_nand_device_ready(struct mtd_info *mtdinfo) +{ + return !!(readl(NFSTAT) & NFSTAT_RnB); +} + +#ifdef CFG_S3C_NAND_HWECC +/* + * This function is called before encoding ecc codes to ready ecc engine. + * Written by jsgood + */ +static void s3c_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + u_long nfcont, nfconf; + + /* + * The original driver used 4-bit ECC for "new" MLC chips, i.e., for + * those with non-zero ID[3][3:2], which anyway only holds for ST + * (Numonyx) chips + */ + nfconf = readl(NFCONF) & ~NFCONF_ECC_4BIT; + + writel(nfconf, NFCONF); + + /* Initialize & unlock */ + nfcont = readl(NFCONT); + nfcont |= NFCONT_INITECC; + nfcont &= ~NFCONT_MECCLOCK; + + if (mode == NAND_ECC_WRITE) + nfcont |= NFCONT_ECC_ENC; + else if (mode == NAND_ECC_READ) + nfcont &= ~NFCONT_ECC_ENC; + + writel(nfcont, NFCONT); +} + +/* + * This function is called immediately after encoding ecc codes. + * This function returns encoded ecc codes. + * Written by jsgood + */ +static int s3c_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + u_long nfcont, nfmecc0; + + /* Lock */ + nfcont = readl(NFCONT); + nfcont |= NFCONT_MECCLOCK; + writel(nfcont, NFCONT); + + nfmecc0 = readl(NFMECC0); + + ecc_code[0] = nfmecc0 & 0xff; + ecc_code[1] = (nfmecc0 >> 8) & 0xff; + ecc_code[2] = (nfmecc0 >> 16) & 0xff; + ecc_code[3] = (nfmecc0 >> 24) & 0xff; + + return 0; +} + +/* + * This function determines whether read data is good or not. + * If SLC, must write ecc codes to controller before reading status bit. + * If MLC, status bit is already set, so only reading is needed. + * If status bit is good, return 0. + * If correctable errors occured, do that. + * If uncorrectable errors occured, return -1. + * Written by jsgood + */ +static int s3c_nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + int ret = -1; + u_long nfestat0, nfmeccdata0, nfmeccdata1, err_byte_addr; + u_char err_type, repaired; + + /* SLC: Write ecc to compare */ + nfmeccdata0 = (calc_ecc[1] << 16) | calc_ecc[0]; + nfmeccdata1 = (calc_ecc[3] << 16) | calc_ecc[2]; + writel(nfmeccdata0, NFMECCDATA0); + writel(nfmeccdata1, NFMECCDATA1); + + /* Read ecc status */ + nfestat0 = readl(NFESTAT0); + err_type = nfestat0 & 0x3; + + switch (err_type) { + case 0: /* No error */ + ret = 0; + break; + + case 1: + /* + * 1 bit error (Correctable) + * (nfestat0 >> 7) & 0x7ff :error byte number + * (nfestat0 >> 4) & 0x7 :error bit number + */ + err_byte_addr = (nfestat0 >> 7) & 0x7ff; + repaired = dat[err_byte_addr] ^ (1 << ((nfestat0 >> 4) & 0x7)); + + printf("S3C NAND: 1 bit error detected at byte %ld. " + "Correcting from 0x%02x to 0x%02x...OK\n", + err_byte_addr, dat[err_byte_addr], repaired); + + dat[err_byte_addr] = repaired; + + ret = 1; + break; + + case 2: /* Multiple error */ + case 3: /* ECC area error */ + printf("S3C NAND: ECC uncorrectable error detected. " + "Not correctable.\n"); + ret = -1; + break; + } + + return ret; +} +#endif /* CFG_S3C_NAND_HWECC */ + +/* + * Board-specific NAND initialization. The following members of the + * argument are board-specific (per include/linux/mtd/nand.h): + * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device + * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device + * - hwcontrol: hardwarespecific function for accesing control-lines + * - dev_ready: hardwarespecific function for accesing device ready/busy line + * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must + * only be provided if a hardware ECC is available + * - eccmode: mode of ecc, see defines + * - chip_delay: chip dependent delay for transfering data from array to + * read regs (tR) + * - options: various chip options. They can partly be set to inform + * nand_scan about special functionality. See the defines for further + * explanation + * Members with a "?" were not set in the merged testing-NAND branch, + * so they are not set here either. + */ +int board_nand_init(struct nand_chip *nand) +{ + static int chip_n; + + if (chip_n >= MAX_CHIPS) + return -ENODEV; + + NFCONT_REG = (NFCONT_REG & ~NFCONT_WP) | NFCONT_ENABLE | 0x6; + + nand->IO_ADDR_R = (void __iomem *)NFDATA; + nand->IO_ADDR_W = (void __iomem *)NFDATA; + nand->cmd_ctrl = s3c_nand_hwcontrol; + nand->dev_ready = s3c_nand_device_ready; + nand->select_chip = s3c_nand_select_chip; + nand->options = 0; +#ifdef CONFIG_NAND_SPL + nand->read_byte = nand_read_byte; + nand->write_buf = nand_write_buf; + nand->read_buf = nand_read_buf; +#endif + +#ifdef CFG_S3C_NAND_HWECC + nand->ecc.hwctl = s3c_nand_enable_hwecc; + nand->ecc.calculate = s3c_nand_calculate_ecc; + nand->ecc.correct = s3c_nand_correct_data; + + /* + * If you get more than 1 NAND-chip with different page-sizes on the + * board one day, it will get more complicated... + */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = CFG_NAND_ECCSIZE; + nand->ecc.bytes = CFG_NAND_ECCBYTES; +#else + nand->ecc.mode = NAND_ECC_SOFT; +#endif /* ! CFG_S3C_NAND_HWECC */ + + nand->priv = nand_cs + chip_n++; + + return 0; +} diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 2384735a2..f30014d32 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -30,6 +30,7 @@ COBJS-$(CONFIG_MCFUART) += mcfuart.o COBJS-$(CONFIG_NS9750_UART) += ns9750_serial.o COBJS-y += ns16550.o COBJS-$(CONFIG_DRIVER_S3C4510_UART) += s3c4510b_uart.o +COBJS-$(CONFIG_S3C64XX) += s3c64xx.o COBJS-y += serial.o COBJS-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o COBJS-y += serial_pl010.o diff --git a/drivers/serial/s3c64xx.c b/drivers/serial/s3c64xx.c new file mode 100644 index 000000000..9d8fcb9b4 --- /dev/null +++ b/drivers/serial/s3c64xx.c @@ -0,0 +1,172 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> + * + * 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 <s3c6400.h> + +#ifdef CONFIG_SERIAL1 +#define UART_NR S3C64XX_UART0 + +#elif defined(CONFIG_SERIAL2) +#define UART_NR S3C64XX_UART1 + +#elif defined(CONFIG_SERIAL3) +#define UART_NR S3C64XX_UART2 + +#else +#error "Bad: you didn't configure serial ..." +#endif + +#define barrier() asm volatile("" ::: "memory") + +/* + * The coefficient, used to calculate the baudrate on S3C6400 UARTs is + * calculated as + * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT + * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1, + * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants: + */ +static const int udivslot[] = { + 0, + 0x0080, + 0x0808, + 0x0888, + 0x2222, + 0x4924, + 0x4a52, + 0x54aa, + 0x5555, + 0xd555, + 0xd5d5, + 0xddd5, + 0xdddd, + 0xdfdd, + 0xdfdf, + 0xffdf, +}; + +void serial_setbrg(void) +{ + DECLARE_GLOBAL_DATA_PTR; + s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); + u32 pclk = get_PCLK(); + u32 baudrate = gd->baudrate; + int i; + + i = (pclk / baudrate) % 16; + + uart->UBRDIV = pclk / baudrate / 16 - 1; + uart->UDIVSLOT = udivslot[i]; + + for (i = 0; i < 100; i++) + barrier(); +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + */ +int serial_init(void) +{ + s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); + + /* reset and enable FIFOs, set triggers to the maximum */ + uart->UFCON = 0xff; + uart->UMCON = 0; + /* 8N1 */ + uart->ULCON = 3; + /* No interrupts, no DMA, pure polling */ + uart->UCON = 5; + + serial_setbrg(); + + return 0; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int serial_getc(void) +{ + s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); + + /* wait for character to arrive */ + while (!(uart->UTRSTAT & 0x1)); + + return uart->URXH & 0xff; +} + +#ifdef CONFIG_MODEM_SUPPORT +static int be_quiet; +void disable_putc(void) +{ + be_quiet = 1; +} + +void enable_putc(void) +{ + be_quiet = 0; +} +#endif + + +/* + * Output a single byte to the serial port. + */ +void serial_putc(const char c) +{ + s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); + +#ifdef CONFIG_MODEM_SUPPORT + if (be_quiet) + return; +#endif + + /* wait for room in the tx FIFO */ + while (!(uart->UTRSTAT & 0x2)); + + uart->UTXH = c; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc('\r'); +} + +/* + * Test whether a character is in the RX buffer + */ +int serial_tstc(void) +{ + s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR); + + return uart->UTRSTAT & 0x1; +} + +void serial_puts(const char *s) +{ + while (*s) + serial_putc(*s++); +} diff --git a/drivers/usb/usb_ohci.c b/drivers/usb/usb_ohci.c index fd60edbb3..0bfa4d782 100644 --- a/drivers/usb/usb_ohci.c +++ b/drivers/usb/usb_ohci.c @@ -69,6 +69,7 @@ #if defined(CONFIG_ARM920T) || \ defined(CONFIG_S3C2400) || \ defined(CONFIG_S3C2410) || \ + defined(CONFIG_S3C6400) || \ defined(CONFIG_440EP) || \ defined(CONFIG_PCI_OHCI) || \ defined(CONFIG_MPC5200) || \ |