summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/soft_i2c.c1
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/arm_pl180_mmci.c443
-rw-r--r--drivers/mmc/arm_pl180_mmci.h183
-rw-r--r--drivers/mmc/bfin_sdh.c2
-rw-r--r--drivers/mmc/davinci_mmc.c3
-rw-r--r--drivers/mmc/fsl_esdhc.c4
-rw-r--r--drivers/mmc/gen_atmel_mci.c2
-rw-r--r--drivers/mmc/mmc.c8
-rw-r--r--drivers/mmc/mxcmmc.c2
-rw-r--r--drivers/mmc/omap_hsmmc.c10
-rw-r--r--drivers/mmc/s5p_mmc.c1
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/oc_tiny_spi.c248
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/cfb_console.c19
-rw-r--r--drivers/video/fsl_diu_fb.c530
-rw-r--r--drivers/video/videomodes.c64
-rw-r--r--drivers/video/videomodes.h3
19 files changed, 1211 insertions, 316 deletions
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 69b5f42205..9b02e89e03 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -286,6 +286,7 @@ int i2c_set_bus_num(unsigned int bus)
int ret;
ret = i2x_mux_select_mux(bus);
+ i2c_init_board();
if (ret == 0)
i2c_bus_num = bus;
else
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 9aca3a2bd6..a8fe17a6f7 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -32,6 +32,7 @@ COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
+COBJS-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
new file mode 100644
index 0000000000..ed296ee026
--- /dev/null
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -0,0 +1,443 @@
+/*
+ * ARM PrimeCell MultiMedia Card Interface - PL180
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com>
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
+ *
+ * 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
+ */
+
+/* #define DEBUG */
+
+#include <asm/io.h>
+#include "common.h"
+#include <errno.h>
+#include <mmc.h>
+#include "arm_pl180_mmci.h"
+#include <malloc.h>
+
+struct mmc_host {
+ struct sdi_registers *base;
+};
+
+static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
+{
+ u32 hoststatus, statusmask;
+ struct mmc_host *host = dev->priv;
+
+ statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
+ if ((cmd->resp_type & MMC_RSP_PRESENT))
+ statusmask |= SDI_STA_CMDREND;
+ else
+ statusmask |= SDI_STA_CMDSENT;
+
+ do
+ hoststatus = readl(&host->base->status) & statusmask;
+ while (!hoststatus);
+
+ writel(statusmask, &host->base->status_clear);
+ if (hoststatus & SDI_STA_CTIMEOUT) {
+ printf("CMD%d time out\n", cmd->cmdidx);
+ return -ETIMEDOUT;
+ } else if ((hoststatus & SDI_STA_CCRCFAIL) &&
+ (cmd->flags & MMC_RSP_CRC)) {
+ printf("CMD%d CRC error\n", cmd->cmdidx);
+ return -EILSEQ;
+ }
+
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ cmd->response[0] = readl(&host->base->response0);
+ cmd->response[1] = readl(&host->base->response1);
+ cmd->response[2] = readl(&host->base->response2);
+ cmd->response[3] = readl(&host->base->response3);
+ debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
+ "response[2]:0x%08X, response[3]:0x%08X\n",
+ cmd->cmdidx, cmd->response[0], cmd->response[1],
+ cmd->response[2], cmd->response[3]);
+ }
+
+ return 0;
+}
+
+/* send command to the mmc card and wait for results */
+static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
+{
+ int result;
+ u32 sdi_cmd = 0;
+ struct mmc_host *host = dev->priv;
+
+ sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
+
+ if (cmd->resp_type) {
+ sdi_cmd |= SDI_CMD_WAITRESP;
+ if (cmd->resp_type & MMC_RSP_136)
+ sdi_cmd |= SDI_CMD_LONGRESP;
+ }
+
+ writel((u32)cmd->cmdarg, &host->base->argument);
+ udelay(COMMAND_REG_DELAY);
+ writel(sdi_cmd, &host->base->command);
+ result = wait_for_command_end(dev, cmd);
+
+ /* After CMD2 set RCA to a none zero value. */
+ if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
+ dev->rca = 10;
+
+ /* After CMD3 open drain is switched off and push pull is used. */
+ if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
+ u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
+ writel(sdi_pwr, &host->base->power);
+ }
+
+ return result;
+}
+
+static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
+{
+ u32 *tempbuff = dest;
+ int i;
+ u64 xfercount = blkcount * blksize;
+ struct mmc_host *host = dev->priv;
+ u32 status, status_err;
+
+ debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
+
+ status = readl(&host->base->status);
+ status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
+ SDI_STA_RXOVERR);
+ while (!status_err &&
+ (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32))) {
+ if (status & SDI_STA_RXFIFOBR) {
+ for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
+ *(tempbuff + i) = readl(&host->base->fifo);
+ tempbuff += SDI_FIFO_BURST_SIZE;
+ xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
+ }
+ status = readl(&host->base->status);
+ status_err = status &
+ (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_RXOVERR);
+ }
+
+ if (status & SDI_STA_DTIMEOUT) {
+ printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
+ xfercount, status);
+ return -ETIMEDOUT;
+ } else if (status & SDI_STA_DCRCFAIL) {
+ printf("Read data blk CRC error: 0x%x\n", status);
+ return -EILSEQ;
+ } else if (status & SDI_STA_RXOVERR) {
+ printf("Read data RX overflow error\n");
+ return -EIO;
+ }
+
+ while ((!status_err) && (xfercount >= sizeof(u32))) {
+ if (status & SDI_STA_RXDAVL) {
+ *(tempbuff) = readl(&host->base->fifo);
+ tempbuff++;
+ xfercount -= sizeof(u32);
+ }
+ status = readl(&host->base->status);
+ status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
+ SDI_STA_RXOVERR);
+ }
+
+ status_err = status &
+ (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
+ SDI_STA_RXOVERR);
+ while (!status_err) {
+ status = readl(&host->base->status);
+ status_err = status &
+ (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
+ SDI_STA_RXOVERR);
+ }
+
+ if (status & SDI_STA_DTIMEOUT) {
+ printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
+ xfercount, status);
+ return -ETIMEDOUT;
+ } else if (status & SDI_STA_DCRCFAIL) {
+ printf("Read data bytes CRC error: 0x%x\n", status);
+ return -EILSEQ;
+ } else if (status & SDI_STA_RXOVERR) {
+ printf("Read data RX overflow error\n");
+ return -EIO;
+ }
+
+ writel(SDI_ICR_MASK, &host->base->status_clear);
+
+ if (xfercount) {
+ printf("Read data error, xfercount: %llu\n", xfercount);
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
+{
+ u32 *tempbuff = src;
+ int i;
+ u64 xfercount = blkcount * blksize;
+ struct mmc_host *host = dev->priv;
+ u32 status, status_err;
+
+ debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
+
+ status = readl(&host->base->status);
+ status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
+ while (!status_err && xfercount) {
+ if (status & SDI_STA_TXFIFOBW) {
+ if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
+ for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
+ writel(*(tempbuff + i),
+ &host->base->fifo);
+ tempbuff += SDI_FIFO_BURST_SIZE;
+ xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
+ } else {
+ while (xfercount >= sizeof(u32)) {
+ writel(*(tempbuff), &host->base->fifo);
+ tempbuff++;
+ xfercount -= sizeof(u32);
+ }
+ }
+ }
+ status = readl(&host->base->status);
+ status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
+ }
+
+ status_err = status &
+ (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
+ while (!status_err) {
+ status = readl(&host->base->status);
+ status_err = status &
+ (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
+ }
+
+ if (status & SDI_STA_DTIMEOUT) {
+ printf("Write data timed out, xfercount:%llu,status:0x%08X\n",
+ xfercount, status);
+ return -ETIMEDOUT;
+ } else if (status & SDI_STA_DCRCFAIL) {
+ printf("Write data CRC error\n");
+ return -EILSEQ;
+ }
+
+ writel(SDI_ICR_MASK, &host->base->status_clear);
+
+ if (xfercount) {
+ printf("Write data error, xfercount:%llu", xfercount);
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+static int do_data_transfer(struct mmc *dev,
+ struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int error = -ETIMEDOUT;
+ struct mmc_host *host = dev->priv;
+ u32 blksz = 0;
+ u32 data_ctrl = 0;
+ u32 data_len = (u32) (data->blocks * data->blocksize);
+
+ blksz = (ffs(data->blocksize) - 1);
+ data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
+ data_ctrl |= SDI_DCTRL_DTEN;
+
+ writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
+ writel(data_len, &host->base->datalength);
+ udelay(DATA_REG_DELAY);
+
+ if (data->flags & MMC_DATA_READ) {
+ data_ctrl |= SDI_DCTRL_DTDIR_IN;
+ writel(data_ctrl, &host->base->datactrl);
+
+ error = do_command(dev, cmd);
+ if (error)
+ return error;
+
+ error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks,
+ (u32)data->blocksize);
+ } else if (data->flags & MMC_DATA_WRITE) {
+ error = do_command(dev, cmd);
+ if (error)
+ return error;
+
+ writel(data_ctrl, &host->base->datactrl);
+ error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
+ (u32)data->blocksize);
+ }
+
+ return error;
+}
+
+static int host_request(struct mmc *dev,
+ struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int result;
+
+ if (data)
+ result = do_data_transfer(dev, cmd, data);
+ else
+ result = do_command(dev, cmd);
+
+ return result;
+}
+
+/* MMC uses open drain drivers in the enumeration phase */
+static int mmc_host_reset(struct mmc *dev)
+{
+ struct mmc_host *host = dev->priv;
+ u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
+
+ writel(sdi_u32, &host->base->power);
+
+ return 0;
+}
+
+static void host_set_ios(struct mmc *dev)
+{
+ struct mmc_host *host = dev->priv;
+ u32 sdi_clkcr;
+
+ sdi_clkcr = readl(&host->base->clock);
+
+ /* Ramp up the clock rate */
+ if (dev->clock) {
+ u32 clkdiv = 0;
+
+ if (dev->clock >= dev->f_max)
+ dev->clock = dev->f_max;
+
+ clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1;
+
+ if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
+ clkdiv = SDI_CLKCR_CLKDIV_MASK;
+
+ sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
+ sdi_clkcr |= clkdiv;
+ }
+
+ /* Set the bus width */
+ if (dev->bus_width) {
+ u32 buswidth = 0;
+
+ switch (dev->bus_width) {
+ case 1:
+ buswidth |= SDI_CLKCR_WIDBUS_1;
+ break;
+ case 4:
+ buswidth |= SDI_CLKCR_WIDBUS_4;
+ break;
+ default:
+ printf("Invalid bus width\n");
+ break;
+ }
+ sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
+ sdi_clkcr |= buswidth;
+ }
+
+ writel(sdi_clkcr, &host->base->clock);
+ udelay(CLK_CHANGE_DELAY);
+}
+
+struct mmc *alloc_mmc_struct(void)
+{
+ struct mmc_host *host = NULL;
+ struct mmc *mmc_device = NULL;
+
+ host = malloc(sizeof(struct mmc_host));
+ if (!host)
+ return NULL;
+
+ mmc_device = malloc(sizeof(struct mmc));
+ if (!mmc_device)
+ goto err;
+
+ mmc_device->priv = host;
+ return mmc_device;
+
+err:
+ free(host);
+ return NULL;
+}
+
+/*
+ * mmc_host_init - initialize the mmc controller.
+ * Set initial clock and power for mmc slot.
+ * Initialize mmc struct and register with mmc framework.
+ */
+static int arm_pl180_mmci_host_init(struct mmc *dev)
+{
+ struct mmc_host *host = dev->priv;
+ u32 sdi_u32;
+
+ host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE;
+
+ /* Initially set power-on, full voltage & MMCI read */
+ sdi_u32 = INIT_PWR;
+ writel(sdi_u32, &host->base->power);
+
+ /* setting clk freq 505KHz */
+ sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN;
+ writel(sdi_u32, &host->base->clock);
+ udelay(CLK_CHANGE_DELAY);
+
+ /* Disable mmc interrupts */
+ sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
+ writel(sdi_u32, &host->base->mask0);
+
+ sprintf(dev->name, "MMC");
+ dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1));
+ dev->send_cmd = host_request;
+ dev->set_ios = host_set_ios;
+ dev->init = mmc_host_reset;
+ dev->host_caps = 0;
+ dev->voltages = VOLTAGE_WINDOW_MMC;
+ dev->f_min = dev->clock;
+ dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ;
+
+ return 0;
+}
+
+int arm_pl180_mmci_init(void)
+{
+ int error;
+ struct mmc *dev;
+
+ dev = alloc_mmc_struct();
+ if (!dev)
+ return -1;
+
+ error = arm_pl180_mmci_host_init(dev);
+ if (error) {
+ printf("mmci_host_init error - %d\n", error);
+ return -1;
+ }
+
+ dev->b_max = 0;
+
+ mmc_register(dev);
+ debug("registered mmc interface number is:%d\n", dev->block_dev.dev);
+
+ return 0;
+}
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
new file mode 100644
index 0000000000..42fbe3e386
--- /dev/null
+++ b/drivers/mmc/arm_pl180_mmci.h
@@ -0,0 +1,183 @@
+/*
+ * ARM PrimeCell MultiMedia Card Interface - PL180
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com>
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
+ *
+ * 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
+ */
+
+#ifndef __ARM_PL180_MMCI_H__
+#define __ARM_PL180_MMCI_H__
+
+int arm_pl180_mmci_init(void);
+
+#define COMMAND_REG_DELAY 300
+#define DATA_REG_DELAY 1000
+#define CLK_CHANGE_DELAY 2000
+
+#define INIT_PWR 0xBF /* Power on, full power, not open drain */
+#define ARM_MCLK (100*1000*1000)
+
+/* SDI Power Control register bits */
+#define SDI_PWR_PWRCTRL_MASK 0x00000003
+#define SDI_PWR_PWRCTRL_ON 0x00000003
+#define SDI_PWR_PWRCTRL_OFF 0x00000000
+#define SDI_PWR_DAT2DIREN 0x00000004
+#define SDI_PWR_CMDDIREN 0x00000008
+#define SDI_PWR_DAT0DIREN 0x00000010
+#define SDI_PWR_DAT31DIREN 0x00000020
+#define SDI_PWR_OPD 0x00000040
+#define SDI_PWR_FBCLKEN 0x00000080
+#define SDI_PWR_DAT74DIREN 0x00000100
+#define SDI_PWR_RSTEN 0x00000200
+
+#define VOLTAGE_WINDOW_MMC 0x00FF8080
+#define VOLTAGE_WINDOW_SD 0x80010000
+
+/* SDI clock control register bits */
+#define SDI_CLKCR_CLKDIV_MASK 0x000000FF
+#define SDI_CLKCR_CLKEN 0x00000100
+#define SDI_CLKCR_PWRSAV 0x00000200
+#define SDI_CLKCR_BYPASS 0x00000400
+#define SDI_CLKCR_WIDBUS_MASK 0x00001800
+#define SDI_CLKCR_WIDBUS_1 0x00000000
+#define SDI_CLKCR_WIDBUS_4 0x00000800
+
+#define SDI_CLKCR_CLKDIV_INIT 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */
+
+/* SDI command register bits */
+#define SDI_CMD_CMDINDEX_MASK 0x000000FF
+#define SDI_CMD_WAITRESP 0x00000040
+#define SDI_CMD_LONGRESP 0x00000080
+#define SDI_CMD_WAITINT 0x00000100
+#define SDI_CMD_WAITPEND 0x00000200
+#define SDI_CMD_CPSMEN 0x00000400
+#define SDI_CMD_SDIOSUSPEND 0x00000800
+#define SDI_CMD_ENDCMDCOMPL 0x00001000
+#define SDI_CMD_NIEN 0x00002000
+#define SDI_CMD_CE_ATACMD 0x00004000
+#define SDI_CMD_CBOOTMODEEN 0x00008000
+
+#define SDI_DTIMER_DEFAULT 0xFFFF0000
+
+/* SDI Status register bits */
+#define SDI_STA_CCRCFAIL 0x00000001
+#define SDI_STA_DCRCFAIL 0x00000002
+#define SDI_STA_CTIMEOUT 0x00000004
+#define SDI_STA_DTIMEOUT 0x00000008
+#define SDI_STA_TXUNDERR 0x00000010
+#define SDI_STA_RXOVERR 0x00000020
+#define SDI_STA_CMDREND 0x00000040
+#define SDI_STA_CMDSENT 0x00000080
+#define SDI_STA_DATAEND 0x00000100
+#define SDI_STA_STBITERR 0x00000200
+#define SDI_STA_DBCKEND 0x00000400
+#define SDI_STA_CMDACT 0x00000800
+#define SDI_STA_TXACT 0x00001000
+#define SDI_STA_RXACT 0x00002000
+#define SDI_STA_TXFIFOBW 0x00004000
+#define SDI_STA_RXFIFOBR 0x00008000
+#define SDI_STA_TXFIFOF 0x00010000
+#define SDI_STA_RXFIFOF 0x00020000
+#define SDI_STA_TXFIFOE 0x00040000
+#define SDI_STA_RXFIFOE 0x00080000
+#define SDI_STA_TXDAVL 0x00100000
+#define SDI_STA_RXDAVL 0x00200000
+#define SDI_STA_SDIOIT 0x00400000
+#define SDI_STA_CEATAEND 0x00800000
+#define SDI_STA_CARDBUSY 0x01000000
+#define SDI_STA_BOOTMODE 0x02000000
+#define SDI_STA_BOOTACKERR 0x04000000
+#define SDI_STA_BOOTACKTIMEOUT 0x08000000
+#define SDI_STA_RSTNEND 0x10000000
+
+/* SDI Interrupt Clear register bits */
+#define SDI_ICR_MASK 0x1DC007FF
+#define SDI_ICR_CCRCFAILC 0x00000001
+#define SDI_ICR_DCRCFAILC 0x00000002
+#define SDI_ICR_CTIMEOUTC 0x00000004
+#define SDI_ICR_DTIMEOUTC 0x00000008
+#define SDI_ICR_TXUNDERRC 0x00000010
+#define SDI_ICR_RXOVERRC 0x00000020
+#define SDI_ICR_CMDRENDC 0x00000040
+#define SDI_ICR_CMDSENTC 0x00000080
+#define SDI_ICR_DATAENDC 0x00000100
+#define SDI_ICR_STBITERRC 0x00000200
+#define SDI_ICR_DBCKENDC 0x00000400
+#define SDI_ICR_SDIOITC 0x00400000
+#define SDI_ICR_CEATAENDC 0x00800000
+#define SDI_ICR_BUSYENDC 0x01000000
+#define SDI_ICR_BOOTACKERRC 0x04000000
+#define SDI_ICR_BOOTACKTIMEOUTC 0x08000000
+#define SDI_ICR_RSTNENDC 0x10000000
+
+#define SDI_MASK0_MASK 0x1FFFFFFF
+
+/* SDI Data control register bits */
+#define SDI_DCTRL_DTEN 0x00000001
+#define SDI_DCTRL_DTDIR_IN 0x00000002
+#define SDI_DCTRL_DTMODE_STREAM 0x00000004
+#define SDI_DCTRL_DMAEN 0x00000008
+#define SDI_DCTRL_DBLKSIZE_MASK 0x000000F0
+#define SDI_DCTRL_RWSTART 0x00000100
+#define SDI_DCTRL_RWSTOP 0x00000200
+#define SDI_DCTRL_RWMOD 0x00000200
+#define SDI_DCTRL_SDIOEN 0x00000800
+#define SDI_DCTRL_DMAREQCTL 0x00001000
+#define SDI_DCTRL_DBOOTMODEEN 0x00002000
+#define SDI_DCTRL_BUSYMODE 0x00004000
+#define SDI_DCTRL_DDR_MODE 0x00008000
+
+#define SDI_FIFO_BURST_SIZE 8
+
+struct sdi_registers {
+ u32 power; /* 0x00*/
+ u32 clock; /* 0x04*/
+ u32 argument; /* 0x08*/
+ u32 command; /* 0x0c*/
+ u32 respcommand; /* 0x10*/
+ u32 response0; /* 0x14*/
+ u32 response1; /* 0x18*/
+ u32 response2; /* 0x1c*/
+ u32 response3; /* 0x20*/
+ u32 datatimer; /* 0x24*/
+ u32 datalength; /* 0x28*/
+ u32 datactrl; /* 0x2c*/
+ u32 datacount; /* 0x30*/
+ u32 status; /* 0x34*/
+ u32 status_clear; /* 0x38*/
+ u32 mask0; /* 0x3c*/
+ u32 mask1; /* 0x40*/
+ u32 card_select; /* 0x44*/
+ u32 fifo_count; /* 0x48*/
+ u32 padding1[(0x80-0x4C)>>2];
+ u32 fifo; /* 0x80*/
+ u32 padding2[(0xFE0-0x84)>>2];
+ u32 periph_id0; /* 0xFE0 mmc Peripheral Identifcation Register*/
+ u32 periph_id1; /* 0xFE4*/
+ u32 periph_id2; /* 0xFE8*/
+ u32 periph_id3; /* 0xFEC*/
+ u32 pcell_id0; /* 0xFF0*/
+ u32 pcell_id1; /* 0xFF4*/
+ u32 pcell_id2; /* 0xFF8*/
+ u32 pcell_id3; /* 0xFFC*/
+};
+
+#endif
diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c
index 31b6459373..bc9057fa9a 100644
--- a/drivers/mmc/bfin_sdh.c
+++ b/drivers/mmc/bfin_sdh.c
@@ -257,6 +257,8 @@ int bfin_mmc_init(bd_t *bis)
mmc->f_min = mmc->f_max >> 9;
mmc->block_dev.part_type = PART_TYPE_DOS;
+ mmc->b_max = 0;
+
mmc_register(mmc);
return 0;
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index d5d19ebee3..5d918e6ffc 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -394,9 +394,8 @@ int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)
mmc->voltages = host->voltages;
mmc->host_caps = host->host_caps;
-#ifdef CONFIG_MMC_MBLOCK
mmc->b_max = DAVINCI_MAX_BLOCKS;
-#endif
+
mmc_register(mmc);
return 0;
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 2838795feb..d2355be6b0 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -99,6 +99,10 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
else if (cmd->resp_type & MMC_RSP_PRESENT)
xfertyp |= XFERTYP_RSPTYP_48;
+#ifdef CONFIG_MX53
+ if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+ xfertyp |= XFERTYP_CMDTYP_ABORT;
+#endif
return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
}
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index 2984d645c9..6577925b8e 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -348,6 +348,8 @@ int atmel_mci_init(void *regs)
mmc->f_min = get_mci_clk_rate() / (2*256);
mmc->f_max = get_mci_clk_rate() / (2*1);
+ mmc->b_max = 0;
+
mmc_register(mmc);
return 0;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index f27b7c79e5..f6d31f5848 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -243,8 +243,7 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
return 0;
do {
- cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
- CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
+ cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
if(mmc_write_blocks(mmc, start, cur, src) != cur)
return 0;
blocks_todo -= cur;
@@ -320,8 +319,7 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
return 0;
do {
- cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
- CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
+ cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
if(mmc_read_blocks(mmc, dst, start, cur) != cur)
return 0;
blocks_todo -= cur;
@@ -1029,6 +1027,8 @@ int mmc_register(struct mmc *mmc)
mmc->block_dev.removable = 1;
mmc->block_dev.block_read = mmc_bread;
mmc->block_dev.block_write = mmc_bwrite;
+ if (!mmc->b_max)
+ mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
INIT_LIST_HEAD (&mmc->link);
diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c
index 59639539f3..ab1fc82fbb 100644
--- a/drivers/mmc/mxcmmc.c
+++ b/drivers/mmc/mxcmmc.c
@@ -511,6 +511,8 @@ static int mxcmci_initialize(bd_t *bis)
mmc->f_min = imx_get_perclk2() >> 7;
mmc->f_max = imx_get_perclk2() >> 1;
+ mmc->b_max = 0;
+
mmc_register(mmc);
return 0;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 6f2280abff..957b9877a0 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -465,6 +465,16 @@ int omap_mmc_init(int dev_index)
mmc->f_min = 400000;
mmc->f_max = 52000000;
+ mmc->b_max = 0;
+
+#if defined(CONFIG_OMAP34XX)
+ /*
+ * Silicon revs 2.1 and older do not support multiblock transfers.
+ */
+ if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
+ mmc->b_max = 1;
+#endif
+
mmc_register(mmc);
return 0;
diff --git a/drivers/mmc/s5p_mmc.c b/drivers/mmc/s5p_mmc.c
index 0323800711..668c28bded 100644
--- a/drivers/mmc/s5p_mmc.c
+++ b/drivers/mmc/s5p_mmc.c
@@ -466,6 +466,7 @@ static int s5p_mmc_initialize(int dev_index, int bus_width)
mmc_host[dev_index].clock = 0;
mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index);
+ mmc->m_bmax = 0;
mmc_register(mmc);
return 0;
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 74f1293612..a9b1ca4c13 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
+COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
COBJS-$(CONFIG_SH_SPI) += sh_spi.o
diff --git a/drivers/spi/oc_tiny_spi.c b/drivers/spi/oc_tiny_spi.c
new file mode 100644
index 0000000000..fc01fb83a2
--- /dev/null
+++ b/drivers/spi/oc_tiny_spi.c
@@ -0,0 +1,248 @@
+/*
+ * Opencore tiny_spi driver
+ *
+ * http://opencores.org/project,tiny_spi
+ *
+ * based on bfin_spi.c
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/gpio.h>
+
+#define TINY_SPI_STATUS_TXE 0x1
+#define TINY_SPI_STATUS_TXR 0x2
+
+struct tiny_spi_regs {
+ unsigned rxdata; /* Rx data reg */
+ unsigned txdata; /* Tx data reg */
+ unsigned status; /* Status reg */
+ unsigned control; /* Control reg */
+ unsigned baud; /* Baud reg */
+};
+
+struct tiny_spi_host {
+ uint base;
+ uint freq;
+ uint baudwidth;
+};
+static const struct tiny_spi_host tiny_spi_host_list[] =
+ CONFIG_SYS_TINY_SPI_LIST;
+
+struct tiny_spi_slave {
+ struct spi_slave slave;
+ const struct tiny_spi_host *host;
+ uint mode;
+ uint baud;
+ uint flg;
+};
+#define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ unsigned int cs = slave->cs;
+
+ gpio_set_value(cs, tiny_spi->flg);
+ debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ unsigned int cs = slave->cs;
+
+ gpio_set_value(cs, !tiny_spi->flg);
+ debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+}
+
+void spi_set_speed(struct spi_slave *slave, uint hz)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ const struct tiny_spi_host *host = tiny_spi->host;
+
+ tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
+ (1 << host->baudwidth)) - 1;
+ debug("%s: speed %u actual %u\n", __func__, hz,
+ host->freq / ((tiny_spi->baud + 1) * 2));
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int hz, unsigned int mode)
+{
+ struct tiny_spi_slave *tiny_spi;
+
+ if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
+ return NULL;
+
+ tiny_spi = malloc(sizeof(*tiny_spi));
+ if (!tiny_spi)
+ return NULL;
+ memset(tiny_spi, 0, sizeof(*tiny_spi));
+
+ tiny_spi->slave.bus = bus;
+ tiny_spi->slave.cs = cs;
+ tiny_spi->host = &tiny_spi_host_list[bus];
+ tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
+ tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
+ spi_set_speed(&tiny_spi->slave, hz);
+
+ debug("%s: bus:%i cs:%i base:%lx\n", __func__,
+ bus, cs, tiny_spi->host->base);
+ return &tiny_spi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+
+ gpio_free(slave->cs);
+ free(tiny_spi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
+
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+ gpio_direction_output(slave->cs, !tiny_spi->flg);
+ writel(tiny_spi->mode, &regs->control);
+ writel(tiny_spi->baud, &regs->baud);
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+}
+
+#ifndef CONFIG_TINY_SPI_IDLE_VAL
+# define CONFIG_TINY_SPI_IDLE_VAL 0xff
+#endif
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ uint bytes = bitlen / 8;
+ uint i;
+
+ debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
+ slave->bus, slave->cs, bitlen, bytes, flags);
+ if (bitlen == 0)
+ goto done;
+
+ /* assume to do 8 bits transfers */
+ if (bitlen % 8) {
+ flags |= SPI_XFER_END;
+ goto done;
+ }
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ /* we need to tighten the transfer loop */
+ if (txp && rxp) {
+ writeb(*txp++, &regs->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, &regs->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx, tx = *txp++;
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(&regs->txdata);
+ writeb(tx, &regs->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(&regs->txdata);
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(&regs->rxdata);
+ } else if (rxp) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, &regs->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ &regs->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx;
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(&regs->txdata);
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ &regs->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(&regs->txdata);
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(&regs->rxdata);
+ } else if (txp) {
+ writeb(*txp++, &regs->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, &regs->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 tx = *txp++;
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(tx, &regs->txdata);
+ }
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ } else {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, &regs->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ &regs->txdata);
+ for (i = 2; i < bytes; i++) {
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ &regs->txdata);
+ }
+ }
+ while (!(readb(&regs->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ }
+
+ done:
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return 0;
+}
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 2c53a6f3e3..086dc05383 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -28,7 +28,7 @@ LIB := $(obj)libvideo.o
COBJS-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
COBJS-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
COBJS-$(CONFIG_CFB_CONSOLE) += cfb_console.o
-COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o
+COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
COBJS-$(CONFIG_S6E63D6) += s6e63d6.o
COBJS-$(CONFIG_VIDEO_AMBA) += amba.o
COBJS-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index dd849c2dc1..b427c84877 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -882,6 +882,8 @@ static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff,
struct palette p[256];
bmp_color_table_entry_t cte;
int green_shift, red_off;
+ int limit = VIDEO_COLS * VIDEO_ROWS;
+ int pixels = 0;
x = 0;
y = __le32_to_cpu(img->header.height) - 1;
@@ -962,6 +964,10 @@ static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff,
/* unencoded run */
cnt = bm[1];
runlen = cnt;
+ pixels += cnt;
+ if (pixels > limit)
+ goto error;
+
bm += 2;
if (y < height) {
if (x >= width) {
@@ -970,7 +976,6 @@ static int display_rle8_bitmap (bmp_image_t *img, int xoff, int yoff,
}
if (x + runlen > width)
cnt = width - x;
-
draw_bitmap (&fbp, bm, p, cnt, 0);
x += runlen;
}
@@ -982,9 +987,13 @@ next_run:
break;
default:
/* encoded run */
+ cnt = bm[0];
+ runlen = cnt;
+ pixels += cnt;
+ if (pixels > limit)
+ goto error;
+
if (y < height) { /* only draw into visible area */
- cnt = bm[0];
- runlen = cnt;
if (x >= width) {
x += runlen;
bm += 2;
@@ -992,7 +1001,6 @@ next_run:
}
if (x + runlen > width)
cnt = width - x;
-
draw_bitmap (&fbp, bm, p, cnt, 1);
x += runlen;
}
@@ -1001,6 +1009,9 @@ next_run:
}
}
return 0;
+error:
+ printf("Error: Too much encoded pixel data, validate your bitmap\n");
+ return -1;
}
#endif
diff --git a/drivers/video/fsl_diu_fb.c b/drivers/video/fsl_diu_fb.c
index 35ed938bef..0709849048 100644
--- a/drivers/video/fsl_diu_fb.c
+++ b/drivers/video/fsl_diu_fb.c
@@ -1,6 +1,7 @@
/*
- * Copyright 2007, 2010 Freescale Semiconductor, Inc.
- * York Sun <yorksun@freescale.com>
+ * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
+ * Authors: York Sun <yorksun@freescale.com>
+ * Timur Tabi <timur@freescale.com>
*
* FSL DIU Framebuffer driver
*
@@ -24,12 +25,42 @@
*/
#include <common.h>
-#include <i2c.h>
#include <malloc.h>
#include <asm/io.h>
+#include "videomodes.h"
+#include <video_fb.h>
#include <fsl_diu_fb.h>
+struct fb_var_screeninfo {
+ unsigned int xres; /* visible resolution */
+ unsigned int yres;
+
+ unsigned int bits_per_pixel; /* guess what */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ unsigned int pixclock; /* pixel clock in ps (pico seconds) */
+ unsigned int left_margin; /* time from sync to picture */
+ unsigned int right_margin; /* time from picture to sync */
+ unsigned int upper_margin; /* time from sync to picture */
+ unsigned int lower_margin;
+ unsigned int hsync_len; /* length of horizontal sync */
+ unsigned int vsync_len; /* length of vertical sync */
+ unsigned int sync; /* see FB_SYNC_* */
+ unsigned int vmode; /* see FB_VMODE_* */
+ unsigned int rotate; /* angle we rotate counter clockwise */
+};
+
+struct fb_info {
+ struct fb_var_screeninfo var; /* Current var */
+ unsigned int smem_len; /* Length of frame buffer mem */
+ unsigned int type; /* see FB_TYPE_* */
+ unsigned int line_length; /* length of a line in bytes */
+
+ void *screen_base;
+ unsigned long screen_size;
+};
+
struct fb_videomode {
const char *name; /* optional */
unsigned int refresh; /* optional */
@@ -53,6 +84,7 @@ struct fb_videomode {
/* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
static struct fb_videomode fsl_diu_mode_800 = {
+ .name = "800x600-60",
.refresh = 60,
.xres = 800,
.yres = 480,
@@ -74,6 +106,7 @@ static struct fb_videomode fsl_diu_mode_800 = {
* hsync 31.5kHz, vsync 60Hz
*/
static struct fb_videomode fsl_diu_mode_1024 = {
+ .name = "1024x768-60",
.refresh = 60,
.xres = 1024,
.yres = 768,
@@ -109,120 +142,137 @@ static struct fb_videomode fsl_diu_mode_1280 = {
*/
struct diu_ad {
/* Word 0(32-bit) in DDR memory */
- unsigned int pix_fmt; /* hard coding pixel format */
+ __le32 pix_fmt; /* hard coding pixel format */
/* Word 1(32-bit) in DDR memory */
- unsigned int addr;
+ __le32 addr;
/* Word 2(32-bit) in DDR memory */
- unsigned int src_size_g_alpha;
+ __le32 src_size_g_alpha;
/* Word 3(32-bit) in DDR memory */
- unsigned int aoi_size;
+ __le32 aoi_size;
/* Word 4(32-bit) in DDR memory */
- unsigned int offset_xyi;
+ __le32 offset_xyi;
/* Word 5(32-bit) in DDR memory */
- unsigned int offset_xyd;
+ __le32 offset_xyd;
/* Word 6(32-bit) in DDR memory */
- unsigned int ckmax_r:8;
- unsigned int ckmax_g:8;
- unsigned int ckmax_b:8;
- unsigned int res9:8;
+ __le32 ckmax_r:8;
+ __le32 ckmax_g:8;
+ __le32 ckmax_b:8;
+ __le32 res9:8;
/* Word 7(32-bit) in DDR memory */
- unsigned int ckmin_r:8;
- unsigned int ckmin_g:8;
- unsigned int ckmin_b:8;
- unsigned int res10:8;
+ __le32 ckmin_r:8;
+ __le32 ckmin_g:8;
+ __le32 ckmin_b:8;
+ __le32 res10:8;
/* Word 8(32-bit) in DDR memory */
- unsigned int next_ad;
+ __le32 next_ad;
/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
- unsigned int res1;
- unsigned int res2;
- unsigned int res3;
-}__attribute__ ((packed));
+ __le32 res[3];
+} __attribute__ ((packed));
/*
* DIU register map
*/
struct diu {
- unsigned int desc[3];
- unsigned int gamma;
- unsigned int pallete;
- unsigned int cursor;
- unsigned int curs_pos;
- unsigned int diu_mode;
- unsigned int bgnd;
- unsigned int bgnd_wb;
- unsigned int disp_size;
- unsigned int wb_size;
- unsigned int wb_mem_addr;
- unsigned int hsyn_para;
- unsigned int vsyn_para;
- unsigned int syn_pol;
- unsigned int thresholds;
- unsigned int int_status;
- unsigned int int_mask;
- unsigned int colorbar[8];
- unsigned int filling;
- unsigned int plut;
+ __be32 desc[3];
+ __be32 gamma;
+ __be32 pallete;
+ __be32 cursor;
+ __be32 curs_pos;
+ __be32 diu_mode;
+ __be32 bgnd;
+ __be32 bgnd_wb;
+ __be32 disp_size;
+ __be32 wb_size;
+ __be32 wb_mem_addr;
+ __be32 hsyn_para;
+ __be32 vsyn_para;
+ __be32 syn_pol;
+ __be32 thresholds;
+ __be32 int_status;
+ __be32 int_mask;
+ __be32 colorbar[8];
+ __be32 filling;
+ __be32 plut;
} __attribute__ ((packed));
-struct diu_hw {
- struct diu *diu_reg;
- volatile unsigned int mode; /* DIU operation mode */
-};
-
struct diu_addr {
- unsigned char * paddr; /* Virtual address */
- unsigned int offset;
+ void *vaddr; /* Virtual address */
+ u32 paddr; /* 32-bit physical address */
+ unsigned int offset; /* Alignment offset */
};
+static struct fb_info info;
+
/*
- * Modes of operation of DIU
+ * Align to 64-bit(8-byte), 32-byte, etc.
*/
-#define MFB_MODE0 0 /* DIU off */
-#define MFB_MODE1 1 /* All three planes output to display */
-#define MFB_MODE2 2 /* Plane 1 to display,
- * planes 2+3 written back to memory */
-#define MFB_MODE3 3 /* All three planes written back to memory */
-#define MFB_MODE4 4 /* Color bar generation */
-
-#define MAX_CURS 32
-
-static struct fb_info fsl_fb_info;
-static struct diu_addr gamma, cursor;
-static struct diu_ad fsl_diu_fb_ad __attribute__ ((aligned(32)));
-static struct diu_ad dummy_ad __attribute__ ((aligned(32)));
-static unsigned char *dummy_fb;
-static struct diu_hw dr = {
- .mode = MFB_MODE1,
-};
+static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+{
+ u32 offset, ssize;
+ u32 mask;
-int fb_enabled = 0;
-int fb_initialized = 0;
-const int default_xres = 1280;
-const int default_pixel_format = 0x88882317;
+ ssize = size + bytes_align;
+ buf->vaddr = malloc(ssize);
+ if (!buf->vaddr)
+ return -1;
-static int map_video_memory(struct fb_info *info, unsigned long bytes_align);
-static void enable_lcdc(void);
-static void disable_lcdc(void);
-static int fsl_diu_enable_panel(struct fb_info *info);
-static int fsl_diu_disable_panel(struct fb_info *info);
-static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align);
-void diu_set_pixel_clock(unsigned int pixclock);
+ memset(buf->vaddr, 0, ssize);
+ mask = bytes_align - 1;
+ offset = (u32)buf->vaddr & mask;
+ if (offset) {
+ buf->offset = bytes_align - offset;
+ buf->vaddr += offset;
+ } else
+ buf->offset = 0;
-int fsl_diu_init(int xres, unsigned int pixel_format, int gamma_fix)
+ buf->paddr = virt_to_phys(buf->vaddr);
+ return 0;
+}
+
+/*
+ * Allocate a framebuffer and an Area Descriptor that points to it. Both
+ * are created in the same memory block. The Area Descriptor is updated to
+ * point to the framebuffer memory. Memory is aligned as needed.
+ */
+static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
+ unsigned int depth, void **fb)
{
- struct fb_videomode *fsl_diu_mode_db;
- struct diu_ad *ad = &fsl_diu_fb_ad;
- struct diu *hw;
- struct fb_info *info = &fsl_fb_info;
- struct fb_var_screeninfo *var = &info->var;
- unsigned char *gamma_table_base;
- unsigned int i, j;
+ unsigned long size = xres * yres * depth;
+ struct diu_addr addr;
+ struct diu_ad *ad;
+ size_t ad_size = roundup(sizeof(struct diu_ad), 32);
+
+ /*
+ * Allocate a memory block that holds the Area Descriptor and the
+ * frame buffer right behind it. To keep the code simple, everything
+ * is aligned on a 32-byte address.
+ */
+ if (allocate_buf(&addr, ad_size + size, 32) < 0)
+ return NULL;
- debug("Enter fsl_diu_init\n");
- dr.diu_reg = (struct diu *) (CONFIG_SYS_DIU_ADDR);
- hw = (struct diu *) dr.diu_reg;
+ ad = addr.vaddr;
+ ad->addr = cpu_to_le32(addr.paddr + ad_size);
+ ad->aoi_size = cpu_to_le32((yres << 16) | xres);
+ ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
+ ad->offset_xyi = 0;
+ ad->offset_xyd = 0;
- disable_lcdc();
+ if (fb)
+ *fb = addr.vaddr + ad_size;
+
+ return ad;
+}
+
+int fsl_diu_init(int xres, u32 pixel_format, int gamma_fix)
+{
+ struct fb_videomode *fsl_diu_mode_db;
+ struct diu_ad *ad;
+ struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
+ u8 *gamma_table_base;
+ unsigned int i, j;
+ struct diu_ad *dummy_ad;
+ struct diu_addr gamma;
+ struct diu_addr cursor;
switch (xres) {
case 800:
@@ -235,65 +285,40 @@ int fsl_diu_init(int xres, unsigned int pixel_format, int gamma_fix)
fsl_diu_mode_db = &fsl_diu_mode_1024;
}
- if (0 == fb_initialized) {
- allocate_buf(&gamma, 768, 32);
- debug("gamma is allocated @ 0x%x\n",
- (unsigned int)gamma.paddr);
- allocate_buf(&cursor, MAX_CURS * MAX_CURS * 2, 32);
- debug("curosr is allocated @ 0x%x\n",
- (unsigned int)cursor.paddr);
-
- /* create a dummy fb and dummy ad */
- dummy_fb = malloc(64);
- if (NULL == dummy_fb) {
- printf("Cannot allocate dummy fb\n");
- return -1;
- }
- dummy_ad.addr = cpu_to_le32((unsigned int)dummy_fb);
- dummy_ad.pix_fmt = 0x88882317;
- dummy_ad.src_size_g_alpha = 0x04400000; /* alpha = 0 */
- dummy_ad.aoi_size = 0x02000400;
- dummy_ad.offset_xyi = 0;
- dummy_ad.offset_xyd = 0;
- dummy_ad.next_ad = 0;
- /* Memory allocation for framebuffer */
- if (map_video_memory(info, 32)) {
- printf("Unable to allocate fb memory 1\n");
- return -1;
- }
+ /* The AD struct for the dummy framebuffer and the FB itself */
+ dummy_ad = allocate_fb(2, 4, 4, NULL);
+ if (!dummy_ad) {
+ printf("DIU: Out of memory\n");
+ return -1;
}
-
- memset(info->screen_base, 0, info->smem_len);
-
- out_be32(&dr.diu_reg->desc[0], (int)&dummy_ad);
- out_be32(&dr.diu_reg->desc[1], (int)&dummy_ad);
- out_be32(&dr.diu_reg->desc[2], (int)&dummy_ad);
- debug("dummy dr.diu_reg->desc[0] = 0x%x\n", dr.diu_reg->desc[0]);
- debug("dummy desc[0] = 0x%x\n", hw->desc[0]);
+ dummy_ad->pix_fmt = 0x88883316;
/* read mode info */
- var->xres = fsl_diu_mode_db->xres;
- var->yres = fsl_diu_mode_db->yres;
- var->bits_per_pixel = 32;
- var->pixclock = fsl_diu_mode_db->pixclock;
- var->left_margin = fsl_diu_mode_db->left_margin;
- var->right_margin = fsl_diu_mode_db->right_margin;
- var->upper_margin = fsl_diu_mode_db->upper_margin;
- var->lower_margin = fsl_diu_mode_db->lower_margin;
- var->hsync_len = fsl_diu_mode_db->hsync_len;
- var->vsync_len = fsl_diu_mode_db->vsync_len;
- var->sync = fsl_diu_mode_db->sync;
- var->vmode = fsl_diu_mode_db->vmode;
- info->line_length = var->xres * var->bits_per_pixel / 8;
+ info.var.xres = fsl_diu_mode_db->xres;
+ info.var.yres = fsl_diu_mode_db->yres;
+ info.var.bits_per_pixel = 32;
+ info.var.pixclock = fsl_diu_mode_db->pixclock;
+ info.var.left_margin = fsl_diu_mode_db->left_margin;
+ info.var.right_margin = fsl_diu_mode_db->right_margin;
+ info.var.upper_margin = fsl_diu_mode_db->upper_margin;
+ info.var.lower_margin = fsl_diu_mode_db->lower_margin;
+ info.var.hsync_len = fsl_diu_mode_db->hsync_len;
+ info.var.vsync_len = fsl_diu_mode_db->vsync_len;
+ info.var.sync = fsl_diu_mode_db->sync;
+ info.var.vmode = fsl_diu_mode_db->vmode;
+ info.line_length = info.var.xres * info.var.bits_per_pixel / 8;
+
+ /* Memory allocation for framebuffer */
+ info.smem_len =
+ info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
+ ad = allocate_fb(info.var.xres, info.var.yres,
+ info.var.bits_per_pixel / 8, &info.screen_base);
+ if (!ad) {
+ printf("DIU: Out of memory\n");
+ return -1;
+ }
ad->pix_fmt = pixel_format;
- ad->addr = cpu_to_le32((unsigned int)info->screen_base);
- ad->src_size_g_alpha
- = cpu_to_le32((var->yres << 12) | var->xres);
- /* fix me. AOI should not be greater than display size */
- ad->aoi_size = cpu_to_le32(( var->yres << 16) | var->xres);
- ad->offset_xyi = 0;
- ad->offset_xyd = 0;
/* Disable chroma keying function */
ad->ckmax_r = 0;
@@ -304,195 +329,91 @@ int fsl_diu_init(int xres, unsigned int pixel_format, int gamma_fix)
ad->ckmin_g = 255;
ad->ckmin_b = 255;
- gamma_table_base = gamma.paddr;
- debug("gamma_table_base is allocated @ 0x%x\n",
- (unsigned int)gamma_table_base);
-
- /* Prep for DIU init - gamma table */
-
+ /* Initialize the gamma table */
+ if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
+ printf("DIU: Out of memory\n");
+ return -1;
+ }
+ gamma_table_base = gamma.vaddr;
for (i = 0; i <= 2; i++)
- for (j = 0; j <= 255; j++)
+ for (j = 0; j < 256; j++)
*gamma_table_base++ = j;
if (gamma_fix == 1) { /* fix the gamma */
- debug("Fix gamma table\n");
- gamma_table_base = gamma.paddr;
- for (i = 0; i < 256*3; i++) {
+ gamma_table_base = gamma.vaddr;
+ for (i = 0; i < 256 * 3; i++) {
gamma_table_base[i] = (gamma_table_base[i] << 2)
| ((gamma_table_base[i] >> 6) & 0x03);
}
}
- debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
+ /* Initialize the cursor */
+ if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
+ printf("DIU: Can't alloc cursor data\n");
+ return -1;
+ }
/* Program DIU registers */
+ out_be32(&hw->diu_mode, 0); /* Temporarily disable the DIU */
- out_be32(&hw->gamma, (int)gamma.paddr);
- out_be32(&hw->cursor, (int)cursor.paddr);
+ out_be32(&hw->gamma, gamma.paddr);
+ out_be32(&hw->cursor, cursor.paddr);
out_be32(&hw->bgnd, 0x007F7F7F);
- out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
- out_be32(&hw->disp_size, var->yres << 16 | var->xres); /* DISP SIZE */
- out_be32(&hw->wb_size, 0); /* WB SIZE */
- out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
- out_be32(&hw->hsyn_para, var->left_margin << 22 | /* BP_H */
- var->hsync_len << 11 | /* PW_H */
- var->right_margin); /* FP_H */
-
- out_be32(&hw->vsyn_para, var->upper_margin << 22 | /* BP_V */
- var->vsync_len << 11 | /* PW_V */
- var->lower_margin); /* FP_V */
-
- out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */
- out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
- out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */
- out_be32(&hw->int_mask, 0); /* INT MASK */
+ out_be32(&hw->bgnd_wb, 0);
+ out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
+ out_be32(&hw->wb_size, 0);
+ out_be32(&hw->wb_mem_addr, 0);
+ out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
+ info.var.hsync_len << 11 |
+ info.var.right_margin);
+
+ out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
+ info.var.vsync_len << 11 |
+ info.var.lower_margin);
+
+ out_be32(&hw->syn_pol, 0);
+ out_be32(&hw->thresholds, 0x00037800);
+ out_be32(&hw->int_status, 0);
+ out_be32(&hw->int_mask, 0);
out_be32(&hw->plut, 0x01F5F666);
/* Pixel Clock configuration */
- debug("DIU pixclock in ps - %d\n", var->pixclock);
- diu_set_pixel_clock(var->pixclock);
-
- fb_initialized = 1;
-
- /* Enable the DIU */
- fsl_diu_enable_panel(info);
- enable_lcdc();
-
- return 0;
-}
-
-char *fsl_fb_open(struct fb_info **info)
-{
- *info = &fsl_fb_info;
- return fsl_fb_info.screen_base;
-}
-
-void fsl_diu_close(void)
-{
- struct fb_info *info = &fsl_fb_info;
- fsl_diu_disable_panel(info);
-}
+ diu_set_pixel_clock(info.var.pixclock);
-static int fsl_diu_enable_panel(struct fb_info *info)
-{
- struct diu *hw = dr.diu_reg;
- struct diu_ad *ad = &fsl_diu_fb_ad;
-
- debug("Entered: enable_panel\n");
- if (in_be32(&hw->desc[0]) != (unsigned)ad)
- out_be32(&hw->desc[0], (unsigned)ad);
- debug("desc[0] = 0x%x\n", hw->desc[0]);
- return 0;
-}
+ /* Set the frame buffers */
+ out_be32(&hw->desc[0], virt_to_phys(ad));
+ out_be32(&hw->desc[1], virt_to_phys(dummy_ad));
+ out_be32(&hw->desc[2], virt_to_phys(dummy_ad));
-static int fsl_diu_disable_panel(struct fb_info *info)
-{
- struct diu *hw = dr.diu_reg;
+ /* Enable the DIU, set display to all three planes */
+ out_be32(&hw->diu_mode, 1);
- debug("Entered: disable_panel\n");
- if (in_be32(&hw->desc[0]) != (unsigned)&dummy_ad)
- out_be32(&hw->desc[0], (unsigned)&dummy_ad);
return 0;
}
-static int map_video_memory(struct fb_info *info, unsigned long bytes_align)
-{
- unsigned long offset;
- unsigned long mask;
-
- debug("Entered: map_video_memory\n");
- /* allocate maximum 1280*1024 with 32bpp */
- info->smem_len = 1280 * 4 *1024 + bytes_align;
- debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->smem_len);
- info->screen_base = malloc(info->smem_len);
- if (info->screen_base == NULL) {
- printf("Unable to allocate fb memory\n");
- return -1;
- }
- info->smem_start = (unsigned int) info->screen_base;
- mask = bytes_align - 1;
- offset = (unsigned long)info->screen_base & mask;
- if (offset) {
- info->screen_base += (bytes_align - offset);
- info->smem_len = info->smem_len - (bytes_align - offset);
- } else
- info->smem_len = info->smem_len - bytes_align;
-
- info->screen_size = info->smem_len;
-
- debug("Allocated fb @ 0x%08lx, size=%d.\n",
- info->smem_start, info->smem_len);
-
- return 0;
-}
-
-static void enable_lcdc(void)
-{
- struct diu *hw = dr.diu_reg;
-
- debug("Entered: enable_lcdc, fb_enabled = %d\n", fb_enabled);
- if (!fb_enabled) {
- out_be32(&hw->diu_mode, dr.mode);
- fb_enabled++;
- }
- debug("diu_mode = %d\n", hw->diu_mode);
-}
-
-static void disable_lcdc(void)
-{
- struct diu *hw = dr.diu_reg;
-
- debug("Entered: disable_lcdc, fb_enabled = %d\n", fb_enabled);
- if (fb_enabled) {
- out_be32(&hw->diu_mode, 0);
- fb_enabled = 0;
- }
-}
-
-/*
- * Align to 64-bit(8-byte), 32-byte, etc.
- */
-static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
+void *video_hw_init(void)
{
- u32 offset, ssize;
- u32 mask;
-
- debug("Entered: allocate_buf\n");
- ssize = size + bytes_align;
- buf->paddr = malloc(ssize);
- if (!buf->paddr)
- return -1;
-
- memset(buf->paddr, 0, ssize);
- mask = bytes_align - 1;
- offset = (u32)buf->paddr & mask;
- if (offset) {
- buf->offset = bytes_align - offset;
- buf->paddr = (unsigned char *) ((u32)buf->paddr + offset);
- } else
- buf->offset = 0;
- return 0;
-}
+ static GraphicDevice ctfb;
+ const char *options;
+ unsigned int depth = 0, freq = 0;
-#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
-#include <stdio_dev.h>
-#include <video_fb.h>
-/*
- * The Graphic Device
- */
-static GraphicDevice ctfb;
+ if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
+ &options))
+ return NULL;
-void *video_hw_init(void)
-{
- struct fb_info *info;
+ /* Find the monitor port, which is a required option */
+ if (!options)
+ return NULL;
+ if (strncmp(options, "monitor=", 8) != 0)
+ return NULL;
- if (platform_diu_init(&ctfb.winSizeX, &ctfb.winSizeY) < 0)
+ if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
return NULL;
/* fill in Graphic device struct */
sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
- ctfb.winSizeX, ctfb.winSizeY, 32, 64, 60);
+ ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
- ctfb.frameAdrs = (unsigned int)fsl_fb_open(&info);
+ ctfb.frameAdrs = (unsigned int)info.screen_base;
ctfb.plnSizeX = ctfb.winSizeX;
ctfb.plnSizeY = ctfb.winSizeY;
@@ -501,7 +422,7 @@ void *video_hw_init(void)
ctfb.isaBase = 0;
ctfb.pciBase = 0;
- ctfb.memSize = info->screen_size;
+ ctfb.memSize = info.screen_size;
/* Cursor Start Address */
ctfb.dprBase = 0;
@@ -510,4 +431,3 @@ void *video_hw_init(void)
return &ctfb;
}
-#endif /* defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) */
diff --git a/drivers/video/videomodes.c b/drivers/video/videomodes.c
index d27ce1d2cd..6fe5811aec 100644
--- a/drivers/video/videomodes.c
+++ b/drivers/video/videomodes.c
@@ -1,6 +1,7 @@
/*
* (C) Copyright 2004
* Pierre Aubert, Staubli Faverges , <p.aubert@staubli.com>
+ * Copyright 2011 Freescale Semiconductor, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -73,6 +74,8 @@
****************************************************************************/
#include <common.h>
+#include <linux/ctype.h>
+
#include "videomodes.h"
const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
@@ -206,3 +209,64 @@ int video_get_params (struct ctfb_res_modes *pPar, char *penv)
}
return bpp;
}
+
+/*
+ * Parse the 'video-mode' environment variable
+ *
+ * Example: "video-mode=fslfb:1280x1024-32@60,monitor=dvi". See
+ * doc/README.video for more information on how to set the variable.
+ *
+ * @xres: returned value of X-resolution
+ * @yres: returned value of Y-resolution
+ * @depth: returned value of color depth
+ * @freq: returned value of monitor frequency
+ * @options: pointer to any remaining options, or NULL
+ *
+ * Returns 1 if valid values were found, 0 otherwise
+ */
+int video_get_video_mode(unsigned int *xres, unsigned int *yres,
+ unsigned int *depth, unsigned int *freq, const char **options)
+{
+ char *p = getenv("video-mode");
+ if (!p)
+ return 0;
+
+ /* Skip over the driver name, which we don't care about. */
+ p = strchr(p, ':');
+ if (!p)
+ return 0;
+
+ /* Get the X-resolution*/
+ while (*p && !isdigit(*p))
+ p++;
+ *xres = simple_strtoul(p, &p, 10);
+ if (!*xres)
+ return 0;
+
+ /* Get the Y-resolution */
+ while (*p && !isdigit(*p))
+ p++;
+ *yres = simple_strtoul(p, &p, 10);
+ if (!*yres)
+ return 0;
+
+ /* Get the depth */
+ while (*p && !isdigit(*p))
+ p++;
+ *depth = simple_strtoul(p, &p, 10);
+ if (!*depth)
+ return 0;
+
+ /* Get the frequency */
+ while (*p && !isdigit(*p))
+ p++;
+ *freq = simple_strtoul(p, &p, 10);
+ if (!*freq)
+ return 0;
+
+ /* Find the extra options, if any */
+ p = strchr(p, ',');
+ *options = p ? p + 1 : NULL;
+
+ return 1;
+}
diff --git a/drivers/video/videomodes.h b/drivers/video/videomodes.h
index 0d7c335410..e546ab44f1 100644
--- a/drivers/video/videomodes.h
+++ b/drivers/video/videomodes.h
@@ -86,3 +86,6 @@ extern const struct ctfb_vesa_modes vesa_modes[];
extern const struct ctfb_res_modes res_mode_init[];
int video_get_params (struct ctfb_res_modes *pPar, char *penv);
+
+int video_get_video_mode(unsigned int *xres, unsigned int *yres,
+ unsigned int *depth, unsigned int *freq, const char **options);