[U-Boot] [PATCH 1/5] Davinci DM355 Build Error Fix

Fixed the build process that is broken by the recent changes in DM9000 network driver with __io(p) configuration option
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- include/configs/davinci_dm355evm.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/include/configs/davinci_dm355evm.h b/include/configs/davinci_dm355evm.h index 37011c0..3828a08 100644 --- a/include/configs/davinci_dm355evm.h +++ b/include/configs/davinci_dm355evm.h @@ -57,6 +57,7 @@ #define DM9000_IO CONFIG_DM9000_BASE #define DM9000_DATA (CONFIG_DM9000_BASE + 2) #define CONFIG_NET_MULTI +#define __io(p) (p)
/* I2C */ #define CONFIG_HARD_I2C

Added support for MMC/SD cards for Davinci. This feature is enabled by CONFIG_DAVINCI_MMC and is dependant on CONFIG_MMC and CONFIG_GENERIC_MMC options. This is tested on DM355 and DM365 EVMs with both the available mmc controllers.
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- arch/arm/include/asm/arch-davinci/sdmmc_defs.h | 175 +++++++++++ board/davinci/dm355evm/dm355evm.c | 44 +++ board/davinci/dm365evm/dm365evm.c | 51 +++ drivers/mmc/Makefile | 1 + drivers/mmc/davinci_mmc.c | 399 ++++++++++++++++++++++++ include/configs/davinci_dm355evm.h | 21 +- include/configs/davinci_dm365evm.h | 13 + 7 files changed, 700 insertions(+), 4 deletions(-) create mode 100644 arch/arm/include/asm/arch-davinci/sdmmc_defs.h create mode 100644 drivers/mmc/davinci_mmc.c
diff --git a/arch/arm/include/asm/arch-davinci/sdmmc_defs.h b/arch/arm/include/asm/arch-davinci/sdmmc_defs.h new file mode 100644 index 0000000..a9118f9 --- /dev/null +++ b/arch/arm/include/asm/arch-davinci/sdmmc_defs.h @@ -0,0 +1,175 @@ +/* + * Davinci MMC Controller Defines - Based on Linux davinci_mmc.c + * + * Copyright (C) Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SDMMC_DEFS_H_ +#define _SDMMC_DEFS_H_ + +#include <asm/arch/hardware.h> + +/* MMC Control Reg fields */ +#define MMCCTL_DATRST (1 << 0) +#define MMCCTL_CMDRST (1 << 1) +#define MMCCTL_WIDTH_4_BIT (1 << 2) +#define MMCCTL_DATEG_DISABLED (0 << 6) +#define MMCCTL_DATEG_RISING (1 << 6) +#define MMCCTL_DATEG_FALLING (2 << 6) +#define MMCCTL_DATEG_BOTH (3 << 6) +#define MMCCTL_PERMDR_LE (0 << 9) +#define MMCCTL_PERMDR_BE (1 << 9) +#define MMCCTL_PERMDX_LE (0 << 10) +#define MMCCTL_PERMDX_BE (1 << 10) + +/* MMC Clock Control Reg fields */ +#define MMCCLK_CLKEN (1 << 8) +#define MMCCLK_CLKRT_MASK (0xFF << 0) + +/* MMC Status Reg0 fields */ +#define MMCST0_DATDNE (1 << 0) +#define MMCST0_BSYDNE (1 << 1) +#define MMCST0_RSPDNE (1 << 2) +#define MMCST0_TOUTRD (1 << 3) +#define MMCST0_TOUTRS (1 << 4) +#define MMCST0_CRCWR (1 << 5) +#define MMCST0_CRCRD (1 << 6) +#define MMCST0_CRCRS (1 << 7) +#define MMCST0_DXRDY (1 << 9) +#define MMCST0_DRRDY (1 << 10) +#define MMCST0_DATED (1 << 11) +#define MMCST0_TRNDNE (1 << 12) + +#define MMCST0_ERR_MASK (0x00F8) + +/* MMC Status Reg1 fields */ +#define MMCST1_BUSY (1 << 0) +#define MMCST1_CLKSTP (1 << 1) +#define MMCST1_DXEMP (1 << 2) +#define MMCST1_DRFUL (1 << 3) +#define MMCST1_DAT3ST (1 << 4) +#define MMCST1_FIFOEMP (1 << 5) +#define MMCST1_FIFOFUL (1 << 6) + +/* MMC INT Mask Reg fields */ +#define MMCIM_EDATDNE (1 << 0) +#define MMCIM_EBSYDNE (1 << 1) +#define MMCIM_ERSPDNE (1 << 2) +#define MMCIM_ETOUTRD (1 << 3) +#define MMCIM_ETOUTRS (1 << 4) +#define MMCIM_ECRCWR (1 << 5) +#define MMCIM_ECRCRD (1 << 6) +#define MMCIM_ECRCRS (1 << 7) +#define MMCIM_EDXRDY (1 << 9) +#define MMCIM_EDRRDY (1 << 10) +#define MMCIM_EDATED (1 << 11) +#define MMCIM_ETRNDNE (1 << 12) + +#define MMCIM_MASKALL (0xFFFFFFFF) + +/* MMC Resp Tout Reg fields */ +#define MMCTOR_TOR_MASK (0xFF) /* dont write to reg, | it */ +#define MMCTOR_TOD_20_16_SHIFT (8) + +/* MMC Data Read Tout Reg fields */ +#define MMCTOD_TOD_0_15_MASK (0xFFFF) + +/* MMC Block len Reg fields */ +#define MMCBLEN_BLEN_MASK (0xFFF) + +/* MMC Num Blocks Reg fields */ +#define MMCNBLK_NBLK_MASK (0xFFFF) +#define MMCNBLK_NBLK_MAX (0xFFFF) + +/* MMC Num Blocks Counter Reg fields */ +#define MMCNBLC_NBLC_MASK (0xFFFF) + +/* MMC Cmd Reg fields */ +#define MMCCMD_CMD_MASK (0x3F) +#define MMCCMD_PPLEN (1 << 7) +#define MMCCMD_BSYEXP (1 << 8) +#define MMCCMD_RSPFMT_NONE (0 << 9) +#define MMCCMD_RSPFMT_R1567 (1 << 9) +#define MMCCMD_RSPFMT_R2 (2 << 9) +#define MMCCMD_RSPFMT_R3 (3 << 9) +#define MMCCMD_DTRW (1 << 11) +#define MMCCMD_STRMTP (1 << 12) +#define MMCCMD_WDATX (1 << 13) +#define MMCCMD_INITCK (1 << 14) +#define MMCCMD_DCLR (1 << 15) +#define MMCCMD_DMATRIG (1 << 16) + +/* FIFO control Reg fields */ +#define MMCFIFOCTL_FIFORST (1 << 0) +#define MMCFIFOCTL_FIFODIR (1 << 1) +#define MMCFIFOCTL_FIFOLEV (1 << 2) +#define MMCFIFOCTL_ACCWD_4 (0 << 3) /* access width of 4 bytes */ +#define MMCFIFOCTL_ACCWD_3 (1 << 3) /* access width of 3 bytes */ +#define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */ +#define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */ + +/* Davinci MMC Register definitions */ +struct davinci_mmc_regs { + dv_reg mmcctl; + dv_reg mmcclk; + dv_reg mmcst0; + dv_reg mmcst1; + dv_reg mmcim; + dv_reg mmctor; + dv_reg mmctod; + dv_reg mmcblen; + dv_reg mmcnblk; + dv_reg mmcnblc; + dv_reg mmcdrr; + dv_reg mmcdxr; + dv_reg mmccmd; + dv_reg mmcarghl; + dv_reg mmcrsp01; + dv_reg mmcrsp23; + dv_reg mmcrsp45; + dv_reg mmcrsp67; + dv_reg mmcdrsp; + dv_reg mmcetok; + dv_reg mmccidx; + dv_reg mmcckc; + dv_reg mmctorc; + dv_reg mmctodc; + dv_reg mmcblnc; + dv_reg sdioctl; + dv_reg sdiost0; + dv_reg sdioien; + dv_reg sdioist; + dv_reg mmcfifoctl; +}; + +/* Davinci MMC board definitions */ +struct davinci_mmc { + struct davinci_mmc_regs *reg_base; /* Register base address */ + uint input_clk; /* Input clock to MMC controller */ + uint host_caps; /* Host capabilities */ + uint voltages; /* Host supported voltages */ + uint version; /* MMC Controller version */ +}; + +enum { + MMC_CTLR_VERSION_1 = 0, /* DM644x and DM355 */ + MMC_CTLR_VERSION_2, /* DA830 */ +}; + +int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host); + +#endif /* _SDMMC_DEFS_H */ diff --git a/board/davinci/dm355evm/dm355evm.c b/board/davinci/dm355evm/dm355evm.c index 87f284c..8d16db8 100644 --- a/board/davinci/dm355evm/dm355evm.c +++ b/board/davinci/dm355evm/dm355evm.c @@ -25,6 +25,10 @@ #include "../common/misc.h" #include <net.h> #include <netdev.h> +#ifdef CONFIG_DAVINCI_MMC +#include <mmc.h> +#include <asm/arch/sdmmc_defs.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -114,3 +118,43 @@ int board_nand_init(struct nand_chip *nand) }
#endif + +#ifdef CONFIG_DAVINCI_MMC + +static struct davinci_mmc mmc_sd0 = { + .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD0_BASE, + .input_clk = 108000000, + .host_caps = MMC_MODE_4BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, + .version = MMC_CTLR_VERSION_1, +}; + +#ifdef CONFIG_DAVINCI_MMC_SD1 +static struct davinci_mmc mmc_sd1 = { + .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD1_BASE, + .input_clk = 108000000, + .host_caps = MMC_MODE_4BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, + .version = MMC_CTLR_VERSION_1, +}; +#endif + +int board_mmc_init(bd_t *bis) +{ + int err; + + /* Add slot-0 to mmc subsystem */ + err = davinci_mmc_init(bis, &mmc_sd0); + if (err) + return err; + +#ifdef CONFIG_DAVINCI_MMC_SD1 + /* Add slot-1 to mmc subsystem */ + err = davinci_mmc_init(bis, &mmc_sd1); +#endif + + return err; +} + +#endif + diff --git a/board/davinci/dm365evm/dm365evm.c b/board/davinci/dm365evm/dm365evm.c index 290eb99..9ba8fd8 100644 --- a/board/davinci/dm365evm/dm365evm.c +++ b/board/davinci/dm365evm/dm365evm.c @@ -25,6 +25,10 @@ #include <asm/arch/gpio_defs.h> #include <netdev.h> #include "../common/misc.h" +#ifdef CONFIG_DAVINCI_MMC +#include <mmc.h> +#include <asm/arch/sdmmc_defs.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -101,3 +105,50 @@ int board_nand_init(struct nand_chip *nand) return 0; } #endif + +#ifdef CONFIG_DAVINCI_MMC + +static struct davinci_mmc mmc_sd0 = { + .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD0_BASE, + .input_clk = 121500000, + .host_caps = MMC_MODE_4BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, + .version = MMC_CTLR_VERSION_2, +}; + +#ifdef CONFIG_DAVINCI_MMC_SD1 +static struct davinci_mmc mmc_sd1 = { + .reg_base = (struct davinci_mmc_regs *)DAVINCI_MMC_SD1_BASE, + .input_clk = 121500000, + .host_caps = MMC_MODE_4BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, + .version = MMC_CTLR_VERSION_2, +}; +#endif + +int board_mmc_init(bd_t *bis) +{ + int err; + + /* Add slot-0 to mmc subsystem */ + err = davinci_mmc_init(bis, &mmc_sd0); + if (err) + return err; + +#ifdef CONFIG_DAVINCI_MMC_SD1 +#define PUPDCTL1 0x01c4007c + /* PINMUX(4)-DAT0-3/CMD; PINMUX(0)-CLK */ + writel((readl(PINMUX4) | 0x55400000), PINMUX4); + writel((readl(PINMUX0) | 0x00010000), PINMUX0); + + /* Configure MMC/SD pins as pullup */ + writel((readl(PUPDCTL1) & ~0x07c0), PUPDCTL1); + + /* Add slot-1 to mmc subsystem */ + err = davinci_mmc_init(bis, &mmc_sd1); +#endif + + return err; +} + +#endif diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6fa04b8..566ab44 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -32,6 +32,7 @@ COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o +COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c new file mode 100644 index 0000000..7ec841c --- /dev/null +++ b/drivers/mmc/davinci_mmc.c @@ -0,0 +1,399 @@ +/* + * Davinci MMC Controller Driver + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <mmc.h> +#include <part.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/arch/sdmmc_defs.h> + +#define DAVINCI_MAX_BLOCKS (32) +#define WATCHDOG_COUNT (100000) + +#define get_val(addr) REG(addr) +#define set_val(addr, val) REG(addr) = (val) +#define set_bit(addr, val) set_val((addr), (get_val(addr) | (val))) +#define clear_bit(addr, val) set_val((addr), (get_val(addr) & ~(val))) + +/* Set davinci clock prescalar value based on the required clock in HZ */ +static void dmmc_set_clock(struct mmc *mmc, uint clock) +{ + struct davinci_mmc *host = mmc->priv; + struct davinci_mmc_regs *regs = host->reg_base; + uint clkrt, sysclk2, act_clock; + + if (clock < mmc->f_min) + clock = mmc->f_min; + if (clock > mmc->f_max) + clock = mmc->f_max; + + set_val(®s->mmcclk, 0); + sysclk2 = host->input_clk; + clkrt = (sysclk2 / (2 * clock)) - 1; + + /* Calculate the actual clock for the divider used */ + act_clock = (sysclk2 / (2 * (clkrt + 1))); + + /* Adjust divider if actual clock exceeds the required clock */ + if (act_clock > clock) + clkrt++; + + /* check clock divider boundary and correct it */ + if (clkrt > 0xFF) + clkrt = 0xFF; + + set_val(®s->mmcclk, (clkrt | MMCCLK_CLKEN)); +} + +/* Status bit wait loop for MMCST1 */ +static int +dmmc_wait_fifo_status(volatile struct davinci_mmc_regs *regs, uint status) +{ + uint mmcstatus1, wdog = WATCHDOG_COUNT; + mmcstatus1 = get_val(®s->mmcst1); + while (--wdog && ((get_val(®s->mmcst1) & status) != status)) + udelay(10); + + if (!(get_val(®s->mmcctl) & MMCCTL_WIDTH_4_BIT)) + udelay(100); + + if (wdog == 0) + return COMM_ERR; + + return 0; +} + +/* Busy bit wait loop for MMCST1 */ +static int dmmc_busy_wait(volatile struct davinci_mmc_regs *regs) +{ + uint mmcstatus1, wdog = WATCHDOG_COUNT; + + mmcstatus1 = get_val(®s->mmcst1); + while (--wdog && (get_val(®s->mmcst1) & MMCST1_BUSY)) + udelay(10); + + if (wdog == 0) + return COMM_ERR; + + return 0; +} + +/* Status bit wait loop for MMCST0 - Checks for error bits as well */ +static int dmmc_check_status(volatile struct davinci_mmc_regs *regs, + uint *cur_st, uint st_ready, uint st_error) +{ + uint wdog = WATCHDOG_COUNT; + uint mmcstatus = *cur_st; + + while (wdog--) { + if (mmcstatus & st_ready) { + *cur_st = mmcstatus; + mmcstatus = get_val(®s->mmcst1); + return 0; + } else if (mmcstatus & st_error) { + if (mmcstatus & MMCST0_TOUTRS) + return TIMEOUT; + printf("[ ST0 ERROR %x]\n", mmcstatus); + /* + * Ignore CRC errors as some MMC cards fail to + * initialize on DM365-EVM on the SD1 slot + */ + if (mmcstatus & MMCST0_CRCRS) + return 0; + return COMM_ERR; + } + udelay(10); + + mmcstatus = get_val(®s->mmcst0); + } + + printf("Status %x Timeout ST0:%x ST1:%x\n", st_ready, mmcstatus, + get_val(®s->mmcst1)); + return COMM_ERR; +} + +/* + * Sends a command out on the bus. Takes the mmc pointer, + * a command pointer, and an optional data pointer. + */ +static int +dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + struct davinci_mmc *host = mmc->priv; + volatile struct davinci_mmc_regs *regs = host->reg_base; + uint mmcstatus, status_rdy, status_err; + uint i, cmddata, bytes_left = 0; + int fifo_words, fifo_bytes, err; + char *data_buf = NULL; + + /* Clear status registers */ + mmcstatus = get_val(®s->mmcst0); + fifo_words = (host->version == MMC_CTLR_VERSION_2) ? 16 : 8; + fifo_bytes = fifo_words << 2; + + /* Wait for any previous busy signal to be cleared */ + dmmc_busy_wait(regs); + + cmddata = cmd->cmdidx; + cmddata |= MMCCMD_PPLEN; + + /* Send init clock for CMD0 */ + if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE) + cmddata |= MMCCMD_INITCK; + + switch (cmd->resp_type) { + case MMC_RSP_R1b: + cmddata |= MMCCMD_BSYEXP; + /* Fall-through */ + case MMC_RSP_R1: /* R1, R1b, R5, R6, R7 */ + cmddata |= MMCCMD_RSPFMT_R1567; + break; + case MMC_RSP_R2: + cmddata |= MMCCMD_RSPFMT_R2; + break; + case MMC_RSP_R3: /* R3, R4 */ + cmddata |= MMCCMD_RSPFMT_R3; + break; + } + + set_val(®s->mmcim, 0); + + if (data) { + /* clear previous data transfer if any and set new one */ + bytes_left = (data->blocksize * data->blocks); + + /* Reset FIFO - Always use 32 byte fifo threshold */ + set_val(®s->mmcfifoctl, + (MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); + + if (host->version == MMC_CTLR_VERSION_2) + cmddata |= MMCCMD_DMATRIG; + + cmddata |= MMCCMD_WDATX; + if (data->flags == MMC_DATA_READ) { + set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); + } else if (data->flags == MMC_DATA_WRITE) { + set_val(®s->mmcfifoctl, + (MMCFIFOCTL_FIFOLEV | + MMCFIFOCTL_FIFODIR)); + cmddata |= MMCCMD_DTRW; + } + + set_val(®s->mmctod, 0xFFFF); + set_val(®s->mmcnblk, (data->blocks & MMCNBLK_NBLK_MASK)); + set_val(®s->mmcblen, (data->blocksize & MMCBLEN_BLEN_MASK)); + + if (data->flags == MMC_DATA_WRITE) { + uint val; + data_buf = (char *)data->src; + /* For write, fill FIFO with data before issue of CMD */ + for (i = 0; (i < fifo_words) && bytes_left; i++) { + memcpy((char *)&val, data_buf, 4); + set_val(®s->mmcdxr, val); + data_buf += 4; + bytes_left -= 4; + } + } + } else { + set_val(®s->mmcblen, 0); + set_val(®s->mmcnblk, 0); + } + + set_val(®s->mmctor, 0x1FFF); + + /* Send the command */ + set_val(®s->mmcarghl, cmd->cmdarg); + set_val(®s->mmccmd, cmddata); + + status_rdy = MMCST0_RSPDNE; + status_err = (MMCST0_TOUTRS | MMCST0_TOUTRD | + MMCST0_CRCWR | MMCST0_CRCRD); + if (cmd->resp_type & MMC_RSP_CRC) + status_err |= MMCST0_CRCRS; + + mmcstatus = get_val(®s->mmcst0); + err = dmmc_check_status(regs, &mmcstatus, status_rdy, status_err); + if (err) + return err; + + /* For R1b wait for busy done */ + if (cmd->resp_type == MMC_RSP_R1b) + dmmc_busy_wait(regs); + + /* Collect response from controller for specific commands */ + if (mmcstatus & MMCST0_RSPDNE) { + /* Copy the response to the response buffer */ + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = get_val(®s->mmcrsp67); + cmd->response[1] = get_val(®s->mmcrsp45); + cmd->response[2] = get_val(®s->mmcrsp23); + cmd->response[3] = get_val(®s->mmcrsp01); + } else if (cmd->resp_type & MMC_RSP_PRESENT) { + cmd->response[0] = get_val(®s->mmcrsp67); + } + } + + if (data == NULL) + return 0; + + if (data->flags == MMC_DATA_READ) { + /* check for DATDNE along with DRRDY as the controller might + * set the DATDNE without DRRDY for smaller transfers with + * less than FIFO threshold bytes + */ + status_rdy = MMCST0_DRRDY | MMCST0_DATDNE; + status_err = MMCST0_TOUTRD | MMCST0_CRCRD; + data_buf = data->dest; + } else { + status_rdy = MMCST0_DXRDY | MMCST0_DATDNE; + status_err = MMCST0_CRCWR; + } + + /* Wait until all of the blocks are transferred */ + while (bytes_left) { + err = dmmc_check_status(regs, &mmcstatus, status_rdy, + status_err); + if (err) + return err; + + if (data->flags == MMC_DATA_READ) { + /* + * MMC controller sets the Data receive ready bit + * (DRRDY) in MMCST0 even before the entire FIFO is + * full. This results in erratic behavior if we start + * reading the FIFO soon after DRRDY. Wait for the + * FIFO full bit in MMCST1 for proper FIFO clearing. + */ + if (bytes_left > fifo_bytes) + dmmc_wait_fifo_status(regs, 0x4a); + else if (bytes_left == fifo_bytes) + dmmc_wait_fifo_status(regs, 0x40); + + for (i = 0; bytes_left && (i < fifo_words); i++) { + cmddata = get_val(®s->mmcdrr); + memcpy(data_buf, (char *)&cmddata, 4); + data_buf += 4; + bytes_left -= 4; + } + } else { + /* + * MMC controller sets the Data transmit ready bit + * (DXRDY) in MMCST0 even before the entire FIFO is + * empty. This results in erratic behavior if we start + * writing the FIFO soon after DXRDY. Wait for the + * FIFO empty bit in MMCST1 for proper FIFO clearing. + */ + dmmc_wait_fifo_status(regs, MMCST1_FIFOEMP); + for (i = 0; bytes_left && (i < fifo_words); i++) { + memcpy((char *)&cmddata, data_buf, 4); + set_val(®s->mmcdxr, cmddata); + data_buf += 4; + bytes_left -= 4; + } + dmmc_busy_wait(regs); + } + } + + err = dmmc_check_status(regs, &mmcstatus, MMCST0_DATDNE, status_err); + if (err) + return err; + + return 0; +} + +/* Initialize Davinci MMC controller */ +static int dmmc_init(struct mmc *mmc) +{ + struct davinci_mmc *host = mmc->priv; + struct davinci_mmc_regs *regs = host->reg_base; + + /* Clear status registers explicitly - soft reset doesn't clear it + * If Uboot is invoked from UBL with SDMMC Support, the status + * registers can have uncleared bits + */ + get_val(®s->mmcst0); + get_val(®s->mmcst1); + + /* Hold software reset */ + set_bit(®s->mmcctl, MMCCTL_DATRST); + set_bit(®s->mmcctl, MMCCTL_CMDRST); + udelay(10); + + set_val(®s->mmcclk, 0x0); + set_val(®s->mmctor, 0x1FFF); + set_val(®s->mmctod, 0xFFFF); + + /* Clear software reset */ + clear_bit(®s->mmcctl, MMCCTL_DATRST); + clear_bit(®s->mmcctl, MMCCTL_CMDRST); + + udelay(10); + + /* Reset FIFO - Always use the maximum fifo threshold */ + set_val(®s->mmcfifoctl, (MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); + set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); + + return 0; +} + +/* Set buswidth or clock as indicated by the GENERIC_MMC framework */ +static void dmmc_set_ios(struct mmc *mmc) +{ + struct davinci_mmc *host = mmc->priv; + struct davinci_mmc_regs *regs = host->reg_base; + + /* Set the bus width */ + if (mmc->bus_width == 4) + set_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); + else + clear_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); + + /* Set clock speed */ + if (mmc->clock) + dmmc_set_clock(mmc, mmc->clock); +} + +/* Called from board_mmc_init during startup. Can be called multiple times + * depending on the number of slots available on board and controller + */ +int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host) +{ + struct mmc *mmc; + + mmc = malloc(sizeof(struct mmc)); + memset(mmc, 0, sizeof(struct mmc)); + + sprintf(mmc->name, "davinci"); + mmc->priv = host; + mmc->send_cmd = dmmc_send_cmd; + mmc->set_ios = dmmc_set_ios; + mmc->init = dmmc_init; + + mmc->f_min = 200000; + mmc->f_max = 25000000; + mmc->voltages = host->voltages; + mmc->host_caps = host->host_caps; + + mmc_register(mmc); + + return 0; +} + diff --git a/include/configs/davinci_dm355evm.h b/include/configs/davinci_dm355evm.h index 3828a08..2b7019b 100644 --- a/include/configs/davinci_dm355evm.h +++ b/include/configs/davinci_dm355evm.h @@ -78,6 +78,12 @@ #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_MAX_CHIPS 2
+/* SD/MMC */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_DAVINCI_MMC +#define CONFIG_DAVINCI_MMC_SD1 + /* USB: OTG connector */ /* NYET -- #define CONFIG_USB_DAVINCI */
@@ -95,6 +101,13 @@ #define CONFIG_CMD_PING #define CONFIG_CMD_SAVES
+#ifdef CONFIG_MMC +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_FAT +#define CONFIG_CMD_MMC +#endif + #ifdef CONFIG_NAND_DAVINCI #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_PARTITIONS @@ -123,7 +136,7 @@ #define CONFIG_SYS_PROMPT "DM355 EVM # " /* Monitor Command Prompt */ #define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */ #define CONFIG_SYS_PBSIZE /* Print buffer size */ \ - (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) + (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) #define CONFIG_SYS_MAXARGS 16 /* max number of command args */ #define CONFIG_SYS_HUSH_PARSER #define CONFIG_SYS_PROMPT_HUSH_PS2 "> " @@ -138,10 +151,10 @@
#define CONFIG_BOOTDELAY 5 #define CONFIG_BOOTCOMMAND \ - "dhcp;bootm" + "dhcp;bootm" #define CONFIG_BOOTARGS \ - "console=ttyS0,115200n8 " \ - "root=/dev/mmcblk0p1 rootwait rootfstype=ext3 ro" + "console=ttyS0,115200n8 " \ +"root=/dev/mmcblk0p1 rootwait rootfstype=ext3 ro"
#define CONFIG_CMDLINE_EDITING #define CONFIG_VERSION_VARIABLE diff --git a/include/configs/davinci_dm365evm.h b/include/configs/davinci_dm365evm.h index 6f99ae0..bcc2f06 100644 --- a/include/configs/davinci_dm365evm.h +++ b/include/configs/davinci_dm365evm.h @@ -85,6 +85,12 @@ #define CONFIG_SYS_MAX_NAND_DEVICE 1 #define CONFIG_SYS_NAND_MAX_CHIPS 2
+/* SD/MMC */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_DAVINCI_MMC +#define CONFIG_DAVINCI_MMC_SD1 + #define PINMUX4_USBDRVBUS_BITCLEAR 0x3000 #define PINMUX4_USBDRVBUS_BITSET 0x2000
@@ -137,6 +143,13 @@ #define CONFIG_CMD_PING #define CONFIG_CMD_SAVES
+#ifdef CONFIG_MMC +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_FAT +#define CONFIG_CMD_MMC +#endif + #ifdef CONFIG_NAND_DAVINCI #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_PARTITIONS

Multi-block Read/Write support for Davinci. Uses the new CONFIG_MMC_MBLOCK feature under Generic MMC framework.
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- drivers/mmc/davinci_mmc.c | 3 +++ include/configs/davinci_dm355evm.h | 1 + include/configs/davinci_dm365evm.h | 1 + 3 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c index 7ec841c..01a84d6 100644 --- a/drivers/mmc/davinci_mmc.c +++ b/drivers/mmc/davinci_mmc.c @@ -392,6 +392,9 @@ 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/include/configs/davinci_dm355evm.h b/include/configs/davinci_dm355evm.h index 2b7019b..c11f59e 100644 --- a/include/configs/davinci_dm355evm.h +++ b/include/configs/davinci_dm355evm.h @@ -83,6 +83,7 @@ #define CONFIG_GENERIC_MMC #define CONFIG_DAVINCI_MMC #define CONFIG_DAVINCI_MMC_SD1 +#define CONFIG_MMC_MBLOCK
/* USB: OTG connector */ /* NYET -- #define CONFIG_USB_DAVINCI */ diff --git a/include/configs/davinci_dm365evm.h b/include/configs/davinci_dm365evm.h index bcc2f06..f426b4f 100644 --- a/include/configs/davinci_dm365evm.h +++ b/include/configs/davinci_dm365evm.h @@ -90,6 +90,7 @@ #define CONFIG_GENERIC_MMC #define CONFIG_DAVINCI_MMC #define CONFIG_DAVINCI_MMC_SD1 +#define CONFIG_MMC_MBLOCK
#define PINMUX4_USBDRVBUS_BITCLEAR 0x3000 #define PINMUX4_USBDRVBUS_BITSET 0x2000

Enables Configuration support in MMC for Davinci. Works with Davinci uflash utility for storing pre-defined configuration options in MMC card.
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- include/configs/davinci_dm355evm.h | 8 ++++++++ include/configs/davinci_dm365evm.h | 8 ++++++++ 2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/configs/davinci_dm355evm.h b/include/configs/davinci_dm355evm.h index c11f59e..6067502 100644 --- a/include/configs/davinci_dm355evm.h +++ b/include/configs/davinci_dm355evm.h @@ -150,6 +150,14 @@ #undef CONFIG_ENV_IS_IN_FLASH #endif
+#if defined(CONFIG_MMC) && !defined(CONFIG_ENV_IS_IN_NAND) +#define CONFIG_CMD_ENV +#define CONFIG_ENV_SIZE (16 << 10) /* 16 KiB */ +#define CONFIG_ENV_OFFSET (51 << 9) /* Sector 51 */ +#define CONFIG_ENV_IS_IN_MMC +#undef CONFIG_ENV_IS_IN_FLASH +#endif + #define CONFIG_BOOTDELAY 5 #define CONFIG_BOOTCOMMAND \ "dhcp;bootm" diff --git a/include/configs/davinci_dm365evm.h b/include/configs/davinci_dm365evm.h index f426b4f..8436aad 100644 --- a/include/configs/davinci_dm365evm.h +++ b/include/configs/davinci_dm365evm.h @@ -182,6 +182,14 @@ #undef CONFIG_ENV_IS_IN_FLASH #endif
+#if defined(CONFIG_MMC) && !defined(CONFIG_ENV_IS_IN_NAND) +#define CONFIG_CMD_ENV +#define CONFIG_ENV_SIZE (16 << 10) /* 16 KiB */ +#define CONFIG_ENV_OFFSET (51 << 9) /* Sector 51 */ +#define CONFIG_ENV_IS_IN_MMC +#undef CONFIG_ENV_IS_IN_FLASH +#endif + #define CONFIG_BOOTDELAY 3 #define CONFIG_BOOTCOMMAND \ "dhcp;bootm"

This is a Linux command line tool specific to TI's Davinci platforms, for flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD card. This MMC/SD card can be used for booting Davinci platforms that supports MMC/SD boot option.
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- Makefile | 2 +- tools/uflash/Makefile | 13 ++ tools/uflash/README | 125 ++++++++++++++++ tools/uflash/config.txt | 11 ++ tools/uflash/uflash.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 529 insertions(+), 1 deletions(-) create mode 100644 tools/uflash/Makefile create mode 100644 tools/uflash/README create mode 100644 tools/uflash/config.txt create mode 100644 tools/uflash/uflash.c
diff --git a/Makefile b/Makefile index 82cbbf4..c2b63db 100644 --- a/Makefile +++ b/Makefile @@ -3746,7 +3746,7 @@ clean: @rm -f $(obj)examples/api/demo{,.bin} @rm -f $(obj)tools/bmp_logo $(obj)tools/easylogo/easylogo \ $(obj)tools/env/{fw_printenv,fw_setenv} \ - $(obj)tools/envcrc \ + $(obj)tools/envcrc $(obj)tools/uflash/uflash \ $(obj)tools/gdb/{astest,gdbcont,gdbsend} \ $(obj)tools/gen_eth_addr $(obj)tools/img2srec \ $(obj)tools/mkimage $(obj)tools/mpc86x_clk \ diff --git a/tools/uflash/Makefile b/tools/uflash/Makefile new file mode 100644 index 0000000..ab98441 --- /dev/null +++ b/tools/uflash/Makefile @@ -0,0 +1,13 @@ +include $(TOPDIR)/config.mk + +all: $(obj)uflash + +HOSTCFLAGS_NOPED += -I $(SRCTREE)/include -DUSE_HOSTCC + +$(obj)uflash: $(SRCTREE)/tools/uflash/uflash.c $(SRCTREE)/lib/crc32.c + $(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $^ + +clean: + rm -f $(obj)uflash + +.PHONY: all clean diff --git a/tools/uflash/README b/tools/uflash/README new file mode 100644 index 0000000..cf7dbfb --- /dev/null +++ b/tools/uflash/README @@ -0,0 +1,125 @@ +This is a Linux command line tool specific to TI's Davinci platforms, for +flashing UBL (User Boot Loader), u-boot and u-boot Environment in the MMC/SD +card. This MMC/SD card can be used for booting Davinci platforms that supports +MMC/SD boot option. + +For simplicity, MMC is used in the following section to represent both MMC and +SD cards. + + +Building uflash utility +======================= +Set the TOOLSUBDIRS macro in the tools/Makefile to contain uflash directory +TOOLSUBDIRS = uflash + +While building the u-boot binary, the uflash utility is also built and is placed +under tools/uflash directory. + + +Creating a Davinci bootable MMC card +===================================== +This document is based on the assumption that UBL is used the primary boot +loader for booting u-boot. For more information on Davinci Boot modes, please +refer the TMS320DM644x DMSoC ARM Subsystem Reference Guide (SPRUE14A). + +The embedded ROM boot loader (RBL) in Davinci expects the bootable code +descriptor to be present in sectors 1 to 25 of the MMC card. Sector 0 is used +for storing DOS partition information. Hence the UBL descriptor is stored +from sectors 1 till 24. The descriptor is 512 bytes in size and is replicated +in each of these sectors. This is followed by the u-boot descriptor, +environment space, UBL binary and u-boot binary as depicted below: + + _______________________________________ + | | + | Sector 0 - Partition Table | + |---------------------------------------| + | Sector 1 - UBL descriptor | + |---------------------------------------| + | Sector 2 - UBL descriptor | + |---------------------------------------| + | .... | + |---------------------------------------| + | Sector 24 - UBL descriptor | + |---------------------------------------| + | Sector 25 - u-boot descriptor | + |---------------------------------------| + | Sector 26 - u-boot descriptor | + |---------------------------------------| + | ... | + |---------------------------------------| + | Sector 51 - u-boot descriptor | + |---------------------------------------| + | Sectors 52 to 83 - u-boot environment | + |---------------------------------------| + | Sectors 84 till 116 - empty | + |---------------------------------------| + | Sector 117 - UBL binary | + |---------------------------------------| + | ... | + |---------------------------------------| + | Sector X = u-boot binary | + | X = 117 + UBL binary size in blocks | + |---------------------------------------| + | ... | + |---------------------------------------| + | Sector Y = Application use | + | Y = X + u-boot binary size in blocks | + |---------------------------------------| + | ... | + |_______________________________________| + +a. The MMC card shall be re-partitioned and formated to create some room for + storing UBL and u-boot. Use fdisk utility (as super user) to delete the + existing partition and create a new one. + # fdisk /dev/mmcblk0 (device name might change if USB card reader is used) + - Delete the existing partitions with 'd' command. + - Create a new partition with 'n' command, followed by 'p' command + - Mark the first cylinder as 20. Typical cylinder size is 32KBytes. So + starting the first cylinder at 20 provides us about 600Kbytes for + storing UBL and u-boot. If the fdisk utility displays a different + cylinder size, make sure that you are leaving atleast 500K space + before the first cylinder. + - Leave the last cylinder to default value (or) any other value + depending on the partition size requirements. + - Save and exit with 'w' command + +b. Format the partition for EXT3 file system + # mkfs.ext3 /dev/mmcblk0p1 + +c. Copy the root file system and kernel uImage onto the newly formated + partition. Pre-built images for Davinci DM355EVM platform are available at: + http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm... (and) + http://arago-project.org/files/releases/davinci-psp_3.x.0.0/images/dm355-evm... + # mount /dev/mmcblk0p1 /mnt + # cd /mnt + # tar xzf /path_to_binaries/arago-demo-image-dm355-evm.tar.gz + # cp /path_to_binaries/uImage-dm355-evm.bin boot/uImage + # cd /home + # umount /mnt + +d. Modify the config.txt file to set environment variables for u-boot. These + environment variables will be used by default by the u-boot. + +e. Using the 'uflash' utility, place the UBL and u-uoot binaries on the MMC + card. Copy the u-boot.bin to tools/uflash directory + # ./uflash -d /dev/mmcblk0 -u UBL.bin -b u-boot.bin -vv + UBL Size 20991 + u-boot Size 252087 + First partition starts at 1216(622592) + Required Blocks 660, Available Blocks 1215 + UBL Magic Number : a1aced00 + UBL Entry Point : 00000100 + UBL Number of Blocks : 00000028 + UBL Starting Block : 00000075 + UBL Load Address : 00000000 + Writing UBL Signature + Writing UBL + U-Boot Magic Number : a1aced66 + U-Boot Entry Point : 81080000 + U-Boot Number of Blocks : 000001ec + U-Boot Starting Block : 000000a7 + Load U-Boot Address : 81080000 + Writing U-Boot Signature + Writing U-Boot + Done... + diff --git a/tools/uflash/config.txt b/tools/uflash/config.txt new file mode 100644 index 0000000..f6acb22 --- /dev/null +++ b/tools/uflash/config.txt @@ -0,0 +1,11 @@ +bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p1 rootwait rootfstype=ext3 rw +bootcmd=ext2load mmc 0 0x80700000 boot/uImage; bootm 0x80700000 +bootdelay=1 +baudrate=115200 +bootfile="uImage" +stdin=serial +stdout=serial +stderr=serial +ethact=dm9000 +videostd=ntsc + diff --git a/tools/uflash/uflash.c b/tools/uflash/uflash.c new file mode 100644 index 0000000..3a2260a --- /dev/null +++ b/tools/uflash/uflash.c @@ -0,0 +1,379 @@ +/* + * (C) Copyright, Alagu Sankar alagusankar@embwise.com + * + * Utility for flashing the UBL and U-Boot binary onto SD/MMC cards. + * Signature as Required by RBL is Added by this utility. + * Tested with DM355EVM Platform with UBL v1.65 and Uboot 2009-03 + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +typedef unsigned int uint32; +typedef unsigned char uint8; + +struct rbl_header { + uint32 magic_num; + uint32 entry_point; + uint32 num_blocks; + uint32 start_block; + uint32 load_address; + uint32 padding[123]; +}; + +#define verbose_printf(x...) if (verbose) printf(x) +#define BLOCK_SIZE 512UL + +#define UBL_SIGN_START 1 +#define UBL_SIGN_COUNT 24 +#define UBL_MAGIC_NUM 0xA1ACED00 +#define UBL_ENTRY_POINT 0x00000100 +#define UBL_START_BLOCK 0x00000075 +#define UBL_BLOCK_OFFSET 0x0000000A + +#define UBOOT_SIGN_START 25 +#define UBOOT_SIGN_COUNT 26 +#define UBOOT_MAGIC_NUM 0xA1ACED66 +#define UBOOT_LOAD_ADDRESS 0x81080000 + +#define PART1_LBA_OFFSET 0x000001C6 +#define DEV_NAME "/dev/mmcblk0" +#define UBL_NAME "UBL.bin" +#define UBOOT_NAME "u-boot.bin" +#define ENV_CONFIG_NAME "config.txt" +#define ENV_OFFSET (51 << 9) +#define ENV_SIZE (16 << 10) /* 16KiB */ + +struct env_t { + uint32 crc; + char data[ENV_SIZE-4]; +}; + +uint8 ubl_signature[BLOCK_SIZE]; +uint8 uboot_signature[BLOCK_SIZE]; +char readbuf[BLOCK_SIZE]; + +static void print_hex(uint8 *buf, int len); +static int get_file_size(char *fname); +static int write_file(int devfd, char *fname); +static uint32 get_le32(uint8 *buf); +static int write_env_file(char *fname, char *data); +extern uint32 crc32(uint32, const unsigned char *, uint32); + +static int verbose; +static char *dev_name = DEV_NAME; +static char *ubl_name = UBL_NAME; +static char *uboot_name = UBOOT_NAME; +static char *env_name = ENV_CONFIG_NAME; +static struct env_t default_env; + +static void usage(void) +{ + printf("Usage : uflash [options]\r\n"); + printf("\t-d DEVNAME - Block device Name/Node (%s)\r\n", DEV_NAME); + printf("\t-u UBL_FILE - UBL File Name (%s)\r\n", UBL_NAME); + printf("\t-b UBOOT_FILE - UBoot File Name (%s)\r\n", UBOOT_NAME); + printf("\t-c CONFIG_FILE - UBoot File Name (%s)\r\n", ENV_CONFIG_NAME); + printf("\t-e UBOOT_ENTRY - UBoot Entry Point (0x%X)\r\n", + UBOOT_LOAD_ADDRESS); + printf("\t-l UBOOT_LOAD - UBoot Load Address (0x%X)\r\n", + UBOOT_LOAD_ADDRESS); + printf("\r\n"); +} + +int main(int argc, char *argv[]) +{ + int i, devfd, c, readlen; + int req_blocks, part1_offset; + int ubl_size, uboot_size; + struct rbl_header *rblp; + unsigned int uboot_load_address, uboot_entry_point; + + uboot_load_address = uboot_entry_point = UBOOT_LOAD_ADDRESS; + + while ((c = getopt(argc, argv, "?hvd:u:b:l:e:")) >= 0) { + switch (c) { + case 'd': + dev_name = optarg; + break; + case 'u': + ubl_name = optarg; + break; + case 'c': + env_name = optarg; + break; + case 'l': + uboot_load_address = strtoul(optarg, NULL, 16); + break; + case 'e': + uboot_entry_point = strtoul(optarg, NULL, 16); + break; + case 'v': + verbose++; + break; + case 'b': + uboot_name = optarg; + break; + case 'h': + case '?': + usage(); + return 0; + } + } + + /* Open the SD/MMC Device in Read-Write Mode */ + devfd = open(dev_name, O_RDWR); + if (devfd <= 0) { + fprintf(stderr, "Open Device %s : %s\n", + dev_name, strerror(errno)); + usage(); + exit(-1); + } + + /* Read Master Boot Record - MBR */ + readlen = read(devfd, readbuf, BLOCK_SIZE); + if (readlen < 0) { + fprintf(stderr, "Read Device %s : %s\n", + dev_name, strerror(errno)); + } + + if (verbose > 2) { + printf("====================Master Boot " + "Record====================\n"); + print_hex((uint8 *)readbuf, BLOCK_SIZE); + printf("================================" + "==========================\n"); + } + + /* Get UBL file size and round it to upper 512 byte boundary */ + ubl_size = get_file_size(ubl_name); + if (ubl_size < 0) { + close(devfd); + return -1; + } + ubl_size = (ubl_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1); + verbose_printf("UBL Size %d\n", ubl_size); + + /* Get U-boot file size and round it to upper 512 byte boundary */ + uboot_size = get_file_size(uboot_name); + if (uboot_size <= 0) { + fprintf(stderr, "Invalid U-Boot Size %d\n", uboot_size); + close(devfd); + return -1; + } + uboot_size = (uboot_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1); + verbose_printf("U-Boot Size %d\n", uboot_size); + + /* Get first partition start address offset from Master Boot Record */ + part1_offset = get_le32((uint8 *)&readbuf[PART1_LBA_OFFSET]); + verbose_printf("First partition starts at %d(%ld)\n", part1_offset, + (part1_offset * BLOCK_SIZE)); + + /* Add MBR + UBL Size + Uboot Size */ + req_blocks = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) + + UBL_BLOCK_OFFSET + (uboot_size / BLOCK_SIZE) + 1; + printf("Required Blocks %d, Available Blocks %d\n", req_blocks, + part1_offset - 1); + + /* Return if the card does not have enough space for writing */ + if (req_blocks > part1_offset) { + fprintf(stderr, "Not enough space left for flashing " + "UBL and U-boot\n"); + fprintf(stderr, "Make sure that the First Partition Starts " + "after %d sectors\n", req_blocks); + close(devfd); + return -1; + } + + /* Generate UBL Signature */ + rblp = (struct rbl_header *)ubl_signature; + memset(rblp, 0, sizeof(struct rbl_header)); + rblp->magic_num = UBL_MAGIC_NUM; + rblp->entry_point = UBL_ENTRY_POINT; + rblp->num_blocks = ubl_size / BLOCK_SIZE; + rblp->start_block = UBL_START_BLOCK; + + if (verbose > 1) { + printf("UBL Magic Number : %08x\n", rblp->magic_num); + printf("UBL Entry Point : %08x\n", rblp->entry_point); + printf("UBL Number of Blocks : %08x\n", rblp->num_blocks); + printf("UBL Starting Block : %08x\n", rblp->start_block); + printf("UBL Load Address : %08x\n", rblp->load_address); + } + + /* Write UBL Signature */ + verbose_printf("Writing UBL Signature\n"); + lseek(devfd, (BLOCK_SIZE * UBL_SIGN_START), SEEK_SET); + for (i = UBL_SIGN_START; i < (UBL_SIGN_COUNT + UBL_SIGN_START); i++) { + write(devfd, rblp, BLOCK_SIZE); + } + + /* Write UBL Binary */ + verbose_printf("Writing UBL\n"); + lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET); + write_file(devfd, ubl_name); + + /* Generate U-boot signature */ + rblp = (struct rbl_header *)uboot_signature; + memset(rblp, 0, sizeof(struct rbl_header)); + rblp->magic_num = UBOOT_MAGIC_NUM; + rblp->entry_point = uboot_entry_point; + rblp->num_blocks = uboot_size / BLOCK_SIZE; + rblp->start_block = UBL_START_BLOCK + (ubl_size / BLOCK_SIZE) + + UBL_BLOCK_OFFSET; + rblp->load_address = uboot_load_address; + + if (verbose > 1) { + printf("U-Boot Magic Number : %08x\n", rblp->magic_num); + printf("U-Boot Entry Point : %08x\n", rblp->entry_point); + printf("U-Boot Number of Blocks : %08x\n", rblp->num_blocks); + printf("U-Boot Starting Block : %08x\n", rblp->start_block); + printf("Load U-Boot Address : %08x\n", rblp->load_address); + } + + /* Write U-Boot Signature */ + verbose_printf("Writing U-Boot Signature\n"); + lseek(devfd, (BLOCK_SIZE * UBOOT_SIGN_START), SEEK_SET); + for (i = UBOOT_SIGN_START; i < (UBOOT_SIGN_COUNT + UBOOT_SIGN_START); + i++) { + write(devfd, rblp, BLOCK_SIZE); + } + + verbose_printf("Writing Environment Settings\n"); + memset(&default_env, 0, sizeof(default_env)); + if (write_env_file(env_name, default_env.data) < 0) { + close(devfd); + return -1; + } + default_env.crc = crc32(0, (unsigned char *)default_env.data, + sizeof(default_env.data)); + + lseek(devfd, ENV_OFFSET, SEEK_SET); + write(devfd, &default_env, ENV_SIZE); + + /* Write U-Boot File */ + lseek(devfd, (BLOCK_SIZE * rblp->start_block), SEEK_SET); + verbose_printf("Writing U-Boot\n"); + write_file(devfd, uboot_name); + + printf("Done...\n"); + close(devfd); + return 0; +} + +static void print_hex(uint8 *buf, int len) +{ + int i, j; + for (i = 0 ; i < len; i += 16) { + printf("%08x : ", i); + for (j = i ; (j < (i+16)) && (j < len); j++) { + printf("%02x,", buf[j]); + } + printf(" "); + for (j = i ; (j < (i+16)) && (j < len); j++) { + if ((buf[j] > 0x20) && (buf[j] < 0x7F)) { + printf("%c", buf[j]); + } else { + printf("."); + } + } + printf("\n"); + } +} + +static int get_file_size(char *fname) +{ + FILE *fp; + int size; + + fp = fopen(fname, "rb"); + if (fp == NULL) { + fprintf(stdout, "File %s Open Error : %s\n", + fname, strerror(errno)); + return -1; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fclose(fp); + + return size; +} + +static int write_file(int devfd, char *fname) +{ + FILE *fp; + int readlen; + + fp = fopen(fname, "rb"); + if (fp == NULL) { + fprintf(stderr, "File %s Open Error: %s", + fname, strerror(errno)); + return -1; + } + + while ((readlen = fread(readbuf, 1, BLOCK_SIZE, fp)) > 0) { + if (readlen < BLOCK_SIZE) { + memset(&readbuf[readlen], 0, BLOCK_SIZE-readlen); + } + write(devfd, readbuf, BLOCK_SIZE); + } + + fclose(fp); + + return 0; +} + +static uint32 get_le32(uint8 *buf) +{ + return (uint32)(((uint32)buf[0]) | + ((uint32)buf[1] << 8) | + ((uint32)buf[2] << 16) | + ((uint32)buf[3] << 24)); +} + +static int write_env_file(char *fname, char *data) +{ + FILE *fp; + + fp = fopen(fname, "r"); + if (fp == NULL) { + fprintf(stderr, "File %s Open Error: %s", + fname, strerror(errno)); + return -1; + } + + while (fgets(readbuf, BLOCK_SIZE, fp) != NULL) { + char *str; + if ((str = strchr((char *)&readbuf[0], '\r')) != NULL) + *str = '\0'; + if ((str = strchr((char *)&readbuf[0], '\n')) != NULL) + *str = '\0'; + strcpy(data, readbuf); + data += (strlen(data)+1); + } + + fclose(fp); + + return 0; +} +
participants (1)
-
Alagu Sankar