Driver for MSDC controller added to U-boot. Signed-off-by: Krzysztof Antonowicz <krzysztof.antonowicz@gmail.com>master
parent
a4361519f6
commit
6ef4ec129b
@ -0,0 +1,146 @@ |
||||
/*
|
||||
* (C) 2010 by Tieto <www.tieto.com> |
||||
* Krzysztof Antonowicz <krzysztof.antonowicz@tieto.com> |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* 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., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __MTK_GPIO_H_ |
||||
#define __MTK_GPIO_H_ |
||||
|
||||
/* GPIOs register definitions */ |
||||
#define MTK_GPIO_DIR1 (MTK_GPIO_BASE + 0x0000) |
||||
#define MTK_GPIO_DIR2 (MTK_GPIO_BASE + 0x0040) |
||||
#define MTK_GPIO_DIR3 (MTK_GPIO_BASE + 0x0080) |
||||
#define MTK_GPIO_DIR4 (MTK_GPIO_BASE + 0x00C0) |
||||
#define MTK_GPIO_DIR5 (MTK_GPIO_BASE + 0x0100) |
||||
|
||||
#define MTK_GPIO_PULLEN1 (MTK_GPIO_BASE + 0x0200) |
||||
#define MTK_GPIO_PULLEN2 (MTK_GPIO_BASE + 0x0240) |
||||
#define MTK_GPIO_PULLEN3 (MTK_GPIO_BASE + 0x0280) |
||||
#define MTK_GPIO_PULLEN4 (MTK_GPIO_BASE + 0x02C0) |
||||
#define MTK_GPIO_PULLEN5 (MTK_GPIO_BASE + 0x0300) |
||||
|
||||
#define MTK_GPIO_PULLSELL1 (MTK_GPIO_BASE + 0x0400) |
||||
#define MTK_GPIO_PULLSELL2 (MTK_GPIO_BASE + 0x0440) |
||||
#define MTK_GPIO_PULLSELL3 (MTK_GPIO_BASE + 0x0480) |
||||
#define MTK_GPIO_PULLSELL4 (MTK_GPIO_BASE + 0x04C0) |
||||
#define MTK_GPIO_PULLSELL5 (MTK_GPIO_BASE + 0x0500) |
||||
|
||||
#define MTK_GPIO_DINV1 (MTK_GPIO_BASE + 0x0600) |
||||
#define MTK_GPIO_DINV2 (MTK_GPIO_BASE + 0x0640) |
||||
#define MTK_GPIO_DINV3 (MTK_GPIO_BASE + 0x0680) |
||||
#define MTK_GPIO_DINV4 (MTK_GPIO_BASE + 0x06C0) |
||||
#define MTK_GPIO_DINV5 (MTK_GPIO_BASE + 0x0700) |
||||
|
||||
#define MTK_GPIO_DOUT1 (MTK_GPIO_BASE + 0x0800) |
||||
#define MTK_GPIO_DOUT2 (MTK_GPIO_BASE + 0x0840) |
||||
#define MTK_GPIO_DOUT3 (MTK_GPIO_BASE + 0x0880) |
||||
#define MTK_GPIO_DOUT4 (MTK_GPIO_BASE + 0x08C0) |
||||
#define MTK_GPIO_DOUT5 (MTK_GPIO_BASE + 0x0900) |
||||
|
||||
#define MTK_GPIO_DIN1 (MTK_GPIO_BASE + 0x0A00) |
||||
#define MTK_GPIO_DIN2 (MTK_GPIO_BASE + 0x0A40) |
||||
#define MTK_GPIO_DIN3 (MTK_GPIO_BASE + 0x0A80) |
||||
#define MTK_GPIO_DIN4 (MTK_GPIO_BASE + 0x0AC0) |
||||
#define MTK_GPIO_DIN5 (MTK_GPIO_BASE + 0x0B00) |
||||
|
||||
#define MTK_GPIO_MODE1 (MTK_GPIO_BASE + 0x1000) |
||||
#define MTK_GPIO_MODE2 (MTK_GPIO_BASE + 0x1100) |
||||
#define MTK_GPIO_MODE3 (MTK_GPIO_BASE + 0x1200) |
||||
#define MTK_GPIO_MODE4 (MTK_GPIO_BASE + 0x1300) |
||||
#define MTK_GPIO_MODE5 (MTK_GPIO_BASE + 0x1400) |
||||
#define MTK_GPIO_MODE6 (MTK_GPIO_BASE + 0x1500) |
||||
#define MTK_GPIO_MODE7 (MTK_GPIO_BASE + 0x1600) |
||||
#define MTK_GPIO_MODE8 (MTK_GPIO_BASE + 0x1700) |
||||
#define MTK_GPIO_MODE9 (MTK_GPIO_BASE + 0x1800) |
||||
#define MTK_GPIO_MODEA (MTK_GPIO_BASE + 0x1900) |
||||
|
||||
#define MTK_GPIO_CLK_OUT1 (MTK_GPIO_BASE + 0x3000) |
||||
#define MTK_GPIO_CLK_OUT2 (MTK_GPIO_BASE + 0x3100) |
||||
#define MTK_GPIO_CLK_OUT3 (MTK_GPIO_BASE + 0x3200) |
||||
#define MTK_GPIO_CLK_OUT4 (MTK_GPIO_BASE + 0x3300) |
||||
#define MTK_GPIO_CLK_OUT5 (MTK_GPIO_BASE + 0x3400) |
||||
#define MTK_GPIO_CLK_OUT6 (MTK_GPIO_BASE + 0x3500) |
||||
#define MTK_GPIO_CLK_OUT7 (MTK_GPIO_BASE + 0x3600) |
||||
#define MTK_GPIO_CLK_OUT8 (MTK_GPIO_BASE + 0x3700) |
||||
#define MTK_GPIO_CLK_OUT9 (MTK_GPIO_BASE + 0x3800) |
||||
#define MTK_GPIO_CLK_OUT10 (MTK_GPIO_BASE + 0x3900) |
||||
|
||||
/* MTK_GPIO_MODE_9 bit field definitions */ |
||||
#define MTK_GPIO_MODE9_GPIO64 0 |
||||
#define MTK_GPIO_MODE9_GPIO64_ALT1 1 |
||||
#define MTK_GPIO_MODE9_GPIO64_ALT2 2 |
||||
#define MTK_GPIO_MODE9_GPIO64_ALT3 3 |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO65 (0 << 2) |
||||
#define MTK_GPIO_MODE9_GPIO65_ALT1 (1 << 2) |
||||
#define MTK_GPIO_MODE9_GPIO65_ALT2 (2 << 2) |
||||
#define MTK_GPIO_MODE9_GPIO65_ALT3 (3 << 2) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO66 (0 << 4) |
||||
#define MTK_GPIO_MODE9_GPIO66_ALT1 (1 << 4) |
||||
#define MTK_GPIO_MODE9_GPIO66_ALT2 (2 << 4) |
||||
#define MTK_GPIO_MODE9_GPIO66_ALT3 (3 << 4) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO67 (0 << 6) |
||||
#define MTK_GPIO_MODE9_GPIO67_ALT1 (1 << 6) |
||||
#define MTK_GPIO_MODE9_GPIO67_ALT2 (2 << 6) |
||||
#define MTK_GPIO_MODE9_GPIO67_ALT3 (3 << 6) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO68 (0 << 8) |
||||
#define MTK_GPIO_MODE9_GPIO68_ALT1 (1 << 8) |
||||
#define MTK_GPIO_MODE9_GPIO68_ALT2 (2 << 8) |
||||
#define MTK_GPIO_MODE9_GPIO68_ALT3 (3 << 8) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO69 (0 << 10) |
||||
#define MTK_GPIO_MODE9_GPIO69_ALT1 (1 << 10) |
||||
#define MTK_GPIO_MODE9_GPIO69_ALT2 (2 << 10) |
||||
#define MTK_GPIO_MODE9_GPIO69_ALT3 (3 << 10) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO70 (0 << 12) |
||||
#define MTK_GPIO_MODE9_GPIO70_ALT1 (1 << 12) |
||||
#define MTK_GPIO_MODE9_GPIO70_ALT2 (2 << 12) |
||||
#define MTK_GPIO_MODE9_GPIO70_ALT3 (3 << 12) |
||||
|
||||
#define MTK_GPIO_MODE9_GPIO71 (0 << 14) |
||||
#define MTK_GPIO_MODE9_GPIO71_ALT1 (1 << 14) |
||||
#define MTK_GPIO_MODE9_GPIO71_ALT2 (2 << 14) |
||||
#define MTK_GPIO_MODE9_GPIO71_ALT3 (3 << 14) |
||||
|
||||
#define MTK_GPIO_MODEA_GPIO72 0 |
||||
#define MTK_GPIO_MODEA_GPIO72_ALT1 1 |
||||
#define MTK_GPIO_MODEA_GPIO72_ALT2 2 |
||||
#define MTK_GPIO_MODEA_GPIO72_ALT3 3 |
||||
|
||||
#define MTK_GPIO_MODEA_GPIO73 (0 << 2) |
||||
#define MTK_GPIO_MODEA_GPIO73_ALT1 (1 << 2) |
||||
#define MTK_GPIO_MODEA_GPIO73_ALT2 (2 << 2) |
||||
#define MTK_GPIO_MODEA_GPIO73_ALT3 (3 << 2) |
||||
|
||||
#define MTK_GPIO_MODEA_GPIO74 (0 << 4) |
||||
#define MTK_GPIO_MODEA_GPIO74_ALT1 (1 << 4) |
||||
#define MTK_GPIO_MODEA_GPIO74_ALT2 (2 << 4) |
||||
#define MTK_GPIO_MODEA_GPIO74_ALT3 (3 << 4) |
||||
|
||||
#define MTK_GPIO_MODEA_GPIO75 (0 << 6) |
||||
#define MTK_GPIO_MODEA_GPIO75_ALT1 (1 << 6) |
||||
#define MTK_GPIO_MODEA_GPIO75_ALT2 (2 << 6) |
||||
#define MTK_GPIO_MODEA_GPIO75_ALT3 (3 << 6) |
||||
|
||||
#endif |
@ -0,0 +1,28 @@ |
||||
/*
|
||||
* (C) 2010 by Tieto <www.tieto.com> |
||||
* Krzysztof Antonowicz <krzysztof.antonowicz@tieto.com> |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* 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., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __ASM_ARCH_MMC_H |
||||
#define __ASM_ARCH_MMC_H |
||||
|
||||
int mtk_mmc_init(void *regs); |
||||
|
||||
#endif /* __ASM_ARCH_MMC_H */ |
@ -0,0 +1,205 @@ |
||||
/*
|
||||
* (C) 2010 by Tieto <www.tieto.com> |
||||
* Krzysztof Antonowicz <krzysztof.antonowicz@tieto.com> |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* 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., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef MTK_MSDC_H |
||||
#define MTK_MSDC_H |
||||
|
||||
/*
|
||||
* Register definitions |
||||
*/ |
||||
|
||||
/* MS/SD Memory Card Controller Configuration Register */ |
||||
#define MTK_MSDC_CFG (MTK_MSDC_BASE + 0x0000) |
||||
|
||||
/* MS/SD Memory Card Controller Status Register MSDC_STA */ |
||||
#define MTK_MSDC_STA (MTK_MSDC_BASE + 0x0004) |
||||
|
||||
/* MS/SD Memory Card Controller Interrupt Register MSDC_INT */ |
||||
#define MTK_MSDC_INT (MTK_MSDC_BASE + 0x0008) |
||||
|
||||
/* MS/SD Memory Card Controller Data Register MSDC_DAT */ |
||||
#define MTK_MSDC_DAT (MTK_MSDC_BASE + 0x000C) |
||||
|
||||
/* MS/SD Memory Card Pin Status Register MSDC_PS */ |
||||
#define MTK_MSDC_PS (MTK_MSDC_BASE + 0x0010) |
||||
|
||||
/* MS/SD Memory Card Controller IO Control Register MSDC_IOCON */ |
||||
#define MTK_MSDC_IOCON (MTK_MSDC_BASE + 0x0014) |
||||
|
||||
/* SD Memory Card Controller Configuration Register SDC_CFG */ |
||||
#define MTK_MSDC_SDC_CFG (MTK_MSDC_BASE + 0x0020) |
||||
|
||||
/* SD Memory Card Controller Command Register SDC_CMD */ |
||||
#define MTK_MSDC_SDC_CMD (MTK_MSDC_BASE + 0x0024) |
||||
|
||||
/* SD Memory Card Controller Argument Register SDC_ARG */ |
||||
#define MTK_MSDC_SDC_ARG (MTK_MSDC_BASE + 0x0028) |
||||
|
||||
/* SD Memory Card Controller Status Register SDC_STA */ |
||||
#define MTK_MSDC_SDC_STA (MTK_MSDC_BASE + 0x002C) |
||||
|
||||
/* SD Memory Card Controller Response Register 0 SDC_RESP0 */ |
||||
#define MTK_MSDC_SDC_RESP0 (MTK_MSDC_BASE + 0x0030) |
||||
|
||||
/* SD Memory Card Controller Response Register 1 SDC_RESP1 */ |
||||
#define MTK_MSDC_SDC_RESP1 (MTK_MSDC_BASE + 0x0034) |
||||
|
||||
/* SD Memory Card Controller Response Register 2 SDC_RESP2 */ |
||||
#define MTK_MSDC_SDC_RESP2 (MTK_MSDC_BASE + 0x0038) |
||||
|
||||
/* SD Memory Card Controller Response Register 3 SDC_RESP3 */ |
||||
#define MTK_MSDC_SDC_RESP3 (MTK_MSDC_BASE + 0x003C) |
||||
|
||||
/* SD Memory Card Controller Command Status Register SDC_CMDSTA */ |
||||
#define MTK_MSDC_SDC_CMDSTA (MTK_MSDC_BASE + 0x0040) |
||||
|
||||
/* SD Memory Card Controller Data Status Register SDC_DATSTA */ |
||||
#define MTK_MSDC_SDC_DATSTA (MTK_MSDC_BASE + 0x0044) |
||||
|
||||
/* SD Memory Card Status Register SDC_CSTA */ |
||||
#define MTK_MSDC_SDC_CSTA (MTK_MSDC_BASE + 0x0048) |
||||
|
||||
/* SD Memory Card IRQ Mask Register 0 SDC_IRQMASK0 */ |
||||
#define MTK_MSDC_SDC_IRQMASK0 (MTK_MSDC_BASE + 0x004C) |
||||
|
||||
/* SD Memory Card IRQ Mask Register 1 SDC_IRQMASK1 */ |
||||
#define MTK_MSDC_SDC_IRQMASK1 (MTK_MSDC_BASE + 0x0050) |
||||
|
||||
/* SDIO Configuration Register SDIO_CFG */ |
||||
#define MTK_MSDC_SDIO_CFG (MTK_MSDC_BASE + 0x0054) |
||||
|
||||
/* SDIO Status Register SDIO_STA */ |
||||
#define MTK_MSDC_SDIO_STA (MTK_MSDC_BASE + 0x0058) |
||||
|
||||
/* Memory Stick Controller Configuration Register MSC_CFG */ |
||||
#define MTK_MSDC_MSC_CFG (MTK_MSDC_BASE + 0x0060) |
||||
|
||||
/* Memory Stick Controller Command Register MSC_CMD */ |
||||
#define MTK_MSDC_MSC_CMD (MTK_MSDC_BASE + 0x0064) |
||||
|
||||
/* Memory Stick Controller Auto Command Register MSC_ACMD */ |
||||
#define MTK_MSDC_MSC_ACMD (MTK_MSDC_BASE + 0x0068) |
||||
|
||||
/* Memory Stick Controller Status Register MSC_STA */ |
||||
#define MTK_MSDC_MSC_STA (MTK_MSDC_BASE + 0x006C) |
||||
|
||||
|
||||
/* MSDC_CFG bit field definitions */ |
||||
#define MTK_MSDC_CFG_MSDC (1 << 0) |
||||
#define MTK_MSDC_CFG_NOCRC (1 << 2) |
||||
#define MTK_MSDC_CFG_RST (1 << 3) |
||||
#define MTK_MSDC_CFG_CLKSRC (1 << 4) |
||||
#define MTK_MSDC_CFG_STDBY (1 << 5) |
||||
#define MTK_MSDC_CFG_RED (1 << 6) |
||||
#define MTK_MSDC_CFG_SCLKON (1 << 7) |
||||
#define MTK_MSDC_CFG_SCLKF 8 |
||||
#define MTK_MSDC_CFG_SCLKF_MASK (0xFF << MTK_MSDC_CFG_SCLKF) |
||||
#define MTK_MSDC_CFG_INTEN (1 << 16) |
||||
#define MTK_MSDC_CFG_DMAEN (1 << 17) |
||||
#define MTK_MSDC_CFG_PINEN (1 << 18) |
||||
#define MTK_MSDC_CFG_DIRQEN (1 << 19) |
||||
#define MTK_MSDC_CFG_RCDEN (1 << 20) |
||||
#define MTK_MSDC_CFG_VDDP (1 << 21) |
||||
|
||||
/* MSDC_SDC_CFG bit field definitions */ |
||||
#define MTK_MSDC_SDC_CFG_SIEN (1 << 16) |
||||
#define MTK_MSDC_SDC_CFG_MDLEN (1 << 17) |
||||
#define MTK_MSDC_SDC_CFG_MDLW8 (1 << 18) |
||||
#define MTK_MSDC_SDC_CFG_SDIO (1 << 19) |
||||
#define MTK_MSDC_SDC_CFG_BSYDLY 12 |
||||
|
||||
#define MTK_MSDC_SDC_CFG_BLKLEN_MASK 0x00000FFF |
||||
|
||||
/* MSDC_SDC_CMD bit field definitions */ |
||||
#define MTK_MSDC_SDC_CMD_BREAK (1 << 6) |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP 7 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_MASK (7 << MTK_MSDC_SDC_CMD_RSPTYP) |
||||
#define MTK_MSDC_SDC_CMD_IDRT (1 << 10) |
||||
|
||||
#define MTK_MSDC_SDC_CMD_DTYPE 11 |
||||
#define MTK_MSDC_SDC_CMD_DTYPE_MASK (3 << MTK_MSDC_SDC_CMD_DTYPE) |
||||
#define MTK_MSDC_SDC_CMD_RW (1 << 13) |
||||
#define MTK_MSDC_SDC_CMD_STOP (1 << 14) |
||||
#define MTK_MSDC_SDC_CMD_INTC (1 << 15) |
||||
#define MTK_MSDC_SDC_CMD_CMDFAIL (1 << 16) |
||||
|
||||
#define MTK_MSDC_SDC_CMD_CMD_MASK 0x0000003F |
||||
|
||||
#define MTK_MSDC_SDC_CMD_DTYPE_NO_DATA 0 |
||||
#define MTK_MSDC_SDC_CMD_DTYPE_SINGLE_BLOCK 1 |
||||
#define MTK_MSDC_SDC_CMD_DTYPE_MULTI_BLOCK 2 |
||||
#define MTK_MSDC_SDC_CMD_DTYPE_MULTI_STREAM 3 |
||||
|
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_NONE 0 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R1 1 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R2 2 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R3 3 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R4 4 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R5 5 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R6 6 |
||||
#define MTK_MSDC_SDC_CMD_RSPTYP_R1B 7 |
||||
|
||||
|
||||
/* Possible values of PRCFG0 field - MTK_MSDC_CFG register. */ |
||||
#define MTK_MSDC_CFG_PRCFG0_PU_DS_PD_DS (0 << 22) |
||||
#define MTK_MSDC_CFG_PRCFG0_PU_DS_PD_EN (1 << 22) |
||||
#define MTK_MSDC_CFG_PRCFG0_PU_EN_PD_DS (2 << 22) |
||||
#define MTK_MSDC_CFG_PRCFG0_KEEPER (3 << 22) |
||||
|
||||
/* MSDC_PS bit field definitions */ |
||||
#define MTK_MSDC_PS_CDEN (1 << 0) |
||||
#define MTK_MSDC_PS_PIEN0 (1 << 1) |
||||
#define MTK_MSDC_PS_POEN0 (1 << 2) |
||||
#define MTK_MSDC_PS_PIN0 (1 << 3) |
||||
#define MTK_MSDC_PS_PINCHG (1 << 4) |
||||
#define MTK_MSDC_PS_CMD (1 << 24) |
||||
|
||||
/* MSDC_STA bit field definitions */ |
||||
#define MTK_MSDC_STA_BF (1 << 0) |
||||
#define MTK_MSDC_STA_BE (1 << 1) |
||||
#define MTK_MSDC_STA_DRQ (1 << 2) |
||||
#define MTK_MSDC_STA_INT (1 << 3) |
||||
#define MTK_MSDC_STA_FIFOCLR (1 << 14) |
||||
#define MTK_MSDC_STA_BUSY (1 << 15) |
||||
#define MTK_MSDC_STA_FIFOCNT 4 |
||||
#define MTK_MSDC_STA_FIFOCNT_MASK 0x00F0 |
||||
|
||||
/* MSDC_SDC_CMDSTA bit field definitions */ |
||||
#define MTK_MSDC_SDC_CMDSTA_CMDRDY (1 << 0) |
||||
#define MTK_MSDC_SDC_CMDSTA_CMDTO (1 << 1) |
||||
#define MTK_MSDC_SDC_CMDSTA_RSPCRCERR (1 << 2) |
||||
#define MTK_MSDC_SDC_CMDSTA_MMCIRQ (1 << 3) |
||||
|
||||
/* MSDC_SDC_DATSTA bit field definitions */ |
||||
#define MTK_MSDC_SDC_DATSTA_BLKDONE (1 << 0) |
||||
#define MTK_MSDC_SDC_DATSTA_DATTO (1 << 1) |
||||
#define MTK_MSDC_SDC_DATSTA_DATCRCERR (1 << 2) |
||||
|
||||
/* MSDC_SDC_STA bit field definitions */ |
||||
#define MTK_MSDC_SDC_STA_SDCBUSY (1 << 0) |
||||
#define MTK_MSDC_SDC_STA_CMDBUSY (1 << 1) |
||||
#define MTK_MSDC_SDC_STA_DATBUSY (1 << 2) |
||||
#define MTK_MSDC_SDC_STA_RSV (1 << 3) |
||||
#define MTK_MSDC_SDC_STA_R1BS (1 << 4) |
||||
#define MTK_MSDC_SDC_STA_WP (1 << 15) |
||||
|
||||
#endif /* MTK_MSDC_H */ |
@ -0,0 +1,833 @@ |
||||
/*
|
||||
* (C) 2010 by Tieto <www.tieto.com> |
||||
* Krzysztof Antonowicz <krzysztof.antonowicz@tieto.com> |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* 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., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
* |
||||
*/ |
||||
#include <malloc.h> |
||||
#include <common.h> |
||||
#include <mmc.h> |
||||
#include <asm/io.h> |
||||
#include <asm/errno.h> |
||||
#include <asm/arch/mtk_msdc.h> |
||||
#include <asm/arch/system.h> |
||||
#include <asm/arch/gpio.h> |
||||
|
||||
#define MIN_SCLK_VALUE 0 |
||||
#define MAX_SCLK_VALUE 255 |
||||
/* According to documentation MCU is 104 MHz or 52 MHz. */ |
||||
#define MCU_CLK_FREQ_HZ 104000000 |
||||
#define MAX_SLAVE_FREQ_HZ 26000000 |
||||
#define MAX_BLOCK_SIZE 2048 |
||||
#define COMMAND_STATUS_READ_DELAY_US 10 |
||||
#define POLL_TRANSFER_COND_TIMEOUT_US 500 |
||||
#define POLL_CMD_STATUS_TIMEOUT_US 100 |
||||
#define DATA_READ_TIMEOUT_US 500 |
||||
|
||||
#define DEBUG_LINE() do { \ |
||||
debug("mtk_msdc_mmc[%s]: called.\n", __func__); \
|
||||
} while (0) |
||||
|
||||
#define DEBUG_MSG(fmt, arg...) do { \ |
||||
debug("mtk_msdc_mmc[%s]: " fmt "\n", __func__, ##arg); \
|
||||
} while (0) |
||||
|
||||
#define ERROR(fmt, arg...) do { \ |
||||
printf("mtk_msdc_mmc[%s] ERROR: " fmt "\n", __func__, ##arg); \
|
||||
} while (0) |
||||
|
||||
struct mmc_host { |
||||
struct mmc *mmc; |
||||
u32 clock; |
||||
u32 msdc_sdc_cmd; |
||||
struct mmc_cmd *cmd; |
||||
struct mmc_data *data; |
||||
}; |
||||
|
||||
static struct mmc_host mmc_host; |
||||
|
||||
#ifdef MTK_MMC_CARD_DETECTION_SUPPORTED |
||||
|
||||
/* Card detection mechanism is not supported by Sci-phone G2 hardware:
|
||||
* 1. missing RCDEN resistor on PCB, |
||||
* 2. grounded MCINS(GPIO75) pin. |
||||
* |
||||
* Checks if memory card is present according to the algorithm: |
||||
* 1. Pull up CD/DAT3 (INS) pin. |
||||
* 2. Enable card detection and input pin at the same time. |
||||
* 3. Turn on power for memory card. |
||||
* 4. Detect insertion of memory card. |
||||
*/ |
||||
static int check_card_presence(struct mmc_host *mmc_host) |
||||
{ |
||||
int retval = -ENODEV; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
writel(readl(MTK_MSDC_CFG) | MTK_MSDC_CFG_PRCFG0_PU_EN_PD_DS, |
||||
MTK_MSDC_CFG); |
||||
|
||||
writel(readl(MTK_MSDC_PS) | MTK_MSDC_PS_CDEN | MTK_MSDC_PS_PIEN0, |
||||
MTK_MSDC_PS); |
||||
|
||||
/* Turn on the power for memory card. */ |
||||
writel(readl(MTK_MSDC_CFG) | MTK_MSDC_CFG_VDDP, MTK_MSDC_CFG); |
||||
|
||||
/* Check if a card is inserted. */ |
||||
|
||||
if (readl(MTK_MSDC_PS) & MTK_MSDC_PS_PINCHG) |
||||
retval = 0; |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
#endif /* MTK_MMC_CARD_DETECTION_SUPPORTED */ |
||||
|
||||
/*
|
||||
* Power up MSDC controller. |
||||
*/ |
||||
static void mtk_power_up(void) |
||||
{ |
||||
DEBUG_LINE(); |
||||
/* Disable power down control for MSDC module. */ |
||||
writew(PDN_CON1_MSDC, MTK_CONFG_PDN_CLR1); |
||||
} |
||||
|
||||
/*
|
||||
* Performs software and synchronous reset of MSDC controller. |
||||
*/ |
||||
static void mtk_software_reset(void) |
||||
{ |
||||
DEBUG_LINE(); |
||||
|
||||
writel(MTK_MSDC_CFG_RST, MTK_MSDC_CFG); |
||||
} |
||||
|
||||
/*
|
||||
* Configures GPIOs for MSDC controller. |
||||
*/ |
||||
static void mtk_configure_gpios(void) |
||||
{ |
||||
DEBUG_LINE(); |
||||
|
||||
u16 mode_9_clear_mask = |
||||
MTK_GPIO_MODE9_GPIO67_ALT3 | |
||||
MTK_GPIO_MODE9_GPIO68_ALT3 | |
||||
MTK_GPIO_MODE9_GPIO69_ALT3 | |
||||
MTK_GPIO_MODE9_GPIO70_ALT3 | |
||||
MTK_GPIO_MODE9_GPIO71_ALT3; |
||||
|
||||
u16 mode_9_set_mask = |
||||
MTK_GPIO_MODE9_GPIO67_ALT1 | |
||||
MTK_GPIO_MODE9_GPIO68_ALT1 | |
||||
MTK_GPIO_MODE9_GPIO69_ALT1 | |
||||
MTK_GPIO_MODE9_GPIO70_ALT1 | |
||||
MTK_GPIO_MODE9_GPIO71_ALT1; |
||||
|
||||
u16 mode_a_clear_mask = |
||||
MTK_GPIO_MODEA_GPIO72_ALT3 | |
||||
/* GPIO73 skipped (used by USB as regular GPIO) */ |
||||
MTK_GPIO_MODEA_GPIO74_ALT3 | |
||||
MTK_GPIO_MODEA_GPIO75_ALT3; |
||||
|
||||
u16 mode_a_set_mask = |
||||
MTK_GPIO_MODEA_GPIO72_ALT1 | |
||||
/* GPIO73 skipped (used by USB as regular GPIO) */ |
||||
MTK_GPIO_MODEA_GPIO74_ALT1 | |
||||
MTK_GPIO_MODEA_GPIO75_ALT1; |
||||
|
||||
writew((readw(MTK_GPIO_MODE9) & (~mode_9_clear_mask)) | |
||||
mode_9_set_mask, MTK_GPIO_MODE9); |
||||
|
||||
writew((readw(MTK_GPIO_MODEA) & (~mode_a_clear_mask)) | |
||||
mode_a_set_mask, MTK_GPIO_MODEA); |
||||
} |
||||
|
||||
/*
|
||||
* Initialization of MMC/SD controller. |
||||
*/ |
||||
static int mtk_init(struct mmc *mmc) |
||||
{ |
||||
DEBUG_LINE(); |
||||
|
||||
(void)mmc; |
||||
|
||||
mtk_configure_gpios(); |
||||
mtk_power_up(); |
||||
mtk_software_reset(); |
||||
|
||||
/* Configure the controller as the host of SD/MMC cards. */ |
||||
writel(readl(MTK_MSDC_CFG) | MTK_MSDC_CFG_MSDC, MTK_MSDC_CFG); |
||||
|
||||
/* Use MCU clock as source clock of memory card. */ |
||||
writel(readl(MTK_MSDC_CFG) & (~MTK_MSDC_CFG_CLKSRC), MTK_MSDC_CFG); |
||||
|
||||
/* Clear FIFO. */ |
||||
writew(readl(MTK_MSDC_STA) | MTK_MSDC_STA_FIFOCLR, MTK_MSDC_STA); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Calculates slave frequency for the given sclk value. |
||||
*/ |
||||
static u32 mtk_calculate_f_slave(const u8 sclk) |
||||
{ |
||||
u32 f_slave = 0; |
||||
|
||||
if (!sclk) |
||||
f_slave = MCU_CLK_FREQ_HZ / 2; |
||||
else |
||||
f_slave = MCU_CLK_FREQ_HZ / (4 * sclk); |
||||
|
||||
return f_slave; |
||||
} |
||||
|
||||
/*
|
||||
* Calculates max. slave frequency. |
||||
*/ |
||||
static u32 mtk_calculate_f_slave_max(void) |
||||
{ |
||||
u32 f_slave_max = 0; |
||||
|
||||
f_slave_max = mtk_calculate_f_slave(MIN_SCLK_VALUE); |
||||
|
||||
return f_slave_max; |
||||
} |
||||
|
||||
/*
|
||||
* Calculates min. slave frequency. |
||||
*/ |
||||
static u32 mtk_calculate_f_slave_min(void) |
||||
{ |
||||
u32 f_slave_min = 0; |
||||
|
||||
f_slave_min = mtk_calculate_f_slave(MAX_SCLK_VALUE); |
||||
|
||||
return f_slave_min; |
||||
} |
||||
|
||||
/*
|
||||
* Configures clock for MSDC. |
||||
*/ |
||||
static void mtk_set_clk_rate(struct mmc_host *mmc_host, const u32 f_slave) |
||||
{ |
||||
u32 f_host; |
||||
u8 sclk; |
||||
u32 calc_f_slave; |
||||
u32 min_f_slave; |
||||
u32 max_f_slave; |
||||
|
||||
DEBUG_LINE(); |
||||
DEBUG_MSG("Requested new slave frequency: %dHz.", f_slave); |
||||
|
||||
f_host = MCU_CLK_FREQ_HZ; |
||||
|
||||
max_f_slave = mtk_calculate_f_slave_max(); |
||||
min_f_slave = mtk_calculate_f_slave_min(); |
||||
|
||||
if (max_f_slave < f_slave) { |
||||
|
||||
DEBUG_MSG("Requested slave frequency is too high: %dHz! " |
||||
"The max. available is: %dHz", f_slave, max_f_slave); |
||||
|
||||
sclk = MIN_SCLK_VALUE; |
||||
|
||||
} else if (min_f_slave > f_slave) { |
||||
|
||||
DEBUG_MSG("Requested slave frequency is too low: %dHz! " |
||||
"The min. available is: %dHz", f_slave, min_f_slave); |
||||
|
||||
sclk = MAX_SCLK_VALUE; |
||||
|
||||
} else if (((f_host / 2) == f_slave) || (f_host < (f_slave * 4))) { |
||||
|
||||
sclk = MIN_SCLK_VALUE; |
||||
} else |
||||
sclk = f_host / (4 * f_slave); |
||||
|
||||
calc_f_slave = mtk_calculate_f_slave(sclk); |
||||
|
||||
/* If the calculated frequency is still too high,
|
||||
it should be decreased. */ |
||||
while (calc_f_slave > f_slave) { |
||||
|
||||
sclk++; |
||||
DEBUG_MSG("Requested frequency out of range, it will " |
||||
"be decreased!"); |
||||
calc_f_slave = mtk_calculate_f_slave(sclk); |
||||
} |
||||
|
||||
DEBUG_MSG("f_host: %dHz, calc_f_slave: %dHz(f_slave: %dHz), " |
||||
"SCLK: %d.", f_host, calc_f_slave, f_slave, sclk); |
||||
|
||||
writel((readl(MTK_MSDC_CFG) & (~MTK_MSDC_CFG_SCLKF_MASK)) | sclk << 8, |
||||
MTK_MSDC_CFG); |
||||
} |
||||
|
||||
/*
|
||||
* Perform configuration related settings for MMC host. |
||||
*/ |
||||
static void mtk_set_ios(struct mmc *mmc) |
||||
{ |
||||
struct mmc_host *mmc_host = mmc->priv; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
/* 4 -bit data line enable/disable. */ |
||||
if (4 == mmc->bus_width) |
||||
writel(readl(MTK_MSDC_SDC_CFG) | MTK_MSDC_SDC_CFG_MDLEN, |
||||
MTK_MSDC_SDC_CFG); |
||||
else |
||||
writel(readl(MTK_MSDC_SDC_CFG) & (~MTK_MSDC_SDC_CFG_MDLEN), |
||||
MTK_MSDC_SDC_CFG); |
||||
|
||||
if (mmc->clock && (mmc_host->clock != mmc->clock)) { |
||||
|
||||
/* Before changing the frequency of serial clock on the bus,
|
||||
it is necessary to disable serial interface |
||||
of the controller. */ |
||||
writel(readl(MTK_MSDC_SDC_CFG) & (~MTK_MSDC_SDC_CFG_SIEN), |
||||
MTK_MSDC_SDC_CFG); |
||||
|
||||
mtk_set_clk_rate(mmc_host, mmc->clock); |
||||
|
||||
writel(readl(MTK_MSDC_SDC_CFG) | MTK_MSDC_SDC_CFG_SIEN, |
||||
MTK_MSDC_SDC_CFG); |
||||
|
||||
DEBUG_MSG("Serial clock rate changed. The clock is enabled."); |
||||
|
||||
mmc_host->clock = mmc->clock; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Configures controller for the given data type. |
||||
*/ |
||||
static int mtk_setup_data(struct mmc_host *mmc_host, u32 *msdc_sdc_cmd) |
||||
{ |
||||
u32 no_of_blocks = mmc_host->data->blocks; |
||||
u32 block_size = mmc_host->data->blocksize; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
/* Read/write command selection. */ |
||||
if (mmc_host->data->flags & MMC_DATA_WRITE) |
||||
*msdc_sdc_cmd |= MTK_MSDC_SDC_CMD_RW; |
||||
else |
||||
*msdc_sdc_cmd &= ~MTK_MSDC_SDC_CMD_RW; |
||||
|
||||
if (MAX_BLOCK_SIZE < block_size) |
||||
DEBUG_MSG("Block size excceeds max. block length!"); |
||||
else { |
||||
/* Write length of block. */ |
||||
writel((readl(MTK_MSDC_SDC_CFG) & |
||||
(~MTK_MSDC_SDC_CFG_BLKLEN_MASK)) | block_size, |
||||
MTK_MSDC_SDC_CFG); |
||||
|
||||
DEBUG_MSG("Block size is: %d.", block_size); |
||||
} |
||||
|
||||
DEBUG_MSG("Number of blocks: %d", no_of_blocks); |
||||
|
||||
if (1 == no_of_blocks) { |
||||
*msdc_sdc_cmd |= (MTK_MSDC_SDC_CMD_DTYPE_SINGLE_BLOCK << |
||||
MTK_MSDC_SDC_CMD_DTYPE); |
||||
} else if (1 < no_of_blocks) { |
||||
*msdc_sdc_cmd |= (MTK_MSDC_SDC_CMD_DTYPE_MULTI_BLOCK << |
||||
MTK_MSDC_SDC_CMD_DTYPE); |
||||
} else { |
||||
DEBUG_MSG("Data supplied but block count is 0!"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
/* Clear FIFO. */ |
||||
writew(readl(MTK_MSDC_STA) | MTK_MSDC_STA_FIFOCLR, MTK_MSDC_STA); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Configures controller for the given command type. |
||||
*/ |
||||
static int mtk_setup_cmd(struct mmc_host *mmc_host, |
||||
struct mmc_cmd *cmd, u32 *msdc_sdc_cmd) |
||||
{ |
||||
u32 response_type; |
||||
|
||||
DEBUG_LINE(); |
||||
DEBUG_MSG("CMD ID: %d, CMD ARG: 0x%.8x, CMD RESP TYPE: %d", |
||||
cmd->cmdidx, cmd->cmdarg, cmd->resp_type); |
||||
|
||||
/* Choose response type. */ |
||||
switch (cmd->resp_type) { |
||||
|
||||
case MMC_RSP_R1: |
||||
/* R1 response token is 48-bit. */ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R1; |
||||
break; |
||||
case MMC_RSP_R1b: |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R1B; |
||||
break; |
||||
case MMC_RSP_R2: |
||||
/* R2 response token is 136-bit. */ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R2; |
||||
break; |
||||
case MMC_RSP_R3: |
||||
/* R3 response token is 48-bit, no CRC */ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R3; |
||||
break; |
||||
#if 0 |
||||
case MMC_RSP_R4: |
||||
/* R4 response token is 48-bit. (Only for MMC) */ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R4; |
||||
break; |
||||
case MMC_RSP_R5: |
||||
/* R5 response token is 48-bit. (Only for MMC) */ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R5; |
||||
break; |
||||
case MMC_RSP_R6: |
||||
/* R6 response token is 48-bit.*/ |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_R6; |
||||
break; |
||||
#endif |
||||
case MMC_RSP_NONE: |
||||
response_type = MTK_MSDC_SDC_CMD_RSPTYP_NONE; |
||||
break; |
||||
default: |
||||
ERROR("Unexpected response type!"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
*msdc_sdc_cmd |= response_type << MTK_MSDC_SDC_CMD_RSPTYP; |
||||
|
||||
/* Store the command argument first! */ |
||||
writel(cmd->cmdarg, MTK_MSDC_SDC_ARG); |
||||
/* ..then the command id. */ |
||||
*msdc_sdc_cmd |= cmd->cmdidx; |
||||
|
||||
if (MMC_CMD_STOP_TRANSMISSION == cmd->cmdidx) { |
||||
*msdc_sdc_cmd |= MTK_MSDC_SDC_CMD_STOP; |
||||
writel(readl(MTK_MSDC_SDC_CFG) | 16 << MTK_MSDC_SDC_CFG_BSYDLY, |
||||
MTK_MSDC_SDC_CFG); |
||||
} else |
||||
*msdc_sdc_cmd &= ~MTK_MSDC_SDC_CMD_STOP; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Read SD/MMC Memory Card bus response. |
||||
*/ |
||||
static void mtk_read_response(struct mmc_host *mmc_host) |
||||
{ |
||||
u32 resp0; |
||||
u32 resp1; |
||||
u32 resp2; |
||||
u32 resp3; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
if (!mmc_host->cmd) |
||||
return; |
||||
|
||||
/* Check if a response is expected and read it.
|
||||
For response of type R2 only bit 127 to 0 of response token is stored |
||||
in the register field SDC_RESP0, SDC_RESP1, SDC_RESP2 and SDC_RESP3. |
||||
For response of other types, only bit 39 to 8 of response token |
||||
is stored in the register field SDC_RESP0. */ |
||||
|
||||
if (mmc_host->cmd->resp_type & MMC_RSP_PRESENT) { |
||||
|
||||
resp0 = readl(MTK_MSDC_SDC_RESP0); |
||||
|
||||
if (mmc_host->cmd->resp_type & MMC_RSP_136) { |
||||
|
||||
resp1 = readl(MTK_MSDC_SDC_RESP1); |
||||
resp2 = readl(MTK_MSDC_SDC_RESP2); |
||||
resp3 = readl(MTK_MSDC_SDC_RESP3); |
||||
|
||||
mmc_host->cmd->response[0] = resp3; |
||||
mmc_host->cmd->response[1] = resp2; |
||||
mmc_host->cmd->response[2] = resp1; |
||||
mmc_host->cmd->response[3] = resp0; |
||||
|
||||
DEBUG_MSG("Response[0]: 0x%.8x", |
||||
mmc_host->cmd->response[0]); |
||||
DEBUG_MSG("Response[1]: 0x%.8x", |
||||
mmc_host->cmd->response[1]); |
||||
DEBUG_MSG("Response[2]: 0x%.8x", |
||||
mmc_host->cmd->response[2]); |
||||
DEBUG_MSG("Response[3]: 0x%.8x", |
||||
mmc_host->cmd->response[3]); |
||||
} else { |
||||
mmc_host->cmd->response[0] = resp0; |
||||
|
||||
DEBUG_MSG("Response[0]: 0x%.8x", |
||||
mmc_host->cmd->response[0]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Checks if reading FIFO is possible. |
||||
*/ |
||||
static int mtk_poll_data_transfer_conditions(const u16 transfer_condition) |
||||
{ |
||||
int retval = 0; |
||||
u16 msdc_sdc_datsta; |
||||
u32 timeout_counter = 0; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
do { |
||||
/* First of all check data status. */ |
||||
msdc_sdc_datsta = readw(MTK_MSDC_SDC_DATSTA); |
||||
|
||||
if (msdc_sdc_datsta & MTK_MSDC_SDC_DATSTA_BLKDONE) |
||||
DEBUG_MSG("A data block was successfully transferred."); |
||||
|
||||
if (msdc_sdc_datsta & MTK_MSDC_SDC_DATSTA_DATTO) { |
||||
ERROR("MS/SD controller detected a timeout " |
||||
"condition while waiting for data token on " |
||||
"the DAT line."); |
||||
|
||||
retval = -1; |
||||
} |
||||
|
||||
if (msdc_sdc_datsta & MTK_MSDC_SDC_DATSTA_DATCRCERR) { |
||||
ERROR("MS/SD controller detected a CRC error!"); |
||||
|
||||
retval = -1; |
||||
} |
||||
|
||||
/* Check FIFO. */ |
||||
if ((!(readw(MTK_MSDC_STA) & transfer_condition)) || retval) |
||||
break; |
||||
else |
||||
DEBUG_MSG("FIFO is empty!"); |
||||
|
||||
udelay(1); |
||||
|
||||
} while (++timeout_counter != POLL_TRANSFER_COND_TIMEOUT_US); |
||||
|
||||
if (timeout_counter == POLL_TRANSFER_COND_TIMEOUT_US) { |
||||
ERROR("Timeout occurred during polling " |
||||
"data transfer conditions."); |
||||
retval = TIMEOUT; |
||||
} |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Reads data received from memory card. |
||||
*/ |
||||
static int mtk_read_data(void *dest, u32 length) |
||||
{ |
||||
int retval = 0; |
||||
u32 *destl = dest; |
||||
u32 timeout_counter = 0; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
/* Wait for data transfer request. */ |
||||
while (!(readw(MTK_MSDC_STA) & MTK_MSDC_STA_DRQ)) { |
||||
|
||||
udelay(1); |
||||
|
||||
if (++timeout_counter == DATA_READ_TIMEOUT_US) { |
||||
ERROR("Data read timeout occured!"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
DEBUG_MSG("Block size is: %d", readl(MTK_MSDC_SDC_CFG) & |
||||
MTK_MSDC_SDC_CFG_BLKLEN_MASK); |
||||
|
||||
while (length) { |
||||
|
||||
DEBUG_MSG("Bytes left to read: %d.", length); |
||||
|
||||
/* Read data if there is any in the FIFO. */ |
||||
retval = mtk_poll_data_transfer_conditions(MTK_MSDC_STA_BE); |
||||
|
||||
if (retval) |
||||
goto finish_read; |
||||
|
||||
if (3 < length) { |
||||
|
||||
*destl++ = readl(MTK_MSDC_DAT); |
||||
length -= 4; |
||||
|
||||
DEBUG_MSG("DATA[R]: 0x%.8x", *(destl - 1)); |
||||
|
||||
} else { |
||||
u8 *dest8 = (u8 *)destl; |
||||
u32 msdc_dat = readl(MTK_MSDC_DAT); |
||||
memcpy(dest8, &msdc_dat, length); |
||||
|
||||
length = 0; |
||||
|
||||
DEBUG_MSG("DATA[R]: 0x%.8x", msdc_dat); |
||||
} |
||||
} |
||||
|
||||
if (!readw(MTK_MSDC_STA) & MTK_MSDC_STA_BE) |
||||
ERROR("There is still some data left in FIFO!"); |
||||
|
||||
finish_read: |
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Writes data to be sent to memory card. |
||||
*/ |
||||
static int mtk_write_data(const void *src, int length) |
||||
{ |
||||
int retval = 0; |
||||
const u32 *srcl = src; |
||||
u32 timeout_counter = 0; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
/* Wait for data transfer request. */ |
||||
while (!(readw(MTK_MSDC_STA) & MTK_MSDC_STA_DRQ)) { |
||||
|
||||
udelay(1); |
||||
|
||||
if (++timeout_counter == DATA_READ_TIMEOUT_US) { |
||||
ERROR("Data write timeout occured!"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
while (length) { |
||||
|
||||
DEBUG_MSG("Length of the data to write: %d.", length); |
||||
|
||||
/* Write data if there is enough space in the FIFO. */ |
||||
retval = mtk_poll_data_transfer_conditions(MTK_MSDC_STA_BF); |
||||
|
||||
if (retval) |
||||
goto finish_write; |
||||
|
||||
if (3 < length) { |
||||
writel(*srcl++, MTK_MSDC_DAT); |
||||
length -= 4; |
||||
|
||||
DEBUG_MSG("DATA[W]: 0x%.8x", *(srcl - 1)); |
||||
} else { |
||||
|
||||
u8 *src8 = (u8 *)srcl; |
||||
u32 temp_val; |
||||
|
||||
memcpy(&temp_val, src8, length); |
||||
writel(temp_val, MTK_MSDC_DAT); |
||||
|
||||
length = 0; |
||||
|
||||
DEBUG_MSG("DATA[W]: 0x%.8x", temp_val); |
||||
} |
||||
} |
||||
|
||||
finish_write: |
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Performs data transfer between host and memory card. |
||||
*/ |
||||
static int mtk_transfer_data(struct mmc_host *mmc_host) |
||||
{ |
||||
int retval = 0; |
||||
struct mmc_data *data = mmc_host->data; |
||||
u32 length = data->blocks * data->blocksize; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
if (data->flags & MMC_DATA_READ) { |
||||
DEBUG_MSG("Reading data..."); |
||||
retval = mtk_read_data(data->dest, length); |
||||
} else { |
||||
DEBUG_MSG("Writing data..."); |
||||
retval = mtk_write_data(data->src, length); |
||||
} |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Sends a command out on the MMC/SD bus. |
||||
*/ |
||||
static int mtk_send_cmd(struct mmc *mmc, |
||||
struct mmc_cmd *cmd, struct mmc_data *data) |
||||
{ |
||||
int retval; |
||||
u16 cmd_status; |
||||
u16 controller_status; |
||||
struct mmc_host *mmc_host = mmc->priv; |
||||
u32 msdc_sdc_cmd = mmc_host->msdc_sdc_cmd; |
||||
u32 timeout_counter; |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
mmc_host->cmd = cmd; |
||||
mmc_host->data = data; |
||||
|
||||
#ifdef MTK_MMC_CARD_DETECTION_SUPPORTED |
||||
|
||||
if (!check_card_presence(mmc_host)) { |
||||
DEBUG_MSG("Memory card inserted!"); |
||||
} else { |
||||
DEBUG_MSG("Memory card not inserted"); |
||||
retval = -1; |
||||
goto finish; |
||||
} |
||||
|
||||
#endif /* MTK_MMC_CARD_DETECTION_SUPPORTED */ |
||||
|
||||
/* Check data supplied. */ |
||||
if (mmc_host->data) { |
||||
retval = mtk_setup_data(mmc_host, &msdc_sdc_cmd); |
||||
|
||||
if (retval) |
||||
goto finish; |
||||
} else |
||||
msdc_sdc_cmd |= (MTK_MSDC_SDC_CMD_DTYPE_NO_DATA << |
||||
MTK_MSDC_SDC_CMD_DTYPE); |
||||
|
||||
/* Prepared command to send. */ |
||||
retval = mtk_setup_cmd(mmc_host, cmd, &msdc_sdc_cmd); |
||||
|
||||
if (retval) |
||||
goto finish; |
||||
|
||||
/* Clear command status register. */ |
||||
(void)readl(MTK_MSDC_SDC_CMDSTA); |
||||
|
||||
/* Send the command... */ |
||||
writel(msdc_sdc_cmd, MTK_MSDC_SDC_CMD); |
||||
|
||||
timeout_counter = 0; |
||||
|
||||
/* Wait until the command is sent. */ |
||||
do { |
||||
controller_status = readl(MTK_MSDC_SDC_STA); |
||||
DEBUG_MSG("Controller status: 0x%.4x", controller_status); |
||||
udelay(1); |
||||
} while ((controller_status & MTK_MSDC_SDC_STA_CMDBUSY) && |
||||
(++timeout_counter != POLL_CMD_STATUS_TIMEOUT_US)); |
||||
|
||||
if (POLL_CMD_STATUS_TIMEOUT_US == timeout_counter) { |
||||
ERROR("Waiting for controller status timeout occured " |
||||
"(controller status: %d)!", controller_status); |
||||
retval = TIMEOUT; |
||||
goto finish; |
||||
} |
||||
|
||||
/* Wait for command status. */ |
||||
do { |
||||
cmd_status = readl(MTK_MSDC_SDC_CMDSTA); |
||||
|
||||
DEBUG_MSG("Command status: 0x%.4x", cmd_status); |
||||
|
||||
if (cmd_status & MTK_MSDC_SDC_CMDSTA_CMDRDY) |
||||
DEBUG_MSG("Command ready!"); |
||||
|
||||
if (cmd_status & MTK_MSDC_SDC_CMDSTA_CMDTO) { |
||||
ERROR("MS/SD controller detected a timeout " |
||||
"condition while waiting for a response on the " |
||||
"CMD line."); |
||||
retval = TIMEOUT; |
||||
goto finish; |
||||
} |
||||
|
||||
if (cmd_status & MTK_MSDC_SDC_CMDSTA_RSPCRCERR) { |
||||
ERROR("MS/SD controller detected a CRC error after " |
||||
"reading a response from the CMD line."); |
||||
retval = -1; |
||||
goto finish; |
||||
} |
||||
|
||||
if (cmd_status & MTK_MSDC_SDC_CMDSTA_MMCIRQ) { |
||||
ERROR("MMC supporting command class 9 issued an " |
||||
"interrupt request."); |
||||
retval = -1; |
||||
goto finish; |
||||
} |
||||
|
||||
udelay(COMMAND_STATUS_READ_DELAY_US); |
||||
|
||||
} while (!cmd_status); |
||||
|
||||
/* Read command response. */ |
||||
mtk_read_response(mmc_host); |
||||
|
||||
/* Read/write data if supplied. */ |
||||
if (mmc_host->data) { |
||||
|
||||
retval = mtk_transfer_data(mmc_host); |
||||
|
||||
if (retval) |
||||
goto finish; |
||||
} |
||||
|
||||
/* Read memory card status register. */ |
||||
DEBUG_MSG("=> Memory card status register: 0x%.8x.<=", |
||||
readl(MTK_MSDC_SDC_CSTA)); |
||||
finish: |
||||
mmc_host->cmd = NULL; |
||||
mmc_host->data = NULL; |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
/*
|
||||
* Initialization of mmc. |
||||
*/ |
||||
int mtk_mmc_init(bd_t *bis) |
||||
{ |
||||
struct mmc *mmc = malloc(sizeof(struct mmc)); |
||||
|
||||
DEBUG_LINE(); |
||||
|
||||
if (!mmc) |
||||
return -1; |
||||
|
||||
strcpy(mmc->name, "msdc_mmc"); |
||||
|
||||
mmc->send_cmd = mtk_send_cmd; |
||||
mmc->set_ios = mtk_set_ios; |
||||
mmc->init = mtk_init; |
||||
|
||||
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; |
||||
mmc->host_caps = MMC_MODE_4BIT; |
||||
|
||||
mmc->priv = &mmc_host; |
||||
mmc_host.mmc = mmc; |
||||
|
||||
/* Min and max frequencies are determined by
|
||||
max and min values of clock divider (SCLKF in MSDC_CFG). */ |
||||
mmc->f_min = mtk_calculate_f_slave_min(); |
||||
mmc->f_max = MAX_SLAVE_FREQ_HZ; |
||||
|
||||
mmc_register(mmc); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue