summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2008-09-01 00:06:05 +0200
committerWolfgang Denk <wd@denx.de>2008-09-01 00:06:05 +0200
commita13b2d937941f6b525abfcfad96c034f94421188 (patch)
tree56e5bdaf62397b2f8cc2be9b17a035d9b059bf8a /drivers
parente155c9e00b5f21a6de28479259c440ba71289d00 (diff)
parentd6e04258be8f2408845468d3cf722a4cf0433445 (diff)
Merge branch 'master' of git://git.denx.de/u-boot-arm
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/s3c64xx.c319
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/s3c64xx.c172
-rw-r--r--drivers/usb/usb_ohci.c1
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) || \