diff options
Diffstat (limited to 'board')
-rwxr-xr-x | board/st/u8500/Makefile | 52 | ||||
-rwxr-xr-x | board/st/u8500/common.h | 134 | ||||
-rw-r--r-- | board/st/u8500/config.mk | 18 | ||||
-rwxr-xr-x | board/st/u8500/core2.S | 56 | ||||
-rw-r--r-- | board/st/u8500/emmc.c | 408 | ||||
-rwxr-xr-x | board/st/u8500/emmc.h | 37 | ||||
-rwxr-xr-x | board/st/u8500/flash.c | 109 | ||||
-rwxr-xr-x | board/st/u8500/gpio.c | 253 | ||||
-rwxr-xr-x | board/st/u8500/gpio.h | 524 | ||||
-rwxr-xr-x | board/st/u8500/i2c.c | 3029 | ||||
-rwxr-xr-x | board/st/u8500/i2c.h | 848 | ||||
-rw-r--r-- | board/st/u8500/init_mmc.c | 347 | ||||
-rwxr-xr-x | board/st/u8500/init_mmc.h | 44 | ||||
-rw-r--r-- | board/st/u8500/mmc.c | 2594 | ||||
-rwxr-xr-x | board/st/u8500/mmc.h | 263 | ||||
-rwxr-xr-x | board/st/u8500/mmc_p.h | 316 | ||||
-rw-r--r-- | board/st/u8500/mmc_utils.c | 1022 | ||||
-rwxr-xr-x | board/st/u8500/mmc_utils.h | 108 | ||||
-rw-r--r-- | board/st/u8500/u8500.c | 347 |
19 files changed, 10509 insertions, 0 deletions
diff --git a/board/st/u8500/Makefile b/board/st/u8500/Makefile new file mode 100755 index 000000000..632a49161 --- /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 := core2.o + +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 100644 index 000000000..62c222dfa --- /dev/null +++ b/board/st/u8500/config.mk @@ -0,0 +1,18 @@ +# mop500/href: +# +# Valid values for TEXT_BASE are: +# +# Standard configuration - all models +# 0x07F8_0000 run from SDRAM +# +# Test configuraton +# 0x4001_0000 run from eSRAM + + +sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp + +ifndef TEXT_BASE +TEXT_BASE = 0x05FC0000 +endif + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) diff --git a/board/st/u8500/core2.S b/board/st/u8500/core2.S new file mode 100755 index 000000000..7152e3077 --- /dev/null +++ b/board/st/u8500/core2.S @@ -0,0 +1,56 @@ +/* + * secondary_wfe() + * Copyright (c) 2009 ST Ericsson + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> + * + * puts the secondary core in wfe. This is required for the locked + * version of ST Ericsson SMP platform to attach the debugger at this stage. + * This is a GCC generated code. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +.global secondary_startup +secondary_startup: + dsb @ WFI may enter a low-power mode + wfi + mov pc, lr + +.global secondary_wfe +secondary_wfe: +.L8: wfe + ldr r0, .L9 + ldr r1, .L9+4 + ldr r3, [r0, #4080] + str r3, [r1, #0] + ldr r3, .L9+8 + ldr r2, [r1, #0] + cmp r2, r3 + bne .L8 + ldr r3, [r0, #4084] + str r3, [r1, #4] + blx r3 + b .L8 +.L10: + .align 2 +.L9: + .word -2146103296 + .word .LANCHOR0 + .word -1577128703 + .size secondary_wfe, .-secondary_wfe + .global handler + .global magic_num + .bss + .align 2 +.LANCHOR0 = . + 0 + .type magic_num, %object + .size magic_num, 4 +magic_num: + .space 4 + .type handler, %object + .size handler, 4 +handler: + .space 4 + .ident "GCC: (GNU) 4.2.3" + .section .note.GNU-stack,"",%progbits diff --git a/board/st/u8500/emmc.c b/board/st/u8500/emmc.c new file mode 100644 index 000000000..110c73702 --- /dev/null +++ b/board/st/u8500/emmc.c @@ -0,0 +1,408 @@ +/* +* (C) Copyright 2009 +* ST-Ericsson, <www.stericsson.com> +* +* See file CREDITS for list of people who contributed to this +* project. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, +* MA 02111-1307 USA +*/ +/* --- includes ----------------------------------------------------------- */ +#include "common.h" /* XXX: Arrgghh! "common.h" includes <common.h> */ +#include <command.h> +#include "mmc.h" +#include "emmc.h" +#include "gpio.h" +#include <asm/boottime.h> + +#define PIB_EMMC_ADDR 0x00 +/* ======================================================================== +Name: init_emmc +Description: init embedded multimedia card interface + +======================================================================== */ +int emmc_init(u8 card_num) +{ + t_mmc_error mmc_error; + t_mmc_error response; + gpio_error gpioerror; + int error; + +#ifndef CONFIG_U8500_V1 +/* Initialize the base address of eMMC */ + mmc_error = mmc_init(card_num, CFG_EMMC_BASE); + + if (MMC_OK != mmc_error) + { + printf("emmc_init() %d \n", mmc_error); + goto end; + } + + /* Initialize the gpio alternate function for eMMC */ + struct gpio_register *p_gpio_register = (void *) IO_ADDRESS(CFG_GPIO_6_BASE); + p_gpio_register -> gpio_dats |= 0x0000FFE0; + p_gpio_register -> gpio_pdis &= ~0x0000FFE0; + + //enable the alternate function of EMMC + gpioerror = gpio_altfuncenable(GPIO_ALT_EMMC, "EMMC"); + if(gpioerror != GPIO_OK) + { + printf("emmc_init() gpio_altfuncenable %d failed\n", gpioerror); + goto end; + } + +#else +/* Initialize the base address of PoP eMMC */ + mmc_error = mmc_init(card_num, CFG_POP_EMMC_BASE); + + if (MMC_OK != mmc_error) + { + printf("emmc_init() %d \n", mmc_error); + goto end; + } + //enable the alternate function of PoP EMMC + gpioerror = gpio_altfuncenable(GPIO_ALT_POP_EMMC, "EMMC"); + if (gpioerror != GPIO_OK) { + printf("emmc_init() gpio_altfuncenable %d failed \n", + gpioerror); + goto end; + } +#endif + //Power-on the controller + response = mmc_poweron(card_num); + if (response != MMC_OK) + { + printf("Error in eMMC power on, response is %d\n",response); + goto end; + } + // Initialise the cards,get CID and CSD on the bus + response = mmc_initializeCards(card_num); + + if (response != MMC_OK) + { + printf(" Error in eMMC initialization\n"); + goto end; + } + + error = emmc_write_pib(); + if(error) + printf("PIB info writing into eMMC failed\n"); + printf("eMMC done\n"); + + return 0; + +end: +#ifndef CONFIG_U8500_V1 + gpio_altfuncdisable(GPIO_ALT_EMMC, "EMMC"); +#else + gpio_altfuncdisable(GPIO_ALT_POP_EMMC, "EMMC"); +#endif + mmc_poweroff(card_num); + return 1; +} + +int emmc_write_pib(void) +{ + int i; + t_mmc_error mmc_error; + u32 block_offset = PIB_EMMC_ADDR; + u8 emmc_last_sector[512]; + u8 card_num = 4; + + for (i = 0; i < 0x1BF; i++) { + emmc_last_sector[i] = 0; + } + emmc_last_sector[0x1BF] = 0x03; + emmc_last_sector[0x1C0] = 0xD0; + emmc_last_sector[0x1C1] = 0xFF; + emmc_last_sector[0x1C2] = 0x83; + emmc_last_sector[0x1C3] = 0x03; + emmc_last_sector[0x1C4] = 0xD0; + emmc_last_sector[0x1C5] = 0xFF; + emmc_last_sector[0x1C6] = 0x00; + emmc_last_sector[0x1C7] = 0x00; + emmc_last_sector[0x1C8] = 0x0A; + emmc_last_sector[0x1C9] = 0x00; + emmc_last_sector[0x1CA] = 0x00; + emmc_last_sector[0x1CB] = 0x40; + emmc_last_sector[0x1CC] = 0x00; + emmc_last_sector[0x1CD] = 0x00; + emmc_last_sector[0x1CE] = 0x00; + emmc_last_sector[0x1CF] = 0x03; + emmc_last_sector[0x1D0] = 0xD0; + emmc_last_sector[0x1D1] = 0xFF; + emmc_last_sector[0x1D2] = 0x83; + emmc_last_sector[0x1D3] = 0x03; + emmc_last_sector[0x1D4] = 0xD0; + emmc_last_sector[0x1D5] = 0xFF; + emmc_last_sector[0x1D6] = 0x00; + emmc_last_sector[0x1D7] = 0x40; + emmc_last_sector[0x1D8] = 0x0A; + emmc_last_sector[0x1D9] = 0x00; + emmc_last_sector[0x1DA] = 0x00; + emmc_last_sector[0x1DB] = 0x00; + emmc_last_sector[0x1DC] = 0x08; + emmc_last_sector[0x1DD] = 0x00; + emmc_last_sector[0x1DE] = 0x00; + emmc_last_sector[0x1DF] = 0x03; + emmc_last_sector[0x1E0] = 0xD0; + emmc_last_sector[0x1E1] = 0xFF; + emmc_last_sector[0x1E2] = 0x83; + emmc_last_sector[0x1E3] = 0x03; + emmc_last_sector[0x1E4] = 0xD0; + emmc_last_sector[0x1E5] = 0xFF; + emmc_last_sector[0x1E6] = 0x00; + emmc_last_sector[0x1E7] = 0x40; + emmc_last_sector[0x1E8] = 0x12; + emmc_last_sector[0x1E9] = 0x00; + emmc_last_sector[0x1EA] = 0x00; + emmc_last_sector[0x1EB] = 0xC0; + emmc_last_sector[0x1EC] = 0x22; + emmc_last_sector[0x1ED] = 0x00; + emmc_last_sector[0x1EE] = 0x00; + emmc_last_sector[0x1EF] = 0x03; + emmc_last_sector[0x1F0] = 0xD0; + emmc_last_sector[0x1F1] = 0xFF; + emmc_last_sector[0x1F2] = 0x0C; + emmc_last_sector[0x1F3] = 0x03; + emmc_last_sector[0x1F4] = 0xD0; + emmc_last_sector[0x1F5] = 0xFF; + emmc_last_sector[0x1F6] = 0x00; + emmc_last_sector[0x1F7] = 0x00; + emmc_last_sector[0x1F8] = 0x35; + emmc_last_sector[0x1F9] = 0x00; + emmc_last_sector[0x1FA] = 0x00; + emmc_last_sector[0x1FB] = 0xA0; + emmc_last_sector[0x1FC] = 0xB9; + emmc_last_sector[0x1FD] = 0x00; + emmc_last_sector[0x1FE] = 0x55; + emmc_last_sector[0x1FF] = 0xAA; + +/* HACK required for HREF board as erase block size = 512KB */ +/* + mmc_error = mmc_erase(card_num, 0x0, 0x1FF); + if (mmc_error != MMC_OK) { + printf(" eMMC erase failed in PIB \n"); + return 1; + } +*/ + mmc_error = + mmc_writeblocks(card_num, block_offset, (u32 *) emmc_last_sector, + 512, 1); + if (mmc_error != MMC_OK) { + printf(" eMMC PIB write failed \n"); + return 1; + } + return 0; +} + +int emmc_erase(u32 start, u32 end) +{ + t_mmc_error mmc_error; + u8 card_num = 4; + printf("emmc erase start \n"); + mmc_error = mmc_erase(card_num, start, end); + if (mmc_error != MMC_OK) { + printf(" eMMC erase failed \n"); + return 1; + } + printf("emmc erase done \n"); + return 0; +} + +int emmc_read(u32 block_offset, u32 read_buffer, u32 filesize) +{ + t_mmc_error mmc_error; + u32 remaining; + u8 card_num = 4; + u8 *mem_address = (u8 *) read_buffer; + u32 n=filesize,blocks; + + remaining = filesize; + + printf(" eMMC read start filesize=0x%x \n", filesize); + + blocks = (n%512==0)?(n/512):(n/512)+1; + + while(blocks>=8) + { + mmc_error = mmc_readblocks(card_num, block_offset, (u32 *) mem_address, 512, 8); + if (mmc_error != MMC_OK) + { + printf(" eMMC read blocks failed \n"); + return 1; + } + + block_offset += 4096; + mem_address += 4096; + blocks -=8; + remaining -= 4096; + } + if(blocks) + { + mmc_error = mmc_readblocks(card_num, block_offset, (u32 *) mem_address, 512, blocks); + if (mmc_error != MMC_OK) + { + printf(" eMMC read blocks failed \n"); + return 1; + } + } + + printf(" eMMC read done \n"); + return 0; +} + +int emmc_write(u32 block_offset, u32 write_buffer, u32 filesize) +{ + t_mmc_error mmc_error; + u32 remaining; + u8 card_num = 4; + u8 *mem_address = (u8 *) write_buffer; + u32 n=filesize,blocks; + + remaining = filesize; + + printf(" eMMC write start filesize=0x%x \n", filesize); + + blocks = (n%512==0)?(n/512):(n/512)+1; + while(blocks>=8) + { + mmc_error = mmc_writeblocks(card_num, block_offset, (u32 *) mem_address,512, 8); + if (mmc_error != MMC_OK) + { + printf(" eMMC write blocks failed \n"); + return 1; + } + + block_offset += 4096; + mem_address += 4096; + blocks -=8; + remaining -= 4096; + } + if(blocks) + { + + mmc_error = mmc_writeblocks(card_num, block_offset, (u32 *) mem_address,512, blocks); + if (mmc_error != MMC_OK) + { + printf(" eMMC write blocks failed \n"); + return 1; + } + + } + + printf(" eMMC write done \n"); + return 0; +} + +/* + * command line commands + */ +#ifdef CONFIG_CMD_EMMC +int do_emmc_erase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + u32 start_address; + u32 end_address; + int load_result = 1; + u32 error_name = 0; + + start_address = simple_strtoul (argv[1],0,16); + end_address = simple_strtoul (argv[2],0,16); + + printf("emmc_erase :: start address = %x end_address=0x%x\n",start_address,end_address); + + load_result = emmc_erase(start_address,end_address); + if (load_result != 0) + { + error_name = (unsigned long) (-load_result); + printf("emmc_erase error : failed \n"); + } + return(0); +} + +U_BOOT_CMD( + emmc_erase, 3, 0, do_emmc_erase, + "- erase the eMMC flash \n", + "start_address- start address of the eMMC block\n" + "end_address- end address of the eMMC block\n" +); + +int do_emmc_read (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + u32 ram_address; + u32 block_offset; + u32 filesize; + int load_result = 1; + u32 error_name = 0; + + ram_address = simple_strtoul (argv[1],0,16); + block_offset = simple_strtoul (argv[2],0,16); + filesize = simple_strtoul (argv[3],0,16); + + boottime_tag("load_image"); + printf("emmc_read :: ram address = 0x%x block address=0x%x \n",ram_address,block_offset); + + load_result = emmc_read(block_offset,ram_address,filesize); + if (load_result != 0) + { + boottime_remove_last(); + error_name = (unsigned long) (-load_result); + printf("emmc_read error : in reading data from eMMC block \n"); + } + return(0); +} + +U_BOOT_CMD( + emmc_read, 4, 0, do_emmc_read, + "- read file from emmc flash \n", + "ram_address - read from eMMC and copy into ram address\n" + "block_offset - address to read the file from the eMMC block \n" + "filesize - size of the file \n" +); + +int do_emmc_write (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + u32 ram_address; + u32 block_offset; + u32 filesize; + int load_result = 1; + u32 error_name = 0; + + ram_address = simple_strtoul (argv[1],0,16); + block_offset = simple_strtoul (argv[2],0,16); + filesize = simple_strtoul (argv[3],0,16); + + printf("emmc_write :: ram address = %x block address=0x%x \n",ram_address,block_offset); + + load_result = emmc_write(block_offset,ram_address,filesize); + if (load_result != 0) + { + error_name = (unsigned long) (-load_result); + printf("emmc_read error : in writing data into eMMC block \n"); + } + return(0); +} + +U_BOOT_CMD( + emmc_write, 4, 0, do_emmc_write, + "- write file from emmc flash \n", + "ram_address - write to eMMC by copying from ram address\n" + "block_offset - address to write the file into the eMMC block \n" + "filesize - size of the file \n" +); + +#endif /* CONFIG_CMD_EMMC */ +/* ------------------------------- End of file ---------------------------- */ 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 100644 index 000000000..5ee8190af --- /dev/null +++ b/board/st/u8500/init_mmc.c @@ -0,0 +1,347 @@ +/* + * (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" + +#define HREF_BOARD_ID ('1') +#define MOP500_BOARD_ID ('0') +char Bootargs_buf[512]; + +#ifdef CONFIG_CMD_FAT +#include <part.h> +#include <fat.h> +#endif + +#define LOOP(x) {int i;for(i=0;i<1000;i++);} + +#define MMC_CARD_NUM 1 +#define EMMC_CARD_NUM 4 +enum { + DEV_EMMC = 0, + DEV_MMC +}; + +static block_dev_desc_t mmc_dev; +static block_dev_desc_t emmc_dev; +static u32 CSD[4]; + +block_dev_desc_t * mmc_get_dev(int dev) +{ + if (dev == DEV_EMMC) + return (block_dev_desc_t *)(&emmc_dev); + else if (dev == DEV_MMC) + return (block_dev_desc_t *)(&mmc_dev); + + printf("mmc_get_dev: unknown dev %d\n", dev); + return 0; +} + +static unsigned long emmc_block_read(int dev, unsigned long blknr, + lbaint_t blkcnt, void *dest) +{ + unsigned long rc; + + rc = mmc_readblocks(EMMC_CARD_NUM, (u32) (512 * blknr), (u32 *)dest, + 512, blkcnt); + if (rc != 0) { + printf("mmc_block_read: readblocks failed %ld\n", rc); + rc = 0; + } else { + rc = blkcnt; + } + return rc; +} + +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, blksize, transfer mode */ + mmc_readblock(MMC_CARD_NUM, (u32) (512 * src), + (u32 *)dest, 512, MMCPOLLING); + rc++; + src++; + dest += 512; + } + return rc; +} + +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; +} + +#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 */ + + +static 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}; + char board_id = HREF_BOARD_ID; + + 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); + board_id = MOP500_BOARD_ID; + } + 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); + board_id = HREF_BOARD_ID; + if(error_status) + printf("Error in I2C_WriteMultipleData error = %d",error_status); + + } + else + printf("\nunknown platform: chip ID = %x\n", read_data); + + /* Now modify bootargs to save the board_id, required for automatic platform detection */ + char * bootargs = getenv("bootargs"); + if(sizeof(Bootargs_buf) < strlen(bootargs)) { + printf("ERROR: Insufficient temp buffer, bootargs not modified"); + return; + } + strcpy(Bootargs_buf, bootargs); + bootargs = strstr (Bootargs_buf, "board_id="); + if(bootargs){ + /*board_id parameter already present , modify correct value*/ + bootargs[9] = board_id; + } + else { + /*board_id parameter not present , append board_id with proper value*/ + strcat(Bootargs_buf, " board_id=1 "); + /*point to the last character of string*/ + bootargs = Bootargs_buf + strlen(Bootargs_buf) -2; + *bootargs = board_id; + } + /*Now save the new bootargs*/ + setenv("bootargs", Bootargs_buf); + saveenv(); + //printf("Bootargs after platform detection:\n%s\n", getenv("bootargs")); + return; +} + + +/* + * mmc_legacy_init - called from commandline mmc init <dev> + * + * Initialise hardware and setup block device structure for fat and ext2 + * commands. + */ +int mmc_legacy_init(int dev) +{ + + if (dev == DEV_EMMC) { + printf("EMMC init\n"); + /* XXX: emmc_init() does write the MBR (called pib)! */ + emmc_init(EMMC_CARD_NUM); + emmc_dev.if_type = IF_TYPE_MMC; + emmc_dev.part_type = PART_TYPE_DOS; + emmc_dev.dev = dev; + emmc_dev.lun = 0; + emmc_dev.type = 0; + emmc_dev.blksz = 512; + emmc_dev.lba = 0x80000; /* XXX: use real size, here 256 MB */ + sprintf((char*)emmc_dev.vendor, "Unknown vendor"); + sprintf((char*)emmc_dev.product, "Unknown product"); + sprintf((char*)emmc_dev.revision, "N/A"); + emmc_dev.removable = 0; + emmc_dev.block_read = emmc_block_read; + return 0; + } else if (dev == DEV_MMC) { + printf("MMC init\n"); + /* config extended GPIO pins for Level shifter and + * SDMMC_ENABLE */ + config_extended_gpio(); + init_mmc(); + return 0; + } + + printf("mmc_legacy_init: unsupported device# %d\n", dev); + return -1; +} + +/* ======================================================================== + 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 |= 0xFFC0000; + gpio_base_address -> gpio_pdis &= ~0xFFC0000; + + 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; +#ifdef CONFIG_CMD_FAT + 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 100644 index 000000000..98b353a3a --- /dev/null +++ b/board/st/u8500/mmc.c @@ -0,0 +1,2594 @@ +/* +* (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; + + if (card_num != selected_card) + { + t_mmc[card_num]->mmc_Argument = card_array[card_num].RCA; + 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; + } + + t_mmc[card_num]->mmc_Argument = (u32) (0x03B70201); + t_mmc[card_num]->mmc_Command = + APP_SD_SET_BUSWIDTH | RespExpected | 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; + t_mmc[card_num]->mmc_Clock = 0x7500; + + 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 100644 index 000000000..a9119f883 --- /dev/null +++ b/board/st/u8500/mmc_utils.c @@ -0,0 +1,1022 @@ +/* + * (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(0x00); /* 26 MHz */ + 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_select_n_switch () +{ + t_mmc_error error = MMC_OK; + t_mmc_command_control commcontrol; + t_mmc_clock_control clockcontrol; + u32 response; + u8 cardno = 1; + + commcontrol.IsRespExpected = TRUE; + commcontrol.IsLongResp = FALSE; + commcontrol.IsInterruptMode = FALSE; + commcontrol.IsPending = FALSE; + commcontrol.cmdpath = MMC_ENABLE; + + // 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) + { + error = MMC_LOCK_UNLOCK_FAILED; + goto end; + } + /* + error = mmc_sendcommand (MMC_APP_CMD, 0x00000000, commcontrol); + error = mmc_cmdresp145error_2(MMC_APP_CMD); + error = mmc_sendcommand (6, 0x2, commcontrol); + error = mmc_cmdresp145error_2(6); + if (error != MMC_OK) + { + goto end; + } + clockcontrol.pwrsave= MMC_DISABLE; + clockcontrol.bypass = MMC_DISABLE; + clockcontrol.widebus= MMC_ENABLE; + error = mmc_configclockcontrol (clockcontrol); + if (error != MMC_OK) + { + goto end; + } + */ +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; + } + + // Select card and switch to 4-Bit, TODO HS if possible + response = mmc_select_n_switch (); + + if (response != MMC_OK) + { + printf ("Error while select or switching to 4-bit/HS\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"); + 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 100644 index 000000000..5be3f5149 --- /dev/null +++ b/board/st/u8500/u8500.c @@ -0,0 +1,347 @@ +/* +* (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 <config.h> +#include <asm/types.h> +#include <asm/io.h> +#include <asm/errno.h> + +#include "common.h" +#define NOMADIK_PER4_BASE (0x80150000) +#define NOMADIK_BACKUPRAM0_BASE (NOMADIK_PER4_BASE + 0x00000) +#define NOMADIK_BACKUPRAM1_BASE (NOMADIK_PER4_BASE + 0x01000) + +/* Power, Reset, Clock Management Unit */ +/* + * SVA: Smart Video Accelerator + * SIA: Smart Imaging Accelerator + * SGA: Smart Graphic accelerator + * B2R2: Graphic blitter + */ +#define PRCMU_BASE CFG_PRCMU_BASE /* 0x80157000 for U8500 */ +#define PRCM_ARMCLKFIX_MGT_REG (PRCMU_BASE + 0x000) +#define PRCM_ACLK_MGT_REG (PRCMU_BASE + 0x004) +#define PRCM_SVAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x008) +#define PRCM_SIAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x00C) +#define PRCM_SAAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x010) +#define PRCM_SGACLK_MGT_REG (PRCMU_BASE + 0x014) +#define PRCM_UARTCLK_MGT_REG (PRCMU_BASE + 0x018) +#define PRCM_MSPCLK_MGT_REG (PRCMU_BASE + 0x01C) +#define PRCM_I2CCLK_MGT_REG (PRCMU_BASE + 0x020) +#define PRCM_SDMMCCLK_MGT_REG (PRCMU_BASE + 0x024) +#define PRCM_SLIMCLK_MGT_REG (PRCMU_BASE + 0x028) +#define PRCM_PER1CLK_MGT_REG (PRCMU_BASE + 0x02C) +#define PRCM_PER2CLK_MGT_REG (PRCMU_BASE + 0x030) +#define PRCM_PER3CLK_MGT_REG (PRCMU_BASE + 0x034) +#define PRCM_PER5CLK_MGT_REG (PRCMU_BASE + 0x038) +#define PRCM_PER6CLK_MGT_REG (PRCMU_BASE + 0x03C) +#define PRCM_PER7CLK_MGT_REG (PRCMU_BASE + 0x040) +#define PRCM_DMACLK_MGT_REG (PRCMU_BASE + 0x074) +#define PRCM_B2R2CLK_MGT_REG (PRCMU_BASE + 0x078) + +#define PRCM_PLLSOC0_FREQ_REG (PRCMU_BASE + 0x080) +#define PRCM_PLLSOC1_FREQ_REG (PRCMU_BASE + 0x084) +#define PRCM_PLLARM_FREQ_REG (PRCMU_BASE + 0x088) +#define PRCM_PLLDDR_FREQ_REG (PRCMU_BASE + 0x08C) +#define PRCM_ARM_CHGCLKREQ_REG (PRCMU_BASE + 0x114) + +#define PRCM_TCR (PRCMU_BASE + 0x1C8) + +/* PLLs for clock management registers */ +enum { + GATED = 0, + PLLSOC0, /* pllsw = 001, ffs() = 1 */ + PLLSOC1, /* pllsw = 010, ffs() = 2 */ + PLLDDR, /* pllsw = 100, ffs() = 3 */ + PLLARM, +}; + +static struct pll_freq_regs { + int idx; /* index fror pll_name and pll_khz arrays */ + uint32_t addr; +} pll_freq_regs[] = { + {PLLSOC0, PRCM_PLLSOC0_FREQ_REG}, + {PLLSOC1, PRCM_PLLSOC1_FREQ_REG}, + {PLLDDR, PRCM_PLLDDR_FREQ_REG}, + {PLLARM, PRCM_PLLARM_FREQ_REG}, + {0, 0}, +}; + +static const char *pll_name[5] = {"GATED", "SOC0", "SOC1", "DDR", "ARM"}; +static uint32_t pll_khz[5]; /* use ffs(pllsw(reg)) as index for 0..3 */ + +static struct clk_mgt_regs { + uint32_t addr; + uint32_t val; + const char *descr; +} clk_mgt_regs[] = { + /* register content taken from bootrom settings */ + {PRCM_ARMCLKFIX_MGT_REG, 0x0120, "ARMCLKFIX"}, /* ena, SOC0/0, ??? */ + {PRCM_ACLK_MGT_REG, 0x0125, "ACLK"}, /* ena, SOC0/5, 160 MHz */ + {PRCM_SVAMMDSPCLK_MGT_REG, 0x1122, "SVA"}, /* ena, SOC0/2, 400 MHz */ + {PRCM_SIAMMDSPCLK_MGT_REG, 0x0022, "SIA"}, /* dis, SOC0/2, 400 MHz */ + {PRCM_SAAMMDSPCLK_MGT_REG, 0x0822, "SAA"}, /* dis, SOC0/4, 200 MHz */ + {PRCM_SGACLK_MGT_REG, 0x0024, "SGA"}, /* dis, SOC0/4, 200 MHz */ + {PRCM_UARTCLK_MGT_REG, 0x0300, "UART"}, /* ena, GATED, CLK38 */ + {PRCM_MSPCLK_MGT_REG, 0x0200, "MSP"}, /* dis, GATED, CLK38 */ + {PRCM_I2CCLK_MGT_REG, 0x0130, "I2C"}, /* ena, SOC0/16, 50 MHz */ + {PRCM_SDMMCCLK_MGT_REG, 0x0130, "SDMMC"}, /* ena, SOC0/16, 50 MHz */ + {PRCM_PER1CLK_MGT_REG, 0x126, "PER1"}, /* ena, SOC0/6, 133 MHz */ + {PRCM_PER2CLK_MGT_REG, 0x126, "PER2"}, /* ena, SOC0/6, 133 MHz */ + {PRCM_PER3CLK_MGT_REG, 0x126, "PER3"}, /* ena, SOC0/6, 133 MHz */ + {PRCM_PER5CLK_MGT_REG, 0x126, "PER5"}, /* ena, SOC0/6, 133 MHz */ + {PRCM_PER6CLK_MGT_REG, 0x126, "PER6"}, /* ena, SOC0/6, 133 MHz */ + {PRCM_PER7CLK_MGT_REG, 0x128, "PER7"}, /* ena, SOC0/8, 100 MHz */ + {PRCM_DMACLK_MGT_REG, 0x125, "DMA"}, /* ena, SOC0/5, 160 MHz */ + {PRCM_B2R2CLK_MGT_REG, 0x025, "B2R2"}, /* dis, SOC0/5, 160 MHz */ + {0, 0, NULL}, +}; + +/* U5500 (Maja) alike clock settings */ +static struct clk_mgt_regs maja_clk_regs[] = { + {PRCM_SVAMMDSPCLK_MGT_REG, 0x1124, "SVA"}, /* SOC0/4, 200 MHz */ + {PRCM_SIAMMDSPCLK_MGT_REG, 0x0024, "SIA"}, /* SOC0/6, 133 MHz */ + {PRCM_SGACLK_MGT_REG, 0x0025, "SGA"}, /* SOC0/5, 160 MHz */ + {0, 0, NULL}, +}; + +extern void (*handler)(void); +extern void secondary_wfe(void); + +void wake_up_other_cores(void) +{ + handler = secondary_wfe; + *((volatile unsigned int *)(NOMADIK_BACKUPRAM0_BASE+0x1FF4))= handler; + *((volatile unsigned int *)(NOMADIK_BACKUPRAM0_BASE+0x1FF0))= 0xA1FEED01; + asm("SEV"); + return; +} + +static void init_regs(void); + +DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_SHOW_BOOT_PROGRESS) +void show_boot_progress(int progress) +{ + printf("Boot reached stage %d\n", progress); +} +#endif + +/* + * Miscellaneous platform dependent initialisations + */ + +int board_init(void) +{ + gd->bd->bi_arch_number = 0x1A4; + gd->bd->bi_boot_params = 0x00000100; + /* MTU timer clock always enabled (not clocked) */ + writel(0x20000, PRCM_TCR); + icache_enable(); + gpio_init(); + + init_regs(); + return 0; +} + +#ifdef CONFIG_MISC_INIT_R +int misc_init_r(void) +{ + setenv("verify", "n"); + return (0); +} +#endif + +int dram_init(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE_1; +#ifdef CONFIG_U8500_V1 + gd->bd->bi_dram[1].start = PHYS_SDRAM_2; + gd->bd->bi_dram[1].size = PHYS_SDRAM_SIZE_2; +#endif + wake_up_other_cores(); + return 0; +} + +unsigned int addr_vall_arr[] = { +0x8011F000, 0x0000FFFF, // Clocks for HSI TODO Enable reqd only +0x8011F008, 0x00001CFF, // 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 +0x80157020, 0x00000150, // I2C 48MHz clock +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 +0x8012E000, 0x20000000, // GPIO ALT FUNC for UART +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, PRCM_APE_RESETN_SET_REG +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 + +static 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]; + } +} + +/* + * get_pll_freq_khz - return PLL frequency in kHz + */ +static uint32_t get_pll_freq_khz(uint32_t inclk_khz, uint32_t freq_reg) +{ + uint32_t idf, ldf, odf, seldiv, phi; + + /* + * PLLOUTCLK = PHI = (INCLK*LDF)/(2*ODF*IDF) if SELDIV2=0 + * PLLOUTCLK = PHI = (INCLK*LDF)/(4*ODF*IDF) if SELDIV2=1 + * where: + * IDF=R(2:0) (when R=000, IDF=1d) + * LDF = 2*D(7:0) (D must be greater than or equal to 6) + * ODF = N(5:0) (when N=000000, 0DF=1d) + */ + + idf = (freq_reg & 0x70000) >> 16; + ldf = (freq_reg & 0xff) * 2; + odf = (freq_reg & 0x3f00) >> 8; + seldiv = (freq_reg & 0x01000000) >> 24; + phi = (inclk_khz * ldf) / (2 * odf * idf); + if (seldiv) + phi = phi/2; + + return phi; +} + +int do_clkinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uint32_t inclk_khz; + uint32_t reg, phi; + uint32_t clk_khz; + unsigned int clk_sel; + struct clk_mgt_regs *clks = clk_mgt_regs; + struct pll_freq_regs *plls = pll_freq_regs; + + /* + * Go through list of PLLs. + * Initialise pll out frequency array (pll_khz) and print frequency. + */ + inclk_khz = 38400; /* 38.4 MHz */ + while (plls->addr) { + reg = readl(plls->addr); + phi = get_pll_freq_khz(inclk_khz, reg); + pll_khz[plls->idx] = phi; + printf("%s PLL out frequency: %d.%d Mhz\n", + pll_name[plls->idx], phi/1000, phi % 1000); + plls++; + } + + /* check ARM clock source */ + reg = readl(PRCM_ARM_CHGCLKREQ_REG); + printf("A9 running on "); + if (reg & 1) + printf("external clock"); + else + printf("ARM PLL"); + printf("\n"); + + /* go through list of clk_mgt_reg */ + printf("\n%19s %9s %7s %9s enabled\n", + "name(addr)", "value", "PLL", "CLK[MHz]"); + while (clks->addr) { + reg = readl(clks->addr); + /* convert bit position into array index */ + clk_sel = ffs((reg >> 5) & 0x7); /* PLLSW[2:0] */ + printf("%9s(%08x): %08x", clks->descr, clks->addr, reg); + printf(", %6s", pll_name[clk_sel]); + if (reg & 0x200) + clk_khz = 38400; /* CLK38 is set */ + else if ((reg & 0x1f) == 0) + /* ARMCLKFIX_MGT is 0x120, e.g. div = 0 ! */ + clk_khz = 0; + else + clk_khz = pll_khz[clk_sel] / (reg & 0x1f); + printf(", %4d.%03d", clk_khz / 1000, clk_khz % 1000); + printf(", %s\n", (reg & 0x100) ? "ena" : "dis"); + clks++; + } + + return 0; +} + +U_BOOT_CMD( + clkinfo, 1, 1, do_clkinfo, + "print clock info", + "" +); + +/* + * do_clkmaja - change certain register to imitate Maja performance + */ +int do_clkmaja(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + uint32_t val; + struct clk_mgt_regs *regs = maja_clk_regs; + + while (regs->addr) { + val = readl(regs->addr); + printf("%s(%08x): %08x -> %08x\n", regs->descr, regs->addr, + val, regs->val); + writel(regs->val, regs->addr); + regs++; + } + + return 0; +} + +U_BOOT_CMD( + clkmaja, 1, 1, do_clkmaja, + "set some clocks maja alike", + "" +); + |