summaryrefslogtreecommitdiff
path: root/board/st/u8500/emmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/st/u8500/emmc.c')
-rw-r--r--board/st/u8500/emmc.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/board/st/u8500/emmc.c b/board/st/u8500/emmc.c
new file mode 100644
index 000000000..110c73702
--- /dev/null
+++ b/board/st/u8500/emmc.c
@@ -0,0 +1,408 @@
+/*
+* (C) Copyright 2009
+* ST-Ericsson, <www.stericsson.com>
+*
+* See file CREDITS for list of people who contributed to this
+* project.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+* MA 02111-1307 USA
+*/
+/* --- includes ----------------------------------------------------------- */
+#include "common.h" /* XXX: Arrgghh! "common.h" includes <common.h> */
+#include <command.h>
+#include "mmc.h"
+#include "emmc.h"
+#include "gpio.h"
+#include <asm/boottime.h>
+
+#define PIB_EMMC_ADDR 0x00
+/* ========================================================================
+Name: init_emmc
+Description: init embedded multimedia card interface
+
+======================================================================== */
+int emmc_init(u8 card_num)
+{
+ t_mmc_error mmc_error;
+ t_mmc_error response;
+ gpio_error gpioerror;
+ int error;
+
+#ifndef CONFIG_U8500_V1
+/* Initialize the base address of eMMC */
+ mmc_error = mmc_init(card_num, CFG_EMMC_BASE);
+
+ if (MMC_OK != mmc_error)
+ {
+ printf("emmc_init() %d \n", mmc_error);
+ goto end;
+ }
+
+ /* Initialize the gpio alternate function for eMMC */
+ struct gpio_register *p_gpio_register = (void *) IO_ADDRESS(CFG_GPIO_6_BASE);
+ p_gpio_register -> gpio_dats |= 0x0000FFE0;
+ p_gpio_register -> gpio_pdis &= ~0x0000FFE0;
+
+ //enable the alternate function of EMMC
+ gpioerror = gpio_altfuncenable(GPIO_ALT_EMMC, "EMMC");
+ if(gpioerror != GPIO_OK)
+ {
+ printf("emmc_init() gpio_altfuncenable %d failed\n", gpioerror);
+ goto end;
+ }
+
+#else
+/* Initialize the base address of PoP eMMC */
+ mmc_error = mmc_init(card_num, CFG_POP_EMMC_BASE);
+
+ if (MMC_OK != mmc_error)
+ {
+ printf("emmc_init() %d \n", mmc_error);
+ goto end;
+ }
+ //enable the alternate function of PoP EMMC
+ gpioerror = gpio_altfuncenable(GPIO_ALT_POP_EMMC, "EMMC");
+ if (gpioerror != GPIO_OK) {
+ printf("emmc_init() gpio_altfuncenable %d failed \n",
+ gpioerror);
+ goto end;
+ }
+#endif
+ //Power-on the controller
+ response = mmc_poweron(card_num);
+ if (response != MMC_OK)
+ {
+ printf("Error in eMMC power on, response is %d\n",response);
+ goto end;
+ }
+ // Initialise the cards,get CID and CSD on the bus
+ response = mmc_initializeCards(card_num);
+
+ if (response != MMC_OK)
+ {
+ printf(" Error in eMMC initialization\n");
+ goto end;
+ }
+
+ error = emmc_write_pib();
+ if(error)
+ printf("PIB info writing into eMMC failed\n");
+ printf("eMMC done\n");
+
+ return 0;
+
+end:
+#ifndef CONFIG_U8500_V1
+ gpio_altfuncdisable(GPIO_ALT_EMMC, "EMMC");
+#else
+ gpio_altfuncdisable(GPIO_ALT_POP_EMMC, "EMMC");
+#endif
+ mmc_poweroff(card_num);
+ return 1;
+}
+
+int emmc_write_pib(void)
+{
+ int i;
+ t_mmc_error mmc_error;
+ u32 block_offset = PIB_EMMC_ADDR;
+ u8 emmc_last_sector[512];
+ u8 card_num = 4;
+
+ for (i = 0; i < 0x1BF; i++) {
+ emmc_last_sector[i] = 0;
+ }
+ emmc_last_sector[0x1BF] = 0x03;
+ emmc_last_sector[0x1C0] = 0xD0;
+ emmc_last_sector[0x1C1] = 0xFF;
+ emmc_last_sector[0x1C2] = 0x83;
+ emmc_last_sector[0x1C3] = 0x03;
+ emmc_last_sector[0x1C4] = 0xD0;
+ emmc_last_sector[0x1C5] = 0xFF;
+ emmc_last_sector[0x1C6] = 0x00;
+ emmc_last_sector[0x1C7] = 0x00;
+ emmc_last_sector[0x1C8] = 0x0A;
+ emmc_last_sector[0x1C9] = 0x00;
+ emmc_last_sector[0x1CA] = 0x00;
+ emmc_last_sector[0x1CB] = 0x40;
+ emmc_last_sector[0x1CC] = 0x00;
+ emmc_last_sector[0x1CD] = 0x00;
+ emmc_last_sector[0x1CE] = 0x00;
+ emmc_last_sector[0x1CF] = 0x03;
+ emmc_last_sector[0x1D0] = 0xD0;
+ emmc_last_sector[0x1D1] = 0xFF;
+ emmc_last_sector[0x1D2] = 0x83;
+ emmc_last_sector[0x1D3] = 0x03;
+ emmc_last_sector[0x1D4] = 0xD0;
+ emmc_last_sector[0x1D5] = 0xFF;
+ emmc_last_sector[0x1D6] = 0x00;
+ emmc_last_sector[0x1D7] = 0x40;
+ emmc_last_sector[0x1D8] = 0x0A;
+ emmc_last_sector[0x1D9] = 0x00;
+ emmc_last_sector[0x1DA] = 0x00;
+ emmc_last_sector[0x1DB] = 0x00;
+ emmc_last_sector[0x1DC] = 0x08;
+ emmc_last_sector[0x1DD] = 0x00;
+ emmc_last_sector[0x1DE] = 0x00;
+ emmc_last_sector[0x1DF] = 0x03;
+ emmc_last_sector[0x1E0] = 0xD0;
+ emmc_last_sector[0x1E1] = 0xFF;
+ emmc_last_sector[0x1E2] = 0x83;
+ emmc_last_sector[0x1E3] = 0x03;
+ emmc_last_sector[0x1E4] = 0xD0;
+ emmc_last_sector[0x1E5] = 0xFF;
+ emmc_last_sector[0x1E6] = 0x00;
+ emmc_last_sector[0x1E7] = 0x40;
+ emmc_last_sector[0x1E8] = 0x12;
+ emmc_last_sector[0x1E9] = 0x00;
+ emmc_last_sector[0x1EA] = 0x00;
+ emmc_last_sector[0x1EB] = 0xC0;
+ emmc_last_sector[0x1EC] = 0x22;
+ emmc_last_sector[0x1ED] = 0x00;
+ emmc_last_sector[0x1EE] = 0x00;
+ emmc_last_sector[0x1EF] = 0x03;
+ emmc_last_sector[0x1F0] = 0xD0;
+ emmc_last_sector[0x1F1] = 0xFF;
+ emmc_last_sector[0x1F2] = 0x0C;
+ emmc_last_sector[0x1F3] = 0x03;
+ emmc_last_sector[0x1F4] = 0xD0;
+ emmc_last_sector[0x1F5] = 0xFF;
+ emmc_last_sector[0x1F6] = 0x00;
+ emmc_last_sector[0x1F7] = 0x00;
+ emmc_last_sector[0x1F8] = 0x35;
+ emmc_last_sector[0x1F9] = 0x00;
+ emmc_last_sector[0x1FA] = 0x00;
+ emmc_last_sector[0x1FB] = 0xA0;
+ emmc_last_sector[0x1FC] = 0xB9;
+ emmc_last_sector[0x1FD] = 0x00;
+ emmc_last_sector[0x1FE] = 0x55;
+ emmc_last_sector[0x1FF] = 0xAA;
+
+/* HACK required for HREF board as erase block size = 512KB */
+/*
+ mmc_error = mmc_erase(card_num, 0x0, 0x1FF);
+ if (mmc_error != MMC_OK) {
+ printf(" eMMC erase failed in PIB \n");
+ return 1;
+ }
+*/
+ mmc_error =
+ mmc_writeblocks(card_num, block_offset, (u32 *) emmc_last_sector,
+ 512, 1);
+ if (mmc_error != MMC_OK) {
+ printf(" eMMC PIB write failed \n");
+ return 1;
+ }
+ return 0;
+}
+
+int emmc_erase(u32 start, u32 end)
+{
+ t_mmc_error mmc_error;
+ u8 card_num = 4;
+ printf("emmc erase start \n");
+ mmc_error = mmc_erase(card_num, start, end);
+ if (mmc_error != MMC_OK) {
+ printf(" eMMC erase failed \n");
+ return 1;
+ }
+ printf("emmc erase done \n");
+ return 0;
+}
+
+int emmc_read(u32 block_offset, u32 read_buffer, u32 filesize)
+{
+ t_mmc_error mmc_error;
+ u32 remaining;
+ u8 card_num = 4;
+ u8 *mem_address = (u8 *) read_buffer;
+ u32 n=filesize,blocks;
+
+ remaining = filesize;
+
+ printf(" eMMC read start filesize=0x%x \n", filesize);
+
+ blocks = (n%512==0)?(n/512):(n/512)+1;
+
+ while(blocks>=8)
+ {
+ mmc_error = mmc_readblocks(card_num, block_offset, (u32 *) mem_address, 512, 8);
+ if (mmc_error != MMC_OK)
+ {
+ printf(" eMMC read blocks failed \n");
+ return 1;
+ }
+
+ block_offset += 4096;
+ mem_address += 4096;
+ blocks -=8;
+ remaining -= 4096;
+ }
+ if(blocks)
+ {
+ mmc_error = mmc_readblocks(card_num, block_offset, (u32 *) mem_address, 512, blocks);
+ if (mmc_error != MMC_OK)
+ {
+ printf(" eMMC read blocks failed \n");
+ return 1;
+ }
+ }
+
+ printf(" eMMC read done \n");
+ return 0;
+}
+
+int emmc_write(u32 block_offset, u32 write_buffer, u32 filesize)
+{
+ t_mmc_error mmc_error;
+ u32 remaining;
+ u8 card_num = 4;
+ u8 *mem_address = (u8 *) write_buffer;
+ u32 n=filesize,blocks;
+
+ remaining = filesize;
+
+ printf(" eMMC write start filesize=0x%x \n", filesize);
+
+ blocks = (n%512==0)?(n/512):(n/512)+1;
+ while(blocks>=8)
+ {
+ mmc_error = mmc_writeblocks(card_num, block_offset, (u32 *) mem_address,512, 8);
+ if (mmc_error != MMC_OK)
+ {
+ printf(" eMMC write blocks failed \n");
+ return 1;
+ }
+
+ block_offset += 4096;
+ mem_address += 4096;
+ blocks -=8;
+ remaining -= 4096;
+ }
+ if(blocks)
+ {
+
+ mmc_error = mmc_writeblocks(card_num, block_offset, (u32 *) mem_address,512, blocks);
+ if (mmc_error != MMC_OK)
+ {
+ printf(" eMMC write blocks failed \n");
+ return 1;
+ }
+
+ }
+
+ printf(" eMMC write done \n");
+ return 0;
+}
+
+/*
+ * command line commands
+ */
+#ifdef CONFIG_CMD_EMMC
+int do_emmc_erase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ u32 start_address;
+ u32 end_address;
+ int load_result = 1;
+ u32 error_name = 0;
+
+ start_address = simple_strtoul (argv[1],0,16);
+ end_address = simple_strtoul (argv[2],0,16);
+
+ printf("emmc_erase :: start address = %x end_address=0x%x\n",start_address,end_address);
+
+ load_result = emmc_erase(start_address,end_address);
+ if (load_result != 0)
+ {
+ error_name = (unsigned long) (-load_result);
+ printf("emmc_erase error : failed \n");
+ }
+ return(0);
+}
+
+U_BOOT_CMD(
+ emmc_erase, 3, 0, do_emmc_erase,
+ "- erase the eMMC flash \n",
+ "start_address- start address of the eMMC block\n"
+ "end_address- end address of the eMMC block\n"
+);
+
+int do_emmc_read (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ u32 ram_address;
+ u32 block_offset;
+ u32 filesize;
+ int load_result = 1;
+ u32 error_name = 0;
+
+ ram_address = simple_strtoul (argv[1],0,16);
+ block_offset = simple_strtoul (argv[2],0,16);
+ filesize = simple_strtoul (argv[3],0,16);
+
+ boottime_tag("load_image");
+ printf("emmc_read :: ram address = 0x%x block address=0x%x \n",ram_address,block_offset);
+
+ load_result = emmc_read(block_offset,ram_address,filesize);
+ if (load_result != 0)
+ {
+ boottime_remove_last();
+ error_name = (unsigned long) (-load_result);
+ printf("emmc_read error : in reading data from eMMC block \n");
+ }
+ return(0);
+}
+
+U_BOOT_CMD(
+ emmc_read, 4, 0, do_emmc_read,
+ "- read file from emmc flash \n",
+ "ram_address - read from eMMC and copy into ram address\n"
+ "block_offset - address to read the file from the eMMC block \n"
+ "filesize - size of the file \n"
+);
+
+int do_emmc_write (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ u32 ram_address;
+ u32 block_offset;
+ u32 filesize;
+ int load_result = 1;
+ u32 error_name = 0;
+
+ ram_address = simple_strtoul (argv[1],0,16);
+ block_offset = simple_strtoul (argv[2],0,16);
+ filesize = simple_strtoul (argv[3],0,16);
+
+ printf("emmc_write :: ram address = %x block address=0x%x \n",ram_address,block_offset);
+
+ load_result = emmc_write(block_offset,ram_address,filesize);
+ if (load_result != 0)
+ {
+ error_name = (unsigned long) (-load_result);
+ printf("emmc_read error : in writing data into eMMC block \n");
+ }
+ return(0);
+}
+
+U_BOOT_CMD(
+ emmc_write, 4, 0, do_emmc_write,
+ "- write file from emmc flash \n",
+ "ram_address - write to eMMC by copying from ram address\n"
+ "block_offset - address to write the file into the eMMC block \n"
+ "filesize - size of the file \n"
+);
+
+#endif /* CONFIG_CMD_EMMC */
+/* ------------------------------- End of file ---------------------------- */