diff options
47 files changed, 14756 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index 67d2cd62c..39fe4e38b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ /LOG /errlog /reloc_off +build # stgit generated dirs patches-* diff --git a/Makefile b/Makefile index bcb3fe953..35f64122d 100644..100755 --- a/Makefile +++ b/Makefile @@ -3171,6 +3171,24 @@ omap3_zoom2_config : unconfig smdkc100_config: unconfig @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 smdkc100 samsung s5pc1xx +u8500_def_config \ +u8500_noconsole_config \ +u8500_auto_config: unconfig + @mkdir -p $(obj)include + @ > $(obj)include/config.h + @if [ "$(findstring _def, $@)" ] ; then \ + echo "#ifndef CONFIG_SKIP_LOWLEVEL_INIT " >> $(obj)include/config.h ; \ + echo "#define CONFIG_SKIP_LOWLEVEL_INIT 1" >> $(obj)include/config.h ; \ + echo "#endif" >> $(obj)include/config.h ; \ + elif [ "$(findstring _noconsole, $@)" ] ; then \ + echo "Configuring for no console ..." ; \ + echo "#ifndef CONFIG_SKIP_LOWLEVEL_INIT" >> $(obj)include/config.h ; \ + echo "#define CONFIG_SKIP_LOWLEVEL_INIT 1" >> $(obj)include/config.h ; \ + echo "#endif" >> $(obj)include/config.h ; \ + echo "#define CONFIG_SILENT_CONSOLE 1" >> $(obj)include/config.h ; \ + fi; + @$(MKCONFIG) -a u8500 arm arm_cortexa9 u8500 st stw8500 + ######################################################################### ## XScale Systems ######################################################################### diff --git a/board/st/u8500/Makefile b/board/st/u8500/Makefile new file mode 100755 index 000000000..78eece7fe --- /dev/null +++ b/board/st/u8500/Makefile @@ -0,0 +1,52 @@ +# +# (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 +# + +include $(TOPDIR)/config.mk + +CFLAGS += -D__RELEASE -D__STN_8500 +LIB = $(obj)lib$(BOARD).a + +COBJS := u8500.o flash.o gpio.o i2c.o mmc.o mmc_utils.o init_mmc.o emmc.o +SOBJS := + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak $(obj).depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/st/u8500/common.h b/board/st/u8500/common.h new file mode 100755 index 000000000..b6185081a --- /dev/null +++ b/board/st/u8500/common.h @@ -0,0 +1,134 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ +#include <common.h> + +#define PASS (1) +#define FAIL (0) + +#define IO(addr) (*((u32*) (addr))) +#define HIO(addr) (*((u16*) (addr))) +#define BIO(addr) (*((u8*) (addr))) + +/* + * macro to get at IO space + */ +#define IO_ADDRESS(x) (x) + +#define REG_WRITE_BITS(reg,val,mask,sb) (writel(((readl(reg) & ~(mask)) | (((val)<<(sb)) & (mask))), reg)) + +#define nmdk_error(format, arg...) printf(": " format "\n" , ## arg) + +#if !defined(FALSE) && !defined(TRUE) +typedef enum {FALSE, TRUE} t_bool; +#else /* FALSE & TRUE already defined */ +typedef enum {BOOL_FALSE, BOOL_TRUE} t_bool; +#endif /* !defined(FALSE) && !defined(TRUE) */ + +/*----------------------------------------------------------------------------- + * Bit mask definition + *---------------------------------------------------------------------------*/ +#define MASK_NULL8 0x00 +#define MASK_NULL16 0x0000 +#define MASK_NULL32 0x00000000 +#define MASK_ALL8 0xFF +#define MASK_ALL16 0xFFFF +#define MASK_ALL32 0xFFFFFFFF + +#define MASK_BIT0 (1UL<<0) +#define MASK_BIT1 (1UL<<1) +#define MASK_BIT2 (1UL<<2) +#define MASK_BIT3 (1UL<<3) +#define MASK_BIT4 (1UL<<4) +#define MASK_BIT5 (1UL<<5) +#define MASK_BIT6 (1UL<<6) +#define MASK_BIT7 (1UL<<7) +#define MASK_BIT8 (1UL<<8) +#define MASK_BIT9 (1UL<<9) +#define MASK_BIT10 (1UL<<10) +#define MASK_BIT11 (1UL<<11) +#define MASK_BIT12 (1UL<<12) +#define MASK_BIT13 (1UL<<13) +#define MASK_BIT14 (1UL<<14) +#define MASK_BIT15 (1UL<<15) +#define MASK_BIT16 (1UL<<16) +#define MASK_BIT17 (1UL<<17) +#define MASK_BIT18 (1UL<<18) +#define MASK_BIT19 (1UL<<19) +#define MASK_BIT20 (1UL<<20) +#define MASK_BIT21 (1UL<<21) +#define MASK_BIT22 (1UL<<22) +#define MASK_BIT23 (1UL<<23) +#define MASK_BIT24 (1UL<<24) +#define MASK_BIT25 (1UL<<25) +#define MASK_BIT26 (1UL<<26) +#define MASK_BIT27 (1UL<<27) +#define MASK_BIT28 (1UL<<28) +#define MASK_BIT29 (1UL<<29) +#define MASK_BIT30 (1UL<<30) +#define MASK_BIT31 (1UL<<31) + +#define NOMADIK_INTERNAL_ERROR (-8) +#define NOMADIK_NOT_CONFIGURED (-7) +#define NOMADIK_REQUEST_PENDING (-6) +#define NOMADIK_REQUEST_NOT_APPLICABLE (-5) +#define NOMADIK_INVALID_PARAMETER (-4) +#define NOMADIK_UNSUPPORTED_FEATURE (-3) +#define NOMADIK_UNSUPPORTED_HW (-2) +#define NOMADIK_ERROR (-1) +#define NOMADIK_OK ( 0) +#define NOMADIK_INTERNAL_EVENT ( 1) +#define NOMADIK_REMAINING_PENDING_EVENTS ( 2) +#define NOMADIK_REMAINING_FILTER_PENDING_EVENTS ( 3) +#define NOMADIK_NO_MORE_PENDING_EVENT ( 4) +#define NOMADIK_NO_MORE_FILTER_PENDING_EVENT ( 5) +#define NOMADIK_NO_PENDING_EVENT_ERROR ( 7) + + +#define NOMADIK_MAX_ERROR_VALUE (-65) /* HW specific error codes + * should start from this offset + */ +/*----------------------------------------------------------------------------- + * Bit setting or clearing + *---------------------------------------------------------------------------*/ +#define NOMADIK_SET_BITS(reg,mask) ((reg) |= (mask)) +#define NOMADIK_CLEAR_BITS(reg,mask) ((reg) &= ~(mask)) +#define NOMADIK_READ_BITS(reg,mask) ((reg) & (mask)) +#define NOMADIK_WRITE_BITS(reg,val,mask) ((reg) = (((reg) & ~(mask)) | ((val) & (mask)))) +#define NOMADIK_READ_REG(reg) (reg) +#define NOMADIK_WRITE_REG(reg,val) ((reg) = (val)) + +/* + * Definition of the different kind of addresses manipulated into a system with MMU + * (handle physical AND logical addresses) + */ + +typedef u32 t_physical_address; +typedef u32 t_logical_address; + +/*function prototypes*/ +void gpio_init(void); +int emmc_init (u8); + +#endif /* _COMMON_H_ */ diff --git a/board/st/u8500/config.mk b/board/st/u8500/config.mk new file mode 100755 index 000000000..a75eda429 --- /dev/null +++ b/board/st/u8500/config.mk @@ -0,0 +1,5 @@ +# +# image should be loaded at 0x01000000 +# + +TEXT_BASE = 0x07F80000 diff --git a/board/st/u8500/emmc.c b/board/st/u8500/emmc.c new file mode 100755 index 000000000..780ddaebc --- /dev/null +++ b/board/st/u8500/emmc.c @@ -0,0 +1,404 @@ +/* +* (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" + +#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] = 0x00; + emmc_last_sector[0x1FC] = 0xC0; + 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); + + 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) + { + 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 ---------------------------- */ diff --git a/board/st/u8500/emmc.h b/board/st/u8500/emmc.h new file mode 100755 index 000000000..aa4b48df0 --- /dev/null +++ b/board/st/u8500/emmc.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +#ifndef _STM_EMMC_H +#define _STM_EMMC_H + + +#include <common.h> + +extern int emmc_init (u8); +int emmc_erase(u32, u32); +int emmc_read (u32,u32,u32); +int emmc_write(u32,u32,u32); +int emmc_write_pib(void); + + +#endif /* !defined(_STM_EMMC_H) */ diff --git a/board/st/u8500/flash.c b/board/st/u8500/flash.c new file mode 100755 index 000000000..299c31992 --- /dev/null +++ b/board/st/u8500/flash.c @@ -0,0 +1,109 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +/* Support for ST NOR flash M30L0R7KB02AQ and M30L0R7KT02AQ */ + +#include <common.h> +#include <linux/byteorder/swab.h> + +#undef DEBUG_FLASH +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/* Board support for 1 or 2 flash devices */ +#undef FLASH_PORT_WIDTH32 +#define FLASH_PORT_WIDTH16 + +#ifdef FLASH_PORT_WIDTH16 +#define FLASH_PORT_WIDTH ushort +#define FLASH_PORT_WIDTHV vu_short +#define SWAP(x) __swab16(x) +#else +#define FLASH_PORT_WIDTH ulong +#define FLASH_PORT_WIDTHV vu_long +#define SWAP(x) __swab32(x) +#endif + +#define FPW FLASH_PORT_WIDTH +#define FPWV FLASH_PORT_WIDTHV + +/*----------------------------------------------------------------------- + * Functions + */ +unsigned long flash_init(void); +/*static ulong flash_get_size(FPW * addr, flash_info_t * info); +static int write_data(flash_info_t * info, ulong dest, FPW data); +static void flash_get_offsets(ulong base, flash_info_t * info);*/ +void inline spin_wheel(void); +void flash_print_info(flash_info_t * info); +void flash_unprotect_sectors(FPWV * addr); +int flash_erase(flash_info_t * info, int s_first, int s_last); +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt); + +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init(void) +{ + ulong size = 0; + return size; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info(flash_info_t * info) +{ +} + +/* unprotects a sector for write and erase + * on some intel parts, this unprotects the entire chip, but it + * wont hurt to call this additional times per sector... + */ +void flash_unprotect_sectors(FPWV * addr) +{ + return; +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase(flash_info_t * info, int s_first, int s_last) +{ + return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * 4 - Flash not identified + */ + +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + return 0; +} + +void inline spin_wheel(void) +{ +} diff --git a/board/st/u8500/gpio.c b/board/st/u8500/gpio.c new file mode 100755 index 000000000..4062d022b --- /dev/null +++ b/board/st/u8500/gpio.c @@ -0,0 +1,253 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 "gpio.h" + +static struct gpio_register *addr_gpio_register[GPIO_BLOCKS_COUNT]; + +int sz_altfun_tbl; + +struct gpio_altfun_data altfun_table[] = { + {.altfun = GPIO_ALT_UART_0_MODEM,.start = 0,.end = 3,.cont = 1,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_UART_0_MODEM,.start = 33,.end = 36,.cont = 0,.type = + GPIO_ALTF_C,}, + {.altfun = GPIO_ALT_UART_1,.start = 4,.end = 7,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_UART_2,.start = 18,.end = 19,.cont = 1,.type = + GPIO_ALTF_B,}, + {.altfun = GPIO_ALT_UART_2,.start = 29,.end = 32,.cont = 0,.type = + GPIO_ALTF_C,}, + {.altfun = GPIO_ALT_MSP_0,.start = 12,.end = 17,.cont = 1,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_MSP_0,.start = 21,.end = 21,.cont = 0,.type = + GPIO_ALTF_B,}, + {.altfun = GPIO_ALT_MSP_1,.start = 33,.end = 36,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_MSP_2,.start = 192,.end = 196,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_LCD_PANEL,.start = 64,.end = 93,.cont = 1,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_LCD_PANEL,.start = 150,.end = 171,.cont = 0,.type = + GPIO_ALTF_B,}, + {.altfun = GPIO_ALT_SD_CARD0,.start = 18,.end = 28,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_MM_CARD0,.start = 18,.end = 32,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_USB_OTG,.start = 256,.end = 267,.cont = 0,.type = + GPIO_ALTF_A,}, + {.altfun = GPIO_ALT_EMMC,.start = 197,.end = 207,.cont = 0,.type = + GPIO_ALTF_A,}, +#ifdef CONFIG_STM_8500_V1 + {.altfun = GPIO_ALT_POP_EMMC,.start = 128,.end = 138,.cont = 0,.type = + GPIO_ALTF_A,}, +#endif +}; + +/* + * Static Function declarations + */ +gpio_error gpio_setpinconfig(gpio_pin pin_id, gpio_config * config) +{ + struct gpio_register *p_gpio_register = addr_gpio_register[GPIO_BLOCK(pin_id)]; + u32 mask = 1UL << (pin_id % GPIO_PINS_PER_BLOCK); + gpio_error gpio_error = GPIO_OK; + u32 temp_reg; + + switch (config->mode) { + case GPIO_ALTF_A: + temp_reg = readl(&p_gpio_register->gpio_afsa); + temp_reg |= mask; + writel(temp_reg, &p_gpio_register->gpio_afsa); + temp_reg = readl(&p_gpio_register->gpio_afsb); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsb); + break; + case GPIO_ALTF_B: + temp_reg = readl(&p_gpio_register->gpio_afsa); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsa); + temp_reg = readl(&p_gpio_register->gpio_afsb); + temp_reg |= mask; + writel(temp_reg, &p_gpio_register->gpio_afsb); + break; + case GPIO_ALTF_C: + temp_reg = readl(&p_gpio_register->gpio_afsa); + temp_reg |= mask; + writel(temp_reg, &p_gpio_register->gpio_afsa); + temp_reg = readl(&p_gpio_register->gpio_afsb); + temp_reg |= mask; + writel(temp_reg, &p_gpio_register->gpio_afsb); + break; + case GPIO_MODE_SOFTWARE: + temp_reg = readl(&p_gpio_register->gpio_afsa); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsa); + temp_reg = readl(&p_gpio_register->gpio_afsb); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsb); + + switch (config->direction) { + case GPIO_DIR_INPUT: + writel(mask, &p_gpio_register->gpio_dirc); + break; + case GPIO_DIR_OUTPUT: + writel(mask, &p_gpio_register->gpio_dirs); + break; + case GPIO_DIR_LEAVE_UNCHANGED: + break; + default: + return (GPIO_INVALID_PARAMETER); + } + + break; + case GPIO_MODE_LEAVE_UNCHANGED: + break; + default: + return (GPIO_INVALID_PARAMETER); + } + return (gpio_error); +} + +gpio_error gpio_resetgpiopin(gpio_pin pin_id, char *dev_name) +{ + struct gpio_register *p_gpio_register = addr_gpio_register[GPIO_BLOCK(pin_id)]; + u32 mask = 1UL << (pin_id % GPIO_PINS_PER_BLOCK); + gpio_error gpio_error = GPIO_OK; + u32 temp_reg; + + temp_reg = readl(&p_gpio_register->gpio_afsa); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsa); + temp_reg = readl(&p_gpio_register->gpio_afsb); + temp_reg &= ~mask; + writel(temp_reg, &p_gpio_register->gpio_afsb); + writel(mask, &p_gpio_register->gpio_dirc); + + return (gpio_error); +} + +gpio_config altfun_pinconfig; +gpio_error gpio_altfunction(gpio_alt_function alt_func, + int which_altfunc, char *dev_name) +{ + int i, j, start, end; + gpio_error error = -1; + + for (i = 0; i < sz_altfun_tbl; i++) { + if (altfun_table[i].altfun == alt_func) + break; + } + start = altfun_table[i].start; + end = altfun_table[i].end; + for (j = start; j <= end; j++) { + { + if (which_altfunc == GPIO_ALTF_FIND) { + altfun_pinconfig.mode = + altfun_table[i].type; + } else { + altfun_pinconfig.mode = which_altfunc; + } + altfun_pinconfig.direction = GPIO_DIR_OUTPUT; + altfun_pinconfig.dev_name = dev_name; + + if (which_altfunc != GPIO_ALTF_DISABLE) { + error = + gpio_setpinconfig(j, + &altfun_pinconfig); + } else { + error = gpio_resetgpiopin(j, dev_name); + } + if (!error) + continue; + nmdk_error + ("GPIO %d configuration failure (nmdk_error:%d)", + j, error); + error = GPIO_INVALID_PARAMETER; + return (error); + } + } + return (error); +} + +int gpio_writepin(gpio_pin pin_id, gpio_data value, char *dev_name) +{ + struct gpio_register *p_gpio_register = addr_gpio_register[GPIO_BLOCK(pin_id)]; + u32 mask = 1UL << (pin_id % GPIO_PINS_PER_BLOCK); + + switch (value) { + case GPIO_DATA_HIGH: + writel(mask, &p_gpio_register->gpio_dats); + break; + case GPIO_DATA_LOW: + writel(mask, &p_gpio_register->gpio_datc); + break; + default: + nmdk_error("Invalid value passed in %s", __FUNCTION__); + return GPIO_INVALID_PARAMETER; + } + return GPIO_OK; +} + +int gpio_readpin(gpio_pin pin_id, gpio_data * p_value) +{ + struct gpio_register *p_gpio_register = addr_gpio_register[GPIO_BLOCK(pin_id)]; + u32 mask = 1UL << (pin_id % GPIO_PINS_PER_BLOCK); + + if ((readl(&p_gpio_register->gpio_dat) & mask) != 0) { + *p_value = GPIO_DATA_HIGH; + } else { + *p_value = GPIO_DATA_LOW; + } + return GPIO_OK; +} + + +int gpio_altfuncenable(gpio_alt_function altfunc, char *dev_name) +{ + return (int)gpio_altfunction(altfunc, GPIO_ALTF_FIND, dev_name); +} + +int gpio_altfuncdisable(gpio_alt_function altfunc, char *dev_name) +{ + return (int)gpio_altfunction(altfunc, GPIO_ALTF_DISABLE, dev_name); +} + +void gpio_init(void) +{ + + sz_altfun_tbl = sizeof(altfun_table) / sizeof(altfun_table[0]); + + addr_gpio_register[0] =(void *) IO_ADDRESS(CFG_GPIO_0_BASE); + addr_gpio_register[1] =(void *) IO_ADDRESS(CFG_GPIO_1_BASE); + addr_gpio_register[2] =(void *) IO_ADDRESS(CFG_GPIO_2_BASE); + addr_gpio_register[3] =(void *) IO_ADDRESS(CFG_GPIO_3_BASE); + addr_gpio_register[4] =(void *) IO_ADDRESS(CFG_GPIO_4_BASE); + addr_gpio_register[5] =(void *) IO_ADDRESS(CFG_GPIO_5_BASE); + addr_gpio_register[6] =(void *) IO_ADDRESS(CFG_GPIO_6_BASE); + addr_gpio_register[7] =(void *) IO_ADDRESS(CFG_GPIO_7_BASE); + addr_gpio_register[8] =(void *) IO_ADDRESS(CFG_GPIO_8_BASE); + + return; +} diff --git a/board/st/u8500/gpio.h b/board/st/u8500/gpio.h new file mode 100755 index 000000000..37908ad37 --- /dev/null +++ b/board/st/u8500/gpio.h @@ -0,0 +1,524 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _MOP500_GPIO_h +#define _MOP500_GPIO_h + +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include "common.h" +#include <configs/u8500.h> + +#define GPIO_TOTAL_PINS 268 + +#define GPIO_PINS_PER_BLOCK 32 +#define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK +1) +#define GPIO_BLOCK(pin) ( ( ( pin + GPIO_PINS_PER_BLOCK ) >> 5) - 1 ) + + +struct gpio_register { + u32 gpio_dat; /* GPIO data register *//*0x000 */ + u32 gpio_dats; /* GPIO data Set register *//*0x004 */ + u32 gpio_datc; /* GPIO data Clear register *//*0x008 */ + u32 gpio_pdis; /* GPIO Pull disable register *//*0x00C */ + u32 gpio_dir; /* GPIO data direction register *//*0x010 */ + u32 gpio_dirs; /* GPIO data dir Set register *//*0x014 */ + u32 gpio_dirc; /* GPIO data dir Clear register *//*0x018 */ + u32 gpio_slpm; /* GPIO Sleep mode register *//*0x01C */ + u32 gpio_afsa; /* GPIO AltFun A Select reg *//*0x020 */ + u32 gpio_afsb; /* GPIO AltFun B Select reg *//*0x024 */ + u32 gpio_lowemi; /* GPIO low EMI Select reg *//*0x028 */ + u32 reserved_1[(0x040 - 0x02C) >> 2]; /*0x028-0x3C Reserved*/ + u32 gpio_rimsc; /* GPIO rising edge intr set/clear *//*0x040 */ + u32 gpio_fimsc; /* GPIO falling edge interrupt set/clear register *//*0x044 */ + u32 gpio_mis; /* GPIO masked interrupt status register *//*0x048 */ + u32 gpio_ic; /* GPIO Interrupt Clear register *//*0x04C */ + u32 gpio_rwimsc; /* GPIO Rising-edge Wakeup IMSC register *//*0x050 */ + u32 gpio_fwimsc; /* GPIO Falling-edge Wakeup IMSC register *//*0x054 */ + u32 gpio_wks; /* GPIO Wakeup Status register *//*0x058 */ +}; + +/* Error values returned by functions */ +typedef enum { + GPIO_OK = 0, /* (0) */ + GPIO_UNSUPPORTED_HW = -2, /* NOMADIK_UNSUPPORTED_HW, (-2) */ + GPIO_UNSUPPORTED_FEATURE = -3, /* NOMADIK_UNSUPPORTED_FEATURE, (-3) */ + GPIO_INVALID_PARAMETER = -4, /* NOMADIK_INVALID_PARAMETER, (-4) */ + GPIO_REQUEST_NOT_APPLICABLE = -5, /* NOMADIK_REQUEST_NOT_APPLICABLE, (-5) */ + GPIO_REQUEST_PENDING = -6, /* NOMADIK_REQUEST_PENDING, (-6) */ + GPIO_NOT_CONFIGURED = -7, /* NOMADIK_NOT_CONFIGURED, (-7) */ + GPIO_INTERNAL_ERROR = -8, /* NOMADIK_INTERNAL_ERROR, (-8) */ + GPIO_INTERNAL_EVENT = 1, /* NOMADIK_INTERNAL_EVENT,*/ + GPIO_REMAINING_EVENT = 2, /* NOMADIK_REMAINING_PENDING_EVENTS,*/ + GPIO_NO_MORE_PENDING_EVENT = 3, /* NOMADIK_NO_MORE_PENDING_EVENT,*/ + GPIO_INVALID_CLIENT = -25, + GPIO_INVALID_PIN = -26, + GPIO_PIN_BUSY = -27, + GPIO_PIN_NOT_ALLOCATED = -28, + GPIO_WRONG_CLIENT = -29, + GPIO_UNSUPPORTED_ALTFUNC = -30, + +} gpio_error; + +/*GPIO DEVICE ID */ +typedef enum { + GPIO_DEVICE_ID_0, + GPIO_DEVICE_ID_1, + GPIO_DEVICE_ID_2, + GPIO_DEVICE_ID_3, + GPIO_DEVICE_ID_INVALID +} gpio_device_id; + +/* + * Pin description To be used in SOFTWARE mode: refers to a pin. + */ +typedef enum { + GPIO_PIN_0, + GPIO_PIN_1, + GPIO_PIN_2, + GPIO_PIN_3, + GPIO_PIN_4, + GPIO_PIN_5, + GPIO_PIN_6, + GPIO_PIN_7, + GPIO_PIN_8, + GPIO_PIN_9, + GPIO_PIN_10, + GPIO_PIN_11, + GPIO_PIN_12, + GPIO_PIN_13, + GPIO_PIN_14, + GPIO_PIN_15, + GPIO_PIN_16, + GPIO_PIN_17, + GPIO_PIN_18, + GPIO_PIN_19, + GPIO_PIN_20, + GPIO_PIN_21, + GPIO_PIN_22, + GPIO_PIN_23, + GPIO_PIN_24, + GPIO_PIN_25, + GPIO_PIN_26, + GPIO_PIN_27, + GPIO_PIN_28, + GPIO_PIN_29, + GPIO_PIN_30, + GPIO_PIN_31, + GPIO_PIN_32, + GPIO_PIN_33, + GPIO_PIN_34, + GPIO_PIN_35, + GPIO_PIN_36, + GPIO_PIN_37, + GPIO_PIN_38, + GPIO_PIN_39, + GPIO_PIN_40, + GPIO_PIN_41, + GPIO_PIN_42, + GPIO_PIN_43, + GPIO_PIN_44, + GPIO_PIN_45, + GPIO_PIN_46, + GPIO_PIN_47, + GPIO_PIN_48, + GPIO_PIN_49, + GPIO_PIN_50, + GPIO_PIN_51, + GPIO_PIN_52, + GPIO_PIN_53, + GPIO_PIN_54, + GPIO_PIN_55, + GPIO_PIN_56, + GPIO_PIN_57, + GPIO_PIN_58, + GPIO_PIN_59, + GPIO_PIN_60, + GPIO_PIN_61, + GPIO_PIN_62, + GPIO_PIN_63, + GPIO_PIN_64, + GPIO_PIN_65, + GPIO_PIN_66, + GPIO_PIN_67, + GPIO_PIN_68, + GPIO_PIN_69, + GPIO_PIN_70, + GPIO_PIN_71, + GPIO_PIN_72, + GPIO_PIN_73, + GPIO_PIN_74, + GPIO_PIN_75, + GPIO_PIN_76, + GPIO_PIN_77, + GPIO_PIN_78, + GPIO_PIN_79, + GPIO_PIN_80, + GPIO_PIN_81, + GPIO_PIN_82, + GPIO_PIN_83, + GPIO_PIN_84, + GPIO_PIN_85, + GPIO_PIN_86, + GPIO_PIN_87, + GPIO_PIN_88, + GPIO_PIN_89, + GPIO_PIN_90, + GPIO_PIN_91, + GPIO_PIN_92, + GPIO_PIN_93, + GPIO_PIN_94, + GPIO_PIN_95, + GPIO_PIN_96, + GPIO_PIN_97, + GPIO_PIN_98, + GPIO_PIN_99, + GPIO_PIN_100, + GPIO_PIN_101, + GPIO_PIN_102, + GPIO_PIN_103, + GPIO_PIN_104, + GPIO_PIN_105, + GPIO_PIN_106, + GPIO_PIN_107, + GPIO_PIN_108, + GPIO_PIN_109, + GPIO_PIN_110, + GPIO_PIN_111, + GPIO_PIN_112, + GPIO_PIN_113, + GPIO_PIN_114, + GPIO_PIN_115, + GPIO_PIN_116, + GPIO_PIN_117, + GPIO_PIN_118, + GPIO_PIN_119, + GPIO_PIN_120, + GPIO_PIN_121, + GPIO_PIN_122, + GPIO_PIN_123, + GPIO_PIN_124, + GPIO_PIN_125, + GPIO_PIN_126, + GPIO_PIN_127, + GPIO_PIN_128, + GPIO_PIN_129, + GPIO_PIN_130, + GPIO_PIN_131, + GPIO_PIN_132, + GPIO_PIN_133, + GPIO_PIN_134, + GPIO_PIN_135, + GPIO_PIN_136, + GPIO_PIN_137, + GPIO_PIN_138, + GPIO_PIN_139, + GPIO_PIN_140, + GPIO_PIN_141, + GPIO_PIN_142, + GPIO_PIN_143, + GPIO_PIN_144, + GPIO_PIN_145, + GPIO_PIN_146, + GPIO_PIN_147, + GPIO_PIN_148, + GPIO_PIN_149, + GPIO_PIN_150, + GPIO_PIN_151, + GPIO_PIN_152, + GPIO_PIN_153, + GPIO_PIN_154, + GPIO_PIN_155, + GPIO_PIN_156, + GPIO_PIN_157, + GPIO_PIN_158, + GPIO_PIN_159, + GPIO_PIN_160, + GPIO_PIN_161, + GPIO_PIN_162, + GPIO_PIN_163, + GPIO_PIN_164, + GPIO_PIN_165, + GPIO_PIN_166, + GPIO_PIN_167, + GPIO_PIN_168, + GPIO_PIN_169, + GPIO_PIN_170, + GPIO_PIN_171, + GPIO_PIN_172, + GPIO_PIN_173, + GPIO_PIN_174, + GPIO_PIN_175, + GPIO_PIN_176, + GPIO_PIN_177, + GPIO_PIN_178, + GPIO_PIN_179, + GPIO_PIN_180, + GPIO_PIN_181, + GPIO_PIN_182, + GPIO_PIN_183, + GPIO_PIN_184, + GPIO_PIN_185, + GPIO_PIN_186, + GPIO_PIN_187, + GPIO_PIN_188, + GPIO_PIN_189, + GPIO_PIN_190, + GPIO_PIN_191, + GPIO_PIN_192, + GPIO_PIN_193, + GPIO_PIN_194, + GPIO_PIN_195, + GPIO_PIN_196, + GPIO_PIN_197, + GPIO_PIN_198, + GPIO_PIN_199, + GPIO_PIN_200, + GPIO_PIN_201, + GPIO_PIN_202, + GPIO_PIN_203, + GPIO_PIN_204, + GPIO_PIN_205, + GPIO_PIN_206, + GPIO_PIN_207, + GPIO_PIN_208, + GPIO_PIN_209, + GPIO_PIN_210, + GPIO_PIN_211, + GPIO_PIN_212, + GPIO_PIN_213, + GPIO_PIN_214, + GPIO_PIN_215, + GPIO_PIN_216, + GPIO_PIN_217, + GPIO_PIN_218, + GPIO_PIN_219, + GPIO_PIN_220, + GPIO_PIN_221, + GPIO_PIN_222, + GPIO_PIN_223, + GPIO_PIN_224, + GPIO_PIN_225, + GPIO_PIN_226, + GPIO_PIN_227, + GPIO_PIN_228, + GPIO_PIN_229, + GPIO_PIN_230, + GPIO_PIN_231, + GPIO_PIN_232, + GPIO_PIN_233, + GPIO_PIN_234, + GPIO_PIN_235, + GPIO_PIN_236, + GPIO_PIN_237, + GPIO_PIN_238, + GPIO_PIN_239, + GPIO_PIN_240, + GPIO_PIN_241, + GPIO_PIN_242, + GPIO_PIN_243, + GPIO_PIN_244, + GPIO_PIN_245, + GPIO_PIN_246, + GPIO_PIN_247, + GPIO_PIN_248, + GPIO_PIN_249, + GPIO_PIN_250, + GPIO_PIN_251, + GPIO_PIN_252, + GPIO_PIN_253, + GPIO_PIN_254, + GPIO_PIN_255, + GPIO_PIN_256, + GPIO_PIN_257, + GPIO_PIN_258, + GPIO_PIN_259, + GPIO_PIN_260, + GPIO_PIN_261, + GPIO_PIN_262, + GPIO_PIN_263, + GPIO_PIN_264, + GPIO_PIN_265, + GPIO_PIN_266, + GPIO_PIN_267 +} gpio_pin; + +/* + * Alternate Function: + * refered in altfun_table to pointout particular altfun to be enabled + * when using GPIO_ALT_FUNCTION A/B/C enable/disable operation + */ +typedef enum { + GPIO_ALT_UART_0_MODEM, + GPIO_ALT_UART_0_NO_MODEM, + GPIO_ALT_UART_1, + GPIO_ALT_UART_2, + GPIO_ALT_I2C_0, + GPIO_ALT_I2C_1, + GPIO_ALT_MSP_0, + GPIO_ALT_MSP_1, + GPIO_ALT_MSP_2, + GPIO_ALT_MSP_3, + GPIO_ALT_MSP_4, + GPIO_ALT_MSP_5, + GPIO_ALT_SSP_0, + GPIO_ALT_SSP_1, + GPIO_ALT_MM_CARD0, + GPIO_ALT_SD_CARD0, + GPIO_ALT_DMA_0, + GPIO_ALT_DMA_1, + GPIO_ALT_HSI0, + GPIO_ALT_CCIR656_INPUT, + GPIO_ALT_CCIR656_OUTPUT, + GPIO_ALT_LCD_PANEL, + GPIO_ALT_MDIF, + GPIO_ALT_SDRAM, + GPIO_ALT_HAMAC_AUDIO_DBG, + GPIO_ALT_HAMAC_VIDEO_DBG, + GPIO_ALT_CLOCK_RESET, + GPIO_ALT_TSP, + GPIO_ALT_IRDA, + GPIO_ALT_USB_MINIMUM, + GPIO_ALT_USB_I2C, + GPIO_ALT_OWM, + GPIO_ALT_PWL, + GPIO_ALT_FSMC, + GPIO_ALT_COMP_FLASH, + GPIO_ALT_SRAM_NOR_FLASH, + GPIO_ALT_FSMC_ADDLINE_0_TO_15, + GPIO_ALT_SCROLL_KEY, + GPIO_ALT_MSHC, + GPIO_ALT_HPI, + GPIO_ALT_USB_OTG, + GPIO_ALT_SDIO, + GPIO_ALT_HSMMC, + GPIO_ALT_FSMC_ADD_DATA_0_TO_25, + GPIO_ALT_HSI1, + GPIO_ALT_NOR, + GPIO_ALT_NAND, + GPIO_ALT_KEYPAD, + GPIO_ALT_VPIP, + GPIO_ALT_CAM, + GPIO_ALT_CCP1, + GPIO_ALT_EMMC, +#ifdef CONFIG_NOMADIK_8500_V1 + GPIO_ALT_POP_EMMC, +#endif + GPIO_ALT_FUNMAX /* Add new alt func before this */ +} gpio_alt_function; + +/* Defines pin assignment(Software mode or Alternate mode) */ +typedef enum { + GPIO_MODE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_MODE_SOFTWARE, /* Pin connected to GPIO (SW controlled) */ + GPIO_ALTF_A, /* Pin connected to alternate function 1 (HW periph 1) */ + GPIO_ALTF_B, /* Pin connected to alternate function 2 (HW periph 2) */ + GPIO_ALTF_C, /* Pin connected to alternate function 3 (HW periph 3) */ + GPIO_ALTF_FIND, /* Pin connected to alternate function 3 (HW periph 3) */ + GPIO_ALTF_DISABLE /* Pin connected to alternate function 3 (HW periph 3) */ +} gpio_mode; + +/* Defines GPIO pin direction */ +typedef enum { + GPIO_DIR_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_DIR_INPUT, /* GPIO set as input */ + GPIO_DIR_OUTPUT /* GPIO set as output */ +} gpio_direction; + +/* Interrupt trigger mode */ +typedef enum { + GPIO_TRIG_LEAVE_UNCHANGED, /* Parameter will be ignored by the function */ + GPIO_TRIG_DISABLE, /* Triggers no IT */ + GPIO_TRIG_RISING_EDGE, /* Triggers an IT on a rising edge */ + GPIO_TRIG_FALLING_EDGE, /* Triggers an IT on a falling edge */ + GPIO_TRIG_BOTH_EDGES, /* Triggers an IT on a rising and a falling edge */ + GPIO_TRIG_HIGH_LEVEL, /* Triggers an IT on a high level */ + GPIO_TRIG_LOW_LEVEL /* Triggers an IT on a low level */ +} gpio_trig; /* Interrupt trigger mode, or disable */ + +/* Configuration parameters for one GPIO pin.*/ +typedef struct { + gpio_mode mode; /* Defines mode (SOFTWARE or Alternate). */ + gpio_direction direction; /* Define pin direction (in SOFTWARE mode only). */ + gpio_trig trig; /* Interrupt trigger (in SOFTWARE mode only) */ + char *dev_name; /* Name of client driver who owns the gpio pin */ +} gpio_config; + +/* GPIO pin data*/ +typedef enum { + GPIO_DATA_LOW, /* GPIO pin status is low. */ + GPIO_DATA_HIGH /* GPIO pin status is high. */ +} gpio_data; + +/* GPIO behaviour in sleep mode */ +typedef enum { + GPIO_SLEEP_MODE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_SLEEP_MODE_INPUT_DEFAULTVOLT, /* GPIO is an input with pull up/down enabled + when in sleep mode. */ + GPIO_SLEEP_MODE_CONTROLLED_BY_GPIO /* GPIO pin is controlled by GPIO IP. So mode, + direction and data values for GPIO pin in + sleep mode are determined by configuration + set to GPIO pin before entering to sleep mode. */ +} gpio_sleep_mode; + +/* GPIO ability to wake the system up from sleep mode.*/ +typedef enum { + GPIO_WAKE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_WAKE_DISABLE, /* GPIO will not wake the system from sleep mode. */ + GPIO_WAKE_LOW_LEVEL, /* GPIO will wake the system up on a LOW level. */ + GPIO_WAKE_HIGH_LEVEL, /* GPIO will wake the system up on a HIGH level. */ + GPIO_WAKE_RISING_EDGE, /* GPIO will wake the system up on a RISING edge. */ + GPIO_WAKE_FALLING_EDGE, /* GPIO will wake the system up on a FALLING edge. */ + GPIO_WAKE_BOTH_EDGES /* GPIO will wake the system up on both RISING and FALLING edge. */ +} gpio_wake; + +/* Configuration parameters for one GPIO pin in sleep mode.*/ +typedef struct { + gpio_sleep_mode sleep_mode; /* GPIO behaviour in sleep mode. */ + gpio_wake wake; /* GPIO ability to wake up the system. */ +} gpio_sleep_config; + +/*------------------------------------------------------------------------ + * Functions declaration + * refer ./Documentation/arm/STM-Nomadik/gpio_user_guide.txt + *----------------------------------------------------------------------*/ + +extern gpio_error gpio_setpinconfig(gpio_pin pin_id, gpio_config * pin_config); +extern gpio_error gpio_resetpinconfig(gpio_pin pin_id, char *dev_name); +extern int gpio_writepin(gpio_pin pin_id, gpio_data value, char *dev_name); +extern int gpio_readpin(gpio_pin pin_id, gpio_data * value); +extern int gpio_altfuncenable(gpio_alt_function altfunc, + char *dev_name); +extern int gpio_altfuncdisable(gpio_alt_function altfunc, + char *dev_name); + +struct gpio_altfun_data { + u16 altfun; + u16 start; + u16 end; + t_bool cont; + u8 type; +}; + +#endif /* __INC_GPIO_H */ diff --git a/board/st/u8500/i2c.c b/board/st/u8500/i2c.c new file mode 100755 index 000000000..9c23c29db --- /dev/null +++ b/board/st/u8500/i2c.c @@ -0,0 +1,3029 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +#include "i2c.h" + +/*--------------------------------------------------------------------------- + * defines + *---------------------------------------------------------------------------*/ +/* 8500 has 4 I2C controllers */ +t_i2c_registers *gp_i2c_registers[4]; + +#define I2C_ENDAD_COUNTER 500000 +#define I2C_INT_ENDED_COUNTER 5 +#define I2C_BTF_COUNTER 5 +#define I2C_BTF_COUNTER_POLLING 10 +#define I2C_FIFO_FLUSH_COUNTER 500 + +/*----------------------------------------------------------------------------- +Global variables +-----------------------------------------------------------------------------*/ + +/* 8500 has 4 I2C Controllers */ + volatile t_i2c_system_context g_i2c_system_context[4]; + +#undef I2C_DEBUG +#ifdef I2C_DEBUG +#define info(fmt,args...) printf("I2C: "fmt, ##args) +#else +#define info(fmt,args...) (void) 0; +#endif + + +/*----------------------------------------------------------------------------- + Configuration functions +-----------------------------------------------------------------------------*/ +/****************************************************************************/ +/* NAME : I2C_Init */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Initialize the given I2C controller by specifying the */ +/* base logical address. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_logical_address : The controller's logical address */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are invalid */ +/* I2C_UNSUPPORTED_HW if peripheral ids are not matched */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_Init(t_i2c_device_id id, t_logical_address address) +{ + t_i2c_registers *p_i2c_registers; + + /* + Check if the controller id is valid. + */ + + + if (((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id) ) || (NULL == address)) + { + return(I2C_INVALID_PARAMETER); + } + + + + p_i2c_registers = (t_i2c_registers *) address; + + + if + ( + (I2C_P_ID_0 != p_i2c_registers->periph_id_0) + || (I2C_P_ID_1 != p_i2c_registers->periph_id_1) + || (I2C_P_ID_2 != p_i2c_registers->periph_id_2) + || (I2C_P_ID_3 != p_i2c_registers->periph_id_3) + || (I2C_CELL_ID_0 != p_i2c_registers->cell_id_0) + || (I2C_CELL_ID_1 != p_i2c_registers->cell_id_1) + || (I2C_CELL_ID_2 != p_i2c_registers->cell_id_2) + || (I2C_CELL_ID_3 != p_i2c_registers->cell_id_3) + ) + { + return(I2C_UNSUPPORTED_HW); + } + + + /* + Initialize the right structure and save the base address. + */ + g_i2c_system_context[id].base_address = address; + g_i2c_system_context[id].freq_scl = 0; + g_i2c_system_context[id].freq_input = 0; + g_i2c_system_context[id].mode = I2C_FREQ_MODE_STANDARD; + g_i2c_system_context[id].own_address = 0; + g_i2c_system_context[id].enabled = FALSE; + g_i2c_system_context[id].slave_address = 0; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].data = 0; + g_i2c_system_context[id].databuffer = NULL; + g_i2c_system_context[id].count_data = 0; + g_i2c_system_context[id].register_index = 0; + g_i2c_system_context[id].operation = (t_i2c_operation) I2C_NO_OPERATION; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = FALSE; + + /* g_i2c_system_context[id].i2c_device_context... to be initialized*/ + g_i2c_system_context[id].digital_filter_control = I2C_DIGITAL_FILTERS_OFF; + g_i2c_system_context[id].dma_sync_logic_control = I2C_DISABLE; + g_i2c_system_context[id].start_byte_procedure = I2C_DISABLE; + g_i2c_system_context[id].slave_data_setup_time = 0; /* TBD */ + g_i2c_system_context[id].high_speed_master_code = 0; + g_i2c_system_context[id].bus_control_mode = I2C_BUS_SLAVE_MODE; + g_i2c_system_context[id].i2c_loopback_mode = I2C_DISABLE; + g_i2c_system_context[id].general_call_mode_handling = I2C_NO_GENERAL_CALL_HANDLING; + + g_i2c_system_context[id].index_transfer_mode = I2C_TRANSFER_MODE_POLLING; + g_i2c_system_context[id].data_transfer_mode = I2C_TRANSFER_MODE_POLLING; + g_i2c_system_context[id].i2c_transmit_interrupt_threshold = 1; + g_i2c_system_context[id].i2c_receive_interrupt_threshold = 1; + g_i2c_system_context[id].transmit_burst_length = 0; + g_i2c_system_context[id].receive_burst_length = 0; + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + g_i2c_system_context[id].current_bus_config = I2C_CURRENT_BUS_SLAVE_TRANSMITTER; + g_i2c_system_context[id].std = FALSE; + + + /*Disable the interrupts */ + I2C_WRITE_REG(p_i2c_registers->imscr,I2C_CLEAR); + /* Disable the controller */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + return(I2C_OK); +} + + +/****************************************************************************/ +/* NAME : I2C_SetDeviceConfiguration */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Configure the given I2C controller, by clearing */ +/* registers, setting the input clock. The controller and */ +/* interrupts are disabled after this routine */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_i2c_device_config : pointer to the structer containg */ +/* the configuration */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not invalid*/ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_SetDeviceConfiguration(t_i2c_device_id id, t_i2c_device_config *p_device_config) +{ + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + + + /* Check if parameters are valid.*/ + + if (NULL == p_device_config || ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id))) + { + return(I2C_INVALID_PARAMETER); + } + + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Disable the controller.*/ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + /* Save the value.*/ + g_i2c_system_context[id].enabled = FALSE; + + /* Now save the input parameters.*/ + g_i2c_system_context[id].digital_filter_control = p_device_config->i2c_digital_filter_control; + g_i2c_system_context[id].slave_data_setup_time = p_device_config->slave_data_setup_time; + g_i2c_system_context[id].dma_sync_logic_control = p_device_config->i2c_dma_sync_logic_control; + g_i2c_system_context[id].start_byte_procedure = p_device_config->i2c_start_byte_procedure; + g_i2c_system_context[id].high_speed_master_code = p_device_config->i2c_high_speed_master_code; + g_i2c_system_context[id].freq_input = p_device_config->input_frequency; + g_i2c_system_context[id].own_address = p_device_config->controller_i2c_address; + + /* Clear registers.*/ + I2C_WRITE_REG(p_i2c_registers->cr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->scr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->hsmcr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->tftr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->rftr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->dmar, I2C_CLEAR); + + /* Set own address.*/ + error_status = i2cp_SetOwnAddress(id, (u16) g_i2c_system_context[id].own_address); + if (I2C_OK != error_status) + { + return(error_status); + } + + /* set the digital filter */ + I2C_WRITE_FIELD + ( + p_i2c_registers->cr, + I2C_CR_FON, + I2C_CR_SHIFT_FON, + (u32) g_i2c_system_context[id].digital_filter_control + ); + + /* Set the DMA sync logic */ + I2C_WRITE_FIELD + ( + p_i2c_registers->cr, + I2C_CR_DMA_SLE, + I2C_CR_SHIFT_DMA_SLE, + (u32) g_i2c_system_context[id].dma_sync_logic_control + ); + + /* Set the Slave Data Set up Time */ + I2C_WRITE_FIELD + ( + p_i2c_registers->scr, + I2C_SCR_DATA_SETUP_TIME, + I2C_SCR_SHIFT_DATA_SETUP_TIME, + g_i2c_system_context[id].slave_data_setup_time + ); + + /* Disable generation of interrupts.*/ + I2C_DisableIRQSrc((t_i2c_irq_src_id) (((u32) id << (u32) I2CID_SHIFT) | (u32) I2C_IRQ_SRC_ALL)); /* + Single Interrupt source matches + the sequence of device ids they + are used interchangeably. + */ + + /* Enable the I2C Controller */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_SetTransferConfiguration */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Configure the given I2C controller for transfer mode, */ +/* baud rate, general call handling and bus access mode. */ +/* Additionally fifo levels, loopback control and DMA */ +/* burst length are also configured. */ +/* This routine enable the I2C controller */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_i2c_transfer_config :pointer to the structure containing */ +/* the configuration */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_UNSUPPORTED_FEATURE if required index and data */ +/* transfer modes are not supported. */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ + +/****************************************************************************/ + t_i2c_error I2C_SetTransferConfiguration(t_i2c_device_id id, t_i2c_transfer_config *p_transfer_config) +{ + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + + /* Check if parameters are valid.*/ + + if (NULL == p_transfer_config || ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id))) + { + return(I2C_INVALID_PARAMETER); + } + + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + + /* + Error handling for unsopported features according to the platform + */ + if + ( + ( + I2C_TRANSFER_MODE_POLLING != p_transfer_config->index_transfer_mode + && I2C_TRANSFER_MODE_POLLING == p_transfer_config->data_transfer_mode + ) + || ( (I2C_TRANSFER_MODE_INTERRUPT == p_transfer_config->index_transfer_mode) + && (I2C_TRANSFER_MODE_DMA == p_transfer_config->data_transfer_mode) + ) + + || (I2C_TRANSFER_MODE_DMA == p_transfer_config->index_transfer_mode) + ) + { + return(I2C_UNSUPPORTED_FEATURE); + } + + /* + Clear all the existing state of the controller by clearing PE bit + */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + /* Now save the input parameters.*/ + g_i2c_system_context[id].i2c_loopback_mode = p_transfer_config->i2c_loopback_mode; + g_i2c_system_context[id].general_call_mode_handling = p_transfer_config->i2c_slave_general_call_mode; + g_i2c_system_context[id].index_transfer_mode = p_transfer_config->index_transfer_mode; + + /*Index transfer mode is still relevant even if I2C_NO_INDEX is + used since then this mode is used for the address transmission */ + + g_i2c_system_context[id].data_transfer_mode = p_transfer_config->data_transfer_mode; + g_i2c_system_context[id].i2c_transmit_interrupt_threshold = p_transfer_config->i2c_transmit_interrupt_threshold; + g_i2c_system_context[id].i2c_receive_interrupt_threshold = p_transfer_config->i2c_receive_interrupt_threshold; + g_i2c_system_context[id].transmit_burst_length = p_transfer_config->transmit_burst_length; + g_i2c_system_context[id].receive_burst_length = p_transfer_config->receive_burst_length; + g_i2c_system_context[id].freq_scl = p_transfer_config->i2c_transfer_frequency; + g_i2c_system_context[id].bus_control_mode = p_transfer_config->bus_control_mode; + + g_i2c_system_context[id].multi_operation = FALSE; + g_i2c_system_context[id].register_index = 0; /* The index of the slave's registers*/ + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + + + /* Set the SCL bus clock frequency. -> transfer frequency*/ + error_status = i2cp_SetBusClock(id, g_i2c_system_context[id].freq_scl, g_i2c_system_context[id].freq_input); + if (I2C_OK != error_status) + { + return(error_status); + } + + /*Set the loop back mode */ + I2C_WRITE_FIELD + ( + p_i2c_registers->cr, + I2C_CR_LM, + I2C_CR_SHIFT_LM, + (u32) g_i2c_system_context[id].i2c_loopback_mode + ); + + /* Enable the general call handing in the controller*/ + /* Only possible general call handing in this controller is + in the software mode. + */ + if (I2C_HARDWARE_GENERAL_CALL_HANDLING == g_i2c_system_context[id].general_call_mode_handling) + { + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_SGCM); + } + else + { + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_SGCM); + } + + /* Disable the Tx DMA */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_DMA_TX_EN); + + /* Disable the Rx DMA */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_DMA_RX_EN); + + /* configure the Tx DMA burst size */ + if (g_i2c_system_context[id].transmit_burst_length >= 1) + { + /* set the DMA Tx request mode to Burst */ + I2C_SET_BIT(p_i2c_registers->dmar, I2C_DMA_BURST_TX); + + /* Set the Destination Burst Size */ + I2C_WRITE_FIELD + ( + p_i2c_registers->dmar, + I2C_DMA_DBSIZE_TX, + I2C_DMA_SHIFT_DBSIZE_TX, + g_i2c_system_context[id].transmit_burst_length + ); + } + else + { + /* Set the DMA Tx Request mode to Single */ + I2C_CLR_BIT(p_i2c_registers->dmar, I2C_DMA_BURST_TX); + } + + /* configure the Rx DMA burst size */ + if (g_i2c_system_context[id].receive_burst_length >= 1) + { + /* set the DMA Rx request mode to Burst */ + I2C_SET_BIT(p_i2c_registers->dmar, I2C_DMA_BURST_RX); + + /* Set the source burst size */ + I2C_WRITE_FIELD + ( + p_i2c_registers->dmar, + I2C_DMA_SBSIZE_RX, + I2C_DMA_SHIFT_SBSIZE_RX, + g_i2c_system_context[id].receive_burst_length + ); + } + else + { + /* Set the DMA Rx Request mode to Single */ + I2C_CLR_BIT(p_i2c_registers->dmar, I2C_DMA_BURST_RX); + } + + /* Set the Bus control mode */ + I2C_WRITE_FIELD + ( + p_i2c_registers->cr, + I2C_CR_OM, + I2C_CR_SHIFT_OM, + (u32) g_i2c_system_context[id].bus_control_mode + ); + + /* Set the Transmit Fifo threshold value */ + p_i2c_registers->tftr = g_i2c_system_context[id].i2c_transmit_interrupt_threshold; + + /* Set the Receive Fifo Threshold value */ + p_i2c_registers->rftr = g_i2c_system_context[id].i2c_receive_interrupt_threshold; + + /*Disable the interrupts if index transfer mode is polling */ + if (I2C_TRANSFER_MODE_POLLING == g_i2c_system_context[id].index_transfer_mode) + { + I2C_DisableIRQSrc((t_i2c_irq_src_id) (((u32) id << (u32) I2CID_SHIFT) | (u32) I2C_IRQ_SRC_ALL)); + } + + /* Now restore CR register with the values it has before it was disabled.*/ + /*Enable the I2C Controller and set the enable status in the global structure */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + g_i2c_system_context[id].enabled = TRUE; + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_SetTransferMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Set the transfer modes for the index and data transfer */ +/* on the given I2C controller */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_i2c_transfer_mode : Index transfer mode */ +/* t_i2c_transfer_mode : data transger mode */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_UNSUPPORTED_FEATURE if required index and data */ +/* transfer modes are not supported. */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_SetTransferMode +( + t_i2c_device_id id, + t_i2c_transfer_mode index_transfer_mode, + t_i2c_transfer_mode data_transfer_mode +) +{ + info( + "Id is %d, index and data transfer modes are %lx and %lx", + id, + (u32) index_transfer_mode, + (u32) data_transfer_mode + ); + + if + ( + (I2C_TRANSFER_MODE_POLLING != index_transfer_mode && I2C_TRANSFER_MODE_POLLING == data_transfer_mode) + || ( (I2C_TRANSFER_MODE_INTERRUPT == index_transfer_mode) + && (I2C_TRANSFER_MODE_DMA == data_transfer_mode) + ) + + || (I2C_TRANSFER_MODE_DMA == index_transfer_mode) + ) + { + return(I2C_UNSUPPORTED_FEATURE); + } + + + /* Check if parameters are valid.*/ + + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + + g_i2c_system_context[id].index_transfer_mode = index_transfer_mode; + + /*Index transfer mode is still relevant even if I2C_NO_INDEX is + used since then this mode is used for the addres transmission */ + + g_i2c_system_context[id].data_transfer_mode = data_transfer_mode; + + /*Disable the interrupts if index tranfer mode is polling */ + if (I2C_TRANSFER_MODE_POLLING == index_transfer_mode) + { + + I2C_DisableIRQSrc((t_i2c_irq_src_id) (((u32) id << (u32) I2CID_SHIFT) | (u32) I2C_IRQ_SRC_ALL)); + + } + + return(I2C_OK); +} + +/****************************************************************************/ +/* NAME : I2C_SetBusControlMode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Set the bus control mode for the data transfer on the */ +/* given I2C controller. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_i2c_bus_control_mode : The mode in which I2C bus */ +/* is accessed */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ + +/****************************************************************************/ + t_i2c_error I2C_SetBusControlMode(t_i2c_device_id id, t_i2c_bus_control_mode bus_control_mode) +{ + + + t_i2c_registers *p_i2c_registers; + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + + /* Check if parameters are valid.*/ + + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + + g_i2c_system_context[id].bus_control_mode = bus_control_mode; + + /* Disable the I2C controller before configuring */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + /* Set the Bus control mode */ + I2C_WRITE_FIELD + ( + p_i2c_registers->cr, + I2C_CR_OM, + I2C_CR_SHIFT_OM, + (u32) g_i2c_system_context[id].bus_control_mode + ); + + /* Enable the I2C controller */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + + return(I2C_OK); +} + +/*----------------------------------------------------------------------------- + Configuration functions +-----------------------------------------------------------------------------*/ +/****************************************************************************/ +/* NAME : I2C_FlushFifo */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Flush the transmit or receive FIFO */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* t_i2c_fifo : FIFO to be flused */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* = I2C_INVALID_PARAMETER - if input id is wrong */ +/* = I2C_HW_FAILED - if FIFO flush bit is not reset */ +/* itself after setting. This could be happen if */ +/* i2c clock frequency is not set */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ + +/****************************************************************************/ + t_i2c_error I2C_FlushFifo(t_i2c_device_id id, t_i2c_fifo fifo) +{ + + u32 loop_counter; + t_i2c_registers *p_i2c_registers; + + /* Check parameters valid */ + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + switch (fifo) + { + case I2C_TRANSMIT_FIFO: + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_FTX); /* Flush the Tx Fifo */ + + /*Wait till for the Tx Flush bit to reset */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->cr, I2C_CR_FTX, I2C_CR_SHIFT_FTX) + && loop_counter < I2C_FIFO_FLUSH_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_FIFO_FLUSH_COUNTER) + { + return(I2C_HW_FAILED); + } + break; + + case I2C_RECEIVE_FIFO: + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_FRX); /* Flush the Rx Fifo */ + + /* Wait till Rx flush bit to reset */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->cr, I2C_CR_FRX, I2C_CR_SHIFT_FRX) + && loop_counter < I2C_FIFO_FLUSH_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_FIFO_FLUSH_COUNTER) + { + return(I2C_HW_FAILED); + } + break; + } + + return(I2C_OK); + +} + + + + + +/****************************************************************************/ +/* NAME : I2C_Enable */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :Enable the given I2C controller. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_Enable(t_i2c_device_id id) +{ + t_i2c_registers *p_i2c_registers; + + /* Check if parameters are valid.*/ + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + + g_i2c_system_context[id].enabled = TRUE; + return(I2C_OK); +} + +/****************************************************************************/ +/* NAME : I2C_Disable */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :Disble the given I2C controller. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to disabled */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_Disable(t_i2c_device_id id) +{ + t_i2c_registers *p_i2c_registers; + + /* Check if parameters are valid.*/ + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + g_i2c_system_context[id].enabled = FALSE; + return(I2C_OK); + +} + + + +/****************************************************************************/ +/* NAME : I2C_WriteSingleData */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :This routine is used to write a single data byte to */ +/* a receiver. Writing can be done to a slave device by */ +/* using the indexed modes. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* u16 : The address of the slave to be accessed */ +/* u16 : The index of the register on the receiver */ +/* to which data is written */ +/* t_unit16 :The format of the index on receiver side */ +/* u8 : The data byte to be written to the slave device */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_SLAVE_ADDRESS_NOT_VALID If requested slave address */ +/* is not valid */ +/* I2C_CONTROLLER_BUSY if I2C controller is busy */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_WriteSingleData +( + t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 data +) +{ + +/* +Steps: + - Check Mode + - Polling + - Interrupt + - DMA +*/ + + volatile u32 mcr = 0; + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + info( + "Id is %d, Address is %x, Index format is %d and value is %d, Data is %d", + id, + slave_address, + index_format, + index_value, + data + ); + + /* Check if parameters are valid.*/ + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + + if (!i2cp_AddressIsValid(slave_address)) + { + return(I2C_SLAVE_ADDRESS_NOT_VALID); + } + + /* Index transfers are only valid in case the Bus Control Mode is not slave*/ + if ((I2C_BUS_MASTER_MODE != g_i2c_system_context[id].bus_control_mode) && (I2C_NO_INDEX != index_format)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Check if not busy.*/ + if ((g_i2c_system_context[id].operation != I2C_NO_OPERATION)) + { + return(I2C_CONTROLLER_BUSY); + } + + /* Save parameters.*/ + g_i2c_system_context[id].slave_address = slave_address; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].register_index = index_value; + g_i2c_system_context[id].index_format = index_format; + g_i2c_system_context[id].data = data; + g_i2c_system_context[id].databuffer = NULL; + g_i2c_system_context[id].count_data = 1; + g_i2c_system_context[id].operation = I2C_WRITE; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = FALSE; + + /* Disable all the interrupts to remove previously garbage interrupts */ + switch(id) + { + case I2C0 : + I2C_DisableIRQSrc(I2C0_IRQ_SRC_ALL); + break; + case I2C1 : + I2C_DisableIRQSrc(I2C1_IRQ_SRC_ALL); + break; + case I2C2: + I2C_DisableIRQSrc(I2C2_IRQ_SRC_ALL); + break; + case I2C3: + I2C_DisableIRQSrc(I2C3_IRQ_SRC_ALL); + break; + default: + break; + } +/* I2C_DisableIRQSrc((I2C0 == id) ? I2C0_IRQ_SRC_ALL : I2C1_IRQ_SRC_ALL);*/ + + /* Check if I2C controller is Master */ + if (I2C_BUS_MASTER_MODE == g_i2c_system_context[id].bus_control_mode) + { + /* Master control configuration */ + + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + + /* start byte procedure configuration */ + I2C_WRITE_FIELD(mcr, I2C_MCR_SB, I2C_MCR_SHIFT_SB, (u32) g_i2c_system_context[id].start_byte_procedure); + + /* Check the General call handling */ + if (g_i2c_system_context[id].general_call_mode_handling != I2C_NO_GENERAL_CALL_HANDLING) + { + /* The Transaction is intiated by a general call command */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 0); + } + else + { + /* Check if Slave address is 10 bit */ + if (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + { + /* Set the Address mode to 10 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 2); + } + else + { + /* Set the Address mode to 7 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 1); + } + } + + /* Store the HS master code */ + if (I2C_FREQ_MODE_HIGH_SPEED == g_i2c_system_context[id].mode) + { + p_i2c_registers->hsmcr = g_i2c_system_context[id].high_speed_master_code; + } + + /* Store the Slave addres in the Master control register */ + I2C_WRITE_FIELD(mcr, I2C_MCR_A10, I2C_MCR_SHIFT_A10, slave_address); + + /* Configure the STOP condition*/ + /* Current transaction is terminated by STOP condition */ + I2C_SET_BIT(mcr, I2C_MCR_STOP); + + /* Configuring the Frame length */ + switch (index_format) + { + case I2C_NO_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 1); + break; + + case I2C_BYTE_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 2); + break; + + case I2C_HALF_WORD_LITTLE_ENDIAN: + case I2C_HALF_WORD_BIG_ENDIAN: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 3); + break; + + default: + break; + } + + /*Write the MCR register */ + p_i2c_registers->mcr = mcr; + + } + + switch (g_i2c_system_context[id].index_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + /* + Index Transfer + */ + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + error_status = i2cp_SlaveIndexReceive(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + else + { + error_status = i2cp_MasterIndexTransmit(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + + /* + Data Transfer + */ + switch (g_i2c_system_context[id].data_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + error_status = i2cp_TransmitDataPolling(id, (u8 *) &g_i2c_system_context[id].data); + if (I2C_OK != error_status) + { + return(error_status); + } + + /* Stop Signal to be sent/received for transfer completion*/ + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + break; + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + return(I2C_INVALID_PARAMETER); + } + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_WriteMultipleData */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :This routine is used to write a multiple data byte to */ +/* a receiver. Writing can be done to a slave device by */ +/* using the indexed modes. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* u16 : The address of the slave to be accessed */ +/* u16 : The index of the register on the receiver */ +/* to which data is written */ +/* t_unit16 :The format of the index on receiver side */ +/* u8* : The data buffer to be written to the */ +/* slave device */ +/* t_unit32 : no of bytes to be transfered */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_SLAVE_ADDRESS_NOT_VALID If requested slave address */ +/* is not valid */ +/* I2C_CONTROLLER_BUSY if I2C controller is busy */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_WriteMultipleData +( + t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data, + u32 count +) +{ + +/* +Steps: + - Check Mode + - Polling + - Interrupt + - DMA +*/ + volatile u32 mcr = 0; + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + info( + "Id is %d, Address is %x, Index format is %d and value is %d, Data count is %d and @ is %p", + id, + slave_address, + index_format, + index_value, + count, + (void *) p_data + ); + + /* Check if parameters are valid.*/ + if (((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) || (NULL == p_data)) + { + return(I2C_INVALID_PARAMETER); + } + + + if (!i2cp_AddressIsValid(slave_address)) + { + return(I2C_SLAVE_ADDRESS_NOT_VALID); + } + + /* Index transfers are only valid in case the Bus Control Mode is not slave*/ + if ((I2C_BUS_MASTER_MODE != g_i2c_system_context[id].bus_control_mode) && (I2C_NO_INDEX != index_format)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Check if not busy.*/ + if ((g_i2c_system_context[id].operation != I2C_NO_OPERATION)) + { + return(I2C_CONTROLLER_BUSY); + } + + /* Save parameters.*/ + g_i2c_system_context[id].slave_address = slave_address; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].register_index = index_value; + g_i2c_system_context[id].index_format = index_format; + g_i2c_system_context[id].data = 0; + g_i2c_system_context[id].databuffer = p_data; + g_i2c_system_context[id].count_data = count; + g_i2c_system_context[id].operation = I2C_WRITE; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = TRUE; + + /* Disable all the interrupts to remove previously garbage interrupts */ + switch(id) + { + case I2C0 : + I2C_DisableIRQSrc(I2C0_IRQ_SRC_ALL); + break; + case I2C1 : + I2C_DisableIRQSrc(I2C1_IRQ_SRC_ALL); + break; + case I2C2: + I2C_DisableIRQSrc(I2C2_IRQ_SRC_ALL); + break; + case I2C3: + I2C_DisableIRQSrc(I2C3_IRQ_SRC_ALL); + break; + default: + break; + } + /*I2C_DisableIRQSrc((I2C0 == id) ? I2C0_IRQ_SRC_ALL : I2C1_IRQ_SRC_ALL);*/ + + /* Check if I2C controller is Master */ + if (I2C_BUS_MASTER_MODE == g_i2c_system_context[id].bus_control_mode) + { + /* Master control configuration */ + + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + + /* start byte procedure configuration */ + I2C_WRITE_FIELD(mcr, I2C_MCR_SB, I2C_MCR_SHIFT_SB, (u32) g_i2c_system_context[id].start_byte_procedure); + + /* Check the General call handling */ + if (g_i2c_system_context[id].general_call_mode_handling != I2C_NO_GENERAL_CALL_HANDLING) + { + /* The Transaction is intiated by a general call command */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 0); + } + else + { + /* Check if Slave address is 10 bit */ + if (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + { + /* Set the Address mode to 10 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 2); + } + else + { + /* Set the Address mode to 7 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 1); + } + } + + /* Store the HS master code */ + if (I2C_FREQ_MODE_HIGH_SPEED == g_i2c_system_context[id].mode) + { + p_i2c_registers->hsmcr = g_i2c_system_context[id].high_speed_master_code; + } + + /* Store the Slave addres in the Master control register */ + I2C_WRITE_FIELD(mcr, I2C_MCR_A10, I2C_MCR_SHIFT_A10, slave_address); + + /* Configure the STOP condition*/ + /* Current transaction is terminated by STOP condition */ + I2C_SET_BIT(mcr, I2C_MCR_STOP); + + /* Configuring the Frame length */ + switch (index_format) + { + case I2C_NO_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, count); + break; + + case I2C_BYTE_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, (count + 1)); + break; + + case I2C_HALF_WORD_LITTLE_ENDIAN: + case I2C_HALF_WORD_BIG_ENDIAN: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, (count + 2)); + break; + + default: + break; + } + + p_i2c_registers->mcr = mcr; + } + + switch (g_i2c_system_context[id].index_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + /* + Index Transfer + */ + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + error_status = i2cp_SlaveIndexReceive(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + else + { + error_status = i2cp_MasterIndexTransmit(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + + /* + Data Transfer + */ + switch (g_i2c_system_context[id].data_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + error_status = i2cp_TransmitDataPolling(id, g_i2c_system_context[id].databuffer); + if (I2C_OK != error_status) + { + return(error_status); + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + break; + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + return(I2C_INVALID_PARAMETER); + } + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_ReadSingleData */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :This routine is used to read a single data byte from */ +/* a transmitter. Read can be done from a slave device by */ +/* using the indexed modes. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* u16 : The address of the slave to be accessed */ +/* u16 : The index of the register on the transmitter */ +/* from which data is read */ +/* t_unit16 :The format of the index on tranmitter side */ +/* u8 : The data to be read from the tranmitter */ +/* t_unit32 : no of bytes to be transfered */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_SLAVE_ADDRESS_NOT_VALID If requested slave address */ +/* is not valid */ +/* I2C_CONTROLLER_BUSY if I2C controller is busy */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_ReadSingleData +( + t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data +) +{ + +/* +Steps: + - Check Mode + - Polling + - Interrupt + - DMA +*/ + volatile u32 mcr = 0; + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + info( + "Id is %d, Address is %x, Index format is %d and value is %d, Data count is %d and @ is %p", + id, + slave_address, + index_format, + index_value, + (void *) p_data + ); + + /* Check if parameters are valid.*/ + if (((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) || (NULL == p_data)) + { + return(I2C_INVALID_PARAMETER); + } + + if (!i2cp_AddressIsValid(slave_address)) + { + return(I2C_SLAVE_ADDRESS_NOT_VALID); + } + + /* Index transfers are only valid in case the Bus Control Mode is not slave*/ + if ((I2C_BUS_MASTER_MODE != g_i2c_system_context[id].bus_control_mode) && (I2C_NO_INDEX != index_format)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Check if not busy.*/ + if ((g_i2c_system_context[id].operation != I2C_NO_OPERATION)) + { + return(I2C_CONTROLLER_BUSY); + } + + /* Save parameters.*/ + g_i2c_system_context[id].slave_address = slave_address; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].register_index = index_value; + g_i2c_system_context[id].index_format = index_format; + g_i2c_system_context[id].data = 0; + g_i2c_system_context[id].databuffer = p_data; + g_i2c_system_context[id].count_data = 1; + g_i2c_system_context[id].operation = I2C_READ; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = FALSE; + + /* Disable all the interrupts to remove previously garbage interrupts */ + switch(id) + { + case I2C0 : + I2C_DisableIRQSrc(I2C0_IRQ_SRC_ALL); + break; + case I2C1 : + I2C_DisableIRQSrc(I2C1_IRQ_SRC_ALL); + break; + case I2C2: + I2C_DisableIRQSrc(I2C2_IRQ_SRC_ALL); + break; + case I2C3: + I2C_DisableIRQSrc(I2C3_IRQ_SRC_ALL); + break; + default: + break; + } + + /*I2C_DisableIRQSrc((id == I2C0) ? I2C0_IRQ_SRC_ALL : I2C1_IRQ_SRC_ALL);*/ + + /* Check if I2C controller is Master */ + if (I2C_BUS_MASTER_MODE == g_i2c_system_context[id].bus_control_mode) + { + + /* start byte procedure configuration */ + I2C_WRITE_FIELD(mcr, I2C_MCR_SB, I2C_MCR_SHIFT_SB, (u32) g_i2c_system_context[id].start_byte_procedure); + + /* Check the General call handling */ + if (g_i2c_system_context[id].general_call_mode_handling != I2C_NO_GENERAL_CALL_HANDLING) + { + /* The Transaction is intiated by a general call command */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 0); + } + else + { + /* Check if Slave address is 10 bit */ + if (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + { + /* Set the Address mode to 10 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 2); + } + else + { + /* Set the Address mode to 7 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 1); + } + } + + /* Store the HS master code */ + if (I2C_FREQ_MODE_HIGH_SPEED == g_i2c_system_context[id].mode) + { + p_i2c_registers->hsmcr = g_i2c_system_context[id].high_speed_master_code; + } + + /* Store the Slave addres in the Master control register */ + I2C_WRITE_FIELD(mcr, I2C_MCR_A10, I2C_MCR_SHIFT_A10, slave_address); + + if + ( + (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + && (I2C_NO_INDEX == index_format) + ) + { + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 0); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + + /*Write MCR register */ + p_i2c_registers->mcr = mcr; + + /* Enable the I2C controller */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + } + else + { + /* Master control configuration */ + if (I2C_NO_INDEX != index_format) + { + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + } + else + { + /* Set the Master read operation */ + I2C_SET_BIT(mcr, I2C_MCR_OP); + } + + /* Configuring the Frame length */ + switch (index_format) + { + case I2C_NO_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 1); + + /* Current transaction is terminated by STOP condition */ + I2C_SET_BIT(mcr, I2C_MCR_STOP); + break; + + case I2C_BYTE_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 1); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + break; + + case I2C_HALF_WORD_LITTLE_ENDIAN: + case I2C_HALF_WORD_BIG_ENDIAN: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 2); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + break; + + default: + break; + } + + /*Write MCR register */ + p_i2c_registers->mcr = mcr; + + } + } + + switch (g_i2c_system_context[id].index_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + /* + Index Transfer + */ + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + error_status = i2cp_SlaveIndexReceive(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + else + { + error_status = i2cp_MasterIndexTransmit(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + + /* + Data Transfer + */ + switch (g_i2c_system_context[id].data_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + error_status = i2cp_ReceiveDataPolling(id, g_i2c_system_context[id].databuffer); + if (I2C_OK != error_status) + { + return(error_status); + } + + /* Stop Signal to be sent/received for transfer completion*/ + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + break; + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + return(I2C_INVALID_PARAMETER); + } + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_ReadMultipleData */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :This routine is used to read a multiple data byte from */ +/* a transmitter. Read can be done from a slave device by */ +/* using the indexed modes. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be initialized */ +/* u16 : The address of the slave to be accessed */ +/* u16 : The index of the register on the transmitter */ +/* from which data is read */ +/* t_unit16 :The format of the index on tranmitter side */ +/* u8* : The data buffer to be written to the */ +/* slave device */ +/* t_unit32 : no of bytes to be transfered */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/* I2C_SLAVE_ADDRESS_NOT_VALID If requested slave address */ +/* is not valid */ +/* I2C_CONTROLLER_BUSY if I2C controller is busy */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_ReadMultipleData +( + t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data, + u32 count +) +{ + +/* +Steps: + - Check Mode + - Polling + - Interrupt + - DMA +*/ + volatile u32 mcr = 0; + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + info( + "Id is %d, Address is %x, Index format is %d and value is %d, Data count is %d and @ is %p", + id, + slave_address, + index_format, + index_value, + count, + (void *) p_data + ); + + /* Check if parameters are valid.*/ + if (((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id) ) || (NULL == p_data)) + { + return(I2C_INVALID_PARAMETER); + } + + + if (!i2cp_AddressIsValid(slave_address)) + { + return(I2C_SLAVE_ADDRESS_NOT_VALID); + } + + /* Index transfers are only valid in case the Bus Control Mode is not slave*/ + if ((I2C_BUS_MASTER_MODE != g_i2c_system_context[id].bus_control_mode) && (I2C_NO_INDEX != index_format)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Check if not busy.*/ + if ((g_i2c_system_context[id].operation != I2C_NO_OPERATION)) + { + return(I2C_CONTROLLER_BUSY); + } + + /* Save parameters.*/ + g_i2c_system_context[id].slave_address = slave_address; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].register_index = index_value; + g_i2c_system_context[id].index_format = index_format; + g_i2c_system_context[id].data = 0; + g_i2c_system_context[id].databuffer = p_data; + g_i2c_system_context[id].count_data = count; + g_i2c_system_context[id].operation = I2C_READ; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = TRUE; + + /* Disable all the interrupts to remove previously garbage interrupts */ + switch(id) + { + case I2C0 : + I2C_DisableIRQSrc(I2C0_IRQ_SRC_ALL); + break; + case I2C1 : + I2C_DisableIRQSrc(I2C1_IRQ_SRC_ALL); + break; + case I2C2: + I2C_DisableIRQSrc(I2C2_IRQ_SRC_ALL); + break; + case I2C3: + I2C_DisableIRQSrc(I2C3_IRQ_SRC_ALL); + break; + default: + break; + } +/* I2C_DisableIRQSrc((I2C0 == id) ? I2C0_IRQ_SRC_ALL : I2C1_IRQ_SRC_ALL);*/ + + /* Check if I2C controller is Master */ + if (I2C_BUS_MASTER_MODE == g_i2c_system_context[id].bus_control_mode) + { + + /* start byte procedure configuration */ + I2C_WRITE_FIELD(mcr, I2C_MCR_SB, I2C_MCR_SHIFT_SB, (u32) g_i2c_system_context[id].start_byte_procedure); + + /* Check the General call handling */ + if (g_i2c_system_context[id].general_call_mode_handling != I2C_NO_GENERAL_CALL_HANDLING) + { + /* The Transaction is intiated by a general call command */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 0); + } + else + { + /* Check if Slave address is 10 bit */ + if (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + { + /* Set the Address mode to 10 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 2); + } + else + { + /* Set the Address mode to 7 bit */ + I2C_WRITE_FIELD(mcr, I2C_MCR_AM, I2C_MCR_SHIFT_AM, 1); + } + } + + /* Store the HS master code */ + if (I2C_FREQ_MODE_HIGH_SPEED == g_i2c_system_context[id].mode) + { + p_i2c_registers->hsmcr = g_i2c_system_context[id].high_speed_master_code; + } + + /* Store the Slave addres in the Master control register */ + I2C_WRITE_FIELD(mcr, I2C_MCR_A10, I2C_MCR_SHIFT_A10, slave_address); + + if + ( + (g_i2c_system_context[id].slave_address < 1024 && g_i2c_system_context[id].slave_address > 127) + && (I2C_NO_INDEX == index_format) + ) + { + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 0); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + + /*Write MCR register */ + p_i2c_registers->mcr = mcr; + + /* Enable the I2C controller */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + } + else + { + /* Master control configuration */ + if (I2C_NO_INDEX != index_format) + { + /* Set the Master write operation */ + I2C_CLR_BIT(mcr, I2C_MCR_OP); + } + else + { + /* Set the Master read operation */ + I2C_SET_BIT(mcr, I2C_MCR_OP); + } + + /* Configuring the Frame length */ + switch (index_format) + { + case I2C_NO_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, count); + + /* Current transaction is terminated by STOP condition */ + I2C_SET_BIT(mcr, I2C_MCR_STOP); + break; + + case I2C_BYTE_INDEX: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 1); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + break; + + case I2C_HALF_WORD_LITTLE_ENDIAN: + case I2C_HALF_WORD_BIG_ENDIAN: + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, 2); + + /* Current transaction is not terminated by STOP condition, + a repeated start operation will be fallowed */ + I2C_CLR_BIT(mcr, I2C_MCR_STOP); + break; + + default: + break; + } + + /*Write MCR register */ + p_i2c_registers->mcr = mcr; + + } + } + + switch (g_i2c_system_context[id].index_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + /* + Index Transfer + */ + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + error_status = i2cp_SlaveIndexReceive(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + else + { + error_status = i2cp_MasterIndexTransmit(id); + if (I2C_OK != error_status) + { + return(error_status); + } + } + + /* + Data Transfer + */ + switch (g_i2c_system_context[id].data_transfer_mode) + { + case I2C_TRANSFER_MODE_POLLING: + error_status = i2cp_ReceiveDataPolling(id, g_i2c_system_context[id].databuffer); + if (I2C_OK != error_status) + { + return(error_status); + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + break; + } + break; + + case I2C_TRANSFER_MODE_INTERRUPT: + case I2C_TRANSFER_MODE_DMA: + default: + return(I2C_INVALID_PARAMETER); + } + + return(error_status); + +} + +/****************************************************************************/ +/* NAME : I2C_Cancel */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : This routine is used to cancel the current transfer */ +/* operation, if any. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller to be canceled */ +/* InOut : None */ +/* : t_i2c_active_event: It will contain the result of */ +/* the operation */ +/* */ +/* RETURN : t_i2c_error */ +/* I2C_OK if it is ok */ +/* I2C_INVALID_PARAMETER if input parameters are not valid */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_i2c_error I2C_Cancel(t_i2c_device_id id, t_i2c_active_event *event) /*Only IT mode*/ +{ + /* Check if parameters are valid.*/ + if ((NULL == event) || ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id))) + { + return(I2C_INVALID_PARAMETER); + } + + if (I2C_NO_EVENT == g_i2c_system_context[id].active_event) + { + event->type = I2C_NO_EVENT; + event->transfer_data = 0; + event->id = id; + } + else + { + event->type = I2C_CANCEL_EVENT; + event->transfer_data = g_i2c_system_context[id].transfer_data; + event->id = id; + g_i2c_system_context[id].active_event = I2C_CANCEL_EVENT; + } + + i2cp_Abort(id); + + /*Set the I2C operation to No operation */ + g_i2c_system_context[id].operation = (t_i2c_operation) I2C_NO_OPERATION; + + return(I2C_OK); +} + + + +/****************************************************************************/ +/* NAME : I2C_IsEventActive */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :This routine is used to determine if the given event */ +/* is still active. */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_active_event: the Event to be checked */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_bool : TRUE or FALSE */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ + t_bool I2C_IsEventActive(t_i2c_active_event *event) +{ + if (event->type == g_i2c_system_context[event->id].active_event) + { + return(TRUE); + } + else + { + return(FALSE); + } +} + + +/****************************************************************************/ +/* NAME : I2C_Reset */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION :Reset the I2C Registers for given I2C controller */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The ID of the controller for reset */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/* return I2C_INVALID_PARAMETER if id is not correct */ +/* else I2C_OK */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ +/****************************************************************************/ +t_i2c_error I2C_Reset(t_i2c_device_id id) +{ + t_i2c_registers *p_i2c_registers; + + /* Check if parameters are valid.*/ + if ((I2C0 != id) && (I2C1 != id) && (I2C2 != id) && (I2C3 != id)) + { + return(I2C_INVALID_PARAMETER); + } + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + + /* Clear registers.*/ + I2C_WRITE_REG(p_i2c_registers->cr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->scr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->hsmcr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->mcr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->tftr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->rftr, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->dmar, I2C_CLEAR); + I2C_WRITE_REG(p_i2c_registers->icr, 0x31F0008); + I2C_WRITE_REG(p_i2c_registers->imscr,I2C_CLEAR); + + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_FTX); /* Flush the Tx Fifo */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_FRX); /* Flush the Rx Fifo */ + + /* + Initialize the right structure to default state + */ + g_i2c_system_context[id].freq_scl = 0; + g_i2c_system_context[id].freq_input = 0; + g_i2c_system_context[id].mode = I2C_FREQ_MODE_STANDARD; + g_i2c_system_context[id].own_address = 0; + g_i2c_system_context[id].enabled = FALSE; + g_i2c_system_context[id].slave_address = 0; + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_MODE; + g_i2c_system_context[id].data = 0; + g_i2c_system_context[id].databuffer = NULL; + g_i2c_system_context[id].count_data = 0; + g_i2c_system_context[id].register_index = 0; + g_i2c_system_context[id].operation = (t_i2c_operation) I2C_NO_OPERATION; + g_i2c_system_context[id].active_event = I2C_NO_EVENT; + g_i2c_system_context[id].transfer_data = 0; + g_i2c_system_context[id].multi_operation = FALSE; + + /* g_i2c_system_context[id].i2c_device_context... to be initialized*/ + g_i2c_system_context[id].digital_filter_control = I2C_DIGITAL_FILTERS_OFF; + g_i2c_system_context[id].dma_sync_logic_control = I2C_DISABLE; + g_i2c_system_context[id].start_byte_procedure = I2C_DISABLE; + g_i2c_system_context[id].slave_data_setup_time = 0; /* TBD */ + g_i2c_system_context[id].high_speed_master_code = 0; + g_i2c_system_context[id].bus_control_mode = I2C_BUS_SLAVE_MODE; + g_i2c_system_context[id].i2c_loopback_mode = I2C_DISABLE; + g_i2c_system_context[id].general_call_mode_handling = I2C_NO_GENERAL_CALL_HANDLING; + + g_i2c_system_context[id].index_transfer_mode = I2C_TRANSFER_MODE_POLLING; + g_i2c_system_context[id].data_transfer_mode = I2C_TRANSFER_MODE_POLLING; + g_i2c_system_context[id].i2c_transmit_interrupt_threshold = 1; + g_i2c_system_context[id].i2c_receive_interrupt_threshold = 1; + g_i2c_system_context[id].transmit_burst_length = 0; + g_i2c_system_context[id].receive_burst_length = 0; + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + g_i2c_system_context[id].current_bus_config = I2C_CURRENT_BUS_SLAVE_TRANSMITTER; + g_i2c_system_context[id].std =FALSE; + + return(I2C_OK); +} + +/*----------------------------------------------------------------------------- + Private functions +-----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- +Name : i2cp_SetOwnAddress +Description : Set the I2C bus address of the controller. +In : t_i2c_registers* p_i2c_registers : pointer to the controller's + registers. + u32 address : the slave address of the + controller. +InOut : None +Out : None +Return value: Always ok / I2C_SLAVE_ADDRESS_NOT_VALID +Type : Private +Comments : + + + In all cases, the bits are not cleared when the interface is disabled + (PE = 0b). +-----------------------------------------------------------------------------*/ + t_i2c_error i2cp_SetOwnAddress(t_i2c_device_id id, u16 address) +{ + t_i2c_registers *p_i2c_registers; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* CM: check if the given address is valid ???*/ + if (!i2cp_AddressIsValid(address)) + { + return(I2C_SLAVE_ADDRESS_NOT_VALID); + } + + if (address < 1024 && address > 127) + { + /* Set Slave address mode to 10 bit addressing mode */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_SAM); + I2C_WRITE_FIELD(p_i2c_registers->scr, I2C_SCR_ADDR, I2C_SCR_SHIFT_ADDR, address); + } + else + { + /* Set the slave address mode to 7 bit addressing mode */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_SAM); + I2C_WRITE_FIELD(p_i2c_registers->scr, I2C_SCR_ADDR, I2C_SCR_SHIFT_ADDR, address); + } + + return(I2C_OK); +} + +/*----------------------------------------------------------------------------- +Name : i2cp_SetBusClock +Description : Set the I2C bus clock for the given controller. +In : t_i2c_registers* p_i2c_registers : pointer to the controller's + registers. + u32 freq_scl : the I2C bus frequency freq_scl (Hz). + u32 freq_input : the input clock frequency (Hz). +InOut : None +Out : None +Return value: I2C_OK : no error. + I2C_INVALID_PARAMETER : wrong id parameter. + I2C_freq_scl_NOT_SUPPORTED : freq_scl is not supported. +Type : Private +Comments : The freq_input parameter is only necessary to calculate the I2C bus + frequency and is not used for other purposes. + It is not necessary to save the freq_scl as it has been already + saved by I2C_Config(). + +-----------------------------------------------------------------------------*/ +t_i2c_error i2cp_SetBusClock(t_i2c_device_id id, u32 freq_scl, u32 freq_input) +{ + + + /* To be defined */ + u32 value; + t_i2c_registers *p_i2c_registers; + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + /* Standard mode */ + if (freq_scl <= (u32) I2C_MAX_STANDARD_SCL) + { + value = (u32) (freq_input / (freq_scl * 2)); + + /*Set the Standard mode in the control register */ + I2C_WRITE_FIELD(p_i2c_registers->cr, I2C_CR_SM, I2C_CR_SHIFT_SM, 0x0); + + /* set the Baud rate counter 2 value */ + I2C_WRITE_FIELD(p_i2c_registers->brcr, I2C_BRCR_BRCNT2, I2C_BRCR_SHIFT_BRCNT2, value); + + /* Make ensure that BRCNT value set to be zero */ + I2C_WRITE_FIELD(p_i2c_registers->brcr, I2C_BRCR_BRCNT1, I2C_BRCR_SHIFT_BRCNT1, 0); + + /*Update the Frequency mode in the global strcture */ + g_i2c_system_context[id].mode = I2C_FREQ_MODE_STANDARD; + } + else /* Fast Mode */ + if (freq_scl <= (u32) I2C_MAX_FAST_SCL) + { + value = (u32) (freq_input / ((freq_scl * 3) / 2)); + + /*Set the Fast mode in the control register */ + I2C_WRITE_FIELD(p_i2c_registers->cr, I2C_CR_SM, I2C_CR_SHIFT_SM, 0x1); + + /* set the Baud rate counter 2 value */ + I2C_WRITE_FIELD(p_i2c_registers->brcr, I2C_BRCR_BRCNT2, I2C_BRCR_SHIFT_BRCNT2, value); + + /* Make ensure that BRCNT value set to be zero */ + I2C_WRITE_FIELD(p_i2c_registers->brcr, I2C_BRCR_BRCNT1, I2C_BRCR_SHIFT_BRCNT1, 0); + + /*Update the Frequency mode in the global strcture */ + g_i2c_system_context[id].mode = I2C_FREQ_MODE_FAST; + } + else /* High Speed Mode */ + if (freq_scl <= (u32) I2C_MAX_HIGH_SPEED_SCL) + { + value = (u32) (freq_input / ((freq_scl * 3) / 2)); + + /*Set the High speed mode in the control register */ + I2C_WRITE_FIELD(p_i2c_registers->cr, I2C_CR_SM, I2C_CR_SHIFT_SM, 0x2); + + /* set the Baud rate counter 1 value */ + I2C_WRITE_FIELD(p_i2c_registers->brcr, I2C_BRCR_BRCNT1, I2C_BRCR_SHIFT_BRCNT1, value); + + /*Update the Frequency mode in the global strcture */ + g_i2c_system_context[id].mode = I2C_FREQ_MODE_HIGH_SPEED; + } + else + { + return(I2C_LINE_FREQ_NOT_SUPPORTED); + } + + return(I2C_OK); + +} + +/*----------------------------------------------------------------------------- +Name : i2cp_AddressIsValid +Description : Check if the given address is valid. +In : u16 address : the slave address to be checked. +InOut : None +Out : None +Return value: TRUE : address is valid. + FALSE : address is not valid. +Type : Private +Comments : Note that the least-significant bit of the address parameter + is not relevant for the addressing of the slave device, for + example 0xE2 and 0xE3 will address the same slave device. + + + Reserved addresses: + SLAVE ADDRESS R/W BIT RANGE DESCRIPTION + 0000 000 0 0 General call address + 0000 000 1 1 START byte(1) + 0000 001 X 2-3 CBUS address(2) + 0000 010 X 4-5 Reserved for different bus format(3) + 0000 011 X 6-7 Reserved for future purposes + 0000 1XX X 8-15 Hs-mode master code + + 1111 1XX X 248-255 Reserved for future purposes + 1111 0XX X 240-247 10-bit slave addressing + + Note that with 7-bit address: + 0000xxxx and 1111xxxx are reserved. +-----------------------------------------------------------------------------*/ +t_bool i2cp_AddressIsValid(u16 address) +{ + /* Check if more than 10 bits are needed.*/ + if (address > 1023) + { + return(FALSE); + } + + /* 7-bit address. LSB is not considered.*/ + /*Address 0x4 is enabled to support the ST Pepper pot camera */ + if (address < 128 && !(address == 0 || address == 0x4)) + { + if ((address < 8) || (address > 119)) + { + return(FALSE); + } + } + + /* CM: add here the 10-bit check.*/ + return(TRUE); +} + + +/*----------------------------------------------------------------------------- +Name : i2cp_Abort +Description : Abort the current transfer operation of the given controller. +In : t_i2c_device_id id : the controller to be aborted. +InOut : None +Out : None +Return : I2C_OK : always no error. +Type : Private +Comments : This is called when an unexpected event happens (internal error). +-----------------------------------------------------------------------------*/ +void i2cp_Abort(t_i2c_device_id id) +{ + + t_i2c_registers *p_i2c_registers; + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + /*Disable the interrupts */ + I2C_WRITE_REG(p_i2c_registers->imscr,I2C_CLEAR); + + /*Disable the Controller */ + I2C_CLR_BIT(p_i2c_registers->cr, I2C_CR_PE); + + /*Enable the controller */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_PE); + + /*Set the I2C operation to No operation */ + g_i2c_system_context[id].operation = (t_i2c_operation) I2C_NO_OPERATION; +} + + + +/*----------------------------------------------------------------------------- +Name : i2cp_SlaveIndexReceive +Description : +In : t_i2c_id : I2C Controller id + +InOut : None +Out : t_i2c_error error status +Return value: I2C_OK : no error + I2C_INVALID_PARAMETER : wrong id parameter. + +Type : Private +Comments : This function perform the operations, when + I2C controller addressed as a slave +-----------------------------------------------------------------------------*/ +t_i2c_error i2cp_SlaveIndexReceive(t_i2c_device_id id) +{ + + u32 loop_counter = 0; + t_i2c_registers *p_i2c_registers; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + if (I2C_WRITE == g_i2c_system_context[id].operation) + { + /* SLAVE TRANSMITTER */ + /* Waiting for the Read from slave request */ + loop_counter = 0; + while + ( + (!I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_RFSR, I2C_INT_SHIFT_RFSR)) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + i2cp_Abort(id); + return(I2C_ADDRESS_MATCH_FAILED); + } + + /* Acknowledge the Read from slave request */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_RFSR); + + /* Read from slave request recieved */ + /* Flush the Tx Fifo */ + I2C_SET_BIT(p_i2c_registers->cr, I2C_CR_FTX); + + /*Wait till for the Tx Flush bit to reset */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->cr, I2C_CR_FTX, I2C_CR_SHIFT_FTX) + && loop_counter < I2C_FIFO_FLUSH_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_FIFO_FLUSH_COUNTER) + { + return(I2C_HW_FAILED); + } + + /* update the status */ + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_TRANSMITTER_MODE; + g_i2c_system_context[id].active_event = I2C_READ_FROM_SLAVE_REQUEST_EVENT; + g_i2c_system_context[id].current_bus_config = I2C_CURRENT_BUS_SLAVE_TRANSMITTER; + + } + else + { + /* SLAVE RECEIVER */ + /* Waiting for the Write to slave request */ + loop_counter = 0; + while + ( + (!I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_WTSR, I2C_INT_SHIFT_WTSR)) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + i2cp_Abort(id); + return(I2C_ADDRESS_MATCH_FAILED); + } + + /* Acknowledge the Write to slave request */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_WTSR); + + /* update the status */ + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_TRANSMITTER_MODE; + g_i2c_system_context[id].active_event = I2C_WRITE_TO_SLAVE_REQUEST_EVENT; + g_i2c_system_context[id].current_bus_config = I2C_CURRENT_BUS_SLAVE_RECEIVER; + + } + + /* Update the status of the I2C controller */ + if (I2C_READ == g_i2c_system_context[id].operation) + { + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_RECEIVER_MODE; + } + else + { + g_i2c_system_context[id].status = I2C_STATUS_SLAVE_TRANSMITTER_MODE; + } + + return(I2C_OK); +} + +/*----------------------------------------------------------------------------- +Name : i2cp_TransmitDataPolling +Description : Transmit the data in the polling mode +In : t_i2c_id : I2C Controller id + +InOut : None +Out : t_i2c_error error status +Return value: I2C_OK : no error + I2C_INVALID_PARAMETER : wrong id parameter. + +Type : Private +Comments : +-----------------------------------------------------------------------------*/ +t_i2c_error i2cp_TransmitDataPolling(t_i2c_device_id id, volatile u8 *p_data) +{ + + u32 loop_counter = 0; + t_i2c_registers *p_i2c_registers; + t_i2c_error error_status; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + /* Slave tranmitter */ + while (g_i2c_system_context[id].count_data != 0) + { + /* Check for Tx Fifo not full */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_TXFF, I2C_INT_SHIFT_TXFF) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + return(I2C_TRANSMIT_FIFO_FULL); + } + } + + p_i2c_registers->tfr = *p_data; + + g_i2c_system_context[id].transfer_data++; + g_i2c_system_context[id].count_data--; + p_data++; + g_i2c_system_context[id].active_event = I2C_DATA_TX_EVENT; + } + + /* End of Data transfer */ + /* Check for the Slave tranaction done */ + loop_counter = 0; + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_STD, I2C_INT_SHIFT_STD) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_INTERNAL_ERROR); + } + + /* Slave Transaction has been done */ + /* Acknowledge the Slave Transaction done */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_STD); + + g_i2c_system_context[id].active_event = I2C_TRANSFER_OK_EVENT; + return(I2C_OK); + } + else + { + /* Master Transmitter */ + while (g_i2c_system_context[id].count_data != 0) + { + /* Check for Tx Fifo not full */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_TXFF, I2C_INT_SHIFT_TXFF) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_TRANSMIT_FIFO_FULL); + } + + p_i2c_registers->tfr = *p_data; + + g_i2c_system_context[id].transfer_data++; + g_i2c_system_context[id].count_data--; + p_data++; + g_i2c_system_context[id].active_event = I2C_DATA_TX_EVENT; + } + + /* End of Data transfer */ + + loop_counter = 0; + /* Check whether the Stop bit has been programmed or not */ + if(I2C_READ_FIELD(p_i2c_registers->mcr, I2C_MCR_STOP, I2C_MCR_SHIFT_STOP)) + { + /* Check for the Master transaction Done */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTD, I2C_INT_SHIFT_MTD) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + else + { + /* Check for the Master transaction Done Without Stop */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTDWS, I2C_INT_SHIFT_MTDWS) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + + + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + i2cp_Abort(id); + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_INTERNAL_ERROR); + } + + + /* Master Transaction has been done */ + /* Acknowledge the Master Transaction Done */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTD); + + /* Master Transaction Without Stop has been done */ + /* Acknowledge the Master Transaction Done Without Stop */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTDWS); + + + g_i2c_system_context[id].active_event = I2C_TRANSFER_OK_EVENT; + + g_i2c_system_context[id].operation = I2C_NO_OPERATION; + return(I2C_OK); + } + +} + +/*----------------------------------------------------------------------------- +Name : i2cp_ReceiveDataPolling +Description : Receiving the data in polling mode +In : t_i2c_id : I2C Controller id + +InOut : None +Out : t_i2c_error error status +Return value: I2C_OK : no error + I2C_WRONG_PARAMETER : wrong id parameter. + +Type : Private +Comments : +-----------------------------------------------------------------------------*/ +t_i2c_error i2cp_ReceiveDataPolling(t_i2c_device_id id, u8 *p_data) +{ + + u32 loop_counter = 0; + t_i2c_error error_status; + t_i2c_registers *p_i2c_registers; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + if (I2C_BUS_SLAVE_MODE == g_i2c_system_context[id].bus_control_mode) + { + /* Slave Receiver */ + while (g_i2c_system_context[id].count_data != 0) + { + /* Wait for the Rx Fifo empty */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_RXFE, I2C_INT_SHIFT_RXFE) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_RECEIVE_FIFO_EMPTY); + } + + /* Read the data byte from Rx Fifo */ + *p_data = (u8) p_i2c_registers->rfr; + + g_i2c_system_context[id].transfer_data++; + g_i2c_system_context[id].count_data--; + p_data++; + g_i2c_system_context[id].active_event = I2C_DATA_RX_EVENT; + } /* Data Reception has been completed */ + + /* Check for the slave transaction done */ + loop_counter = 0; + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_STD, I2C_INT_SHIFT_STD) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_INTERNAL_ERROR); + } + + /* Slave Transaction has been done */ + /* Acknowledge the Slave Transaction Done */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_STD); + g_i2c_system_context[id].active_event = I2C_TRANSFER_OK_EVENT; + g_i2c_system_context[id].operation = I2C_NO_OPERATION; + + return(I2C_OK); + } + else + { + /* Master Receiver */ + while (g_i2c_system_context[id].count_data != 0) + { + /* Wait for the Rx Fifo empty */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_RXFE, I2C_INT_SHIFT_RXFE) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_RECEIVE_FIFO_EMPTY); + } + + /* Read the data byte from Rx Fifo */ + *p_data = (u8) p_i2c_registers->rfr; + + g_i2c_system_context[id].transfer_data++; + g_i2c_system_context[id].count_data--; + p_data++; + g_i2c_system_context[id].active_event = I2C_DATA_RX_EVENT; + } /* Data reception has been completed */ + + loop_counter = 0; + /* Check whether the Stop bit has been programmed or not */ + if(I2C_READ_FIELD(p_i2c_registers->mcr, I2C_MCR_STOP, I2C_MCR_SHIFT_STOP)) + { + /* Check for the Master transaction Done */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTD, I2C_INT_SHIFT_MTD) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + else + { + /* Check for the Master transaction Done Without Stop */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTDWS, I2C_INT_SHIFT_MTDWS) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_INTERNAL_ERROR); + } + + /* Master Transaction has been done */ + /* Acknowledge the Master Transaction Done */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTD); + + /* Master Transaction Without Stop has been done */ + /* Acknowledge the Master Transaction Done Without Stop */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTDWS); + + g_i2c_system_context[id].active_event = I2C_TRANSFER_OK_EVENT; + g_i2c_system_context[id].operation = I2C_NO_OPERATION; + + } + + return(I2C_OK); +} + +/*----------------------------------------------------------------------------- +Name : i2cp_MasterIndexTransmit +Description : Transmits the index to slave +In : t_i2c_id : I2C Controller id + +InOut : None +Out : t_i2c_error error status +Return value: I2C_OK : no error + I2C_WRONG_PARAMETER : wrong id parameter. + +Type : Private +Comments : +-----------------------------------------------------------------------------*/ +t_i2c_error i2cp_MasterIndexTransmit(t_i2c_device_id id) +{ + + volatile u32 mcr = 0; + u32 loop_counter = 0; + t_i2c_error error_status = I2C_OK; + t_i2c_registers *p_i2c_registers; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + switch (g_i2c_system_context[id].index_format) + { + case I2C_NO_INDEX: + if (g_i2c_system_context[id].slave_address <= 127) + { + return(I2C_OK); + } + + break; + + case I2C_BYTE_INDEX: + /* Checking for the Tx fifo not full */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_TXFF, I2C_INT_SHIFT_TXFF) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_TRANSMIT_FIFO_FULL); + } + + p_i2c_registers->tfr = (0xFF & g_i2c_system_context[id].register_index); + + g_i2c_system_context[id].active_event = I2C_INDEX_TX_EVENT; + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + + break; + + case I2C_HALF_WORD_LITTLE_ENDIAN: + /* Checking for the Tx Fifo not full */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_TXFF, I2C_INT_SHIFT_TXFF) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_TRANSMIT_FIFO_FULL); + } + + p_i2c_registers->tfr = (0xFF & (u32) g_i2c_system_context[id].register_index); + + p_i2c_registers->tfr = (g_i2c_system_context[id].register_index >> 8); + + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + g_i2c_system_context[id].active_event = I2C_INDEX_TX_EVENT; + break; + + case I2C_HALF_WORD_BIG_ENDIAN: + /* Cheking for the Tx Fifo full */ + loop_counter = 0; + while + ( + I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_TXFF, I2C_INT_SHIFT_TXFF) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_TRANSMIT_FIFO_FULL); + } + + p_i2c_registers->tfr = (g_i2c_system_context[id].register_index >> 8); + + p_i2c_registers->tfr = (0xFF & g_i2c_system_context[id].register_index); + + g_i2c_system_context[id].index_format = I2C_NO_INDEX; + g_i2c_system_context[id].active_event = I2C_INDEX_TX_EVENT; + break; + + default: + break; + } + + if (g_i2c_system_context[id].operation == I2C_READ) + { + loop_counter = 0; + /* Check whether the Stop bit has been programmed or not */ + if(I2C_READ_FIELD(p_i2c_registers->mcr, I2C_MCR_STOP, I2C_MCR_SHIFT_STOP)) + { + /* Check for the Master transaction Done */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTD, I2C_INT_SHIFT_MTD) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + else + { + /* Check for the Master transaction Done Without Stop */ + while + ( + !I2C_READ_FIELD(p_i2c_registers->risr, I2C_INT_MTDWS, I2C_INT_SHIFT_MTDWS) + && loop_counter < I2C_ENDAD_COUNTER + ) + { + loop_counter++; + }; + } + + if (loop_counter >= I2C_ENDAD_COUNTER) + { + error_status = i2cp_GetAbortCause(id); + if (error_status != I2C_OK) + { + return(error_status); + } + else + { + i2cp_Abort(id); + } + + return(I2C_INTERNAL_ERROR); + } + + /* Master Transaction has been done */ + /* Acknowledge the Master Transaction Done */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTD); + + /* Master Transaction Without Stop has been done */ + /* Acknowledge the Master Transaction Done Without Stop */ + I2C_SET_BIT(p_i2c_registers->icr, I2C_INT_MTDWS); + + /* Master control configuration for read operation */ + I2C_SET_BIT(mcr, I2C_MCR_OP); + + /* Configure the STOP condition*/ + I2C_SET_BIT(mcr, I2C_MCR_STOP); + + /* Configuring the Frame length */ + I2C_WRITE_FIELD(mcr, I2C_MCR_LENGTH, I2C_MCR_SHIFT_LENGTH, g_i2c_system_context[id].count_data); + + I2C_WRITE_FIELD(p_i2c_registers->mcr,I2C_MCR_LENGTH_STOP_OP,I2C_MCR_SHIFT_LENGTH_STOP_OP,mcr); + + } + + /* added to remove the warning unused variable */ + error_status = error_status; + + /* Update the status of the I2C controller */ + if (I2C_READ == g_i2c_system_context[id].operation) + { + g_i2c_system_context[id].status = I2C_STATUS_MASTER_RECEIVER_MODE; + } + else + { + g_i2c_system_context[id].status = I2C_STATUS_MASTER_TRANSMITTER_MODE; + } + + return(I2C_OK); +} + + +/* Private function valid for HS controller */ + + +/****************************************************************************/ +/* NAME : i2cp_GetAbortCause */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Get the abort Cause */ +/* */ +/* PARAMETERS : */ +/* : t_i2c_device_id : The controller that aborted */ +/* InOut : None */ +/* : None */ +/* */ +/* RETURN : t_i2c_error */ +/*--------------------------------------------------------------------------*/ +/* Type : */ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES : */ + +/****************************************************************************/ +t_i2c_error i2cp_GetAbortCause(t_i2c_device_id id) +{ + u8 abort_cause; + t_i2c_error error_status; + + t_i2c_registers *p_i2c_registers; + + p_i2c_registers = (t_i2c_registers *) g_i2c_system_context[id].base_address; + + if (I2C_READ_FIELD(p_i2c_registers->sr, I2C_SR_STATUS, I2C_SR_SHIFT_STATUS) == 3) + { + abort_cause = (u8) I2C_READ_FIELD(p_i2c_registers->sr, I2C_SR_CAUSE, I2C_SR_SHIFT_CAUSE); + + switch (abort_cause) + { + case 0: + error_status = I2C_ACK_FAIL_ON_ADDRESS; + break; + + case 1: + error_status = I2C_ACK_FAIL_ON_DATA; + break; + + case 2: + error_status = I2C_ACK_IN_HS_MODE; + break; + + case 3: + error_status = I2C_ARBITRATION_LOST; + break; + + case 4: + error_status = I2C_BUS_ERROR_DETECTED_START; + break; + + case 5: + error_status = I2C_BUS_ERROR_DETECTED_STOP; + break; + + case 6: + error_status = I2C_OVERFLOW; + break; + + default: + error_status = I2C_INTERNAL_ERROR; + break; + } + + return(error_status); + } + + return(I2C_OK); +} + + +/****************************************************************************/ +/* NAME : I2C_SetBaseAddress */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : This routine initializes I2C register base address. */ +/* */ +/* PARAMETERS : */ +/* IN : id : I2C controller id */ +/* i2c_base_address : I2C registers base address */ +/* OUT : None */ +/* */ +/* RETURN : None */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES: */ +/* 1) Global variable gp_registers (register base address) */ +/* is being modified */ + +/****************************************************************************/ +void I2C_SetBaseAddress(t_i2c_device_id id, t_logical_address address) +{ + /* Initializing the I2C controller base address */ + gp_i2c_registers[id] = (t_i2c_registers *) address; +} + +/****************************************************************************/ +/* NAME : I2C_DisableIRQSrc */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION : Disable the given I2C controller to generate interrupts. */ +/* */ +/* PARAMETERS : */ +/* IN : t_i2c_irq_src_id id : the IRQ source to be disabled. */ +/* OUT : None */ +/* */ +/* RETURN : None */ +/*--------------------------------------------------------------------------*/ +/* REENTRANCY : Non Re-entrant */ +/* REENTRANCY ISSUES: */ + +/****************************************************************************/ +void I2C_DisableIRQSrc(t_i2c_irq_src_id irq_id) +{ + + gp_i2c_registers[GETDEVICE((u32)irq_id)]->imscr &= ~((u32)I2C_IRQ_SRC_ALL & (u32)irq_id); + +} diff --git a/board/st/u8500/i2c.h b/board/st/u8500/i2c.h new file mode 100755 index 000000000..3a5b93625 --- /dev/null +++ b/board/st/u8500/i2c.h @@ -0,0 +1,848 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + + +#ifndef _U8500_I2C_H_ +#define _U8500_I2C_H_ + +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include "common.h" +#include <configs/u8500.h> + +#define MASK_BIT0 (1UL<<0) +#define MASK_BIT1 (1UL<<1) +#define MASK_BIT2 (1UL<<2) +#define MASK_BIT3 (1UL<<3) +#define MASK_BIT4 (1UL<<4) +#define MASK_BIT5 (1UL<<5) +#define MASK_BIT6 (1UL<<6) +#define MASK_BIT7 (1UL<<7) +#define MASK_BIT8 (1UL<<8) +#define MASK_BIT9 (1UL<<9) +#define MASK_BIT10 (1UL<<10) +#define MASK_BIT11 (1UL<<11) +#define MASK_BIT12 (1UL<<12) +#define MASK_BIT13 (1UL<<13) +#define MASK_BIT14 (1UL<<14) +#define MASK_BIT15 (1UL<<15) +#define MASK_BIT16 (1UL<<16) +#define MASK_BIT17 (1UL<<17) +#define MASK_BIT18 (1UL<<18) +#define MASK_BIT19 (1UL<<19) +#define MASK_BIT20 (1UL<<20) +#define MASK_BIT21 (1UL<<21) +#define MASK_BIT22 (1UL<<22) +#define MASK_BIT23 (1UL<<23) +#define MASK_BIT24 (1UL<<24) +#define MASK_BIT25 (1UL<<25) +#define MASK_BIT26 (1UL<<26) +#define MASK_BIT27 (1UL<<27) +#define MASK_BIT28 (1UL<<28) +#define MASK_BIT29 (1UL<<29) +#define MASK_BIT30 (1UL<<30) +#define MASK_BIT31 (1UL<<31) +/*----------------------------------------------------------------------------- + Typedefs +-----------------------------------------------------------------------------*/ +typedef enum{ + I2C0, + I2C1, + I2C2, + I2C3 +}t_i2c_device_id; + + + +/*----------------------------------------------------------------------------- + + Generic Macros + +-----------------------------------------------------------------------------*/ + +#define I2C_SET_BIT(reg_name,mask) ((reg_name) |= (mask)) +#define I2C_CLR_BIT(reg_name,mask) ((reg_name) &= ~(mask)) +#define I2C_WRITE_BIT(reg_name,val,mask) ((reg_name) = (((reg_name) & ~(mask)) | ((val) & (mask)))) +#define I2C_TEST_BIT(reg_name,val) ((reg_name) & (mask)) +#define I2C_WRITE_REG(reg_name,val) ((reg_name) = (val)) +#define I2C_READ_REG(reg_name) (reg_name) +#define I2C_CLEAR 0x00000000 + + +#define I2C_WRITE_FIELD(reg_name,mask,shift,value) \ + (reg_name = ((reg_name & ~mask) | (value << shift))) + + +#define I2C_READ_FIELD(reg_name,mask,shift) ((reg_name & mask) >> shift ) + +typedef volatile struct +{ + + + u32 cr; /* Control Register 0x00 */ + u32 scr; /* Slave Address Register 0x04 */ + u32 hsmcr; /* HS Master code Register 0x08 */ + u32 mcr; /* Master Control Register 0x0C */ + u32 tfr; /* Transmit Fifo Register 0x10 */ + u32 sr; /* Status Register 0x14 */ + u32 rfr; /* Receiver Fifo Register 0x18 */ + u32 tftr; /* Transmit Fifo Threshold Register 0x1C */ + u32 rftr; /* Receiver Fifo Threshold Register 0x20 */ + u32 dmar; /* DMA register 0x24 */ + u32 brcr; /* Baud Rate Counter Register 0x28 */ + u32 imscr; /* Interrupt Mask Set and Clear Register 0x2C */ + u32 risr; /* Raw interrupt status register 0x30 */ + u32 misr; /* Masked interrupt status register 0x34 */ + u32 icr; /* Interrupt Set and Clear Register 0x38 */ + u32 reserved_1[(0xFE0 - 0x3c) >> 2]; /* Reserved 0x03C to 0xFE0*/ + u32 periph_id_0; /*peripheral ID 0 0xFE0 */ + u32 periph_id_1; /*peripheral ID 1 0xFE4 */ + u32 periph_id_2; /*peripheral ID 2 0xFE8 */ + u32 periph_id_3; /*peripheral ID 3 0xFEC */ + u32 cell_id_0; /*I2C cell ID 0 0xFF0 */ + u32 cell_id_1; /*I2C cell ID 1 0xFF4 */ + u32 cell_id_2; /*I2C cell ID 2 0xFF8 */ + u32 cell_id_3; /*I2C cell ID 3 0xFFC */ + + +}t_i2c_registers; + + + +/* Control Register */ + /* Mask values for control register mask */ +#define I2C_CR_PE MASK_BIT0 /* Peripheral enable*/ +#define I2C_CR_OM 0x6 /* Operation mode */ +#define I2C_CR_SAM MASK_BIT3 /* Slave Addressing mode */ +#define I2C_CR_SM 0x30 /* Speed mode */ +#define I2C_CR_SGCM MASK_BIT6 /* Slave General call mode */ +#define I2C_CR_FTX MASK_BIT7 /* Flush Transmit */ +#define I2C_CR_FRX MASK_BIT8 /* Flush Receive */ +#define I2C_CR_DMA_TX_EN MASK_BIT9 /* DMA TX Enable */ +#define I2C_CR_DMA_RX_EN MASK_BIT10 /* DMA Rx Enable */ +#define I2C_CR_DMA_SLE MASK_BIT11 /* DMA Synchronization Logic enable */ +#define I2C_CR_LM MASK_BIT12 /* Loop back mode */ +#define I2C_CR_FON 0x6000 /* Filtering On */ + + /* shift valus for control register bit fields */ +#define I2C_CR_SHIFT_PE 0 /* Peripheral enable*/ +#define I2C_CR_SHIFT_OM 1 /* Operation mode */ +#define I2C_CR_SHIFT_SAM 3 /* Slave Addressing mode */ +#define I2C_CR_SHIFT_SM 4 /* Speed mode */ +#define I2C_CR_SHIFT_SGCM 6 /* Slave General call mode */ +#define I2C_CR_SHIFT_FTX 7 /* Flush Transmit */ +#define I2C_CR_SHIFT_FRX 8 /* Flush Receive */ +#define I2C_CR_SHIFT_DMA_TX_EN 9 /* DMA TX Enable */ +#define I2C_CR_SHIFT_DMA_RX_EN 10 /* DMA Rx Enable */ +#define I2C_CR_SHIFT_DMA_SLE 11 /* DMA Synchronization Logic enable */ +#define I2C_CR_SHIFT_LM 12 /* Loop back mode */ +#define I2C_CR_SHIFT_FON 13 /* Filtering On */ + + +/* Slave control register*/ + /* Mask values slave control register */ +#define I2C_SCR_ADDR 0x3FF +#define I2C_SCR_DATA_SETUP_TIME 0xFFFF0000 + + /* Shift values for Slave control register */ +#define I2C_SCR_SHIFT_ADDR 0 +#define I2C_SCR_SHIFT_DATA_SETUP_TIME 16 + + + +/* Master Control Register */ + /* Mask values for Master control register */ +#define I2C_MCR_OP MASK_BIT0 /* Operation */ +#define I2C_MCR_A7 0xFE /* LSB bits of the Address(7-bit ) */ +#define I2C_MCR_EA10 0x700 /* Extended Address */ +#define I2C_MCR_SB MASK_BIT11 /* Start byte procedure */ +#define I2C_MCR_AM 0x3000 /* Address type */ +#define I2C_MCR_STOP MASK_BIT14 /* stop condition */ +#define I2C_MCR_LENGTH 0x3FF8000 /* Frame length */ +#define I2C_MCR_A10 0x7FE /* Define to set the 10 bit address */ + +#define I2C_MCR_LENGTH_STOP_OP 0x3FFC001 /*mask for length field,stop and operation */ + /* Shift values for Master control values */ + +#define I2C_MCR_SHIFT_OP 0 /* Operation */ +#define I2C_MCR_SHIFT_A7 1 /* LSB bits of the Address(7-bit ) */ +#define I2C_MCR_SHIFT_EA10 8 /* Extended Address */ +#define I2C_MCR_SHIFT_SB 11 /* Start byte procedure */ +#define I2C_MCR_SHIFT_AM 12 /* Address type */ +#define I2C_MCR_SHIFT_STOP 14 /* stop condition */ +#define I2C_MCR_SHIFT_LENGTH 15 /* Frame length */ +#define I2C_MCR_SHIFT_A10 1 /* define to set the 10 bit addres */ + +#define I2C_MCR_SHIFT_LENGTH_STOP_OP 0 + +/* Status Register */ + /* Mask values for Status register */ +#define I2C_SR_OP 0x3 /* Operation */ +#define I2C_SR_STATUS 0xC /* Controller Status */ +#define I2C_SR_CAUSE 0x70 /* Abort Cause */ +#define I2C_SR_TYPE 0x180 /* Receive Type */ +#define I2C_SR_LENGTH 0xFF700 /* Transfer length */ + +/* Shift values for Status register */ +#define I2C_SR_SHIFT_OP 0 /* Operation */ +#define I2C_SR_SHIFT_STATUS 2 /* Controller Status */ +#define I2C_SR_SHIFT_CAUSE 4 /* Abort Cause */ +#define I2C_SR_SHIFT_TYPE 7 /* Receive Type */ +#define I2C_SR_SHIFT_LENGTH 9 /* Transfer length */ + + +/* DMA Register */ + /* Mask values for DMA register */ +#define I2C_DMA_SBSIZE_RX 0x7 /* Source Burst Size Rx */ +#define I2C_DMA_BURST_RX MASK_BIT3 /* Burst Rx */ +#define I2C_DMA_DBSIZE_TX 0x700 /* Destination Burst Size Tx */ +#define I2C_DMA_BURST_TX MASK_BIT11 /* Burst Tx */ + + /* Shift values for DMA register */ +#define I2C_DMA_SHIFT_SBSIZE_RX 0 /* Source Burst Size Rx */ +#define I2C_DMA_SHIFT_BURST_RX 3 /* Burst Rx */ +#define I2C_DMA_SHIFT_DBSIZE_TX 8 /* Destination Burst Size Tx */ +#define I2C_DMA_SHIFT_BURST_TX 11 /* Burst Tx */ + +/* Baud rate counter registers */ + /* Mask values for Baud rate counter register */ +#define I2C_BRCR_BRCNT2 0xFFFF /* Baud rate counter value for HS mode */ +#define I2C_BRCR_BRCNT1 0xFFFF0000 /* Baud rate counter value for Standard and Fast mode*/ + +/* Shift values for the Baud rate counter register */ +#define I2C_BRCR_SHIFT_BRCNT2 0 +#define I2C_BRCR_SHIFT_BRCNT1 16 + + + +/* Interrupt Register */ + /* Mask values for Interrupt registers */ +#define I2C_INT_TXFE MASK_BIT0 /* Tx fifo empty */ +#define I2C_INT_TXFNE MASK_BIT1 /* Tx Fifo nearly empty */ +#define I2C_INT_TXFF MASK_BIT2 /* Tx Fifo Full */ +#define I2C_INT_TXFOVR MASK_BIT3 /* Tx Fifo over run */ +#define I2C_INT_RXFE MASK_BIT4 /* Rx Fifo Empty */ +#define I2C_INT_RXFNF MASK_BIT5 /* Rx Fifo nearly empty */ +#define I2C_INT_RXFF MASK_BIT6 /* Rx Fifo Full */ +#define I2C_INT_RFSR MASK_BIT16 /* Read From slave request */ +#define I2C_INT_RFSE MASK_BIT17 /* Read from slave empty */ +#define I2C_INT_WTSR MASK_BIT18 /* Write to Slave request */ +#define I2C_INT_MTD MASK_BIT19 /* Master Transcation Done*/ +#define I2C_INT_STD MASK_BIT20 /* Slave Transaction Done */ +#define I2C_INT_MAL MASK_BIT24 /* Master Arbitation Lost */ +#define I2C_INT_BERR MASK_BIT25 /* Bus Error */ +#define I2C_INT_MTDWS MASK_BIT28 /* Master Transcation Done Without Stop*/ + /* Shift values for Interrupt registers */ +#define I2C_INT_SHIFT_TXFE 0 /* Tx fifo empty */ +#define I2C_INT_SHIFT_TXFNE 1 /* Tx Fifo nearly empty */ +#define I2C_INT_SHIFT_TXFF 2 /* Tx Fifo Full */ +#define I2C_INT_SHIFT_TXFOVR 3 /* Tx Fifo over run */ +#define I2C_INT_SHIFT_RXFE 4 /* Rx Fifo Empty */ +#define I2C_INT_SHIFT_RXFNF 5 /* Rx Fifo nearly empty */ +#define I2C_INT_SHIFT_RXFF 6 /* Rx Fifo Full */ +#define I2C_INT_SHIFT_RFSR 16 /* Read From slave request */ +#define I2C_INT_SHIFT_RFSE 17 /* Read from slave empty */ +#define I2C_INT_SHIFT_WTSR 18 /* Write to Slave request */ +#define I2C_INT_SHIFT_MTD 19 /* Master Transcation Done */ +#define I2C_INT_SHIFT_STD 20 /* Slave Transaction Done */ +#define I2C_INT_SHIFT_MAL 24 /* Master Arbitation Lost */ +#define I2C_INT_SHIFT_BERR 25 /* Bus Error */ +#define I2C_INT_SHIFT_MTDWS 28 /* Master Transcation Done Without Stop*/ + + + +/*----------------------------------------------------------------------------- + Typedefs +-----------------------------------------------------------------------------*/ +typedef enum { + I2C_FREQ_MODE_STANDARD, /* Standard mode. */ + I2C_FREQ_MODE_FAST, /* Fast mode. */ + I2C_FREQ_MODE_HIGH_SPEED /* High Speed mode. */ +} t_i2c_freq_mode; + +typedef enum { + I2C_BUS_SLAVE_MODE = 0, /* Slave Mode */ + I2C_BUS_MASTER_MODE, /* Master Mode */ + I2C_BUS_MASTER_SLAVE_MODE /* Dual Configuration Mode */ +} t_i2c_bus_control_mode; + +typedef enum { + I2C_CURRENT_BUS_SLAVE_TRANSMITTER, + I2C_CURRENT_BUS_SLAVE_RECEIVER, + I2C_CURRENT_BUS_MASTER_TRANSMITTER, + I2C_CURRENT_BUS_MASTER_RECEIVER +}t_i2c_current_bus_configuration; + +typedef enum { + I2C_TRANSFER_MODE_POLLING, + I2C_TRANSFER_MODE_INTERRUPT, + I2C_TRANSFER_MODE_DMA +}t_i2c_transfer_mode; + +typedef enum { + I2C_DISABLE, + I2C_ENABLE +}t_i2c_control; + +typedef enum { + I2C_COMMAND_SEND_START, + I2C_COMMAND_SEND_STOP, + I2C_COMMAND_SEND_ACKNOWLEDGE, + I2C_COMMAND_CLEAR_ACKNOWLEDGE, + I2C_COMMAND_SET_TRANSMIT_DMA, + I2C_COMMAND_CLEAR_TRANSMIT_DMA, + I2C_COMMAND_SET_RECEIVE_DMA, + I2C_COMMAND_CLEAR_RECEIVE_DMA +}t_i2c_command; + + +typedef enum { + I2C_STATUS_SLAVE_MODE, /* Controller is in slave mode.*/ + I2C_STATUS_MASTER_MODE, /* Controller is in master mode.*/ + I2C_STATUS_MASTER_TRANSMITTER_MODE, /* Controller is in master transmitter mode.*/ + I2C_STATUS_MASTER_RECEIVER_MODE, /* Controller is in master receiver mode.*/ + I2C_STATUS_SLAVE_TRANSMITTER_MODE, /* Controller is in slave transmitter mode.*/ + I2C_STATUS_SLAVE_RECEIVER_MODE /* Controller is in slave receiver mode.*/ +} t_i2c_device_status; + + +typedef enum { + I2C_TRANSMIT_FIFO, + I2C_RECEIVE_FIFO +}t_i2c_fifo; + + +typedef enum { + I2C_DIGITAL_FILTERS_OFF, + I2C_DIGITAL_FILTERS_1_CLK_SPIKES, + I2C_DIGITAL_FILTERS_2_CLK_SPIKES, + I2C_DIGITAL_FILTERS_4_CLK_SPIKES +}t_i2c_digital_filter; + + +typedef struct { + t_i2c_digital_filter i2c_digital_filter_control; + t_i2c_control i2c_dma_sync_logic_control; + t_i2c_control i2c_start_byte_procedure; /*ONLY VALID FOR MASTER MODE TRANSACTIONS*/ + u8 i2c_high_speed_master_code; /*ONLY VALID FOR MASTER MODE TRANSACTIONS*/ + u16 slave_data_setup_time; /* Only valid for HS controller */ + u16 controller_i2c_address; + u32 input_frequency; +} t_i2c_device_config; + +typedef enum { + I2C_NO_GENERAL_CALL_HANDLING, + I2C_SOFTWARE_GENERAL_CALL_HANDLING, + I2C_HARDWARE_GENERAL_CALL_HANDLING +} t_i2c_general_call_handling; + +typedef struct { + t_i2c_control i2c_loopback_mode; + t_i2c_general_call_handling i2c_slave_general_call_mode; + t_i2c_transfer_mode index_transfer_mode; + t_i2c_transfer_mode data_transfer_mode; + t_i2c_bus_control_mode bus_control_mode; + u8 i2c_transmit_interrupt_threshold; + u8 i2c_receive_interrupt_threshold; + u8 transmit_burst_length; + u8 receive_burst_length; + u32 i2c_transfer_frequency; +} t_i2c_transfer_config; + + + +typedef struct { + t_logical_address base_address; /* The controller's logical base address. */ + t_i2c_device_id id; /* The controller's id. */ + t_i2c_freq_mode freq_mode; /* Standard ,Fast mode or Hs Mode. */ + t_bool is_enabled; /* True means controller is enabled. */ + t_i2c_bus_control_mode bus_control_mode; + t_i2c_current_bus_configuration current_bus_config; + t_i2c_general_call_handling general_call_handling; + u32 freq_scl; /* The I2C bus SCL clock frequency (Hz). */ + u32 freq_input; /* The controller's input clock frequency (Hz). */ + u32 own_address; /* The controller's slave address. */ +} t_i2c_info; /* Used to provide information to the user. */ + + +typedef enum { + /*Common to all platforms*/ + I2C_STATE_GENERAL_CALL_DETECTED = MASK_BIT0, + I2C_STATE_ARBITRATION_LOST = MASK_BIT2, + I2C_STATE_BUSY = MASK_BIT12, + + I2C_STATE_TRANSFER_COMPLETE = MASK_BIT16, + I2C_STATE_ABORT_NACK_ON_ADDRESS = MASK_BIT17, + I2C_STATE_ABORT_NACK_ON_DATA = MASK_BIT18, + I2C_STATE_ABORT_ACK_ON_MASTER_CODE = MASK_BIT19, + I2C_STATE_BUS_ERROR_DETECTED_START = MASK_BIT20, + I2C_STATE_BUS_ERROR_DETECTED_STOP = MASK_BIT21, + I2C_STATE_OVERFLOW = MASK_BIT22, + I2C_STATE_HARDWARE_GENERAL_CALL = MASK_BIT23 +} t_i2c_device_states; + + +typedef enum { + I2C_NO_PENDG_EVENT_ERROR = 7, /*U8500_NO_PENDG_EVENT_ERROR,*/ + I2C_NO_MORE_FILTER_PENDG_EVENT = 5, /*U8500_NO_MORE_FILTER_PENDG_EVENT,*/ + I2C_NO_MORE_PENDG_EVENT = 5, /*U8500_NO_MORE_PENDG_EVENT,*/ + I2C_REMAG_FILTER_PENDG_EVENTS = 3,/*U8500_REMAG_FILTER_PENDG_EVENTS,*/ + I2C_REMAG_PENDG_EVENTS = 2,/*U8500_REMAG_PENDG_EVENTS,*/ + I2C_INTERNAL_EVENT = 1,/*U8500_INTERNAL_EVENT,*/ + I2C_OK = 0, /*U8500_OK,*/ /* No error. */ + I2C_INTERNAL_ERROR = -8, /*U8500_INTERNAL_ERROR,*/ + I2C_NOT_CONFIGURED = -7, /*U8500_NOT_CONFIGURED,*/ + I2C_REQUEST_PENDG = -6, /*U8500_REQUEST_PENDG,*/ + I2C_REQUEST_NOT_APPLICABLE = -5, /*U8500_REQUEST_NOT_APPLICABLE,*/ + I2C_INVALID_PARAMETER = -4, /*U8500_VALID_PARAMETER,*/ + I2C_UNSUPPORTED_FEATURE = -3, /*U8500_UNSUPPORTED_FEATURE,*/ + I2C_UNSUPPORTED_HW = -2, /*U8500_UNSUPPORTED_HW,*/ + I2C_HW_FAILED = -66, /*(U8500_MAX_ERROR_VALUE -1),*/ /* Generic hardware error. */ + I2C_SW_FAILED = -67, /*(U8500_MAX_ERROR_VALUE -2),*/ /* Generic software error. */ + I2C_CONTROLLER_BUSY = -68, /*(U8500_MAX_ERROR_VALUE -3),*/ /* Transfer on going. */ + I2C_LINE_FREQ_NOT_SUPPORTED = -69, /*(U8500_MAX_ERROR_VALUE -4),*/ /* SCL bus frequency not supported. */ + I2C_PUT_FREQ_NOT_SUPPORTED = -70, /*(U8500_MAX_ERROR_VALUE -5),*/ /* Input frequency not supported. */ + I2C_DDC_MODE_NOT_SUPPORTED = -71, /*(U8500_MAX_ERROR_VALUE -6),*/ /* DDC mode not supported. */ + I2C_SLAVE_ADDRESS_NOT_VALID = -72, /*(U8500_MAX_ERROR_VALUE -7),*/ /* Slave address is reserved or not valid. */ + + I2C_BYTE_TRANSFER_FAILED = -165, /*(U8500_MAX_ERROR_VALUE -100),*/ + I2C_ADDRESS_MATCH_FAILED = -166, /*(U8500_MAX_ERROR_VALUE -101),*/ + I2C_START_BYTE_FAILED = -167, /*(U8500_MAX_ERROR_VALUE -102),*/ + I2C_ACKNOWLEDGE_FAILURE = -168, /*(U8500_MAX_ERROR_VALUE -103),*/ + I2C_STOP_FAILED = -169, /*(U8500_MAX_ERROR_VALUE -104),*/ + I2C_ARBITRATION_LOST = -170, /*(U8500_MAX_ERROR_VALUE -105),*/ + I2C_BUS_ERROR = -171, /*(U8500_MAX_ERROR_VALUE -106),*/ + I2C_10_BIT_ADDRESS_FAILED = -172, /*(U8500_MAX_ERROR_VALUE -107),*/ + I2C_SCL_FALL_FAILED = -173, /*(U8500_MAX_ERROR_VALUE -108),*/ + I2C_END_ADDRESS_FAILED = -174, /*(U8500_MAX_ERROR_VALUE -109),*/ + + I2C_TRANSMIT_FIFO_FULL = -175, /*(U8500_MAX_ERROR_VALUE -200),*/ + I2C_RECEIVE_FIFO_EMPTY = -176, /*(U8500_MAX_ERROR_VALUE -201),*/ + I2C_ACK_FAIL_ON_ADDRESS = -177, /*(U8500_MAX_ERROR_VALUE -202),*/ + I2C_ACK_FAIL_ON_DATA = -178, /*(U8500_MAX_ERROR_VALUE -203),*/ + I2C_ACK_IN_HS_MODE = -179, /*(U8500_MAX_ERROR_VALUE -204),*/ + I2C_BUS_ERROR_DETECTED_START = -180, /*(U8500_MAX_ERROR_VALUE -205),*/ + I2C_BUS_ERROR_DETECTED_STOP = -181, /*(U8500_MAX_ERROR_VALUE -206),*/ + I2C_OVERFLOW = -182, /*(U8500_MAX_ERROR_VALUE -207)*/ +} t_i2c_error; + +typedef enum +{ + /*Common to all platforms*/ + I2C_NO_EVENT = MASK_BIT0, /* No activity. */ + I2C_TRANSFER_OK_EVENT = MASK_BIT1, /* Transfer operation ended correctly. */ + I2C_CANCEL_EVENT = MASK_BIT2, /* Transfer operation cancelled by the user. */ + I2C_INTERNAL_ERROR_EVENT = MASK_BIT3, /* Internal error happened. */ + I2C_ARBITRATION_LOST_ERROR_EVENT = MASK_BIT4, /* Arbitration Lost happened. */ + + I2C_AF_ERROR_EVENT = MASK_BIT5, /* Acknowledge Failure happened. */ + I2C_BUS_ERROR_EVENT = MASK_BIT6, /* Bus Error happened. */ + I2C_START_EVENT = MASK_BIT7, /* START generated. */ + I2C_INDEX_TX_EVENT = MASK_BIT8, /* Register index byte transmitted. */ + I2C_DATA_TX_EVENT = MASK_BIT9, /* Data byte transmitted. */ + I2C_DATA_RX_EVENT = MASK_BIT10, /* Data byte received. */ + I2C_WAITG_DATA_RX_EVENT = MASK_BIT11, /* Waiting for a data byte. */ + + + I2C_TRANSMIT_FIFO_EMPTY_EVENT = MASK_BIT12, + I2C_TRANSMIT_FIFO_NEARLY_EMPTY_EVENT = MASK_BIT13, + I2C_TRANSMIT_FIFO_FULL_EVENT = MASK_BIT14, + I2C_TRANSMIT_FIFO_OVERRUN_EVENT = MASK_BIT15, + I2C_RECEIVE_FIFO_EMPTY_EVENT = MASK_BIT16, + I2C_RECEIVE_FIFO_NEARLY_FULL_EVENT = MASK_BIT17, + I2C_RECEIVE_FIFO_FULL_EVENT = MASK_BIT18, + I2C_READ_FROM_SLAVE_REQUEST_EVENT = MASK_BIT19, + I2C_READ_FROM_SLAVE_EMPTY_EVENT = MASK_BIT20, + I2C_WRITE_TO_SLAVE_REQUEST_EVENT = MASK_BIT21, + I2C_MASTER_TRANSACTION_DONE_EVENT = MASK_BIT22, + I2C_SLAVE_TRANSACTION_DONE_EVENT = MASK_BIT23, + I2C_ABORT_NACK_ON_ADDRESS_EVENT = MASK_BIT24, + I2C_ABORT_NACK_ON_DATA_EVENT = MASK_BIT25, + I2C_ABORT_ACK_ON_MASTER_CODE_EVENT = MASK_BIT26, + I2C_BUS_ERROR_DETECTED_START_EVENT = MASK_BIT27, + I2C_BUS_ERROR_DETECTED_STOP_EVENT = MASK_BIT28, + I2C_OVERFLOW_EVENT = MASK_BIT29, + I2C_MASTER_TRANSACTION_DONE_WITHOUT_STOP_EVENT = MASK_BIT30 +} t_i2c_event; /* Inform the I2C HCL user about the last occurred event.*/ + + +typedef enum +{ + I2C_NO_INDEX, /* Current transfer is non-indexed */ + I2C_BYTE_INDEX, /* Current transfer uses 8-bit index */ + I2C_HALF_WORD_LITTLE_ENDIAN, /* Current transfer uses 16-bit index + in little endian mode */ + I2C_HALF_WORD_BIG_ENDIAN /* Current transfer uses 16-bit index + in big endian mode */ +}t_i2c_index_format; + +typedef struct { + t_i2c_device_id id; + t_i2c_event type; /* The active event. */ + u32 transfer_data; /* Number of data bytes actually transferred. */ +} t_i2c_active_event; + +typedef t_i2c_device_id t_i2c_irq_status; + +/*----------------------------------------------------------------------------- + Configuration functions +-----------------------------------------------------------------------------*/ + t_i2c_error I2C_Init (t_i2c_device_id id, + t_logical_address address); + + t_i2c_error I2C_SetDeviceConfiguration (t_i2c_device_id id, + t_i2c_device_config *p_device_config); + + t_i2c_error I2C_SetTransferConfiguration (t_i2c_device_id id, + t_i2c_transfer_config *p_transfer_config); + + t_i2c_error I2C_SetTransferMode ( t_i2c_device_id id, + t_i2c_transfer_mode index_transfer_mode, + t_i2c_transfer_mode data_transfer_mode); + + t_i2c_error I2C_SetBusControlMode (t_i2c_device_id id, + t_i2c_bus_control_mode bus_control_mode); + + t_i2c_error I2C_SendCommand ( t_i2c_device_id, + t_i2c_command); + + +/*----------------------------------------------------------------------------- + Configuration functions +-----------------------------------------------------------------------------*/ + t_i2c_error I2C_FlushFifo(t_i2c_device_id , t_i2c_fifo ); + +/*----------------------------------------------------------------------------- + Status functions +-----------------------------------------------------------------------------*/ + t_i2c_error I2C_GetInfo ( t_i2c_device_id id, + t_i2c_info *p_info); +/*----------------------------------------------------------------------------- + Operative functions +-----------------------------------------------------------------------------*/ + t_i2c_error I2C_Enable (t_i2c_device_id id); + + t_i2c_error I2C_Disable (t_i2c_device_id id); + + t_i2c_error I2C_WriteSingleData (t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 data); + + t_i2c_error I2C_WriteMultipleData (t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data, + u32 count); + + t_i2c_error I2C_ReadSingleData (t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data); + + t_i2c_error I2C_ReadMultipleData (t_i2c_device_id id, + u16 slave_address, + t_i2c_index_format index_format, + u16 index_value, + u8 *p_data, + u32 count); + + + t_i2c_error I2C_Cancel ( t_i2c_device_id id, + t_i2c_active_event *event);/*Only IT mode*/ + + + t_bool I2C_IsEventActive ( t_i2c_active_event* event); + + t_bool I2C_AcknowledgeEvent ( t_i2c_active_event* event); + + + t_i2c_error I2C_GetInputClock( t_i2c_device_id id, + u32 *p_fIn); + + t_i2c_error I2C_GetBusClock( t_i2c_device_id id, + u32 *p_fSCL); + + t_i2c_error I2C_GetEnabled( t_i2c_device_id id, + t_bool *p_status); + + t_i2c_error I2C_GetDeviceConfiguration( t_i2c_device_id id, + t_i2c_device_config *p_device_config); + + t_i2c_error I2C_GetTransferConfiguration(t_i2c_device_id id, + t_i2c_transfer_config *p_transfer_config); + + t_i2c_error I2C_GetTransferMode( t_i2c_device_id id, + t_i2c_transfer_mode *p_index_transfer_mode, + t_i2c_transfer_mode *p_data_transfer_mode); + + t_i2c_error I2C_GetBusControlMode( t_i2c_device_id id, + t_i2c_current_bus_configuration + *p_i2c_current_transfer_mode, + t_i2c_bus_control_mode *p_bus_control_mode); + + +/*----------------------------------------------------------------------------- + Power Management functions +-----------------------------------------------------------------------------*/ + t_i2c_error I2C_Reset(t_i2c_device_id id); + + void I2C_SaveDeviceContext (t_i2c_device_id id); + + void I2C_RestoreDeviceContext(t_i2c_device_id id); + + +/* Start of _I2CP_H_*/ + +/*Peripheral ID s */ + +#define I2C_P_ID_0 0x24 +#define I2C_P_ID_1 0x00 +#define I2C_P_ID_2 0x38 +#define I2C_P_ID_3 0x00 +#define I2C_CELL_ID_0 0x0D +#define I2C_CELL_ID_1 0xF0 +#define I2C_CELL_ID_2 0x05 +#define I2C_CELL_ID_3 0xB1 + +/*----------------------------------------------------------------------------- + + Constants + +-----------------------------------------------------------------------------*/ +typedef enum { + I2C_NO_OPERATION = 0xFF, + I2C_WRITE = 0x00, + I2C_READ = 0x01 +} t_i2c_operation; + +/*----------------------------------------------------------------------------- + Typedefs +-----------------------------------------------------------------------------*/ +typedef enum { + I2C_MAX_STANDARD_SCL = 100000, /* Max clock frequency (Hz) for Standard Mode.*/ + I2C_MAX_FAST_SCL = 400000, /* Max clock frequency (Hz) for Fast Mode.*/ + I2C_MAX_HIGH_SPEED_SCL = 3400000 /* Max clock frequency (Hz) for HS Mode.*/ +} I2C_MaxClocks; + +typedef enum { + I2C_DDC1, /* DDC1 mode.*/ + I2C_DDC2B, /* DD2 B mode.*/ + I2C_DDC2AB /* DDC2 AB mode (I2C).*/ +} t_i2c_ddc_mode; + +typedef enum { + I2C_IT_TXFE = MASK_BIT0, /* Tx fifo empty */ + I2C_IT_TXFNE = MASK_BIT1, /* Tx Fifo nearly empty */ + I2C_IT_TXFF = MASK_BIT2, /* Tx Fifo Full */ + I2C_IT_TXOVR = MASK_BIT3, /* Tx Fifo over run */ + I2C_IT_RXFE = MASK_BIT4, /* Rx Fifo Empty */ + I2C_IT_RXFNF = MASK_BIT5, /* Rx Fifo nearly empty */ + I2C_IT_RXFF = MASK_BIT6, /* Rx Fifo Full */ + I2C_IT_RFSR = MASK_BIT16, /* Read From slave request */ + I2C_IT_RFSE = MASK_BIT17, /* Read from slave empty */ + I2C_IT_WTSR = MASK_BIT18, /* Write Slave request */ + I2C_IT_MTD = MASK_BIT19, /* Master Transcation Done */ + I2C_IT_STD = MASK_BIT20, /* Slave Transaction Done */ + I2C_IT_MAL = MASK_BIT24, /* Master Arbitation Lost */ + I2C_IT_BERR = MASK_BIT25, /* Bus Error */ + I2C_IT_MTDWS = MASK_BIT28 /* Master Transcation Done Without Stop */ +}t_i2c_interrupt; /* IRQ source numbers.*/ + + +typedef enum { + I2C_NO_REG_INDEX_OP, /* Do not send any register index.*/ + I2C_8_BIT_REG_INDEX_OP, /* Send a 8-bit register index.*/ + I2C_16_BIT_REG_INDEX_OP /* Send a 16-bit register index.*/ +} t_i2c_reg_op; + +typedef u32 t_i2c_device_context[5]; + +typedef struct { + /*Device configuration*/ + t_logical_address base_address; /* The controller's base address.*/ + u32 freq_scl; /* The I2C bus SCL clock frequency (Hz).*/ + u16 own_address; /* The controller's slave address.*/ + t_i2c_device_context i2c_device_context; + t_i2c_digital_filter digital_filter_control; + t_i2c_control dma_sync_logic_control; + t_i2c_control start_byte_procedure; + u8 high_speed_master_code; + u16 slave_data_setup_time; + + /*Transfer configuration*/ + u32 freq_input; /* The controller's input clock frequency (Hz).*/ + t_i2c_freq_mode mode; /* Standard or Fast mode.*/ + t_i2c_operation operation; /* Write or read.*/ + t_i2c_bus_control_mode bus_control_mode; + t_i2c_control i2c_loopback_mode; + t_i2c_general_call_handling general_call_mode_handling; + t_i2c_transfer_mode index_transfer_mode; + t_i2c_transfer_mode data_transfer_mode; + u8 i2c_transmit_interrupt_threshold; + u8 i2c_receive_interrupt_threshold; + u8 transmit_burst_length; + u8 receive_burst_length; + u16 burst_length; + u16 slave_address; /* The slave to talk to.*/ + u16 register_index; /* The index of the slave's registers*/ + t_i2c_index_format index_format; + t_bool multi_operation; + + /*Device Status*/ + t_bool enabled; /* True means controller is enabled.*/ + u32 count_data; /* The number of bytes to be transferred.*/ + u32 transfer_data; /* Number of transferred data bytes.*/ + u8* databuffer; /* Pointer to the data buffer. Used in Multi operation.*/ + t_i2c_current_bus_configuration current_bus_config; + t_i2c_device_status status; /* The controller's status.*/ + u8 data; /* Used in Single operation.*/ + t_i2c_event active_event; /* The current active event.*/ + t_bool std; /*This variable is used to store the STD interrupt */ + /*status for 10 bit slave transmitter case */ + +} t_i2c_system_context; + + +/*----------------------------------------------------------------------------- + + Private service functions + +-----------------------------------------------------------------------------*/ + t_i2c_error i2cp_SetOwnAddress(t_i2c_device_id id, u16 address); + t_i2c_error i2cp_SetBusClock(t_i2c_device_id id, u32 fSCL, u32 fIn); + t_bool i2cp_AddressIsValid(u16 address); + void i2cp_Abort(t_i2c_device_id id); + + t_i2c_error i2cp_SlaveIndexReceive(t_i2c_device_id id ); + t_i2c_error i2cp_TransmitDataPolling (t_i2c_device_id id, volatile u8* p_data); + t_i2c_error i2cp_ReceiveDataPolling(t_i2c_device_id id, u8* p_data ); + t_i2c_error i2cp_MasterIndexTransmit(t_i2c_device_id id ); + + + t_i2c_error i2cp_GetAbortCause(t_i2c_device_id id ); + +/* End of _I2CP_H_*/ + + +typedef enum +{ + + + I2C0_IRQ_SRC_TRANSMIT_FIFO_EMPTY = MASK_BIT0, + I2C0_IRQ_SRC_TRANSMIT_FIFO_NEARLY_EMPTY = MASK_BIT1, + I2C0_IRQ_SRC_TRANSMIT_FIFO_FULL = MASK_BIT2, + I2C0_IRQ_SRC_TRANSMIT_FIFO_OVERRUN = MASK_BIT3, + I2C0_IRQ_SRC_RECEIVE_FIFO_EMPTY = MASK_BIT4, + I2C0_IRQ_SRC_RECEIVE_FIFO_NEARLY_FULL = MASK_BIT5, + I2C0_IRQ_SRC_RECEIVE_FIFO_FULL = MASK_BIT6, + I2C0_IRQ_SRC_READ_FROM_SLAVE_REQUEST = MASK_BIT16, + I2C0_IRQ_SRC_READ_FROM_SLAVE_EMPTY = MASK_BIT17, + I2C0_IRQ_SRC_WRITE_TO_SLAVE_REQUEST = MASK_BIT18, + I2C0_IRQ_SRC_MASTER_TRANSACTION_DONE = MASK_BIT19, + I2C0_IRQ_SRC_SLAVE_TRANSACTION_DONE = MASK_BIT20, + I2C0_IRQ_SRC_MASTER_ARBITRATION_LOST = MASK_BIT24, + I2C0_IRQ_SRC_BUS_ERROR = MASK_BIT25, + I2C0_IRQ_SRC_MASTER_TRANSACTION_DONE_WITHOUT_STOP = MASK_BIT28, + I2C0_IRQ_SRC_ALL = 0x131F007F, + + I2C1_IRQ_SRC_TRANSMIT_FIFO_EMPTY = MASK_BIT29 | MASK_BIT0, + I2C1_IRQ_SRC_TRANSMIT_FIFO_NEARLY_EMPTY = MASK_BIT29 | MASK_BIT1, + I2C1_IRQ_SRC_TRANSMIT_FIFO_FULL = MASK_BIT29 | MASK_BIT2, + I2C1_IRQ_SRC_TRANSMIT_FIFO_OVERRUN = MASK_BIT29 | MASK_BIT3, + I2C1_IRQ_SRC_RECEIVE_FIFO_EMPTY = MASK_BIT29 | MASK_BIT4, + I2C1_IRQ_SRC_RECEIVE_FIFO_NEARLY_FULL = MASK_BIT29 | MASK_BIT5, + I2C1_IRQ_SRC_RECEIVE_FIFO_FULL = MASK_BIT29 | MASK_BIT6, + I2C1_IRQ_SRC_READ_FROM_SLAVE_REQUEST = MASK_BIT29 | MASK_BIT16, + I2C1_IRQ_SRC_READ_FROM_SLAVE_EMPTY = MASK_BIT29 | MASK_BIT17, + I2C1_IRQ_SRC_WRITE_TO_SLAVE_REQUEST = MASK_BIT29 | MASK_BIT18, + I2C1_IRQ_SRC_MASTER_TRANSACTION_DONE = MASK_BIT29 | MASK_BIT19, + I2C1_IRQ_SRC_SLAVE_TRANSACTION_DONE = MASK_BIT29 | MASK_BIT20, + I2C1_IRQ_SRC_MASTER_ARBITRATION_LOST = MASK_BIT29 | MASK_BIT24, + I2C1_IRQ_SRC_BUS_ERROR = MASK_BIT29 | MASK_BIT25, + I2C1_IRQ_SRC_MASTER_TRANSACTION_DONE_WITHOUT_STOP = MASK_BIT29 | MASK_BIT28, + I2C1_IRQ_SRC_ALL = MASK_BIT29 | 0x131F007F, + + + I2C2_IRQ_SRC_TRANSMIT_FIFO_EMPTY = MASK_BIT30 | MASK_BIT0, + I2C2_IRQ_SRC_TRANSMIT_FIFO_NEARLY_EMPTY = MASK_BIT30 | MASK_BIT1, + I2C2_IRQ_SRC_TRANSMIT_FIFO_FULL = MASK_BIT30 | MASK_BIT2, + I2C2_IRQ_SRC_TRANSMIT_FIFO_OVERRUN = MASK_BIT30 | MASK_BIT3, + I2C2_IRQ_SRC_RECEIVE_FIFO_EMPTY = MASK_BIT30 | MASK_BIT4, + I2C2_IRQ_SRC_RECEIVE_FIFO_NEARLY_FULL = MASK_BIT30 | MASK_BIT5, + I2C2_IRQ_SRC_RECEIVE_FIFO_FULL = MASK_BIT30 | MASK_BIT6, + I2C2_IRQ_SRC_READ_FROM_SLAVE_REQUEST = MASK_BIT30 | MASK_BIT16, + I2C2_IRQ_SRC_READ_FROM_SLAVE_EMPTY = MASK_BIT30 | MASK_BIT17, + I2C2_IRQ_SRC_WRITE_TO_SLAVE_REQUEST = MASK_BIT30 | MASK_BIT18, + I2C2_IRQ_SRC_MASTER_TRANSACTION_DONE = MASK_BIT30 | MASK_BIT19, + I2C2_IRQ_SRC_SLAVE_TRANSACTION_DONE = MASK_BIT30 | MASK_BIT20, + I2C2_IRQ_SRC_MASTER_ARBITRATION_LOST = MASK_BIT30 | MASK_BIT24, + I2C2_IRQ_SRC_BUS_ERROR = MASK_BIT30 | MASK_BIT25, + I2C2_IRQ_SRC_MASTER_TRANSACTION_DONE_WITHOUT_STOP = MASK_BIT30 | MASK_BIT28, + I2C2_IRQ_SRC_ALL = MASK_BIT30 | 0x131F007F, + + + + I2C3_IRQ_SRC_TRANSMIT_FIFO_EMPTY = MASK_BIT30 | MASK_BIT29 | MASK_BIT0, + I2C3_IRQ_SRC_TRANSMIT_FIFO_NEARLY_EMPTY = MASK_BIT30 | MASK_BIT29 | MASK_BIT1, + I2C3_IRQ_SRC_TRANSMIT_FIFO_FULL = MASK_BIT30 | MASK_BIT29 | MASK_BIT2, + I2C3_IRQ_SRC_TRANSMIT_FIFO_OVERRUN = MASK_BIT30 | MASK_BIT29 | MASK_BIT3, + I2C3_IRQ_SRC_RECEIVE_FIFO_EMPTY = MASK_BIT30 | MASK_BIT29 | MASK_BIT4, + I2C3_IRQ_SRC_RECEIVE_FIFO_NEARLY_FULL = MASK_BIT30 | MASK_BIT29 | MASK_BIT5, + I2C3_IRQ_SRC_RECEIVE_FIFO_FULL = MASK_BIT30 | MASK_BIT29 | MASK_BIT6, + I2C3_IRQ_SRC_READ_FROM_SLAVE_REQUEST = MASK_BIT30 | MASK_BIT29 | MASK_BIT16, + I2C3_IRQ_SRC_READ_FROM_SLAVE_EMPTY = MASK_BIT30 | MASK_BIT29 | MASK_BIT17, + I2C3_IRQ_SRC_WRITE_TO_SLAVE_REQUEST = MASK_BIT30 | MASK_BIT29 | MASK_BIT18, + I2C3_IRQ_SRC_MASTER_TRANSACTION_DONE = MASK_BIT30 | MASK_BIT29 | MASK_BIT19, + I2C3_IRQ_SRC_SLAVE_TRANSACTION_DONE = MASK_BIT30 | MASK_BIT29 | MASK_BIT20, + I2C3_IRQ_SRC_MASTER_ARBITRATION_LOST = MASK_BIT30 | MASK_BIT29 | MASK_BIT24, + I2C3_IRQ_SRC_BUS_ERROR = MASK_BIT30 | MASK_BIT29 | MASK_BIT25, + I2C3_IRQ_SRC_MASTER_TRANSACTION_DONE_WITHOUT_STOP = MASK_BIT30 | MASK_BIT29 | MASK_BIT28, + I2C3_IRQ_SRC_ALL = MASK_BIT30 | MASK_BIT29 |0x131F007F + + +} t_i2c_irq_src_id; + + + +/* Macros for handling the device id */ +#define I2CID_SHIFT 29 +#define GETDEVICE(irqsrc) ((t_i2c_device_id)((irqsrc >>I2CID_SHIFT ) & 0x3)) + +/* a macro for masking all interrupts */ +#define I2C_IRQ_SRC_ALL I2C0_IRQ_SRC_ALL + +typedef u32 t_i2c_irq_src; /*Combination of various interrupt sources + described by t_i2c_irq_src_id*/ + +/*----------------------------------------------------------------------------- + Events and interrupts management functions +-----------------------------------------------------------------------------*/ +void I2C_SetBaseAddress (t_i2c_device_id id, t_logical_address address ); +void I2C_DisableIRQSrc (t_i2c_irq_src_id id); +#endif /* _U8500_I2C_H_ */ diff --git a/board/st/u8500/init_mmc.c b/board/st/u8500/init_mmc.c new file mode 100755 index 000000000..02d9f32f7 --- /dev/null +++ b/board/st/u8500/init_mmc.c @@ -0,0 +1,359 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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" +#include "mmc.h" +#include "init_mmc.h" +#include "gpio.h" +#include "mmc_utils.h" +#include "i2c.h" + +#ifdef CONFIG_CMD_FAT +#include <part.h> +#include <fat.h> +#endif + +#define LOOP(x) {int i;for(i=0;i<1000;i++);} +#ifdef CONFIG_CMD_FAT +static block_dev_desc_t mmc_dev; +u32 CSD[4]; +char MMC_CmdBuffer[1024] ; + +extern long do_fat_read (const char *filename, void *buffer, unsigned long maxsize,int dols); + +block_dev_desc_t * mmc_get_dev(int dev) +{ + return (block_dev_desc_t *)(&mmc_dev); +} + +unsigned long mmc_block_read(int dev, unsigned long blknr,lbaint_t blkcnt, + void *dest) +{ + unsigned long i; + unsigned long src= blknr; + unsigned long rc = 0; + + for(i = 0; i < blkcnt; i++) + { + /* card#, read offset, buffer, blocksize, transfer mode */ + mmc_readblock(1, (u32) (512 * src), (u32 *)dest, 512, + MMCPOLLING); + rc++; + src++; + dest += 512; + } + + return rc; +} + +t_mmc_error mmc_fat_read_file (char *filename, u32 address, u32 FileSize) +{ + u8 *mem_address = (u8 *) address; + t_mmc_error mmc_error = MMC_OK; + + if((do_fat_read(filename,mem_address,FileSize,0)) < 0) + { + printf("error in reading %s file\n",filename); + mmc_error = MMC_INVALID_PARAMETER; + } + return mmc_error; +} + +int mmc_hw_init (void) +{ + t_mmc_error response; + + /* save the GPIO0 AFSELA register*/ + gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC"); + /* Power-on the controller*/ + response = mmc_enable (); + + if (response != MMC_OK) + { + response = mmc_enable (); + if (response != MMC_OK) + { + printf ("Error in card power on\n"); + goto end; + } + } + /* Initialise the cards on the bus, if any*/ + response = mmc_initCard (); + if (response != MMC_OK) + { + printf ("Error in card initialization\n"); + goto end; + } + response = mmc_readcsd (CSD); + if (response != MMC_OK) + { + printf ("Error while fetching card info\n"); + goto end; + } + + return 0; + end: + return 1; +} + +/* + * init_mmc_fat - initialise MMC HW and register as FAT device + */ +int init_mmc_fat(void) +{ + unsigned int size; + unsigned int sizemult; + unsigned long num_sects; + unsigned long sect_size; /* in bytes */ + unsigned long mmc_size; + + if(mmc_hw_init()) + { + goto end; + } + /*read block len*/ + sect_size = 1<<((CSD[2] << 12 )>>28); + /*c_size */ + size = ((CSD[2] & 0x3ff)<<2) + (CSD[1]>>30) ; + /*size of multiplier */ + sizemult = (CSD[1] << 14 )>>29; + + num_sects = (size+1)*(1<<(sizemult+2)); + /* memory capcity of the Inserted Card */ + mmc_size = (num_sects * sect_size)/(1024 * 1024); + printf("Memory Card size = %d MiB \n", mmc_size); + printf("sector size is %d, num_sects %d\n", sect_size, num_sects); + + mmc_dev.if_type = IF_TYPE_MMC; + mmc_dev.part_type = PART_TYPE_DOS; + mmc_dev.dev = 0; + mmc_dev.lun = 0; + mmc_dev.type = 0; + mmc_dev.blksz = 512; + mmc_dev.lba = num_sects; /* XXX: assumes 512 blksize */ + sprintf((char*)mmc_dev.vendor, "Unknown vendor"); + sprintf((char*)mmc_dev.product, "Unknown product"); + sprintf((char*)mmc_dev.revision, "N/A"); + mmc_dev.removable = 0; + mmc_dev.block_read = mmc_block_read; + + /* do fat registration with the SD/MMC device*/ + if (fat_register_device(&mmc_dev, 1) != 0) { + printf("could not register as FAT device\n"); + goto end; + } +#if 0 + printf(" Size \t FileName \n"); + do_fat_read("/", NULL, 0, 1); + /* do fat read for the commands to be executed*/ + if (do_fat_read("command.txt", &MMC_CmdBuffer[0], sizeof(MMC_CmdBuffer), 0) + == -1) { + printf(" No command.txt found in the Card\n"); + return (0); + } + setenv("bootcmd", MMC_CmdBuffer); +#endif + return(0); +end: + gpio_altfuncdisable(GPIO_ALT_SD_CARD0, "MMC"); + mmc_disable(); + return 1; +} +#endif /* CONFIG_CMD_FAT */ + +#define I2C_SCL_FREQ 100000 /* I2C bus clock frequency.*/ +#define I2C_INPUT_FREQ 48000000 /* Input clock frequency.*/ +#define I2C0_SLAVE_ADDRESS (0x84 >>1) /*GPIO expander slave address*/ +#define REG_CHIP_ID_INDEX 0x80 +#define HS_MASTER_CODE 0x01 /* High speed Master code */ +#define TX_FIFO_THRESHOLD 0x4 /* The threshold below or equal to which the transmit FIFO generates interrupt */ +#define RX_FIFO_THRESHOLD 0x4 /* The threshold above or equal to which the receive FIFO generates interrupt */ +#define BURST_LENGTH 0 /* The burst length used in the DMA operation */ +#define SLAVE_SETUP_TIME 14 /* Slave data setup time */ + + +void config_extended_gpio(void) +{ + t_i2c_error error_status; + t_i2c_device_config i2c_device_config; + t_i2c_transfer_config i2c_transfer_config; + t_i2c_error error_i2c; + u8 read_data = 0; + u8 dataArr[2]={0x06,0x06}; + + I2C_SetBaseAddress(I2C0, CFG_I2C0_BASE); + error_i2c = I2C_Init(I2C0, CFG_I2C0_BASE); + + i2c_device_config.controller_i2c_address = 0; + i2c_device_config.input_frequency = I2C_INPUT_FREQ; + i2c_device_config.i2c_digital_filter_control = I2C_DIGITAL_FILTERS_OFF; + i2c_device_config.i2c_dma_sync_logic_control = I2C_DISABLE; + i2c_device_config.i2c_start_byte_procedure = I2C_DISABLE; + + i2c_transfer_config.i2c_transfer_frequency = I2C_SCL_FREQ; + i2c_transfer_config.bus_control_mode = I2C_BUS_MASTER_MODE; + + i2c_transfer_config.i2c_transmit_interrupt_threshold = TX_FIFO_THRESHOLD; + i2c_transfer_config.i2c_receive_interrupt_threshold = RX_FIFO_THRESHOLD; + i2c_transfer_config.transmit_burst_length = BURST_LENGTH; + i2c_transfer_config.receive_burst_length = BURST_LENGTH; + i2c_transfer_config.i2c_loopback_mode = I2C_DISABLE; + i2c_transfer_config.index_transfer_mode = I2C_TRANSFER_MODE_POLLING; + i2c_transfer_config.data_transfer_mode = I2C_TRANSFER_MODE_POLLING; + i2c_transfer_config.bus_control_mode = I2C_BUS_MASTER_MODE; + i2c_transfer_config.i2c_slave_general_call_mode = I2C_NO_GENERAL_CALL_HANDLING; + + i2c_device_config.slave_data_setup_time = SLAVE_SETUP_TIME; + + error_status = I2C_SetDeviceConfiguration(I2C0, &i2c_device_config); + if (I2C_OK != error_status) + { + printf("\n Error in I2C_SetDeviceConfiguration; err = %d", error_status); + return; + } + + error_status = I2C_SetTransferConfiguration(I2C0, &i2c_transfer_config); + if (I2C_OK != error_status) + { + printf("\n Error in I2C_SetTransferConfiguration; err = %d", error_status); + return; + } + LOOP(10); + error_status = I2C_ReadSingleData (I2C0, I2C0_SLAVE_ADDRESS, I2C_BYTE_INDEX, 0x80, &read_data); + LOOP(1); + printf("\nGPIO expander Chip ID %x\n", read_data); + + if(error_status){ + printf("\n Error in I2C_ReadSingleData = %d", error_status); + return; + } + if (read_data == 0x01) /*If chip is = 0x1, the platform is MOP500, so config STMPE*/ + { + printf("\nMOP500 platform\n"); + //config_stmpe(); + error_status = I2C_WriteSingleData(I2C0, I2C0_SLAVE_ADDRESS, I2C_BYTE_INDEX, 0x89, 0x0C); + LOOP(5); + error_status = I2C_WriteSingleData(I2C0, I2C0_SLAVE_ADDRESS, I2C_BYTE_INDEX, 0x83, 0x0C); + LOOP(5); + } + else if(read_data==0x03) /* If chip is = 0x3,the platform is HREF, so config Toshiba controller*/ + { + printf("\nHREF platform\n"); + //following code is for HREF + //set the direction of the GPIO KPY9 and KPY10 + error_status = I2C_WriteSingleData(I2C0, I2C0_SLAVE_ADDRESS, I2C_BYTE_INDEX, 0xC8, 0x06); + LOOP(5); + dataArr[0]= 0x06; + dataArr[1]= 0x06; + + error_status = I2C_WriteMultipleData(I2C0, I2C0_SLAVE_ADDRESS, I2C_BYTE_INDEX, 0xC4, dataArr,2); + LOOP(5); + if(error_status) + printf("Error in I2C_WriteMultipleData error = %d",error_status); + + } + else + printf("\nunknown platform: chip ID = %x\n", read_data); + return; + + +} + + +/* ======================================================================== + Achraf + Name: init_mmc_card + Description: init VIC, GPIO and MMC + + ======================================================================== */ +int mmc_legacy_init(int dev) +{ + /*config extended GPIO pins for Level shifter and SDMMC_ENABLE */ + config_extended_gpio(); + + init_mmc(); + +#ifndef CONFIG_CMD_FAT + if (display_file_list("*") == MMC_CMD_RSP_TIMEOUT) + { + printf("MMC card not available on board\n"); + } +#endif + return 0; +} + +/* ======================================================================== + Name: init_mmc + Description: init multimedia card interface + + ======================================================================== */ +static int init_mmc(void) +{ + t_mmc_error mmc_error; + struct gpio_register * gpio_base_address; + + /* Initialize the base address of MMC-SD */ + mmc_error = mmc_init (0,CFG_MMC_BASE); + + if (MMC_OK != mmc_error) + { + printf("mmc_init():: %d \n", mmc_error); + return 1 ; + } + + gpio_base_address = (void *) IO_ADDRESS(CFG_GPIO_0_BASE); + gpio_base_address -> gpio_dats |= 0x1FFC0000; + gpio_base_address -> gpio_pdis &= ~0x1FFC0000; + +#ifdef CONFIG_CMD_FAT +#if 0 + if(init_mmc_fat()) + { + printf(" MMC Card not found \n"); + } +#endif + if (mmc_hw_init() != 0) { + printf("mmc_init: hw init failed\n"); + } + mmc_dev.if_type = IF_TYPE_MMC; + mmc_dev.part_type = PART_TYPE_DOS; + mmc_dev.dev = 0; + mmc_dev.lun = 0; + mmc_dev.type = 0; + mmc_dev.blksz = 512; + mmc_dev.lba = 0x20000; /* XXX: use real size, here 64 MB */ + sprintf((char*)mmc_dev.vendor, "Unknown vendor"); + sprintf((char*)mmc_dev.product, "Unknown product"); + sprintf((char*)mmc_dev.revision, "N/A"); + mmc_dev.removable = 0; + mmc_dev.block_read = mmc_block_read; + if (fat_register_device(&mmc_dev, 1) != 0) { + printf("mmc_init: could not register as FAT device\n"); + } +#endif /* CONFIG_CMD_FAT */ + + return 0; +} + + +/* ------------------------------- End of file ---------------------------- */ diff --git a/board/st/u8500/init_mmc.h b/board/st/u8500/init_mmc.h new file mode 100755 index 000000000..24ec9e689 --- /dev/null +++ b/board/st/u8500/init_mmc.h @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +#ifndef __INIT_MMC_H +#define __INIT_MMC_H +#define PUBLIC /* Extern by default */ + +#include <common.h> + +typedef void (*t_callback_fct) (u32); +typedef struct +{ + t_callback_fct fct; + u32 param; +} t_callback; + +static int init_mmc(void); +int init_mmc_fat(void); +t_mmc_error mmc_fat_read_file (char *, u32, u32); +int mmc_hw_init (void); +unsigned long mmc_block_read(int dev,unsigned long blknr,lbaint_t blkcnt,void *dest); + + +#endif /* !defined(__INIT_MMC_H) */ diff --git a/board/st/u8500/mmc.c b/board/st/u8500/mmc.c new file mode 100755 index 000000000..e80f8315f --- /dev/null +++ b/board/st/u8500/mmc.c @@ -0,0 +1,2580 @@ +/* +* (C) Copyright 2009 +* STEricsson, <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 +*/ +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include <configs/u8500.h> +#include "common.h" +#include "mmc.h" +#include "mmc_p.h" + +#define MAX_NUM_CARDS 5 +t_mmc_register *t_mmc0; /* Removed so it can be used in mmc_utils.c, by Chris S. */ +t_mmc_register *t_mmc4; +t_mmc_register *t_mmc[MAX_NUM_CARDS]; +u32 t_mmc_rel_addr = 0x00010000; +u32 emmc_rel_addr = 0x00100000; +u8 no_of_cards = 0; +u8 mmc_card = 0, sd_card = 0; +u32 clockfreq; +t_mmc_card_info card_array[30]; +t_mmc_device_mode device_mode = POLLING_MODE; +u32 *source_buffer; +u32 *dest_buffer; +u16 total_no_of_bytes = 0; +u8 selected_card = 0; +t_mmc_error transfer_error = MMC_CMD_CRC_FAIL; +u32 pwddata[8]; +t_mmc_event mmc_event; // For event management +u32 write_freq = 0; + +/* Private Functions*/ +t_mmc_error mmc_cmderror(u8); +t_mmc_error mmc_cmdresp145error(u8, u8); +t_mmc_error mmc_cmdresp2error(u8); +t_mmc_error mmc_cmdresp3error(u8); +t_mmc_error mmc_cmdresp6error(u8, u16 *, u8); +t_mmc_error mmc_cmdresp7error(u8); +t_mmc_error mmc_findblocklen(u16 nobytes, u8 * power); +t_mmc_error mmc_sendstatus(u8, u32 *); +t_mmc_error mmc_iscardprogramming(u8, u8 *); + +/****************************************************************************/ +/* NAME : mmc_init() */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine initializes the MMC registers, checks */ +/* Peripheral and PCell Id and clears all interrupts. */ +/* PARAMETERS : */ +/* IN : t_logical_address MMCBaseAddress:MMC registers base address */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error : MMC error code */ +/****************************************************************************/ + +t_mmc_error mmc_init(u8 card_num, t_logical_address MMCBaseAddress) +{ + t_mmc_error error; + if (card_num == 0) + t_mmc0 = (t_mmc_register *) MMCBaseAddress; + else if (card_num == 4) + t_mmc[card_num] = (t_mmc_register *) MMCBaseAddress; + error = MMC_OK; + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_setpowerstate() */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets the power status of the controller. */ +/* */ +/* PARAMETERS : */ +/* IN : t_mmc_Power_state Power state to set */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error : MMC error code */ +/****************************************************************************/ +t_mmc_error mmc_setpowerstate(t_mmc_power_state MMCPowerState) +{ + t_mmc_error error; + + MMC_SET_CTRL(t_mmc0->mmc_Power, MMCPowerState); + error = MMC_OK; + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_getpowerstate() */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine returns the power status of the controller. */ +/* */ +/* PARAMETERS : */ +/* IN : t_mmc_Power_state Power state to set */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error : MMC error code */ +/****************************************************************************/ + +t_mmc_power_state mmc_getpowerstate() +{ + t_mmc_power_state state; + state = MMC_READ_BITS(t_mmc0->mmc_Power, MMC_Power_MASK_CTRL, sbMMC_Power_CTRL); + return (state); +} + +/*****************************************************************************/ +/* NAME : mmc_setoperatingvoltage */ +/*-------------------------------------------------------------------------- */ +/* DESCRIPTION: This routine sets the operating voltage range of . */ +/* the controller */ +/* PARAMETERS : */ +/* IN : u8 The encoded value of the output voltage range to set.*/ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error : MMC error code */ +/*****************************************************************************/ + +t_mmc_error mmc_setoperatingvoltage(u8 value) +{ + t_mmc_error error; + if (value < 16) + { + MMC_SET_VOLT(t_mmc0->mmc_Power, value); + error = MMC_OK; + } + else + error = MMC_INVALID_PARAMETER; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_getoperatingvoltage */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine returns the encoded value of the current */ +/* operating voltage range */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : u8 The encoded value of the output voltage range to set*/ +/****************************************************************************/ + +u8 mmc_getoperatingvoltage() +{ + u8 voltage; + voltage = + MMC_READ_BITS(t_mmc0->mmc_Power, MMC_Power_MASK_VOLT,sbMMC_Power_VOLT); + return (voltage); +} + +/****************************************************************************/ +/* NAME : mmc_configbus */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine configures the bus in open drain or . */ +/* push-pull mode */ +/* PARAMETERS : */ +/* IN : t_mmc_bus_configuration Bus configuration to set */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_configbus(t_mmc_bus_configuration busconfig) +{ + t_mmc_error error; + MMC_SET_OPEND(t_mmc0->mmc_Power, busconfig.mode); + MMC_SET_ROD(t_mmc0->mmc_Power, busconfig.rodctrl); + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_setclock */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets the clock state as enabled or disabled. */ +/* */ +/* PARAMETERS : */ +/* IN : t_mmc_state clock state to set. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_setclock(t_mmc_state busstate) +{ + t_mmc_error error; + MMC_SET_CENABLE(t_mmc0->mmc_Clock, busstate); + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_configclockcontrol */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets configurations for clock and bus mode. */ +/* */ +/* PARAMETERS : */ +/* IN : t_mmc_Clock_control clock control state to set. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_configclockcontrol(t_mmc_clock_control clockcontrol) +{ + t_mmc_error error; + + MMC_SET_PWRSAVE(t_mmc0->mmc_Clock, clockcontrol.pwrsave); + MMC_SET_BYPASS(t_mmc0->mmc_Clock, clockcontrol.bypass); + MMC_SET_WIDEBUS(t_mmc0->mmc_Clock, clockcontrol.widebus); + error = MMC_OK; + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_setclockfrequency */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets clock frequency for MMCI controller. */ +/* */ +/* PARAMETERS : */ +/* IN : u8 Clock divider value for desired frequency. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ +/* COMMENT: Clock frequency is calculated by this formula: */ +/* MCICLK = MCLK/(2 * [Clock_div +1]) */ + +/****************************************************************************/ + +t_mmc_error mmc_setclockfrequency(u8 clockdiv) +{ + t_mmc_error error; + + MMC_SET_CLKDIV(t_mmc0->mmc_Clock, clockdiv); + error = MMC_OK; + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_sendcommand */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sends command and enable Command path */ +/* state machine. */ +/* PARAMETERS : */ +/* IN : t_mmc_Command_index: Command to send. */ +/* u32: argument to send. */ +/* t_mmc_Command_control: Command control parameters to set. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_sendcommand(t_mmc_command_index commandindex, u32 argument, + t_mmc_command_control commcontrol) +{ + t_mmc_error error; + u32 reg; + + if (commandindex != MMC_NO_CMD) + { + reg = commandindex; + t_mmc0->mmc_Argument = argument; + reg |= (commcontrol.IsRespExpected << 6); + reg |= (commcontrol.IsLongResp << 7); + reg |= (commcontrol.IsInterruptMode << 8); + reg |= (commcontrol.IsPending << 9); + reg |= (commcontrol.cmdpath << 10); + t_mmc0->mmc_Command = reg; + } + + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_getresponse */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine returns command index of last command for */ +/* which response received. */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_Command_index command index of last command */ + +/****************************************************************************/ + +t_mmc_command_index mmc_getcommandresponse() +{ + t_mmc_command_index respcommand; + respcommand = t_mmc0->mmc_RespCommand; + return respcommand; +} + +/****************************************************************************/ +/* NAME : mmc_getresponse */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine returns response received from the card for */ +/* the last command. */ +/* PARAMETERS : */ +/* IN : t_mmc_response_type Expected response type */ +/* u32 * u32 pointer to store response. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_getresponse(t_mmc_response_type resptype, u32 * response) +{ + t_mmc_error error; + if (resptype == MMC_SHORT_RESP) + *response = (t_mmc0->mmc_Response0); + else + { + *response = t_mmc0->mmc_Response0; + *(response + 1) = t_mmc0->mmc_Response1; + *(response + 2) = t_mmc0->mmc_Response2; + *(response + 3) = t_mmc0->mmc_Response3; + } + + error = MMC_OK; + return error; + +} + +/****************************************************************************/ +/* NAME : mmc_setdatapath */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine enables/disables the data path for data transfer.*/ +/* */ +/* PARAMETERS : */ +/* IN : t_mmc_state Specifies the state of the */ +/* data path, whether to enabled or disabled. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_setdatapath(t_mmc_state datapath) +{ + t_mmc_error error; + MMC_SET_DATAPATH(t_mmc0->mmc_DataCtrl, datapath); + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_setdatatimeout */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets the data timeout period in card bus */ +/* clock periods */ +/* PARAMETERS : */ +/* IN : u32 Specifies the timeout value of the data path. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_setdatatimeout(u32 datatimeout) +{ + t_mmc_error error; + t_mmc0->mmc_DataTimer = datatimeout; + error = MMC_OK; + return error; + +} + +/******************************************************************************/ +/* NAME : mmc_setdatalength */ +/*----------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets the data length (in bytes) for the data */ +/* transfer. */ +/* PARAMETERS : */ +/* IN : u16 Specifies the number of data bytes to be transferred.*/ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/******************************************************************************/ + +t_mmc_error mmc_setdatalength(u16 datalength) +{ + t_mmc_error error; + + t_mmc0->mmc_DataLength = datalength; + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_setdatablocklength */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets the data block size (in an encoded fashion)*/ +/* for block data transfer. */ +/* PARAMETERS : */ +/* IN : u8 Specifies the data block size for block transfer. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_setdatablocklength(u8 blocksize) +{ + t_mmc_error error; + if (blocksize <= MAXBSIZEPOWER) + { + MMC_SET_BLOCKSIZE(t_mmc0->mmc_DataCtrl, blocksize); + error = MMC_OK; + } + else + error = MMC_INVALID_PARAMETER; + return error; + +} + +/****************************************************************************/ +/* NAME : mmc_settransferdirection */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: routine sets direction for data transfer, whether */ +/* the transfer is a read or write. */ +/* PARAMETERS : */ +/* IN : t_mmc_transfer_direction the direction for data transfer. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_settransferdirection(t_mmc_transfer_direction transdir) +{ + t_mmc_error error = MMC_OK; + MMC_SET_DATADIR(t_mmc0->mmc_DataCtrl, transdir); + return error; +} + +/***********************************************************************************/ +/* NAME : mmc_settransfertype */ +/*---------------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets whether data transfer is */ +/* in stream mode or block mode. */ +/* PARAMETERS : */ +/* IN : t_mmc_transfer_type Specifies the transfer type for data transfer.*/ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/***********************************************************************************/ + +t_mmc_error mmc_settransfertype(t_mmc_transfer_type transtype) +{ + t_mmc_error error = MMC_OK; + MMC_SET_MODE(t_mmc0->mmc_DataCtrl, transtype); + return error; +} + +/****************************************************************************/ +/* NAME : mmc_handledma */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine enables or disables data transfer through DMA. */ +/* PARAMETERS : */ +/* IN : t_mmc_state Specifies whether to enable/disable DMA for */ +/* data transfer. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_handledma(t_mmc_state dmastate) +{ + t_mmc_error error = MMC_OK; + MMC_SET_DMA(t_mmc0->mmc_DataCtrl, dmastate); + return error; +} + +/****************************************************************************/ +/* NAME : mmc_getdatacounter */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine returns number of data elements (in bytes) */ +/* yet to be transferred. */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : u16 */ + +/****************************************************************************/ + +u16 mmc_getdatacounter() +{ + u16 no_of_elements; + no_of_elements = t_mmc0->mmc_DataCnt; + return no_of_elements; +} + +/****************************************************************************/ +/* NAME : mmc_selectsdcard */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine selects specific SD card. */ +/* PARAMETERS : */ +/* IN : u8 SD card to select. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_selectsdcard(u8 cardno) +{ + t_mmc_error error; + + if (cardno < 16) + { + t_mmc0->mmc_SelectSD = cardno; + error = MMC_OK; + } + else + error = MMC_REQUEST_NOT_APPLICABLE; + + return error; + +} + +/****************************************************************************/ +/* NAME : mmc_Poweron */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine enquires cards about their operating voltage */ +/* and sets optimal value to supply output voltage. Sends out */ +/* of range cards to inactive states. Also configures */ +/* clock controls. */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_poweron(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 response, one_msec, count = 0, delay; + t_bool validvoltage, flag = FALSE; + u32 address_mode = Byte_Mode; + + validvoltage = FALSE; + selected_card = 0; + no_of_cards = 5; + + t_mmc[card_num]->mmc_Power = 0x43; //PowerOn | OpenDrain; + + t_mmc[card_num]->mmc_Clock = 0x41FF; //ClkDivInit| ClkEnable | Hwfc_en;//setting clk freq just less than 400KHz + clockfreq = MCLK / (2 * (ClkDivInit + 1)); + t_mmc[card_num]->mmc_Mask0 &= ~AllInterrupts; + one_msec = 52000 / ((t_mmc[card_num]->mmc_Power & 0xFF) + 2); + + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = (GO_IDLE_STATE & ~RespExpected) | CmdPathEnable; + error = mmc_cmderror(card_num); + if (error != MMC_OK) + return error; + + /* send CMD8 to verify SD card interface operating condition */ + t_mmc[card_num]->mmc_Argument = Check_Pattern; + t_mmc[card_num]->mmc_Command = SD_SEND_IF_COND | RespExpected | CmdPathEnable; + + error = mmc_cmdresp7error(card_num); + /* IF ERROR IS COMMAND TIMEOUT IT IS MMC CARD */ + if (error == MMC_OK) + { + address_mode = Sector_Mode; + } + else + { + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = (GO_IDLE_STATE & ~RespExpected) | CmdPathEnable; + error = mmc_cmderror(card_num); + if (error != MMC_OK) + return error; + } + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = APP_CMD | RespExpected | CmdPathEnable; + + for (delay = 0; delay < (one_msec * 27); delay++) ; + error = mmc_cmdresp145error(APP_CMD, card_num); + + /* IF ERROR IS COMMAND TIMEOUT IT IS MMC CARD */ + if (MMC_OK == error) + { + /*SD CARD */ + /*Send CMD41 SD_APP_APP_OP_COND WITH ARGUMENT 0x00FFC000 */ + printf(" initcard:: Set the SD voltage \n"); + while ((!validvoltage) && (count < 0xFFFF)) + { + if (flag) + { + /*SEND CMD55 APP_CMD with RCA as 0*/ + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = APP_CMD | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(APP_CMD, card_num); + if (error != MMC_OK) + { + return (error); + } + } + + t_mmc[card_num]->mmc_Argument = VoltageWindowSD | address_mode; /* voltage window */ + t_mmc[card_num]->mmc_Command = SD_APP_OP_COND | RespExpected | CmdPathEnable; + + error = mmc_cmdresp3error(card_num); + if (MMC_OK != error) + { + return (error); + } + + response = t_mmc[card_num]->mmc_Response0; + validvoltage = (t_bool) (((response >> 31) == 1) ? 1 : 0); + flag = TRUE; + count++; + } + + if (count >= 0xFFFF) + { + error = MMC_INVALID_VOLTRANGE; + return (error); + } + + if (Sector_Mode == address_mode) + { + printf(" SD high capacity card detected \n"); + } + else + { + printf(" SD card detected \n"); + } + sd_card = 1; + } + else if (MMC_CMD_RSP_TIMEOUT == error) + { + /*Send CMD0 GO_IDLE_STATE*/ + printf(" initcard:: Set the MMC voltage \n"); + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = (GO_IDLE_STATE & ~RespExpected) | CmdPathEnable; + + error = mmc_cmderror(card_num); + if (MMC_OK != error) + { + return (error); + } + address_mode = Byte_Mode; + validvoltage = FALSE; + response = 0; + + /* MMC_CARD */ + while ((!validvoltage) && (count < 0xFFFF)) + { + t_mmc[card_num]->mmc_Argument = 0xc0ff8000; //VoltageWindowMMC | address_mode; + t_mmc[card_num]->mmc_Command = SEND_OP_COND | RespExpected | CmdPathEnable; + + error = mmc_cmdresp3error(card_num); + if (MMC_OK != error) + { + return (error); + } + + for (delay = 0; delay < 1; delay++) ; + + response = t_mmc[card_num]->mmc_Response0; + validvoltage = (t_bool) (((response >> 31) == 1) ? 1 : 0); + count++; + } + + if (count >= 0xFFFF) + { + error = MMC_INVALID_VOLTRANGE; + return (error); + } + + if (response & Sector_Mode) + { + printf(" MMC high capacity card detected \n"); + } + else + { + printf(" EMMC card detected \n"); + } + mmc_card = 1; + error = MMC_OK; + } + return error; +} + +/****************************************************************************/ +/* NAME : mmc_Poweroff */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine turns the supply output voltage off. */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ +t_mmc_error mmc_poweroff(u8 card_num) +{ + t_mmc_error error = MMC_OK; + t_mmc[card_num]->mmc_Power &= ~PowerOn; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_initializeCards */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine initializes all cards. All cards come into */ +/* standby state. */ +/* PARAMETERS : */ +/* IN : */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_initializeCards(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u16 rca = emmc_rel_addr; + t_bool card_initialized = FALSE; + + if ((t_mmc[card_num]->mmc_Power & PowerOn) == 0x00) + { + printf("emmc power failed \n"); + error = MMC_REQUEST_NOT_APPLICABLE; + return error; + } + while (!card_initialized) + { + t_mmc[card_num]->mmc_Argument = 0x00000000; + t_mmc[card_num]->mmc_Command = ALL_SEND_CID | RespExpected | LongResponse | CmdPathEnable; + + error = mmc_cmdresp2error(card_num); + if (MMC_OK != error) + { + return (error); + } + + card_array[card_num].CID[0] = t_mmc[card_num]->mmc_Response3; + card_array[card_num].CID[1] = t_mmc[card_num]->mmc_Response2; + card_array[card_num].CID[2] = t_mmc[card_num]->mmc_Response1; + card_array[card_num].CID[3] = t_mmc[card_num]->mmc_Response0; + if (mmc_card == 1) + { + printf("init the MMC Card\n"); + t_mmc[card_num]->mmc_Argument = rca;//rca << 16; + t_mmc[card_num]->mmc_Command = SET_REL_ADDR | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(SET_REL_ADDR, card_num); + if (error != MMC_OK) + { + printf ("emmc card init response for CMD3 error \n"); + return error; + } + } + else if (sd_card == 1) + { + printf("init the SD Card\n"); + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = SET_REL_ADDR | RespExpected | CmdPathEnable; + + error = mmc_cmdresp6error(SET_REL_ADDR, &rca, card_num); + if (error != MMC_OK) + { + printf ("emmc card init response for CMD6 error \n"); + return error; + } + } + card_array[card_num].RCA = rca; + t_mmc[card_num]->mmc_Argument = rca;//(u32) rca << 16; + t_mmc[card_num]->mmc_Command = SEND_CSD | RespExpected | LongResponse | CmdPathEnable; + + error = mmc_cmdresp2error(card_num); + if (error != MMC_OK) + { + printf("emmc card init response for CMD9 error \n"); + return error; + } + card_array[card_num].CSD[0] = t_mmc[card_num]->mmc_Response3; + card_array[card_num].CSD[1] = t_mmc[card_num]->mmc_Response2; + card_array[card_num].CSD[2] = t_mmc[card_num]->mmc_Response1; + card_array[card_num].CSD[3] = t_mmc[card_num]->mmc_Response0; + + //rca++; + error = MMC_OK; //All cards get intialized + card_initialized = TRUE; + /* + t_mmc[card_num]->mmc_Argument = (u32) 0x03B70100; + t_mmc[card_num]->mmc_Command = + APP_SD_SET_BUSWIDTH | RespExpected | LongResponse | CmdPathEnable; + + error = mmc_cmdresp2error(card_num); + if (error != MMC_OK) + { + printf("emmc card init response for CMD6 error \n"); + return error; + } + */ + } + t_mmc[card_num]->mmc_Power = 0x3; /* PUSHPULL mode after intialization */ + t_mmc[card_num]->mmc_Clock = 0x4100; //(t_mmc0->mmc_Clock & 0xFFFFFF00) | 0x00000002; + + return error; + +} + +/****************************************************************************/ +/* NAME : mmc_setdevicemode */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine sets device mode whether to operate in Polling,*/ +/* Interrupt, dma mode. */ +/* PARAMETERS : */ +/* IN : t_mmc_device_mode mode to for further transmission. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_setdevicemode(t_mmc_device_mode mode) +{ + t_mmc_error error; + + switch (mode) + { + case POLLING_MODE: + device_mode = POLLING_MODE; + break; + case INTERRUPT_MODE: + device_mode = INTERRUPT_MODE; + break; + case DMA_MODE: + device_mode = DMA_MODE; + break; + default: + error = MMC_INVALID_PARAMETER; + return error; + } + + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_readbytes */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine allows to read bytes from specified address */ +/* in a card */ +/* PARAMETERS : */ +/* IN : u8 cardno: card to access */ +/* u32 addr : address from where to start reading */ +/* u16 no_of_bytes: no. of bytes to read */ +/* OUT : u32* readbuff: buffer to store data */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_readbytes(u8 card_num, u32 addr, u32 * readbuff,u16 no_of_bytes) +{ + t_mmc_error error = MMC_OK; + u32 i; + u32 timeout = 0; + u32 *tempbuff = readbuff; + + total_no_of_bytes = 0; + + t_mmc0->mmc_DataCtrl = AllZero; + + if ((card_num > no_of_cards) || (card_num == 0)) + { + error = MMC_INVALID_PARAMETER; + return error; + } + + /* send command for selecting the card */ + if (card_num != selected_card) + { + t_mmc0->mmc_Argument = card_array[card_num].RCA;//card_array[card_num - 1].RCA << 16; + t_mmc0->mmc_Command = SEL_DESEL_CARD | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_REL_ADDR, card_num); + if (error != MMC_OK) + return error; + else + selected_card = card_num; + } + + /* now depending on parameter no_of_bytes, send command READ_DAT_UNTIL_STOP */ + + if (no_of_bytes == 0) // this means open-ended stream read,until STOP_TRANSMISSION follows + { + if (device_mode != INTERRUPT_MODE) + return MMC_REQUEST_NOT_APPLICABLE; + + total_no_of_bytes = 65532; + + t_mmc0->mmc_DataLength = 65532; + + t_mmc0->mmc_DataTimer = 0xefffffff; + + t_mmc0->mmc_DataCtrl = ReadDir | StreamMode | DataPathEnable; + + dest_buffer = readbuff; + + t_mmc0->mmc_Clock = (t_mmc0->mmc_Clock & 0xFFFFFF00) | 0x0000000B; + + t_mmc0->mmc_Argument = addr >> 9; + t_mmc0->mmc_Command = READ_DAT_UNTIL_STOP | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(READ_DAT_UNTIL_STOP, card_num); + if (error != MMC_OK) + return error; + + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | RxFifoHalfFull | RxOverrun; + } + else if (no_of_bytes > 0) + { + total_no_of_bytes = no_of_bytes; + + t_mmc0->mmc_DataLength = no_of_bytes; + + t_mmc0->mmc_DataTimer = 0xefffffff; + + t_mmc0->mmc_DataCtrl = ReadDir | StreamMode | DataPathEnable; + + dest_buffer = readbuff; + + t_mmc0->mmc_Clock = (t_mmc0->mmc_Clock & 0xFFFFFF00) | 0x0000000B; + + t_mmc0->mmc_Argument = addr >> 9; + t_mmc0->mmc_Command = READ_DAT_UNTIL_STOP | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(READ_DAT_UNTIL_STOP, card_num); + + if (error != MMC_OK) + return error; + + if (device_mode == POLLING_MODE) + { + + timeout = 0xffffffff; + + while ((timeout > 0) && !(t_mmc0->mmc_Status & (DataCrcFail | DataTimeOut | DataEnd))) + { + timeout--; + if (t_mmc0->mmc_Status & RxFifoHalfFull) + { + for (i = 0; i < 8; i++) + *(tempbuff + i) = t_mmc0->mmc_Fifo; + tempbuff += 8; + } + + } + + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + error = MMC_DATA_TIMEOUT; + transfer_error = MMC_DATA_TIMEOUT; + return error; + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + error = MMC_DATA_CRC_FAIL; + transfer_error = MMC_DATA_CRC_FAIL; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + while (t_mmc0->mmc_Status & RxDataAvlbl) + { + *tempbuff = t_mmc0->mmc_Fifo; + tempbuff++; + } + + t_mmc0->mmc_Argument = 0x00000000; + t_mmc0->mmc_Command = STOP_TRANSMISSION | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(STOP_TRANSMISSION, card_num); + + transfer_error = error; + if (error != MMC_OK) + return error; + + } + + else if (device_mode == INTERRUPT_MODE) + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxFifoHalfFull | RxOverrun; + + else if (device_mode == DMA_MODE) + { + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxOverrun; + t_mmc0->mmc_DataCtrl |= DMAEnab; + } + } + return error; +} + +/****************************************************************************/ +/* NAME : mmc_writebytes */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine allows to write bytes starting from a specified*/ +/* address in a card */ +/* PARAMETERS : */ +/* IN : u8 cardno: card to access */ +/* u32 addr : address where to start writing */ +/* u16 no_of_bytes: no. of bytes to write */ +/* OUT : u32* writebuff: source buffer */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_writebytes(u8 card_num, u32 addr, u32 * writebuff, u16 no_of_bytes) +{ + t_mmc_error error; + u32 timeout = 0; + u32 *tempbuff = writebuff; + u32 i, j, bytes_transferred = 0; + u8 cardstate; + + total_no_of_bytes = 0; + + t_mmc0->mmc_DataCtrl = AllZero; + + if ((card_num > no_of_cards) || (card_num == 0)) + { + error = MMC_INVALID_PARAMETER; + return error; + } + /* send command for selecting the card */ + + if (card_num != selected_card) + { + t_mmc0->mmc_Argument = card_array[card_num].RCA;//card_array[card_num - 1].RCA << 16; + t_mmc0->mmc_Command = SEL_DESEL_CARD | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SEL_DESEL_CARD, card_num); + + if (error != MMC_OK) + return error; + else + selected_card = card_num; + } + + /* now depending on parameter no_of_bytes, send command WRITE_DAT_UNTIL_STOP */ + + if (no_of_bytes == 0) // this means open-ended stream read,until STOP_TRANSMISSION follows + { + if (device_mode != INTERRUPT_MODE) + return MMC_REQUEST_NOT_APPLICABLE; + + t_mmc0->mmc_DataTimer = 0xefffffff; + + total_no_of_bytes = 65532; + + t_mmc0->mmc_DataLength = 65532; + + source_buffer = writebuff; + + t_mmc0->mmc_Clock = (t_mmc0->mmc_Clock & 0xFFFFFF00) | 0x00000031; + + t_mmc0->mmc_Argument = addr >> 9; + t_mmc0->mmc_Command = WRITE_DAT_UNTIL_STOP | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(WRITE_DAT_UNTIL_STOP, card_num); + + if (error != MMC_OK) + return error; + + t_mmc0->mmc_DataCtrl = (StreamMode & ~ReadDir) | DataPathEnable; + + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | TxFifoHalfEmpty | TxUnderrun; + + /*Now the card will send data thru DMA to the destination buffer.CRC/TimeOut error will + be handled in the interrupt handler*/ + } + else if (no_of_bytes > 0) + { + total_no_of_bytes = no_of_bytes; + + t_mmc0->mmc_DataLength = no_of_bytes; + + t_mmc0->mmc_DataTimer = 0xefffffff; + + source_buffer = writebuff; + + t_mmc0->mmc_Argument = addr >> 9; + t_mmc0->mmc_Command = WRITE_DAT_UNTIL_STOP | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(WRITE_DAT_UNTIL_STOP, card_num); + + if (error != MMC_OK) + return error; + + t_mmc0->mmc_DataCtrl = (StreamMode & ~ReadDir) | DataPathEnable; + + if (device_mode == POLLING_MODE) + { + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc0->mmc_Status & (DataCrcFail | DataTimeOut | DataEnd))) + { + timeout--; + if (t_mmc0->mmc_Status & TxFifoHalfEmpty) + { + if ((total_no_of_bytes - bytes_transferred) < 32) + { + j = ((total_no_of_bytes - bytes_transferred) % 4 == 0) ? + ((total_no_of_bytes - bytes_transferred) / 4) + : ((total_no_of_bytes - bytes_transferred) / 4 +1); + + for (i = 0; i < j; i++, tempbuff++,bytes_transferred += 4) + t_mmc0->mmc_Fifo = *tempbuff; + + } + else + { + for (i = 0; i < 8; i++) + t_mmc0->mmc_Fifo = *(tempbuff + i); + tempbuff += 8; + bytes_transferred += 32; + } + } + } + + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + transfer_error = error = MMC_DATA_TIMEOUT; + return error; + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + transfer_error = error = MMC_DATA_CRC_FAIL; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + mmc_iscardprogramming(card_num, &cardstate); + while ((cardstate == 7) || (cardstate == 6)) + mmc_iscardprogramming(card_num, &cardstate); + + t_mmc0->mmc_Argument = 0x00000000; + t_mmc0->mmc_Command = STOP_TRANSMISSION | RespExpected | CmdPathEnable; + + transfer_error = error = mmc_cmdresp145error(STOP_TRANSMISSION, card_num); + + if (error != MMC_OK) + return error; + + } + + else if (device_mode == INTERRUPT_MODE) + + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | TxFifoHalfEmpty | TxUnderrun; + + else if (device_mode == DMA_MODE) + { + t_mmc0->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | TxUnderrun; + t_mmc0->mmc_DataCtrl |= DMAEnab; + } + + } + error = MMC_OK; + return error; +} + +/****************************************************************************/ +/* NAME : mmc_readblocks */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine allows to read blocks from a specified */ +/* address in a card */ +/* PARAMETERS : */ +/* IN : u8 cardno: card to access */ +/* u32 addr : address from where to start reading */ +/* u16 blocksize : size of block in bytes */ +/* u16 no_of_blocks: no. of blocks to read */ +/* OUT : u32* readbuff: source buffer */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_readblocks(u8 card_num, u32 addr, u32 * readbuff, u16 blocksize, u16 no_of_blocks) +{ + t_mmc_error error = MMC_OK; + u32 i; + u32 timeout = 0; + u8 power; + u32 *tempbuff = readbuff; + + total_no_of_bytes = 0; + + t_mmc[card_num]->mmc_DataCtrl = AllZero; + + /* send command for selecting the card */ + if ((card_num > no_of_cards) || (card_num == 0)) + { + error = MMC_INVALID_PARAMETER; + return error; + } + if (card_num != selected_card) + { + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA;//0x1 << 16; //card_array[cardno - 1].RCA << 16; + t_mmc[card_num]->mmc_Command = SEL_DESEL_CARD | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SEL_DESEL_CARD, card_num); + + if (error != MMC_OK) + { + printf("SEL_DESEL_CARD ::error=0x%x \n", error); + return error; + } + else + selected_card = card_num; + } + + if (t_mmc[card_num]->mmc_Response0 & 0x02000000) + return MMC_LOCK_UNLOCK_FAILED; + + /* now depending on parameter no_of_blocks, send command READ_DAT_UNTIL_STOP */ + + //set the block size,both on controller and card + + if ((blocksize > 0) && (blocksize <= 2048) && ((blocksize & (blocksize - 1)) == 0)) + { + + power = convert_from_bytes_to_power_of_two(blocksize); + t_mmc[card_num]->mmc_DataCtrl = power << 4; + + t_mmc[card_num]->mmc_Argument = (u32) blocksize; + t_mmc[card_num]->mmc_Command = SET_BLOCKLEN | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCKLEN, card_num); + + if (error != MMC_OK) + { + printf("SET_BLOCKLEN ::error=0x%x \n", error); + return error; + } + } + else + { + printf("SET_BLOCKLEN ::error set proper block len\n"); + error = MMC_INVALID_PARAMETER; + return error; + } + + if (no_of_blocks == 0) // this means open-ended block read,until STOP_TRANSMISSION follows + { + + if (device_mode != INTERRUPT_MODE) + return MMC_REQUEST_NOT_APPLICABLE; + + t_mmc[card_num]->mmc_DataTimer = 0xefffffff; + + t_mmc[card_num]->mmc_DataLength = (65535 / blocksize) * blocksize; + + total_no_of_bytes = (65535 / blocksize) * blocksize; + + t_mmc[card_num]->mmc_Argument = (65535 / blocksize); + t_mmc[card_num]->mmc_Command = SET_BLOCK_COUNT | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCK_COUNT, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_DataCtrl |= (ReadDir & ~StreamMode) | DataPathEnable; + + dest_buffer = readbuff; + + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = READ_MULT_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(READ_MULT_BLOCK, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | RxFifoHalfFull | RxOverrun; + + /*Now the card will send data thru DMA to the destination buffer.CRC/TimeOut error will + be handled in the interrupt handler*/ + + } + else if (no_of_blocks == 1) + { + total_no_of_bytes = blocksize; + + t_mmc[card_num]->mmc_DataLength = blocksize; + + t_mmc[card_num]->mmc_DataTimer = 0x0fffffff; + + t_mmc[card_num]->mmc_DataCtrl |= (ReadDir & ~StreamMode) | DataPathEnable; + + dest_buffer = readbuff; + + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = READ_SINGLE_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(READ_SINGLE_BLOCK, card_num); + + if (error != MMC_OK) + { + printf("READ_SINGLE_BLOCK ::error=0x%x \n", error); + return error; + } + if (device_mode == POLLING_MODE) + { + + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc[card_num]->mmc_Status & (RxOverrun | DataCrcFail | + DataTimeOut | DataBlockEnd))) + { + timeout--; + if (t_mmc[card_num]->mmc_Status & RxFifoHalfFull) + { + for (i = 0; i < 8; i++) + { + *(tempbuff + i) = t_mmc[card_num]->mmc_Fifo; + } + tempbuff += 8; + } + + } + + if ((timeout == 0)|| (t_mmc[card_num]->mmc_Status & DataTimeOut)) + { + t_mmc[card_num]->mmc_Clear |= DataTimeOut; + transfer_error = error = MMC_DATA_TIMEOUT; + printf("mmc_readblocks::1 MMC_DATA_TIMEOUT \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & DataCrcFail) + { + t_mmc[card_num]->mmc_Clear |= DataCrcFail; + transfer_error = error = MMC_DATA_CRC_FAIL; + printf("mmc_readblocks::1 MMC_DATA_CRC_FAIL \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & RxOverrun) + { + t_mmc[card_num]->mmc_Clear |= RxOverrun; + transfer_error = error = MMC_RX_OVERRUN; + printf("mmc_readblocks::1 MMC_RX_OVERRUN \n"); + return error; + } + + while (t_mmc[card_num]->mmc_Status & RxDataAvlbl) + { + *tempbuff = t_mmc[card_num]->mmc_Fifo; + tempbuff++; + } + transfer_error = error; + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; //clear all the static status flags + } + + else if (device_mode == INTERRUPT_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxFifoHalfFull | RxOverrun; + } + else if (device_mode == DMA_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxOverrun; + t_mmc[card_num]->mmc_DataCtrl |= DMAEnab; + } + + } + else if (no_of_blocks > 1) + { + // set the block count,both for the controller and the card + total_no_of_bytes = no_of_blocks * blocksize; + + t_mmc[card_num]->mmc_DataLength = no_of_blocks * blocksize; + + t_mmc[card_num]->mmc_Argument = (u32) no_of_blocks; + t_mmc[card_num]->mmc_Command = SET_BLOCK_COUNT | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCK_COUNT, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_DataTimer = 0xefffffff; + + t_mmc[card_num]->mmc_DataCtrl |= (ReadDir & ~StreamMode) | DataPathEnable; + + dest_buffer = readbuff; + + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = READ_MULT_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(READ_MULT_BLOCK, card_num); + if (error != MMC_OK) + return error; + + if (device_mode == POLLING_MODE) + { + timeout = 0xefffffff; + while ((timeout > 0)&& !(t_mmc[card_num]->mmc_Status & (RxOverrun | DataCrcFail |DataTimeOut | DataEnd))) + { + timeout--; + if (t_mmc[card_num]->mmc_Status & RxFifoHalfFull) + { + for (i = 0; i < 8; i++) + { + *(tempbuff + i) = t_mmc[card_num]->mmc_Fifo; + } + tempbuff += 8; + } + } + + if ((timeout == 0) || (t_mmc[card_num]->mmc_Status & DataTimeOut)) + { + t_mmc[card_num]->mmc_Clear |= DataTimeOut; + transfer_error = error = MMC_DATA_TIMEOUT; + return error; + + } + else if (t_mmc[card_num]->mmc_Status & DataCrcFail) + { + t_mmc[card_num]->mmc_Clear |= DataCrcFail; + transfer_error = error = MMC_DATA_CRC_FAIL; + return error; + } + else if (t_mmc[card_num]->mmc_Status & RxOverrun) + { + t_mmc[card_num]->mmc_Clear |= RxOverrun; + transfer_error = error = MMC_RX_OVERRUN; + return error; + } + + while (t_mmc[card_num]->mmc_Status & RxDataAvlbl) + { + *tempbuff = t_mmc[card_num]->mmc_Fifo; + tempbuff++; + } + transfer_error = error; + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; //clear all the static status flags + } + + else if (device_mode == INTERRUPT_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxFifoHalfFull | RxOverrun; + } + else if (device_mode == DMA_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | RxOverrun; + t_mmc[card_num]->mmc_DataCtrl |= DMAEnab; + } + } + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_writeblocks */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine allows to write blocks starting from a */ +/* specified address in a card */ +/* PARAMETERS : */ +/* IN : u8 cardno: card to access */ +/* u32 addr : address from where to start writing */ +/* u16 blocksize : size of block in bytes */ +/* u16 no_of_blocks: no. of blocks to write */ +/* OUT : u32* writebuff: source buffer */ +/* */ +/* RETURN : t_mmc_error */ +/****************************************************************************/ + +t_mmc_error mmc_writeblocks(u8 card_num, u32 addr, u32 * writebuff, + u16 blocksize, u16 no_of_blocks) +{ + t_mmc_error error = MMC_OK; + u32 count, rest_words; + u8 power, cardstate; + u32 timeout = 0; + u32 *tempbuff = writebuff; + u32 bytes_transferred = 0; + u32 card_status; + + if (NULL == writebuff) + { + error = MMC_INVALID_PARAMETER; + return (error); + } + + total_no_of_bytes = 0; + + t_mmc[card_num]->mmc_DataCtrl = AllZero; + + /* send command for selecting the card */ + if ((card_num > no_of_cards) || (card_num == 0)) + { + error = MMC_INVALID_PARAMETER; + return error; + } + if (card_num != selected_card) + { + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA; //card_array[cardno - 1].RCA << 16; + t_mmc[card_num]->mmc_Command = SEL_DESEL_CARD | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SEL_DESEL_CARD, card_num); + + if (error != MMC_OK) + return error; + else + selected_card = card_num; + } + + if (t_mmc[card_num]->mmc_Response0 & R1_CARD_IS_LOCKED) + return MMC_LOCK_UNLOCK_FAILED; + + /* now depending on parameter no_of_blocks, send command READ_DAT_UNTIL_STOP */ + + //set the block size,both on controller and card + + if ((blocksize > 0) && (blocksize <= 2048) + && (((blocksize & (blocksize - 1)) == 0))) + { + power = convert_from_bytes_to_power_of_two(blocksize); + t_mmc[card_num]->mmc_DataCtrl = power << 4; + + t_mmc[card_num]->mmc_Argument = (u32) blocksize; + t_mmc[card_num]->mmc_Command = SET_BLOCKLEN | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCKLEN, card_num); + + if (error != MMC_OK) + return error; + + } + else + { + printf(" mmc_writeblocks::bad block size \n"); + error = MMC_INVALID_PARAMETER; + return error; + } + + if (no_of_blocks == 0) // this means open-ended block read,until STOP_TRANSMISSION follows + { + if (device_mode != INTERRUPT_MODE) + return MMC_REQUEST_NOT_APPLICABLE; + + t_mmc[card_num]->mmc_DataTimer = 0xefffffff; + + t_mmc[card_num]->mmc_DataLength = (65535 / blocksize) * blocksize; + + total_no_of_bytes = (65535 / blocksize) * blocksize; + + t_mmc[card_num]->mmc_Argument = (65535 / blocksize); + t_mmc[card_num]->mmc_Command = SET_BLOCK_COUNT | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCK_COUNT, card_num); + + if (error != MMC_OK) + return error; + + source_buffer = writebuff; + + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = WRITE_MULT_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(WRITE_MULT_BLOCK, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_DataCtrl |= DataPathEnable & ~(ReadDir | StreamMode); + + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | TxFifoHalfEmpty | TxUnderrun; + + /*Now the card will send data thru DMA to the destination buffer.CRC/TimeOut error will + be handled in the interrupt handler*/ + + } + else if (no_of_blocks == 1) + { + total_no_of_bytes = blocksize; + + t_mmc[card_num]->mmc_DataLength = blocksize; + + t_mmc[card_num]->mmc_DataTimer = 0xefffffff; + + source_buffer = writebuff; + + /*Wait till card is ready for data Added*/ + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA; //card_array[cardno - 1].RCA << 16; + t_mmc[card_num]->mmc_Command = SEND_STATUS | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(SEND_STATUS, card_num); + + if (error != MMC_OK) + return error; + + card_status = t_mmc[card_num]->mmc_Response0; + timeout = 0xefffffff; + + while ((0 == (card_status & 0x00000100)) && (timeout > 0)) + { + timeout--; + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA;//0x1 << 16; + t_mmc[card_num]->mmc_Command = SEND_STATUS | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SEND_STATUS, card_num); + + if (error != MMC_OK) + return error; + card_status = t_mmc[card_num]->mmc_Response0; + } + if (timeout == 0) + { + return (MMC_DATA_TIMEOUT); + } + + /*Till here*/ + /*SEND CMD24 WRITE_SINGLE_BLOCK */ + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = WRITE_SINGLE_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(WRITE_SINGLE_BLOCK, card_num); + if (error != MMC_OK) + return error; + t_mmc[card_num]->mmc_DataCtrl |= DataPathEnable & ~(ReadDir | StreamMode); + + if (device_mode == POLLING_MODE) + { + + while (!(t_mmc[card_num]->mmc_Status & (DataBlockEnd | TxUnderrun | DataCrcFail | DataTimeOut))) + { + + if (t_mmc[card_num]-> mmc_Status & TxFifoHalfEmpty) + { + if ((total_no_of_bytes - bytes_transferred) < 32) + { + rest_words = ((total_no_of_bytes - bytes_transferred) % 4 == 0) ? + ((total_no_of_bytes - bytes_transferred) / 4) + : ((total_no_of_bytes - bytes_transferred) / 4 +1); + + for (count = 0; count < rest_words; count++, tempbuff++, bytes_transferred += 4) + t_mmc[card_num]-> mmc_Fifo = *tempbuff; + + } + else + { + for (count = 0; count < 8; count++) + { + t_mmc[card_num]->mmc_Fifo = *(tempbuff + count); + } + tempbuff += 8; + bytes_transferred += 32; + } + } + } + + if ((timeout == 0) || (t_mmc[card_num]->mmc_Status & DataTimeOut)) + { + t_mmc[card_num]->mmc_Clear |= DataTimeOut; + transfer_error = error = MMC_DATA_TIMEOUT; + printf(" MMC_DATA_TIMEOUT error \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & DataCrcFail) + { + t_mmc[card_num]->mmc_Clear |= DataCrcFail; + transfer_error = error = MMC_DATA_CRC_FAIL; + printf(" MMC_DATA_CRC_FAIL error \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & TxUnderrun) + { + t_mmc[card_num]->mmc_Clear |= TxUnderrun; + transfer_error = error = MMC_TX_UNDERRUN; + printf(" MMC_TX_UNDERRUN underrun error \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & StartBitError) + { + t_mmc[card_num]->mmc_Clear |= StartBitError; + transfer_error = error = MMC_START_BIT_ERR; + printf(" MMC_START_BIT_ERR start bit error \n"); + return error; + } + //clear all the static status flags + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; + transfer_error = error; + + error = mmc_iscardprogramming(card_num, &cardstate); + while (error == MMC_OK && ((cardstate == 7) || (cardstate == 6))) + error = mmc_iscardprogramming(card_num, &cardstate); + } + + else if (device_mode == INTERRUPT_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | TxFifoHalfEmpty | TxUnderrun; + } + else if (device_mode == DMA_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | TxUnderrun; + t_mmc[card_num]->mmc_DataCtrl |= DMAEnab; + } + + } + else if (no_of_blocks > 1) + { + // set the block count,both for the controller and the card + if (no_of_blocks * blocksize > 0x01FFFFFF) + { + error = MMC_INVALID_PARAMETER; + return (error); + } + + total_no_of_bytes = no_of_blocks * blocksize; + + t_mmc[card_num]->mmc_DataLength = (u32) (no_of_blocks * blocksize); + + t_mmc[card_num]->mmc_Argument = (u32) no_of_blocks; + t_mmc[card_num]->mmc_Command = SET_BLOCK_COUNT | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SET_BLOCK_COUNT, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_DataTimer = 0xefffffff; + + source_buffer = writebuff; + + /*SEND CMD25 WRITE_MULT_BLOCK with argument data address*/ + t_mmc[card_num]->mmc_Argument = addr >> 9; + t_mmc[card_num]->mmc_Command = WRITE_MULT_BLOCK | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(WRITE_MULT_BLOCK, card_num); + + if (error != MMC_OK) + return error; + + t_mmc[card_num]->mmc_DataCtrl |= DataPathEnable & ~(ReadDir | StreamMode); + + if (device_mode == POLLING_MODE) + { + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc[card_num]->mmc_Status & (TxUnderrun | DataCrcFail | + DataTimeOut | DataEnd | StartBitError))) + { + timeout--; + if (t_mmc[card_num]-> mmc_Status & TxFifoHalfEmpty) + { + if ((total_no_of_bytes - bytes_transferred) < 32) + { + rest_words = ((total_no_of_bytes - bytes_transferred) % 4 == 0) ? + ((total_no_of_bytes - bytes_transferred) /4) + : ((total_no_of_bytes - bytes_transferred) / 4 +1); + + for (count = 0; count < rest_words; count++, tempbuff++,bytes_transferred += 4) + t_mmc[card_num]-> mmc_Fifo = *tempbuff; + + } + else + { + for (count = 0; count < 8; count++) + { + t_mmc[card_num]-> mmc_Fifo = *(tempbuff + count); + } + tempbuff += 8; + bytes_transferred += 32; + } + } + + } + + if ((timeout == 0) || (t_mmc[card_num]->mmc_Status & DataTimeOut)) + { + t_mmc[card_num]->mmc_Clear |= DataTimeOut; + transfer_error = error = MMC_DATA_TIMEOUT; + printf(" MMC_DATA_TIMEOUT start bit error \n"); + return error; + + } + else if (t_mmc[card_num]->mmc_Status & DataCrcFail) + { + t_mmc[card_num]->mmc_Clear |= DataCrcFail; + transfer_error = error = MMC_DATA_CRC_FAIL; + printf(" MMC_DATA_CRC_FAIL start bit error \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & TxUnderrun) + { + t_mmc[card_num]->mmc_Clear |= TxUnderrun; + transfer_error = error = MMC_TX_UNDERRUN; + printf(" MMC_TX_UNDERRUN start bit error \n"); + return error; + } + else if (t_mmc[card_num]->mmc_Status & StartBitError) + { + t_mmc[card_num]->mmc_Clear |= StartBitError; + transfer_error = error = MMC_START_BIT_ERR; + printf(" MMC_START_BIT_ERR start bit error \n"); + return error; + } + + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; //clear all the static status flags + transfer_error = error; + error = mmc_iscardprogramming(card_num, &cardstate); + while ((MMC_OK == error) && ((cardstate == 7) || (cardstate == 6))) + error = mmc_iscardprogramming(card_num, &cardstate); + } + else if (device_mode == INTERRUPT_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd |TxFifoHalfEmpty | TxUnderrun; + } + else if (device_mode == DMA_MODE) + { + t_mmc[card_num]->mmc_Mask0 = DataCrcFail | DataTimeOut | DataEnd | TxUnderrun; + t_mmc[card_num]->mmc_DataCtrl |= DMAEnab; + } + + } + + return error; +} + +/****************************************************************************/ +/* NAME : mmc_gettransferstate() */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine */ +/* PARAMETERS : */ +/* */ +/* RETURN : t_mmc_transfer_state */ +/****************************************************************************/ + +t_mmc_transfer_state mmc_gettransferstate() +{ + if (t_mmc0->mmc_Status & (TxActive | RxActive)) + return TRANSFER_IN_PROGRESS; + else + return NO_TRANSFER; +} + +/****************************************************************************/ +/* NAME : mmc_erase */ +/*--------------------------------------------------------------------------*/ +/* DESCRIPTION: This routine allows to erase memory area specified for the */ +/* given card. */ +/* PARAMETERS : */ +/* IN : u8 Cardno. to access */ +/* u32 start address for erase. */ +/* u32 Last address for erase. */ +/* OUT : */ +/* */ +/* RETURN : t_mmc_error */ + +/****************************************************************************/ + +t_mmc_error mmc_erase(u8 card_num, u32 StartAddr, u32 EndAddr) +{ + t_mmc_error error; + u32 response; + u8 cardstate; + u32 delay, max_delay; + + if ((card_num > no_of_cards) || (card_num == 0)) + { + printf("mmc_erase:: card no=%d no_of_cards=%d failed \n",card_num, no_of_cards); + error = MMC_INVALID_PARAMETER; + return error; + } + max_delay = 52000 / ((t_mmc[card_num]->mmc_Clock & 0xFF) + 2); + + /* send command for selecting the card */ + + if (card_num != selected_card) + { + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA; //card_array[cardno - 1].RCA << 16; + t_mmc[card_num]->mmc_Command = SEL_DESEL_CARD | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(SEL_DESEL_CARD, card_num); + if (error != MMC_OK) + return error; + else + selected_card = card_num; + } + + if (t_mmc[card_num]->mmc_Response0 & R1_CARD_IS_LOCKED) + { + error = MMC_LOCK_UNLOCK_FAILED; + return (error); + } + + t_mmc[card_num]->mmc_Argument = StartAddr >> 9; + t_mmc[card_num]->mmc_Command = ERASE_GRP_START | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(ERASE_GRP_START, card_num); + if (error != MMC_OK) + { + printf("mmc_erase:: erase start CMD35 failed \n"); + return error; + } + response = t_mmc[card_num]->mmc_Response0; + + if (response & (R1_OUT_OF_RANGE | R1_ERASE_PARAM)) + { + printf("mmc_erase:: erase start CMD35 R1_OUT_OF_RANGE \n"); + error = MMC_BAD_ERASE_PARAM; + return error; + } + + if (response & R1_ERASE_SEQ_ERROR) + { + printf("mmc_erase:: erase start CMD35 R1_ERASE_SEQ_ERROR \n"); + error = MMC_ERASE_SEQ_ERR; + return error; + } + + if (response & (R1_CARD_IS_LOCKED | R1_LOCK_UNLOCK_FAILED)) + { + printf("mmc_erase:: erase start CMD35 R1_CARD_IS_LOCKED \n"); + error = MMC_LOCK_UNLOCK_FAILED; + return error; + } + + t_mmc[card_num]->mmc_Argument = EndAddr >> 9; + t_mmc[card_num]->mmc_Command = ERASE_GRP_END | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(ERASE_GRP_END, card_num); + if (error != MMC_OK) + { + printf("mmc_erase:: erase end CMD36 failed \n"); + return error; + } + response = t_mmc[card_num]->mmc_Response0; + + if (response & (R1_OUT_OF_RANGE | R1_ERASE_PARAM)) + { + printf("mmc_erase:: erase end R1_OUT_OF_RANGE \n"); + error = MMC_BAD_ERASE_PARAM; + return error; + } + + if (response & R1_ERASE_SEQ_ERROR) + { + printf("mmc_erase:: erase end R1_ERASE_SEQ_ERROR \n"); + error = MMC_ERASE_SEQ_ERR; + return error; + } + + if (response & (R1_CARD_IS_LOCKED | R1_LOCK_UNLOCK_FAILED)) + { + printf("mmc_erase:: erase end R1_CARD_IS_LOCKED\n"); + error = MMC_LOCK_UNLOCK_FAILED; + return error; + } + + t_mmc[card_num]->mmc_Argument = 0; + t_mmc[card_num]->mmc_Command = ERASE | RespExpected | CmdPathEnable; + error = mmc_cmdresp145error(ERASE, card_num); + if (error != MMC_OK) + { + printf("mmc_erase:: erase CMD38 failed \n"); + return error; + } + response = t_mmc[card_num]->mmc_Response0; + if (response & R1_ERASE_SEQ_ERROR) + { + printf("mmc_erase:: erase R1_ERASE_SEQ_ERROR \n"); + error = MMC_ERASE_SEQ_ERR; + return error; + } + + if (response & (R1_CARD_IS_LOCKED | R1_LOCK_UNLOCK_FAILED)) + { + printf("mmc_erase:: erase R1_CARD_IS_LOCKED \n"); + error = MMC_LOCK_UNLOCK_FAILED; + return error; + } + + if (response & R1_WP_ERASE_SKIP) + { + printf("mmc_erase:: erase R1_WP_ERASE_SKIP \n"); + error = MMC_WRITE_PROT_VIOLATION; + return error; + } + for (delay = 0; delay < (max_delay * 3); delay++) ; + + mmc_iscardprogramming(card_num, &cardstate); + while ((MMC_OK == error) && ((cardstate == 7) || (cardstate == 6))) + mmc_iscardprogramming(card_num, &cardstate); + + error = MMC_OK; + return error; +} + +t_mmc_error mmc_cmderror(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 timeout; + + timeout = 100000; + while ((timeout > 0) && !(t_mmc[card_num]->mmc_Status & CmdSent)) + timeout--; + + if (timeout == 0) { + error = MMC_CMD_RSP_TIMEOUT; + return error; + } + + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; //clear all the static flags + + return error; +} + +t_mmc_error mmc_cmdresp145error(u8 cmd, u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 100000; + status = t_mmc[card_num]->mmc_Status; + while ((timeout > 0) && !(status & (CmdCrcFail | CmdRespEnd | CmdTimeOut))) + { + timeout--; + status = t_mmc[card_num]->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc[card_num]->mmc_Clear |= CmdTimeOut; + return error; + } + else if (status & CmdCrcFail) + { + error = MMC_CMD_CRC_FAIL; + t_mmc[card_num]->mmc_Clear |= CmdCrcFail; + return error; + } + + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; /*Clear Static flags */ + if (t_mmc[card_num]->mmc_RespCommand != cmd) + { + /* check response received for CMD7*/ + error = MMC_ILLEGAL_CMD; + return error; + } + return error; +} + +t_mmc_error mmc_cmdresp2error(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 100000; + status = t_mmc[card_num]->mmc_Status; + while ((timeout > 0) && !(status & (CmdCrcFail | CmdTimeOut | CmdRespEnd))) + { + timeout--; + status = t_mmc[card_num]->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc[card_num]->mmc_Clear |= CmdTimeOut; + return error; + } + else if (status & CmdCrcFail) + { + error = MMC_CMD_CRC_FAIL; + t_mmc[card_num]->mmc_Clear |= CmdCrcFail; + return error; + } + + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; /*Clear Static flags */ + + return error; +} + +t_mmc_error mmc_cmdresp3error(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 0x100000; + status = t_mmc[card_num]->mmc_Status; + while ((timeout > 0) && !(status & (CmdRespEnd | CmdTimeOut | CmdCrcFail))) + { + timeout--; + status = t_mmc[card_num]->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc[card_num]->mmc_Clear |= CmdTimeOut; + return error; + } + + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; + return error; +} + +t_mmc_error mmc_cmdresp6error(u8 cmd, u16 * p_rca, u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 status; + u32 response_r1; + + status = t_mmc[card_num]->mmc_Status; + while (!(status & (CmdRespEnd | CmdTimeOut | CmdCrcFail))) + { + status = t_mmc[card_num]->mmc_Status; + } + + if (status & CmdTimeOut) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc[card_num]->mmc_Clear |= CmdTimeOut; + return (error); + } + else if (status & CmdCrcFail) + { + error = MMC_CMD_CRC_FAIL; + t_mmc[card_num]->mmc_Clear |= CmdCrcFail; + return (error); + } + + /* CHECK RESPONSE RECEIVED IS OF DESIRED COMMAND */ + if (t_mmc[card_num]->mmc_RespCommand != cmd) + { + error = MMC_ILLEGAL_CMD; + return (error); + } + + /*Clear Static flags*/ + t_mmc[card_num]->mmc_Clear = ClrStaticFlags; + + /* WE HAVE RECEIVED RESPONSE, RETRIEVE IT. */ + response_r1 = t_mmc[card_num]->mmc_Response0; + + if (AllZero == (response_r1 & (R6_GEN_UNKNOWN_ERROR | R6_ILLEGAL_CMD | R6_COM_CRC_FAILED))) + { + *p_rca = (u16) (response_r1 >> 16); + return (error); + } + + if (response_r1 & R6_GEN_UNKNOWN_ERROR) + { + return (MMC_GENERAL_UNKNOWN_ERROR); + } + + if (response_r1 & R6_ILLEGAL_CMD) + { + return (MMC_ILLEGAL_CMD); + } + + if (response_r1 & R6_COM_CRC_FAILED) + { + return (MMC_COM_CRC_FAILED); + } + + return (error); +} + +t_mmc_error mmc_cmdresp7error(u8 card_num) +{ + t_mmc_error error = MMC_OK; + u32 status; + u32 timeout = 10000; + + status = t_mmc[card_num]->mmc_Status; + while (!(status & (CmdCrcFail | CmdRespEnd | CmdTimeOut)) && (timeout > 0)) + { + timeout--; + status = t_mmc[card_num]->mmc_Status; + } + + if ((timeout == 0) || (status & CmdTimeOut)) + { + /* Card is not V2.0 complient or card does not support the set voltage range */ + error = MMC_CMD_RSP_TIMEOUT; + return (error); + } + + if (status & CmdRespEnd) + { + /* Card is V2.0 complient */ + error = MMC_OK; + return (error); + } + + return (error); +} + +t_mmc_error mmc_iscardprogramming(u8 card_num, u8 * status) +{ + t_mmc_error error; + u32 response; + + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA;//0x1 << 16; //RCA + t_mmc[card_num]->mmc_Command = SEND_STATUS | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(SEND_STATUS, card_num); + if (error != MMC_OK) + return error; + + response = t_mmc[card_num]->mmc_Response0; + *status = (response >> 9) & 0x0000000f; + + return error; + +} + +t_mmc_error mmc_sendstatus(u8 cardno, u32 * status) +{ + t_mmc_error error = MMC_OK; + + t_mmc0->mmc_Argument = card_array[cardno].RCA;//card_array[cardno - 1].RCA << 16; //RCA + t_mmc0->mmc_Command = SEND_STATUS | RespExpected | CmdPathEnable; + + error = mmc_cmdresp145error(SEND_STATUS, cardno); + if (error != MMC_OK) + return error; + + *status = t_mmc0->mmc_Response0; + + return error; +} + +t_mmc_error mmc_cmderror_2(void) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 0xefffffff; + status = t_mmc0->mmc_Status; + while ((timeout > 0) && !(status & (CmdSent| CmdCrcFail | CmdTimeOut | CmdRespEnd))) + { + timeout--; + status = t_mmc0->mmc_Status; + } + + if (timeout == 0) + { + printf(" cmd1 timeout error\n"); + error = MMC_CMD_RSP_TIMEOUT; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static flags + + return error; +} + +t_mmc_error mmc_cmdresp2error_2(void) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 0xefffffff; //(u32)((float)(64/(float)clockfreq )/ ((float)(1/(float)MCLK) + 8*(float)(1/(float)PROCESSOR_CLK))); + status = t_mmc0->mmc_Status; + + while ((timeout > 0) && !(status & (CmdCrcFail | CmdTimeOut | CmdRespEnd))) + { + timeout--; + status = t_mmc0->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc0->mmc_Clear |= CmdTimeOut; + return error; + } + if (status & CmdCrcFail) + { + error = MMC_CMD_CRC_FAIL; + t_mmc0->mmc_Clear |= CmdCrcFail; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; /*Clear Static flags */ + + return error; +} + +t_mmc_error mmc_cmdresp3error_2(void) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 0xefffffff; + status = t_mmc0->mmc_Status; + + while ((timeout > 0) && !(status & (CmdRespEnd | CmdTimeOut | CmdCrcFail))) + { + timeout--; + status = t_mmc0->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc0->mmc_Clear |= CmdTimeOut; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; + + return error; +} + +t_mmc_error mmc_cmdresp145error_2(u8 cmd) +{ + t_mmc_error error = MMC_OK; + u32 status, timeout; + + timeout = 0xefffffff; + status = t_mmc0->mmc_Status; + + while ((timeout > 0) && !(status & (CmdCrcFail | CmdRespEnd | CmdTimeOut))) + { + timeout--; + status = t_mmc0->mmc_Status; + } + if ((timeout == 0) || (status & CmdTimeOut)) + { + error = MMC_CMD_RSP_TIMEOUT; + t_mmc0->mmc_Clear |= CmdTimeOut; + return error; + } + else if (status & CmdCrcFail) + { + error = MMC_CMD_CRC_FAIL; + t_mmc0->mmc_Clear |= CmdCrcFail; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; /*Clear Static flags */ + if (t_mmc0->mmc_RespCommand != cmd) + { + /* check response received for CMD7*/ + error = MMC_ILLEGAL_CMD; + return error; + } + + return error; +} + +t_mmc_error mmc_cmdreadresp(u32 * tempbuff) +{ + t_mmc_error error = MMC_OK; + u32 i; + u32 timeout = 0; + + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc0-> mmc_Status & (RxOverrun | DataCrcFail | DataTimeOut |DataBlockEnd))) + { + timeout--; + if (t_mmc0->mmc_Status & RxFifoHalfFull) + { + for (i = 0; i < 8; i++) + { + *(tempbuff + i) = t_mmc0->mmc_Fifo; + } + tempbuff += 8; + } + } + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + return error; + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + error = MMC_DATA_CRC_FAIL; + return error; + } + else if (t_mmc0->mmc_Status & RxOverrun) + { + t_mmc0->mmc_Clear |= RxOverrun; + error = MMC_RX_OVERRUN; + return error; + } + + while (t_mmc0->mmc_Status & RxDataAvlbl) + { + *tempbuff = t_mmc0->mmc_Fifo; + tempbuff++; + } + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + return error; +} + +t_mmc_error mmc_waitcmdreadresp(void) +{ + t_mmc_error error = MMC_OK; + u32 timeout = 0; + + timeout = 0xefffffff; + + while (!(t_mmc0->mmc_Status & (RxOverrun | DataCrcFail | DataTimeOut | DataBlockEnd))) + { + + } + + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + return error; + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + error = MMC_DATA_CRC_FAIL; + return error; + } + else if (t_mmc0->mmc_Status & RxOverrun) + { + t_mmc0->mmc_Clear |= RxOverrun; + error = MMC_RX_OVERRUN; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + return error; +} + +t_mmc_error mmc_iscardprogramming_2(u8 * status) +{ + t_mmc_error error; + u32 response; + t_mmc_command_control commcontrol; + + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand(MMC_SEND_STATUS, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp145error_2(MMC_SEND_STATUS); + + if (error != MMC_OK) + return error; + + response = t_mmc0->mmc_Response0; + *status = (response >> 9) & 0x0000000f; + + return error; +} + +t_mmc_error mmc_cmdwriteresp(u8 cardno, u32 * tempbuff, u16 total_num_of_bytes) +{ + u32 timeout = 0; + t_mmc_error error = MMC_OK; + u32 bytes_transferred = 0; + u32 i, j; + u8 cardstate; + + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc0-> mmc_Status & (DataBlockEnd | TxUnderrun | DataCrcFail | DataTimeOut))) + { + timeout--; + if (t_mmc0->mmc_Status & TxFifoHalfEmpty) + { + if ((total_num_of_bytes - bytes_transferred) < 32) + { + j = ((total_num_of_bytes - bytes_transferred) % 4 ==0) ? + ((total_num_of_bytes - bytes_transferred) / 4) : + ((total_num_of_bytes - bytes_transferred) / 4 + 1); + + for (i = 0; i < j; i++, tempbuff++, bytes_transferred += 4) + t_mmc0->mmc_Fifo = *tempbuff; + } + else + { + for (i = 0; i < 8; i++) + t_mmc0->mmc_Fifo = *(tempbuff + i); + tempbuff += 8; + bytes_transferred += 32; + } + } + } + + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + error = MMC_DATA_TIMEOUT; + printf(" mmc_cmdwriteresp timeout error \n"); + return error; + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + error = MMC_DATA_CRC_FAIL; + printf(" mmc_cmdwriteresp CRC error \n"); + return error; + } + else if (t_mmc0->mmc_Status & TxUnderrun) + { + t_mmc0->mmc_Clear |= TxUnderrun; + error = MMC_TX_UNDERRUN; + printf(" mmc_cmdwriteresp underrun error \n"); + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + error = mmc_iscardprogramming_2(&cardstate); + while (error == MMC_OK && cardstate == 7) + error = mmc_iscardprogramming_2(&cardstate); + + return error; +} + +t_mmc_error mmc_waitcmdwriteresp(u8 cardno, u32 * tempbuff, u16 total_num_of_bytes) +{ + u32 timeout = 0; + t_mmc_error error = MMC_OK; + u8 cardstate; + + timeout = 0xefffffff; + + while ((timeout > 0) && !(t_mmc0-> mmc_Status & (DataBlockEnd | TxUnderrun | DataCrcFail | DataTimeOut))) + { + + } + + if ((timeout == 0) || (t_mmc0->mmc_Status & DataTimeOut)) + { + t_mmc0->mmc_Clear |= DataTimeOut; + error = MMC_DATA_TIMEOUT; + return error; + + } + else if (t_mmc0->mmc_Status & DataCrcFail) + { + t_mmc0->mmc_Clear |= DataCrcFail; + error = MMC_DATA_CRC_FAIL; + return error; + } + else if (t_mmc0->mmc_Status & TxUnderrun) + { + t_mmc0->mmc_Clear |= TxUnderrun; + error = MMC_TX_UNDERRUN; + return error; + } + + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags + + error = mmc_iscardprogramming_2(&cardstate); + while (error == MMC_OK && cardstate == 7) + error = mmc_iscardprogramming_2(&cardstate); + + return error; +} diff --git a/board/st/u8500/mmc.h b/board/st/u8500/mmc.h new file mode 100755 index 000000000..c114ffab8 --- /dev/null +++ b/board/st/u8500/mmc.h @@ -0,0 +1,263 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _MMC_H_ +#define _MMC_H_ + +#include <common.h> +#include "asm-arm/arch-stw8500/mmc.h" + +/*--------------------------------------------------------------------------- + * Enums + *---------------------------------------------------------------------------*/ + +extern char *mmc_error_name[]; + +#define t_mmc_irq_src u32 + +typedef enum { + MMC_CMD_CRC_FAIL_INT = 0x00000001, + MMC_DATA_CRC_FAIL_INT = 0x00000002, + MMC_CMD_TIMEOUT_INT = 0x00000004, + MMC_DATA_TIMEOUT_INT = 0x00000008, + MMC_TX_UNDERRUN_INT = 0x00000010, + MMC_RX_OVERRUN_INT = 0x00000020, + MMC_CMD_RESP_OK_INT = 0x00000040, + MMC_CMD_SENT_INT = 0x00000080, + MMC_DATA_END_INT = 0x00000100, + MMC_DATA_BLOCK_OK_INT = 0x00000400, + MMC_CMD_ACTIVE_INT = 0x00000800, + MMC_TX_ACTIVE_INT = 0x00001000, + MMC_RX_ACTIVE_INT = 0x00002000, + MMC_TX_FIFO_HALF_EMPTY_INT = 0x00004000, + MMC_RX_FIFO_HALF_FULL_INT = 0x00008000, + MMC_TX_FIFO_FULL_INT = 0x00010000, + MMC_RX_FIFO_FULL_INT = 0x00020000, + MMC_TX_FIFO_EMPTY_INT = 0x00040000, + MMC_RX_FIFO_EMPTY_INT = 0x00080000, + MMC_TX_DATA_AVLBL_INT = 0x00100000, + MMC_RX_DATA_AVLBL_INT = 0x00200000, + MMC_ALL_STATIC_IT = 0x000005FF, + MMC_ALL_IT = 0x003FFDFF + +} t_mmc_interrupt; + +typedef enum { + MMC_DISABLE = 0, + MMC_ENABLE +} t_mmc_state; + + +typedef enum { + MMC_POWER_OFF = 0x0, + MMC_POWER_UP = 0x2, + MMC_POWER_ON = 0x3 +} t_mmc_power_state; + +typedef enum { + MMC_PUSH_PULL = 0, + MMC_OPEN_DRAIN +} t_mmc_bus_mode; + +typedef enum { + MMC_GO_IDLE_STATE = 0, + MMC_SEND_OP_COND = 1, + MMC_ALL_SEND_CID = 2, + MMC_SET_REL_ADDR = 3, + MMC_SET_DSR = 4, + MMC_SEL_DESEL_CARD = 7, + MMC_SEND_CSD = 9, + MMC_SEND_CID = 10, + MMC_READ_DAT_UNTIL_STOP = 11, + MMC_STOP_TRANSMISSION = 12, + MMC_SEND_STATUS = 13, + MMC_GO_INACTIVE_STATE = 15, + MMC_SET_BLOCKLEN = 16, + MMC_READ_SINGLE_BLOCK = 17, + MMC_READ_MULT_BLOCK = 18, + MMC_WRITE_DAT_UNTIL_STOP = 20, + MMC_SET_BLOCK_COUNT = 23, + MMC_WRITE_SINGLE_BLOCK = 24, + MMC_WRITE_MULT_BLOCK = 25, + MMC_PROG_CID = 26, + MMC_PROG_CSD = 27, + MMC_SET_WRITE_PROT = 28, + MMC_CLR_WRITE_PROT = 29, + MMC_SEND_WRITE_PROT = 30, + MMC_ERASE_GRP_START = 35, + MMC_ERASE_GRP_END = 36, + MMC_ERASE = 38, + MMC_FAST_IO = 39, + MMC_GO_IRQ_STATE = 40, + SD_SEND_OP_COND = 41, + MMC_LOCK_UNLOCK = 42, + MMC_APP_CMD = 55, + MMC_GEN_CMD = 56, + MMC_NO_CMD = 64 +} t_mmc_command_index; + +typedef enum { + MMC_SHORT_RESP = 0, + MMC_LONG_RESP +} t_mmc_response_type; + + +typedef enum { + MMC_WRITE= 0, + MMC_READ +} t_mmc_transfer_direction; + +typedef enum { + MMC_BLOCK = 0, + MMC_STREAM +} t_mmc_transfer_type; + +typedef enum { + POLLING_MODE = 0, + INTERRUPT_MODE, + DMA_MODE +} t_mmc_device_mode; + +/*--------------------------------------------------------------------------- + * Structures + *---------------------------------------------------------------------------*/ + +typedef struct { + t_mmc_bus_mode mode; + t_mmc_state rodctrl; +} t_mmc_bus_configuration; + +typedef struct { + t_mmc_state pwrsave; + t_mmc_state bypass; + t_mmc_state widebus; +} t_mmc_clock_control; + +typedef struct { + t_bool IsRespExpected; + t_bool IsLongResp; + t_bool IsInterruptMode; + t_bool IsPending; + t_mmc_state cmdpath; +} t_mmc_command_control; + + +#define t_mmc_event u32 + +#define t_mmc_filter_mode u32 +#define NO_FILTER_MODE 0 + +typedef enum +{ + MMC_NEW = 0, + MMC_OLD +} t_mmc_irq_status_usage; + +typedef struct +{ + t_mmc_irq_status_usage usage; + u32 IRQStatus; + u32 EventStatus; +} t_mmc_irq_status; + +typedef enum { + + MMC_MULTIMEDIA_CARD, + MMC_SECURE_DIGITAL_CARD, + MMC_SECURE_DIGITAL_IO_CARD, + MMC_HIGH_SPEED_MULTIMEDIA_CARD, + MMC_SECURE_DIGITAL_IO_COMBO_CARD + +} t_mmc_card_type; + +typedef struct { + u32 CID[4]; + u32 CSD[4]; + u16 RCA; + t_mmc_card_type card_type; + u8 padding; + u8 sdio_cccr[4]; /* I/O ready, CCCR/SDIO revision, SD Specification revision, and Card Capability registers */ +} t_mmc_card_info; + +typedef struct { + t_mmc_error error; + u16 transferred_bytes; +} t_mmc_last_transfer_info; + +typedef enum { + NO_TRANSFER = 0, + TRANSFER_IN_PROGRESS +} t_mmc_transfer_state; + +typedef enum { + WRITE_PROT_WHOLE_CARD_TEMP = 0, + WRITE_PROT_WHOLE_CARD_PERM, + WRITE_PROT_SINGLE_GROUP +} t_mmc_write_protect_type; + +/*--------------------------------------------------------------------------- + * Functions Prototype + *---------------------------------------------------------------------------*/ + + +t_mmc_error mmc_init (u8,t_logical_address) ; + +t_mmc_error mmc_setpowerstate(t_mmc_power_state); +t_mmc_power_state mmc_getpowerstate(void); +t_mmc_error mmc_setoperatingvoltage(u8); +u8 mmc_getoperatingvoltage (void); +t_mmc_error mmc_configbus(t_mmc_bus_configuration); + +t_mmc_error mmc_setclock(t_mmc_state); +t_mmc_error mmc_configclockcontrol(t_mmc_clock_control); +t_mmc_error mmc_setclockfrequency(u8); +t_mmc_error mmc_sendcommand(t_mmc_command_index, u32,t_mmc_command_control) ; +t_mmc_command_index mmc_getcommandresponse(void) ; +t_mmc_error mmc_getresponse(t_mmc_response_type, u32*) ; +t_mmc_error mmc_setdatapath(t_mmc_state); +t_mmc_error mmc_setdatatimeout(u32); +t_mmc_error mmc_setdatalength(u16); +t_mmc_error mmc_setdatablocklength(u8); +t_mmc_error mmc_settransferdirection(t_mmc_transfer_direction) ; +t_mmc_error mmc_settransfertype(t_mmc_transfer_type); +t_mmc_error mmc_handledma(t_mmc_state); +u16 mmc_getdatacounter(void); + +t_mmc_error mmc_selectsdcard(u8); +t_mmc_error mmc_poweron(u8) ; +t_mmc_error mmc_poweroff(u8); +t_mmc_error mmc_initializeCards(u8); +t_mmc_error mmc_getcardinfo(u8, t_mmc_card_info *) ; +t_mmc_error mmc_setdevicemode(t_mmc_device_mode); +t_mmc_error mmc_readbytes(u8, u32, u32*, u16) ; +t_mmc_error mmc_readblocks(u8, u32, u32*, u16, u16) ; +t_mmc_error mmc_writebytes(u8, u32, u32* , u16) ; +t_mmc_error mmc_writeblocks(u8, u32, u32*, u16, u16) ; +t_mmc_transfer_state mmc_gettransferstate(void); +t_mmc_error mmc_erase(u8, u32, u32) ; + +u8 convert_from_bytes_to_power_of_two (u16 no_of_bytes); + +/*New Interrupt strategy(M1 functions)*/ +void mmc_acknowledgementevent(t_mmc_event *); + +#endif /* _MMC_H_ */ diff --git a/board/st/u8500/mmc_p.h b/board/st/u8500/mmc_p.h new file mode 100755 index 000000000..26b4b7795 --- /dev/null +++ b/board/st/u8500/mmc_p.h @@ -0,0 +1,316 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _MMC_P_H_ +#define _MMC_P_H_ + +#define BIT31 0x80000000 +#define PROCESSOR_CLK 200000000 +#define MAXBSIZEPOWER 11 + +#define MCLK 26000000 + +#define MMC_PERIPHERAL_ID0 0x81 +#define MMC_PERIPHERAL_ID1 0x11 +#define MMC_PERIPHERAL_ID2 0x04 +#define MMC_PERIPHERAL_ID3 0x00 + + +#define MMC_PCELL_ID0 0x0D +#define MMC_PCELL_ID1 0xF0 +#define MMC_PCELL_ID2 0x05 +#define MMC_PCELL_ID3 0xB1 + + +typedef volatile struct { + u32 mmc_Power; // 0x00 + u32 mmc_Clock; // 0x04 + u32 mmc_Argument; // 0x08 + u32 mmc_Command; // 0x0c + u32 mmc_RespCommand; // 0x10 + u32 mmc_Response0; // 0x14 + u32 mmc_Response1; // 0x18 + u32 mmc_Response2; // 0x1c + u32 mmc_Response3; // 0x20 + u32 mmc_DataTimer; // 0x24 + u32 mmc_DataLength; // 0x28 + u32 mmc_DataCtrl; // 0x2c + u32 mmc_DataCnt; // 0x30 + u32 mmc_Status; // 0x34 + u32 mmc_Clear; // 0x38 + u32 mmc_Mask0; // 0x3c + u32 mmc_Mask1; // 0x40 + u32 mmc_SelectSD; // 0x44 + u32 mmc_FifoCnt; // 0x48 + u32 mmc_unused1[(0x80-0x4C)>>2]; + u32 mmc_Fifo; // 0x80 + u32 mmc_unused2[(0xFE0-0x84)>>2]; + u32 mmc_PeriphId0; // 0xFE0 mmc Peripheral Identi.cation Register + u32 mmc_PeriphId1; // 0xFE4 + u32 mmc_PeriphId2; // 0xFE8 + u32 mmc_PeriphId3; // 0xFEC + + u32 mmc_PCellId0; // 0xFF0 mmc PCell Identi.cation Register + u32 mmc_PCellId1; // 0xFF4 + u32 mmc_PCellId2; // 0xFF8 + u32 mmc_PCellId3; // 0xFFc +}t_mmc_register; + + +// Elementary layer +#define BIT_MASK(__bws) ((u32)(((wb ## __bws)==32)?0xFFFFFFFF:\ + ((1U << (wb ## __bws)) - 1)) << (sb ## __bws)) + +#define MMC_WRITE_BITS(reg,val,mask,sb) ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask)))) +#define MMC_READ_BITS(reg,mask,sb) ((reg & mask)>>sb) + +#define wbMMC_Power_CTRL 2 +#define sbMMC_Power_CTRL 0 +#define MMC_Power_MASK_CTRL BIT_MASK(MMC_Power_CTRL) + +#define wbMMC_Power_VOLT 4 +#define sbMMC_Power_VOLT 2 +#define MMC_Power_MASK_VOLT BIT_MASK(MMC_Power_VOLT) + +#define wbMMC_Power_OPEND 1 +#define sbMMC_Power_OPEND 6 +#define MMC_Power_MASK_OPEND BIT_MASK(MMC_Power_OPEND) + +#define wbMMC_Power_ROD 1 +#define sbMMC_Power_ROD 7 +#define MMC_Power_MASK_ROD BIT_MASK(MMC_Power_ROD) + +#define wbMMC_Clock_CLKDIV 8 +#define sbMMC_Clock_CLKDIV 0 +#define MMC_Clock_MASK_CLKDIV BIT_MASK(MMC_Clock_CLKDIV) + +#define wbMMC_Clock_ENABLE 1 +#define sbMMC_Clock_ENABLE 8 +#define MMC_Clock_MASK_ENABLE BIT_MASK(MMC_Clock_ENABLE) + +#define wbMMC_Clock_PWRSAVE 1 +#define sbMMC_Clock_PWRSAVE 9 +#define MMC_Clock_MASK_PWRSAVE BIT_MASK(MMC_Clock_PWRSAVE) + +#define wbMMC_Clock_BYPASS 1 +#define sbMMC_Clock_BYPASS 10 +#define MMC_Clock_MASK_BYPASS BIT_MASK(MMC_Clock_BYPASS) + +#define wbMMC_Clock_WIDEBUS 1 +#define sbMMC_Clock_WIDEBUS 11 +#define MMC_Clock_MASK_WIDEBUS BIT_MASK(MMC_Clock_WIDEBUS) +#define MMC_SET_WIDEBUS(reg,a) MMC_WRITE_BITS(reg,a,MMC_Clock_MASK_WIDEBUS,sbMMC_Clock_WIDEBUS) + +#define wbMMC_DataPath_ENABLE 1 +#define sbMMC_DataPath_ENABLE 0 +#define MMC_DataPath_MASK_ENABLE BIT_MASK(MMC_DataPath_ENABLE) + +#define wbMMC_DataPath_BLOCKSIZE 4 +#define sbMMC_DataPath_BLOCKSIZE 4 +#define MMC_DataPath_MASK_BLOCKSIZE BIT_MASK(MMC_DataPath_BLOCKSIZE) + +#define wbMMC_DataPath_DIRECTION 1 +#define sbMMC_DataPath_DIRECTION 1 +#define MMC_DataPath_MASK_DIRECTION BIT_MASK(MMC_DataPath_DIRECTION) + +#define wbMMC_DataPath_MODE 1 +#define sbMMC_DataPath_MODE 2 +#define MMC_DataPath_MASK_MODE BIT_MASK(MMC_DataPath_MODE) + +#define wbMMC_DataPath_DMA 1 +#define sbMMC_DataPath_DMA 3 +#define MMC_DataPath_MASK_DMA BIT_MASK(MMC_DataPath_DMA) + +#define MMC_SET_CTRL(reg,a) MMC_WRITE_BITS(reg,a,MMC_Power_MASK_CTRL,sbMMC_Power_CTRL) +#define MMC_SET_VOLT(reg,a) MMC_WRITE_BITS(reg,a,MMC_Power_MASK_VOLT,sbMMC_Power_VOLT) +#define MMC_SET_OPEND(reg,a) MMC_WRITE_BITS(reg,a,MMC_Power_MASK_OPEND,sbMMC_Power_OPEND) +#define MMC_SET_ROD(reg,a) MMC_WRITE_BITS(reg,a,MMC_Power_MASK_ROD,sbMMC_Power_ROD) +#define MMC_SET_CENABLE(reg,a) MMC_WRITE_BITS(reg,a,MMC_Clock_MASK_ENABLE,sbMMC_Clock_ENABLE) +#define MMC_SET_PWRSAVE(reg,a) MMC_WRITE_BITS(reg,a,MMC_Clock_MASK_PWRSAVE,sbMMC_Clock_PWRSAVE) +#define MMC_SET_BYPASS(reg,a) MMC_WRITE_BITS(reg,a,MMC_Clock_MASK_BYPASS,sbMMC_Clock_BYPASS) + +#define MMC_SET_CLKDIV(reg,a) MMC_WRITE_BITS(reg,a,MMC_Clock_MASK_CLKDIV,sbMMC_Clock_CLKDIV) +#define MMC_SET_DATAPATH(reg,a) MMC_WRITE_BITS(reg,a,MMC_DataPath_MASK_ENABLE,sbMMC_DataPath_ENABLE) +#define MMC_SET_BLOCKSIZE(reg,a) MMC_WRITE_BITS(reg,a,MMC_DataPath_MASK_BLOCKSIZE,sbMMC_DataPath_BLOCKSIZE) +#define MMC_SET_DATADIR(reg,a) MMC_WRITE_BITS(reg,a,MMC_DataPath_MASK_DIRECTION,sbMMC_DataPath_DIRECTION) +#define MMC_SET_MODE(reg,a) MMC_WRITE_BITS(reg,a,MMC_DataPath_MASK_MODE,sbMMC_DataPath_MODE) +#define MMC_SET_DMA(reg,a) MMC_WRITE_BITS(reg,a,MMC_DataPath_MASK_DMA,sbMMC_DataPath_DMA) + + + +// Functional layer +#define R1_OUT_OF_RANGE 0x80000000 +#define R1_ADDRESS_ERROR 0x40000000 +#define R1_BLOCK_LEN_ERROR 0x20000000 +#define R1_ERASE_SEQ_ERROR 0x10000000 +#define R1_ERASE_PARAM 0x08000000 +#define R1_WP_VIOLATION 0x04000000 +#define R1_CARD_IS_LOCKED 0x02000000 +#define R1_LOCK_UNLOCK_FAILED 0x01000000 +#define R1_COM_CRC_ERROR 0x00800000 +#define R1_ILLEGAL_COMMAND 0x00400000 +#define R1_CARD_ECC_FAILED 0x00200000 +#define R1_CC_ERROR 0x00100000 +#define R1_UNKNOWN_ERROR 0x00080000 +#define R1_STREAM_READ_UNDERRUN 0x00040000 +#define R1_STREAM_WRITE_OVERRUN 0x00020000 +#define R1_CID_CSD_OVERWRITE 0x00010000 +#define R1_WP_ERASE_SKIP 0x00008000 +#define R1_CARD_ECC_DISABLED 0x00004000 +#define R1_ERASE_RESET 0x00002000 +#define R1_AKE_SEQ_ERROR 0x00000008 +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA 0x000000100 +#define R1_APP_CMD 0x000000020 + +/* DEFINES FOR R6 RESPONSE */ +#define R6_GEN_UNKNOWN_ERROR 0x00002000 +#define R6_ILLEGAL_CMD 0x00004000 +#define R6_COM_CRC_FAILED 0x00008000 + +#define AllOne (0xffffffff) +#define AllZero (0x00000000) + + +//Power Control register + +#define PowerOn (0x00000003) +#define OpenDrain (0x00000040) +#define CmdDatEn (0x0000003C) +#define VoltageWindowMMC (0x80FFC000) +#define VoltageWindowSD (0x80010000) +#define StuffBits0To32 (0xFFFFFFFF) +#define StuffBits0To15 (0xFFFF) +#define Sector_Mode (0x40000000) +#define Byte_Mode (0x00000000) +#define Check_Pattern (0x000001AA) + +//Clock Control register + +#define ClkDivInit (0x00000076) +#define ClkDivTrans (0x00000001) +#define ClkEnable (0x00000100) +#define PwrSave (0x00000200) +#define Enab_Bypass (0x00000400) +#define Widebus_4 (0x00000800) +#define Widebus_8 (0x00001000) +#define Hwfc_en (0x00004000) + +//Command register + +//all commands + +#define GO_IDLE_STATE (0) +#define SEND_OP_COND (1) +#define ALL_SEND_CID (2) +#define SET_REL_ADDR (3) +#define SET_DSR (4) +#define SEL_DESEL_CARD (7) +#define SEND_EXT_CSD (8) +#define SEND_CSD (9) +#define SEND_CID (10) +#define READ_DAT_UNTIL_STOP (11) +#define STOP_TRANSMISSION (12) +#define SEND_STATUS (13) +#define GO_INACTIVE_STATE (15) +#define SET_BLOCKLEN (16) +#define READ_SINGLE_BLOCK (17) +#define READ_MULT_BLOCK (18) +#define WRITE_DAT_UNTIL_STOP (20) +#define SET_BLOCK_COUNT (23) +#define WRITE_SINGLE_BLOCK (24) +#define WRITE_MULT_BLOCK (25) +#define PROG_CID (26) +#define PROG_CSD (27) +#define SET_WRITE_PROT (28) +#define CLR_WRITE_PROT (29) +#define SEND_WRITE_PROT (30) +#define ERASE_GRP_START (35) +#define ERASE_GRP_END (36) +#define ERASE (38) +#define FAST_IO (39) +#define GO_IRQ_STATE (40) +#define LOCK_UNLOCK (42) +#define APP_CMD (55) +#define GEN_CMD (56) + +/*Following commands are SD Card Specific commands. MMC_APP_CMD should be sent before sending these commands.*/ +#define APP_SD_SET_BUSWIDTH (6) +#define SD_APP_STAUS (13) +#define SD_APP_SEND_NUM_WRITE_BLOCKS (22) +#define SD_APP_OP_COND (41) +#define SD_APP_SET_CLR_CARD_DETECT (42) +#define SD_APP_SEND_SCR (51) +#define SD_SEND_IF_COND (8) + +//Command control register + +#define RespExpected (0x00000040) +#define LongResponse (0x00000080) +#define EnabIntrReq (0x00000100) +#define EnabCmdPend (0x00000200) +#define CmdPathEnable (0x00000400) + + +//Data Control register + +#define DataPathEnable (0x00000001) +#define ReadDir (0x00000002) +#define StreamMode (0x00000004) +#define DMAEnab (0x00000008) +#define BlockSize (0x000000F0) + +//Status register + +#define CmdCrcFail (0x00000001) +#define DataCrcFail (0x00000002) +#define CmdTimeOut (0x00000004) +#define DataTimeOut (0x00000008) +#define TxUnderrun (0x00000010) +#define RxOverrun (0x00000020) +#define CmdRespEnd (0x00000040) +#define CmdSent (0x00000080) +#define DataEnd (0x00000100) +#define StartBitError (0x00000200) +#define DataBlockEnd (0x00000400) +#define CmdActive (0x00000800) +#define TxActive (0x00001000) +#define RxActive (0x00002000) +#define TxFifoHalfEmpty (0x00004000) +#define RxFifoHalfFull (0x00008000) +#define TxFifoFull (0x00010000) +#define RxFifoFull (0x00020000) +#define TxFifoEmpty (0x00040000) +#define RxFifoEmpty (0x00080000) +#define TxDataAvlbl (0x00100000) +#define RxDataAvlbl (0x00200000) +#define AllInterrupts (0x003FFDFF) +#define ErrorBits (0xFDFFE008) + +#define ClrStaticFlags (0x00C007FF) + +/* COMMAND CLASS SUPPORTED */ +#define CCCC_LOCK_UNLOCK (0x80) +#define CCCC_WRITE_PROT (0x40) +#define CCCC_ERASE (0x20) + +#endif /*MMCP*/ diff --git a/board/st/u8500/mmc_utils.c b/board/st/u8500/mmc_utils.c new file mode 100755 index 000000000..b7d4e7085 --- /dev/null +++ b/board/st/u8500/mmc_utils.c @@ -0,0 +1,956 @@ +/* + * (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 + */ +#include <linux/ctype.h> + +#include <common.h> +#include <command.h> +#include "gpio.h" +#include "mmc.h" // MMC api +#include "mmc_utils.h" // to access MMC +#include "mmc_p.h" // t_mmc_register definition + +u32 MMCBuffer[1024] ; +static int IS_SD_CARD; + +/* --- exported from other modules ---------------------------------------- */ +static u8 selected_card = 0; +extern t_mmc_error mmc_cmderror_2 (void); +extern t_mmc_error mmc_cmdresp2error_2 (void); +extern t_mmc_error mmc_cmdresp3error_2 (void); +extern t_mmc_error mmc_cmdresp145error_2 (u8 cmd); +extern t_mmc_error mmc_cmdreadresp (u32 * tempbuff); +extern t_mmc_error mmc_waitcmdreadresp (void); +extern t_mmc_error mmc_cmdwriteresp (u8 cardno, u32 * tempbuff, u16 total_num_of_bytes); +extern t_mmc_error mmc_waitcmdwriteresp (u8 cardno, u32 * tempbuff, u16 total_num_of_bytes); + +extern t_mmc_register *t_mmc0; +extern u32 t_mmc_rel_addr; + +t_mmc_boot_record mmc_boot_record; + +void mmc_copyByteH (u8 * sourceAddr, u8 * destAddress, int size) +{ + int i; + for (i = 0; i < size; i++) + { + *(destAddress + i) = *(sourceAddr + i); + } +} + +void mmc_shift_memH (int num_of_words, u32 * start_address, u32 * dest_address, u32 shift) +{ + u32 *address; + int word = 0; + u32 high; + int i, word_offset, bit_offset; + + word_offset = (int) (shift / 32); + bit_offset = (int) (shift % 32); + for (i = 0; i < num_of_words; i++) + { + *(dest_address + i) = 0; + } + for (i = word_offset; i < num_of_words; i++) + { + *(dest_address + i - word_offset) = *(start_address + i); + } + address = dest_address; + for (word = 0; word < num_of_words - 1; word++) + { + *address = (*address) >> bit_offset; + address++; + high = (*address << (32 - bit_offset)); + *(address - 1) |= high; + } + *address = (*address) >> bit_offset; +} + +u8 convert_from_bytes_to_power_of_two (u16 no_of_bytes) +{ + u8 count = 0; + while (no_of_bytes != 1) + { + no_of_bytes >>= 1; + count++; + } + return count; +} + +t_mmc_error mmc_enable () +{ + t_mmc_error error = MMC_OK; + t_mmc_command_control commcontrol; + t_bool validvoltage = FALSE; + u32 arg, response; + int i; + + IS_SD_CARD = 0; + + selected_card = 0; + + t_mmc0->mmc_Power = 0x1BF; + t_mmc0->mmc_Clock = 0x41FF; + + commcontrol.IsRespExpected = FALSE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand (MMC_GO_IDLE_STATE, 0x00000000, commcontrol); + + error = mmc_cmderror_2 (); + + //// Added by Chris Sebastian for SD Card support: + //// Send ACMD41. If we do not get a response, it is not an SD card. + //// If we do get a response, loop until card is not busy. + + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + for(i = 200; i; i--) { + error = mmc_sendcommand (MMC_APP_CMD, 0x00000000, commcontrol); // Let the card know that the next command is an app-cmd. + error = mmc_cmdresp145error_2(MMC_APP_CMD); + error = mmc_sendcommand (SD_SEND_OP_COND, 0x00060000, commcontrol); // I got the 0x00060000 from Linux kernel source. + error = mmc_cmdresp3error_2 (); + t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags. CmdResp3Error_2 leaves some bits set. + if (t_mmc0->mmc_Response0 & 0x80000000) { + printf("SD card detected \n"); + IS_SD_CARD = 1; + return MMC_OK; // SD CARD DETECTED. Do not continue with MMC init logic. Quick escape! + } + } + + commcontrol.IsRespExpected = FALSE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand (MMC_GO_IDLE_STATE, 0x00000000, commcontrol); + error = mmc_cmderror_2 (); + + arg = 0x00060000; // High Voltage MMC, byte mode. Was 0x00FFC000, but that writes to reserved bits... + while (!validvoltage) + { + // send CMD1 (SEND_OP_COND) + commcontrol.IsRespExpected = TRUE; + error = mmc_sendcommand (MMC_SEND_OP_COND, arg, commcontrol); + + error = mmc_cmdresp3error_2 (); + + if (error != MMC_OK) + { + goto end; + } + mmc_getresponse (MMC_SHORT_RESP, &response); + + arg = response; + validvoltage = (t_bool) (((response >> 31) == 1) ? 1 : 0); + + } +end: + return error; +} + +t_mmc_error mmc_disable () +{ + t_mmc_error error = MMC_OK; + t_mmc_power_state powerstate = MMC_POWER_OFF; + + error = mmc_setpowerstate (powerstate); + return error; +} + +t_mmc_error mmc_initCard () +{ + t_mmc_error error = MMC_OK; + t_mmc_command_control commcontrol; + t_mmc_bus_configuration busconfig; + t_mmc_clock_control clockcontrol; + + // send CMD2 (ALL_SEND_CID) + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = TRUE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand (MMC_ALL_SEND_CID, 0x00000000, commcontrol); + error = mmc_cmdresp2error_2 (); + // error is MMC_CMD_CRC_FAIL on COB board ?! + // if( error != MMC_OK) + // goto end; + + // send CMD3 (SET_RELATIVE_ADDR) + + commcontrol.IsLongResp = FALSE; + error = mmc_sendcommand (MMC_SET_REL_ADDR, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp145error_2 (MMC_SET_REL_ADDR); + if(IS_SD_CARD) { + t_mmc_rel_addr = t_mmc0->mmc_Response0 & 0xFFFF0000; + } + + if (error != MMC_OK) + { + goto end; + } + busconfig.mode = MMC_PUSH_PULL; + busconfig.rodctrl = MMC_DISABLE; + error = mmc_configbus (busconfig); + clockcontrol.pwrsave= MMC_DISABLE; + clockcontrol.bypass = MMC_DISABLE; + clockcontrol.widebus= MMC_DISABLE; + error = mmc_setclockfrequency (0x0A); // 12MHz + if (error != MMC_OK) + { + goto end; + } + error = mmc_configclockcontrol (clockcontrol); + if (error != MMC_OK) + { + goto end; + } +end: + return error; +} + +t_mmc_error mmc_readblock (u8 cardno, u32 addr, u32 * readbuff, u16 blocksize, t_mmc_transfer_mode mmc_transfer_mode) +{ + t_mmc_error error = MMC_OK; + u8 power; + t_mmc_command_control commcontrol; + u32 response; + + commcontrol.IsRespExpected = TRUE ; + commcontrol.IsLongResp = FALSE ; + commcontrol.IsInterruptMode = FALSE ; + commcontrol.IsPending = FALSE ; + commcontrol.cmdpath = MMC_ENABLE ; + error = mmc_setdatapath (MMC_DISABLE); + error = mmc_handledma (MMC_DISABLE); + if (error != MMC_OK) + { + goto end; + } + // send command for selecting the card + if (cardno != selected_card) + { + error = mmc_sendcommand (MMC_SEL_DESEL_CARD, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp145error_2 (MMC_SEL_DESEL_CARD); + if (error != MMC_OK) + { + goto end; + } + else + { + selected_card = cardno; + } + } + error = mmc_getresponse (MMC_SHORT_RESP, &response); + if (response & 0x02000000) + { + return MMC_LOCK_UNLOCK_FAILED; + } + // set the block size,both on controller and card + if ((blocksize > 0) && (blocksize <= 2048) && ((blocksize & (blocksize - 1)) == 0)) + { + power = convert_from_bytes_to_power_of_two (blocksize); + error = mmc_setdatablocklength (power); + error = mmc_sendcommand (MMC_SET_BLOCKLEN, (u32) blocksize, commcontrol); + error = mmc_cmdresp145error_2 (MMC_SET_BLOCKLEN); + if (error != MMC_OK) + { + return error; + } + } + else + { + error = MMC_INVALID_PARAMETER; + goto end; + } + error = mmc_setdatalength (blocksize ); + error = mmc_setdatatimeout (0xefffffff ); + error = mmc_settransferdirection (MMC_READ ); + error = mmc_settransfertype (MMC_BLOCK ); + error = mmc_setdatapath (MMC_ENABLE); + //t_mmc0->mmc_DataCtrl |= (ReadDir & ~StreamMode) | DataPathEnable; + error = mmc_sendcommand (MMC_READ_SINGLE_BLOCK, addr, commcontrol); + error = mmc_cmdresp145error_2 (MMC_READ_SINGLE_BLOCK); + if (error != MMC_OK) + { + goto end; + } + if (mmc_transfer_mode == MMCDMA) + { + error = mmc_waitcmdreadresp (); + } + else + { + error = mmc_cmdreadresp (readbuff); + } + if (error != MMC_OK) + { + goto end; + } +end: + return error; +} + +t_mmc_error mmc_writeblock (u8 cardno, u32 addr, u32 * writebuff, u16 blocksize, t_mmc_transfer_mode mmc_transfer_mode) +{ + t_mmc_error error = MMC_OK; + u8 power; + t_mmc_command_control commcontrol; + u32 response; + + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_setdatapath (MMC_DISABLE); + error = mmc_handledma (MMC_DISABLE); + error = mmc_settransferdirection(MMC_WRITE); + error = mmc_settransfertype (MMC_BLOCK); + + if (cardno != selected_card) + { + error = mmc_sendcommand (MMC_SEL_DESEL_CARD, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp145error_2 (MMC_SEL_DESEL_CARD); + if (error != MMC_OK) + { + goto end; + } + else + { + selected_card = cardno; + } + } + + mmc_getresponse (MMC_SHORT_RESP, &response); + if (response & 0x02000000) + { + return MMC_LOCK_UNLOCK_FAILED; + } + // set the block size,both on controller and card + if ((blocksize > 0) && (blocksize <= 2048) && (((blocksize & (blocksize - 1)) == 0))) + { + power = convert_from_bytes_to_power_of_two (blocksize); + error = mmc_setdatablocklength (power); + error = mmc_sendcommand (MMC_SET_BLOCKLEN, (u32) blocksize, commcontrol); + error = mmc_cmdresp145error_2 (MMC_SET_BLOCKLEN); + if (error != MMC_OK) + { + goto end; + } + } + else + { + error = MMC_INVALID_PARAMETER; + goto end; + } + + error = mmc_setdatalength (blocksize); + error = mmc_setdatatimeout (0xefffffff); + error = mmc_settransferdirection (MMC_WRITE); + error = mmc_settransfertype (MMC_BLOCK); + error = mmc_setdatapath (MMC_ENABLE); + error = mmc_sendcommand (MMC_WRITE_SINGLE_BLOCK, addr, commcontrol); + error = mmc_cmdresp145error_2 (MMC_WRITE_SINGLE_BLOCK); + if (error != MMC_OK) + { + goto end; + } + if (mmc_transfer_mode == MMCDMA) + { + error = mmc_waitcmdwriteresp (cardno, writebuff, blocksize); + } + else + { + error = mmc_cmdwriteresp (cardno, writebuff, blocksize); + } + if (error != MMC_OK) + { + goto end; + } +end: + return error; +} + +t_mmc_error mmc_readcsd (u32 * CSD) +{ + t_mmc_error error = MMC_OK; + t_mmc_command_control commcontrol; + u32 buf[4]; + + // send CMD9 (SEND CSD) + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = TRUE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand (MMC_SEND_CSD, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp2error_2 (); + if (error != MMC_OK) + { + goto end; + } + error = mmc_getresponse (MMC_LONG_RESP, buf); + CSD[0] = buf[3]; + CSD[1] = buf[2]; + CSD[2] = buf[1]; + CSD[3] = buf[0]; +end: + return error; +} + +t_mmc_error mmc_readcid (u32 * CID) +{ + t_mmc_error error = MMC_OK; + t_mmc_command_control commcontrol; + u32 buf[4]; + + // send CMD9 (SEND CSD) + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = TRUE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + error = mmc_sendcommand (MMC_SEND_CID, t_mmc_rel_addr, commcontrol); + error = mmc_cmdresp2error_2 (); + if (error != MMC_OK) + { + goto end; + } + error = mmc_getresponse (MMC_LONG_RESP, buf); + CID[0] = buf[3]; + CID[1] = buf[2]; + CID[2] = buf[1]; + CID[3] = buf[0]; +end: + return error; +} + +t_mmc_error mmc_read_file (char *filename, u32 address, u32 * FileSize) +{ + u8 *mem_address = (u8 *) address; + u8 sector[512]; + u16 BytesPerSector; + u32 BRStartSector; + u32 FATStartSector; + u32 DataStartSector; + u32 FileStartSector; + u16 SectorsPerFAT; + u8 SectorsPerCluster; + u8 k; + u16 MaxRDEntries; + u16 ReservedSectors; + u32 RDStartSector, j; + char nomefile[12] = " "; + int filelength; + u16 FileStartCluster = 0; + t_mmc_error response, response2; + int i, goout, found, result = PASS; + u32 CSD[4]; + char mmcfilename[] = " "; + char *dotpos; + + /////////// Attention please: ///////////////////// + // // + // if other Alternate function apart from MMCI // + // are selected, the MMCI I/F has some problems // + // // + //////////////////////////////////////////////////// + + gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC"); + // Power-on the controller + response = mmc_enable (); + + if (response != MMC_OK) + { + + response = mmc_enable (); // This actually IS necessary because it takes time for newly-inserted cards initialize. ~Chris S. + if (response != MMC_OK) + { + printf ("Error in card power on\n"); + result = FAIL; + goto end; + } + } + // Initialise the cards on the bus, if any + response = mmc_initCard (); + + if (response != MMC_OK) + { + printf ("Error in card initialization\n"); + result = FAIL; + goto end; + } + // Get card info: CID, CSD, RCA registers + response = mmc_readcsd (CSD); + + if (response != MMC_OK) + { + printf ("Error while fetching card info\n"); + result = FAIL; + goto end; + } + // Read the MBR + response = mmc_readblock (1, 0, (u32 *) sector, 512, MMCPOLLING); + + if (response != MMC_OK) + { + printf ("Error while reading boot record\n"); + result = FAIL; + goto end; + } + if (sector[446] == 0x00 || sector[446] == 0x80) + { // found a MBR at the beginning of card + BRStartSector = sector[454]; + } + else + { // BR at the beginning of card + BRStartSector = 0x00; + } + // Read the BR + response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING); + + k = 0; + while (response == MMC_DATA_CRC_FAIL && (k < 2)) + { + response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING); + k++; + } + if (response != MMC_OK) + { + printf ("Error while reading boot record\n"); + result = FAIL; + goto end; + } + mmc_copyByteH (mmc_boot_record.BytesPerSector, (u8 *) & BytesPerSector, 2); + mmc_copyByteH (mmc_boot_record.ReservedSectors, (u8 *) & ReservedSectors, 2); + FATStartSector = BRStartSector + ReservedSectors; // the field at offset 15 contains the number of reserved sectors at + // the beginning of the media including the boot sector + mmc_copyByteH (mmc_boot_record.SectorsPerFat, (u8 *) & SectorsPerFAT, 2); + SectorsPerCluster = mmc_boot_record.SectorsPerCluster[0]; + mmc_copyByteH (mmc_boot_record.NumOfRootEntries, (u8 *) & MaxRDEntries, 2); + FATStartSector += SectorsPerFAT; + RDStartSector = FATStartSector + SectorsPerFAT; + DataStartSector = RDStartSector + (u32) ((MaxRDEntries * 32) / 512); + + + + // convert filename into mmc compatible file name (upper case , <= 8+3 char, no dot, no extension) + filelength = strlen (filename); + dotpos = strchr (filename, '.'); + if (dotpos == NULL) + { + // no dot + if (filelength <= 8) + { + for (j = 0; j < filelength; j++) + { + mmcfilename[j] = (char) toupper (filename[j]); + } + } + else + { + for (j = 0; j < 6; j++) + { + mmcfilename[j] = (char) toupper (filename[j]); + } + mmcfilename[7] = '~'; + mmcfilename[8] = '1'; + filelength = 8; + } + } + else + { + // dot + if ((dotpos - filename) <= 8) + { + for (j = 0; j < (dotpos - filename); j++) + { + mmcfilename[j] = (char) toupper (filename[j]); + } + for (; j < 8; j++) + { + mmcfilename[j] = ' '; + } + // copy 3 char after . + mmcfilename[j++] = (char) toupper (dotpos[1]); + mmcfilename[j++] = (char) toupper (dotpos[2]); + mmcfilename[j++] = (char) toupper (dotpos[3]); + + } + else + { + for (j = 0; j < 6; j++) + { + mmcfilename[j] = (char) toupper (filename[j]); + } + mmcfilename[6] = '~'; + mmcfilename[7] = '1'; + // copy 3 char after . + mmcfilename[8] = (char) toupper (dotpos[1]); + mmcfilename[9] = (char) toupper (dotpos[2]); + mmcfilename[10] = (char) toupper (dotpos[3]); + } + filelength = 11; + } + mmcfilename[11] = '\0'; + + + // search Root Directory for entry filename + goout = 0; + found = 0; + for (j = 0; j < (DataStartSector - RDStartSector); j++) + { + if (goout == 1) + break; + response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING); + if (response != MMC_OK) + { + printf ("Error while reading root directory\n"); + result = FAIL; + goto end; + } + + for (i = 0; i < 512; i += 32) + { + strncpy (nomefile, (char *) §or[i], filelength); + if (strcmp (nomefile, mmcfilename) == 0) + { + mmc_copyByteH (§or[i + 26], (u8 *) & FileStartCluster, 2); + mmc_copyByteH (§or[i + 28], (u8 *) FileSize, 4); + FileStartCluster -= 2; + goout = 1; + found = 1; + break; + } + if (nomefile[0] == 0) + { // end of Root Directory + goout = 1; + break; + } + } + } + + // size of file : *FileSize ( 32 bits quantum) + // number of bytes per sector : BytesPerSector + // Beginning of file : FileStartSector + + printf ("Bytes per sector : %d \n", BytesPerSector ); + printf ("Sectors per cluster : %d \n", SectorsPerCluster ); + if (found) + { + u32 remaining = *FileSize ; + u32 count; + u32 burstsize = BytesPerSector ; + + FileStartSector = ( DataStartSector + (u32)(FileStartCluster * SectorsPerCluster)) ; + printf ("Reading file %s from MMC ..., start sector = %d, address 0x%x \n",filename,FileStartSector,address); + count = SectorsPerCluster - (FileStartSector % SectorsPerCluster) ; + FileStartSector = FileStartSector * BytesPerSector; // the first burst might be different to align of clusters + + do + { + if ( remaining >= burstsize ) + { // read straight burst + + k = 0; + do + { + response = mmc_readblock (1, (u32) FileStartSector , (u32 *) mem_address, burstsize , MMCPOLLING); + k++; + + } while ((response==MMC_DATA_CRC_FAIL)&&(k<4)); + if ( k != 1) printf ("!"); + FileStartSector += burstsize; + mem_address += burstsize; + remaining -= burstsize; + } + else + { // read burst +1 and perform memcpy + + burstsize = ((remaining + (BytesPerSector-1))/BytesPerSector) * BytesPerSector ; + k = 0; + do + { + response = mmc_readblock (1, (u32) FileStartSector , (u32 *) MMCBuffer , burstsize , MMCPOLLING); + k++; + } while ((response==MMC_DATA_CRC_FAIL)&&(k<4)); + if ( k != 1) printf ("!"); + memcpy ((char *) mem_address, (char *)MMCBuffer,remaining); + remaining = 0; + } + if (response != MMC_OK) + { + printf ("Error while reading file %s\n", filename); + result = FAIL; + goto end; + } + } while ( remaining ); + + } + else + { + printf ("Unable to find %s on Multi Media Card\n", filename); + response = MMC_INVALID_PARAMETER; + result = FAIL; + goto end; + } + +end: + gpio_altfuncdisable(GPIO_ALT_SD_CARD0, "MMC"); + response2 = mmc_disable (); + + return response; +} + +t_mmc_error display_file_list (char *extension) +{ + u32 i, j, k, goout; + u32 FATStartSector; + u8 SectorsPerCluster; + u32 RDStartSector; + u32 DataStartSector; + u16 BytesPerSector; + u32 BRStartSector; + u16 SectorsPerFAT; + u16 MaxRDEntries; + u16 ReservedSectors; + u8 sector[512]; + t_mmc_error response; + t_mmc_error response2; + u32 CSD[4]; + char nomefile[12] = " "; + char name[9] = " "; + char extent[4] = " "; + u32 FileSize; + + //printf("disp:: start\n"); + gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC"); + + // Power-on the controller + response = mmc_enable (); + + if (response != MMC_OK) + { + response = mmc_enable (); // This actually IS necessary because it takes time for newly-inserted cards initialize. ~Chris S. + if (response != MMC_OK) + { + printf ("Error in card power on, response is %d\n", response); + goto end; + } + } + // Initialise the cards on the bus, if any + + response = mmc_initCard (); + + if (response != MMC_OK) + { + printf ("1. Error in card initialization\n"); + goto end; + } + // Get card info: CID, CSD, RCA registers + + response = mmc_readcsd (CSD); + + if (response != MMC_OK) { + printf ("Error while fetching card info\n"); + goto end; + } + // Read the MBR + + response = mmc_readblock (1, 0, (u32 *) sector, 512, MMCPOLLING); + + if (response != MMC_OK) + { + printf ("Error while reading boot record\n"); + goto end; + } + if (sector[446] == 0x00 || sector[446] == 0x80) + { // found a MBR at the beginning of card + + BRStartSector = sector[454]; + } + else + { // BR at the beginning of card + + BRStartSector = 0x00; + } + // Read the BR + response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING); + + k = 0; + while (response == MMC_DATA_CRC_FAIL && (k < 2)) + { + response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING); + k++; + } + if (response != MMC_OK) + { + printf ("Error while reading boot record\n"); + goto end; + } + mmc_copyByteH (mmc_boot_record.BytesPerSector, (u8 *) & BytesPerSector, 2); + mmc_copyByteH (mmc_boot_record.ReservedSectors, (u8 *) & ReservedSectors, 2); + FATStartSector = BRStartSector + ReservedSectors; // the field at offset 15 contains the number of reserved sectors at + // the beginning of the media including the boot sector + + mmc_copyByteH (mmc_boot_record.SectorsPerFat, (u8 *) & SectorsPerFAT, 2); + SectorsPerCluster = mmc_boot_record.SectorsPerCluster[0]; + mmc_copyByteH (mmc_boot_record.NumOfRootEntries, (u8 *) & MaxRDEntries, 2); + + FATStartSector += SectorsPerFAT; + RDStartSector = FATStartSector + SectorsPerFAT; + DataStartSector = RDStartSector + (u32) ((MaxRDEntries * 32) / 512); + // search Root Directory for entry filename + goout = 0; + printf ("file \t\t size\n"); + + for (j = 0; j < (DataStartSector - RDStartSector); j++) + { + printf(" disp:: data start \n"); + if (goout == 1) + { + break; + } + response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING); + k = 0; + while (response == MMC_DATA_CRC_FAIL && (k < 2)) + { + response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING); + k++; + } + if (response != MMC_OK) + { + printf ("Error while reading root directory\n"); + goto end; + } + for (i = 0; i < 512; i += 32) + { + strncpy (nomefile, (char *) §or[i], 11); + if (nomefile[0] == 0) // end of Root Directory + { + goout = 1; + break; + } + if (nomefile[0] != 0xE5) // not deleted file only + { + for (k = 0; k < 3; k++) + { + extent[k] = (char) toupper (extension[k]); + } + if ((strncmp (&nomefile[8], extent, strlen (extension)) == 0) || (*extension == '*')) + { + mmc_copyByteH (§or[i + 28], (u8 *) & FileSize, 4); + k = 0; + while ((nomefile[k] != 0x20) && (k < 8)) + { + name[k] = (char) tolower (nomefile[k]); + k++; + } + name[k] = '\0'; + for (k = 0; k < 3; k++) + { + extent[k] = (char) tolower (nomefile[k + 8]); + } + printf ("%s.%s \t %10ld\n", name, extent, FileSize); + } + } + } + } +end: + gpio_altfuncdisable(GPIO_ALT_SD_CARD0, "MMC"); + response2 = mmc_disable (); + //printf("disp:: done \n"); + return response; +} + +/* + * command line commands + */ + +static char mmc_cmdbuffer[1024] ; + +int copy_file_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned long address; + unsigned long filesize; + int load_result; + char filename[30]; + + strcpy(filename , argv[1]); + address = simple_strtoul (argv[2], 0, 16); + + printf("copy_file_mmc : filename = %s\n", filename); + printf("copy_file_mmc : address = %x\n", address); + + load_result = mmc_read_file(filename, address, &filesize); + if (load_result != 0) + { + printf("copy_file_mmc error : in loading file \n"); + } + return(load_result); +} + +int mmc_read_cmd_file (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned long filesize; + int load_result; + + load_result = mmc_read_file("command.txt", + (unsigned long)&mmc_cmdbuffer, &filesize); + if (load_result != 0) { + printf("mmc_read_cmd_file error : in loading file \n"); + } else { + setenv ("bootcmd", mmc_cmdbuffer); + } + return(load_result); +} + + +U_BOOT_CMD( + copy_file_mmc, 3, 0, copy_file_mmc, + "- copy file from mmc card\n", + "filename address\n" + " - load binary file from the MMC/SD card to a memory address\n" +); + + +U_BOOT_CMD( + mmc_read_cmd_file, 1, 0, mmc_read_cmd_file, + "- copy command file from mmc card\n", + NULL +); + +/* ------------------------------- End of file ---------------------------- */ diff --git a/board/st/u8500/mmc_utils.h b/board/st/u8500/mmc_utils.h new file mode 100755 index 000000000..b998814c5 --- /dev/null +++ b/board/st/u8500/mmc_utils.h @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef __MMC_UTILS_H +#define __MMC_UTILS_H + +#include <common.h> + +typedef struct +{ + u8 jump [3]; + u8 OEMname [8]; + u8 BytesPerSector [2]; + u8 SectorsPerCluster [1]; + u8 ReservedSectors [2]; + u8 NumOfFAT [1]; + u8 NumOfRootEntries [2]; + u8 NumOfSectors [2]; + u8 MediaDesc [1]; + u8 SectorsPerFat [2]; + u8 SectorsPerTrack [2]; + u8 NumOfHeads [2]; + u8 NumOfHiddenSectors [4]; + u8 NumOfTotSectors [4]; + u8 DriveNumber [1]; + u8 reserved [1]; + u8 ExtBootSig [1]; + u8 VolumeID [4]; + u8 VolumeLabel [11]; + u8 FSType [8]; + u8 LoadProg [448]; + u8 Signature [2]; +} t_mmc_boot_record; + +typedef struct +{ + u8 filename [8]; + u8 extension [3]; + u8 attrib ; + u8 reserved [10]; + u8 hour [2]; + u8 date [2]; + u8 startCluster [2]; + u8 dimension [4]; +} t_mmc_root_entry; + +typedef struct s_root_elem +{ + char name[8]; + char ext[3]; + char nulll[0xf]; + short offset; + unsigned sizee; +} s_root_elem; + +typedef struct s_root +{ + s_root_elem elem[16]; +} s_root; + +typedef struct s_file_elem +{ + char filename [8] ; +} s_file_elem; + +typedef struct s_file_list +{ + s_file_elem elem [30]; +} s_file_list ; + +typedef enum +{ + MMCPOLLING, + MMCDMA +}t_mmc_transfer_mode; + + +t_mmc_error mmc_readblock (u8 cardno, u32 addr, u32* readbuff, u16 blocksize, t_mmc_transfer_mode transfer_mode); +t_mmc_error mmc_writeblock (u8 cardno, u32 addr, u32* writebuff, u16 blocksize, t_mmc_transfer_mode transfer_mode); +t_mmc_error mmc_enable (void); +t_mmc_error mmc_disable (void); +t_mmc_error mmc_initCard (void); +t_mmc_error mmc_readcsd (u32 *response); +t_mmc_error mmc_readcid (u32 *response) ; +t_mmc_error display_file_list(char *extension); + +#endif /* !defined(__MMC_UTILS_H) */ + + diff --git a/board/st/u8500/u8500.c b/board/st/u8500/u8500.c new file mode 100755 index 000000000..0cca76cf3 --- /dev/null +++ b/board/st/u8500/u8500.c @@ -0,0 +1,140 @@ +/* +* (C) Copyright 2009 +* STEricsson, <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 +*/ + +#include <config.h> +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include "common.h" + +void init_regs(void); +#if 0 +void *memcopy(void *dest, const void *src, size_t count) +{ + u16 *tmp = (u16 *) dest, *s = (u16 *) src; + + count = count / 2; + while (count--) + *tmp++ = *s++; + + return dest; +} +#endif +#if defined(CONFIG_SHOW_BOOT_PROGRESS) +void show_boot_progress(int progress) +{ + printf("Boot reached stage %d\n", progress); +} +#endif + +static inline void delay(unsigned long loops) +{ + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0"(loops)); +} + +/* +* Miscellaneous platform dependent initialisations +*/ + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + gd->bd->bi_arch_number = 0x1A4; + gd->bd->bi_boot_params = 0x00000100; + //enable the timers in PRCMU reg + *((volatile unsigned int *)(CFG_PRCMU_BASE + 0x1C8)) = 0x20000; + icache_enable(); + gpio_init(); + + init_regs(); + return 0; +} + +#ifdef CONFIG_MISC_INIT_R +int misc_init_r(void) +{ + setenv("verify", "n"); + return (0); +} +#endif + +/****************************** +Routine: +Description: +******************************/ +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE_1; + gd->bd->bi_dram[1].start = PHYS_SDRAM_2; + gd->bd->bi_dram[1].size = PHYS_SDRAM_SIZE_2; + + return 0; +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +unsigned int addr_vall_arr[] = { +0x8011F000, 0x0000FFFF, // Clocks for HSI TODO Enable reqd only +0x8011F008, 0x00001C44, // Clocks for HSI TODO Enable reqd only +0x8000F000, 0x00007FFF, // Clocks for I2C TODO Enable reqd only +0x8000F008, 0x00007FFF, // Clocks for I2C TODO Enable reqd only +0x8000E120, 0x003C0000, // GPIO for I2C/SD +0x8000E124, 0x00000000, // GPIO for I2C/SD +0x8012F000, 0x00007FFF, // Clocks for SD TODO Enable reqd only +0x8012F008, 0x00007FFF, // Clocks for SD TODO Enable reqd only +0xA03DF000, 0x0000000D, // Clock for MTU Timers +0x8011E00C, 0x00000000, // GPIO ALT FUNC for EMMC +0x8011E004, 0x0000FFE0, // GPIO ALT FUNC for EMMC +0x8011E020, 0x0000FFE0, // GPIO ALT FUNC for EMMC +0x8011E024, 0x00000000, // GPIO ALT FUNC for EMMC +0x8012E00C, 0x00000000, // GPIO ALT FUNC for SD +0x8012E004, 0x0FFC0000, // GPIO ALT FUNC for SD +0x8012E020, 0x60000000, // GPIO ALT FUNC for SD +0x8012E024, 0x60000000, // GPIO ALT FUNC for SD +0x801571E4, 0x0000000C, // PRCMU settings for B2R2 +0x80157024, 0x00000130, // PRCMU settings for EMMC/SD +0xA03FF000, 0x00000003, // USB +0xA03FF008, 0x00000001, // USB +0xA03FE00C, 0x00000000, // USB +0xA03FE020, 0x00000FFF, // USB +0xA03FE024, 0x00000000 // USB +}; +#ifdef BOARD_LATE_INIT +int board_late_init(void) +{ + return (0); +} +#endif +void init_regs(void) +{ + int i; + for(i = 0; i < ARRAY_SIZE(addr_vall_arr)/2; i++) + { + + *((volatile unsigned int *)(addr_vall_arr[2 * i])) + = addr_vall_arr[(2 * i) + 1]; + } +} diff --git a/common/Makefile b/common/Makefile index 3781738e1..7ba449505 100644..100755 --- a/common/Makefile +++ b/common/Makefile @@ -61,6 +61,7 @@ COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o +COBJS-$(CONFIG_ENV_IS_IN_EMMC) += env_emmc.o COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o # command diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index eb89e9e60..6040a9996 100644..100755 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -63,9 +63,10 @@ DECLARE_GLOBAL_DATA_PTR; !defined(CONFIG_ENV_IS_IN_NVRAM) && \ !defined(CONFIG_ENV_IS_IN_ONENAND) && \ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ + !defined(CONFIG_ENV_IS_IN_EMMC) && \ !defined(CONFIG_ENV_IS_NOWHERE) # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\ -SPI_FLASH|MG_DISK|NVRAM|NOWHERE} +SPI_FLASH|MG_DISK|NVRAM|EMMC|NOWHERE} #endif #define XMK_STR(x) #x diff --git a/common/env_emmc.c b/common/env_emmc.c new file mode 100755 index 000000000..c46e18aa6 --- /dev/null +++ b/common/env_emmc.c @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +/* #define DEBUG */ + +#include <common.h> + +#if defined(CONFIG_ENV_IS_IN_EMMC) /* Environment is in EMMC Flash */ + +#include <command.h> +#include <environment.h> +#include <linux/stddef.h> +#include <malloc.h> +#include <asm/arch/emmc.h> + +#if defined(CONFIG_CMD_ENV) && defined(CONFIG_CMD_EMMC) +#define CMD_SAVEENV +#elif defined(CONFIG_ENV_OFFSET_REDUND) +#error Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_ENV & CONFIG_CMD_EMMC +#endif + +#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE) +#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE +#endif + +#ifdef CONFIG_INFERNO +#error CONFIG_INFERNO not supported yet +#endif + +/* references to names in env_common.c */ +extern uchar default_environment[]; +extern int default_environment_size; + +char * env_name_spec = "EMMC"; + + +#ifdef ENV_IS_EMBEDDED +extern uchar environment[]; +env_t *env_ptr = (env_t *)(&environment[0]); +#else /* ! ENV_IS_EMBEDDED */ +env_t *env_ptr = 0; +#endif /* ENV_IS_EMBEDDED */ + + +DECLARE_GLOBAL_DATA_PTR; + +uchar env_get_char_spec (int index) +{ + return ( *((uchar *)(gd->env_addr + index)) ); +} + + +/* this is called before nand_init() + * so we can't read Nand to validate env data. + * Mark it OK for now. env_relocate() in env_common.c + * will call our relocate function which will does + * the real validation. + * + * When using a eMMC boot image (like sequoia_nand), the environment + * can be embedded or attached to the U-Boot image in eMMC flash. This way + * the SPL loads not only the U-Boot image from eMMC but also the + * environment. + */ +int env_init(void) +{ +#if defined(ENV_IS_EMBEDDED) + ulong total; + int crc1_ok = 0, crc2_ok = 0; + env_t *tmp_env1, *tmp_env2; + + total = CONFIG_ENV_SIZE; + + tmp_env1 = env_ptr; + tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE); + + crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); + crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); + + if (!crc1_ok && !crc2_ok) + gd->env_valid = 0; + else if(crc1_ok && !crc2_ok) + gd->env_valid = 1; + else if(!crc1_ok && crc2_ok) + gd->env_valid = 2; + else { + #ifdef CONFIG_REDUNDAND_ENVIRONMENT + /* both ok - check serial */ + if(tmp_env1->flags == 255 && tmp_env2->flags == 0) + gd->env_valid = 2; + else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) + gd->env_valid = 1; + else if(tmp_env1->flags > tmp_env2->flags) + gd->env_valid = 1; + else if(tmp_env2->flags > tmp_env1->flags) + gd->env_valid = 2; + else /* flags are equal - almost impossible */ + #endif + gd->env_valid = 1; + } + + if (gd->env_valid == 1) + env_ptr = tmp_env1; + else if (gd->env_valid == 2) + env_ptr = tmp_env2; +#else /* ENV_IS_EMBEDDED */ + gd->env_addr = (ulong)&default_environment[0]; + gd->env_valid = 1; +#endif /* ENV_IS_EMBEDDED */ + + return (0); +} + +#ifdef CMD_SAVEENV +int saveenv(void) +{ + ulong total; + int ret = 0; + + puts ("Erasing eMMC..."); + if (emmc_erase(CONFIG_ENV_OFFSET_START, CONFIG_ENV_OFFSET_END)) + return 1; + + puts ("Writing to EMMC... "); + total = CONFIG_ENV_SIZE; + ret = emmc_write(CONFIG_ENV_OFFSET_START, (u32 *) env_ptr, + CONFIG_ENV_SIZE); + //if (ret || total != CONFIG_ENV_SIZE) + //return 1; + + puts ("done\n"); + return ret; +} +#endif /* CMD_SAVEENV */ +#ifdef CONFIG_ENV_OFFSET_REDUND +void env_relocate_spec (void) +{ +#if !defined(ENV_IS_EMBEDDED) + ulong total; + int crc1_ok = 0, crc2_ok = 0; + env_t *tmp_env1, *tmp_env2; + + total = CONFIG_ENV_SIZE; + + tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE); + tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE); + + emmc_read(CONFIG_ENV_OFFSET_START,(u32 *) tmp_env1, total); + emmc_read(CONFIG_ENV_OFFSET_START,(u32 *) tmp_env2, total); + + crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); + crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); + + if(!crc1_ok && !crc2_ok) + return set_default_env(); + else if(crc1_ok && !crc2_ok) + gd->env_valid = 1; + else if(!crc1_ok && crc2_ok) + gd->env_valid = 2; + else { + /* both ok - check serial */ + if(tmp_env1->flags == 255 && tmp_env2->flags == 0) + gd->env_valid = 2; + else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) + gd->env_valid = 1; + else if(tmp_env1->flags > tmp_env2->flags) + gd->env_valid = 1; + else if(tmp_env2->flags > tmp_env1->flags) + gd->env_valid = 2; + else /* flags are equal - almost impossible */ + gd->env_valid = 1; + + } + + free(env_ptr); + if(gd->env_valid == 1) { + env_ptr = tmp_env1; + free(tmp_env2); + } else { + env_ptr = tmp_env2; + free(tmp_env1); + } + +#endif /* ! ENV_IS_EMBEDDED */ +} +#else /* ! CONFIG_ENV_OFFSET_REDUND */ +void env_relocate_spec (void) +{ +#if !defined(ENV_IS_EMBEDDED) + ulong total; + int ret; + + total = CONFIG_ENV_SIZE; + printf("env_relocate_spec start\n"); + emmc_init(4); + ret = emmc_read(CONFIG_ENV_OFFSET_START, (u_char*)env_ptr, total); + if (ret || total != CONFIG_ENV_SIZE) + return set_default_env(); + + if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) + return set_default_env(); +#endif /* ! ENV_IS_EMBEDDED */ +} +#endif /* CONFIG_ENV_OFFSET_REDUND */ + +#endif /* CONFIG_ENV_IS_IN_EMMC */ diff --git a/cpu/arm_cortexa9/Makefile b/cpu/arm_cortexa9/Makefile new file mode 100755 index 000000000..ae20299db --- /dev/null +++ b/cpu/arm_cortexa9/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START := start.o +COBJS := cpu.o + +SRCS := $(START:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +#########################################################################
\ No newline at end of file diff --git a/cpu/arm_cortexa9/config.mk b/cpu/arm_cortexa9/config.mk new file mode 100755 index 000000000..3036fa624 --- /dev/null +++ b/cpu/arm_cortexa9/config.mk @@ -0,0 +1,36 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <gj@denx.de> +# +# 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 +# +PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ + -msoft-float + +# Make ARMv5 to allow more compilers to work, even though its v7a. +PLATFORM_CPPFLAGS += -march=armv7-a -mcpu=cortex-a9 +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option) +PLATFORM_CPPFLAGS +=$(call cc-option,-mno-thumb-interwork,) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,\ + $(call cc-option,-malignment-traps,)) diff --git a/cpu/arm_cortexa9/cpu.c b/cpu/arm_cortexa9/cpu.c new file mode 100755 index 000000000..02e716b6d --- /dev/null +++ b/cpu/arm_cortexa9/cpu.c @@ -0,0 +1,249 @@ +/* + * (C) Copyright 2008 Texas Insturments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * 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 + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> + +#ifdef CONFIG_USE_IRQ +DECLARE_GLOBAL_DATA_PTR; +#endif + +#ifndef CONFIG_L2_OFF +void l2cache_enable(void); +void l2cache_disable(void); +#endif + +static void cache_flush(void); + +/* read co-processor 15, register #1 (control register) */ +static unsigned long read_p15_c1(void) +{ + unsigned long value; + + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0\ + @ read control reg\n":"=r"(value) + ::"memory"); + return value; +} + +/* write to co-processor 15, register #1 (control register) */ +static void write_p15_c1(unsigned long value) +{ + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 0\ + @ write it back\n"::"r"(value) + : "memory"); + + read_p15_c1(); +} + +static void cp_delay(void) +{ + /* Many OMAP regs need at least 2 nops */ + asm("nop"); + asm("nop"); +} + +/* See also ARM Ref. Man. */ +#define C1_MMU (1<<0) /* mmu off/on */ +#define C1_ALIGN (1<<1) /* alignment faults off/on */ +#define C1_DC (1<<2) /* dcache off/on */ +#define C1_WB (1<<3) /* merging write buffer on/off */ +#define C1_BIG_ENDIAN (1<<7) /* big endian off/on */ +#define C1_SYS_PROT (1<<8) /* system protection */ +#define C1_ROM_PROT (1<<9) /* ROM protection */ +#define C1_IC (1<<12) /* icache off/on */ +#define C1_HIGH_VECTORS (1<<13) /* location of vectors: low/high addresses */ +#define RESERVED_1 (0xf << 3) /* must be 111b for R/W */ + +int cpu_init(void) +{ + /* + * setup up stacks if necessary + */ +#ifdef CONFIG_USE_IRQ + IRQ_STACK_START = + _armboot_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE - 4; + FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ; +#endif + return 0; +} + +int cleanup_before_linux(void) +{ + unsigned int i; + + /* + * this function is called just before we call linux + * it prepares the processor for linux + * + * we turn off caches etc ... + */ + disable_interrupts(); + + /* turn off I/D-cache */ + icache_disable(); + dcache_disable(); + + /* invalidate I-cache */ + cache_flush(); + +#ifndef CONFIG_L2_OFF + /* turn off L2 cache */ + l2cache_disable(); + /* invalidate L2 cache also */ + v7_flush_dcache_all(get_device_type()); +#endif + i = 0; + /* mem barrier to sync up things */ + asm("mcr p15, 0, %0, c7, c10, 4": :"r"(i)); + +#ifndef CONFIG_L2_OFF + l2cache_enable(); +#endif +#ifdef CONFIG_U8500 + *((volatile unsigned int *)(0xA04127CC)) = 0xFF; + while (*((volatile unsigned int *)(0xA04127CC)) & 0xFF); + *((volatile unsigned int *)(0xA0412900)) = 0xFF; + *((volatile unsigned int *)(0xA0412904)) = 0xFF; +#endif + return 0; +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + disable_interrupts(); + reset_cpu(0); + + /* NOTREACHED */ + return 0; +} + +void icache_enable(void) +{ + ulong reg; + + reg = read_p15_c1(); /* get control reg. */ + cp_delay(); + write_p15_c1(reg | C1_IC); +} + +void icache_disable(void) +{ + ulong reg; + + reg = read_p15_c1(); + cp_delay(); + write_p15_c1(reg & ~C1_IC); +} + +void dcache_disable (void) +{ + ulong reg; + + reg = read_p15_c1 (); + cp_delay (); + write_p15_c1 (reg & ~C1_DC); +} + +#ifndef CONFIG_U8500 +void l2cache_enable() +{ + unsigned long i; + volatile unsigned int j; + + /* ES2 onwards we can disable/enable L2 ourselves */ + if (get_cpu_rev() == CPU_3430_ES2) { + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(i)); + __asm__ __volatile__("orr %0, %0, #0x2":"=r"(i)); + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1":"=r"(i)); + } else { + /* Save r0, r12 and restore them after usage */ + __asm__ __volatile__("mov %0, r12":"=r"(j)); + __asm__ __volatile__("mov %0, r0":"=r"(i)); + + /* + * GP Device ROM code API usage here + * r12 = AUXCR Write function and r0 value + */ + __asm__ __volatile__("mov r12, #0x3"); + __asm__ __volatile__("mrc p15, 0, r0, c1, c0, 1"); + __asm__ __volatile__("orr r0, r0, #0x2"); + /* SMI instruction to call ROM Code API */ + __asm__ __volatile__(".word 0xE1600070"); + __asm__ __volatile__("mov r0, %0":"=r"(i)); + __asm__ __volatile__("mov r12, %0":"=r"(j)); + } +} +#endif + +void l2cache_disable() +{ +#ifndef CONFIG_U8500 + unsigned long i; + volatile unsigned int j; + + /* ES2 onwards we can disable/enable L2 ourselves */ + if (get_cpu_rev() == CPU_3430_ES2) { + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(i)); + __asm__ __volatile__("bic %0, %0, #0x2":"=r"(i)); + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1":"=r"(i)); + } else { + /* Save r0, r12 and restore them after usage */ + __asm__ __volatile__("mov %0, r12":"=r"(j)); + __asm__ __volatile__("mov %0, r0":"=r"(i)); + + /* + * GP Device ROM code API usage here + * r12 = AUXCR Write function and r0 value + */ + __asm__ __volatile__("mov r12, #0x3"); + __asm__ __volatile__("mrc p15, 0, r0, c1, c0, 1"); + __asm__ __volatile__("bic r0, r0, #0x2"); + /* SMI instruction to call ROM Code API */ + __asm__ __volatile__(".word 0xE1600070"); + __asm__ __volatile__("mov r0, %0":"=r"(i)); + __asm__ __volatile__("mov r12, %0":"=r"(j)); + } +#endif +} + +int icache_status(void) +{ + return (read_p15_c1() & C1_IC) != 0; +} + +static void cache_flush(void) +{ + asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); +} + diff --git a/cpu/arm_cortexa9/start.S b/cpu/arm_cortexa9/start.S new file mode 100755 index 000000000..62c9e5a53 --- /dev/null +++ b/cpu/arm_cortexa9/start.S @@ -0,0 +1,524 @@ +/* + * armboot - Startup Code for OMAP3530/ARM Cortex CPU-core + * + * Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com> + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim@ti.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 + */ + +#include <config.h> +#include <version.h> + +.globl _start +_start: b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: .word undefined_instruction +_software_interrupt: .word software_interrupt +_prefetch_abort: .word prefetch_abort +_data_abort: .word data_abort +_not_used: .word not_used +_irq: .word irq +_fiq: .word fiq +_pad: .word 0x12345678 /* now 16*4=64 */ +.global _end_vect +_end_vect: + + .balignl 16,0xdeadbeef +/************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + *************************************************************************/ + +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr,r0 + +#if (CONFIG_OMAP34XX) + /* Copy vectors to mask ROM indirect addr */ + adr r0, _start @ r0 <- current position of code + add r0, r0, #4 @ skip reset vector + mov r2, #64 @ r2 <- size to copy + add r2, r0, r2 @ r2 <- source end address + mov r1, #SRAM_OFFSET0 @ build vect addr + mov r3, #SRAM_OFFSET1 + add r1, r1, r3 + mov r3, #SRAM_OFFSET2 + add r1, r1, r3 +next: + ldmia r0!, {r3 - r10} @ copy from source address [r0] + stmia r1!, {r3 - r10} @ copy to target address [r1] + cmp r0, r2 @ until source end address [r2] + bne next @ loop until equal */ +#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) + /* No need to copy/exec the clock code - DPLL adjust already done + * in NAND/oneNAND Boot. + */ + bl cpy_clk_code @ put dpll adjust code behind vectors +#endif /* NAND Boot */ +#endif + /* the mask ROM code should have PLL and others stable */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif + +#ifndef CONFIG_SKIP_RELOCATE_UBOOT +relocate: @ relocate U-Boot to RAM + adr r0, _start @ r0 <- current position of code + ldr r1, _TEXT_BASE @ test if we run from flash or RAM + cmp r0, r1 @ don't reloc during debug + beq stack_setup + + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 @ r2 <- size of armboot + add r2, r0, r2 @ r2 <- source end address + +copy_loop: @ copy 32 bytes at a time + ldmia r0!, {r3 - r10} @ copy from source address [r0] + stmia r1!, {r3 - r10} @ copy to target address [r1] + cmp r0, r2 @ until source end addreee [r2] + ble copy_loop +#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ + + /* Set up the stack */ +stack_setup: + ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot + sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area + sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo +#ifdef CONFIG_USE_IRQ + sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) +#endif + sub sp, r0, #12 @ leave 3 words for abort-stack + and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d + + /* Clear BSS (if any). Is below tx (watch load addr - need space) */ +clear_bss: + ldr r0, _bss_start @ find start of bss segment + ldr r1, _bss_end @ stop here + mov r2, #0x00000000 @ clear value +clbss_l: + str r2, [r0] @ clear BSS location + cmp r0, r1 @ are we at the end yet + add r0, r0, #4 @ increment clear index pointer + bne clbss_l @ keep clearing till at end + + ldr pc, _start_armboot @ jump to C code + +_start_armboot: .word start_armboot + + +/************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + *************************************************************************/ +cpu_init_crit: + /* + * Invalidate L1 I/D + */ + mov r0, #0 @ set up for MCR + mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, r0, c7, c5, 0 @ invalidate icache + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002000 @ clear bits 13 (--V-) + bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) + orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align + orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB + mcr p15, 0, r0, c1, c0, 0 + + /* + * Jump to board specific initialization... + * The Mask ROM will have already initialized + * basic memory. Go here to bump up clock rate and handle + * wake up conditions. + */ + mov ip, lr @ persevere link reg across call +#ifndef CONFIG_U8500 + bl lowlevel_init @ go setup pll,mux,memory +#endif + mov lr, ip @ restore link + mov pc, lr @ back to my caller +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current + @ user stack + stmia sp, {r0 - r12} @ Save user registers (now in + @ svc mode) r0-r12 + + ldr r2, _armboot_start + sub r2, r2, #(CONFIG_SYS_MALLOC_LEN) + sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ set base 2 words into abort + @ stack + ldmia r2, {r2 - r3} @ get values for "aborted" pc + @ and cpsr (into parm regs) + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack + + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 + @ (param register) + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC @ !! R8 NEEDS to be saved !! + @ a reserved stack spot would + @ be good. + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC + mrs r6, spsr + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + subs pc, lr, #4 @ return & move spsr_svc into + @ cpsr + .endm + + .macro get_bad_stack + ldr r13, _armboot_start @ setup our mode stack (enter + @ in banked mode) + sub r13, r13, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool + sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move to reserved a couple + @ spots for abort stack + + str lr, [r13] @ save caller lr in position 0 + @ of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of + @ saved stack + + mov r13, #MODE_SVC @ prepare SVC-Mode + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure + @ moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & + @ switch modes. + .endm + + .macro get_bad_stack_swi + sub r13, r13, #4 @ space on current stack for + @ scratch reg. + str r0, [r13] @ save R0's value. + ldr r0, _armboot_start @ get data regions start + sub r0, r0, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool + sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move past gbl and a couple + @ spots for abort stack + str lr, [r0] @ save caller lr in position 0 + @ of saved stack + mrs r0, spsr @ get the spsr + str lr, [r0, #4] @ save spsr in position 1 of + @ saved stack + ldr r0, [r13] @ restore r0 + add r13, r13, #4 @ pop stack entry + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm + +/* + * exception handlers + */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack_swi + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + +#ifdef CONFIG_USE_IRQ + + .align 5 +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effective fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs + +#else + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq + +#endif + +/* + * v7_flush_dcache_all() + * + * Flush the whole D-cache. + * + * Corrupted registers: r0-r5, r7, r9-r11 + * + * - mm - mm_struct describing address space + */ + .align 5 +.global v7_flush_dcache_all +v7_flush_dcache_all: + stmfd r13!, {r0 - r5, r7, r9 - r12, r14} + + mov r7, r0 @ take a backup of device type + cmp r0, #0x3 @ check if the device type is + @ GP + moveq r12, #0x1 @ set up to invalide L2 +smi: .word 0x01600070 @ Call SMI monitor (smieq) + cmp r7, #0x3 @ compare again in case its + @ lost + beq finished_inval @ if GP device, inval done + @ above + + mrc p15, 1, r0, c0, c0, 1 @ read clidr + ands r3, r0, #0x7000000 @ extract loc from clidr + mov r3, r3, lsr #23 @ left align loc bit field + beq finished_inval @ if loc is 0, then no need to + @ clean + mov r10, #0 @ start clean at cache level 0 +inval_loop1: + add r2, r10, r10, lsr #1 @ work out 3x current cache + @ level + mov r1, r0, lsr r2 @ extract cache type bits from + @ clidr + and r1, r1, #7 @ mask of the bits for current + @ cache only + cmp r1, #2 @ see what cache we have at + @ this level + blt skip_inval @ skip if no cache, or just + @ i-cache + mcr p15, 2, r10, c0, c0, 0 @ select current cache level + @ in cssr + mov r2, #0 @ operand for mcr SBZ + mcr p15, 0, r2, c7, c5, 4 @ flush prefetch buffer to + @ sych the new cssr&csidr, + @ with armv7 this is 'isb', + @ but we compile with armv5 + mrc p15, 1, r1, c0, c0, 0 @ read the new csidr + and r2, r1, #7 @ extract the length of the + @ cache lines + add r2, r2, #4 @ add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 @ find maximum number on the + @ way size + clz r5, r4 @ find bit position of way + @ size increment + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ extract max number of the + @ index size +inval_loop2: + mov r9, r4 @ create working copy of max + @ way size +inval_loop3: + orr r11, r10, r9, lsl r5 @ factor way and cache number + @ into r11 + orr r11, r11, r7, lsl r2 @ factor index number into r11 + mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way + subs r9, r9, #1 @ decrement the way + bge inval_loop3 + subs r7, r7, #1 @ decrement the index + bge inval_loop2 +skip_inval: + add r10, r10, #2 @ increment cache number + cmp r3, r10 + bgt inval_loop1 +finished_inval: + mov r10, #0 @ swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 @ select current cache level + @ in cssr + mcr p15, 0, r10, c7, c5, 4 @ flush prefetch buffer, + @ with armv7 this is 'isb', + @ but we compile with armv5 + + ldmfd r13!, {r0 - r5, r7, r9 - r12, pc} + + + .align 5 +.global reset_cpu +reset_cpu: +#if defined CONFIG_U8500 + ldr r0, =CFG_PRCMU_BASE + ldr r1, =0x1 + str r1, [r0, #0x1F0] +#else + ldr r1, rstctl @ get addr for global reset + @ reg + mov r3, #0x2 @ full reset pll + mpu + str r3, [r1] @ force reset + mov r0, r0 +#endif +_loop_forever: + b _loop_forever +rstctl: + .word 0x48307250 diff --git a/cpu/arm_cortexa9/start.S.bak b/cpu/arm_cortexa9/start.S.bak new file mode 100755 index 000000000..6bd65521b --- /dev/null +++ b/cpu/arm_cortexa9/start.S.bak @@ -0,0 +1,502 @@ +/* + * armboot - Startup Code for OMAP3530/ARM Cortex CPU-core + * + * Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com> + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim@ti.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 + */ + +#include <config.h> +#include <version.h> + +.globl _start +_start: b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: .word undefined_instruction +_software_interrupt: .word software_interrupt +_prefetch_abort: .word prefetch_abort +_data_abort: .word data_abort +_not_used: .word not_used +_irq: .word irq +_fiq: .word fiq +_pad: .word 0x12345678 /* now 16*4=64 */ +.global _end_vect +_end_vect: + + .balignl 16,0xdeadbeef +/************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + *************************************************************************/ + +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr,r0 + +#if (CONFIG_OMAP34XX) + /* Copy vectors to mask ROM indirect addr */ + adr r0, _start @ r0 <- current position of code + add r0, r0, #4 @ skip reset vector + mov r2, #64 @ r2 <- size to copy + add r2, r0, r2 @ r2 <- source end address + mov r1, #SRAM_OFFSET0 @ build vect addr + mov r3, #SRAM_OFFSET1 + add r1, r1, r3 + mov r3, #SRAM_OFFSET2 + add r1, r1, r3 +next: + ldmia r0!, {r3 - r10} @ copy from source address [r0] + stmia r1!, {r3 - r10} @ copy to target address [r1] + cmp r0, r2 @ until source end address [r2] + bne next @ loop until equal */ +#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) + /* No need to copy/exec the clock code - DPLL adjust already done + * in NAND/oneNAND Boot. + */ + bl cpy_clk_code @ put dpll adjust code behind vectors +#endif /* NAND Boot */ +#endif + /* the mask ROM code should have PLL and others stable */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif + +#ifndef CONFIG_SKIP_RELOCATE_UBOOT +relocate: @ relocate U-Boot to RAM + adr r0, _start @ r0 <- current position of code + ldr r1, _TEXT_BASE @ test if we run from flash or RAM + cmp r0, r1 @ don't reloc during debug + beq stack_setup + + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 @ r2 <- size of armboot + add r2, r0, r2 @ r2 <- source end address + +copy_loop: @ copy 32 bytes at a time + ldmia r0!, {r3 - r10} @ copy from source address [r0] + stmia r1!, {r3 - r10} @ copy to target address [r1] + cmp r0, r2 @ until source end addreee [r2] + ble copy_loop +#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ + + /* Set up the stack */ +stack_setup: + ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot + sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area + sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo +#ifdef CONFIG_USE_IRQ + sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) +#endif + sub sp, r0, #12 @ leave 3 words for abort-stack + and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d + + /* Clear BSS (if any). Is below tx (watch load addr - need space) */ +clear_bss: + ldr r0, _bss_start @ find start of bss segment + ldr r1, _bss_end @ stop here + mov r2, #0x00000000 @ clear value +clbss_l: + str r2, [r0] @ clear BSS location + cmp r0, r1 @ are we at the end yet + add r0, r0, #4 @ increment clear index pointer + bne clbss_l @ keep clearing till at end + + ldr pc, _start_armboot @ jump to C code + +_start_armboot: .word start_armboot + + +/************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + *************************************************************************/ +cpu_init_crit: + /* + * Invalidate L1 I/D + */ + mov r0, #0 @ set up for MCR + mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, r0, c7, c5, 0 @ invalidate icache + + /* + * disable MMU stuff and caches + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002000 @ clear bits 13 (--V-) + bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) + orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align + orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB + mcr p15, 0, r0, c1, c0, 0 + + /* + * Jump to board specific initialization... + * The Mask ROM will have already initialized + * basic memory. Go here to bump up clock rate and handle + * wake up conditions. + */ + mov ip, lr @ persevere link reg across call + bl lowlevel_init @ go setup pll,mux,memory + mov lr, ip @ restore link + mov pc, lr @ back to my caller +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current + @ user stack + stmia sp, {r0 - r12} @ Save user registers (now in + @ svc mode) r0-r12 + + ldr r2, _armboot_start + sub r2, r2, #(CONFIG_SYS_MALLOC_LEN) + sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ set base 2 words into abort + @ stack + ldmia r2, {r2 - r3} @ get values for "aborted" pc + @ and cpsr (into parm regs) + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack + + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 + @ (param register) + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + add r8, sp, #S_PC @ !! R8 NEEDS to be saved !! + @ a reserved stack spot would + @ be good. + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC + mrs r6, spsr + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + subs pc, lr, #4 @ return & move spsr_svc into + @ cpsr + .endm + + .macro get_bad_stack + ldr r13, _armboot_start @ setup our mode stack (enter + @ in banked mode) + sub r13, r13, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool + sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move to reserved a couple + @ spots for abort stack + + str lr, [r13] @ save caller lr in position 0 + @ of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of + @ saved stack + + mov r13, #MODE_SVC @ prepare SVC-Mode + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure + @ moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & + @ switch modes. + .endm + + .macro get_bad_stack_swi + sub r13, r13, #4 @ space on current stack for + @ scratch reg. + str r0, [r13] @ save R0's value. + ldr r0, _armboot_start @ get data regions start + sub r0, r0, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool + sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move past gbl and a couple + @ spots for abort stack + str lr, [r0] @ save caller lr in position 0 + @ of saved stack + mrs r0, spsr @ get the spsr + str lr, [r0, #4] @ save spsr in position 1 of + @ saved stack + ldr r0, [r13] @ restore r0 + add r13, r13, #4 @ pop stack entry + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm + +/* + * exception handlers + */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack_swi + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + +#ifdef CONFIG_USE_IRQ + + .align 5 +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effective fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs + +#else + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq + +#endif + +/* + * v7_flush_dcache_all() + * + * Flush the whole D-cache. + * + * Corrupted registers: r0-r5, r7, r9-r11 + * + * - mm - mm_struct describing address space + */ + .align 5 +.global v7_flush_dcache_all +v7_flush_dcache_all: + stmfd r13!, {r0 - r5, r7, r9 - r12, r14} + + mov r7, r0 @ take a backup of device type + cmp r0, #0x3 @ check if the device type is + @ GP + moveq r12, #0x1 @ set up to invalide L2 +smi: .word 0x01600070 @ Call SMI monitor (smieq) + cmp r7, #0x3 @ compare again in case its + @ lost + beq finished_inval @ if GP device, inval done + @ above + + mrc p15, 1, r0, c0, c0, 1 @ read clidr + ands r3, r0, #0x7000000 @ extract loc from clidr + mov r3, r3, lsr #23 @ left align loc bit field + beq finished_inval @ if loc is 0, then no need to + @ clean + mov r10, #0 @ start clean at cache level 0 +inval_loop1: + add r2, r10, r10, lsr #1 @ work out 3x current cache + @ level + mov r1, r0, lsr r2 @ extract cache type bits from + @ clidr + and r1, r1, #7 @ mask of the bits for current + @ cache only + cmp r1, #2 @ see what cache we have at + @ this level + blt skip_inval @ skip if no cache, or just + @ i-cache + mcr p15, 2, r10, c0, c0, 0 @ select current cache level + @ in cssr + mov r2, #0 @ operand for mcr SBZ + mcr p15, 0, r2, c7, c5, 4 @ flush prefetch buffer to + @ sych the new cssr&csidr, + @ with armv7 this is 'isb', + @ but we compile with armv5 + mrc p15, 1, r1, c0, c0, 0 @ read the new csidr + and r2, r1, #7 @ extract the length of the + @ cache lines + add r2, r2, #4 @ add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 @ find maximum number on the + @ way size + clz r5, r4 @ find bit position of way + @ size increment + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ extract max number of the + @ index size +inval_loop2: + mov r9, r4 @ create working copy of max + @ way size +inval_loop3: + orr r11, r10, r9, lsl r5 @ factor way and cache number + @ into r11 + orr r11, r11, r7, lsl r2 @ factor index number into r11 + mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way + subs r9, r9, #1 @ decrement the way + bge inval_loop3 + subs r7, r7, #1 @ decrement the index + bge inval_loop2 +skip_inval: + add r10, r10, #2 @ increment cache number + cmp r3, r10 + bgt inval_loop1 +finished_inval: + mov r10, #0 @ swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 @ select current cache level + @ in cssr + mcr p15, 0, r10, c7, c5, 4 @ flush prefetch buffer, + @ with armv7 this is 'isb', + @ but we compile with armv5 + + ldmfd r13!, {r0 - r5, r7, r9 - r12, pc} diff --git a/cpu/arm_cortexa9/stw8500/Makefile b/cpu/arm_cortexa9/stw8500/Makefile new file mode 100755 index 000000000..6e0fe8af4 --- /dev/null +++ b/cpu/arm_cortexa9/stw8500/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS = timer.o interrupts.o + +SRCS := $(START:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm_cortexa9/stw8500/interrupts.c b/cpu/arm_cortexa9/stw8500/interrupts.c new file mode 100755 index 000000000..4357ede39 --- /dev/null +++ b/cpu/arm_cortexa9/stw8500/interrupts.c @@ -0,0 +1,181 @@ +/* + * (C) Copyright 2006, NXP BV + * Jean-Paul Saman + * + * (C) Copyright 2004 + * Texas Instruments + * Richard Woodruff <r-woodruff2@ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * 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/arch/bits.h> +#include <asm/proc-armv/ptrace.h> + +extern void reset_cpu(ulong addr); + +#ifdef CONFIG_USE_IRQ +/* enable IRQ interrupts */ +void enable_interrupts (void) +{ + unsigned long temp; + __asm__ __volatile__("mrs %0, cpsr\n" + "bic %0, %0, #0x80\n" + "msr cpsr_c, %0" + : "=r" (temp) + : + : "memory"); +} + +/* + * disable IRQ/FIQ interrupts + * returns true if interrupts had been enabled before we disabled them + */ +int disable_interrupts (void) +{ + unsigned long old,temp; + __asm__ __volatile__("mrs %0, cpsr\n" + "orr %1, %0, #0xc0\n" + "msr cpsr_c, %1" + : "=r" (old), "=r" (temp) + : + : "memory"); + return(old & 0x80) == 0; +} +#else +void enable_interrupts (void) +{ + return; +} +int disable_interrupts (void) +{ + return 0; +} +#endif + + +void bad_mode (void) +{ + panic ("Resetting CPU ...\n"); + reset_cpu (0); +} + +void show_regs (struct pt_regs *regs) +{ + unsigned long flags; + const char *processor_modes[] = { + "USER_26", "FIQ_26", "IRQ_26", "SVC_26", + "UK4_26", "UK5_26", "UK6_26", "UK7_26", + "UK8_26", "UK9_26", "UK10_26", "UK11_26", + "UK12_26", "UK13_26", "UK14_26", "UK15_26", + "USER_32", "FIQ_32", "IRQ_32", "SVC_32", + "UK4_32", "UK5_32", "UK6_32", "ABT_32", + "UK8_32", "UK9_32", "UK10_32", "UND_32", + "UK12_32", "UK13_32", "UK14_32", "SYS_32", + }; + + flags = condition_codes (regs); + + printf ("pc : [<%08lx>] lr : [<%08lx>]\n" + "sp : %08lx ip : %08lx fp : %08lx\n", + instruction_pointer (regs), + regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); + printf ("r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); + printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); + printf ("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); + printf ("Flags: %c%c%c%c", + flags & CC_N_BIT ? 'N' : 'n', + flags & CC_Z_BIT ? 'Z' : 'z', + flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v'); + printf (" IRQs %s FIQs %s Mode %s%s\n", + interrupts_enabled (regs) ? "on" : "off", + fast_interrupts_enabled (regs) ? "on" : "off", + processor_modes[processor_mode (regs)], + thumb_mode (regs) ? " (T)" : ""); +} + +void do_undefined_instruction (struct pt_regs *pt_regs) +{ + printf ("undefined instruction\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_software_interrupt (struct pt_regs *pt_regs) +{ + printf ("software interrupt\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_prefetch_abort (struct pt_regs *pt_regs) +{ + printf ("prefetch abort\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_data_abort (struct pt_regs *pt_regs) +{ + printf ("data abort\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_not_used (struct pt_regs *pt_regs) +{ + printf ("not used\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_fiq (struct pt_regs *pt_regs) +{ + printf ("fast interrupt request\n"); + show_regs (pt_regs); + bad_mode (); +} + +void do_irq (struct pt_regs *pt_regs) +{ + printf ("interrupt request\n"); + show_regs (pt_regs); + bad_mode (); +} + +/* nothing really to do with interrupts, just starts up a counter. */ +int interrupt_init (void) +{ + + (void) timer_init(); + + return(0); +} diff --git a/cpu/arm_cortexa9/stw8500/timer.c b/cpu/arm_cortexa9/stw8500/timer.c new file mode 100755 index 000000000..16067c900 --- /dev/null +++ b/cpu/arm_cortexa9/stw8500/timer.c @@ -0,0 +1,70 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * 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/io.h> +#include <asm/arch/mtu.h> + +/* + * The timer is a decrementer, we'll left it free running at 2.4MHz. + * We have 2.4 ticks per microsecond and an overflow in almost 30min + */ +#define TIMER_CLOCK (24 * 100 * 1000) +#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */ +#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */ +#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) +#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) + +/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0))) + +/* Configure a free-running, auto-wrap counter with no prescaler */ +int timer_init(void) +{ + writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS, + CONFIG_SYS_TIMERBASE + MTU_CR(0)); + reset_timer(); + return 0; +} + +/* Restart counting from 0 */ +void reset_timer(void) +{ + writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); /* Immediate effect */ +} + +/* Return how many HZ passed since "base" */ +ulong get_timer(ulong base) +{ + return TICKS_TO_HZ(READ_TIMER()) - base; +} + +/* Delay x useconds */ +void udelay(unsigned long usec) +{ + ulong ini, end; + + ini = READ_TIMER(); + end = ini + USEC_TO_COUNT(usec); + while ((signed)(end - READ_TIMER()) > 0) + ; +} diff --git a/cpu/arm_cortexa9/u-boot.lds b/cpu/arm_cortexa9/u-boot.lds new file mode 100755 index 000000000..fc787cd5d --- /dev/null +++ b/cpu/arm_cortexa9/u-boot.lds @@ -0,0 +1,58 @@ +/* + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + cpu/arm_cortexa9/start.o (.text) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index c645cef87..839b0a812 100644..100755 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -144,6 +144,11 @@ int serial_init (void) IO_WRITE (port[CONSOLE_PORT] + UART_PL011_LCRH, (UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN)); +#ifdef CONFIG_U8500 + /* program receive line control register */ + IO_WRITE(port[CONSOLE_PORT] + 0x1C, 0x70); +#endif + /* ** Finally, enable the UART */ diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index f746d6317..c693dd5f0 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -27,6 +27,8 @@ #include <usbdevice.h> #if defined(CONFIG_PPC) #include <usb/mpc8xx_udc.h> +#elif defined(CONFIG_MUSB) +#include <usb/musb_udc.h> #elif defined(CONFIG_OMAP1510) #include <usb/omap1510_udc.h> #elif defined(CONFIG_PXA27X) diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 2a19b1e44..0f77319d0 100644..100755 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -32,6 +32,9 @@ COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o COBJS-$(CONFIG_PXA27X) += pxa27x_udc.o +COBJS-$(CONFIG_MUSB) += musb_udc.o +COBJS-$(CONFIG_TWL4030_USB) += twl4030_usb.o +COBJS-$(CONFIG_U8500) += u8500_udc.o endif COBJS := $(COBJS-y) diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c index 2b4ec44e1..2b4ec44e1 100644..100755 --- a/drivers/usb/gadget/ep0.c +++ b/drivers/usb/gadget/ep0.c diff --git a/drivers/usb/gadget/musb_udc.c b/drivers/usb/gadget/musb_udc.c new file mode 100755 index 000000000..a46a6e948 --- /dev/null +++ b/drivers/usb/gadget/musb_udc.c @@ -0,0 +1,813 @@ +/* + * (C) Copyright 2009 Texas Instruments Incorporated. + * + * Based on + * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) + * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + * Atin Malaviya (atin.malaviya@gmail.com) + * + * 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/io.h> +// #include <asm/arch/clocks.h> +// #include <asm/arch/clocks_omap3.h> +// #include <asm/arch/sys_proto.h> +#include <usbdevice.h> +#include <usb/musb_udc.h> +#include "ep0.h" + +/* Private definitions */ +enum ep0_status { IDLE, DATA_STAGE, DATA_COMPLETE }; + +/* Private variables */ +static struct usb_device_instance *udc_device; +static enum ep0_status ep0status = IDLE; +static unsigned char do_set_address = 0; +static struct urb *ep0_urb = NULL; + +/* Helper functions */ + +/* sr32 from cpu/arm_cortexa8/omap3/syslib.c */ +/***************************************************************** + * sr32 - clear & set a value in a bit range for a 32 bit address + *****************************************************************/ +static void sr32(void *addr, u32 start_bit, u32 num_bits, u32 value) +{ + u32 tmp, msk = 0; + msk = 1 << num_bits; + --msk; + tmp = readl((u32)addr) & ~(msk << start_bit); + tmp |= value << start_bit; + writel(tmp, (u32)addr); +} + +static void insl(u32 reg, u32 *data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++) + *data = inl(reg); +} + +static void outsl(u32 reg, u32 *data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++) + outl(*data, reg); +} + +static void outsb(u32 reg, u8 *data, u32 size) +{ + u32 t; + + for (t = 0; t < size; t++, data++) + outb(*data, reg); +} + +static void musb_fifo_read(int epnumber, u8 *data, u32 size) +{ + if ((u32)data & 0x3) { /* Not aligned data */ + insb((UDC_FIFO0 + (epnumber << 2)), data, size); + } else { /* 32 bits aligned data */ + int i; + + insl(UDC_FIFO0 + (epnumber << 2), (u32 *)data, size >> 2); + data += size & ~0x3; + i = size & 0x3; + while (i--) { + *data = inb(UDC_FIFO0 + (epnumber << 2)); + data++; + } + } +} + +static void musb_fifo_write(int epnumber, u8 *data, u32 size) +{ + if ((u32)data & 0x3) { /* Not aligned data */ + outsb(UDC_FIFO0 + (epnumber << 2), data, size); + } else { /* 32 bits aligned data */ + int i; + + outsl(UDC_FIFO0 + (epnumber << 2), (u32 *)data, size >> 2); + data += size & ~0x3; + i = size & 0x3; + while (i--) { + outb(*data, UDC_FIFO0 + (epnumber << 2)); + data++; + } + } +} + +static void musb_fifos_configure(struct usb_device_instance *device) +{ + int ep; + struct usb_bus_instance *bus; + struct usb_endpoint_instance *endpoint; + unsigned short ep_ptr, ep_size, ep_doublebuffer; + int ep_addr, packet_size, buffer_size, attributes; + + bus = device->bus; + + ep_ptr = 0; + + for (ep = 0; ep < bus->max_endpoints; ep++) { + endpoint = bus->endpoint_array + ep; + ep_addr = endpoint->endpoint_address; + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + packet_size = endpoint->tx_packetSize; + attributes = endpoint->tx_attributes; + } else { + /* OUT endpoint */ + packet_size = endpoint->rcv_packetSize; + attributes = endpoint->rcv_attributes; + } + + switch (packet_size) { + case 0: + ep_size = 0; + break; + case 8: + ep_size = 0; + break; + case 16: + ep_size = 1; + break; + case 32: + ep_size = 2; + break; + case 64: + ep_size = 3; + break; + case 128: + ep_size = 4; + break; + case 256: + ep_size = 5; + break; + case 512: + ep_size = 6; + break; + default: + serial_printf("ep 0x%02x has bad packet size %d", + ep_addr, packet_size); + packet_size = 0; + ep_size = 0; + break; + } + + switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + default: + /* A non-isochronous endpoint may optionally be + * double-buffered. For now we disable + * double-buffering. + */ + ep_doublebuffer = 0; + if (packet_size > 64) + packet_size = 0; + if (!ep || !ep_doublebuffer) + buffer_size = packet_size; + else + buffer_size = packet_size * 2; + break; + case USB_ENDPOINT_XFER_ISOC: + /* Isochronous endpoints are always double- + * buffered + */ + ep_doublebuffer = 1; + buffer_size = packet_size * 2; + break; + } + + /* check to see if our packet buffer RAM is exhausted */ + if ((ep_ptr + buffer_size) > UDC_MAX_FIFO_SIZE) { + serial_printf("out of packet RAM for ep 0x%02x buf size %d", + ep_addr, buffer_size); + buffer_size = packet_size = 0; + } + + /* force a default configuration for endpoint 0 since it is + * always enabled + */ + if (!ep && ((packet_size < 8) || (packet_size > 64))) { + buffer_size = packet_size = 64; + ep_size = 3; + } + + outb(ep & 0xF, UDC_INDEX); + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + outb((ep_doublebuffer << 4) | (ep_size & 0xf), + UDC_TXFIFOSZ); + outw(ep_ptr >> 3, UDC_TXFIFOADDR); + if (!ep) { /* This only apply for ep != 0 */ + outw(packet_size & 0x3FF, UDC_TXMAXP); + } + } else { + /* OUT endpoint */ + outb((ep_doublebuffer << 4) | (ep_size & 0xf), + UDC_RXFIFOSZ); + outw(ep_ptr >> 3, UDC_RXFIFOADDR); + if (!ep) { /* This only apply for ep != 0 */ + outw(packet_size & 0x3FF, UDC_RXMAXP); + } + } + ep_ptr += buffer_size; + } +} + +static void musb_ep0_tx(struct usb_endpoint_instance *endpoint) +{ + unsigned int size = 0; + struct urb *urb = endpoint->tx_urb; + + outb(0, UDC_INDEX); + + if (urb) { + + if ((size = + MIN(urb->actual_length - endpoint->sent, + endpoint->tx_packetSize))) { + + musb_fifo_write(0, urb->buffer + endpoint->sent, size); + } + endpoint->last = size; + + if (((endpoint->sent + size) == ep0_urb->device_request.wLength) + || (size != endpoint->tx_packetSize)) { + ep0status = DATA_COMPLETE; + /* Transmit packet and set data end */ + outw(0xA, UDC_CSR0); + } else { + outw(0x2, UDC_CSR0); /* Transmit packet */ + } + } +} + +static void musb_ep0_handler(struct usb_endpoint_instance *endpoint) +{ + u16 csr0; + + outb(0, UDC_INDEX); + + /* Check errors */ + csr0 = inw(UDC_CSR0); + + if (csr0 & 0x4) { /* Sent stall */ + outw(csr0 & ~0x4, UDC_CSR0); /* Clear stall */ + serial_printf("%s: stall received on EP0!, csr0 %hx\n", + __FUNCTION__, csr0); + csr0 = inw(UDC_CSR0); + serial_printf("state %d -> %d (IDLE), csr0 0x%hx\n", + ep0status, IDLE, csr0); + ep0status = IDLE; + } + + if (csr0 & 0x10) { /* Setup end */ + outw(0x80, UDC_CSR0); /* Clear setup end */ + serial_printf("%s: setup END early happened! status is %d\n", + __FUNCTION__, ep0status); + ep0status = IDLE; + return; + } + + switch (ep0status) { + case DATA_COMPLETE: + if (do_set_address) { + /* + * We need to set the address only after + * the status stage is complete + */ + outb(udc_device->address, UDC_FADDR); + do_set_address = 0; + } + ep0status = IDLE; + /* Fallthrough */ + case IDLE: /* Receiving a setup packet */ + if (csr0 & 0x1) { + insl(UDC_FIFO0, + (unsigned int *) &ep0_urb->device_request, 2); + + /* If we have data, then don't go to IDLE state */ + if (ep0_urb->device_request.wLength) { + ep0status = DATA_STAGE; + + outw(0x40, UDC_CSR0); /* Clear RXPKTRDY */ + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + + /* Try to process setup packet */ + if (ep0_recv_setup(ep0_urb)) { + /* + * Not a setup packet, stall + * next EP0 transaction + */ + outw(0x20, UDC_CSR0); + serial_printf("not a setup packed 1, stalling\n"); + ep0status = IDLE; + return; + } + /* + * If we are sending data, do it now, as + * ep0_recv_setup should have prepare + * them + */ + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + + musb_ep0_tx(endpoint); + } else { + endpoint->rcv_urb = ep0_urb; + ep0_urb->actual_length = 0; + } + } else { /* Processing zero-length packet */ + /* + * The www.linux-usb.org/usbtest 'test 14' + * fails with error for zero length request. + * If the SETUP packet requests ZERO length data + * from device-to-host, the TXPKTRDY bit needs + * to be set in TXCSR otherwise the STATUS stage + * of control transfer will never complete. + */ + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + /* + * Clear RXPKTRDY and DATAEND and + * TXPKTRDY + */ + outw(0x4A, UDC_CSR0); + } else { + /* Clear RXPKTRDY and DATAEND */ + outw(0x48, UDC_CSR0); + } + + /* Try to process setup packet */ + if (ep0_recv_setup(ep0_urb)) { + /* + * Not a setup packet, stall next EP0 + * transaction + */ + outw(0x20, UDC_CSR0); + serial_printf("not a setup packed 2, stalling\n"); + ep0status = IDLE; + return; + } + + switch (ep0_urb->device_request.bRequest) { + case USB_REQ_SET_ADDRESS: + usbd_device_event_irq(udc_device, + DEVICE_ADDRESS_ASSIGNED, 0); + do_set_address = 1; + break; + case USB_REQ_SET_CONFIGURATION: + usbd_device_event_irq(udc_device, + DEVICE_CONFIGURED, 0); + break; + } + + ep0status = DATA_COMPLETE; + } + } + break; + case DATA_STAGE: + if ((ep0_urb->device_request. + bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_DEVICE2HOST) { + if (!(csr0 & 0x2)) { /* There packet was send? */ + endpoint->sent += endpoint->last; + /* + * If we finished sending data we would not + * be on the DATA_STAGE + */ + musb_ep0_tx(endpoint); + } + } else { + /* Receiving data */ + u16 length = inw(UDC_COUNT0); + + if (length) { + if (ep0_urb->actual_length + length > + ep0_urb->device_request.wLength) + length = + ep0_urb->device_request.wLength - + ep0_urb->actual_length; + + endpoint->last = length; + + musb_fifo_read(0, &ep0_urb-> + buffer[ep0_urb->actual_length], length); + ep0_urb->actual_length += length; + } + + /* + * We finish if we received the amount of data expected, + * or less of the packet size + */ + if ((ep0_urb->actual_length == + ep0_urb->device_request.wLength) || + (endpoint->last != endpoint->tx_packetSize)) { + ep0status = DATA_COMPLETE; + /* Clear RXPKTRDY and DATAEND */ + outw(0x48, UDC_CSR0); + /* This will process the incoming data */ + if (ep0_recv_setup(ep0_urb)) { + /* + * Not a setup packet, stall next EP0 + * transaction + */ + outw(0x20, UDC_CSR0); + serial_printf("not a setup packed 3, stalling\n"); + return; + } + } else + outw(0x40, UDC_CSR0); /* Clear RXPKTRDY */ + } + break; + } +} + +static void musb_ep_tx(struct usb_endpoint_instance *endpoint) +{ + unsigned int size = 0, epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + struct urb *urb = endpoint->tx_urb; + + outb(epnumber, UDC_INDEX); + if (urb) { + if ((size = + MIN(urb->actual_length - endpoint->sent, + endpoint->tx_packetSize))) { + musb_fifo_write(epnumber, urb->buffer + endpoint->sent, + size); + } + endpoint->last = size; + endpoint->state = 1; /* Transmit hardware is busy */ + + outw(inw(UDC_TXCSR) | 0x1, UDC_TXCSR); /* Transmit packet */ + } +} + + +static void musb_tx_handler(struct usb_endpoint_instance *endpoint) +{ + unsigned int epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u16 txcsr; + + outb(epnumber, UDC_INDEX); + + /* Check errors */ + txcsr = inw(UDC_TXCSR); + + if (txcsr & 0x4) { /* Clear underrun */ + txcsr &= ~0x4; + } + if (txcsr & 0x20) { /* SENTSTALL */ + outw(txcsr & ~0x20, UDC_TXCSR); /* Clear stall */ + serial_printf("musb_tx_handler: SENTSTALL, txcsr 0x%hx\n", + txcsr); + return; + } + + if (endpoint->tx_urb && !(txcsr & 0x1)) { /* The packet was send? */ + if ((endpoint->sent + endpoint->last == endpoint->tx_urb-> + actual_length) /* Send a zero length packet? */ + && (endpoint->last == endpoint->tx_packetSize)) { + /* Prepare to transmit a zero-length packet. */ + endpoint->sent += endpoint->last; + musb_ep_tx(endpoint); + } else if (endpoint->tx_urb->actual_length) { + /* retire the data that was just sent */ + usbd_tx_complete(endpoint); + endpoint->state = 0; /* Transmit hardware is free */ + + /* + * Check to see if we have more data ready to transmit + * now. + */ + if (endpoint->tx_urb && endpoint->tx_urb-> + actual_length) { + musb_ep_tx(endpoint); + } + } + } +} + +static void musb_rx_handler(struct usb_endpoint_instance *endpoint) +{ + unsigned int epnumber = + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u16 rxcsr; + u16 length; + + outb(epnumber, UDC_INDEX); + + /* Check errors */ + rxcsr = inw(UDC_RXCSR); + + if (!(rxcsr & 0x1)) /* There is a package received? */ + return; + + if (rxcsr & 0x40) { /* SENTSTALL */ + outw(rxcsr & ~0x40, UDC_RXCSR); /* Clear stall */ + serial_printf("musb_rx_handler: SENTSTALL, rxcsr 0x%hx\n", + rxcsr); + return; + } + + length = inw(UDC_RXCOUNT); + + if (endpoint->rcv_urb) { + /* Receiving data */ + if (length) { + musb_fifo_read(epnumber, &endpoint->rcv_urb-> + buffer[endpoint->rcv_urb->actual_length], + length); + outw(rxcsr & ~0x1, UDC_RXCSR); /* Clear RXPKTRDY */ + usbd_rcv_complete(endpoint, length, 0); + } + } else { + serial_printf("%s: no receive URB!\n", __FUNCTION__); + } +} + +static void musb_reset(void) +{ + usbd_device_event_irq(udc_device, DEVICE_HUB_CONFIGURED, 0); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + ep0status = IDLE; + do_set_address = 0; +} + +/* Public functions - called by usbdcore, usbtty, etc. */ +void udc_irq(void) +{ + unsigned char int_usb = inb(UDC_INTRUSB); + unsigned short int_tx = inw(UDC_INTRTX); + unsigned short int_rx = inw(UDC_INTRRX); + int ep; + + if (int_usb) { + if (int_usb & 0x4) { /* Reset */ + /* The controller clears FADDR, INDEX, and FIFOs */ + musb_reset(); + } + if (int_usb & 0x20) { /* Disconnected */ + usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); + } + if (int_usb & 0x1) + usbd_device_event_irq(udc_device, + DEVICE_BUS_INACTIVE, 0); + if (int_usb & 0x2) + usbd_device_event_irq(udc_device, + DEVICE_BUS_ACTIVITY, 0); + } + + /* Note: IRQ values auto clear so read just before processing */ + if (int_rx) { /* OUT endpoints */ + ep = 1; + int_rx >>= 1; + while (int_rx) { + if (int_rx & 1) + musb_rx_handler(udc_device->bus->endpoint_array + + ep); + int_rx >>= 1; + ep++; + } + } + if (int_tx) { /* IN endpoints */ + if (int_tx & 1) + musb_ep0_handler(udc_device->bus->endpoint_array); + + ep = 1; + int_tx >>= 1; + while (int_tx) { + if (int_tx & 1) + musb_tx_handler(udc_device->bus->endpoint_array + + ep); + int_tx >>= 1; + ep++; + } + } +} + +/* Turn on the USB connection */ +void udc_connect(void) +{ + outb(0x1, UDC_DEVCTL); + + if (!(inb(UDC_DEVCTL) & 0x80)) { + serial_printf("Error, the USB hardware is not on B mode\n"); + outb(0x0, UDC_DEVCTL); + return; + } +} + +/* Turn off the USB connection */ +void udc_disconnect(void) +{ + if (!(inb(UDC_DEVCTL) & 0x80)) { + serial_printf("Error, the USB hardware is not on B mode"); + return; + } + + outb(0x0, UDC_DEVCTL); +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + /* Transmit only if the hardware is available */ + if (endpoint->tx_urb && endpoint->state == 0) + musb_ep_tx(endpoint); + + return 0; +} + +/* + * udc_setup_ep - setup endpoint + * + * Associate a physical endpoint with endpoint_instance + */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *endpoint) +{ + int ep_addr; + int attributes; + + /* + * We dont' have a way to identify if the endpoint definitions changed, + * so we have to always reconfigure the FIFOs to avoid problems + */ + musb_fifos_configure(device); + + ep_addr = endpoint->endpoint_address; + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + attributes = endpoint->tx_attributes; + } else { + /* OUT endpoint */ + attributes = endpoint->rcv_attributes; + } + + outb(ep & 0xF, UDC_INDEX); + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + if (!ep) { /* This only apply for ep != 0 */ + /* Empty fifo twice on case of previous double buffer */ + outw(1<<3, UDC_TXCSR); + outw(1<<3, UDC_TXCSR); + + if (attributes & USB_ENDPOINT_XFER_ISOC) + outw(inw(UDC_TXCSR) | (1 << 13) | (1 << 14) | + 0x4, UDC_TXCSR); + else + outw((inw(UDC_TXCSR) | (1 << 13) | 0x4) & + ~(1 << 14), UDC_TXCSR); + } + /* Enable interrupt */ + outw(inw(UDC_INTRTXE) | (1 << ep), UDC_INTRTXE); + } else { + /* OUT endpoint */ + if (!ep) { /* This only apply for ep != 0 */ + if (attributes & USB_ENDPOINT_XFER_ISOC) + outw((inw(UDC_RXCSR) | (1 << 14)) & ~(1 << 13), + UDC_RXCSR); + else + outw(inw(UDC_RXCSR) & ~(1 << 14) & ~(1 << 13), + UDC_RXCSR); + } + /* Enable interrupt */ + outw(inw(UDC_INTRRXE) | (1 << ep), UDC_INTRRXE); + } +} + +/* + * udc_startup_events - allow udc code to do any additional startup + */ +void udc_startup_events(struct usb_device_instance *device) +{ + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ + usbd_device_event_irq(device, DEVICE_INIT, 0); + + /* + * The DEVICE_CREATE event puts the USB device in the state + * STATE_ATTACHED. + */ + usbd_device_event_irq(device, DEVICE_CREATE, 0); + + /* + * Some USB controller driver implementations signal + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. + * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, + * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. + * The MUSB client controller has the capability to detect when the + * USB cable is connected to a powered USB bus, so we will defer the + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. + */ + + /* Save the device structure pointer */ + udc_device = device; + + /* Setup ep0 urb */ + if (!ep0_urb) { + ep0_urb = + usbd_alloc_urb(udc_device, udc_device->bus-> + endpoint_array); + } else { + serial_printf("udc_enable: ep0_urb already allocated %p\n", ep0_urb); + } + + /* Enable control interrupts */ + outb(0xf7, UDC_INTRUSBE); +} + +void udc_set_nak(int epid) +{ +/* + * On MUSB the NAKing is controlled by the USB controller buffers, + * so as long as we don't read data from the FIFO, the controller will NAK. + * Nothing to see here, move along... + */ +} + +void udc_unset_nak(int epid) +{ +/* + * On MUSB the NAKing is controlled by the USB controller buffers, + * so as long as we don't read data from the FIFO, the controller will NAK. + * Nothing to see here, move along... + */ +} + +/* Start to initialize h/w stuff */ +int udc_init(void) +{ + /* Clock is initialized on the board code */ + +#if 0 + /* XXX: this is platform specific, move to udc_musb_platform_init */ + /* MUSB soft-reset */ + outl(2, UDC_SYSCONFIG); + /* MUSB end any previous session */ + outb(0x0, UDC_DEVCTL); +#endif + + if (udc_musb_platform_init()) { + serial_printf("udc_init: platform init failed\n"); + return -1; + } + +#if 0 + /* XXX: this is platform specific, move to udc_musb_platform_init */ + outl(inl(UDC_FORCESTDBY) & ~1, UDC_FORCESTDBY); /* disable MSTANDBY */ + outl(inl(UDC_SYSCONFIG) | (2<<12), UDC_SYSCONFIG); /* ena SMARTSTDBY */ + outl(inl(UDC_SYSCONFIG) & ~1, UDC_SYSCONFIG); /* disable AUTOIDLE */ + outl(inl(UDC_SYSCONFIG) | (2<<3), UDC_SYSCONFIG); /* enable SMARTIDLE */ + outl(inl(UDC_SYSCONFIG) | 1, UDC_SYSCONFIG); /* enable AUTOIDLE */ + + /* Configure the PHY as PHY interface is 12-pin, 8-bit SDR ULPI */ + sr32((void *)UDC_INTERFSEL, 0, 1, 1); +#endif + +#if 0 + /* Turn off interrupts */ + outw(0x00, UDC_INTRTXE); + outw(0x00, UDC_INTRRXE); + +#if CONFIG_MUSB_FULL_SPEED + /* + * Use Full speed for debugging proposes, useful so most USB + * analyzers can catch the transactions + */ + outb(0, UDC_POWER); + serial_printf("MUSB: using full speed\n"); +#else + serial_printf("MUSB: using high speed\n"); +#endif +#endif + + return 0; +} diff --git a/drivers/usb/gadget/u8500_udc.c b/drivers/usb/gadget/u8500_udc.c new file mode 100755 index 000000000..109e11dda --- /dev/null +++ b/drivers/usb/gadget/u8500_udc.c @@ -0,0 +1,61 @@ +/* + * u8500_udc.c - + * + * (C) Copyright 2009 ST-Ericsson + * + * 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 "u8500_udc.h" +#include <asm/arch/gpio.h> + +static volatile struct mg_dev_register *pRegs = 0; + +int udc_musb_platform_init(void) +{ + u16 top; + u8 power; + u8 soft_reset; + u16 temp; + pRegs = (volatile struct mg_dev_register *) CONFIG_USB_BASE; + + gpio_altfuncenable(GPIO_ALT_USB_OTG, "USB-OTG"); + + top = pRegs->OTG_TOPCTRL; + pRegs->OTG_TOPCTRL = (top | MODE_ULPI); + + soft_reset = pRegs->OTG_SOFTRST; + pRegs->OTG_SOFTRST = (soft_reset | 0x2); + + power = pRegs->OTG_PWR; + /* Enabling high speed and soft connection */ + power = power | POWER_HSENAB; + pRegs->OTG_PWR = (power | POWER_SOFTCONN); + + pRegs->OTG_INTUSBEN = 0x0; + pRegs->OTG_INTTXEN = 0x0; + pRegs->OTG_INTRXEN = 0x0; + + /* off */ + pRegs->OTG_DEVCTL = 0x0; + + /* flush pending interrupts */ + temp = pRegs->OTG_INTUSB; + temp = pRegs->OTG_INTTX; + temp = pRegs->OTG_INTRX; + return 0; +} diff --git a/drivers/usb/gadget/u8500_udc.h b/drivers/usb/gadget/u8500_udc.h new file mode 100755 index 000000000..f42c0686a --- /dev/null +++ b/drivers/usb/gadget/u8500_udc.h @@ -0,0 +1,484 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef __MUSB_UDC_H__ +#define __MUSB_UDC_H__ + +#include <linux/byteorder/little_endian.h> +#include <linux/byteorder/generic.h> + +/* Endpoint parameters */ +#define EP_MAX_PACKET_SIZE 512 + +#define EP0_MAX_PACKET_SIZE 64 +#define UDC_OUT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_IN_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_INT_PACKET_SIZE EP_MAX_PACKET_SIZE//64 +#define UDC_BULK_PACKET_SIZE EP_MAX_PACKET_SIZE + + +/* Get offset for a given FIFO */ +#define FIFO_OFFSET(_bEnd) (0x20 + (_bEnd * 4)) + +/* Endpoint 0 states */ +#define END0_STAGE_SETUP 0x0 +#define END0_STAGE_TX 0x1 +#define END0_STAGE_RX 0x2 +#define END0_STAGE_STATUSIN 0x3 +#define END0_STAGE_STATUSOUT 0x4 +#define END0_STAGE_STALL_BIT 0x10 + +/* offsets to registers in flat model */ + +#define HDRC_TXMAXP 0x00 +#define HDRC_TXCSR 0x02 +#define HDRC_CSR0 HDRC_TXCSR /* re-used for EP0 */ +#define HDRC_RXMAXP 0x04 +#define HDRC_RXCSR 0x06 +#define HDRC_RXCOUNT 0x08 +#define HDRC_COUNT0 HDRC_RXCOUNT /* re-used for EP0 */ +#define HDRC_TXTYPE 0x0A +#define HDRC_TYPE0 HDRC_TXTYPE /* re-used for EP0 */ +#define HDRC_TXINTERVAL 0x0B +#define HDRC_NAKLIMIT0 HDRC_TXINTERVAL /* re-used for EP0 */ +#define HDRC_RXTYPE 0x0C +#define HDRC_RXINTERVAL 0x0D +#define HDRC_INDEX 0x0E +#define HDRC_FIFOSIZE 0x0F +#define HDRC_CONFIGDATA HDRC_FIFOSIZE /* re-used for EP0 */ + +/* INTRUSB */ +#define INTR_SUSPEND 0x01 +#define INTR_RESUME 0x02 +#define INTR_RESET 0x04 +#define INTR_BABBLE 0x04 +#define INTR_SOF 0x08 +#define INTR_CONNECT 0x10 +#define INTR_DISCONNECT 0x20 +#define INTR_SESSREQ 0x40 +#define INTR_VBUSERROR 0x80 /* FOR SESSION END */ +#define INTR_EP0 0x01 /* FOR EP0 INTERRUPT */ + +/* CONFIGDATA */ + +#define CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */ +#define CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */ +#define CONFIGDATA_BIGENDIAN 0x20 +#define CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ +#define CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ +#define CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */ +#define CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ +#define CONFIGDATA_UTMIDW 0x01 /* data width 0 => 8bits, 1 => 16bits */ + +/* DEVCTL */ +#define DEVCTL_BDEVICE 0x80 +#define DEVCTL_FSDEV 0x40 +#define DEVCTL_LSDEV 0x20 +#define DEVCTL_VBUS 0x18 +#define DEVCTL_HM 0x04 +#define DEVCTL_HR 0x02 +#define DEVCTL_SESSION 0x01 + +/* TXCSR in Peripheral mode */ + +#define TXCSR_AUTOSET 0x8000 +#define TXCSR_ISO 0x4000 +#define TXCSR_MODE 0x2000 +#define TXCSR_DMAENAB 0x1000 +#define TXCSR_FRCDATATOG 0x0800 +#define TXCSR_DMAMODE 0x0400 +#define TXCSR_CLRDATATOG 0x0040 +#define TXCSR_FLUSHFIFO 0x0008 +#define TXCSR_FIFONOTEMPTY 0x0002 +#define TXCSR_TXPKTRDY 0x0001 + +#define TXCSR_P_INCOMPTX 0x0080 +#define TXCSR_P_SENTSTALL 0x0020 +#define TXCSR_P_SENDSTALL 0x0010 +#define TXCSR_P_UNDERRUN 0x0004 + +/* RXCSR in Peripheral */ + +#define RXCSR_AUTOCLEAR 0x8000 +#define RXCSR_DMAENAB 0x2000 +#define RXCSR_DISNYET 0x1000 +#define RXCSR_DMAMODE 0x0800 +#define RXCSR_INCOMPRX 0x0100 +#define RXCSR_CLRDATATOG 0x0080 +#define RXCSR_FLUSHFIFO 0x0010 +#define RXCSR_DATAERROR 0x0008 +#define RXCSR_FIFOFULL 0x0002 +#define RXCSR_RXPKTRDY 0x0001 + + +#define RXCSR_P_ISO 0x4000 +#define RXCSR_P_SENTSTALL 0x0040 +#define RXCSR_P_SENDSTALL 0x0020 +#define RXCSR_P_OVERRUN 0x0004 + +#define READ8(base_ptr, offset) *((volatile u8*)((unsigned long)base_ptr + offset)) +#define READ16(base_ptr, offset) *((volatile u16*)((unsigned long)base_ptr + offset)) +#define READ32(base_ptr, offset) *((volatile uint32_t*)((unsigned long)base_ptr + offset)) + + +#define WRITE8(base_ptr, offset, data) *(volatile u8*)((unsigned long)base_ptr + offset) = data; +#define WRITE16(base_ptr, offset, data) *(volatile u16*)((unsigned long)base_ptr + offset) = data; +#define WRITE32(base_ptr, offset, data) *(volatile uint32_t*)((unsigned long)base_ptr + offset) = data; + +#define SELECTEND(base_ptr, end) WRITE8(base_ptr, HDRC_INDEX, end) +#define READCSR8(base_ptr, offset, end) READ8(base_ptr, (offset + 0x10)) +#define READCSR16(base_ptr, offset, end) READ16(base_ptr, (offset + 0x10)) +#define WRITECSR8(base_ptr, offset, end, data) WRITE8(base_ptr, (offset + 0x10), data) +#define WRITECSR16(base_ptr, offset, end, data) WRITE16(base_ptr, (offset + 0x10), data) + +#define MODE_ULPI 0x01 +#define POWER_HSENAB 0x20 +#define POWER_SOFTCONN 0x40 + +/*EP0 related macros */ +/* CSR0 in Peripheral mode */ +#define CSR0_P_SVDSETUPEND 0x0080 +#define CSR0_P_SVDRXPKTRDY 0x0040 +#define CSR0_P_SENDSTALL 0x0020 +#define CSR0_P_SETUPEND 0x0010 +#define CSR0_P_DATAEND 0x0008 +#define CSR0_P_SENTSTALL 0x0004 +#define CSR0_FLUSHFIFO 0x0100 +#define CSR0_TXPKTRDY 0x0002 +#define CSR0_RXPKTRDY 0x0001 + + +#define EP_ACTIVE 0 +#define EP_HALTED 1 +#define EP_DISABLED 2 + +/* TESTMODE */ + +#define TEST_FORCE_HOST 0x80 +#define TEST_FIFO_ACCESS 0x40 +#define TEST_FORCE_FS 0x20 +#define TEST_FORCE_HS 0x10 +#define TEST_PACKET 0x08 +#define TEST_K 0x04 +#define TEST_J 0x02 +#define TEST_SE0_NAK 0x01 + +struct endpoint_control { + __u8 OTG_TX0FAD; + __u8 FILL4; + __u8 OTG_TX0HAD; + __u8 OTG_TX0HP; + __u8 OTG_RX0FAD; + __u8 FILL5; + __u8 OTG_RX0HAD; + __u8 OTG_RX0HP; +}; +struct mg_dev_register +{ + __u8 OTG_FADDR; + __u8 OTG_PWR; + __u16 OTG_INTTX; + __u16 OTG_INTRX; + __u16 OTG_INTTXEN; + __u16 OTG_INTRXEN; + __u8 OTG_INTUSB; + __u8 OTG_INTUSBEN; + __u16 OTG_FMNO; + __u8 OTG_INDX; + __u8 OTG_TM; + __u16 OTG_TXMAXP; + __u16 OTG_CSR0_TXCSR; + __u16 OTG_RXMAXP; + __u16 OTG_RXCSR; + __u16 OTG_CNT0_RXCNT; + __u8 OTG_TYPE0_TXTYPE; + __u8 OTG_NAKLMT0_TXINTV; + __u8 OTG_RXTYPE; + __u8 OTG_RXINTV; + __u8 FILL0; + __u8 OTG_CFD_FSIZE; + + /* FIFO registers */ + __u32 OTG_FIFO[16]; + __u8 OTG_DEVCTL; + __u8 FILL1; + __u8 OTG_TXFSZ; + __u8 OTG_RXFSZ; + __u16 OTG_TXFA; + __u16 OTG_RXFA; + __u32 OTG_VCNTL; + __u16 OTG_HWVER; + __u16 FILL2; + __u8 OTG_UVBCTRL; + __u8 OTG_UCKIT; + __u8 OTG_UINTMASK; + __u8 OTG_UINTSRC; + __u8 OTG_UREGDATA; + __u8 OTG_UREGADDR; + __u8 OTG_UREGCTRL; + __u8 OTG_URAWDATA; + __u8 OTG_EPINFO; + __u8 OTG_RAMINFO; + __u8 OTG_LINKINFO; + __u8 OTG_VPLEN; + __u8 OTG_HSEOF1; + __u8 OTG_FSEOF1; + __u8 OTG_LSEOF1; + __u8 OTG_SOFTRST; + + /* Target Endpoint control registers */ + struct endpoint_control endp_control[16]; + /* Control Status register for Endpoint 0 */ + __u16 OTG_TX0MAXP; + __u16 OTG_CSR0; + __u16 OTG_RX0MAXP; + __u16 OTG_RX0CSR; + __u16 OTG_CNT0; + __u8 OTG_TYPE0; + __u8 OTG_NAKLMT0; + __u8 OTG_RX0TYPE; + __u8 OTG_RX0INTV; + __u8 FILL36; + __u8 OTG_CFD; + + /* Control Status register for Endpoint 1 */ + __u16 OTG_TX1MAXP; + __u16 OTG_TX1CSR; + __u16 OTG_RX1MAXP; + __u16 OTG_RX1CSR; + __u16 OTG_RX1CNT; + __u8 OTG_TX1TYPE; + __u8 OTG_TX1INTV; + __u8 OTG_RX1TYPE; + __u8 OTG_RX1INTV; + __u8 FILL37; + __u8 OTG_FSIZE1; + + /* Control Status register for Endpoint 2 */ + __u16 OTG_TX2MAXP; + __u16 OTG_TX2CSR; + __u16 OTG_RX2MAXP; + __u16 OTG_RX2CSR; + __u16 OTG_RX2CNT; + __u8 OTG_TX2TYPE; + __u8 OTG_TX2INTV; + __u8 OTG_RX2TYPE; + __u8 OTG_RX2INTV; + __u8 FILL38; + __u8 OTG_FSIZE2; + + /* Control Status register for Endpoint 3 */ + __u16 OTG_TX3MAXP; + __u16 OTG_TX3CSR; + __u16 OTG_RX3MAXP; + __u16 OTG_RX3CSR; + __u16 OTG_RX3CNT; + __u8 OTG_TX3TYPE; + __u8 OTG_TX3INTV; + __u8 OTG_RX3TYPE; + __u8 OTG_RX3INTV; + __u8 FILL39; + __u8 OTG_FSIZE3; + + /* Control Status register for Endpoint 4 */ + __u16 OTG_TX4MAXP; + __u16 OTG_TX4CSR; + __u16 OTG_RX4MAXP; + __u16 OTG_RX4CSR; + __u16 OTG_RX4CNT; + __u8 OTG_TX4TYPE; + __u8 OTG_TX4INTV; + __u8 OTG_RX4TYPE; + __u8 OTG_RX4INTV; + __u8 FILL40; + __u8 OTG_FSIZE4; + + /* Control Status register for Endpoint 5 */ + __u16 OTG_TX5MAXP; + __u16 OTG_TX5CSR; + __u16 OTG_RX5MAXP; + __u16 OTG_RX5CSR; + __u16 OTG_RX5CNT; + __u8 OTG_TX5TYPE; + __u8 OTG_TX5INTV; + __u8 OTG_RX5TYPE; + __u8 OTG_RX5INTV; + __u8 FILL41; + __u8 OTG_FSIZE5; + + /* Control Status register for Endpoint 6 */ + __u16 OTG_TX6MAXP; + __u16 OTG_TX6CSR; + __u16 OTG_RX6MAXP; + __u16 OTG_RX6CSR; + __u16 OTG_RX6CNT; + __u8 OTG_TX6TYPE; + __u8 OTG_TX6INTV; + __u8 OTG_RX6TYPE; + __u8 OTG_RX6INTV; + __u8 FILL42; + __u8 OTG_FSIZE6; + + /* Control Status register for Endpoint 7 */ + __u16 OTG_TX7MAXP; + __u16 OTG_TX7CSR; + __u16 OTG_RX7MAXP; + __u16 OTG_RX7CSR; + __u16 OTG_RX7CNT; + __u8 OTG_TX7TYPE; + __u8 OTG_TX7INTV; + __u8 OTG_RX7TYPE; + __u8 OTG_RX7INTV; + __u8 FILL43; + __u8 OTG_FSIZE7; + + /* Control Status register for Endpoint 8 */ + __u16 OTG_TX8MAXP; + __u16 OTG_TX8CSR; + __u16 OTG_RX8MAXP; + __u16 OTG_RX8CSR; + __u16 OTG_RX8CNT; + __u8 OTG_TX8TYPE; + __u8 OTG_TX8INTV; + __u8 OTG_RX8TYPE; + __u8 OTG_RX8INTV; + __u8 FILL44; + __u8 OTG_FSIZE8; + + /* Control Status register for Endpoint 9 */ + __u16 OTG_TX9MAXP; + __u16 OTG_TX9CSR; + __u16 OTG_RX9MAXP; + __u16 OTG_RX9CSR; + __u16 OTG_RX9CNT; + __u8 OTG_TX9TYPE; + __u8 OTG_TX9INTV; + __u8 OTG_RX9TYPE; + __u8 OTG_RX9INTV; + __u8 FILL45; + __u8 OTG_FSIZE9; + + /* Control Status register for Endpoint 10 */ + __u16 OTG_TX10MAXP; + __u16 OTG_TX10CSR; + __u16 OTG_RX10MAXP; + __u16 OTG_RX10CSR; + __u16 OTG_RX10CNT; + __u8 OTG_TX10TYPE; + __u8 OTG_TX10INTV; + __u8 OTG_RX10TYPE; + __u8 OTG_RX10INTV; + __u8 FILL46; + __u8 OTG_FSIZE10; + + /* Control Status register for Endpoint 11 */ + __u16 OTG_TX11MAXP; + __u16 OTG_TX11CSR; + __u16 OTG_RX11MAXP; + __u16 OTG_RX11CSR; + __u16 OTG_RX11CNT; + __u8 OTG_TX11TYPE; + __u8 OTG_TX11INTV; + __u8 OTG_RX11TYPE; + __u8 OTG_RX11INTV; + __u8 FILL47; + __u8 OTG_FSIZE11; + + /* Control Status register for Endpoint 12 */ + __u16 OTG_TX12MAXP; + __u16 OTG_TX12CSR; + __u16 OTG_RX12MAXP; + __u16 OTG_RX12CSR; + __u16 OTG_RX12CNT; + __u8 OTG_TX12TYPE; + __u8 OTG_TX12INTV; + __u8 OTG_RX12TYPE; + __u8 OTG_RX12INTV; + __u8 FILL48; + __u8 OTG_FSIZE12; + + /* Control Status register for Endpoint 13 */ + __u16 OTG_TX13MAXP; + __u16 OTG_TX13CSR; + __u16 OTG_RX13MAXP; + __u16 OTG_RX13CSR; + __u16 OTG_RX13CNT; + __u8 OTG_TX13TYPE; + __u8 OTG_TX13INTV; + __u8 OTG_RX13TYPE; + __u8 OTG_RX13INTV; + __u8 FILL49; + __u8 OTG_FSIZE13; + + /* Control Status register for Endpoint 14 */ + __u16 OTG_TX14MAXP; + __u16 OTG_TX14CSR; + __u16 OTG_RX14MAXP; + __u16 OTG_RX14CSR; + __u16 OTG_RX14CNT; + __u8 OTG_TX14TYPE; + __u8 OTG_TX14INTV; + __u8 OTG_RX14TYPE; + __u8 OTG_RX14INTV; + __u8 FILL50; + __u8 OTG_FSIZE14; + + /* Control Status register for Endpoint 15 */ + __u16 OTG_TX15MAXP; + __u16 OTG_TX15CSR; + __u16 OTG_RX15MAXP; + __u16 OTG_RX15CSR; + __u16 OTG_RX15CNT; + __u8 OTG_TX15TYPE; + __u8 OTG_TX15INTV; + __u8 OTG_RX15TYPE; + __u8 OTG_RX15INTV; + __u8 FILL51; + __u8 OTG_FSIZE15; + + __u32 OTG_DMASEL; + __u8 OTG_TOPCTRL; +}; + +struct udc_end0_buffer { + u8 data[EP0_MAX_PACKET_SIZE]; + u16 count; +}; +/* Higher level functions for abstracting away from specific device */ +int udc_init (void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint); + +void udc_irq (void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid); +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +#endif //__MUSB_UDC_H__ diff --git a/include/asm-arm/arch-stw8500/bits.h b/include/asm-arm/arch-stw8500/bits.h new file mode 100755 index 000000000..08e16a2a8 --- /dev/null +++ b/include/asm-arm/arch-stw8500/bits.h @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef __bits_h +#define __bits_h 1 + +#define BIT0 (1<<0) +#define BIT1 (1<<1) +#define BIT2 (1<<2) +#define BIT3 (1<<3) +#define BIT4 (1<<4) +#define BIT5 (1<<5) +#define BIT6 (1<<6) +#define BIT7 (1<<7) +#define BIT8 (1<<8) +#define BIT9 (1<<9) +#define BIT10 (1<<10) +#define BIT11 (1<<11) +#define BIT12 (1<<12) +#define BIT13 (1<<13) +#define BIT14 (1<<14) +#define BIT15 (1<<15) +#define BIT16 (1<<16) +#define BIT17 (1<<17) +#define BIT18 (1<<18) +#define BIT19 (1<<19) +#define BIT20 (1<<20) +#define BIT21 (1<<21) +#define BIT22 (1<<22) +#define BIT23 (1<<23) +#define BIT24 (1<<24) +#define BIT25 (1<<25) +#define BIT26 (1<<26) +#define BIT27 (1<<27) +#define BIT28 (1<<28) +#define BIT29 (1<<29) +#define BIT30 (1<<30) +#define BIT31 (1<<31) + +#endif diff --git a/include/asm-arm/arch-stw8500/common.h b/include/asm-arm/arch-stw8500/common.h new file mode 100755 index 000000000..b6185081a --- /dev/null +++ b/include/asm-arm/arch-stw8500/common.h @@ -0,0 +1,134 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _COMMON_H_ +#define _COMMON_H_ +#include <common.h> + +#define PASS (1) +#define FAIL (0) + +#define IO(addr) (*((u32*) (addr))) +#define HIO(addr) (*((u16*) (addr))) +#define BIO(addr) (*((u8*) (addr))) + +/* + * macro to get at IO space + */ +#define IO_ADDRESS(x) (x) + +#define REG_WRITE_BITS(reg,val,mask,sb) (writel(((readl(reg) & ~(mask)) | (((val)<<(sb)) & (mask))), reg)) + +#define nmdk_error(format, arg...) printf(": " format "\n" , ## arg) + +#if !defined(FALSE) && !defined(TRUE) +typedef enum {FALSE, TRUE} t_bool; +#else /* FALSE & TRUE already defined */ +typedef enum {BOOL_FALSE, BOOL_TRUE} t_bool; +#endif /* !defined(FALSE) && !defined(TRUE) */ + +/*----------------------------------------------------------------------------- + * Bit mask definition + *---------------------------------------------------------------------------*/ +#define MASK_NULL8 0x00 +#define MASK_NULL16 0x0000 +#define MASK_NULL32 0x00000000 +#define MASK_ALL8 0xFF +#define MASK_ALL16 0xFFFF +#define MASK_ALL32 0xFFFFFFFF + +#define MASK_BIT0 (1UL<<0) +#define MASK_BIT1 (1UL<<1) +#define MASK_BIT2 (1UL<<2) +#define MASK_BIT3 (1UL<<3) +#define MASK_BIT4 (1UL<<4) +#define MASK_BIT5 (1UL<<5) +#define MASK_BIT6 (1UL<<6) +#define MASK_BIT7 (1UL<<7) +#define MASK_BIT8 (1UL<<8) +#define MASK_BIT9 (1UL<<9) +#define MASK_BIT10 (1UL<<10) +#define MASK_BIT11 (1UL<<11) +#define MASK_BIT12 (1UL<<12) +#define MASK_BIT13 (1UL<<13) +#define MASK_BIT14 (1UL<<14) +#define MASK_BIT15 (1UL<<15) +#define MASK_BIT16 (1UL<<16) +#define MASK_BIT17 (1UL<<17) +#define MASK_BIT18 (1UL<<18) +#define MASK_BIT19 (1UL<<19) +#define MASK_BIT20 (1UL<<20) +#define MASK_BIT21 (1UL<<21) +#define MASK_BIT22 (1UL<<22) +#define MASK_BIT23 (1UL<<23) +#define MASK_BIT24 (1UL<<24) +#define MASK_BIT25 (1UL<<25) +#define MASK_BIT26 (1UL<<26) +#define MASK_BIT27 (1UL<<27) +#define MASK_BIT28 (1UL<<28) +#define MASK_BIT29 (1UL<<29) +#define MASK_BIT30 (1UL<<30) +#define MASK_BIT31 (1UL<<31) + +#define NOMADIK_INTERNAL_ERROR (-8) +#define NOMADIK_NOT_CONFIGURED (-7) +#define NOMADIK_REQUEST_PENDING (-6) +#define NOMADIK_REQUEST_NOT_APPLICABLE (-5) +#define NOMADIK_INVALID_PARAMETER (-4) +#define NOMADIK_UNSUPPORTED_FEATURE (-3) +#define NOMADIK_UNSUPPORTED_HW (-2) +#define NOMADIK_ERROR (-1) +#define NOMADIK_OK ( 0) +#define NOMADIK_INTERNAL_EVENT ( 1) +#define NOMADIK_REMAINING_PENDING_EVENTS ( 2) +#define NOMADIK_REMAINING_FILTER_PENDING_EVENTS ( 3) +#define NOMADIK_NO_MORE_PENDING_EVENT ( 4) +#define NOMADIK_NO_MORE_FILTER_PENDING_EVENT ( 5) +#define NOMADIK_NO_PENDING_EVENT_ERROR ( 7) + + +#define NOMADIK_MAX_ERROR_VALUE (-65) /* HW specific error codes + * should start from this offset + */ +/*----------------------------------------------------------------------------- + * Bit setting or clearing + *---------------------------------------------------------------------------*/ +#define NOMADIK_SET_BITS(reg,mask) ((reg) |= (mask)) +#define NOMADIK_CLEAR_BITS(reg,mask) ((reg) &= ~(mask)) +#define NOMADIK_READ_BITS(reg,mask) ((reg) & (mask)) +#define NOMADIK_WRITE_BITS(reg,val,mask) ((reg) = (((reg) & ~(mask)) | ((val) & (mask)))) +#define NOMADIK_READ_REG(reg) (reg) +#define NOMADIK_WRITE_REG(reg,val) ((reg) = (val)) + +/* + * Definition of the different kind of addresses manipulated into a system with MMU + * (handle physical AND logical addresses) + */ + +typedef u32 t_physical_address; +typedef u32 t_logical_address; + +/*function prototypes*/ +void gpio_init(void); +int emmc_init (u8); + +#endif /* _COMMON_H_ */ diff --git a/include/asm-arm/arch-stw8500/emmc.h b/include/asm-arm/arch-stw8500/emmc.h new file mode 100755 index 000000000..aa4b48df0 --- /dev/null +++ b/include/asm-arm/arch-stw8500/emmc.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +#ifndef _STM_EMMC_H +#define _STM_EMMC_H + + +#include <common.h> + +extern int emmc_init (u8); +int emmc_erase(u32, u32); +int emmc_read (u32,u32,u32); +int emmc_write(u32,u32,u32); +int emmc_write_pib(void); + + +#endif /* !defined(_STM_EMMC_H) */ diff --git a/include/asm-arm/arch-stw8500/gpio.h b/include/asm-arm/arch-stw8500/gpio.h new file mode 100755 index 000000000..26e14d04c --- /dev/null +++ b/include/asm-arm/arch-stw8500/gpio.h @@ -0,0 +1,524 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef _MOP500_GPIO_h +#define _MOP500_GPIO_h + +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include "common.h" +#include <configs/u8500.h> + +#define GPIO_TOTAL_PINS 268 + +#define GPIO_PINS_PER_BLOCK 32 +#define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK +1) +#define GPIO_BLOCK(pin) ( ( ( pin + GPIO_PINS_PER_BLOCK ) >> 5) - 1 ) + + +struct gpio_register { + u32 gpio_dat; /* GPIO data register *//*0x000 */ + u32 gpio_dats; /* GPIO data Set register *//*0x004 */ + u32 gpio_datc; /* GPIO data Clear register *//*0x008 */ + u32 gpio_pdis; /* GPIO Pull disable register *//*0x00C */ + u32 gpio_dir; /* GPIO data direction register *//*0x010 */ + u32 gpio_dirs; /* GPIO data dir Set register *//*0x014 */ + u32 gpio_dirc; /* GPIO data dir Clear register *//*0x018 */ + u32 gpio_slpm; /* GPIO Sleep mode register *//*0x01C */ + u32 gpio_afsa; /* GPIO AltFun A Select reg *//*0x020 */ + u32 gpio_afsb; /* GPIO AltFun B Select reg *//*0x024 */ + u32 gpio_lowemi; /* GPIO low EMI Select reg *//*0x028 */ + u32 reserved_1[(0x040 - 0x02C) >> 2]; /*0x028-0x3C Reserved*/ + u32 gpio_rimsc; /* GPIO rising edge intr set/clear *//*0x040 */ + u32 gpio_fimsc; /* GPIO falling edge interrupt set/clear register *//*0x044 */ + u32 gpio_mis; /* GPIO masked interrupt status register *//*0x048 */ + u32 gpio_ic; /* GPIO Interrupt Clear register *//*0x04C */ + u32 gpio_rwimsc; /* GPIO Rising-edge Wakeup IMSC register *//*0x050 */ + u32 gpio_fwimsc; /* GPIO Falling-edge Wakeup IMSC register *//*0x054 */ + u32 gpio_wks; /* GPIO Wakeup Status register *//*0x058 */ +}; + +/* Error values returned by functions */ +typedef enum { + GPIO_OK = 0, /* (0) */ + GPIO_UNSUPPORTED_HW = -2, /* NOMADIK_UNSUPPORTED_HW, (-2) */ + GPIO_UNSUPPORTED_FEATURE = -3, /* NOMADIK_UNSUPPORTED_FEATURE, (-3) */ + GPIO_INVALID_PARAMETER = -4, /* NOMADIK_INVALID_PARAMETER, (-4) */ + GPIO_REQUEST_NOT_APPLICABLE = -5, /* NOMADIK_REQUEST_NOT_APPLICABLE, (-5) */ + GPIO_REQUEST_PENDING = -6, /* NOMADIK_REQUEST_PENDING, (-6) */ + GPIO_NOT_CONFIGURED = -7, /* NOMADIK_NOT_CONFIGURED, (-7) */ + GPIO_INTERNAL_ERROR = -8, /* NOMADIK_INTERNAL_ERROR, (-8) */ + GPIO_INTERNAL_EVENT = 1, /* NOMADIK_INTERNAL_EVENT,*/ + GPIO_REMAINING_EVENT = 2, /* NOMADIK_REMAINING_PENDING_EVENTS,*/ + GPIO_NO_MORE_PENDING_EVENT = 3, /* NOMADIK_NO_MORE_PENDING_EVENT,*/ + GPIO_INVALID_CLIENT = -25, + GPIO_INVALID_PIN = -26, + GPIO_PIN_BUSY = -27, + GPIO_PIN_NOT_ALLOCATED = -28, + GPIO_WRONG_CLIENT = -29, + GPIO_UNSUPPORTED_ALTFUNC = -30, + +} gpio_error; + +/*GPIO DEVICE ID */ +typedef enum { + GPIO_DEVICE_ID_0, + GPIO_DEVICE_ID_1, + GPIO_DEVICE_ID_2, + GPIO_DEVICE_ID_3, + GPIO_DEVICE_ID_INVALID +} gpio_device_id; + +/* + * Pin description To be used in SOFTWARE mode: refers to a pin. + */ +typedef enum { + GPIO_PIN_0, + GPIO_PIN_1, + GPIO_PIN_2, + GPIO_PIN_3, + GPIO_PIN_4, + GPIO_PIN_5, + GPIO_PIN_6, + GPIO_PIN_7, + GPIO_PIN_8, + GPIO_PIN_9, + GPIO_PIN_10, + GPIO_PIN_11, + GPIO_PIN_12, + GPIO_PIN_13, + GPIO_PIN_14, + GPIO_PIN_15, + GPIO_PIN_16, + GPIO_PIN_17, + GPIO_PIN_18, + GPIO_PIN_19, + GPIO_PIN_20, + GPIO_PIN_21, + GPIO_PIN_22, + GPIO_PIN_23, + GPIO_PIN_24, + GPIO_PIN_25, + GPIO_PIN_26, + GPIO_PIN_27, + GPIO_PIN_28, + GPIO_PIN_29, + GPIO_PIN_30, + GPIO_PIN_31, + GPIO_PIN_32, + GPIO_PIN_33, + GPIO_PIN_34, + GPIO_PIN_35, + GPIO_PIN_36, + GPIO_PIN_37, + GPIO_PIN_38, + GPIO_PIN_39, + GPIO_PIN_40, + GPIO_PIN_41, + GPIO_PIN_42, + GPIO_PIN_43, + GPIO_PIN_44, + GPIO_PIN_45, + GPIO_PIN_46, + GPIO_PIN_47, + GPIO_PIN_48, + GPIO_PIN_49, + GPIO_PIN_50, + GPIO_PIN_51, + GPIO_PIN_52, + GPIO_PIN_53, + GPIO_PIN_54, + GPIO_PIN_55, + GPIO_PIN_56, + GPIO_PIN_57, + GPIO_PIN_58, + GPIO_PIN_59, + GPIO_PIN_60, + GPIO_PIN_61, + GPIO_PIN_62, + GPIO_PIN_63, + GPIO_PIN_64, + GPIO_PIN_65, + GPIO_PIN_66, + GPIO_PIN_67, + GPIO_PIN_68, + GPIO_PIN_69, + GPIO_PIN_70, + GPIO_PIN_71, + GPIO_PIN_72, + GPIO_PIN_73, + GPIO_PIN_74, + GPIO_PIN_75, + GPIO_PIN_76, + GPIO_PIN_77, + GPIO_PIN_78, + GPIO_PIN_79, + GPIO_PIN_80, + GPIO_PIN_81, + GPIO_PIN_82, + GPIO_PIN_83, + GPIO_PIN_84, + GPIO_PIN_85, + GPIO_PIN_86, + GPIO_PIN_87, + GPIO_PIN_88, + GPIO_PIN_89, + GPIO_PIN_90, + GPIO_PIN_91, + GPIO_PIN_92, + GPIO_PIN_93, + GPIO_PIN_94, + GPIO_PIN_95, + GPIO_PIN_96, + GPIO_PIN_97, + GPIO_PIN_98, + GPIO_PIN_99, + GPIO_PIN_100, + GPIO_PIN_101, + GPIO_PIN_102, + GPIO_PIN_103, + GPIO_PIN_104, + GPIO_PIN_105, + GPIO_PIN_106, + GPIO_PIN_107, + GPIO_PIN_108, + GPIO_PIN_109, + GPIO_PIN_110, + GPIO_PIN_111, + GPIO_PIN_112, + GPIO_PIN_113, + GPIO_PIN_114, + GPIO_PIN_115, + GPIO_PIN_116, + GPIO_PIN_117, + GPIO_PIN_118, + GPIO_PIN_119, + GPIO_PIN_120, + GPIO_PIN_121, + GPIO_PIN_122, + GPIO_PIN_123, + GPIO_PIN_124, + GPIO_PIN_125, + GPIO_PIN_126, + GPIO_PIN_127, + GPIO_PIN_128, + GPIO_PIN_129, + GPIO_PIN_130, + GPIO_PIN_131, + GPIO_PIN_132, + GPIO_PIN_133, + GPIO_PIN_134, + GPIO_PIN_135, + GPIO_PIN_136, + GPIO_PIN_137, + GPIO_PIN_138, + GPIO_PIN_139, + GPIO_PIN_140, + GPIO_PIN_141, + GPIO_PIN_142, + GPIO_PIN_143, + GPIO_PIN_144, + GPIO_PIN_145, + GPIO_PIN_146, + GPIO_PIN_147, + GPIO_PIN_148, + GPIO_PIN_149, + GPIO_PIN_150, + GPIO_PIN_151, + GPIO_PIN_152, + GPIO_PIN_153, + GPIO_PIN_154, + GPIO_PIN_155, + GPIO_PIN_156, + GPIO_PIN_157, + GPIO_PIN_158, + GPIO_PIN_159, + GPIO_PIN_160, + GPIO_PIN_161, + GPIO_PIN_162, + GPIO_PIN_163, + GPIO_PIN_164, + GPIO_PIN_165, + GPIO_PIN_166, + GPIO_PIN_167, + GPIO_PIN_168, + GPIO_PIN_169, + GPIO_PIN_170, + GPIO_PIN_171, + GPIO_PIN_172, + GPIO_PIN_173, + GPIO_PIN_174, + GPIO_PIN_175, + GPIO_PIN_176, + GPIO_PIN_177, + GPIO_PIN_178, + GPIO_PIN_179, + GPIO_PIN_180, + GPIO_PIN_181, + GPIO_PIN_182, + GPIO_PIN_183, + GPIO_PIN_184, + GPIO_PIN_185, + GPIO_PIN_186, + GPIO_PIN_187, + GPIO_PIN_188, + GPIO_PIN_189, + GPIO_PIN_190, + GPIO_PIN_191, + GPIO_PIN_192, + GPIO_PIN_193, + GPIO_PIN_194, + GPIO_PIN_195, + GPIO_PIN_196, + GPIO_PIN_197, + GPIO_PIN_198, + GPIO_PIN_199, + GPIO_PIN_200, + GPIO_PIN_201, + GPIO_PIN_202, + GPIO_PIN_203, + GPIO_PIN_204, + GPIO_PIN_205, + GPIO_PIN_206, + GPIO_PIN_207, + GPIO_PIN_208, + GPIO_PIN_209, + GPIO_PIN_210, + GPIO_PIN_211, + GPIO_PIN_212, + GPIO_PIN_213, + GPIO_PIN_214, + GPIO_PIN_215, + GPIO_PIN_216, + GPIO_PIN_217, + GPIO_PIN_218, + GPIO_PIN_219, + GPIO_PIN_220, + GPIO_PIN_221, + GPIO_PIN_222, + GPIO_PIN_223, + GPIO_PIN_224, + GPIO_PIN_225, + GPIO_PIN_226, + GPIO_PIN_227, + GPIO_PIN_228, + GPIO_PIN_229, + GPIO_PIN_230, + GPIO_PIN_231, + GPIO_PIN_232, + GPIO_PIN_233, + GPIO_PIN_234, + GPIO_PIN_235, + GPIO_PIN_236, + GPIO_PIN_237, + GPIO_PIN_238, + GPIO_PIN_239, + GPIO_PIN_240, + GPIO_PIN_241, + GPIO_PIN_242, + GPIO_PIN_243, + GPIO_PIN_244, + GPIO_PIN_245, + GPIO_PIN_246, + GPIO_PIN_247, + GPIO_PIN_248, + GPIO_PIN_249, + GPIO_PIN_250, + GPIO_PIN_251, + GPIO_PIN_252, + GPIO_PIN_253, + GPIO_PIN_254, + GPIO_PIN_255, + GPIO_PIN_256, + GPIO_PIN_257, + GPIO_PIN_258, + GPIO_PIN_259, + GPIO_PIN_260, + GPIO_PIN_261, + GPIO_PIN_262, + GPIO_PIN_263, + GPIO_PIN_264, + GPIO_PIN_265, + GPIO_PIN_266, + GPIO_PIN_267 +} gpio_pin; + +/* + * Alternate Function: + * refered in altfun_table to pointout particular altfun to be enabled + * when using GPIO_ALT_FUNCTION A/B/C enable/disable operation + */ +typedef enum { + GPIO_ALT_UART_0_MODEM, + GPIO_ALT_UART_0_NO_MODEM, + GPIO_ALT_UART_1, + GPIO_ALT_UART_2, + GPIO_ALT_I2C_0, + GPIO_ALT_I2C_1, + GPIO_ALT_MSP_0, + GPIO_ALT_MSP_1, + GPIO_ALT_MSP_2, + GPIO_ALT_MSP_3, + GPIO_ALT_MSP_4, + GPIO_ALT_MSP_5, + GPIO_ALT_SSP_0, + GPIO_ALT_SSP_1, + GPIO_ALT_MM_CARD0, + GPIO_ALT_SD_CARD0, + GPIO_ALT_DMA_0, + GPIO_ALT_DMA_1, + GPIO_ALT_HSI0, + GPIO_ALT_CCIR656_INPUT, + GPIO_ALT_CCIR656_OUTPUT, + GPIO_ALT_LCD_PANEL, + GPIO_ALT_MDIF, + GPIO_ALT_SDRAM, + GPIO_ALT_HAMAC_AUDIO_DBG, + GPIO_ALT_HAMAC_VIDEO_DBG, + GPIO_ALT_CLOCK_RESET, + GPIO_ALT_TSP, + GPIO_ALT_IRDA, + GPIO_ALT_USB_MINIMUM, + GPIO_ALT_USB_I2C, + GPIO_ALT_OWM, + GPIO_ALT_PWL, + GPIO_ALT_FSMC, + GPIO_ALT_COMP_FLASH, + GPIO_ALT_SRAM_NOR_FLASH, + GPIO_ALT_FSMC_ADDLINE_0_TO_15, + GPIO_ALT_SCROLL_KEY, + GPIO_ALT_MSHC, + GPIO_ALT_HPI, + GPIO_ALT_USB_OTG, + GPIO_ALT_SDIO, + GPIO_ALT_HSMMC, + GPIO_ALT_FSMC_ADD_DATA_0_TO_25, + GPIO_ALT_HSI1, + GPIO_ALT_NOR, + GPIO_ALT_NAND, + GPIO_ALT_KEYPAD, + GPIO_ALT_VPIP, + GPIO_ALT_CAM, + GPIO_ALT_CCP1, + GPIO_ALT_EMMC, +#ifdef CONFIG_NOMADIK_8500_V1 + GPIO_ALT_POP_EMMC, +#endif + GPIO_ALT_FUNMAX /* Add new alt func before this */ +} gpio_alt_function; + +/* Defines pin assignment(Software mode or Alternate mode) */ +typedef enum { + GPIO_MODE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_MODE_SOFTWARE, /* Pin connected to GPIO (SW controlled) */ + GPIO_ALTF_A, /* Pin connected to alternate function 1 (HW periph 1) */ + GPIO_ALTF_B, /* Pin connected to alternate function 2 (HW periph 2) */ + GPIO_ALTF_C, /* Pin connected to alternate function 3 (HW periph 3) */ + GPIO_ALTF_FIND, /* Pin connected to alternate function 3 (HW periph 3) */ + GPIO_ALTF_DISABLE /* Pin connected to alternate function 3 (HW periph 3) */ +} gpio_mode; + +/* Defines GPIO pin direction */ +typedef enum { + GPIO_DIR_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_DIR_INPUT, /* GPIO set as input */ + GPIO_DIR_OUTPUT /* GPIO set as output */ +} gpio_direction; + +/* Interrupt trigger mode */ +typedef enum { + GPIO_TRIG_LEAVE_UNCHANGED, /* Parameter will be ignored by the function */ + GPIO_TRIG_DISABLE, /* Triggers no IT */ + GPIO_TRIG_RISING_EDGE, /* Triggers an IT on a rising edge */ + GPIO_TRIG_FALLING_EDGE, /* Triggers an IT on a falling edge */ + GPIO_TRIG_BOTH_EDGES, /* Triggers an IT on a rising and a falling edge */ + GPIO_TRIG_HIGH_LEVEL, /* Triggers an IT on a high level */ + GPIO_TRIG_LOW_LEVEL /* Triggers an IT on a low level */ +} gpio_trig; /* Interrupt trigger mode, or disable */ + +/* Configuration parameters for one GPIO pin.*/ +typedef struct { + gpio_mode mode; /* Defines mode (SOFTWARE or Alternate). */ + gpio_direction direction; /* Define pin direction (in SOFTWARE mode only). */ + gpio_trig trig; /* Interrupt trigger (in SOFTWARE mode only) */ + char *dev_name; /* Name of client driver who owns the gpio pin */ +} gpio_config; + +/* GPIO pin data*/ +typedef enum { + GPIO_DATA_LOW, /* GPIO pin status is low. */ + GPIO_DATA_HIGH /* GPIO pin status is high. */ +} gpio_data; + +/* GPIO behaviour in sleep mode */ +typedef enum { + GPIO_SLEEP_MODE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_SLEEP_MODE_INPUT_DEFAULTVOLT, /* GPIO is an input with pull up/down enabled + when in sleep mode. */ + GPIO_SLEEP_MODE_CONTROLLED_BY_GPIO /* GPIO pin is controlled by GPIO IP. So mode, + direction and data values for GPIO pin in + sleep mode are determined by configuration + set to GPIO pin before entering to sleep mode. */ +} gpio_sleep_mode; + +/* GPIO ability to wake the system up from sleep mode.*/ +typedef enum { + GPIO_WAKE_LEAVE_UNCHANGED, /* Parameter will be ignored by the function. */ + GPIO_WAKE_DISABLE, /* GPIO will not wake the system from sleep mode. */ + GPIO_WAKE_LOW_LEVEL, /* GPIO will wake the system up on a LOW level. */ + GPIO_WAKE_HIGH_LEVEL, /* GPIO will wake the system up on a HIGH level. */ + GPIO_WAKE_RISING_EDGE, /* GPIO will wake the system up on a RISING edge. */ + GPIO_WAKE_FALLING_EDGE, /* GPIO will wake the system up on a FALLING edge. */ + GPIO_WAKE_BOTH_EDGES /* GPIO will wake the system up on both RISING and FALLING edge. */ +} gpio_wake; + +/* Configuration parameters for one GPIO pin in sleep mode.*/ +typedef struct { + gpio_sleep_mode sleep_mode; /* GPIO behaviour in sleep mode. */ + gpio_wake wake; /* GPIO ability to wake up the system. */ +} gpio_sleep_config; + +/*------------------------------------------------------------------------ + * Functions declaration + * refer ./Documentation/arm/STM-Nomadik/gpio_user_guide.txt + *----------------------------------------------------------------------*/ + +extern int gpio_setpinconfig(gpio_pin pin_id, gpio_config * pin_config); +extern int gpio_resetpinconfig(gpio_pin pin_id, char *dev_name); +extern int gpio_writepin(gpio_pin pin_id, gpio_data value, char *dev_name); +extern int gpio_readpin(gpio_pin pin_id, gpio_data * value); +extern int gpio_altfuncenable(gpio_alt_function altfunc, + char *dev_name); +extern int gpio_altfuncdisable(gpio_alt_function altfunc, + char *dev_name); + +struct gpio_altfun_data { + u16 altfun; + u16 start; + u16 end; + t_bool cont; + u8 type; +}; + +#endif /* __INC_GPIO_H */ diff --git a/include/asm-arm/arch-stw8500/mmc.h b/include/asm-arm/arch-stw8500/mmc.h new file mode 100755 index 000000000..c8aa4d71c --- /dev/null +++ b/include/asm-arm/arch-stw8500/mmc.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ +#ifndef __MMC_NOMADIK_P_H__ +#define __MMC_NOMADIK_P_H__ + +#define MAX_ERROR_VALUE -65 +typedef enum +{ + /* MMC specific error defines */ + MMC_CMD_CRC_FAIL = (MAX_ERROR_VALUE - 1), /* Command response received (but CRC check failed) */ + MMC_DATA_CRC_FAIL = (MAX_ERROR_VALUE - 2), /* Data bock sent/received (CRC check Failed) */ + MMC_CMD_RSP_TIMEOUT = (MAX_ERROR_VALUE - 3), /* Command response timeout */ + MMC_DATA_TIMEOUT = (MAX_ERROR_VALUE - 4), /* Data time out*/ + MMC_TX_UNDERRUN = (MAX_ERROR_VALUE - 5), /* Transmit FIFO under-run */ + MMC_RX_OVERRUN = (MAX_ERROR_VALUE - 6), /* Receive FIFO over-run */ + MMC_START_BIT_ERR = (MAX_ERROR_VALUE - 7), /* Start bit not detected on all data signals in widE bus mode */ + MMC_CMD_OUT_OF_RANGE = (MAX_ERROR_VALUE - 8), /* CMD's argument was out of range.*/ + MMC_ADDR_MISALIGNED = (MAX_ERROR_VALUE - 9), /* Misaligned address */ + MMC_BLOCK_LEN_ERR = (MAX_ERROR_VALUE - 10), /* Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */ + MMC_ERASE_SEQ_ERR = (MAX_ERROR_VALUE - 11), /* An error in the sequence of erase command occurs.*/ + MMC_BAD_ERASE_PARAM = (MAX_ERROR_VALUE - 12), /* An Invalid selection for erase groups */ + MMC_WRITE_PROT_VIOLATION = (MAX_ERROR_VALUE - 13), /* Attempt to program a write protect block */ + MMC_LOCK_UNLOCK_FAILED = (MAX_ERROR_VALUE - 14), /* Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */ + MMC_COM_CRC_FAILED = (MAX_ERROR_VALUE - 15), /* CRC check of the previous command failed */ + MMC_ILLEGAL_CMD = (MAX_ERROR_VALUE - 16), /* Command is not legal for the card state */ + MMC_CARD_ECC_FAILED = (MAX_ERROR_VALUE - 17), /* Card internal ECC was applied but failed to correct the data */ + MMC_CC_ERROR = (MAX_ERROR_VALUE - 18), /* Internal card controller error */ + MMC_GENERAL_UNKNOWN_ERROR = (MAX_ERROR_VALUE - 19), /* General or Unknown error */ + MMC_STREAM_READ_UNDERRUN = (MAX_ERROR_VALUE - 20), /* The card could not sustain data transfer in stream read operation. */ + MMC_STREAM_WRITE_OVERRUN = (MAX_ERROR_VALUE - 21), /* The card could not sustain data programming in stream mode */ + MMC_CID_CSD_OVERWRITE = (MAX_ERROR_VALUE - 22), /* CID/CSD overwrite error */ + MMC_WP_ERASE_SKIP = (MAX_ERROR_VALUE - 23), /* only partial address space was erased */ + MMC_CARD_ECC_DISABLED = (MAX_ERROR_VALUE - 24), /* Command has been executed without using internal ECC */ + MMC_ERASE_RESET = (MAX_ERROR_VALUE - 25), /* Erase sequence was cleared before executing because an out of erase sequence command was received */ + MMC_AKE_SEQ_ERROR = (MAX_ERROR_VALUE - 26), /* Error in sequence of authentication. */ + MMC_INVALID_VOLTRANGE = (MAX_ERROR_VALUE - 27), + MMC_ADDR_OUT_OF_RANGE = (MAX_ERROR_VALUE - 28), + MMC_SWITCH_ERROR = (MAX_ERROR_VALUE - 29), + MMC_SDIO_DISABLED = (MAX_ERROR_VALUE - 30), + MMC_SDIO_FUNCTION_BUSY = (MAX_ERROR_VALUE - 31), + MMC_SDIO_FUNCTION_FAILED = (MAX_ERROR_VALUE - 32), + MMC_SDIO_UNKNOWN_FUNCTION = MAX_ERROR_VALUE, + + /* standard error defines */ + MMC_INTERNAL_ERROR = -8, + MMC_NOT_CONFIGURED = -7, + MMC_REQUEST_PENDING = -6, + MMC_REQUEST_NOT_APPLICABLE = -5, + MMC_INVALID_PARAMETER = -4, + MMC_UNSUPPORTED_FEATURE = -3, + MMC_UNSUPPORTED_HW = -2, + MMC_ERROR = -1, + MMC_OK = 0, + MMC_INTERNAL_EVENT = 1, + MMC_REMAINING_PENDING_EVENTS = 2, + MMC_REMAINING_FILTER_PENDING_EVENTS = 3, + MMC_NO_MORE_PENDING_EVENT = 4, + MMC_NO_MORE_FILTER_PENDING_EVENT = 5, + MMC_NO_PENDING_EVENT_ERROR = 7, +} t_mmc_error; + +int init_mmc_card(void); + +#endif + diff --git a/include/asm-arm/arch-stw8500/mtu.h b/include/asm-arm/arch-stw8500/mtu.h new file mode 100755 index 000000000..a87be9ef4 --- /dev/null +++ b/include/asm-arm/arch-stw8500/mtu.h @@ -0,0 +1,66 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * 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 + */ + +#ifndef __ASM_ARCH_MTU_H +#define __ASM_ARCH_MTU_H + +/* + * The MTU device hosts four different counters, with 4 set of + * registers. These are register names. + */ + +#define MTU_IMSC 0x00 /* Interrupt mask set/clear */ +#define MTU_RIS 0x04 /* Raw interrupt status */ +#define MTU_MIS 0x08 /* Masked interrupt status */ +#define MTU_ICR 0x0C /* Interrupt clear register */ + +/* per-timer registers take 0..3 as argument */ +#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */ +#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */ +#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */ +#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */ + +/* bits for the control register */ +#define MTU_CRn_ENA 0x80 +#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */ +#define MTU_CRn_PRESCALE_MASK 0x0c +#define MTU_CRn_PRESCALE_1 0x00 +#define MTU_CRn_PRESCALE_16 0x04 +#define MTU_CRn_PRESCALE_256 0x08 +#define MTU_CRn_32BITS 0x02 +#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/ + +/* Other registers are usual amba/primecell registers, currently not used */ +#define MTU_ITCR 0xff0 +#define MTU_ITOP 0xff4 + +#define MTU_PERIPH_ID0 0xfe0 +#define MTU_PERIPH_ID1 0xfe4 +#define MTU_PERIPH_ID2 0xfe8 +#define MTU_PERIPH_ID3 0xfeC + +#define MTU_PCELL0 0xff0 +#define MTU_PCELL1 0xff4 +#define MTU_PCELL2 0xff8 +#define MTU_PCELL3 0xffC + +#endif /* __ASM_ARCH_MTU_H */ diff --git a/include/configs/u8500.h b/include/configs/u8500.h new file mode 100755 index 000000000..b9aa3c835 --- /dev/null +++ b/include/configs/u8500.h @@ -0,0 +1,244 @@ +/* + * (C) Copyright 2009 + * STEricsson, <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 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/*----------------------------------------------------------------------- + * High Level Configuration Options + * (easy to change) + */ +#define CONFIG_U8500 1 +#define CONFIG_U8500_ED 1 +#define CONFIG_L2_OFF 1 + +// XXX: nomadik left over? +// #define PCI_IO_VADDR 0xee000000 + +// #define __io(a) ((void __iomem *)(PCI_IO_VADDR + (a))) + +#define CONFIG_SYS_MEMTEST_START 0x00000000 +#define CONFIG_SYS_MEMTEST_END 0x1FFFFFFF +#define CONFIG_SYS_HZ 1000//(2400000 / 128) /* Timer0 is clocked at 2.4Mhz with 256 divider */ + +#ifndef CONFIG_U8500_V1 +#define CONFIG_SYS_TIMERBASE 0xA03DA000 /* MTU0 timer */ +#else +#define CONFIG_SYS_TIMERBASE 0xA03C6000 /* MTU0 timer */ +#endif + +#define CONFIG_MISC_INIT_R 1 /* call misc_init_r during start up */ + +#define BOARD_LATE_INIT 1 +#define LITTLEENDIAN /* XXX: obsoleted */ + +/*----------------------------------------------------------------------- + * Size of malloc() pool + */ +#define CONFIG_ENV_SIZE 128*1024 +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 256*1024) +#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ + +/*----------------------------------------------------------------------- + * PL011 Configuration + */ + +#define CONFIG_PL011_SERIAL +/* + * U8500 UART registers base for 3 serial devices + */ +#define CFG_UART0_BASE 0x80120000 +#define CFG_UART1_BASE 0x80121000 +#define CFG_UART2_BASE 0x80007000 +#define CFG_SERIAL0 CFG_UART0_BASE +#define CFG_SERIAL1 CFG_UART1_BASE +#define CFG_SERIAL2 CFG_UART2_BASE +#define CONFIG_PL011_CLOCK 38400000 +#define CONFIG_PL01x_PORTS { (void *) (CFG_SERIAL0), (void *) (CFG_SERIAL1), (void *) (CFG_SERIAL2) } +#define CONFIG_CONS_INDEX 2 +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +// do_fat_read will loop (insane timeout), e.g. fail, if this is defined +#define CONFIG_MMC 1 +#define CONFIG_DOS_PARTITION 1 + +#define CONFIG_CMD_MEMORY +#define CONFIG_CMD_BOOTD +#define CONFIG_CMD_BDI +#define CONFIG_CMD_IMI +#define CONFIG_CMD_MISC +#define CONFIG_CMD_RUN +#define CONFIG_CMD_ECHO +#define CONFIG_CMD_CONSOLE +#define CONFIG_CMD_LOADS +#define CONFIG_CMD_LOADB +#define CONFIG_CMD_MMC +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EMMC + +#define CONFIG_BOOTDELAY 5 +#define CONFIG_BOOTARGS "cachepolicy=writealloc root=/dev/ram0 initrd=0x800000,20M init=linuxrc rw console=ttyAMA2,115200n8 mem=256M board_id=0" +#define CONFIG_BOOTCOMMAND "emmc_read 0x100000 0x280000 0x200000; bootm 0x100000" + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "loadaddr=0x00100000\0" \ + "console=ttyAMA2,115200n8\0" \ + "loadbootscript=fatload mmc 0 ${loadaddr} boot.scr\0" \ + "bootscript=echo Running bootscript from mmc ...; " \ + "source ${loadaddr}\0" \ + "loaduimage=fatload mmc 0 ${loadaddr} uImage\0" \ + "usbtty=cdc_acm\0"\ + "stdout=serial,usbtty\0" \ + "stdin=serial,usbtty\0" \ + "stderr=serial,usbtty\0" + +#define CONFIG_USB_TTY 1 +#ifndef CONFIG_USB_TTY +#define CONFIG_PREBOOT "mmc init;mmc_read_cmd_file" +#endif +/*----------------------------------------------------------------------- + * Miscellaneous configurable options + */ + +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_PROMPT "U8500 $ " /* Monitor Command Prompt */ +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ + +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE \ + + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE /* Boot Arg Buffer Size */ + +#undef CONFIG_SYS_CLKS_IN_HZ /* everything, incl board info, in Hz */ +#define CONFIG_SYS_LOAD_ADDR 0x800000 /* default load address */ +#define CONFIG_SYS_LOADS_BAUD_CHANGE 1 + +#define CONFIG_SYS_HUSH_PARSER 1 +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#define CONFIG_CMDLINE_EDITING + + +#define CONFIG_SETUP_MEMORY_TAGS 2 +#define CONFIG_INITRD_TAG 1 +#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ + +#define CONFIG_STACKSIZE (128*1024) /* regular stack */ +#ifdef CONFIG_USE_IRQ +#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */ +#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */ +#endif + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 2 /* we have dual bank of DRAM */ +#define PHYS_SDRAM_1 0x00000000 /* DDR-SDRAM Bank #1 */ +#define PHYS_SDRAM_SIZE_1 0x10000000 /* 256 MB */ +#define PHYS_SDRAM_2 0x20000000 /* DDR-SDRAM Bank #2 */ +#define PHYS_SDRAM_SIZE_2 0x10000000 /* 256 MB */ + +/*----------------------------------------------------------------------- + * MMC related configs + */ +#define MMC_BLOCK_SIZE 512 +#define CFG_MMC_BASE 0x80126000 /* MMC base for 8500 */ + +/*----------------------------------------------------------------------- + * EMMC related configs + */ +#define CFG_EMMC_BASE 0x80114000 /* EMMC base of size 2GB for 8500 */ +#define CONFIG_CMD_ENV +#define CONFIG_CMD_SAVEENV /* CMD_ENV is obsolete but used in env_emmc.c */ +#define CONFIG_ENV_IS_IN_EMMC 1 +#define CONFIG_ENV_OFFSET_START 0x260000 +#define CONFIG_ENV_OFFSET_END 0x27F000 + +/*----------------------------------------------------------------------- + * USB related configs + */ +#define CONFIG_USB_BASE 0xA03E0000 +#define UDC_BASE 0xA03E0000 + +#define CONFIG_USB_DEVICE 1 +#define CONFIG_MUSB 1 /* Enable USB driver */ +#ifdef CONFIG_USB_TTY +#define CONFIG_USBTTY "cdc_acm" /* XXX: obsoleted */ +/* Allow console in serial and USB at the same time */ +#define CONFIG_CONSOLE_MUX 1 +#define CONFIG_SYS_CONSOLE_IS_IN_ENV 1 +#define __LITTLE_ENDIAN 1 /* XXX: not necessary, handled by buildsystem */ +#define CONFIG_SYS_CONSOLE_ENV_OVERWRITE +#endif +/*----------------------------------------------------------------------- + * FLASH and environment organization + */ +#ifndef CONFIG_U8500_V1 + +#define CONFIG_SYS_MAX_FLASH_SECT 512 +#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ + +#else + +#define CFG_POP_EMMC_BASE 0x80005000 /*POP EMMC base of size 256MB for 8500 cut1.0 */ + +#endif + +/*------------------------------------------------------------------------------ + * base register values for U8500 + */ +#define CFG_PRCMU_BASE 0x80157000 /* Power, reset and clock Management Unit */ +#define CFG_SDRAMC_BASE 0x903CF000 /* SDRAMC cnf registers */ +#define CFG_FSMC_BASE 0x80000000 /* FSMC Controller */ + +/* + * U8500 GPIO register base for 9 banks + */ +#define CFG_GPIO_0_BASE 0x8012E000 +#define CFG_GPIO_1_BASE 0x8012E080 +#define CFG_GPIO_2_BASE 0x8000E000 +#define CFG_GPIO_3_BASE 0x8000E080 +#define CFG_GPIO_4_BASE 0x8000E100 +#define CFG_GPIO_5_BASE 0x8000E180 +#define CFG_GPIO_6_BASE 0x8011E000 +#define CFG_GPIO_7_BASE 0x8011E080 +#define CFG_GPIO_8_BASE 0xA03FE000 + +/* + * U8500 I2C0 register base for SD card + */ +#define CFG_I2C0_BASE 0x80004000 + +/* + * U8500 RTC register base + */ +#define CFG_RTC_BASE 0x80154000 /* Real time clock */ + +#endif /* __CONFIG_H */ diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h new file mode 100755 index 000000000..c1cb99601 --- /dev/null +++ b/include/usb/musb_udc.h @@ -0,0 +1,119 @@ +/* + * (C) Copyright 2009 Texas Instruments Incorporated. + * + * Based on + * u-boot OMAP1510 USB drivers (include/usbdcore_omap1510.h) + * + * Author: Diego Dompe (diego.dompe@ridgerun.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MUSB_UDC_H__ +#define __MUSB_UDC_H__ + +/* USB Function Module Registers */ + +/* + * UDC_BASE is defined for the specific silicon under soc + * specific cpu.h or related header. + */ + +#define UDC_OFFSET(offset) (UDC_BASE+(offset)) + +#define UDC_INTSRCR UDC_OFFSET(0x0A) /* USB Interrupt src reg */ +#define UDC_INTCLRR UDC_OFFSET(0x0A) /* USB Interrupt src clr reg */ + +#define UDC_FADDR UDC_OFFSET(0x00) +#define UDC_POWER UDC_OFFSET(0x01) +#define UDC_INTRTX UDC_OFFSET(0x02) +#define UDC_INTRRX UDC_OFFSET(0x04) +#define UDC_INTRTXE UDC_OFFSET(0x06) /* Enable reg for INTRTX */ +#define UDC_INTRRXE UDC_OFFSET(0x08) /* Enable reg for INTRRX */ +#define UDC_INTRUSB UDC_OFFSET(0x0A) +#define UDC_INTRUSBE UDC_OFFSET(0x0B) +#define UDC_INDEX UDC_OFFSET(0x0E) +#define UDC_TESTMODE UDC_OFFSET(0x0F) +#define UDC_TXMAXP UDC_OFFSET(0x10) +#define UDC_CSR0 UDC_OFFSET(0x12) +#define UDC_TXCSR UDC_OFFSET(0x12) +#define UDC_RXMAXP UDC_OFFSET(0x14) +#define UDC_RXCSR UDC_OFFSET(0x16) +#define UDC_COUNT0 UDC_OFFSET(0x18) +#define UDC_RXCOUNT UDC_OFFSET(0x18) +#define UDC_FIFO0 UDC_OFFSET(0x20) +#define UDC_FIFO1 UDC_OFFSET(0x24) +#define UDC_FIFO2 UDC_OFFSET(0x28) +#define UDC_FIFO3 UDC_OFFSET(0x2C) +#define UDC_FIFO4 UDC_OFFSET(0x30) +#define UDC_FIFO5 UDC_OFFSET(0x34) +#define UDC_FIFO6 UDC_OFFSET(0x38) +#define UDC_FIFO7 UDC_OFFSET(0x3C) +#define UDC_FIFO8 UDC_OFFSET(0x40) +#define UDC_FIFO9 UDC_OFFSET(0x44) +#define UDC_FIFO10 UDC_OFFSET(0x48) +#define UDC_FIFO11 UDC_OFFSET(0x4C) +#define UDC_FIFO12 UDC_OFFSET(0x50) +#define UDC_FIFO13 UDC_OFFSET(0x54) +#define UDC_FIFO14 UDC_OFFSET(0x58) +#define UDC_FIFO15 UDC_OFFSET(0x5C) +#define UDC_DEVCTL UDC_OFFSET(0x60) +#define UDC_TXFIFOSZ UDC_OFFSET(0x62) +#define UDC_RXFIFOSZ UDC_OFFSET(0x63) +#define UDC_TXFIFOADDR UDC_OFFSET(0x64) +#define UDC_RXFIFOADDR UDC_OFFSET(0x66) + +#define UDC_SYSCONFIG UDC_OFFSET(0x404) +#define UDC_INTERFSEL UDC_OFFSET(0x40C) +#define UDC_FORCESTDBY UDC_OFFSET(0x414) + +/* MUSB Endpoint parameters */ +#define EP0_MAX_PACKET_SIZE 64 +#define UDC_OUT_ENDPOINT 2 /* Device RX endpoint */ +#define UDC_OUT_PACKET_SIZE 512 +#define UDC_IN_ENDPOINT 3 /* Device TX endpoint */ +#define UDC_IN_PACKET_SIZE 512 +#define UDC_INT_ENDPOINT 1 /* Device Interrupt/Status endpoint */ +#define UDC_INT_PACKET_SIZE 16 +#define UDC_BULK_PACKET_SIZE 512 + +#define UDC_MAX_FIFO_SIZE 16384 + +#define DEV_CONFIG_VALUE 1 /* Only one i.e. CDC */ + +void udc_irq(void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak(int epid); + +/* Higher level functions for abstracting away from specific device */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int udc_init(void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *endpoint); + +/* platform specific initialization */ +int udc_musb_platform_init(void); + +#endif /* __MUSB_UDC_H__ */ |