diff options
author | Frank Li <frank.li@freescale.com> | 2010-01-18 16:32:13 +0800 |
---|---|---|
committer | Frank Li <frank.li@freescale.com> | 2010-01-25 16:53:54 +0800 |
commit | c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26 (patch) | |
tree | d2bae95d336dcfb306f8607f15be01217511af87 /cpu | |
parent | 8a42ad8f7feea158bf3589a90981f7499032a5cd (diff) | |
download | u-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.zip u-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.tar.gz u-boot-imx-c77b09d0ede28f2d9ab940ed15bd16bdafb7ea26.tar.bz2 |
ENGR00120206 iMX28 Enable Ethernet and MMC boot supportrel_imx_2.6.31_10.02.00
Enable Ethernet and MMC boot support for imx28-evk
Signed-off-by: Frank Li <frank.li@freescale.com>
Diffstat (limited to 'cpu')
-rw-r--r-- | cpu/arm926ejs/mx28/Makefile | 2 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/generic.c | 136 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/mmcops.c | 579 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/pinctrl.c | 133 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/reset.S | 5 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/serial.c | 108 | ||||
-rw-r--r-- | cpu/arm926ejs/mx28/timer.c | 74 |
7 files changed, 992 insertions, 45 deletions
diff --git a/cpu/arm926ejs/mx28/Makefile b/cpu/arm926ejs/mx28/Makefile index 3b23886..9f2d5e5 100644 --- a/cpu/arm926ejs/mx28/Makefile +++ b/cpu/arm926ejs/mx28/Makefile @@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).a -COBJS = timer.o spi.o +COBJS = timer.o serial.o generic.o pinctrl.o mmcops.o SOBJS = reset.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm926ejs/mx28/generic.c b/cpu/arm926ejs/mx28/generic.c new file mode 100644 index 0000000..6ac75e0 --- /dev/null +++ b/cpu/arm926ejs/mx28/generic.c @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/arch/mx28.h> +#include <asm/arch/regs-clkctrl.h> + +#if defined(CONFIG_ARCH_CPU_INIT) +int arch_cpu_init(void) +{ + icache_enable(); + dcache_enable(); + return 0; +} +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + const u32 xtal = 24, ref = 480; + u32 cpu, bus, emi; + u32 clkfrac, clkdeq, clkctrl; + u32 frac, div; + + clkfrac = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_FRAC0); + clkdeq = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CLKSEQ); + + /* CPU */ + clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_CPU); + if (clkctrl & (BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN | + BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN)) { + /* No support of fractional divider calculation */ + cpu = 0; + } else { + if (clkdeq & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) { + /* xtal path */ + div = (clkctrl & BM_CLKCTRL_CPU_DIV_XTAL) >> + BP_CLKCTRL_CPU_DIV_XTAL; + cpu = xtal / div; + } else { + /* ref path */ + frac = (clkfrac & BM_CLKCTRL_FRAC0_CPUFRAC) >> + BP_CLKCTRL_FRAC0_CPUFRAC; + div = (clkctrl & BM_CLKCTRL_CPU_DIV_CPU) >> + BP_CLKCTRL_CPU_DIV_CPU; + cpu = (ref * 18 / frac) / div; + } + } + + /* BUS */ + clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_HBUS); + if (clkctrl & BM_CLKCTRL_HBUS_DIV_FRAC_EN) { + /* No support of fractional divider calculation */ + bus = 0; + } else { + div = (clkctrl & BM_CLKCTRL_HBUS_DIV) >> + BP_CLKCTRL_HBUS_DIV; + bus = cpu / div; + } + + /* EMI */ + clkctrl = REG_RD(REGS_CLKCTRL_BASE, HW_CLKCTRL_EMI); + if (clkdeq & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) { + /* xtal path */ + div = (clkctrl & BM_CLKCTRL_EMI_DIV_XTAL) >> + BP_CLKCTRL_EMI_DIV_XTAL; + emi = xtal / div; + } else { + /* ref path */ + frac = (clkfrac & BM_CLKCTRL_FRAC0_EMIFRAC) >> + BP_CLKCTRL_FRAC0_EMIFRAC; + div = (clkctrl & BM_CLKCTRL_EMI_DIV_EMI) >> + BP_CLKCTRL_EMI_DIV_EMI; + emi = (ref * 18 / frac) / div; + } + + /* Print */ + printf("Freescale i.MX28 family\n"); + printf("CPU: %d MHz\n", cpu); + printf("BUS: %d MHz\n", bus); + printf("EMI: %d MHz\n", emi); + + return 0; +} +#endif + +/* + * Initializes on-chip MMC controllers. + */ +#if defined(CONFIG_MXC_ENET) +int imx_ssp_mmc_initialize(bd_t *bis); +#endif +int cpu_mmc_init(bd_t *bis) +{ + int rc = ENODEV; +#ifdef CONFIG_IMX_SSP_MMC + rc = imx_ssp_mmc_initialize(bis); +#endif + return rc; +} + +/* + * Initializes on-chip ethernet controllers. + */ +#if defined(CONFIG_MXC_ENET) +int mxc_enet_initialize(bd_t *bis); +#endif +int cpu_eth_init(bd_t *bis) +{ + int rc = ENODEV; +#if defined(CONFIG_MXC_ENET) + rc = mxc_enet_initialize(bis); +#endif + return rc; +} + diff --git a/cpu/arm926ejs/mx28/mmcops.c b/cpu/arm926ejs/mx28/mmcops.c new file mode 100644 index 0000000..eed2046 --- /dev/null +++ b/cpu/arm926ejs/mx28/mmcops.c @@ -0,0 +1,579 @@ +/* + * (C) Copyright 2010 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <command.h> +#include <exports.h> +#include <mmc.h> + +#if defined(CONFIG_GENERIC_MMC) && defined(CONFIG_CUSTOMIZE_MMCOPS) +#define MMCOPS_DEBUG + +#define MBR_SIGNATURE 0xaa55 +#define MBR_SECTOR_COUNT (CONFIG_ENV_OFFSET >> 9) +/* 1. RSV partition (env and uImage) */ +#define RSVPART_SECTOR_OFFSET (MBR_SECTOR_COUNT) +#define RSVPART_SECTOR_COUNT 0x3ffe /* 8 MB */ +/* 2. FAT partition */ +#define FATPART_FILESYS 0xb +#define FATPART_SECTOR_OFFSET (RSVPART_SECTOR_OFFSET + RSVPART_SECTOR_COUNT) +#define FATPART_SECTOR_COUNT 0x10000 /* 32 MB (minimal) */ +/* 3. EXT partition */ +#define EXTPART_FILESYS 0x83 +#define EXTPART_SECTOR_COUNT 0xc0000 /* 384 MB */ +/* 4. SB partition (uboot.sb or linux.sb) */ +#define SBPART_FILESYS 'S' +#define SBPART_SECTOR_COUNT 0x4000 /* 8 MB */ +#define CB_SIGNATURE 0x00112233 +#define CB_SECTOR_COUNT 2 + +#define MAX_CYLINDERS 1024 +#define MAX_HEADS 256 +#define MAX_SECTORS 63 + +struct partition { + u8 boot_flag; + u8 start_head; + u8 start_sector; + u8 start_cylinder; + u8 file_system; + u8 end_head; + u8 end_sector; + u8 end_cylinder; + u32 sector_offset; + u32 sector_count; +} __attribute__ ((__packed__)); + +struct partition_table { + u8 reserved[446]; + struct partition partitions[4]; + u16 signature; +}; + +struct drive_info { + u32 chip_num; + u32 drive_type; + u32 drive_tag; + u32 sector_offset; + u32 sector_count; +}; + +struct config_block { + u32 signature; + u32 primary_tag; + u32 secondary_tag; + u32 num_copies; + struct drive_info drive_info[2]; +}; + +static int mmc_format(int dev) +{ + int rc = 0; + u8 *buf = 0; + u32 i, cnt, total_sectors; + u32 offset[4]; + struct config_block *cb; + struct partition_table *mbr; + struct mmc *mmc = find_mmc_device(dev); + + /* Warning */ + printf("WARN: Data on card will get lost with format.\n" + "Continue?(y/n)"); + char ch = getc(); + printf("\n"); + if (ch != 'y') { + rc = -1; + goto out; + } + + /* Allocate sector buffer */ + buf = malloc(mmc->read_bl_len); + if (!buf) { + printf("%s[%d]: malloc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + memset(buf, 0, mmc->read_bl_len); + + /* Erase the first sector of each partition */ + cnt = mmc->block_dev.block_read(dev, 0, 1, buf); + if (cnt != 1) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + mbr = (struct partition_table *)buf; + if (mbr->signature == MBR_SIGNATURE) { + /* Get sector offset of each partition */ + for (i = 0; i < 4; i++) + offset[i] = mbr->partitions[i].sector_offset; + /* Erase */ + memset(buf, 0, mmc->read_bl_len); + for (i = 0; i < 4; i++) { + if (offset[i] > 0) { + cnt = mmc->block_dev.block_write(dev, + offset[i], 1, buf); + if (cnt != 1) { + printf("%s[%d]: write mmc error\n", + __func__, __LINE__); + rc = -1; + goto out; + } + } + } + } + + /* Get total sectors */ + total_sectors = mmc->capacity >> 9; + if (RSVPART_SECTOR_COUNT + SBPART_SECTOR_COUNT > total_sectors) { + printf("Card capacity is too low to format\n"); + rc = -1; + goto out; + } + + /* Write config block */ + cb = (struct config_block *)buf; + cb->signature = CB_SIGNATURE; + cb->num_copies = 2; + cb->primary_tag = 0x1; + cb->secondary_tag = 0x2; + cb->drive_info[0].chip_num = 0; + cb->drive_info[0].drive_type = 0; + cb->drive_info[0].drive_tag = 0x1; + cb->drive_info[0].sector_count = SBPART_SECTOR_COUNT - CB_SECTOR_COUNT; + cb->drive_info[0].sector_offset = + total_sectors - cb->drive_info[0].sector_count; + cb->drive_info[1].chip_num = 0; + cb->drive_info[1].drive_type = 0; + cb->drive_info[1].drive_tag = 0x2; + cb->drive_info[1].sector_count = SBPART_SECTOR_COUNT - CB_SECTOR_COUNT; + cb->drive_info[1].sector_offset = + total_sectors - cb->drive_info[1].sector_count; + + cnt = mmc->block_dev.block_write(dev, + total_sectors - SBPART_SECTOR_COUNT, 1, (void *)cb); + if (cnt != 1) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Prepare for MBR */ + memset(buf, 0, mmc->read_bl_len); + mbr = (struct partition_table *)buf; + + /* RSV partition */ + mbr->partitions[0].sector_offset = RSVPART_SECTOR_OFFSET; + mbr->partitions[0].sector_count = RSVPART_SECTOR_COUNT; + + /* SB partition */ + mbr->partitions[3].file_system = SBPART_FILESYS; + mbr->partitions[3].sector_offset = total_sectors - SBPART_SECTOR_COUNT; + mbr->partitions[3].sector_count = SBPART_SECTOR_COUNT; + + /* EXT partition */ + if (EXTPART_SECTOR_COUNT + SBPART_SECTOR_COUNT + + RSVPART_SECTOR_COUNT > total_sectors) { +#ifdef MMCOPS_DEBUG + printf("No room for EXT partition\n"); +#endif + } else { + mbr->partitions[2].file_system = EXTPART_FILESYS; + mbr->partitions[2].sector_offset = total_sectors - + SBPART_SECTOR_COUNT - EXTPART_SECTOR_COUNT; + mbr->partitions[2].sector_count = EXTPART_SECTOR_COUNT; + } + + /* FAT partition */ + if (FATPART_SECTOR_COUNT + MBR_SECTOR_COUNT + + mbr->partitions[0].sector_count + + mbr->partitions[2].sector_count + + mbr->partitions[3].sector_count > total_sectors) { +#ifdef MMCOPS_DEBUG + printf("No room for FAT partition\n"); +#endif + goto out; + } + mbr->partitions[1].file_system = FATPART_FILESYS; + mbr->partitions[1].sector_offset = FATPART_SECTOR_OFFSET; + mbr->partitions[1].sector_count = total_sectors - MBR_SECTOR_COUNT - + mbr->partitions[0].sector_count - + mbr->partitions[2].sector_count - + mbr->partitions[3].sector_count; + +out: + if (rc == 0) { + /* Write MBR */ + mbr->signature = MBR_SIGNATURE; + cnt = mmc->block_dev.block_write(dev, 0, 1, (void *)mbr); + if (cnt != 1) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + } else + printf("Done.\n"); + } + + if (!buf) + free(buf); + return rc; +} + +static int install_sbimage(int dev, void *addr, u32 size) +{ + int rc = 0; + u8 *buf = 0; + u32 cnt, offset, cb_offset, sectors, not_format = 0; + struct config_block *cb; + struct partition_table *mbr; + struct mmc *mmc = find_mmc_device(dev); + + /* Allocate sector buffer */ + buf = malloc(mmc->read_bl_len); + if (!buf) { + printf("%s[%d]: malloc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Check partition */ + offset = 0; + cnt = mmc->block_dev.block_read(dev, offset, 1, buf); + if (cnt != 1) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + mbr = (struct partition_table *)buf; + if ((mbr->signature != MBR_SIGNATURE) || + (mbr->partitions[3].file_system != SBPART_FILESYS)) + not_format = 1; + + /* Check config block */ + offset = mbr->partitions[3].sector_offset; + cb_offset = offset; /* Save for later use */ + cnt = mmc->block_dev.block_read(dev, offset, 1, buf); + if (cnt != 1) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + cb = (struct config_block *)buf; + if (cb->signature != CB_SIGNATURE) + not_format = 1; + + /* Not formatted */ + if (not_format) { + printf("Card is not formatted yet\n"); + rc = -1; + goto out; + } + + /* Calculate sectors of image */ + sectors = size / mmc->read_bl_len; + if (size % mmc->read_bl_len) + sectors++; + + /* Write image */ + offset = cb->drive_info[0].sector_offset; + cnt = mmc->block_dev.block_write(dev, offset, sectors, addr); + if (cnt != sectors) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + /* Verify */ + cnt = mmc->block_dev.block_read(dev, offset, sectors, + addr + sectors * mmc->read_bl_len); + if (cnt != sectors) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + if (memcmp(addr, addr + sectors * mmc->read_bl_len, + sectors * mmc->read_bl_len)) { + printf("Verifying sbImage write fails"); + rc = -1; + goto out; + } + + /* Redundant one */ + offset += sectors; + cnt = mmc->block_dev.block_write(dev, offset, sectors, addr); + if (cnt != sectors) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + /* Verify */ + cnt = mmc->block_dev.block_read(dev, offset, sectors, + addr + sectors * mmc->read_bl_len); + if (cnt != sectors) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + if (memcmp(addr, addr + sectors * mmc->read_bl_len, + sectors * mmc->read_bl_len)) { + printf("Verifying redundant sbImage write fails"); + rc = -1; + goto out; + } + + /* Update config block */ + cb->drive_info[0].sector_count = sectors; + cb->drive_info[1].sector_count = sectors; + cb->drive_info[1].sector_offset = offset; + cnt = mmc->block_dev.block_write(dev, cb_offset, 1, (void *)cb); + if (cnt != 1) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Done */ + printf("Done: %d (%x hex) sectors written at %d (%x hex)\n", + sectors, sectors, offset - sectors, offset - sectors); + +out: + if (!buf) + free(buf); + return rc; +} + +static int install_uimage(int dev, void *addr, u32 size) +{ + int rc = 0; + u8 *buf = 0; + u32 cnt, offset, sectors; + struct partition_table *mbr; + struct mmc *mmc = find_mmc_device(dev); + + /* Calculate sectors of uImage */ + sectors = size / mmc->read_bl_len; + if (size % mmc->read_bl_len) + sectors++; + + /* Allocate sector buffer */ + buf = malloc(mmc->read_bl_len); + if (!buf) { + printf("%s[%d]: malloc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Check partition */ + offset = 0; + cnt = mmc->block_dev.block_read(dev, offset, 1, buf); + if (cnt != 1) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + mbr = (struct partition_table *)buf; + if (mbr->signature != MBR_SIGNATURE) { + printf("No valid partition table\n"); + rc = -1; + goto out; + } + if (mbr->partitions[0].sector_count < sectors) { + printf("No enough uImage partition room\n"); + rc = -1; + goto out; + } + + /* Write uImage */ + offset = mbr->partitions[0].sector_offset + (CONFIG_ENV_SIZE >> 9); + cnt = mmc->block_dev.block_write(dev, offset, sectors, addr); + if (cnt != sectors) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + /* Verify */ + cnt = mmc->block_dev.block_read(dev, offset, sectors, + addr + sectors * mmc->read_bl_len); + if (cnt != sectors) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + if (memcmp(addr, addr + sectors * mmc->read_bl_len, + sectors * mmc->read_bl_len)) { + printf("Verifying uImage write fails"); + rc = -1; + goto out; + } + + /* Done */ + printf("Done: %d (%x hex) sectors written at %d (%x hex)\n", + sectors, sectors, offset, offset); + +out: + if (!buf) + free(buf); + return rc; +} + +static int install_rootfs(int dev, void *addr, u32 size) +{ + int rc = 0; + u8 *buf = 0; + u32 cnt, offset, sectors; + struct partition_table *mbr; + struct mmc *mmc = find_mmc_device(dev); + + /* Calculate sectors of rootfs */ + sectors = size / mmc->read_bl_len; + if (size % mmc->read_bl_len) + sectors++; + + /* Allocate sector buffer */ + buf = malloc(mmc->read_bl_len); + if (!buf) { + printf("%s[%d]: malloc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Check partition */ + offset = 0; + cnt = mmc->block_dev.block_read(dev, offset, 1, buf); + if (cnt != 1) { + printf("%s[%d]: read mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + mbr = (struct partition_table *)buf; + if ((mbr->signature != MBR_SIGNATURE) || + (mbr->partitions[2].file_system != EXTPART_FILESYS)) { + printf("No rootfs partition\n"); + rc = -1; + goto out; + } + if (mbr->partitions[2].sector_count < sectors) { + printf("No enough rootfs partition room\n"); + rc = -1; + goto out; + } + + /* Write rootfs */ + offset = mbr->partitions[2].sector_offset; + cnt = mmc->block_dev.block_write(dev, offset, sectors, addr); + if (cnt != sectors) { + printf("%s[%d]: write mmc error\n", __func__, __LINE__); + rc = -1; + goto out; + } + + /* Done */ + printf("Done: %d (%x hex) sectors written at %d (%x hex)\n", + sectors, sectors, offset, offset); + +out: + if (!buf) + free(buf); + return rc; +} + +int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int dev = 0; + struct mmc *mmc; + + if (argc < 2) + goto err_out; + + if (strcmp(argv[1], "read") && strcmp(argv[1], "write") && + strcmp(argv[1], "rescan") && strcmp(argv[1], "format") && + strcmp(argv[1], "install") && strcmp(argv[1], "list")) + goto err_out; + + if (argc == 2) { /* list */ + print_mmc_devices('\n'); + return 0; + } + + /* Find and init mmc */ + dev = simple_strtoul(argv[2], NULL, 10); + mmc = find_mmc_device(dev); + if (!mmc) { + printf("%s[%d]: find mmc error\n", __func__, __LINE__); + return -1; + } + if (mmc_init(mmc)) { + printf("%s[%d]: init mmc error\n", __func__, __LINE__); + return -1; + } + + if (!strcmp(argv[1], "format")) + mmc_format(dev); + if (argc == 3) /* rescan (mmc_init) */ + return 0; + + if (argc != 6) + goto err_out; + + if (!strcmp(argv[1], "read") || !strcmp(argv[1], "write")) { + void *addr = (void *)simple_strtoul(argv[3], NULL, 16); + u32 blk = simple_strtoul(argv[4], NULL, 16); + u32 cnt = simple_strtoul(argv[5], NULL, 16); + u32 n; + + printf("\nMMC %s: dev # %d, block # %d, count %d ... ", + argv[1], dev, blk, cnt); + + if (!strcmp(argv[1], "read")) { + n = mmc->block_dev.block_read(dev, blk, cnt, addr); + /* flush cache after read */ + flush_cache((ulong)addr, cnt * 512); /* FIXME */ + } else /* write */ + n = mmc->block_dev.block_write(dev, blk, cnt, addr); + + printf("%d blocks %s: %s\n", n, argv[1], + (n == cnt) ? "OK" : "ERROR"); + return (n == cnt) ? 0 : -1; + } else if (!strcmp(argv[1], "install")) { + void *addr = (void *)simple_strtoul(argv[3], NULL, 16); + u32 size = simple_strtoul(argv[4], NULL, 16); + + if (!strcmp(argv[5], "sbImage")) + return install_sbimage(dev, addr, size); + else if (!strcmp(argv[5], "uImage")) + return install_uimage(dev, addr, size); + else if (!strcmp(argv[5], "rootfs")) + return install_rootfs(dev, addr, size); + } + +err_out: + printf("Usage:\n%s\n", cmdtp->usage); + return -1; +} + +U_BOOT_CMD( + mmc, 6, 1, do_mmcops, + "MMC sub system", + "mmc read <device num> addr blk# cnt\n" + "mmc write <device num> addr blk# cnt\n" + "mmc rescan <device num>\n" + "mmc format <device num>\n" + "mmc install <device num> addr size sbImage/uImage/rootfs\n" + "mmc list - lists available devices"); +#endif /* (CONFIG_GENERIC_MMC && CONFIG_CUSTOMIZE_MMCOPS) */ diff --git a/cpu/arm926ejs/mx28/pinctrl.c b/cpu/arm926ejs/mx28/pinctrl.c new file mode 100644 index 0000000..88427c8 --- /dev/null +++ b/cpu/arm926ejs/mx28/pinctrl.c @@ -0,0 +1,133 @@ +/* + * + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <common.h> +#include <asm/arch/mx28.h> +#include <asm/arch/regs-pinctrl.h> +#include <asm/arch/pinctrl.h> + +void pin_gpio_direction(u32 id, u32 output) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0; + addr += 0x10 * bank; + if (output) + REG_SET_ADDR(addr, 1 << pin); + else + REG_CLR_ADDR(addr, 1 << pin); +} + +u32 pin_gpio_get(u32 id) +{ + u32 addr, val; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0; + addr += 0x10 * bank; + val = REG_RD_ADDR(addr); + + return (val & (1 << pin)) >> pin; +} + +void pin_gpio_set(u32 id, u32 val) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0; + addr += 0x10 * bank; + if (val) + REG_SET_ADDR(addr, 1 << pin); + else + REG_CLR_ADDR(addr, 1 << pin); +} + +void pin_set_strength(u32 id, enum pad_strength strength) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0; + addr += 0x40 * bank + 0x10 * (pin >> 3); + pin &= 0x7; + REG_CLR_ADDR(addr, 0x3 << (pin * 4)); + REG_SET_ADDR(addr, strength << (pin * 4)); +} + +void pin_set_voltage(u32 id, enum pad_voltage volt) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0; + addr += 0x40 * bank + 0x10 * (pin >> 3); + pin &= 0x7; + if (volt == PAD_1V8) + REG_CLR_ADDR(addr, 1 << (pin * 4 + 2)); + else + REG_SET_ADDR(addr, 1 << (pin * 4 + 2)); +} + +void pin_set_pullup(u32 id, u32 pullup) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0; + addr += 0x10 * bank; + if (pullup) + REG_SET_ADDR(addr, 1 << pin); + else + REG_CLR_ADDR(addr, 1 << pin); +} + +void pin_set_type(u32 id, enum pin_fun cfg) +{ + u32 addr; + u32 bank = PINID_2_BANK(id); + u32 pin = PINID_2_PIN(id); + + addr = REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0; + addr += 0x20 * bank + 0x10 * (pin >> 4); + pin &= 0xf; + REG_CLR_ADDR(addr, 0x3 << (pin * 2)); + REG_SET_ADDR(addr, cfg << (pin * 2)); +} + +void pin_set_group(struct pin_group *pin_group) +{ + u32 p; + struct pin_desc *pin; + + for (p = 0; p < pin_group->nr_pins; p++) { + pin = &pin_group->pins[p]; + pin_set_type(pin->id, pin->fun); + pin_set_strength(pin->id, pin->strength); + pin_set_voltage(pin->id, pin->voltage); + pin_set_pullup(pin->id, pin->pullup); + } +} + diff --git a/cpu/arm926ejs/mx28/reset.S b/cpu/arm926ejs/mx28/reset.S index 324c384..c8596e5 100644 --- a/cpu/arm926ejs/mx28/reset.S +++ b/cpu/arm926ejs/mx28/reset.S @@ -1,7 +1,8 @@ /* - * Processor reset for Freescale MX28 SoC. + * Processor reset for Freescale i.MX28 SoC. * * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. * * ----------------------------------------------------- * @@ -39,5 +40,5 @@ POWER_MINPWR: POWER_CHARGE: .word 0x80044030 CLKCTRL_RESET: - .word 0x80040120 + .word 0x800401e0 diff --git a/cpu/arm926ejs/mx28/serial.c b/cpu/arm926ejs/mx28/serial.c new file mode 100644 index 0000000..58f7d2a --- /dev/null +++ b/cpu/arm926ejs/mx28/serial.c @@ -0,0 +1,108 @@ +/* + * (c) 2007 Sascha Hauer <s.hauer@pengutronix.de> + * + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <common.h> +#include <asm/arch/mx28.h> +#include <asm/arch/regs-uartdbg.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Set baud rate. The settings are always 8n1: + * 8 data bits, no parity, 1 stop bit + */ +void serial_setbrg(void) +{ + u32 cr; + u32 quot; + + /* Disable everything */ + cr = REG_RD(REGS_UARTDBG_BASE, HW_UARTDBGCR); + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR, 0); + + /* Calculate and set baudrate */ + quot = (CONFIG_DBGUART_CLK * 4) / gd->baudrate; + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGFBRD, quot & 0x3f); + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGIBRD, quot >> 6); + + /* Set 8n1 mode, enable FIFOs */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGLCR_H, + BM_UARTDBGLCR_H_WLEN | BM_UARTDBGLCR_H_FEN); + + /* Enable Debug UART */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR, cr); +} + +int serial_init(void) +{ + /* Disable UART */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR, 0); + + /* Mask interrupts */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGIMSC, 0); + + /* Set default baudrate */ + serial_setbrg(); + + /* Enable UART */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGCR, + BM_UARTDBGCR_TXE | BM_UARTDBGCR_RXE | BM_UARTDBGCR_UARTEN); + + return 0; +} + +/* Send a character */ +void serial_putc(const char c) +{ + /* Wait for room in TX FIFO */ + while (REG_RD(REGS_UARTDBG_BASE, HW_UARTDBGFR) & BM_UARTDBGFR_TXFF) + ; + + /* Write the data byte */ + REG_WR(REGS_UARTDBG_BASE, HW_UARTDBGDR, c); + + if (c == '\n') + serial_putc('\r'); +} + +void serial_puts(const char *s) +{ + while (*s) + serial_putc(*s++); +} + +/* Test whether a character is in TX buffer */ +int serial_tstc(void) +{ + /* Check if RX FIFO is not empty */ + return !(REG_RD(REGS_UARTDBG_BASE, HW_UARTDBGFR) & BM_UARTDBGFR_RXFE); +} + +/* Receive character */ +int serial_getc(void) +{ + /* Wait while TX FIFO is empty */ + while (REG_RD(REGS_UARTDBG_BASE, HW_UARTDBGFR) & BM_UARTDBGFR_RXFE) + ; + + /* Read data byte */ + return REG_RD(REGS_UARTDBG_BASE, HW_UARTDBGDR) & 0xff; +} + diff --git a/cpu/arm926ejs/mx28/timer.c b/cpu/arm926ejs/mx28/timer.c index ffad4d8..873b30c 100644 --- a/cpu/arm926ejs/mx28/timer.c +++ b/cpu/arm926ejs/mx28/timer.c @@ -16,7 +16,7 @@ * (C) Copyright 2004 * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> * - * (C) Copyright 2009 Freescale Semiconductor, Inc. + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -39,72 +39,60 @@ #include <common.h> #include <asm/arch/mx28.h> -#include <asm/arch/timrot.h> - -#define CONFIG_USE_TIMER0 - -#if defined(CONFIG_USE_TIMER0) -#define TIMCTRL TIMCTRL0 -#define TIMCOUNT TIMCOUNT0 -#elif defined(CONFIG_USE_TIMER1) -#define TIMCTRL TIMCTRL1 -#define TIMCOUNT TIMCOUNT1 -#elif defined(CONFIG_USE_TIMER2) -#define TIMCTRL TIMCTRL2 -#define TIMCOUNT TIMCOUNT2 -#elif defined(CONFIG_USE_TIMER3) -#define TIMCTRL TIMCTRL3 -#define TIMCOUNT TIMCOUNT3 -#else -#error "Define which STMP378x timer to use" -#endif - -#define TIMER_LOAD_VAL 0x0000ffff - -/* macro to read the 16 bit timer */ -#define READ_TIMER ((REG_RD(TIMROT_BASE + TIMCOUNT) & 0xffff0000) >> 16) +#include <asm/arch/regs-timrot.h> + +/* + * TIMROT gets 4 timer instances + * Define N as 0..3 to specify + */ +#define N 0 + +/* Ticks per second */ +#define CONFIG_SYS_HZ 1000 + +/* Maximum fixed count */ +#define TIMER_LOAD_VAL 0xffffffff static ulong timestamp; static ulong lastdec; int timer_init(void) { - u32 val; - /* * Reset Timers and Rotary Encoder module */ /* Clear SFTRST */ - REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 31); - while (REG_RD(TIMROT_BASE + ROTCTRL) & (1 << 31)) + REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31); + while (REG_RD(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL) & (1 << 31)) ; /* Clear CLKGATE */ - REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 30); + REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 30); /* Set SFTRST and wait until CLKGATE is set */ - REG_SET(TIMROT_BASE + ROTCTRL, 1 << 31); - while (!(REG_RD(TIMROT_BASE + ROTCTRL) & (1 << 30))) + REG_SET(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31); + while (!(REG_RD(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL) & (1 << 30))) ; /* Clear SFTRST and CLKGATE */ - REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 31); - REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 30); + REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 31); + REG_CLR(REGS_TIMROT_BASE, HW_TIMROT_ROTCTRL, 1 << 30); /* * Now initialize timer */ /* Set fixed_count to 0 */ - REG_WR(TIMROT_BASE + TIMCOUNT, 0); + REG_WR(REGS_TIMROT_BASE, HW_TIMROT_FIXED_COUNTn(N), 0); /* set UPDATE bit and 1Khz frequency */ - REG_WR(TIMROT_BASE + TIMCTRL, - TIMCTRL_RELOAD | TIMCTRL_UPDATE | TIMCTRL_SELECT_1KHZ); + REG_WR(REGS_TIMROT_BASE, HW_TIMROT_TIMCTRLn(N), + BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE | + BV_TIMROT_TIMCTRLn_SELECT__1KHZ_XTAL); /* Set fixed_count to maximal value */ - REG_WR(TIMROT_BASE + TIMCOUNT, TIMER_LOAD_VAL); + REG_WR(REGS_TIMROT_BASE, HW_TIMROT_FIXED_COUNTn(N), TIMER_LOAD_VAL); /* init the timestamp and lastdec value */ reset_timer_masked(); @@ -166,14 +154,16 @@ void udelay(unsigned long usec) void reset_timer_masked(void) { - /* reset time */ - lastdec = READ_TIMER; /* capure current decrementer value time */ - timestamp = 0; /* start "advancing" time stamp from 0 */ + /* capure current decrementer value time */ + lastdec = REG_RD(REGS_TIMROT_BASE, HW_TIMROT_RUNNING_COUNTn(N)); + /* start "advancing" time stamp from 0 */ + timestamp = 0; } ulong get_timer_masked(void) { - ulong now = READ_TIMER; /* current tick value */ + /* current tick value */ + ulong now = REG_RD(REGS_TIMROT_BASE, HW_TIMROT_RUNNING_COUNTn(N)); if (lastdec >= now) { /* normal mode (non roll) */ /* normal mode */ |