summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dfu/dfu.c4
-rw-r--r--drivers/dfu/dfu_mmc.c46
-rw-r--r--drivers/dfu/dfu_nand.c13
-rw-r--r--drivers/fpga/fpga.c36
-rw-r--r--drivers/fpga/spartan2.c3
-rw-r--r--drivers/fpga/spartan3.c3
-rw-r--r--drivers/fpga/virtex2.c3
-rw-r--r--drivers/fpga/xilinx.c26
-rw-r--r--drivers/fpga/zynqpl.c105
-rw-r--r--drivers/gpio/s5p_gpio.c204
-rw-r--r--drivers/gpio/tegra_gpio.c20
-rw-r--r--drivers/i2c/mvtwsi.c28
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/fsl_esdhc.c28
-rw-r--r--drivers/mmc/mmc.c35
-rw-r--r--drivers/mmc/rpmb.c323
-rw-r--r--drivers/mmc/tegra_mmc.c13
-rw-r--r--drivers/mtd/nand/omap_gpmc.c2
-rw-r--r--drivers/net/fm/Makefile1
-rw-r--r--drivers/net/fm/memac_phy.c8
-rw-r--r--drivers/net/phy/vitesse.c46
-rw-r--r--drivers/pci/fsl_pci_init.c9
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/pmic_ltc3676.c32
-rw-r--r--drivers/power/pmic/pmic_pfuze100.c2
-rw-r--r--drivers/qe/qe.c9
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/ci_udc.c182
-rw-r--r--drivers/usb/gadget/ci_udc.h17
-rw-r--r--drivers/usb/gadget/f_dfu.c10
-rw-r--r--drivers/usb/gadget/f_fastboot.c513
-rw-r--r--drivers/usb/gadget/f_thor.c12
-rw-r--r--drivers/usb/gadget/storage_common.c4
-rw-r--r--drivers/usb/host/ehci-fsl.c15
-rw-r--r--drivers/usb/host/ehci-tegra.c165
-rw-r--r--drivers/usb/musb-new/musb_gadget_ep0.c8
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/imx25lcdc.c121
38 files changed, 1790 insertions, 260 deletions
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 51b1026..a938109 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -131,6 +131,10 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
{
int ret = 0;
+ ret = dfu_write_buffer_drain(dfu);
+ if (ret)
+ return ret;
+
if (dfu->flush_medium)
ret = dfu->flush_medium(dfu);
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 5e10ea7..63cc876 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -18,11 +18,29 @@ static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
static long dfu_file_buf_len;
+static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
+{
+ int ret;
+
+ if (part == mmc->part_num)
+ return 0;
+
+ ret = mmc_switch_part(dfu->dev_num, part);
+ if (ret) {
+ error("Cannot switch to partition %d\n", part);
+ return ret;
+ }
+ mmc->part_num = part;
+
+ return 0;
+}
+
static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
struct mmc *mmc = find_mmc_device(dfu->dev_num);
u32 blk_start, blk_count, n = 0;
+ int ret, part_num_bkp = 0;
/*
* We must ensure that we work in lba_blk_size chunks, so ALIGN
@@ -39,6 +57,13 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
return -EINVAL;
}
+ if (dfu->data.mmc.hw_partition >= 0) {
+ part_num_bkp = mmc->part_num;
+ ret = mmc_access_part(dfu, mmc, dfu->data.mmc.hw_partition);
+ if (ret)
+ return ret;
+ }
+
debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__,
op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
blk_start, blk_count, buf);
@@ -57,9 +82,17 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
if (n != blk_count) {
error("MMC operation failed");
+ if (dfu->data.mmc.hw_partition >= 0)
+ mmc_access_part(dfu, mmc, part_num_bkp);
return -EIO;
}
+ if (dfu->data.mmc.hw_partition >= 0) {
+ ret = mmc_access_part(dfu, mmc, part_num_bkp);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -194,6 +227,8 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf,
* 2nd and 3rd:
* lba_start and lba_size, for raw write
* mmc_dev and mmc_part, for filesystems and part
+ * 4th (optional):
+ * mmcpart <num> (access to HW eMMC partitions)
*/
int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
{
@@ -233,11 +268,22 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
return -ENODEV;
}
+ dfu->data.mmc.hw_partition = -EINVAL;
if (!strcmp(entity_type, "raw")) {
dfu->layout = DFU_RAW_ADDR;
dfu->data.mmc.lba_start = second_arg;
dfu->data.mmc.lba_size = third_arg;
dfu->data.mmc.lba_blk_size = mmc->read_bl_len;
+
+ /*
+ * Check for an extra entry at dfu_alt_info env variable
+ * specifying the mmc HW defined partition number
+ */
+ if (s)
+ if (!strcmp(strsep(&s, " "), "mmcpart"))
+ dfu->data.mmc.hw_partition =
+ simple_strtoul(s, NULL, 0);
+
} else if (!strcmp(entity_type, "part")) {
disk_partition_t partinfo;
block_dev_desc_t *blk_dev = &mmc->block_dev;
diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c
index 2d07097..ccdbef6 100644
--- a/drivers/dfu/dfu_nand.c
+++ b/drivers/dfu/dfu_nand.c
@@ -163,6 +163,18 @@ static int dfu_flush_medium_nand(struct dfu_entity *dfu)
return ret;
}
+unsigned int dfu_polltimeout_nand(struct dfu_entity *dfu)
+{
+ /*
+ * Currently, Poll Timeout != 0 is only needed on nand
+ * ubi partition, as the not used sectors need an erase
+ */
+ if (dfu->data.nand.ubi)
+ return DFU_MANIFEST_POLL_TIMEOUT;
+
+ return DFU_DEFAULT_POLL_TIMEOUT;
+}
+
int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
{
char *st;
@@ -211,6 +223,7 @@ int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
dfu->read_medium = dfu_read_medium_nand;
dfu->write_medium = dfu_write_medium_nand;
dfu->flush_medium = dfu_flush_medium_nand;
+ dfu->poll_timeout = dfu_polltimeout_nand;
/* initial state */
dfu->inited = 0;
diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c
index b940d9b..37946d5 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -173,16 +173,45 @@ int fpga_add(fpga_type devtype, void *desc)
/*
* Convert bitstream data and load into the fpga
*/
-int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
+int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
{
printf("Bitstream support not implemented for this FPGA device\n");
return FPGA_FAIL;
}
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int fpga_fsload(int devnum, const void *buf, size_t size,
+ fpga_fs_info *fpga_fsinfo)
+{
+ int ret_val = FPGA_FAIL; /* assume failure */
+ const fpga_desc *desc = fpga_validate(devnum, buf, size,
+ (char *)__func__);
+
+ if (desc) {
+ switch (desc->devtype) {
+ case fpga_xilinx:
+#if defined(CONFIG_FPGA_XILINX)
+ ret_val = xilinx_loadfs(desc->devdesc, buf, size,
+ fpga_fsinfo);
+#else
+ fpga_no_sup((char *)__func__, "Xilinx devices");
+#endif
+ break;
+ default:
+ printf("%s: Invalid or unsupported device type %d\n",
+ __func__, desc->devtype);
+ }
+ }
+
+ return ret_val;
+}
+#endif
+
/*
* Generic multiplexing code
*/
-int fpga_load(int devnum, const void *buf, size_t bsize)
+int fpga_load(int devnum, const void *buf, size_t bsize, bitstream_type bstype)
{
int ret_val = FPGA_FAIL; /* assume failure */
const fpga_desc *desc = fpga_validate(devnum, buf, bsize,
@@ -192,7 +221,8 @@ int fpga_load(int devnum, const void *buf, size_t bsize)
switch (desc->devtype) {
case fpga_xilinx:
#if defined(CONFIG_FPGA_XILINX)
- ret_val = xilinx_load(desc->devdesc, buf, bsize);
+ ret_val = xilinx_load(desc->devdesc, buf, bsize,
+ bstype);
#else
fpga_no_sup((char *)__func__, "Xilinx devices");
#endif
diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c
index 7054056..859fb3c 100644
--- a/drivers/fpga/spartan2.c
+++ b/drivers/fpga/spartan2.c
@@ -41,7 +41,8 @@ static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
-static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c
index 5c9412c..b0213e6 100644
--- a/drivers/fpga/spartan3.c
+++ b/drivers/fpga/spartan3.c
@@ -45,7 +45,8 @@ static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
/* ------------------------------------------------------------------------- */
/* Spartan-II Generic Implementation */
-static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/virtex2.c b/drivers/fpga/virtex2.c
index e092147..0d2d9a4 100644
--- a/drivers/fpga/virtex2.c
+++ b/drivers/fpga/virtex2.c
@@ -90,7 +90,8 @@ static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
-static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
int ret_val = FPGA_FAIL;
diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c
index 8837f5c..3795c1a 100644
--- a/drivers/fpga/xilinx.c
+++ b/drivers/fpga/xilinx.c
@@ -24,7 +24,8 @@ static int xilinx_validate(xilinx_desc *desc, char *fn);
/* ------------------------------------------------------------------------- */
-int fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
+int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
+ bitstream_type bstype)
{
unsigned int length;
unsigned int swapsize;
@@ -127,19 +128,36 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size)
dataptr += 4;
printf(" bytes in bitstream = %d\n", swapsize);
- return fpga_load(devnum, dataptr, swapsize);
+ return fpga_load(devnum, dataptr, swapsize, bstype);
}
-int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize)
+int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
printf ("%s: Invalid device descriptor\n", __FUNCTION__);
return FPGA_FAIL;
}
- return desc->operations->load(desc, buf, bsize);
+ return desc->operations->load(desc, buf, bsize, bstype);
}
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+int xilinx_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fpga_fsinfo)
+{
+ if (!xilinx_validate(desc, (char *)__func__)) {
+ printf("%s: Invalid device descriptor\n", __func__);
+ return FPGA_FAIL;
+ }
+
+ if (!desc->operations->loadfs)
+ return FPGA_FAIL;
+
+ return desc->operations->loadfs(desc, buf, bsize, fpga_fsinfo);
+}
+#endif
+
int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
if (!xilinx_validate (desc, (char *)__FUNCTION__)) {
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index c066f21..68fe0f3 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <asm/io.h>
+#include <fs.h>
#include <zynqpl.h>
#include <linux/sizes.h>
#include <asm/arch/hardware.h>
@@ -194,7 +195,7 @@ static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
return FPGA_SUCCESS;
}
-static int zynq_dma_xfer_init(u32 partialbit)
+static int zynq_dma_xfer_init(bitstream_type bstype)
{
u32 status, control, isr_status;
unsigned long ts;
@@ -202,7 +203,7 @@ static int zynq_dma_xfer_init(u32 partialbit)
/* Clear loopback bit */
clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
- if (!partialbit) {
+ if (bstype != BIT_PARTIAL) {
zynq_slcr_devcfg_disable();
/* Setting PCFG_PROG_B signal to high */
@@ -322,16 +323,11 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
size_t bsize, u32 blocksize, u32 *swap,
- u32 *partialbit)
+ bitstream_type *bstype)
{
u32 *buf_start;
u32 diff;
- /* Detect if we are going working with partial or full bitstream */
- if (bsize != desc->size) {
- printf("%s: Working with partial bitstream\n", __func__);
- *partialbit = 1;
- }
buf_start = check_data((u8 *)buf, blocksize, swap);
if (!buf_start)
@@ -351,17 +347,16 @@ static int zynq_validate_bitstream(xilinx_desc *desc, const void *buf,
return FPGA_FAIL;
}
- if (zynq_dma_xfer_init(*partialbit))
+ if (zynq_dma_xfer_init(*bstype))
return FPGA_FAIL;
return 0;
}
-
-static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
+static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
+ bitstream_type bstype)
{
unsigned long ts; /* Timestamp */
- u32 partialbit = 0;
u32 isr_status, swap;
/*
@@ -369,7 +364,7 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
* in chunks
*/
if (zynq_validate_bitstream(desc, buf, bsize, bsize, &swap,
- &partialbit))
+ &bstype))
return FPGA_FAIL;
buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);
@@ -398,11 +393,92 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize)
debug("%s: FPGA config done\n", __func__);
+ if (bstype != BIT_PARTIAL)
+ zynq_slcr_devcfg_enable();
+
+ return FPGA_SUCCESS;
+}
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize,
+ fpga_fs_info *fsinfo)
+{
+ unsigned long ts; /* Timestamp */
+ u32 isr_status, swap;
+ u32 partialbit = 0;
+ u32 blocksize;
+ u32 pos = 0;
+ int fstype;
+ char *interface, *dev_part, *filename;
+
+ blocksize = fsinfo->blocksize;
+ interface = fsinfo->interface;
+ dev_part = fsinfo->dev_part;
+ filename = fsinfo->filename;
+ fstype = fsinfo->fstype;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ return FPGA_FAIL;
+
+ if (zynq_validate_bitstream(desc, buf, bsize, blocksize, &swap,
+ &partialbit))
+ return FPGA_FAIL;
+
+ dcache_disable();
+
+ do {
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, blocksize >> 2,
+ 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ bsize -= blocksize;
+ pos += blocksize;
+
+ if (fs_set_blk_dev(interface, dev_part, fstype))
+ return FPGA_FAIL;
+
+ if (bsize > blocksize) {
+ if (fs_read(filename, (u32) buf, pos, blocksize) < 0)
+ return FPGA_FAIL;
+ } else {
+ if (fs_read(filename, (u32) buf, pos, bsize) < 0)
+ return FPGA_FAIL;
+ }
+ } while (bsize > blocksize);
+
+ buf = zynq_align_dma_buffer((u32 *)buf, blocksize, swap);
+
+ if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
+ return FPGA_FAIL;
+
+ dcache_enable();
+
+ isr_status = readl(&devcfg_base->int_sts);
+
+ /* Check FPGA configuration completion */
+ ts = get_timer(0);
+ while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
+ if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for FPGA to config\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ isr_status = readl(&devcfg_base->int_sts);
+ }
+
+ debug("%s: FPGA config done\n", __func__);
+
if (!partialbit)
zynq_slcr_devcfg_enable();
return FPGA_SUCCESS;
}
+#endif
static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
{
@@ -411,6 +487,9 @@ static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize)
struct xilinx_fpga_op zynq_op = {
.load = zynq_load,
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+ .loadfs = zynq_loadfs,
+#endif
.dump = zynq_dump,
.info = zynq_info,
};
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 11a0472..db7b673 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -8,11 +8,9 @@
#include <common.h>
#include <asm/io.h>
#include <asm/gpio.h>
+#include <asm/arch/gpio.h>
-#define S5P_GPIO_GET_BANK(x) ((x >> S5P_GPIO_BANK_SHIFT) \
- & S5P_GPIO_BANK_MASK)
-
-#define S5P_GPIO_GET_PIN(x) (x & S5P_GPIO_PIN_MASK)
+#define S5P_GPIO_GET_PIN(x) (x % GPIO_PER_BANK)
#define CON_MASK(x) (0xf << ((x) << 2))
#define CON_SFR(x, v) ((v) << ((x) << 2))
@@ -28,7 +26,103 @@
#define RATE_MASK(x) (0x1 << (x + 16))
#define RATE_SET(x) (0x1 << (x + 16))
-void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
+#define name_to_gpio(n) s5p_name_to_gpio(n)
+static inline int s5p_name_to_gpio(const char *name)
+{
+ unsigned num, irregular_set_number, irregular_bank_base;
+ const struct gpio_name_num_table *tabp;
+ char this_bank, bank_name, irregular_bank_name;
+ char *endp;
+
+ /*
+ * The gpio name starts with either 'g' or 'gp' followed by the bank
+ * name character. Skip one or two characters depending on the prefix.
+ */
+ if (name[0] == 'g' && name[1] == 'p')
+ name += 2;
+ else if (name[0] == 'g')
+ name++;
+ else
+ return -1; /* Name must start with 'g' */
+
+ bank_name = *name++;
+ if (!*name)
+ return -1; /* At least one digit is required/expected. */
+
+ /*
+ * On both exynos5 and exynos5420 architectures there is a bank of
+ * GPIOs which does not fall into the regular address pattern. Those
+ * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below
+ * assignments help to handle these irregularities.
+ */
+#if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5)
+ if (cpu_is_exynos5()) {
+ if (proid_is_exynos5420()) {
+ tabp = exynos5420_gpio_table;
+ irregular_bank_name = 'y';
+ irregular_set_number = '7';
+ irregular_bank_base = EXYNOS5420_GPIO_Y70;
+ } else {
+ tabp = exynos5_gpio_table;
+ irregular_bank_name = 'c';
+ irregular_set_number = '4';
+ irregular_bank_base = EXYNOS5_GPIO_C40;
+ }
+ } else {
+ if (proid_is_exynos4412())
+ tabp = exynos4x12_gpio_table;
+ else
+ tabp = exynos4_gpio_table;
+ irregular_bank_name = 0;
+ irregular_set_number = 0;
+ irregular_bank_base = 0;
+ }
+#else
+ if (cpu_is_s5pc110())
+ tabp = s5pc110_gpio_table;
+ else
+ tabp = s5pc100_gpio_table;
+ irregular_bank_name = 0;
+ irregular_set_number = 0;
+ irregular_bank_base = 0;
+#endif
+
+ this_bank = tabp->bank;
+ do {
+ if (bank_name == this_bank) {
+ unsigned pin_index; /* pin number within the bank */
+ if ((bank_name == irregular_bank_name) &&
+ (name[0] == irregular_set_number)) {
+ pin_index = name[1] - '0';
+ /* Irregular sets have 8 pins. */
+ if (pin_index >= GPIO_PER_BANK)
+ return -1;
+ num = irregular_bank_base + pin_index;
+ } else {
+ pin_index = simple_strtoul(name, &endp, 8);
+ pin_index -= tabp->bank_offset;
+ /*
+ * Sanity check: bunk 'z' has no set number,
+ * for all other banks there must be exactly
+ * two octal digits, and the resulting number
+ * should not exceed the number of pins in the
+ * bank.
+ */
+ if (((bank_name != 'z') && !name[1]) ||
+ *endp ||
+ (pin_index >= tabp->bank_size))
+ return -1;
+ num = tabp->base + pin_index;
+ }
+ return num;
+ }
+ this_bank = (++tabp)->bank;
+ } while (this_bank);
+
+ return -1;
+}
+
+static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
{
unsigned int value;
@@ -38,18 +132,7 @@ void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
writel(value, &bank->con);
}
-void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en)
-{
- s5p_gpio_cfg_pin(bank, gpio, GPIO_OUTPUT);
- s5p_gpio_set_value(bank, gpio, en);
-}
-
-void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio)
-{
- s5p_gpio_cfg_pin(bank, gpio, GPIO_INPUT);
-}
-
-void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
+static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
{
unsigned int value;
@@ -60,7 +143,19 @@ void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
writel(value, &bank->dat);
}
-unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
+static void s5p_gpio_direction_output(struct s5p_gpio_bank *bank,
+ int gpio, int en)
+{
+ s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_OUTPUT);
+ s5p_gpio_set_value(bank, gpio, en);
+}
+
+static void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio)
+{
+ s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_INPUT);
+}
+
+static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
{
unsigned int value;
@@ -68,7 +163,7 @@ unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
return !!(value & DAT_MASK(gpio));
}
-void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
+static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
{
unsigned int value;
@@ -76,8 +171,8 @@ void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
value &= ~PULL_MASK(gpio);
switch (mode) {
- case GPIO_PULL_DOWN:
- case GPIO_PULL_UP:
+ case S5P_GPIO_PULL_DOWN:
+ case S5P_GPIO_PULL_UP:
value |= PULL_MODE(gpio, mode);
break;
default:
@@ -87,7 +182,7 @@ void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
writel(value, &bank->pull);
}
-void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
+static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
{
unsigned int value;
@@ -95,10 +190,10 @@ void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
value &= ~DRV_MASK(gpio);
switch (mode) {
- case GPIO_DRV_1X:
- case GPIO_DRV_2X:
- case GPIO_DRV_3X:
- case GPIO_DRV_4X:
+ case S5P_GPIO_DRV_1X:
+ case S5P_GPIO_DRV_2X:
+ case S5P_GPIO_DRV_3X:
+ case S5P_GPIO_DRV_4X:
value |= DRV_SET(gpio, mode);
break;
default:
@@ -108,7 +203,7 @@ void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
writel(value, &bank->drv);
}
-void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
+static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
{
unsigned int value;
@@ -116,8 +211,8 @@ void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
value &= ~RATE_MASK(gpio);
switch (mode) {
- case GPIO_DRV_FAST:
- case GPIO_DRV_SLOW:
+ case S5P_GPIO_DRV_FAST:
+ case S5P_GPIO_DRV_SLOW:
value |= RATE_SET(gpio);
break;
default:
@@ -127,12 +222,31 @@ void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
writel(value, &bank->drv);
}
-struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio)
+struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio)
{
- unsigned bank = S5P_GPIO_GET_BANK(gpio);
- unsigned base = s5p_gpio_base(gpio);
+ const struct gpio_info *data;
+ unsigned int upto;
+ int i, count;
+
+ data = get_gpio_data();
+ count = get_bank_num();
+ upto = 0;
+
+ for (i = 0; i < count; i++) {
+ debug("i=%d, upto=%d\n", i, upto);
+ if (gpio < data->max_gpio) {
+ struct s5p_gpio_bank *bank;
+ bank = (struct s5p_gpio_bank *)data->reg_addr;
+ bank += (gpio - upto) / GPIO_PER_BANK;
+ debug("gpio=%d, bank=%p\n", gpio, bank);
+ return bank;
+ }
+
+ upto = data->max_gpio;
+ data++;
+ }
- return (struct s5p_gpio_bank *)(base + bank);
+ return NULL;
}
int s5p_gpio_get_pin(unsigned gpio)
@@ -179,3 +293,27 @@ int gpio_set_value(unsigned gpio, int value)
return 0;
}
+
+void gpio_set_pull(int gpio, int mode)
+{
+ s5p_gpio_set_pull(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
+
+void gpio_set_drv(int gpio, int mode)
+{
+ s5p_gpio_set_drv(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
+
+void gpio_cfg_pin(int gpio, int cfg)
+{
+ s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), cfg);
+}
+
+void gpio_set_rate(int gpio, int mode)
+{
+ s5p_gpio_set_rate(s5p_gpio_get_bank(gpio),
+ s5p_gpio_get_pin(gpio), mode);
+}
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 82b30d5..fea9d17 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -221,6 +221,26 @@ int gpio_set_value(unsigned gpio, int value)
return 0;
}
+void gpio_config_table(const struct tegra_gpio_config *config, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ switch (config[i].init) {
+ case TEGRA_GPIO_INIT_IN:
+ gpio_direction_input(config[i].gpio);
+ break;
+ case TEGRA_GPIO_INIT_OUT0:
+ gpio_direction_output(config[i].gpio, 0);
+ break;
+ case TEGRA_GPIO_INIT_OUT1:
+ gpio_direction_output(config[i].gpio, 1);
+ break;
+ }
+ set_config(config[i].gpio, 1);
+ }
+}
+
/*
* Display Tegra GPIO information
*/
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index 90c8387..5ba0e03 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -216,21 +216,7 @@ static int twsi_stop(int status)
*/
#define TWSI_FREQUENCY(m, n) \
- ((u8) (CONFIG_SYS_TCLK / (10 * (m + 1) * 2 * (1 << n))))
-
-/*
- * These are required to be reprogrammed before enabling the controller
- * because a reset loses them.
- * Default values come from the spec, but a twsi_reset will change them.
- * twsi_slave_address left uninitialized lest checkpatch.pl complains.
- */
-
-/* Baudrate generator: m (bits 7..4) =4, n (bits 3..0) =4 */
-static u8 twsi_baud_rate = 0x44; /* baudrate at controller reset */
-/* Default frequency corresponding to default m=4, n=4 */
-static u8 twsi_actual_speed = TWSI_FREQUENCY(4, 4);
-/* Default slave address is 0 (so is an uninitialized static) */
-static u8 twsi_slave_address;
+ (CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n)))
/*
* Reset controller.
@@ -238,7 +224,7 @@ static u8 twsi_slave_address;
* Controller reset also resets the baud rate and slave address, so
* re-establish them.
*/
-static void twsi_reset(void)
+static void twsi_reset(u8 baud_rate, u8 slave_address)
{
/* ensure controller will be enabled by any twsi*() function */
twsi_control_flags = MVTWSI_CONTROL_TWSIEN;
@@ -247,9 +233,9 @@ static void twsi_reset(void)
/* wait 2 ms -- this is what the Marvell LSP does */
udelay(20000);
/* set baud rate */
- writel(twsi_baud_rate, &twsi->baudrate);
+ writel(baud_rate, &twsi->baudrate);
/* set slave address even though we don't use it */
- writel(twsi_slave_address, &twsi->slave_address);
+ writel(slave_address, &twsi->slave_address);
writel(0, &twsi->xtnd_slave_addr);
/* assert STOP but don't care for the result */
(void) twsi_stop(0);
@@ -277,12 +263,8 @@ void i2c_init(int requested_speed, int slaveadd)
}
}
}
- /* save baud rate and slave for later calls to twsi_reset */
- twsi_baud_rate = baud;
- twsi_actual_speed = highest_speed;
- twsi_slave_address = slaveadd;
/* reset controller */
- twsi_reset();
+ twsi_reset(baud, slaveadd);
}
/*
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 931922b..4c6ab9e 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_DWMMC) += dw_mmc.o
obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
+obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 4c3b93d..5541613 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -96,7 +96,7 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
else if (cmd->resp_type & MMC_RSP_PRESENT)
xfertyp |= XFERTYP_RSPTYP_48;
-#if defined(CONFIG_MX53) || defined(CONFIG_T4240QDS)
+#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240)
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
xfertyp |= XFERTYP_CMDTYP_ABORT;
#endif
@@ -174,7 +174,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
int timeout;
struct fsl_esdhc_cfg *cfg = mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
-#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+
uint wml_value;
wml_value = data->blocksize/4;
@@ -184,12 +184,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = WML_RD_WML_MAX_VAL;
esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->dest);
+#endif
} else {
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
flush_dcache_range((ulong)data->src,
(ulong)data->src+data->blocks
*data->blocksize);
-
+#endif
if (wml_value > WML_WR_WML_MAX)
wml_value = WML_WR_WML_MAX_VAL;
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
@@ -199,19 +202,10 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
wml_value << 16);
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->src);
+#endif
}
-#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
- if (!(data->flags & MMC_DATA_READ)) {
- if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
- printf("\nThe SD card is locked. "
- "Can not write to a locked card.\n\n");
- return TIMEOUT;
- }
- esdhc_write32(&regs->dsaddr, (u32)data->src);
- } else
- esdhc_write32(&regs->dsaddr, (u32)data->dest);
-#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
@@ -252,6 +246,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
return 0;
}
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
static void check_and_invalidate_dcache_range
(struct mmc_cmd *cmd,
struct mmc_data *data) {
@@ -261,6 +256,8 @@ static void check_and_invalidate_dcache_range
unsigned end = start+size ;
invalidate_dcache_range(start, end);
}
+#endif
+
/*
* Sends a command out on the bus. Takes the mmc pointer,
* a command pointer, and an optional data pointer.
@@ -388,9 +385,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
goto out;
}
} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
-#endif
+
if (data->flags & MMC_DATA_READ)
check_and_invalidate_dcache_range(cmd, data);
+#endif
}
out:
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 16051e5..8b53ead 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -150,6 +150,8 @@ int mmc_send_status(struct mmc *mmc, int timeout)
#endif
return TIMEOUT;
}
+ if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
+ return SWITCH_ERR;
return 0;
}
@@ -501,7 +503,7 @@ static int mmc_change_freq(struct mmc *mmc)
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if (err)
- return err;
+ return err == SWITCH_ERR ? 0 : err;
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
@@ -550,6 +552,32 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0;
}
+int mmc_select_hwpart(int dev_num, int hwpart)
+{
+ struct mmc *mmc = find_mmc_device(dev_num);
+ int ret;
+
+ if (!mmc)
+ return -1;
+
+ if (mmc->part_num == hwpart)
+ return 0;
+
+ if (mmc->part_config == MMCPART_NOAVAILABLE) {
+ printf("Card doesn't support part_switch\n");
+ return -1;
+ }
+
+ ret = mmc_switch_part(dev_num, hwpart);
+ if (ret)
+ return -1;
+
+ mmc->part_num = hwpart;
+
+ return 0;
+}
+
+
int mmc_switch_part(int dev_num, unsigned int part_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
@@ -1310,10 +1338,13 @@ static int mmc_complete_init(struct mmc *mmc)
int mmc_init(struct mmc *mmc)
{
int err = IN_PROGRESS;
- unsigned start = get_timer(0);
+ unsigned start;
if (mmc->has_init)
return 0;
+
+ start = get_timer(0);
+
if (!mmc->init_in_progress)
err = mmc_start_init(mmc);
diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c
new file mode 100644
index 0000000..05936f5
--- /dev/null
+++ b/drivers/mmc/rpmb.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2014, Staubli Faverges
+ * Pierre Aubert
+ *
+ * eMMC- Replay Protected Memory Block
+ * According to JEDEC Standard No. 84-A441
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mmc.h>
+#include <sha256.h>
+#include "mmc_private.h"
+
+/* Request codes */
+#define RPMB_REQ_KEY 1
+#define RPMB_REQ_WCOUNTER 2
+#define RPMB_REQ_WRITE_DATA 3
+#define RPMB_REQ_READ_DATA 4
+#define RPMB_REQ_STATUS 5
+
+/* Response code */
+#define RPMB_RESP_KEY 0x0100
+#define RPMB_RESP_WCOUNTER 0x0200
+#define RPMB_RESP_WRITE_DATA 0x0300
+#define RPMB_RESP_READ_DATA 0x0400
+
+/* Error codes */
+#define RPMB_OK 0
+#define RPMB_ERR_GENERAL 1
+#define RPMB_ERR_AUTH 2
+#define RPMB_ERR_COUNTER 3
+#define RPMB_ERR_ADDRESS 4
+#define RPMB_ERR_WRITE 5
+#define RPMB_ERR_READ 6
+#define RPMB_ERR_KEY 7
+#define RPMB_ERR_CNT_EXPIRED 0x80
+#define RPMB_ERR_MSK 0x7
+
+/* Sizes of RPMB data frame */
+#define RPMB_SZ_STUFF 196
+#define RPMB_SZ_MAC 32
+#define RPMB_SZ_DATA 256
+#define RPMB_SZ_NONCE 16
+
+#define SHA256_BLOCK_SIZE 64
+
+/* Error messages */
+static const char * const rpmb_err_msg[] = {
+ "",
+ "General failure",
+ "Authentication failure",
+ "Counter failure",
+ "Address failure",
+ "Write failure",
+ "Read failure",
+ "Authentication key not yet programmed",
+};
+
+
+/* Structure of RPMB data frame. */
+struct s_rpmb {
+ unsigned char stuff[RPMB_SZ_STUFF];
+ unsigned char mac[RPMB_SZ_MAC];
+ unsigned char data[RPMB_SZ_DATA];
+ unsigned char nonce[RPMB_SZ_NONCE];
+ unsigned long write_counter;
+ unsigned short address;
+ unsigned short block_count;
+ unsigned short result;
+ unsigned short request;
+};
+
+static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
+ bool is_rel_write)
+{
+ struct mmc_cmd cmd = {0};
+
+ cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
+ cmd.cmdarg = blockcount & 0x0000FFFF;
+ if (is_rel_write)
+ cmd.cmdarg |= 1 << 31;
+ cmd.resp_type = MMC_RSP_R1;
+
+ return mmc_send_cmd(mmc, &cmd, NULL);
+}
+static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
+ unsigned int count, bool is_rel_write)
+{
+ struct mmc_cmd cmd = {0};
+ struct mmc_data data;
+ int ret;
+
+ ret = mmc_set_blockcount(mmc, count, is_rel_write);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
+#endif
+ return 1;
+ }
+
+ cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+
+ data.src = (const char *)s;
+ data.blocks = 1;
+ data.blocksize = MMC_MAX_BLOCK_LEN;
+ data.flags = MMC_DATA_WRITE;
+
+ ret = mmc_send_cmd(mmc, &cmd, &data);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
+#endif
+ return 1;
+ }
+ return 0;
+}
+static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
+ unsigned short expected)
+{
+ struct mmc_cmd cmd = {0};
+ struct mmc_data data;
+ int ret;
+
+ ret = mmc_set_blockcount(mmc, 1, false);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
+#endif
+ return -1;
+ }
+ cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ data.dest = (char *)s;
+ data.blocks = 1;
+ data.blocksize = MMC_MAX_BLOCK_LEN;
+ data.flags = MMC_DATA_READ;
+
+ ret = mmc_send_cmd(mmc, &cmd, &data);
+ if (ret) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
+#endif
+ return -1;
+ }
+ /* Check the response and the status */
+ if (be16_to_cpu(s->request) != expected) {
+#ifdef CONFIG_MMC_RPMB_TRACE
+ printf("%s:response= %x\n", __func__,
+ be16_to_cpu(s->request));
+#endif
+ return -1;
+ }
+ ret = be16_to_cpu(s->result);
+ if (ret) {
+ printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
+ (ret & RPMB_ERR_CNT_EXPIRED) ?
+ "Write counter has expired" : "");
+ }
+
+ /* Return the status of the command */
+ return ret;
+}
+static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ return -1;
+
+ /* Read the result */
+ return mmc_rpmb_response(mmc, rpmb_frame, expected);
+}
+static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
+ unsigned char *output)
+{
+ sha256_context ctx;
+ int i;
+ unsigned char k_ipad[SHA256_BLOCK_SIZE];
+ unsigned char k_opad[SHA256_BLOCK_SIZE];
+
+ sha256_starts(&ctx);
+
+ /* According to RFC 4634, the HMAC transform looks like:
+ SHA(K XOR opad, SHA(K XOR ipad, text))
+
+ where K is an n byte key.
+ ipad is the byte 0x36 repeated blocksize times
+ opad is the byte 0x5c repeated blocksize times
+ and text is the data being protected.
+ */
+
+ for (i = 0; i < RPMB_SZ_MAC; i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ k_opad[i] = key[i] ^ 0x5c;
+ }
+ /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
+ for ( ; i < SHA256_BLOCK_SIZE; i++) {
+ k_ipad[i] = 0x36;
+ k_opad[i] = 0x5c;
+ }
+ sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
+ sha256_update(&ctx, buff, len);
+ sha256_finish(&ctx, output);
+
+ /* Init context for second pass */
+ sha256_starts(&ctx);
+
+ /* start with outer pad */
+ sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
+
+ /* then results of 1st hash */
+ sha256_update(&ctx, output, RPMB_SZ_MAC);
+
+ /* finish up 2nd pass */
+ sha256_finish(&ctx, output);
+}
+int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
+{
+ int ret;
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ return -1;
+
+ /* Read the result */
+ ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
+ if (ret)
+ return ret;
+
+ *pcounter = be32_to_cpu(rpmb_frame->write_counter);
+ return 0;
+}
+int mmc_rpmb_set_key(struct mmc *mmc, void *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
+ memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
+
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
+ return -1;
+
+ /* read the operation status */
+ return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
+}
+int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ rpmb_frame->address = cpu_to_be16(blk + i);
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
+ break;
+
+ /* Read the result */
+ if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
+ break;
+
+ /* Check the HMAC if key is provided */
+ if (key) {
+ unsigned char ret_hmac[RPMB_SZ_MAC];
+
+ rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
+ if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
+ printf("MAC error on block #%d\n", i);
+ break;
+ }
+ }
+ /* Copy data */
+ memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
+ }
+ return i;
+}
+int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
+ unsigned short cnt, unsigned char *key)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
+ unsigned long wcount;
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ if (mmc_rpmb_get_counter(mmc, &wcount)) {
+ printf("Cannot read RPMB write counter\n");
+ break;
+ }
+
+ /* Fill the request */
+ memset(rpmb_frame, 0, sizeof(struct s_rpmb));
+ memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
+ rpmb_frame->address = cpu_to_be16(blk + i);
+ rpmb_frame->block_count = cpu_to_be16(1);
+ rpmb_frame->write_counter = cpu_to_be32(wcount);
+ rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
+ /* Computes HMAC */
+ rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
+
+ if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
+ break;
+
+ /* Get status */
+ if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
+ break;
+ }
+ return i;
+}
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index ed67eec..ca9c4aa 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -18,7 +18,7 @@
DECLARE_GLOBAL_DATA_PTR;
-struct mmc_host mmc_host[MAX_HOSTS];
+struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE];
#ifndef CONFIG_OF_CONTROL
#error "Please enable device tree support to use this driver"
@@ -669,13 +669,14 @@ static int process_nodes(const void *blob, int node_list[], int count)
void tegra_mmc_init(void)
{
- int node_list[MAX_HOSTS], count;
+ int node_list[CONFIG_SYS_MMC_MAX_DEVICE], count;
const void *blob = gd->fdt_blob;
debug("%s entry\n", __func__);
/* See if any Tegra124 MMC controllers are present */
count = fdtdec_find_aliases_for_id(blob, "sdhci",
- COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, MAX_HOSTS);
+ COMPAT_NVIDIA_TEGRA124_SDMMC, node_list,
+ CONFIG_SYS_MMC_MAX_DEVICE);
debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count);
if (process_nodes(blob, node_list, count)) {
printf("%s: Error processing T30 mmc node(s)!\n", __func__);
@@ -684,7 +685,8 @@ void tegra_mmc_init(void)
/* See if any Tegra30 MMC controllers are present */
count = fdtdec_find_aliases_for_id(blob, "sdhci",
- COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS);
+ COMPAT_NVIDIA_TEGRA30_SDMMC, node_list,
+ CONFIG_SYS_MMC_MAX_DEVICE);
debug("%s: count of T30 sdhci nodes is %d\n", __func__, count);
if (process_nodes(blob, node_list, count)) {
printf("%s: Error processing T30 mmc node(s)!\n", __func__);
@@ -693,7 +695,8 @@ void tegra_mmc_init(void)
/* Now look for any Tegra20 MMC controllers */
count = fdtdec_find_aliases_for_id(blob, "sdhci",
- COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS);
+ COMPAT_NVIDIA_TEGRA20_SDMMC, node_list,
+ CONFIG_SYS_MMC_MAX_DEVICE);
debug("%s: count of T20 sdhci nodes is %d\n", __func__, count);
if (process_nodes(blob, node_list, count)) {
printf("%s: Error processing T20 mmc node(s)!\n", __func__);
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c
index 881a636..bf99b8e 100644
--- a/drivers/mtd/nand/omap_gpmc.c
+++ b/drivers/mtd/nand/omap_gpmc.c
@@ -403,7 +403,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
dat[byte_pos] ^= 1 << bit_pos;
printf("nand: bit-flip corrected @data=%d\n", byte_pos);
} else if (byte_pos < error_max) {
- read_ecc[byte_pos - SECTOR_BYTES] = 1 << bit_pos;
+ read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
printf("nand: bit-flip corrected @oob=%d\n", byte_pos -
SECTOR_BYTES);
} else {
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index ee5d768..5ae3b16 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -32,5 +32,6 @@ obj-$(CONFIG_PPC_T2080) += t2080.o
obj-$(CONFIG_PPC_T2081) += t2080.o
obj-$(CONFIG_PPC_T4240) += t4240.o
obj-$(CONFIG_PPC_T4160) += t4240.o
+obj-$(CONFIG_PPC_T4080) += t4240.o
obj-$(CONFIG_PPC_B4420) += b4860.o
obj-$(CONFIG_PPC_B4860) += b4860.o
diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c
index 2f4bc11..de9c0e9 100644
--- a/drivers/net/fm/memac_phy.c
+++ b/drivers/net/fm/memac_phy.c
@@ -29,10 +29,8 @@ int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
- } else {
+ } else
setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
- setbits_be32(&regs->mdio_stat, MDIO_STAT_HOLD_15_CLK);
- }
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
@@ -76,10 +74,8 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
- } else {
+ } else
setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
- setbits_be32(&regs->mdio_stat, MDIO_STAT_HOLD_15_CLK);
- }
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 3a55d27..c58fe50 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -58,6 +58,14 @@
#define MIIM_VSC8514_18G_QSGMII 0x80e0
#define MIIM_VSC8514_18G_CMDSTAT 0x8000
+/* Vitesse VSC8664 Control/Status Register */
+#define MIIM_VSC8664_SERDES_AND_SIGDET 0x13
+#define MIIM_VSC8664_ADDITIONAL_DEV 0x16
+#define MIIM_VSC8664_EPHY_CON 0x17
+#define MIIM_VSC8664_LED_CON 0x1E
+
+#define PHY_EXT_PAGE_ACCESS_EXTENDED 0x0001
+
/* CIS8201 */
static int vitesse_config(struct phy_device *phydev)
{
@@ -244,6 +252,33 @@ static int vsc8514_config(struct phy_device *phydev)
return 0;
}
+static int vsc8664_config(struct phy_device *phydev)
+{
+ u32 val;
+
+ /* Enable MAC interface auto-negotiation */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON);
+ val |= (1 << 13);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_EPHY_CON, val);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_EXTENDED);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET);
+ val |= (1 << 11);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_SERDES_AND_SIGDET, val);
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
+ /* Enable LED blink */
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON);
+ val &= ~(1 << 2);
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8664_LED_CON, val);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
static struct phy_driver VSC8211_driver = {
.name = "Vitesse VSC8211",
.uid = 0xfc4b0,
@@ -334,6 +369,16 @@ static struct phy_driver VSC8662_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver VSC8664_driver = {
+ .name = "Vitesse VSC8664",
+ .uid = 0x70660,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8664_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
/* Vitesse bought Cicada, so we'll put these here */
static struct phy_driver cis8201_driver = {
.name = "CIS8201",
@@ -366,6 +411,7 @@ int phy_vitesse_init(void)
phy_register(&VSC8574_driver);
phy_register(&VSC8514_driver);
phy_register(&VSC8662_driver);
+ phy_register(&VSC8664_driver);
phy_register(&cis8201_driver);
phy_register(&cis8204_driver);
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index 6317fb1..3a41b0e 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -49,8 +49,13 @@ static void set_inbound_window(volatile pit_t *pi,
u64 size)
{
u32 sz = (__ilog2_u64(size) - 1);
- u32 flag = PIWAR_EN | PIWAR_LOCAL |
- PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+#ifdef CONFIG_SYS_FSL_ERRATUM_A005434
+ u32 flag = 0;
+#else
+ u32 flag = PIWAR_LOCAL;
+#endif
+
+ flag |= PIWAR_EN | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
out_be32(&pi->pitar, r->phys_start >> 12);
out_be32(&pi->piwbar, r->bus_start >> 12);
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 4129bda..920bbdc 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
+obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
diff --git a/drivers/power/pmic/pmic_ltc3676.c b/drivers/power/pmic/pmic_ltc3676.c
new file mode 100644
index 0000000..9b874cb
--- /dev/null
+++ b/drivers/power/pmic/pmic_ltc3676.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Gateworks Corporation
+ * Tim Harvey <tharvey@gateworks.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/ltc3676_pmic.h>
+
+int power_ltc3676_init(unsigned char bus)
+{
+ static const char name[] = "LTC3676_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = LTC3676_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_LTC3676_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/drivers/power/pmic/pmic_pfuze100.c b/drivers/power/pmic/pmic_pfuze100.c
index 22c1f15..21f12d2 100644
--- a/drivers/power/pmic/pmic_pfuze100.c
+++ b/drivers/power/pmic/pmic_pfuze100.c
@@ -11,7 +11,7 @@
#include <power/pmic.h>
#include <power/pfuze100_pmic.h>
-int pmic_init(unsigned char bus)
+int power_pfuze100_init(unsigned char bus)
{
static const char name[] = "PFUZE100_PMIC";
struct pmic *p = pmic_alloc();
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index b1da75e..9c5fbd1 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -14,6 +14,8 @@
#include "asm/immap_qe.h"
#include "qe.h"
+#define MPC85xx_DEVDISR_QE_DISABLE 0x1
+
qe_map_t *qe_immr = NULL;
static qe_snum_t snums[QE_NUM_OF_SNUM];
@@ -317,7 +319,9 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
size_t calc_size = sizeof(struct qe_firmware);
size_t length;
const struct qe_header *hdr;
-
+#ifdef CONFIG_DEEP_SLEEP
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
if (!firmware) {
printf("Invalid address\n");
return -EINVAL;
@@ -330,6 +334,9 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
(hdr->magic[2] != 'F')) {
printf("Not a microcode\n");
+#ifdef CONFIG_DEEP_SLEEP
+ setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_QE_DISABLE);
+#endif
return -EPERM;
}
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 896c8d4..66becdc 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
+obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o
endif
ifdef CONFIG_USB_ETHER
obj-y += ether.o
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 02d3fda..9cd0036 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -205,13 +205,26 @@ static void ci_invalidate_qtd(int ep_num)
static struct usb_request *
ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags)
{
- struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
- return &ci_ep->req;
+ struct ci_req *ci_req;
+
+ ci_req = memalign(ARCH_DMA_MINALIGN, sizeof(*ci_req));
+ if (!ci_req)
+ return NULL;
+
+ INIT_LIST_HEAD(&ci_req->queue);
+ ci_req->b_buf = 0;
+
+ return &ci_req->req;
}
-static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req)
{
- return;
+ struct ci_req *ci_req;
+
+ ci_req = container_of(req, struct ci_req, req);
+ if (ci_req->b_buf)
+ free(ci_req->b_buf);
+ free(ci_req);
}
static void ep_enable(int num, int in, int maxpacket)
@@ -267,99 +280,102 @@ static int ci_ep_disable(struct usb_ep *ep)
return 0;
}
-static int ci_bounce(struct ci_ep *ep, int in)
+static int ci_bounce(struct ci_req *ci_req, int in)
{
- uint32_t addr = (uint32_t)ep->req.buf;
- uint32_t ba;
+ struct usb_request *req = &ci_req->req;
+ uint32_t addr = (uint32_t)req->buf;
+ uint32_t hwaddr;
+ uint32_t aligned_used_len;
/* Input buffer address is not aligned. */
if (addr & (ARCH_DMA_MINALIGN - 1))
goto align;
/* Input buffer length is not aligned. */
- if (ep->req.length & (ARCH_DMA_MINALIGN - 1))
+ if (req->length & (ARCH_DMA_MINALIGN - 1))
goto align;
/* The buffer is well aligned, only flush cache. */
- ep->b_len = ep->req.length;
- ep->b_buf = ep->req.buf;
+ ci_req->hw_len = req->length;
+ ci_req->hw_buf = req->buf;
goto flush;
align:
- /* Use internal buffer for small payloads. */
- if (ep->req.length <= 64) {
- ep->b_len = 64;
- ep->b_buf = ep->b_fast;
- } else {
- ep->b_len = roundup(ep->req.length, ARCH_DMA_MINALIGN);
- ep->b_buf = memalign(ARCH_DMA_MINALIGN, ep->b_len);
- if (!ep->b_buf)
+ if (ci_req->b_buf && req->length > ci_req->b_len) {
+ free(ci_req->b_buf);
+ ci_req->b_buf = 0;
+ }
+ if (!ci_req->b_buf) {
+ ci_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN);
+ ci_req->b_buf = memalign(ARCH_DMA_MINALIGN, ci_req->b_len);
+ if (!ci_req->b_buf)
return -ENOMEM;
}
+ ci_req->hw_len = ci_req->b_len;
+ ci_req->hw_buf = ci_req->b_buf;
+
if (in)
- memcpy(ep->b_buf, ep->req.buf, ep->req.length);
+ memcpy(ci_req->hw_buf, req->buf, req->length);
flush:
- ba = (uint32_t)ep->b_buf;
- flush_dcache_range(ba, ba + ep->b_len);
+ hwaddr = (uint32_t)ci_req->hw_buf;
+ aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN);
+ flush_dcache_range(hwaddr, hwaddr + aligned_used_len);
return 0;
}
-static void ci_debounce(struct ci_ep *ep, int in)
+static void ci_debounce(struct ci_req *ci_req, int in)
{
- uint32_t addr = (uint32_t)ep->req.buf;
- uint32_t ba = (uint32_t)ep->b_buf;
+ struct usb_request *req = &ci_req->req;
+ uint32_t addr = (uint32_t)req->buf;
+ uint32_t hwaddr = (uint32_t)ci_req->hw_buf;
+ uint32_t aligned_used_len;
- if (in) {
- if (addr == ba)
- return; /* not a bounce */
- goto free;
- }
- invalidate_dcache_range(ba, ba + ep->b_len);
+ if (in)
+ return;
+
+ aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);
+ invalidate_dcache_range(hwaddr, hwaddr + aligned_used_len);
- if (addr == ba)
- return; /* not a bounce */
+ if (addr == hwaddr)
+ return; /* not a bounce */
- memcpy(ep->req.buf, ep->b_buf, ep->req.actual);
-free:
- /* Large payloads use allocated buffer, free it. */
- if (ep->b_buf != ep->b_fast)
- free(ep->b_buf);
+ memcpy(req->buf, ci_req->hw_buf, req->actual);
}
-static int ci_ep_queue(struct usb_ep *ep,
- struct usb_request *req, gfp_t gfp_flags)
+static void ci_ep_submit_next_request(struct ci_ep *ci_ep)
{
- struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_item *item;
struct ept_queue_head *head;
- int bit, num, len, in, ret;
+ int bit, num, len, in;
+ struct ci_req *ci_req;
+
+ ci_ep->req_primed = true;
+
num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
item = ci_get_qtd(num, in);
head = ci_get_qh(num, in);
- len = req->length;
- ret = ci_bounce(ci_ep, in);
- if (ret)
- return ret;
+ ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+ len = ci_req->req.length;
item->next = TERMINATE;
item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE;
- item->page0 = (uint32_t)ci_ep->b_buf;
- item->page1 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x1000;
- item->page2 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x2000;
- item->page3 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x3000;
- item->page4 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x4000;
+ item->page0 = (uint32_t)ci_req->hw_buf;
+ item->page1 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x1000;
+ item->page2 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x2000;
+ item->page3 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x3000;
+ item->page4 = ((uint32_t)ci_req->hw_buf & 0xfffff000) + 0x4000;
ci_flush_qtd(num);
head->next = (unsigned) item;
head->info = 0;
- DBG("ept%d %s queue len %x, buffer %p\n",
- num, in ? "in" : "out", len, ci_ep->b_buf);
+ DBG("ept%d %s queue len %x, req %p, buffer %p\n",
+ num, in ? "in" : "out", len, ci_req, ci_req->hw_buf);
ci_flush_qh(num);
if (in)
@@ -368,6 +384,29 @@ static int ci_ep_queue(struct usb_ep *ep,
bit = EPT_RX(num);
writel(bit, &udc->epprime);
+}
+
+static int ci_ep_queue(struct usb_ep *ep,
+ struct usb_request *req, gfp_t gfp_flags)
+{
+ struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
+ struct ci_req *ci_req = container_of(req, struct ci_req, req);
+ int in, ret;
+ int __maybe_unused num;
+
+ num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
+
+ ret = ci_bounce(ci_req, in);
+ if (ret)
+ return ret;
+
+ DBG("ept%d %s pre-queue req %p, buffer %p\n",
+ num, in ? "in" : "out", ci_req, ci_req->hw_buf);
+ list_add_tail(&ci_req->queue, &ci_ep->queue);
+
+ if (!ci_ep->req_primed)
+ ci_ep_submit_next_request(ci_ep);
return 0;
}
@@ -376,6 +415,8 @@ static void handle_ep_complete(struct ci_ep *ep)
{
struct ept_queue_item *item;
int num, in, len;
+ struct ci_req *ci_req;
+
num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0;
if (num == 0)
@@ -383,20 +424,27 @@ static void handle_ep_complete(struct ci_ep *ep)
item = ci_get_qtd(num, in);
ci_invalidate_qtd(num);
+ len = (item->info >> 16) & 0x7fff;
if (item->info & 0xff)
printf("EP%d/%s FAIL info=%x pg0=%x\n",
num, in ? "in" : "out", item->info, item->page0);
- len = (item->info >> 16) & 0x7fff;
- ep->req.actual = ep->req.length - len;
- ci_debounce(ep, in);
+ ci_req = list_first_entry(&ep->queue, struct ci_req, queue);
+ list_del_init(&ci_req->queue);
+ ep->req_primed = false;
+
+ if (!list_empty(&ep->queue))
+ ci_ep_submit_next_request(ep);
+
+ ci_req->req.actual = ci_req->req.length - len;
+ ci_debounce(ci_req, in);
- DBG("ept%d %s complete %x\n",
- num, in ? "in" : "out", len);
- ep->req.complete(&ep->ep, &ep->req);
+ DBG("ept%d %s req %p, complete %x\n",
+ num, in ? "in" : "out", ci_req, len);
+ ci_req->req.complete(&ep->ep, &ci_req->req);
if (num == 0) {
- ep->req.length = 0;
- usb_ep_queue(&ep->ep, &ep->req, 0);
+ ci_req->req.length = 0;
+ usb_ep_queue(&ep->ep, &ci_req->req, 0);
ep->desc = &ep0_in_desc;
}
}
@@ -405,13 +453,18 @@ static void handle_ep_complete(struct ci_ep *ep)
static void handle_setup(void)
{
- struct usb_request *req = &controller.ep[0].req;
+ struct ci_ep *ci_ep = &controller.ep[0];
+ struct ci_req *ci_req;
+ struct usb_request *req;
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
struct ept_queue_head *head;
struct usb_ctrlrequest r;
int status = 0;
int num, in, _num, _in, i;
char *buf;
+
+ ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+ req = &ci_req->req;
head = ci_get_qh(0, 0); /* EP0 OUT */
ci_invalidate_qh(0);
@@ -424,6 +477,9 @@ static void handle_setup(void)
DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest),
r.bRequestType, r.bRequest, r.wIndex, r.wValue);
+ list_del_init(&ci_req->queue);
+ ci_ep->req_primed = false;
+
switch (SETUP(r.bRequestType, r.bRequest)) {
case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE):
_num = r.wIndex & 15;
@@ -701,6 +757,8 @@ static int ci_udc_probe(void)
/* Init EP 0 */
memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init));
controller.ep[0].desc = &ep0_in_desc;
+ INIT_LIST_HEAD(&controller.ep[0].queue);
+ controller.ep[0].req_primed = false;
controller.gadget.ep0 = &controller.ep[0].ep;
INIT_LIST_HEAD(&controller.gadget.ep0->ep_list);
@@ -708,6 +766,8 @@ static int ci_udc_probe(void)
for (i = 1; i < NUM_ENDPOINTS; i++) {
memcpy(&controller.ep[i].ep, &ci_ep_init[1],
sizeof(*ci_ep_init));
+ INIT_LIST_HEAD(&controller.ep[i].queue);
+ controller.ep[i].req_primed = false;
list_add_tail(&controller.ep[i].ep.ep_list,
&controller.gadget.ep_list);
}
diff --git a/drivers/usb/gadget/ci_udc.h b/drivers/usb/gadget/ci_udc.h
index 4425fd9..23cff56 100644
--- a/drivers/usb/gadget/ci_udc.h
+++ b/drivers/usb/gadget/ci_udc.h
@@ -77,15 +77,22 @@ struct ci_udc {
#define CTRL_TXT_BULK (2 << 18)
#define CTRL_RXT_BULK (2 << 2)
+struct ci_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* Bounce buffer allocated if needed to align the transfer */
+ uint8_t *b_buf;
+ uint32_t b_len;
+ /* Buffer for the current transfer. Either req.buf/len or b_buf/len */
+ uint8_t *hw_buf;
+ uint32_t hw_len;
+};
+
struct ci_ep {
struct usb_ep ep;
struct list_head queue;
+ bool req_primed;
const struct usb_endpoint_descriptor *desc;
-
- struct usb_request req;
- uint8_t *b_buf;
- uint32_t b_len;
- uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN);
};
struct ci_drv {
diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
index 1b1e179..859fe82 100644
--- a/drivers/usb/gadget/f_dfu.c
+++ b/drivers/usb/gadget/f_dfu.c
@@ -175,10 +175,17 @@ static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req)
req->length, f_dfu->blk_seq_num);
}
+static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu)
+{
+ return dfu->poll_timeout ? dfu->poll_timeout(dfu) :
+ DFU_MANIFEST_POLL_TIMEOUT;
+}
+
static void handle_getstatus(struct usb_request *req)
{
struct dfu_status *dstat = (struct dfu_status *)req->buf;
struct f_dfu *f_dfu = req->context;
+ struct dfu_entity *dfu = dfu_get_entity(f_dfu->altsetting);
dfu_set_poll_timeout(dstat, 0);
@@ -191,7 +198,8 @@ static void handle_getstatus(struct usb_request *req)
f_dfu->dfu_state = DFU_STATE_dfuMANIFEST;
break;
case DFU_STATE_dfuMANIFEST:
- dfu_set_poll_timeout(dstat, DFU_MANIFEST_POLL_TIMEOUT);
+ dfu_set_poll_timeout(dstat, dfu_get_manifest_timeout(dfu));
+ break;
default:
break;
}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
new file mode 100644
index 0000000..9dd85b6
--- /dev/null
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -0,0 +1,513 @@
+/*
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Copyright 2014 Linaro, Ltd.
+ * Rob Herring <robh@kernel.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
+#include <linux/compiler.h>
+#include <version.h>
+#include <g_dnl.h>
+
+#define FASTBOOT_VERSION "0.4"
+
+#define FASTBOOT_INTERFACE_CLASS 0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
+#define FASTBOOT_INTERFACE_PROTOCOL 0x03
+
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
+
+/* The 64 defined bytes plus \0 */
+#define RESPONSE_LEN (64 + 1)
+
+#define EP_BUFFER_SIZE 4096
+
+struct f_fastboot {
+ struct usb_function usb_function;
+
+ /* IN/OUT EP's and correspoinding requests */
+ struct usb_ep *in_ep, *out_ep;
+ struct usb_request *in_req, *out_req;
+};
+
+static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
+{
+ return container_of(f, struct f_fastboot, usb_function);
+}
+
+static struct f_fastboot *fastboot_func;
+static unsigned int download_size;
+static unsigned int download_bytes;
+
+static struct usb_endpoint_descriptor fs_ep_in = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+ .bInterval = 0x00,
+};
+
+static struct usb_endpoint_descriptor fs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
+ .bInterval = 0x00,
+};
+
+static struct usb_endpoint_descriptor hs_ep_out = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
+ .bInterval = 0x00,
+};
+
+static struct usb_interface_descriptor interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
+ .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
+ .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
+};
+
+static struct usb_descriptor_header *fb_runtime_descs[] = {
+ (struct usb_descriptor_header *)&interface_desc,
+ (struct usb_descriptor_header *)&fs_ep_in,
+ (struct usb_descriptor_header *)&hs_ep_out,
+ NULL,
+};
+
+/*
+ * static strings, in UTF-8
+ */
+static const char fastboot_name[] = "Android Fastboot";
+
+static struct usb_string fastboot_string_defs[] = {
+ [0].s = fastboot_name,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_fastboot = {
+ .language = 0x0409, /* en-us */
+ .strings = fastboot_string_defs,
+};
+
+static struct usb_gadget_strings *fastboot_strings[] = {
+ &stringtab_fastboot,
+ NULL,
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
+
+static void fastboot_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ int status = req->status;
+ if (!status)
+ return;
+ printf("status: %d ep '%s' trans: %d\n", status, ep->name, req->actual);
+}
+
+static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ int id;
+ struct usb_gadget *gadget = c->cdev->gadget;
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ /* DYNAMIC interface numbers assignments */
+ id = usb_interface_id(c, f);
+ if (id < 0)
+ return id;
+ interface_desc.bInterfaceNumber = id;
+
+ id = usb_string_id(c->cdev);
+ if (id < 0)
+ return id;
+ fastboot_string_defs[0].id = id;
+ interface_desc.iInterface = id;
+
+ f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
+ if (!f_fb->in_ep)
+ return -ENODEV;
+ f_fb->in_ep->driver_data = c->cdev;
+
+ f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
+ if (!f_fb->out_ep)
+ return -ENODEV;
+ f_fb->out_ep->driver_data = c->cdev;
+
+ hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
+
+ return 0;
+}
+
+static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ memset(fastboot_func, 0, sizeof(*fastboot_func));
+}
+
+static void fastboot_disable(struct usb_function *f)
+{
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ usb_ep_disable(f_fb->out_ep);
+ usb_ep_disable(f_fb->in_ep);
+
+ if (f_fb->out_req) {
+ free(f_fb->out_req->buf);
+ usb_ep_free_request(f_fb->out_ep, f_fb->out_req);
+ f_fb->out_req = NULL;
+ }
+ if (f_fb->in_req) {
+ free(f_fb->in_req->buf);
+ usb_ep_free_request(f_fb->in_ep, f_fb->in_req);
+ f_fb->in_req = NULL;
+ }
+}
+
+static struct usb_request *fastboot_start_ep(struct usb_ep *ep)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, 0);
+ if (!req)
+ return NULL;
+
+ req->length = EP_BUFFER_SIZE;
+ req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+
+ memset(req->buf, 0, req->length);
+ return req;
+}
+
+static int fastboot_set_alt(struct usb_function *f,
+ unsigned interface, unsigned alt)
+{
+ int ret;
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ struct f_fastboot *f_fb = func_to_fastboot(f);
+
+ debug("%s: func: %s intf: %d alt: %d\n",
+ __func__, f->name, interface, alt);
+
+ /* make sure we don't enable the ep twice */
+ if (gadget->speed == USB_SPEED_HIGH)
+ ret = usb_ep_enable(f_fb->out_ep, &hs_ep_out);
+ else
+ ret = usb_ep_enable(f_fb->out_ep, &fs_ep_out);
+ if (ret) {
+ puts("failed to enable out ep\n");
+ return ret;
+ }
+
+ f_fb->out_req = fastboot_start_ep(f_fb->out_ep);
+ if (!f_fb->out_req) {
+ puts("failed to alloc out req\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ f_fb->out_req->complete = rx_handler_command;
+
+ ret = usb_ep_enable(f_fb->in_ep, &fs_ep_in);
+ if (ret) {
+ puts("failed to enable in ep\n");
+ goto err;
+ }
+
+ f_fb->in_req = fastboot_start_ep(f_fb->in_ep);
+ if (!f_fb->in_req) {
+ puts("failed alloc req in\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ f_fb->in_req->complete = fastboot_complete;
+
+ ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ fastboot_disable(f);
+ return ret;
+}
+
+static int fastboot_add(struct usb_configuration *c)
+{
+ struct f_fastboot *f_fb = fastboot_func;
+ int status;
+
+ debug("%s: cdev: 0x%p\n", __func__, c->cdev);
+
+ if (!f_fb) {
+ f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
+ if (!f_fb)
+ return -ENOMEM;
+
+ fastboot_func = f_fb;
+ memset(f_fb, 0, sizeof(*f_fb));
+ }
+
+ f_fb->usb_function.name = "f_fastboot";
+ f_fb->usb_function.hs_descriptors = fb_runtime_descs;
+ f_fb->usb_function.bind = fastboot_bind;
+ f_fb->usb_function.unbind = fastboot_unbind;
+ f_fb->usb_function.set_alt = fastboot_set_alt;
+ f_fb->usb_function.disable = fastboot_disable;
+ f_fb->usb_function.strings = fastboot_strings;
+
+ status = usb_add_function(c, &f_fb->usb_function);
+ if (status) {
+ free(f_fb);
+ fastboot_func = f_fb;
+ }
+
+ return status;
+}
+DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
+
+int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
+{
+ struct usb_request *in_req = fastboot_func->in_req;
+ int ret;
+
+ memcpy(in_req->buf, buffer, buffer_size);
+ in_req->length = buffer_size;
+ ret = usb_ep_queue(fastboot_func->in_ep, in_req, 0);
+ if (ret)
+ printf("Error %d on queue\n", ret);
+ return 0;
+}
+
+static int fastboot_tx_write_str(const char *buffer)
+{
+ return fastboot_tx_write(buffer, strlen(buffer));
+}
+
+static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
+{
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_func->in_req->complete = compl_do_reset;
+ fastboot_tx_write_str("OKAY");
+}
+
+static int strcmp_l1(const char *s1, const char *s2)
+{
+ if (!s1 || !s2)
+ return -1;
+ return strncmp(s1, s2, strlen(s1));
+}
+
+static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+ const char *s;
+
+ strcpy(response, "OKAY");
+ strsep(&cmd, ":");
+ if (!cmd) {
+ fastboot_tx_write_str("FAILmissing var");
+ return;
+ }
+
+ if (!strcmp_l1("version", cmd)) {
+ strncat(response, FASTBOOT_VERSION, sizeof(response));
+ } else if (!strcmp_l1("bootloader-version", cmd)) {
+ strncat(response, U_BOOT_VERSION, sizeof(response));
+ } else if (!strcmp_l1("downloadsize", cmd)) {
+ char str_num[12];
+
+ sprintf(str_num, "%08x", CONFIG_USB_FASTBOOT_BUF_SIZE);
+ strncat(response, str_num, sizeof(response));
+ } else if (!strcmp_l1("serialno", cmd)) {
+ s = getenv("serial#");
+ if (s)
+ strncat(response, s, sizeof(response));
+ else
+ strcpy(response, "FAILValue not set");
+ } else {
+ strcpy(response, "FAILVariable not implemented");
+ }
+ fastboot_tx_write_str(response);
+}
+
+static unsigned int rx_bytes_expected(void)
+{
+ int rx_remain = download_size - download_bytes;
+ if (rx_remain < 0)
+ return 0;
+ if (rx_remain > EP_BUFFER_SIZE)
+ return EP_BUFFER_SIZE;
+ return rx_remain;
+}
+
+#define BYTES_PER_DOT 0x20000
+static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
+{
+ char response[RESPONSE_LEN];
+ unsigned int transfer_size = download_size - download_bytes;
+ const unsigned char *buffer = req->buf;
+ unsigned int buffer_size = req->actual;
+
+ if (req->status != 0) {
+ printf("Bad status: %d\n", req->status);
+ return;
+ }
+
+ if (buffer_size < transfer_size)
+ transfer_size = buffer_size;
+
+ memcpy((void *)CONFIG_USB_FASTBOOT_BUF_ADDR + download_bytes,
+ buffer, transfer_size);
+
+ download_bytes += transfer_size;
+
+ /* Check if transfer is done */
+ if (download_bytes >= download_size) {
+ /*
+ * Reset global transfer variable, keep download_bytes because
+ * it will be used in the next possible flashing command
+ */
+ download_size = 0;
+ req->complete = rx_handler_command;
+ req->length = EP_BUFFER_SIZE;
+
+ sprintf(response, "OKAY");
+ fastboot_tx_write_str(response);
+
+ printf("\ndownloading of %d bytes finished\n", download_bytes);
+ } else {
+ req->length = rx_bytes_expected();
+ if (req->length < ep->maxpacket)
+ req->length = ep->maxpacket;
+ }
+
+ if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
+ putc('.');
+ if (!(download_bytes % (74 * BYTES_PER_DOT)))
+ putc('\n');
+ }
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+}
+
+static void cb_download(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+ char response[RESPONSE_LEN];
+
+ strsep(&cmd, ":");
+ download_size = simple_strtoul(cmd, NULL, 16);
+ download_bytes = 0;
+
+ printf("Starting download of %d bytes\n", download_size);
+
+ if (0 == download_size) {
+ sprintf(response, "FAILdata invalid size");
+ } else if (download_size > CONFIG_USB_FASTBOOT_BUF_SIZE) {
+ download_size = 0;
+ sprintf(response, "FAILdata too large");
+ } else {
+ sprintf(response, "DATA%08x", download_size);
+ req->complete = rx_handler_dl_image;
+ req->length = rx_bytes_expected();
+ if (req->length < ep->maxpacket)
+ req->length = ep->maxpacket;
+ }
+ fastboot_tx_write_str(response);
+}
+
+static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ char boot_addr_start[12];
+ char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+
+ puts("Booting kernel..\n");
+
+ sprintf(boot_addr_start, "0x%lx", load_addr);
+ do_bootm(NULL, 0, 2, bootm_args);
+
+ /* This only happens if image is somehow faulty so we start over */
+ do_reset(NULL, 0, 0, NULL);
+}
+
+static void cb_boot(struct usb_ep *ep, struct usb_request *req)
+{
+ fastboot_func->in_req->complete = do_bootm_on_complete;
+ fastboot_tx_write_str("OKAY");
+}
+
+struct cmd_dispatch_info {
+ char *cmd;
+ void (*cb)(struct usb_ep *ep, struct usb_request *req);
+};
+
+static const struct cmd_dispatch_info cmd_dispatch_info[] = {
+ {
+ .cmd = "reboot",
+ .cb = cb_reboot,
+ }, {
+ .cmd = "getvar:",
+ .cb = cb_getvar,
+ }, {
+ .cmd = "download:",
+ .cb = cb_download,
+ }, {
+ .cmd = "boot",
+ .cb = cb_boot,
+ },
+};
+
+static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmdbuf = req->buf;
+ void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
+ if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
+ func_cb = cmd_dispatch_info[i].cb;
+ break;
+ }
+ }
+
+ if (!func_cb)
+ fastboot_tx_write_str("FAILunknown command");
+ else
+ func_cb(ep, req);
+
+ if (req->status == 0) {
+ *cmdbuf = '\0';
+ req->actual = 0;
+ usb_ep_queue(ep, req, 0);
+ }
+}
diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c
index feef9e4..28f215e 100644
--- a/drivers/usb/gadget/f_thor.c
+++ b/drivers/usb/gadget/f_thor.c
@@ -219,21 +219,15 @@ static int download_tail(long long int left, int cnt)
}
/*
- * To store last "packet" DFU storage backend requires dfu_write with
- * size parameter equal to 0
+ * To store last "packet" or write file from buffer to filesystem
+ * DFU storage backend requires dfu_flush
*
* This also frees memory malloc'ed by dfu_get_buf(), so no explicit
* need fo call dfu_free_buf() is needed.
*/
- ret = dfu_write(dfu_entity, transfer_buffer, 0, cnt);
- if (ret)
- error("DFU write failed [%d] cnt: %d", ret, cnt);
-
ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt);
- if (ret) {
+ if (ret)
error("DFU flush failed!");
- return ret;
- }
return ret;
}
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 7430074..02803df 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -311,11 +311,7 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
/* Number of buffers we will use. 2 is enough for double-buffering */
-#ifndef CONFIG_CI_UDC
#define FSG_NUM_BUFFERS 2
-#else
-#define FSG_NUM_BUFFERS 1 /* ci_udc only allows 1 req per ep at present */
-#endif
/* Default size of buffer length. */
#define FSG_BUFLEN ((u32)16384)
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 6cb4d98..45062e6 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -104,15 +104,20 @@ int ehci_hcd_init(int index, enum usb_init_type init,
if (!strncmp(phy_type, "utmi", 4)) {
#if defined(CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY)
- setbits_be32(&ehci->control, PHY_CLK_SEL_UTMI);
- setbits_be32(&ehci->control, UTMI_PHY_EN);
+ clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+ PHY_CLK_SEL_UTMI);
+ clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+ UTMI_PHY_EN);
udelay(1000); /* delay required for PHY Clk to appear */
#endif
out_le32(&(*hcor)->or_portsc[0], PORT_PTS_UTMI);
- setbits_be32(&ehci->control, USB_EN);
+ clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+ USB_EN);
} else {
- setbits_be32(&ehci->control, PHY_CLK_SEL_ULPI);
- clrsetbits_be32(&ehci->control, UTMI_PHY_EN, USB_EN);
+ clrsetbits_be32(&ehci->control, CONTROL_REGISTER_W1C_MASK,
+ PHY_CLK_SEL_ULPI);
+ clrsetbits_be32(&ehci->control, UTMI_PHY_EN |
+ CONTROL_REGISTER_W1C_MASK, USB_EN);
udelay(1000); /* delay required for PHY Clk to appear */
if (!usb_phy_clk_valid(ehci))
return -EINVAL;
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 38db18e..33e5ea9 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -69,6 +69,7 @@ struct fdt_usb {
unsigned enabled:1; /* 1 to enable, 0 to disable */
unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */
unsigned initialized:1; /* has this port already been initialized? */
+ enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
enum periph_id periph_id;/* peripheral id */
struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */
@@ -237,29 +238,31 @@ int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
return PORTSC_PSPD(reg);
}
-/* Put the port into host mode */
-static void set_host_mode(struct fdt_usb *config)
+/* Set up VBUS for host/device mode */
+static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
{
/*
- * If we are an OTG port, check if remote host is driving VBus and
- * bail out in this case.
+ * If we are an OTG port initializing in host mode,
+ * check if remote host is driving VBus and bail out in this case.
*/
- if (config->dr_mode == DR_MODE_OTG &&
- (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))
+ if (init == USB_INIT_HOST &&
+ config->dr_mode == DR_MODE_OTG &&
+ (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS)) {
+ printf("tegrausb: VBUS input active; not enabling as host\n");
return;
+ }
- /*
- * If not driving, we set the GPIO to enable VBUS. We assume
- * that the pinmux is set up correctly for this.
- */
if (fdt_gpio_isvalid(&config->vbus_gpio)) {
+ int vbus_value;
+
fdtdec_setup_gpio(&config->vbus_gpio);
- gpio_direction_output(config->vbus_gpio.gpio,
- (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ?
- 0 : 1);
- debug("set_host_mode: GPIO %d %s\n", config->vbus_gpio.gpio,
- (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ?
- "low" : "high");
+
+ vbus_value = (init == USB_INIT_HOST) ^
+ !!(config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW);
+ gpio_direction_output(config->vbus_gpio.gpio, vbus_value);
+
+ debug("set_up_vbus: GPIO %d %d\n", config->vbus_gpio.gpio,
+ vbus_value);
}
}
@@ -293,10 +296,44 @@ static const unsigned *get_pll_timing(void)
return timing;
}
+/* select the PHY to use with a USB controller */
+static void init_phy_mux(struct fdt_usb *config, uint pts,
+ enum usb_init_type init)
+{
+ struct usb_ctlr *usbctlr = config->reg;
+
+#if defined(CONFIG_TEGRA20)
+ if (config->periph_id == PERIPH_ID_USBD) {
+ clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
+ PTS_UTMI << PTS1_SHIFT);
+ clrbits_le32(&usbctlr->port_sc1, STS1);
+ } else {
+ clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
+ PTS_UTMI << PTS_SHIFT);
+ clrbits_le32(&usbctlr->port_sc1, STS);
+ }
+#else
+ /* Set to Host mode (if applicable) after Controller Reset was done */
+ clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
+ (init == USB_INIT_HOST) ? USBMODE_CM_HC : 0);
+ /*
+ * Select PHY interface after setting host mode.
+ * For device mode, the ordering requirement is not an issue, since
+ * only the first USB controller supports device mode, and that USB
+ * controller can only talk to a UTMI PHY, so the PHY selection is
+ * already made at reset time, so this write is a no-op.
+ */
+ clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
+ pts << PTS_SHIFT);
+ clrbits_le32(&usbctlr->hostpc1_devlc, STS);
+#endif
+}
+
/* set up the UTMI USB controller with the parameters provided */
-static int init_utmi_usb_controller(struct fdt_usb *config)
+static int init_utmi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
- u32 val;
+ u32 b_sess_valid_mask, val;
int loop_count;
const unsigned *timing;
struct usb_ctlr *usbctlr = config->reg;
@@ -314,6 +351,10 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
/* Follow the crystal clock disable by >100ns delay */
udelay(1);
+ b_sess_valid_mask = (VBUS_B_SESS_VLD_SW_VALUE | VBUS_B_SESS_VLD_SW_EN);
+ clrsetbits_le32(&usbctlr->phy_vbus_sensors, b_sess_valid_mask,
+ (init == USB_INIT_DEVICE) ? b_sess_valid_mask : 0);
+
/*
* To Use the A Session Valid for cable detection logic, VBUS_WAKEUP
* mux must be switched to actually use a_sess_vld threshold.
@@ -485,21 +526,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
/* Select UTMI parallel interface */
-#if defined(CONFIG_TEGRA20)
- if (config->periph_id == PERIPH_ID_USBD) {
- clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
- PTS_UTMI << PTS1_SHIFT);
- clrbits_le32(&usbctlr->port_sc1, STS1);
- } else {
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32(&usbctlr->port_sc1, STS);
- }
-#else
- clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32(&usbctlr->hostpc1_devlc, STS);
-#endif
+ init_phy_mux(config, PTS_UTMI, init);
/* Deassert power down state */
clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN |
@@ -529,7 +556,8 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
#endif
/* set up the ULPI USB controller with the parameters provided */
-static int init_ulpi_usb_controller(struct fdt_usb *config)
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
u32 val;
int loop_count;
@@ -557,13 +585,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config)
ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
/* Select ULPI parallel interface */
-#if defined(CONFIG_TEGRA20)
- clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
- PTS_ULPI << PTS_SHIFT);
-#else
- clrsetbits_le32(&usbctlr->hostpc1_devlc, PTS_MASK,
- PTS_ULPI << PTS_SHIFT);
-#endif
+ init_phy_mux(config, PTS_ULPI, init);
/* enable ULPI transceiver */
setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB);
@@ -612,7 +634,8 @@ static int init_ulpi_usb_controller(struct fdt_usb *config)
return 0;
}
#else
-static int init_ulpi_usb_controller(struct fdt_usb *config)
+static int init_ulpi_usb_controller(struct fdt_usb *config,
+ enum usb_init_type init)
{
printf("No code to set up ULPI controller, please enable"
"CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT");
@@ -765,42 +788,66 @@ int ehci_hcd_init(int index, enum usb_init_type init,
config = &port[index];
+ switch (init) {
+ case USB_INIT_HOST:
+ switch (config->dr_mode) {
+ case DR_MODE_HOST:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for host mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ case USB_INIT_DEVICE:
+ if (config->periph_id != PERIPH_ID_USBD) {
+ printf("tegrausb: Device mode only supported on first USB controller\n");
+ return -1;
+ }
+ if (!config->utmi) {
+ printf("tegrausb: Device mode only supported with UTMI PHY\n");
+ return -1;
+ }
+ switch (config->dr_mode) {
+ case DR_MODE_DEVICE:
+ case DR_MODE_OTG:
+ break;
+ default:
+ printf("tegrausb: Invalid dr_mode %d for device mode\n",
+ config->dr_mode);
+ return -1;
+ }
+ break;
+ default:
+ printf("tegrausb: Unknown USB_INIT_* %d\n", init);
+ return -1;
+ }
+
/* skip init, if the port is already initialized */
- if (config->initialized)
+ if (config->initialized && config->init_type == init)
goto success;
- if (config->utmi && init_utmi_usb_controller(config)) {
+ if (config->utmi && init_utmi_usb_controller(config, init)) {
printf("tegrausb: Cannot init port %d\n", index);
return -1;
}
- if (config->ulpi && init_ulpi_usb_controller(config)) {
+ if (config->ulpi && init_ulpi_usb_controller(config, init)) {
printf("tegrausb: Cannot init port %d\n", index);
return -1;
}
- set_host_mode(config);
+ set_up_vbus(config, init);
config->initialized = 1;
+ config->init_type = init;
success:
usbctlr = config->reg;
*hccr = (struct ehci_hccr *)&usbctlr->cap_length;
*hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
- if (controller->has_hostpc) {
- /* Set to Host mode after Controller Reset was done */
- clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
- USBMODE_CM_HC);
- /* Select UTMI parallel interface after setting host mode */
- if (config->utmi) {
- clrsetbits_le32((char *)&usbctlr->usb_cmd +
- HOSTPC1_DEVLC, PTS_MASK,
- PTS_UTMI << PTS_SHIFT);
- clrbits_le32((char *)&usbctlr->usb_cmd +
- HOSTPC1_DEVLC, STS);
- }
- }
return 0;
}
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index 6599d38..8c3b0a1 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -576,6 +576,10 @@ static void ep0_txstate(struct musb *musb)
} else
request = NULL;
+ /* send it out, triggering a "txpktrdy cleared" irq */
+ musb_ep_select(musb->mregs, 0);
+ musb_writew(regs, MUSB_CSR0, csr);
+
/* report completions as soon as the fifo's loaded; there's no
* win in waiting till this last packet gets acked. (other than
* very precise fault reporting, needed by USB TMC; possible with
@@ -588,10 +592,6 @@ static void ep0_txstate(struct musb *musb)
return;
musb->ackpend = 0;
}
-
- /* send it out, triggering a "txpktrdy cleared" irq */
- musb_ep_select(musb->mregs, 0);
- musb_writew(regs, MUSB_CSR0, csr);
}
/*
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index c527029..945f35d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
obj-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o
obj-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
+obj-$(CONFIG_VIDEO_IMX25LCDC) += imx25lcdc.o videomodes.o
obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
obj-$(CONFIG_VIDEO_MB86R0xGDC) += mb86r0xgdc.o videomodes.o
obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
diff --git a/drivers/video/imx25lcdc.c b/drivers/video/imx25lcdc.c
new file mode 100644
index 0000000..ef5767b
--- /dev/null
+++ b/drivers/video/imx25lcdc.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2011
+ * Matthias Weisser <weisserm@arcor.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * imx25lcdc.c - Graphic interface for i.MX25 lcd controller
+ */
+
+#include <common.h>
+
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <video_fb.h>
+#include "videomodes.h"
+
+/*
+ * 4MB (at the end of system RAM)
+ */
+#define VIDEO_MEM_SIZE 0x400000
+
+#define FB_SYNC_CLK_INV (1<<16) /* pixel clock inverted */
+
+/*
+ * Graphic Device
+ */
+static GraphicDevice imx25fb;
+
+void *video_hw_init(void)
+{
+ struct lcdc_regs *lcdc = (struct lcdc_regs *)IMX_LCDC_BASE;
+ struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
+ GraphicDevice *pGD = &imx25fb;
+ char *s;
+ u32 *videomem;
+
+ memset(pGD, 0, sizeof(GraphicDevice));
+
+ pGD->gdfIndex = GDF_16BIT_565RGB;
+ pGD->gdfBytesPP = 2;
+ pGD->memSize = VIDEO_MEM_SIZE;
+ pGD->frameAdrs = PHYS_SDRAM + PHYS_SDRAM_SIZE - VIDEO_MEM_SIZE;
+
+ videomem = (u32 *)pGD->frameAdrs;
+
+ s = getenv("videomode");
+ if (s != NULL) {
+ struct ctfb_res_modes var_mode;
+ u32 lsr, lpcr, lhcr, lvcr;
+ unsigned long div;
+ int bpp;
+
+ /* Disable all clocks of the LCDC */
+ writel(readl(&ccm->cgr0) & ~((1<<7) | (1<<24)), &ccm->cgr0);
+ writel(readl(&ccm->cgr1) & ~(1<<29), &ccm->cgr1);
+
+ bpp = video_get_params(&var_mode, s);
+
+ if (bpp == 0) {
+ var_mode.xres = 320;
+ var_mode.yres = 240;
+ var_mode.pixclock = 154000;
+ var_mode.left_margin = 68;
+ var_mode.right_margin = 20;
+ var_mode.upper_margin = 4;
+ var_mode.lower_margin = 18;
+ var_mode.hsync_len = 40;
+ var_mode.vsync_len = 6;
+ var_mode.sync = 0;
+ var_mode.vmode = 0;
+ }
+
+ /* Fill memory with white */
+ memset(videomem, 0xFF, var_mode.xres * var_mode.yres * 2);
+
+ imx25fb.winSizeX = var_mode.xres;
+ imx25fb.winSizeY = var_mode.yres;
+
+ /* LCD base clock is 66.6MHZ. We do calculations in kHz */
+ div = 66000 / (1000000000L / var_mode.pixclock);
+ if (div > 63)
+ div = 63;
+ if (0 == div)
+ div = 1;
+
+ lsr = ((var_mode.xres / 16) << 20) |
+ var_mode.yres;
+ lpcr = (1 << 31) |
+ (1 << 30) |
+ (5 << 25) |
+ (1 << 23) |
+ (1 << 22) |
+ (1 << 19) |
+ (1 << 7) |
+ div;
+ lhcr = (var_mode.right_margin << 0) |
+ (var_mode.left_margin << 8) |
+ (var_mode.hsync_len << 26);
+
+ lvcr = (var_mode.lower_margin << 0) |
+ (var_mode.upper_margin << 8) |
+ (var_mode.vsync_len << 26);
+
+ writel((uint32_t)videomem, &lcdc->lssar);
+ writel(lsr, &lcdc->lsr);
+ writel(var_mode.xres * 2 / 4, &lcdc->lvpwr);
+ writel(lpcr, &lcdc->lpcr);
+ writel(lhcr, &lcdc->lhcr);
+ writel(lvcr, &lcdc->lvcr);
+ writel(0x00040060, &lcdc->ldcr);
+
+ writel(0xA90300, &lcdc->lpccr);
+
+ /* Ensable all clocks of the LCDC */
+ writel(readl(&ccm->cgr0) | ((1<<7) | (1<<24)), &ccm->cgr0);
+ writel(readl(&ccm->cgr1) | (1<<29), &ccm->cgr1);
+ }
+
+ return pGD;
+}