summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/dw_mmc.c27
-rw-r--r--drivers/mmc/exynos_dw_mmc.c127
-rw-r--r--drivers/mmc/mmc.c134
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/fsl_ifc_spl.c258
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/gigadevice.c81
-rw-r--r--drivers/mtd/spi/spi_flash.c3
-rw-r--r--drivers/mtd/spi/spi_flash_internal.h1
-rw-r--r--drivers/pci/fsl_pci_init.c6
-rw-r--r--drivers/power/exynos-tmu.c123
-rw-r--r--drivers/serial/serial_s5p.c13
-rw-r--r--drivers/video/exynos_fb.c4
13 files changed, 699 insertions, 80 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 4070d4e..5da20ed 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -129,13 +129,13 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
unsigned int timeout = 100000;
u32 retry = 10000;
u32 mask, ctrl;
+ ulong start = get_timer(0);
while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
- if (timeout == 0) {
+ if (get_timer(start) > timeout) {
printf("Timeout on data busy\n");
return TIMEOUT;
}
- timeout--;
}
dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
@@ -143,7 +143,6 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
if (data)
dwmci_prepare_data(host, data);
-
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
if (data)
@@ -231,9 +230,8 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq)
int timeout = 10000;
unsigned long sclk;
- if (freq == host->clock)
+ if ((freq == host->clock) || (freq == 0))
return 0;
-
/*
* If host->mmc_clk didn't define,
* then assume that host->bus_hz is source clock value.
@@ -314,7 +312,7 @@ static void dwmci_set_ios(struct mmc *mmc)
static int dwmci_init(struct mmc *mmc)
{
struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
- u32 fifo_size, fifoth_val;
+ u32 fifo_size;
dwmci_writel(host, DWMCI_PWREN, 1);
@@ -323,6 +321,9 @@ static int dwmci_init(struct mmc *mmc)
return -1;
}
+ /* Enumerate at 400KHz */
+ dwmci_setup_bus(host, mmc->f_min);
+
dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF);
dwmci_writel(host, DWMCI_INTMASK, 0);
@@ -331,13 +332,13 @@ static int dwmci_init(struct mmc *mmc)
dwmci_writel(host, DWMCI_IDINTEN, 0);
dwmci_writel(host, DWMCI_BMOD, 1);
- fifo_size = dwmci_readl(host, DWMCI_FIFOTH);
- if (host->fifoth_val)
- fifoth_val = host->fifoth_val;
- else
- fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) |
- TX_WMARK(fifo_size/2);
- dwmci_writel(host, DWMCI_FIFOTH, fifoth_val);
+ if (!host->fifoth_val) {
+ fifo_size = dwmci_readl(host, DWMCI_FIFOTH);
+ fifo_size = ((fifo_size & RX_WMARK_MASK) >> RX_WMARK_SHIFT) + 1;
+ host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size / 2 - 1) |
+ TX_WMARK(fifo_size / 2);
+ }
+ dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val);
dwmci_writel(host, DWMCI_CLKENA, 0);
dwmci_writel(host, DWMCI_CLKSRC, 0);
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 72a31b7..4238dd9 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -19,39 +19,146 @@
*/
#include <common.h>
-#include <malloc.h>
#include <dwmmc.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <malloc.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/clk.h>
+#include <asm/arch/pinmux.h>
-static char *EXYNOS_NAME = "EXYNOS DWMMC";
+#define DWMMC_MAX_CH_NUM 4
+#define DWMMC_MAX_FREQ 52000000
+#define DWMMC_MIN_FREQ 400000
+#define DWMMC_MMC0_CLKSEL_VAL 0x03030001
+#define DWMMC_MMC2_CLKSEL_VAL 0x03020001
+/*
+ * Function used as callback function to initialise the
+ * CLKSEL register for every mmc channel.
+ */
static void exynos_dwmci_clksel(struct dwmci_host *host)
{
- u32 val;
- val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) |
- DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(0);
+ dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
+}
- dwmci_writel(host, DWMCI_CLKSEL, val);
+unsigned int exynos_dwmci_get_clk(int dev_index)
+{
+ return get_mmc_clk(dev_index);
}
-int exynos_dwmci_init(u32 regbase, int bus_width, int index)
+/*
+ * This function adds the mmc channel to be registered with mmc core.
+ * index - mmc channel number.
+ * regbase - register base address of mmc channel specified in 'index'.
+ * bus_width - operating bus width of mmc channel specified in 'index'.
+ * clksel - value to be written into CLKSEL register in case of FDT.
+ * NULL in case od non-FDT.
+ */
+int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
{
struct dwmci_host *host = NULL;
+ unsigned int div;
+ unsigned long freq, sclk;
host = malloc(sizeof(struct dwmci_host));
if (!host) {
printf("dwmci_host malloc fail!\n");
return 1;
}
+ /* request mmc clock vlaue of 52MHz. */
+ freq = 52000000;
+ sclk = get_mmc_clk(index);
+ div = DIV_ROUND_UP(sclk, freq);
+ /* set the clock divisor for mmc */
+ set_mmc_clk(index, div);
- host->name = EXYNOS_NAME;
+ host->name = "EXYNOS DWMMC";
host->ioaddr = (void *)regbase;
host->buswidth = bus_width;
+
+ if (clksel) {
+ host->clksel_val = clksel;
+ } else {
+ if (0 == index)
+ host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
+ if (2 == index)
+ host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
+ }
+
host->clksel = exynos_dwmci_clksel;
host->dev_index = index;
+ host->mmc_clk = exynos_dwmci_get_clk;
+ /* Add the mmc channel to be registered with mmc core */
+ if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
+ debug("dwmmc%d registration failed\n", index);
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int exynos_dwmmc_init(const void *blob)
+{
+ int index, bus_width;
+ int node_list[DWMMC_MAX_CH_NUM];
+ int err = 0, dev_id, flag, count, i;
+ u32 clksel_val, base, timing[3];
+
+ count = fdtdec_find_aliases_for_id(blob, "mmc",
+ COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
+ DWMMC_MAX_CH_NUM);
+
+ for (i = 0; i < count; i++) {
+ int node = node_list[i];
+
+ if (node <= 0)
+ continue;
- add_dwmci(host, 52000000, 400000);
+ /* Extract device id for each mmc channel */
+ dev_id = pinmux_decode_periph_id(blob, node);
+ /* Get the bus width from the device node */
+ bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
+ if (bus_width <= 0) {
+ debug("DWMMC: Can't get bus-width\n");
+ return -1;
+ }
+ if (8 == bus_width)
+ flag = PINMUX_FLAG_8BIT_MODE;
+ else
+ flag = PINMUX_FLAG_NONE;
+
+ /* config pinmux for each mmc channel */
+ err = exynos_pinmux_config(dev_id, flag);
+ if (err) {
+ debug("DWMMC not configured\n");
+ return err;
+ }
+
+ index = dev_id - PERIPH_ID_SDMMC0;
+
+ /* Get the base address from the device node */
+ base = fdtdec_get_addr(blob, node, "reg");
+ if (!base) {
+ debug("DWMMC: Can't get base address\n");
+ return -1;
+ }
+ /* Extract the timing info from the node */
+ err = fdtdec_get_int_array(blob, node, "samsung,timing",
+ timing, 3);
+ if (err) {
+ debug("Can't get sdr-timings for divider\n");
+ return -1;
+ }
+
+ clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
+ DWMCI_SET_DRV_CLK(timing[1]) |
+ DWMCI_SET_DIV_RATIO(timing[2]));
+ /* Initialise each mmc channel */
+ err = exynos_dwmci_add_port(index, base, bus_width, clksel_val);
+ if (err)
+ debug("dwmmc Channel-%d init failed\n", index);
+ }
return 0;
}
-
+#endif
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e6a296a..83d2df7 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1503,3 +1503,137 @@ int mmc_initialize(bd_t *bis)
do_preinit();
return 0;
}
+
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+/*
+ * This function changes the size of boot partition and the size of rpmb
+ * partition present on EMMC devices.
+ *
+ * Input Parameters:
+ * struct *mmc: pointer for the mmc device strcuture
+ * bootsize: size of boot partition
+ * rpmbsize: size of rpmb partition
+ *
+ * Returns 0 on success.
+ */
+
+int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ int err;
+ struct mmc_cmd cmd;
+
+ /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = MMC_CMD62_ARG1;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
+ return err;
+ }
+
+ /* Boot partition changing mode */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = MMC_CMD62_ARG2;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
+ return err;
+ }
+ /* boot partition size is multiple of 128KB */
+ bootsize = (bootsize * 1024) / 128;
+
+ /* Arg: boot partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = bootsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
+ return err;
+ }
+ /* RPMB partition size is multiple of 128KB */
+ rpmbsize = (rpmbsize * 1024) / 128;
+ /* Arg: RPMB partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = rpmbsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+/*
+ * This function shall form and send the commands to open / close the
+ * boot partition specified by user.
+ *
+ * Input Parameters:
+ * ack: 0x0 - No boot acknowledge sent (default)
+ * 0x1 - Boot acknowledge sent during boot operation
+ * part_num: User selects boot data that will be sent to master
+ * 0x0 - Device not boot enabled (default)
+ * 0x1 - Boot partition 1 enabled for boot
+ * 0x2 - Boot partition 2 enabled for boot
+ * access: User selects partitions to access
+ * 0x0 : No access to boot partition (default)
+ * 0x1 : R/W boot partition 1
+ * 0x2 : R/W boot partition 2
+ * 0x3 : R/W Replay Protected Memory Block (RPMB)
+ *
+ * Returns 0 on success.
+ */
+int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
+{
+ int err;
+ struct mmc_cmd cmd;
+
+ /* Boot ack enable, boot partition enable , boot partition access */
+ cmd.cmdidx = MMC_CMD_SWITCH;
+ cmd.resp_type = MMC_RSP_R1b;
+
+ cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_PART_CONF << 16) |
+ ((EXT_CSD_BOOT_ACK(ack) |
+ EXT_CSD_BOOT_PART_NUM(part_num) |
+ EXT_CSD_PARTITION_ACCESS(access)) << 8);
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ if (access) {
+ debug("mmc boot partition#%d open fail:Error1 = %d\n",
+ part_num, err);
+ } else {
+ debug("mmc boot partition#%d close fail:Error = %d\n",
+ part_num, err);
+ }
+ return err;
+ }
+
+ if (access) {
+ /* 4bit transfer mode at booting time. */
+ cmd.cmdidx = MMC_CMD_SWITCH;
+ cmd.resp_type = MMC_RSP_R1b;
+
+ cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_BOOT_BUS_WIDTH << 16) |
+ ((1 << 0) << 8);
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err) {
+ debug("mmc boot partition#%d open fail:Error2 = %d\n",
+ part_num, err);
+ return err;
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8821704..bb81e84 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -83,6 +83,7 @@ COBJS-$(CONFIG_NAND_DOCG4) += docg4.o
else # minimal SPL drivers
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
+COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
COBJS-$(CONFIG_NAND_MXC) += mxc_nand_spl.o
endif # drivers
diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c
new file mode 100644
index 0000000..8537c4c
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc_spl.c
@@ -0,0 +1,258 @@
+/*
+ * NAND boot for Freescale Integrated Flash Controller, NAND FCM
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Author: Dipen Dudhat <dipen.dudhat@freescale.com>
+ *
+ * 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 <asm/io.h>
+#include <asm/fsl_ifc.h>
+#include <linux/mtd/nand.h>
+
+static inline int is_blank(uchar *addr, int page_size)
+{
+ int i;
+
+ for (i = 0; i < page_size; i++) {
+ if (__raw_readb(&addr[i]) != 0xff)
+ return 0;
+ }
+
+ /*
+ * For the SPL, don't worry about uncorrectable errors
+ * where the main area is all FFs but shouldn't be.
+ */
+ return 1;
+}
+
+/* returns nonzero if entire page is blank */
+static inline int check_read_ecc(uchar *buf, u32 *eccstat,
+ unsigned int bufnum, int page_size)
+{
+ u32 reg = eccstat[bufnum / 4];
+ int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf;
+
+ if (errors == 0xf) { /* uncorrectable */
+ /* Blank pages fail hw ECC checks */
+ if (is_blank(buf, page_size))
+ return 1;
+
+ puts("ecc error\n");
+ for (;;)
+ ;
+ }
+
+ return 0;
+}
+
+static inline void nand_wait(uchar *buf, int bufnum, int page_size)
+{
+ struct fsl_ifc *ifc = IFC_BASE_ADDR;
+ u32 status;
+ u32 eccstat[4];
+ int bufperpage = page_size / 512;
+ int bufnum_end, i;
+
+ bufnum *= bufperpage;
+ bufnum_end = bufnum + bufperpage - 1;
+
+ do {
+ status = in_be32(&ifc->ifc_nand.nand_evter_stat);
+ } while (!(status & IFC_NAND_EVTER_STAT_OPC));
+
+ if (status & IFC_NAND_EVTER_STAT_FTOER) {
+ puts("flash time out error\n");
+ for (;;)
+ ;
+ }
+
+ for (i = bufnum / 4; i <= bufnum_end / 4; i++)
+ eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+
+ for (i = bufnum; i <= bufnum_end; i++) {
+ if (check_read_ecc(buf, eccstat, i, page_size))
+ break;
+ }
+
+ out_be32(&ifc->ifc_nand.nand_evter_stat, status);
+}
+
+static inline int bad_block(uchar *marker, int port_size)
+{
+ if (port_size == 8)
+ return __raw_readb(marker) != 0xff;
+ else
+ return __raw_readw((u16 *)marker) != 0xffff;
+}
+
+static void nand_load(unsigned int offs, int uboot_size, uchar *dst)
+{
+ struct fsl_ifc *ifc = IFC_BASE_ADDR;
+ uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE;
+ int page_size;
+ int port_size;
+ int pages_per_blk;
+ int blk_size;
+ int bad_marker = 0;
+ int bufnum_mask, bufnum;
+
+ int csor, cspr;
+ int pos = 0;
+ int j = 0;
+
+ int sram_addr;
+ int pg_no;
+
+ /* Get NAND Flash configuration */
+ csor = CONFIG_SYS_NAND_CSOR;
+ cspr = CONFIG_SYS_NAND_CSPR;
+
+ port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8;
+
+ if (csor & CSOR_NAND_PGS_4K) {
+ page_size = 4096;
+ bufnum_mask = 0x1;
+ } else if (csor & CSOR_NAND_PGS_2K) {
+ page_size = 2048;
+ bufnum_mask = 0x3;
+ } else {
+ page_size = 512;
+ bufnum_mask = 0xf;
+
+ if (port_size == 8)
+ bad_marker = 5;
+ }
+
+ pages_per_blk =
+ 32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT);
+
+ blk_size = pages_per_blk * page_size;
+
+ /* Open Full SRAM mapping for spare are access */
+ out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+
+ /* Clear Boot events */
+ out_be32(&ifc->ifc_nand.nand_evter_stat, 0xffffffff);
+
+ /* Program FIR/FCR for Large/Small page */
+ if (page_size > 512) {
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+ (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP4_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+ } else {
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP3_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+ }
+
+ /* Program FBCR = 0 for full page read */
+ out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+
+ /* Read and copy u-boot on SDRAM from NAND device, In parallel
+ * check for Bad block if found skip it and read continue to
+ * next Block
+ */
+ while (pos < uboot_size) {
+ int i = 0;
+ do {
+ pg_no = offs / page_size;
+ bufnum = pg_no & bufnum_mask;
+ sram_addr = bufnum * page_size * 2;
+
+ out_be32(&ifc->ifc_nand.row0, pg_no);
+ out_be32(&ifc->ifc_nand.col0, 0);
+ /* start read */
+ out_be32(&ifc->ifc_nand.nandseq_strt,
+ IFC_NAND_SEQ_STRT_FIR_STRT);
+
+ /* wait for read to complete */
+ nand_wait(&buf[sram_addr], bufnum, page_size);
+
+ /*
+ * If either of the first two pages are marked bad,
+ * continue to the next block.
+ */
+ if (i++ < 2 &&
+ bad_block(&buf[sram_addr + page_size + bad_marker],
+ port_size)) {
+ puts("skipping\n");
+ offs = (offs + blk_size) & ~(blk_size - 1);
+ pos &= ~(blk_size - 1);
+ break;
+ }
+
+ for (j = 0; j < page_size; j++)
+ dst[pos + j] = __raw_readb(&buf[sram_addr + j]);
+
+ pos += page_size;
+ offs += page_size;
+ } while ((offs & (blk_size - 1)) && (pos < uboot_size));
+ }
+}
+
+/*
+ * Main entrypoint for NAND Boot. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-boot image
+ * from NAND into SDRAM and starts from there.
+ */
+void nand_boot(void)
+{
+ __attribute__((noreturn)) void (*uboot)(void);
+ /*
+ * Load U-Boot image from NAND into RAM
+ */
+ nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
+ (uchar *)CONFIG_SYS_NAND_U_BOOT_DST);
+
+#ifdef CONFIG_NAND_ENV_DST
+ nand_load(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
+ (uchar *)CONFIG_NAND_ENV_DST);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+ nand_load(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE,
+ (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE);
+#endif
+#endif
+ /*
+ * Jump to U-Boot image
+ */
+#ifdef CONFIG_SPL_FLUSH_IMAGE
+ /*
+ * Clean d-cache and invalidate i-cache, to
+ * make sure that no stale data is executed.
+ */
+ flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE);
+#endif
+ uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
+ uboot();
+}
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 90f8392..ecbb210 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -32,6 +32,7 @@ endif
COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o
COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o
COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o
+COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o
COBJS-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.o
COBJS-$(CONFIG_SPI_FLASH_SPANSION) += spansion.o
COBJS-$(CONFIG_SPI_FLASH_SST) += sst.o
diff --git a/drivers/mtd/spi/gigadevice.c b/drivers/mtd/spi/gigadevice.c
new file mode 100644
index 0000000..b5e1ebe
--- /dev/null
+++ b/drivers/mtd/spi/gigadevice.c
@@ -0,0 +1,81 @@
+/*
+ * Gigadevice SPI flash driver
+ * Copyright 2013, Samsung Electronics Co., Ltd.
+ * Author: Banajit Goswami <banajit.g@samsung.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 <malloc.h>
+#include <spi_flash.h>
+
+#include "spi_flash_internal.h"
+
+struct gigadevice_spi_flash_params {
+ uint16_t id;
+ uint16_t nr_blocks;
+ const char *name;
+};
+
+static const struct gigadevice_spi_flash_params gigadevice_spi_flash_table[] = {
+ {
+ .id = 0x6016,
+ .nr_blocks = 64,
+ .name = "GD25LQ",
+ },
+ {
+ .id = 0x4017,
+ .nr_blocks = 128,
+ .name = "GD25Q64B",
+ },
+};
+
+struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode)
+{
+ const struct gigadevice_spi_flash_params *params;
+ struct spi_flash *flash;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gigadevice_spi_flash_table); i++) {
+ params = &gigadevice_spi_flash_table[i];
+ if (params->id == ((idcode[1] << 8) | idcode[2]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(gigadevice_spi_flash_table)) {
+ debug("SF: Unsupported Gigadevice ID %02x%02x\n",
+ idcode[1], idcode[2]);
+ return NULL;
+ }
+
+ flash = spi_flash_alloc_base(spi, params->name);
+ if (!flash) {
+ debug("SF: Failed to allocate memory\n");
+ return NULL;
+ }
+ /* page_size */
+ flash->page_size = 256;
+ /* sector_size = page_size * pages_per_sector */
+ flash->sector_size = flash->page_size * 16;
+ /* size = sector_size * sector_per_block * number of blocks */
+ flash->size = flash->sector_size * 16 * params->nr_blocks;
+
+ return flash;
+}
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index a468208..6a6fe37 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -458,6 +458,9 @@ static const struct {
#ifdef CONFIG_SPI_FLASH_EON
{ 0, 0x1c, spi_flash_probe_eon, },
#endif
+#ifdef CONFIG_SPI_FLASH_GIGADEVICE
+ { 0, 0xc8, spi_flash_probe_gigadevice, },
+#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX
{ 0, 0xc2, spi_flash_probe_macronix, },
#endif
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
index be3c768..af1afa9 100644
--- a/drivers/mtd/spi/spi_flash_internal.h
+++ b/drivers/mtd/spi/spi_flash_internal.h
@@ -137,3 +137,4 @@ struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode);
struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode);
struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode);
struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode);
+struct spi_flash *spi_flash_probe_gigadevice(struct spi_slave *spi, u8 *idcode);
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index 77ac1f7..621c899 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -211,7 +211,7 @@ static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
return 1;
}
-#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
static void fsl_pcie_boot_master(pit_t *pi)
{
/* configure inbound window for slave's u-boot image */
@@ -388,7 +388,7 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
/* see if we are a PCIe or PCI controller */
pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
-#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
/* boot from PCIE --master */
char *s = getenv("bootmaster");
char pcie[6];
@@ -624,7 +624,7 @@ int fsl_pci_init_port(struct fsl_pci_info *pci_info,
if (fsl_is_pci_agent(hose)) {
fsl_pci_config_unlock(hose);
hose->last_busno = hose->first_busno;
-#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
} else {
/* boot from PCIE --master releases slave's core 0 */
char *s = getenv("bootmaster");
diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c
index d4b3e65..9a093a5 100644
--- a/drivers/power/exynos-tmu.c
+++ b/drivers/power/exynos-tmu.c
@@ -50,15 +50,15 @@
/* Tmeperature threshold values for various thermal events */
struct temperature_params {
/* minimum value in temperature code range */
- unsigned int min_val;
+ unsigned min_val;
/* maximum value in temperature code range */
- unsigned int max_val;
+ unsigned max_val;
/* temperature threshold to start warning */
- unsigned int start_warning;
+ unsigned start_warning;
/* temperature threshold CPU tripping */
- unsigned int start_tripping;
+ unsigned start_tripping;
/* temperature threshold for HW tripping */
- unsigned int hardware_tripping;
+ unsigned hardware_tripping;
};
/* Pre-defined values and thresholds for calibration of current temperature */
@@ -66,25 +66,27 @@ struct tmu_data {
/* pre-defined temperature thresholds */
struct temperature_params ts;
/* pre-defined efuse range minimum value */
- unsigned int efuse_min_value;
+ unsigned efuse_min_value;
/* pre-defined efuse value for temperature calibration */
- unsigned int efuse_value;
+ unsigned efuse_value;
/* pre-defined efuse range maximum value */
- unsigned int efuse_max_value;
+ unsigned efuse_max_value;
/* current temperature sensing slope */
- unsigned int slope;
+ unsigned slope;
};
/* TMU device specific details and status */
struct tmu_info {
/* base Address for the TMU */
- unsigned tmu_base;
+ struct exynos5_tmu_reg *tmu_base;
+ /* mux Address for the TMU */
+ int tmu_mux;
/* pre-defined values for calibration and thresholds */
struct tmu_data data;
/* value required for triminfo_25 calibration */
- unsigned int te1;
+ unsigned te1;
/* value required for triminfo_85 calibration */
- unsigned int te2;
+ unsigned te2;
/* Value for measured data calibration */
int dc_value;
/* enum value indicating status of the TMU */
@@ -103,17 +105,24 @@ static struct tmu_info gbl_info;
*/
static int get_cur_temp(struct tmu_info *info)
{
- int cur_temp;
- struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base;
+ struct exynos5_tmu_reg *reg = info->tmu_base;
+ ulong start;
+ int cur_temp = 0;
/*
* Temperature code range between min 25 and max 125.
* May run more than once for first call as initial sensing
* has not yet happened.
*/
- do {
- cur_temp = readl(&reg->current_temp) & 0xff;
- } while (cur_temp == 0 && info->tmu_state == TMU_STATUS_NORMAL);
+ if (info->tmu_state == TMU_STATUS_NORMAL) {
+ start = get_timer(0);
+ do {
+ cur_temp = readl(&reg->current_temp) & 0xff;
+ } while ((cur_temp == 0) || (get_timer(start) > 100));
+ }
+
+ if (cur_temp == 0)
+ return cur_temp;
/* Calibrate current temperature */
cur_temp = cur_temp - info->te1 + info->dc_value;
@@ -137,23 +146,29 @@ enum tmu_status_t tmu_monitor(int *temp)
/* Read current temperature of the SOC */
cur_temp = get_cur_temp(&gbl_info);
+
+ if (!cur_temp)
+ goto out;
+
*temp = cur_temp;
/* Temperature code lies between min 25 and max 125 */
- if (cur_temp >= data->ts.start_tripping &&
- cur_temp <= data->ts.max_val) {
+ if ((cur_temp >= data->ts.start_tripping) &&
+ (cur_temp <= data->ts.max_val))
return TMU_STATUS_TRIPPED;
- } else if (cur_temp >= data->ts.start_warning) {
+
+ if (cur_temp >= data->ts.start_warning)
return TMU_STATUS_WARNING;
- } else if (cur_temp < data->ts.start_warning &&
- cur_temp >= data->ts.min_val) {
+
+ if ((cur_temp < data->ts.start_warning) &&
+ (cur_temp >= data->ts.min_val))
return TMU_STATUS_NORMAL;
- } else {
- /* Temperature code does not lie between min 25 and max 125 */
- gbl_info.tmu_state = TMU_STATUS_INIT;
- debug("EXYNOS_TMU: Thermal reading failed\n");
- return TMU_STATUS_INIT;
- }
+
+ out:
+ /* Temperature code does not lie between min 25 and max 125 */
+ gbl_info.tmu_state = TMU_STATUS_INIT;
+ debug("EXYNOS_TMU: Thermal reading failed\n");
+ return TMU_STATUS_INIT;
}
/*
@@ -166,6 +181,7 @@ enum tmu_status_t tmu_monitor(int *temp)
static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
{
#ifdef CONFIG_OF_CONTROL
+ fdt_addr_t addr;
int node;
int error = 0;
@@ -183,46 +199,58 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
* miscalculation of register values in tmu_setup_parameters
* may result in misleading current temperature.
*/
- info->tmu_base = fdtdec_get_addr(blob, node, "reg");
- if (info->tmu_base == FDT_ADDR_T_NONE) {
+ addr = fdtdec_get_addr(blob, node, "reg");
+ if (addr == FDT_ADDR_T_NONE) {
debug("%s: Missing tmu-base\n", __func__);
return -1;
}
+ info->tmu_base = (struct exynos5_tmu_reg *)addr;
+
+ /* Optional field. */
+ info->tmu_mux = fdtdec_get_int(blob,
+ node, "samsung,mux", -1);
+ /* Take default value as per the user manual b(110) */
+ if (info->tmu_mux == -1)
+ info->tmu_mux = 0x6;
+
info->data.ts.min_val = fdtdec_get_int(blob,
node, "samsung,min-temp", -1);
- error |= info->data.ts.min_val;
+ error |= (info->data.ts.min_val == -1);
info->data.ts.max_val = fdtdec_get_int(blob,
node, "samsung,max-temp", -1);
- error |= info->data.ts.max_val;
+ error |= (info->data.ts.max_val == -1);
info->data.ts.start_warning = fdtdec_get_int(blob,
node, "samsung,start-warning", -1);
- error |= info->data.ts.start_warning;
+ error |= (info->data.ts.start_warning == -1);
info->data.ts.start_tripping = fdtdec_get_int(blob,
node, "samsung,start-tripping", -1);
- error |= info->data.ts.start_tripping;
+ error |= (info->data.ts.start_tripping == -1);
info->data.ts.hardware_tripping = fdtdec_get_int(blob,
node, "samsung,hw-tripping", -1);
- error |= info->data.ts.hardware_tripping;
+ error |= (info->data.ts.hardware_tripping == -1);
info->data.efuse_min_value = fdtdec_get_int(blob,
node, "samsung,efuse-min-value", -1);
- error |= info->data.efuse_min_value;
+ error |= (info->data.efuse_min_value == -1);
info->data.efuse_value = fdtdec_get_int(blob,
node, "samsung,efuse-value", -1);
- error |= info->data.efuse_value;
+ error |= (info->data.efuse_value == -1);
info->data.efuse_max_value = fdtdec_get_int(blob,
node, "samsung,efuse-max-value", -1);
- error |= info->data.efuse_max_value;
+ error |= (info->data.efuse_max_value == -1);
info->data.slope = fdtdec_get_int(blob,
node, "samsung,slope", -1);
- error |= info->data.slope;
+ error |= (info->data.slope == -1);
info->dc_value = fdtdec_get_int(blob,
node, "samsung,dc-value", -1);
- error |= info->dc_value;
+ error |= (info->dc_value == -1);
- if (error == -1) {
+ if (error) {
debug("fail to get tmu node properties\n");
return -1;
}
+#else
+ /* Non DT support may never be added. Just in case */
+ return -1;
#endif
return 0;
@@ -236,12 +264,12 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob)
*/
static void tmu_setup_parameters(struct tmu_info *info)
{
- unsigned int te_code, con;
- unsigned int warning_code, trip_code, hwtrip_code;
- unsigned int cooling_temp;
- unsigned int rising_value;
+ unsigned te_code, con;
+ unsigned warning_code, trip_code, hwtrip_code;
+ unsigned cooling_temp;
+ unsigned rising_value;
struct tmu_data *data = &info->data;
- struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base;
+ struct exynos5_tmu_reg *reg = info->tmu_base;
/* Must reload for reading efuse value from triminfo register */
writel(TRIMINFO_RELOAD, &reg->triminfo_control);
@@ -288,7 +316,7 @@ static void tmu_setup_parameters(struct tmu_info *info)
/* TMU core enable */
con = readl(&reg->tmu_control);
- con |= THERM_TRIP_EN | CORE_EN;
+ con |= THERM_TRIP_EN | CORE_EN | (info->tmu_mux << 20);
writel(con, &reg->tmu_control);
@@ -314,6 +342,5 @@ int tmu_init(const void *blob)
tmu_setup_parameters(&gbl_info);
gbl_info.tmu_state = TMU_STATUS_NORMAL;
ret:
-
return gbl_info.tmu_state;
}
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 3c41242..e65125c 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -30,6 +30,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#define RX_FIFO_COUNT_MASK 0xff
+#define RX_FIFO_FULL_MASK (1 << 8)
+#define TX_FIFO_FULL_MASK (1 << 24)
+
static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
{
u32 offset = dev_index * sizeof(struct s5p_uart);
@@ -87,8 +91,8 @@ int serial_init_dev(const int dev_index)
{
struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
- /* reset and enable FIFOs, set triggers to the maximum */
- writel(0, &uart->ufcon);
+ /* enable FIFOs */
+ writel(0x1, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
@@ -130,7 +134,8 @@ int serial_getc_dev(const int dev_index)
struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
/* wait for character to arrive */
- while (!(readl(&uart->utrstat) & 0x1)) {
+ while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
+ RX_FIFO_FULL_MASK))) {
if (serial_err_check(dev_index, 0))
return 0;
}
@@ -146,7 +151,7 @@ void serial_putc_dev(const char c, const int dev_index)
struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
/* wait for room in the tx FIFO */
- while (!(readl(&uart->utrstat) & 0x2)) {
+ while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
if (serial_err_check(dev_index, 1))
return;
}
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index ed0823b..c3606d5 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -319,10 +319,10 @@ void lcd_ctrl_init(void *lcdbase)
#ifdef CONFIG_OF_CONTROL
if (exynos_fimd_parse_dt(gd->fdt_blob))
debug("Can't get proper panel info\n");
-#endif
+#else
/* initialize parameters which is specific to panel. */
init_panel_info(&panel_info);
-
+#endif
panel_width = panel_info.vl_width;
panel_height = panel_info.vl_height;