2533 lines
83 KiB
C
2533 lines
83 KiB
C
|
/**
|
|||
|
* @file hal_sdhost.c
|
|||
|
* @author ALLWINNERTECH IOT WLAN Team
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved.
|
|||
|
*
|
|||
|
* Redistribution and use in source and binary forms, with or without
|
|||
|
* modification, are permitted provided that the following conditions
|
|||
|
* are met:
|
|||
|
* 1. Redistributions of source code must retain the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer.
|
|||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|||
|
* notice, this list of conditions and the following disclaimer in the
|
|||
|
* documentation and/or other materials provided with the
|
|||
|
* distribution.
|
|||
|
* 3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of
|
|||
|
* its contributors may be used to endorse or promote products derived
|
|||
|
* from this software without specific prior written permission.
|
|||
|
*
|
|||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
|
* LIMITED TO, )|hhst->sdio_irq_maskPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
*/
|
|||
|
#include "_sdhost.h"
|
|||
|
#include "sunxi_hal_common.h"
|
|||
|
#include "stdint.h"
|
|||
|
//#include "io.h"
|
|||
|
//#include "hal_prcm.h"
|
|||
|
#include "hal_ccm.h"
|
|||
|
#include "hal_gpio.h"
|
|||
|
#include "hal_board.h"
|
|||
|
|
|||
|
#include "hal_dev.h"
|
|||
|
#include "hal_clock.h"
|
|||
|
#include "sdmmc/sys/param.h"
|
|||
|
|
|||
|
#include "hal_sdhost.h"
|
|||
|
#ifdef CONFIG_USE_SDIO
|
|||
|
#include "sdio.h"
|
|||
|
#endif
|
|||
|
#include "sdmmc.h"
|
|||
|
|
|||
|
#include "_sd_define.h"
|
|||
|
#include "_core.h"
|
|||
|
#ifndef CONFIG_KERNEL_FREERTOS
|
|||
|
#include "osal/os/RT-Thread/os_util.h"
|
|||
|
#else
|
|||
|
#include "osal/os/FreeRTOS/os_util.h"
|
|||
|
#endif
|
|||
|
#include "interrupt.h"
|
|||
|
|
|||
|
//#include "k_arch.h"
|
|||
|
extern uint32_t sdmmc_pinctrl_init(struct mmc_host *host);
|
|||
|
extern int mmc_gpiod_request_cd_irq(struct mmc_host* host);
|
|||
|
//#define __dsb__() dsb(0xf)
|
|||
|
|
|||
|
#ifndef UINT_MAX
|
|||
|
#define UINT_MAX (~0U)
|
|||
|
#endif
|
|||
|
|
|||
|
/*
|
|||
|
#define SDC_REQUEST_IRQ(n, hdl) HAL_NVIC_SetIRQHandler(n, hdl)
|
|||
|
#define SDC_SetPriority(n, l) HAL_NVIC_SetPriority(n, l)
|
|||
|
#define SDC_ENABLE_IRQ(n) HAL_NVIC_EnableIRQ(n)
|
|||
|
#define SDC_CONFIG_IRQ(n, hdl, l) HAL_NVIC_ConfigExtIRQ(n, hdl, l)
|
|||
|
#define SDC_DISABLE_IRQ(n) HAL_NVIC_DisableIRQ(n)
|
|||
|
#define SDC_CLEAR_IRQPINGD(n) HAL_NVIC_ClearPendingIRQ(n)
|
|||
|
#define SDC_IRQHandler NVIC_IRQHandler
|
|||
|
*/
|
|||
|
|
|||
|
#define SDC_REQUEST_IRQ(n, hdl,d) ({SDC_LOGD("%s,%d,sdc %d irq request \n",__func__, __LINE__, d->sdc_id);\
|
|||
|
request_irq(n, hdl, 0, "sdmmc",d);})
|
|||
|
#define SDC_FREE_IRQ(n, d) (free_irq(n, d))
|
|||
|
#define SDC_SetPriority(n, l) ({SDC_LOGN("Not imp %s,%d\n", __FUNCTION__,__LINE__);})
|
|||
|
#define SDC_ENABLE_IRQ(n) enable_irq(n)
|
|||
|
#define SDC_CONFIG_IRQ(n, hdl, l) ({SDC_LOGN("Not imp %s,%d\n", __FUNCTION__,__LINE__);})
|
|||
|
#define SDC_DISABLE_IRQ(n) disable_irq(n)
|
|||
|
//#define SDC_CLEAR_IRQPINGD(n) gic_clear_pending(n)
|
|||
|
#define SDC_CLEAR_IRQPINGD(n) ({SDC_LOGN("Not imp %s,%d\n", __FUNCTION__,__LINE__);})
|
|||
|
//#define SDC_CLEAR_IRQPINGD(n) free_irq(n)
|
|||
|
//#define SDC_IRQHandler interrupt_handler_t
|
|||
|
#define SDC_IRQHandler irq_handler_t *
|
|||
|
|
|||
|
#define NUSE_STANDARD_INTERFACE 1
|
|||
|
#ifdef NUSE_STANDARD_INTERFACE
|
|||
|
#define SDC1_SUPPORT 1
|
|||
|
#define SDC_CCM_SDC0_SCLK_CTRL (SDC_CCM_BASE + 0x830)
|
|||
|
#define SDC_CCM_SDC1_SCLK_CTRL (SDC_CCM_BASE + 0x834)
|
|||
|
#define SDC_CCM_SDC_BUS_GATE_RESET (SDC_CCM_BASE + 0x84c)
|
|||
|
/*
|
|||
|
#define SDC0_CCM_BusForceReset() HAL_CCM_BusForcePeriphReset(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusReleaseRest() HAL_CCM_BusReleasePeriphReset(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusEnableClock() HAL_CCM_BusEnablePeriphClock(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusDisableClock() HAL_CCM_BusDisablePeriphClock(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_EnableMClock() HAL_CCM_SDC0_EnableMClock()
|
|||
|
#define SDC0_DisableMClock HAL_CCM_SDC0_DisableMClock
|
|||
|
#define SDC0_SetMClock HAL_CCM_SDC0_SetMClock
|
|||
|
*/
|
|||
|
|
|||
|
#define SDC0_CCM_BusForceReset() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v &= ~(1<<16); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC0_CCM_BusReleaseRest() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v |= (1<<16); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC0_CCM_BusEnableClock() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v |= (1<<0); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC0_CCM_BusDisableClock() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v &= ~(1<<0); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC0_CCM_EnableMClock() ({int v = readl(SDC_CCM_SDC0_SCLK_CTRL); v |= (1<<31); writel(v,SDC_CCM_SDC0_SCLK_CTRL);})
|
|||
|
#define SDC0_DisableMClock() ({int v = readl(SDC_CCM_SDC0_SCLK_CTRL); v &= ~(1<<31); writel(v,SDC_CCM_SDC0_SCLK_CTRL);})
|
|||
|
|
|||
|
|
|||
|
#define SDC1_CCM_BusForceReset() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v &= ~(1<<17); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC1_CCM_BusReleaseRest() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v |= (1<<17); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC1_CCM_BusEnableClock() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v |= (1<<1); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC1_CCM_BusDisableClock() ({int v = readl(SDC_CCM_SDC_BUS_GATE_RESET); v &= ~(1<<1); writel(v,SDC_CCM_SDC_BUS_GATE_RESET);})
|
|||
|
#define SDC1_CCM_EnableMClock() ({int v = readl(SDC_CCM_SDC1_SCLK_CTRL); v |= (1<<31); writel(v,SDC_CCM_SDC1_SCLK_CTRL);})
|
|||
|
#define SDC1_DisableMClock() ({int v = readl(SDC_CCM_SDC1_SCLK_CTRL); v &= ~(1<<31); writel(v,SDC_CCM_SDC1_SCLK_CTRL);})
|
|||
|
|
|||
|
#define SDC1_SET_GPIO_MUX() ({int v = readl(SDC_GPIO_BASE + 0xd8);\
|
|||
|
SDC_LOGD("RAW SET SDC1 MUX\n");\
|
|||
|
v &= ~(0xffffff); v |=0x222222;\
|
|||
|
writel(v,SDC_GPIO_BASE + 0xd8);\
|
|||
|
SDC_LOGD("RAW SDC1 MUX %x\n", readl(SDC_GPIO_BASE + 0xd8));})
|
|||
|
#define SDC1_SET_GPIO_DRV() ({int v = readl(SDC_GPIO_BASE + 0xec);\
|
|||
|
SDC_LOGD("RAW SET SDC1 DRV\n");\
|
|||
|
v &= ~(0xfff);\
|
|||
|
v |=0x000; writel(v,SDC_GPIO_BASE + 0xec);\
|
|||
|
SDC_LOGD("RAW SDC1 DRV %x\n",readl(SDC_GPIO_BASE + 0xec));})
|
|||
|
#define SDC1_SET_GPIO_PULL() ({int v = readl(SDC_GPIO_BASE + 0xf4);\
|
|||
|
SDC_LOGD("RAW SET SDC1 PULL\n");\
|
|||
|
v &= ~(0xfff);\
|
|||
|
v |=0x555; writel(v,SDC_GPIO_BASE + 0xf4);\
|
|||
|
SDC_LOGD("RAW SDC1 PULL %x\n",readl(SDC_GPIO_BASE + 0xf4));})
|
|||
|
|
|||
|
|
|||
|
#define SDC_TIG_SET_GPIO_MUX() ({int v = readl(SDC_GPIO_BASE + 0x28);\
|
|||
|
SDC_LOGD("+RAW SET TIG SDC MUX %x\n", SDC_GPIO_BASE + 0x28);\
|
|||
|
v &= ~(0x0000F000); v |=0x00001000;\
|
|||
|
writel(v,SDC_GPIO_BASE + 0x28);\
|
|||
|
SDC_LOGD("-RAW SDC TIG MUX %x\n", readl(SDC_GPIO_BASE + 0x28));})
|
|||
|
#define SDC_TIG_SET_GPIO_DRV() ({int v = readl(SDC_GPIO_BASE + 0x38);\
|
|||
|
SDC_LOGD("+RAW SET SDC TIG DRV %x\n", SDC_GPIO_BASE + 0x38);\
|
|||
|
v &= ~(0x00C00000);\
|
|||
|
v |=0x00C00000; writel(v,SDC_GPIO_BASE + 0x38);\
|
|||
|
SDC_LOGD("-RAW SDC TRG DRV %x\n",readl(SDC_GPIO_BASE + 0x38));})
|
|||
|
#define SDC_TIG_SET_GPIO_PULL() ({int v = readl(SDC_GPIO_BASE + 0x40);\
|
|||
|
SDC_LOGD("+RAW SET SDC TRG PULL %x\n", SDC_GPIO_BASE + 0x40);\
|
|||
|
v &= ~(0x00C00000);\
|
|||
|
v |=0x00400000; writel(v,SDC_GPIO_BASE + 0x40);\
|
|||
|
SDC_LOGD("-RAW SDC1 PULL %x\n",readl(SDC_GPIO_BASE + 0x40));})
|
|||
|
|
|||
|
#define SDC_TIG_SET_GPIO_DAT() ({int v = readl(SDC_GPIO_BASE + 0x34);\
|
|||
|
SDC_LOGD("+raw set sdc trg dat %x\n",SDC_GPIO_BASE + 0x34);\
|
|||
|
v &= ~(0x00000800);\
|
|||
|
v |=0x00000800; writel(v,SDC_GPIO_BASE + 0x34);\
|
|||
|
SDC_LOGD("-RAW SDC1 DAT %x\n",readl(SDC_GPIO_BASE + 0x34));})
|
|||
|
|
|||
|
|
|||
|
#define SDC_TIG_CLR_GPIO_DAT() ({int v = readl(SDC_GPIO_BASE + 0x34);\
|
|||
|
SDC_LOGD("RAW SET SDC TRG dat\n");\
|
|||
|
v &= ~(0x00000800);\
|
|||
|
v |=0x00000000; writel(v,SDC_GPIO_BASE + 0x34);\
|
|||
|
SDC_LOGD("RAW SDC1 dat %x\n",readl(SDC_GPIO_BASE + 0x34));})
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#define HAL_BoardIoctl(a,b,c) ({SDC_LOGN("NOT IMP %s,%d\n",__FUNCTION__, __LINE__);})
|
|||
|
#define HAL_GPIO_ReadPin(cd_gpios, data) ({hal_gpio_get_data(cd_gpios, (gpio_data_t *)data);\
|
|||
|
*(data);})
|
|||
|
|
|||
|
#else
|
|||
|
#define SDC0_CCM_BusForceReset() HAL_CCM_BusForcePeriphReset(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusReleaseRest() HAL_CCM_BusReleasePeriphReset(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusEnableClock() HAL_CCM_BusEnablePeriphClock(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_BusDisableClock() HAL_CCM_BusDisablePeriphClock(CCM_BUS_PERIPH_BIT_SDC0)
|
|||
|
#define SDC0_CCM_EnableMClock() HAL_CCM_SDC0_EnableMClock()
|
|||
|
#define SDC0_DisableMClock HAL_CCM_SDC0_DisableMClock
|
|||
|
#define SDC0_SetMClock HAL_CCM_SDC0_SetMClock
|
|||
|
|
|||
|
#define SDC1_SUPPORT 1
|
|||
|
#define SDC1_CCM_BusForceReset() HAL_CCM_BusForcePeriphReset(CCM_BUS_PERIPH_BIT_SDC1)
|
|||
|
#define SDC1_CCM_BusReleaseRest() HAL_CCM_BusReleasePeriphReset(CCM_BUS_PERIPH_BIT_SDC1)
|
|||
|
#define SDC1_CCM_BusEnableClock() HAL_CCM_BusEnablePeriphClock(CCM_BUS_PERIPH_BIT_SDC1)
|
|||
|
#define SDC1_CCM_BusDisableClock() HAL_CCM_BusDisablePeriphClock(CCM_BUS_PERIPH_BIT_SDC1)
|
|||
|
#define SDC1_CCM_EnableMClock() HAL_CCM_SDC1_EnableMClock()
|
|||
|
#define SDC1_DisableMClock HAL_CCM_SDC1_DisableMClock
|
|||
|
#define SDC1_SetMClock HAL_CCM_SDC1_SetMClock
|
|||
|
|
|||
|
#endif /* NUSE_STANDARD_INTERFACE */
|
|||
|
|
|||
|
#ifndef SDC1_SUPPORT
|
|||
|
#define SDC1_SUPPORT 0
|
|||
|
#endif
|
|||
|
|
|||
|
#define MEMS_VA2PA(x) __va_to_pa(x)
|
|||
|
|
|||
|
#if 0
|
|||
|
#define mci_readl(host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x\n", (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readl((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg val 0x%x\n", val);\
|
|||
|
val;})
|
|||
|
#define mci_writel(value, host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x write val 0x%x\n", (uint32_t)(host)->reg_base + reg, value);\
|
|||
|
writel((value), (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readl((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg read val 0x%x\n", val);})
|
|||
|
|
|||
|
#define mci_readw(host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x\n", (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readw((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg val 0x%x\n", val);\
|
|||
|
val;})
|
|||
|
#define mci_writew(value, host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x write val 0x%x\n", (uint32_t)(host)->reg_base + reg, value);\
|
|||
|
writew((value), (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readl((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg read val 0x%x\n", val);})
|
|||
|
#define mci_readb(host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x\n", (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readb((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg val 0x%x\n", val);\
|
|||
|
val;})
|
|||
|
#define mci_writeb(value, host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
SDC_LOGD("+reg add 0x%x write val 0x%x\n", (uint32_t)(host)->reg_base + reg, value);\
|
|||
|
writeb((value), (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readl((uint32_t)(host)->reg_base + reg);\
|
|||
|
SDC_LOGD("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
SDC_LOGD("-reg read val 0x%x\n", val);})
|
|||
|
|
|||
|
|
|||
|
#else
|
|||
|
#define mci_readl(host, reg) \
|
|||
|
readl(HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
#define mci_writel(value, host, reg) \
|
|||
|
writel((value), HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
|
|||
|
#define mci_writew(value, host, reg) \
|
|||
|
writew((value), HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
|
|||
|
#define mci_readw(host, reg) \
|
|||
|
readw(HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
|
|||
|
#define mci_readb(host, reg) \
|
|||
|
readb(HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
|
|||
|
#define mci_writeb(value, host, reg) \
|
|||
|
writeb((value),HAL_PT_TO_U((host)->reg_base) + reg)
|
|||
|
#endif
|
|||
|
|
|||
|
#define SDC_BUSY_WAIT_LOOP (0xffffffff)
|
|||
|
int32_t __mci_check_bit_clear(struct mmc_host *host, uint32_t reg_offset, uint32_t bit_map);
|
|||
|
|
|||
|
static struct mmc_host *_mci_host[SDC_NUM];
|
|||
|
|
|||
|
/**
|
|||
|
* sdc timer timeout flags
|
|||
|
*/
|
|||
|
static int __sdc_init_timeout_flags = 0;
|
|||
|
|
|||
|
static uint64_t __mci_get_rate(uint64_t bytes, uint64_t time_us)
|
|||
|
{
|
|||
|
uint64_t ns;
|
|||
|
|
|||
|
ns = time_us * 1000;
|
|||
|
bytes *= 1000000000;
|
|||
|
|
|||
|
while (ns > UINT_MAX) {
|
|||
|
bytes >>= 1;
|
|||
|
ns >>= 1;
|
|||
|
}
|
|||
|
|
|||
|
if (!ns)
|
|||
|
return 0;
|
|||
|
|
|||
|
do_div(bytes, (uint32_t)ns);
|
|||
|
|
|||
|
return bytes;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_force_dump_host_info(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint16_t debug_mask = host->debug_mask;
|
|||
|
host->debug_mask |= ROM_DUMP_MASK | ROM_ERR_MASK;
|
|||
|
SDC_LOGE("*force dump gpio reg*\n");
|
|||
|
sdc_hex_dump_word((void *)SDC_GPIO_BASE+0xb0,0xff);
|
|||
|
sdc_hex_dump_word((void *)SDC_GPIO_BASE+0x340,0xff);
|
|||
|
SDC_LOGE("*force dump ccmu reg*\n");
|
|||
|
sdc_hex_dump_word((void *)SDC_CCM_SDC0_SCLK_CTRL ,0xff);
|
|||
|
sdc_hex_dump_word((void *)SDC_CCM_BASE ,0xff);
|
|||
|
SDC_LOGE("*force dump smc reg*\n");
|
|||
|
sdc_hex_dump_word((void *)(SMC0_BASE + 0x1000UL * host->sdc_id) ,0x150);
|
|||
|
SDC_LOGE("force dump state wait:%x,int_sum %x, int_err %x\n",\
|
|||
|
(unsigned int)host->wait, (unsigned int)host->int_sum, (unsigned int)host->int_err);
|
|||
|
SDC_LOGE("force dump done dma_done:%x,transfer_done %x\n",\
|
|||
|
(unsigned int)host->dma_done, (unsigned int)host->trans_done);
|
|||
|
host->debug_mask = debug_mask;
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_exit_host(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_SUPPORT_1V8
|
|||
|
host->voltage = SDC_WOLTAGE_OFF;
|
|||
|
#endif
|
|||
|
|
|||
|
rval = mci_readl(host, SDXC_REG_GCTRL) | SDXC_HWReset;
|
|||
|
mci_writel(rval, host, SDXC_REG_GCTRL);
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_GCTRL, SDXC_HWReset);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static __inline void __mci_sel_access_mode(struct mmc_host *host, uint32_t access_mode)
|
|||
|
{
|
|||
|
mci_writel((mci_readl(host, SDXC_REG_GCTRL) & (~SDXC_ACCESS_BY_AHB)) | access_mode,
|
|||
|
host, SDXC_REG_GCTRL);
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_reset(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t value;
|
|||
|
uint32_t time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
|
|||
|
value = mci_readl(host, SDXC_REG_GCTRL)|SDXC_HWReset;
|
|||
|
mci_writel(value, host, SDXC_REG_GCTRL);
|
|||
|
while ((mci_readl(host, SDXC_REG_GCTRL) & SDXC_SoftReset) && (HAL_TimeBefore(HAL_Ticks(), time)));
|
|||
|
if (mci_readl(host, SDXC_REG_GCTRL) & SDXC_SoftReset) {
|
|||
|
SDC_LOGE("SDC reset time out\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
SDC_LOGD("%s,%d SDC reset finish \n", __func__, __LINE__);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_program_clk(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t value;
|
|||
|
int32_t ret = 0;
|
|||
|
uint32_t time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
|
|||
|
/* disable command done interrupt */
|
|||
|
mci_writel((mci_readl(host, SDXC_REG_IMASK) & (~SDXC_CmdDone))|host->sdio_irq_mask,
|
|||
|
host, SDXC_REG_IMASK);
|
|||
|
|
|||
|
mci_writel(mci_readl(host, SDXC_REG_CLKCR) | SDXC_Mask_Data0,\
|
|||
|
host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
value = SDXC_Start | SDXC_UPCLKOnly | SDXC_WaitPreOver;
|
|||
|
mci_writel(value, host, SDXC_REG_CMDR);
|
|||
|
|
|||
|
do {
|
|||
|
value = mci_readl(host, SDXC_REG_CMDR);
|
|||
|
} while ((value & SDXC_Start) && HAL_TimeBefore(HAL_Ticks(), time));
|
|||
|
|
|||
|
if (mci_readl(host, SDXC_REG_CMDR) & SDXC_Start) {
|
|||
|
SDC_LOGE("%s,%d SDC change clock time out\n", __func__, __LINE__);
|
|||
|
__mci_force_dump_host_info(host);
|
|||
|
ret = -1;
|
|||
|
}
|
|||
|
|
|||
|
/* clear command done flag */
|
|||
|
value = mci_readl(host, SDXC_REG_RINTR);
|
|||
|
mci_writel(value, host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
mci_writel(mci_readl(host, SDXC_REG_CLKCR) & ~SDXC_Mask_Data0,\
|
|||
|
host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
/* enable command done interrupt */
|
|||
|
mci_writel((mci_readl(host, SDXC_REG_IMASK) | SDXC_CmdDone)|host->sdio_irq_mask,
|
|||
|
host, SDXC_REG_IMASK);
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_trans_by_ahb(struct mmc_host *host, struct mmc_data *data)
|
|||
|
{
|
|||
|
uint32_t i, j;
|
|||
|
uint32_t *buf_temp; /* Cortex-M3/4 can access data with unaligned address */
|
|||
|
uint32_t time;
|
|||
|
|
|||
|
for (i = 0; i < data->sg_len; i++) {
|
|||
|
buf_temp = data->sg[i].buffer;
|
|||
|
if (data->flags & MMC_DATA_READ) {
|
|||
|
for (j = 0; j < (data->sg[i].len >> 2); j++) { /* sg[i].len should be multiply of 4 */
|
|||
|
time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1 ;
|
|||
|
while ((mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOEmpty) &&
|
|||
|
(HAL_TimeBefore(HAL_Ticks(), time)) && host->present);
|
|||
|
if(mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOEmpty){
|
|||
|
SDC_LOGE("read from fifo timeout1\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
buf_temp[j] = mci_readl(host, SDXC_REG_FIFO);
|
|||
|
}
|
|||
|
|
|||
|
if((data->sg[i].len) & 0x3) {
|
|||
|
time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
while ((mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOEmpty) &&
|
|||
|
(HAL_TimeBefore(HAL_Ticks(), time)) && host->present);
|
|||
|
if(mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOEmpty){
|
|||
|
SDC_LOGE("read from fifo timeout2\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(((data->sg[i].len) & 0x3) == 2){
|
|||
|
buf_temp[j] = (uint16_t)mci_readl(host, SDXC_REG_FIFO);
|
|||
|
}else if(((data->sg[i].len) & 0x3) == 1){
|
|||
|
buf_temp[j] = (uint8_t)mci_readl(host, SDXC_REG_FIFO);
|
|||
|
}else
|
|||
|
SDC_BUG_ON(1);
|
|||
|
}
|
|||
|
} else if (data->flags & MMC_DATA_WRITE) {
|
|||
|
for (j = 0; j < (data->sg[i].len >> 2); j++) { /* sg[i].len should be multiply of 4 */
|
|||
|
time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
while ((mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOFull) &&
|
|||
|
(HAL_TimeBefore(HAL_Ticks(), time)) && host->present);
|
|||
|
if(mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOFull){
|
|||
|
SDC_LOGE("write to fifo timeout1\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
mci_writel(buf_temp[j], host, SDXC_REG_FIFO);
|
|||
|
}
|
|||
|
|
|||
|
if((data->sg[i].len) & 0x3) {
|
|||
|
time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
while ((mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOFull) &&
|
|||
|
(HAL_TimeBefore(HAL_Ticks(), time)) && host->present);
|
|||
|
if(mci_readl(host, SDXC_REG_STAS) & SDXC_FIFOFull){
|
|||
|
SDC_LOGE("write to fifo timeout2\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if(((data->sg[i].len) & 0x3) == 2){
|
|||
|
mci_writel((uint16_t)buf_temp[j], host, SDXC_REG_FIFO);
|
|||
|
}else if(((data->sg[i].len) & 0x3) == 1){
|
|||
|
mci_writel((uint8_t)buf_temp[j], host, SDXC_REG_FIFO);
|
|||
|
}else
|
|||
|
SDC_BUG_ON(1);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
SDC_LOGW("illigle data request\n");
|
|||
|
SDC_BUG_ON(1);
|
|||
|
return ;
|
|||
|
}
|
|||
|
}
|
|||
|
HAL_WMB();
|
|||
|
}
|
|||
|
|
|||
|
static smc_idma_des *__mci_alloc_idma_des(struct mmc_host *host, struct mmc_data *data)
|
|||
|
{
|
|||
|
smc_idma_des *pdes = host->idma_des;
|
|||
|
uint32_t des_idx = 0;
|
|||
|
uint32_t buff_frag_num = 0;
|
|||
|
uint32_t remain;
|
|||
|
uint32_t i, j;
|
|||
|
uint32_t config;
|
|||
|
|
|||
|
|
|||
|
/* init IDMA Descriptor, two mode: 1-fixed skip length, 2-chain mode */
|
|||
|
for (i = 0; i < data->sg_len; i++) {
|
|||
|
buff_frag_num = data->sg[i].len >> SDXC_DES_NUM_SHIFT; /* num = len/8192 = len>>13 */
|
|||
|
remain = data->sg[i].len & (SDXC_DES_BUFFER_MAX_LEN - 1);
|
|||
|
if (remain) {
|
|||
|
buff_frag_num++;
|
|||
|
} else {
|
|||
|
remain = SDXC_DES_BUFFER_MAX_LEN;
|
|||
|
}
|
|||
|
|
|||
|
for (j = 0; j < buff_frag_num; j++, des_idx++) {
|
|||
|
SDC_Memset((void *)&pdes[des_idx], 0, sizeof(smc_idma_des));
|
|||
|
config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_DIC;
|
|||
|
if (buff_frag_num > 1 && j != buff_frag_num - 1) {
|
|||
|
pdes[des_idx].data_buf1_sz = SDXC_DES_BUFFER_MAX_LEN;
|
|||
|
} else {
|
|||
|
pdes[des_idx].data_buf1_sz = remain;
|
|||
|
}
|
|||
|
|
|||
|
pdes[des_idx].buf_addr_ptr1 = SDXC_IDMAC_DES_ADDR((uint32_t)MEMS_VA2PA(HAL_PT_TO_U(data->sg[i].buffer)) + j * SDXC_DES_BUFFER_MAX_LEN);
|
|||
|
if (i == 0 && j == 0) {
|
|||
|
config |= SDXC_IDMAC_DES0_FD;
|
|||
|
}
|
|||
|
|
|||
|
if ((i == data->sg_len - 1) && (j == buff_frag_num - 1)) {
|
|||
|
config &= ~SDXC_IDMAC_DES0_DIC;
|
|||
|
config |= SDXC_IDMAC_DES0_LD | SDXC_IDMAC_DES0_ER;
|
|||
|
pdes[des_idx].buf_addr_ptr2 = 0;
|
|||
|
} else {
|
|||
|
pdes[des_idx].buf_addr_ptr2 = SDXC_IDMAC_DES_ADDR((uint32_t)MEMS_VA2PA(HAL_PT_TO_U(&pdes[des_idx + 1])));
|
|||
|
}
|
|||
|
pdes[des_idx].config = config;
|
|||
|
SDC_LOGD("sg %lu, frag %lu, remain %lu, des[%lu](%p): [0]:%lx, [1]:%lx, [2]:%lx, [3]:%lx\n",
|
|||
|
HAL_PR_SZ_L(i), HAL_PR_SZ_L(j), HAL_PR_SZ_L(remain), HAL_PR_SZ_L(des_idx), &pdes[des_idx],
|
|||
|
HAL_PR_SZ_L(((uint32_t *)&pdes[des_idx])[0]), HAL_PR_SZ_L(((uint32_t *)&pdes[des_idx])[1]),
|
|||
|
HAL_PR_SZ_L(((uint32_t *)&pdes[des_idx])[2]), HAL_PR_SZ_L(((uint32_t *)&pdes[des_idx])[3]));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
HAL_FlushDcacheRegion((unsigned long)pdes, HAL_ALIGN(SDXC_MAX_DES_NUM * sizeof(smc_idma_des), OS_CACHE_ALIGN_BYTES));
|
|||
|
HAL_WMB();
|
|||
|
return pdes;
|
|||
|
}
|
|||
|
|
|||
|
static smc_idma_des *__mci_prepare_dma(struct mmc_host *host, struct mmc_data *data)
|
|||
|
{
|
|||
|
uint32_t temp;
|
|||
|
smc_idma_des *pdes = NULL;
|
|||
|
|
|||
|
/* creat descriptor list, two mode: 1-fixed skip length, 2-chain mode */
|
|||
|
pdes = __mci_alloc_idma_des(host, data);
|
|||
|
if (NULL == pdes) {
|
|||
|
SDC_LOGW("alloc IDMA descriptor failed\n");
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
temp = mci_readl(host, SDXC_REG_GCTRL);
|
|||
|
temp |= SDXC_DMAEnb;
|
|||
|
mci_writel(temp, host, SDXC_REG_GCTRL);
|
|||
|
temp |= (SDXC_DMAReset | SDXC_FIFOReset);
|
|||
|
mci_writel(temp, host, SDXC_REG_GCTRL);
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_GCTRL, (SDXC_DMAReset | SDXC_FIFOReset));
|
|||
|
mci_writel(SDXC_IDMACSoftRST, host, SDXC_REG_DMAC); /* reset IDMAC */
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_DMAC, SDXC_IDMACSoftRST);
|
|||
|
temp = SDXC_IDMACFixBurst | SDXC_IDMACIDMAOn;
|
|||
|
mci_writel(temp, host, SDXC_REG_DMAC);
|
|||
|
/* enable IDMA interrupt, here not use */
|
|||
|
temp = mci_readl(host, SDXC_REG_IDIE);
|
|||
|
temp &= ~(SDXC_IDMACReceiveInt | SDXC_IDMACTransmitInt);
|
|||
|
if (data->flags & MMC_DATA_WRITE) {
|
|||
|
;//temp |= SDXC_IDMACTransmitInt; /* disable dma int for less irqs */
|
|||
|
} else {
|
|||
|
temp |= SDXC_IDMACReceiveInt;
|
|||
|
}
|
|||
|
mci_writel(temp, host, SDXC_REG_IDIE);
|
|||
|
|
|||
|
/* write descriptor address to register */
|
|||
|
mci_writel(SDXC_IDMAC_DES_ADDR((uint32_t)MEMS_VA2PA(HAL_PT_TO_U(pdes))), host, SDXC_REG_DLBA);
|
|||
|
/* write water level */
|
|||
|
mci_writel((BURST_SIZE << 28) | (SMC_RX_WLEVEL << 16) | SMC_TX_WLEVEL,
|
|||
|
host, SDXC_REG_FTRGL);
|
|||
|
|
|||
|
return pdes;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_free_idma_des(smc_idma_des *pdes)
|
|||
|
{
|
|||
|
pdes->config &= ~SDXC_IDMAC_DES0_OWN;
|
|||
|
}
|
|||
|
|
|||
|
int32_t __mci_wait_access_done(struct mmc_host *host)
|
|||
|
{
|
|||
|
int32_t own_set = 0;
|
|||
|
uint32_t time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
|
|||
|
while (!(mci_readl(host, SDXC_REG_GCTRL) & SDXC_MemAccessDone) && (HAL_TimeBefore(HAL_Ticks(), time)));
|
|||
|
if (!(mci_readl(host, SDXC_REG_GCTRL) & SDXC_MemAccessDone)) {
|
|||
|
SDC_LOGE("wait memory access done timeout !!\n");
|
|||
|
}
|
|||
|
|
|||
|
return own_set;
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_request_done(struct mmc_host *host)
|
|||
|
{
|
|||
|
struct mmc_request *mrq = host->mrq;
|
|||
|
unsigned long iflags;
|
|||
|
uint32_t temp;
|
|||
|
int32_t ret = 0;
|
|||
|
|
|||
|
iflags = HAL_EnterCriticalSection();
|
|||
|
if (host->wait != SDC_WAIT_FINALIZE) {
|
|||
|
HAL_ExitCriticalSection(iflags);
|
|||
|
SDC_LOGW("%s nothing finalize, wt %lx\n", __func__, HAL_PR_SZ_L(host->wait));
|
|||
|
return -1;
|
|||
|
}
|
|||
|
host->wait = SDC_WAIT_NONE;
|
|||
|
host->trans_done = 0;
|
|||
|
host->dma_done = 0;
|
|||
|
HAL_ExitCriticalSection(iflags);
|
|||
|
|
|||
|
if (host->int_sum & SDXC_IntErrBit) {
|
|||
|
SDC_LOGE("SDC err, cmd %ld, %s%s%s%s%s%s%s%s%s%s\n",
|
|||
|
HAL_PR_SZ_L(host->smc_cmd & SDXC_CMD_OPCODE),
|
|||
|
host->int_sum & SDXC_RespErr ? " RE" : "",
|
|||
|
host->int_sum & SDXC_RespCRCErr ? " RCE" : "",
|
|||
|
host->int_sum & SDXC_DataCRCErr ? " DCE" : "",
|
|||
|
host->int_sum & SDXC_RespTimeout ? " RTO" : "",
|
|||
|
host->int_sum & SDXC_DataTimeout ? " DTO" : "",
|
|||
|
host->int_sum & SDXC_DataStarve ? " DS" : "",
|
|||
|
host->int_sum & SDXC_FIFORunErr ? " FRE" : "",
|
|||
|
host->int_sum & SDXC_HardWLocked ? " HL" : "",
|
|||
|
host->int_sum & SDXC_StartBitErr ? " SBE" : "",
|
|||
|
host->int_sum & SDXC_EndBitErr ? " EBE" : "");
|
|||
|
|
|||
|
sdc_hex_dump_word((void *)(SDC_GPIO_BASE+0xB0),0xff);
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
sdc_hex_dump_word((void *)SDC_CCM_SDC0_SCLK_CTRL ,0x200);
|
|||
|
sdc_hex_dump_word((void *)SMC0_BASE ,0x200);
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
sdc_hex_dump_word((void *)SDC_CCM_SDC1_SCLK_CTRL ,0x200);
|
|||
|
sdc_hex_dump_word((void *)SMC1_BASE ,0x200);
|
|||
|
}
|
|||
|
ret = -1;
|
|||
|
goto out;
|
|||
|
}
|
|||
|
|
|||
|
if (mrq->cmd->flags & MMC_RSP_136) {
|
|||
|
mrq->cmd->resp[0] = mci_readl(host, SDXC_REG_RESP3);
|
|||
|
mrq->cmd->resp[1] = mci_readl(host, SDXC_REG_RESP2);
|
|||
|
mrq->cmd->resp[2] = mci_readl(host, SDXC_REG_RESP1);
|
|||
|
mrq->cmd->resp[3] = mci_readl(host, SDXC_REG_RESP0);
|
|||
|
} else
|
|||
|
mrq->cmd->resp[0] = mci_readl(host, SDXC_REG_RESP0);
|
|||
|
|
|||
|
out:
|
|||
|
if (mrq->data) {
|
|||
|
if (host->dma_hdle) {
|
|||
|
__mci_wait_access_done(host);
|
|||
|
mci_writel(0x337, host, SDXC_REG_IDST); /* clear interrupt flags */
|
|||
|
mci_writel(0, host, SDXC_REG_IDIE); /* disable idma interrupt */
|
|||
|
mci_writel(0, host, SDXC_REG_DMAC); /* idma off */
|
|||
|
temp = mci_readl(host, SDXC_REG_GCTRL);
|
|||
|
mci_writel(temp | SDXC_DMAReset, host, SDXC_REG_GCTRL);
|
|||
|
temp &= ~SDXC_DMAEnb;
|
|||
|
mci_writel(temp, host, SDXC_REG_GCTRL); /* disable IDMA */
|
|||
|
temp |= SDXC_FIFOReset;
|
|||
|
mci_writel(temp, host, SDXC_REG_GCTRL);
|
|||
|
__mci_free_idma_des((void *)host->dma_hdle);
|
|||
|
host->dma_hdle = NULL;
|
|||
|
}
|
|||
|
mci_writel(mci_readl(host, SDXC_REG_GCTRL) | SDXC_FIFOReset,
|
|||
|
host, SDXC_REG_GCTRL);
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3){
|
|||
|
mci_writel((SDXC_CardInsert|SDXC_CardRemove)|host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
} else
|
|||
|
#endif
|
|||
|
{
|
|||
|
mci_writel(host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
}
|
|||
|
if (host->int_sum & (SDXC_RespErr | SDXC_HardWLocked | SDXC_RespTimeout)) {
|
|||
|
SDC_LOGE("sdc %d abnormal status: %s\n", __LINE__,
|
|||
|
host->int_sum & SDXC_HardWLocked ? "HardWLocked" : "RespErr");
|
|||
|
}
|
|||
|
|
|||
|
mci_writel(0xffff, host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
SDC_LOGD("SDC done, resp %lx %lx %lx %lx\n", HAL_PR_SZ_L(mrq->cmd->resp[0]),
|
|||
|
HAL_PR_SZ_L(mrq->cmd->resp[1]), HAL_PR_SZ_L(mrq->cmd->resp[2]), HAL_PR_SZ_L(mrq->cmd->resp[3]));
|
|||
|
|
|||
|
if (mrq->data && (host->int_sum & SDXC_IntErrBit)) {
|
|||
|
SDC_LOGW("found data error, need to send stop command !!\n");
|
|||
|
__mci_reset(host);
|
|||
|
__mci_program_clk(host);
|
|||
|
}
|
|||
|
|
|||
|
host->int_err = 0;
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
#define mci_writel_irq(value, host, reg) \
|
|||
|
({ uint32_t val;\
|
|||
|
printf("+irq reg add 0x%x write val 0x%x\n", (uint32_t)(host)->reg_base + reg, value);\
|
|||
|
writel((value), (uint32_t)(host)->reg_base + reg);\
|
|||
|
val = readl((uint32_t)(host)->reg_base + reg);\
|
|||
|
printf("%s,%d\n", __FUNCTION__, __LINE__);\
|
|||
|
printf("-irq reg read val 0x%x\n", (unsigned int)val);})
|
|||
|
|
|||
|
|
|||
|
//#ifdef CONFIG_SDIO_IRQ_SUPPORT
|
|||
|
__nonxip_text
|
|||
|
static void __mci_enable_sdio_irq(struct mmc_host *host, int enable)
|
|||
|
{
|
|||
|
uint32_t imask;
|
|||
|
uint32_t flags = HAL_EnterCriticalSection();
|
|||
|
imask = mci_readl(host, SDXC_REG_IMASK);
|
|||
|
if (enable){
|
|||
|
// mci_writel(SDXC_SDIOInt, host, SDXC_REG_RINTR);
|
|||
|
host->sdio_irq_mask = SDXC_SDIOInt;
|
|||
|
imask |= SDXC_SDIOInt;
|
|||
|
}else{
|
|||
|
host->sdio_irq_mask = 0;
|
|||
|
imask &= ~SDXC_SDIOInt;
|
|||
|
}
|
|||
|
mci_writel(imask, host, SDXC_REG_IMASK);
|
|||
|
HAL_ExitCriticalSection(flags);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
__nonxip_text
|
|||
|
static inline void __mci_signal_sdio_irq(struct mmc_host *host)
|
|||
|
{
|
|||
|
// if (!host->card || !host->card->irq_handler) {
|
|||
|
if (!host->card) {
|
|||
|
SDC_IT_LOGE("BUG at __mci_signal_sdio_irq():%d\n", __LINE__);
|
|||
|
return;
|
|||
|
}
|
|||
|
#ifdef SD_PERF_TRACE_ON
|
|||
|
host->start_sdio_irq_times_ns = HAL_GetTimeNs();
|
|||
|
host->sdio_irq_count ++;
|
|||
|
#endif
|
|||
|
__mci_enable_sdio_irq(host, 0);
|
|||
|
host->sdio_irq_pending = true;
|
|||
|
//if (host.sdio_irq_thread)
|
|||
|
//xTaskResumeFromISR(host->sdio_irq_thread.handle);
|
|||
|
OS_SemaphoreRelease(&host->sdio_irq_signal);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void rom_HAL_SDC_Enable_Sdio_Irq(struct mmc_host *host, int enable)
|
|||
|
{
|
|||
|
uint32_t flags = 0;
|
|||
|
|
|||
|
__mci_enable_sdio_irq(host,enable);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//#endif
|
|||
|
|
|||
|
static void __mci_clk_prepare_enable(struct mmc_host *host)
|
|||
|
{
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_CCM_BusEnableClock(); /* clock enable */
|
|||
|
SDC0_CCM_BusReleaseRest(); /* reset and gating */
|
|||
|
SDC0_CCM_EnableMClock();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_CCM_BusEnableClock(); /* clock enable */
|
|||
|
SDC1_CCM_BusReleaseRest(); /* reset and gating */
|
|||
|
SDC1_CCM_EnableMClock();
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_clk_disable_unprepare(struct mmc_host *host)
|
|||
|
{
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_CCM_BusDisableClock();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_CCM_BusDisableClock();
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_hold_io(struct mmc_host* host)
|
|||
|
{
|
|||
|
#ifdef __CONFIG_ARCH_APP_CORE
|
|||
|
#ifndef NUSE_STANDARD_INTERFACE
|
|||
|
/* disable gpio to avoid power leakage */
|
|||
|
if (host->pin_ref) {
|
|||
|
HAL_BoardIoctl(HAL_BIR_PINMUX_DEINIT, HAL_MKDEV(HAL_DEV_MAJOR_SDC,
|
|||
|
host->sdc_id), SDCGPIO_BAS);
|
|||
|
host->pin_ref = 0;
|
|||
|
}
|
|||
|
#else
|
|||
|
SDC_LOGN("Not implement %s,%d\n", __FUNCTION__, __LINE__);
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_restore_io(struct mmc_host* host)
|
|||
|
{
|
|||
|
#ifdef __CONFIG_ARCH_APP_CORE
|
|||
|
#ifndef NUSE_STANDARD_INTERFACE
|
|||
|
if (host->pin_ref == 0) {
|
|||
|
HAL_BoardIoctl(HAL_BIR_PINMUX_INIT, HAL_MKDEV(HAL_DEV_MAJOR_SDC,
|
|||
|
host->sdc_id), SDCGPIO_BAS);
|
|||
|
host->pin_ref = 1;
|
|||
|
}
|
|||
|
#else
|
|||
|
SDC_LOGN("Not implement %s,%d\n", __FUNCTION__, __LINE__);
|
|||
|
#endif
|
|||
|
#
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
__nonxip_text
|
|||
|
static irqreturn_t __mci_irq_handler(uint32_t sdc_id)
|
|||
|
{
|
|||
|
struct mmc_host *host = _mci_host[sdc_id];
|
|||
|
uint32_t sdio_int = 0;
|
|||
|
uint32_t raw_int;
|
|||
|
uint32_t msk_int;
|
|||
|
uint32_t idma_inte;
|
|||
|
uint32_t idma_int;
|
|||
|
|
|||
|
#if (defined(__CONFIG_SECTION_ATTRIBUTE_NONXIP) && SDC_DEBUG)
|
|||
|
__nonxip_rodata static const char __s_func[] = "__mci_irq_handler";
|
|||
|
#endif
|
|||
|
//SDC_IT_LOGD("***%s,%d***\n",__FUNCTION__, __LINE__);
|
|||
|
if (!host) {
|
|||
|
SDC_IT_LOGE_RAW(ROM_ERR_MASK, "%s,%d no host exist!\n", __func__, __LINE__);
|
|||
|
return IRQ_NONE;
|
|||
|
}
|
|||
|
|
|||
|
if (!host->present) {
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_CCM_BusEnableClock();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_CCM_BusEnableClock();
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
idma_int = mci_readl(host, SDXC_REG_IDST);
|
|||
|
idma_inte = mci_readl(host, SDXC_REG_IDIE);
|
|||
|
raw_int = mci_readl(host, SDXC_REG_RINTR);
|
|||
|
msk_int = mci_readl(host, SDXC_REG_MISTA);
|
|||
|
|
|||
|
if (!msk_int && !idma_int) {
|
|||
|
SDC_IT_LOGE("sdc nop irq: ri:%08lx mi:%08lx ie:%08lx idi:%08lx\n",
|
|||
|
HAL_PR_SZ_L(raw_int), HAL_PR_SZ_L(msk_int), HAL_PR_SZ_L(idma_inte), HAL_PR_SZ_L(idma_int));
|
|||
|
return IRQ_NONE;
|
|||
|
}
|
|||
|
|
|||
|
host->int_sum = raw_int;
|
|||
|
SDC_IT_LOGD("sdc %d ri:%02x(%02x), mi:%x, ie:%x, idi:%x\n", __LINE__,
|
|||
|
(int)raw_int, (int)host->int_sum,
|
|||
|
(int)msk_int, (int)idma_inte, (int)idma_int);
|
|||
|
|
|||
|
(void)idma_inte;
|
|||
|
|
|||
|
#ifdef CONFIG_SDIO_IRQ_SUPPORT
|
|||
|
if (msk_int & SDXC_SDIOInt) {
|
|||
|
sdio_int = 1;
|
|||
|
mci_writel(SDXC_SDIOInt, host, SDXC_REG_RINTR);
|
|||
|
goto sdio_out;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
if (msk_int & SDXC_CardInsert) {
|
|||
|
SDC_IT_LOGN("Card Insert !!\n");
|
|||
|
host->present = 1;
|
|||
|
SDC_IT_ModTimer(&host->cd_timer, 10);
|
|||
|
} else if (msk_int & SDXC_CardRemove) {
|
|||
|
SDC_IT_LOGN("Card Remove !!\n");
|
|||
|
host->present = 0;
|
|||
|
SDC_IT_ModTimer(&host->cd_timer, 10);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (host->wait == SDC_WAIT_NONE && !sdio_int) {
|
|||
|
SDC_IT_LOGE("%s nothing to complete, ri:%08lx, mi:%08lx\n",
|
|||
|
__s_func, HAL_PR_SZ_L(raw_int), HAL_PR_SZ_L(msk_int));
|
|||
|
goto irq_out;
|
|||
|
}
|
|||
|
|
|||
|
if ((raw_int & SDXC_IntErrBit) || (idma_int & SDXC_IDMA_ERR)) {
|
|||
|
host->int_err = raw_int & SDXC_IntErrBit;
|
|||
|
host->wait = SDC_WAIT_FINALIZE;
|
|||
|
SDC_IT_LOGE("%s,%d raw_int:%lx err!\n", __s_func, __LINE__, HAL_PR_SZ_L(raw_int));
|
|||
|
goto irq_out;
|
|||
|
}
|
|||
|
if (raw_int & SDXC_HardWLocked) {
|
|||
|
SDC_IT_LOGE("command hardware lock\n");
|
|||
|
}
|
|||
|
|
|||
|
if (idma_int & (SDXC_IDMACTransmitInt|SDXC_IDMACReceiveInt)) {
|
|||
|
host->dma_done = 1;
|
|||
|
mci_writel(idma_int, host, SDXC_REG_IDST);
|
|||
|
}
|
|||
|
if (msk_int & (SDXC_AutoCMDDone|SDXC_DataOver|SDXC_CmdDone|SDXC_VolChgDone))
|
|||
|
host->trans_done = 1;
|
|||
|
if ((host->trans_done && \
|
|||
|
(host->wait == SDC_WAIT_AUTOCMD_DONE || host->wait == SDC_WAIT_DATA_OVER
|
|||
|
|| host->wait == SDC_WAIT_CMD_DONE || host->wait == SDC_WAIT_SWITCH1V8))
|
|||
|
|| (host->trans_done && host->dma_done && (host->wait & SDC_WAIT_IDMA_DONE))) {
|
|||
|
host->wait = SDC_WAIT_FINALIZE;
|
|||
|
}
|
|||
|
|
|||
|
irq_out:
|
|||
|
mci_writel(msk_int & (~SDXC_SDIOInt), host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
if (host->wait == SDC_WAIT_FINALIZE) {
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3){
|
|||
|
mci_writel(SDXC_CardInsert|SDXC_CardRemove|host->sdio_irq_mask,
|
|||
|
host, SDXC_REG_IMASK);
|
|||
|
} else
|
|||
|
#endif
|
|||
|
{
|
|||
|
mci_writel(host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
}
|
|||
|
|
|||
|
HAL_WMB();
|
|||
|
if(!OS_IsISRContext()){
|
|||
|
SDC_BUG_ON(1);
|
|||
|
sys_abort();
|
|||
|
}
|
|||
|
|
|||
|
SDC_SemPost(&host->lock);
|
|||
|
SDC_IT_LOGD("SDC irq post, trans:%d, dma:%d\n",
|
|||
|
(int)host->trans_done, (int)host->dma_done);
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_SDIO_IRQ_SUPPORT
|
|||
|
sdio_out:
|
|||
|
if (sdio_int)
|
|||
|
__mci_signal_sdio_irq(host);
|
|||
|
#endif
|
|||
|
return IRQ_HANDLED;
|
|||
|
}
|
|||
|
__nonxip_text
|
|||
|
irqreturn_t SDC0_IRQHandler(int id, void *data)
|
|||
|
{
|
|||
|
return __mci_irq_handler(SDC0);
|
|||
|
}
|
|||
|
|
|||
|
#if SDC1_SUPPORT
|
|||
|
__nonxip_text
|
|||
|
irqreturn_t SDC1_IRQHandler(int id, void *data) //static
|
|||
|
{
|
|||
|
return __mci_irq_handler(SDC1);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/* clock config:
|
|||
|
* SYS_CRYSTAL: 26M
|
|||
|
* 400K, SCLK-26M, 26M/(2^3)/(7+1)/2 = 361K
|
|||
|
* SYS_CRYSTAL: 24M
|
|||
|
* 400K, SCLK-24M, 24M/(2^2)/(7+1)/2 = 375K
|
|||
|
*
|
|||
|
* 25M, SCLK-192M, 192M/(2^0)/(3+1)/2 = 24M
|
|||
|
* 50M, SCLK-192M, 192M/(2^0)/(1+1)/2 = 48M
|
|||
|
* 64M, SCLK-192M, 192M/(2^0)/(1+1)/2 = 48M
|
|||
|
*/
|
|||
|
#define DEFINE_SYS_CRYSTAL HAL_GetHFClock()
|
|||
|
#define DEFINE_SYS_DEVCLK HAL_GetDevClock()
|
|||
|
|
|||
|
static int32_t __mci_update_clock(struct mmc_host *host, uint32_t cclk)
|
|||
|
{
|
|||
|
uint32_t sclk;
|
|||
|
uint32_t div;
|
|||
|
uint32_t rval;
|
|||
|
uint32_t src = 0;
|
|||
|
uint32_t m, n;
|
|||
|
|
|||
|
if (cclk > DEFINE_SYS_CRYSTAL/2) {
|
|||
|
#ifdef NUSE_STANDARD_INTERFACE
|
|||
|
src = 1;
|
|||
|
#else
|
|||
|
src = CCM_AHB_PERIPH_CLK_SRC_DEVCLK;
|
|||
|
#endif
|
|||
|
sclk = DEFINE_SYS_DEVCLK;
|
|||
|
} else {
|
|||
|
#ifdef NUSE_STANDARD_INTERFACE
|
|||
|
src = 0;
|
|||
|
#else
|
|||
|
src = CCM_AHB_PERIPH_CLK_SRC_HFCLK;
|
|||
|
#endif
|
|||
|
sclk = DEFINE_SYS_CRYSTAL;
|
|||
|
}
|
|||
|
cclk = cclk * 2; /* 2x MODE clock configure */
|
|||
|
div = (2 * sclk + cclk) / (2 * cclk);
|
|||
|
div = div == 0 ? 1 : div;
|
|||
|
if (div > 128) {
|
|||
|
n = 3;
|
|||
|
m = 16;
|
|||
|
SDC_LOGE("source clk is too high!\n");
|
|||
|
} else if (div > 64) {
|
|||
|
n = 3;
|
|||
|
m = div >> 3;
|
|||
|
} else if (div > 32) {
|
|||
|
n = 2;
|
|||
|
m = div >> 2;
|
|||
|
} else if (div > 16) {
|
|||
|
n = 1;
|
|||
|
m = div >> 1;
|
|||
|
} else {
|
|||
|
n = 0;
|
|||
|
m = div;
|
|||
|
}
|
|||
|
m = m - 1;
|
|||
|
#ifdef NUSE_STANDARD_INTERFACE
|
|||
|
/*
|
|||
|
if (src) {
|
|||
|
rval |= (2U << 20) | (1 << 8);
|
|||
|
SDC_LOGN("%s,%d check spec. bit20, 8!!\n", __func__, __LINE__);
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
rval = readl(SDC_CCM_SDC0_SCLK_CTRL);
|
|||
|
rval &= ~(1U<<31);
|
|||
|
writel(rval,SDC_CCM_SDC0_SCLK_CTRL);
|
|||
|
HAL_WMB();
|
|||
|
rval = (src << 24) | (n << 8) | (m);
|
|||
|
|
|||
|
writel(rval,SDC_CCM_SDC0_SCLK_CTRL);
|
|||
|
HAL_WMB();
|
|||
|
rval = readl(SDC_CCM_SDC0_SCLK_CTRL);
|
|||
|
rval |= (1U<<31);
|
|||
|
writel(rval,SDC_CCM_SDC0_SCLK_CTRL);
|
|||
|
HAL_WMB();
|
|||
|
|
|||
|
SDC_LOGN("SDC clock=%ld kHz,src:%x, n:%d, m:%d\n",
|
|||
|
HAL_PR_SZ_L((src ? DEFINE_SYS_DEVCLK:DEFINE_SYS_CRYSTAL)/(1<<n)/(m+1)/2),
|
|||
|
(int)src, (int)n, (int)m);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
rval = readl(SDC_CCM_SDC1_SCLK_CTRL);
|
|||
|
rval &= ~(1U<<31);
|
|||
|
writel(rval,SDC_CCM_SDC1_SCLK_CTRL);
|
|||
|
|
|||
|
HAL_WMB();
|
|||
|
rval = (src << 24) | (n << 8) | (m);
|
|||
|
writel(rval,SDC_CCM_SDC1_SCLK_CTRL);
|
|||
|
|
|||
|
HAL_WMB();
|
|||
|
rval = readl(SDC_CCM_SDC1_SCLK_CTRL);
|
|||
|
rval |= (1U<<31);
|
|||
|
writel(rval,SDC_CCM_SDC1_SCLK_CTRL);
|
|||
|
HAL_WMB();
|
|||
|
SDC_LOGN("SDC clock=%ld kHz,src:%x, n:%d, m:%d\n",
|
|||
|
HAL_PR_SZ_L((src?DEFINE_SYS_DEVCLK:DEFINE_SYS_CRYSTAL)/(1<<n)/(m+1)/2),
|
|||
|
(int)src, (int)n, (int)m);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_DisableMClock();
|
|||
|
SDC0_SetMClock(src, n << CCM_PERIPH_CLK_DIV_N_SHIFT, m << CCM_PERIPH_CLK_DIV_M_SHIFT);
|
|||
|
SDC0_CCM_EnableMClock();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_DisableMClock();
|
|||
|
SDC1_SetMClock(src, n << CCM_PERIPH_CLK_DIV_N_SHIFT, m << CCM_PERIPH_CLK_DIV_M_SHIFT);
|
|||
|
SDC1_CCM_EnableMClock();
|
|||
|
#endif
|
|||
|
}
|
|||
|
SDC_LOGN("SDC source:%u MHz clock=%u kHz, src:%x, n:%d, m:%d\n", sclk/1000000,
|
|||
|
sclk/(1<<n)/(m+1)/2000, (int)src, (int)n, (int)m);
|
|||
|
#endif
|
|||
|
|
|||
|
/* clear internal divider */
|
|||
|
rval = mci_readl(host, SDXC_REG_CLKCR) & (~0xff);
|
|||
|
mci_writel(rval, host, SDXC_REG_CLKCR);
|
|||
|
sdc_hex_dump_word((void *)SDC_CCM_BASE ,0x900);
|
|||
|
|
|||
|
return cclk;
|
|||
|
}
|
|||
|
|
|||
|
int32_t rom_HAL_SDC_Update_Clk(struct mmc_host *host, uint32_t clk)
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
if (!host || clk < 200000) { /* 200K */
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
/* Disable Clock */
|
|||
|
rval = mci_readl(host, SDXC_REG_CLKCR) & (~SDXC_CardClkOn) & (~SDXC_LowPowerOn);
|
|||
|
mci_writel(rval, host, SDXC_REG_CLKCR);
|
|||
|
if (__mci_program_clk(host)) {
|
|||
|
SDC_LOGE("Clock Program Failed 0!!\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
__mci_update_clock(host, clk);
|
|||
|
|
|||
|
/* Re-enable Clock */
|
|||
|
rval = mci_readl(host, SDXC_REG_CLKCR) | (SDXC_CardClkOn);// | SDXC_LowPowerOn;
|
|||
|
mci_writel(rval, host, SDXC_REG_CLKCR);
|
|||
|
if (__mci_program_clk(host)) {
|
|||
|
SDC_LOGE("Clock Program Failed 1!!\n");
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
host->clk = clk;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_update_clk(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
int32_t ret = 0;
|
|||
|
uint32_t time = HAL_Ticks() + HAL_MSecsToTicks(1000) + 1;
|
|||
|
|
|||
|
mci_writel(mci_readl(host, SDXC_REG_CLKCR) | SDXC_Mask_Data0,\
|
|||
|
host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
rval = SDXC_Start|SDXC_UPCLKOnly|SDXC_WaitPreOver;
|
|||
|
#ifdef CONFIG_SDC_SUPPORT_1V8
|
|||
|
if (host->voltage_switching)
|
|||
|
rval |= SDXC_VolSwitch;
|
|||
|
#endif
|
|||
|
mci_writel(rval, host, SDXC_REG_CMDR);
|
|||
|
|
|||
|
do {
|
|||
|
rval = mci_readl(host, SDXC_REG_CMDR);
|
|||
|
} while ((rval & SDXC_Start) && HAL_TimeBefore(HAL_Ticks(), time));
|
|||
|
|
|||
|
if (mci_readl(host, SDXC_REG_CMDR) & SDXC_Start) {
|
|||
|
SDC_LOGE("sdc update clock timeout, fatal error!!!\n");
|
|||
|
__mci_force_dump_host_info(host);
|
|||
|
ret = -1;
|
|||
|
}
|
|||
|
|
|||
|
if (!ret)
|
|||
|
SDC_LOGD("sdc update clock ok\n");
|
|||
|
|
|||
|
/* clear command done flag */
|
|||
|
rval = mci_readl(host, SDXC_REG_RINTR);
|
|||
|
mci_writel(rval, host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
mci_writel(mci_readl(host, SDXC_REG_CLKCR) & ~SDXC_Mask_Data0,\
|
|||
|
host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
int32_t rom_HAL_SDC_Clk_PWR_Opt(struct mmc_host *host, uint32_t oclk_en, uint32_t pwr_save)
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
if (!host->power_on)
|
|||
|
return 0;
|
|||
|
|
|||
|
rval = mci_readl(host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
rval &= ~(SDXC_CardClkOn | SDXC_LowPowerOn);
|
|||
|
if (oclk_en)
|
|||
|
rval |= SDXC_CardClkOn;
|
|||
|
if (pwr_save)
|
|||
|
rval |= SDXC_LowPowerOn;
|
|||
|
mci_writel(rval, host, SDXC_REG_CLKCR);
|
|||
|
|
|||
|
__mci_update_clk(host);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_debounce_onoff(struct mmc_host *host, uint32_t onoff)
|
|||
|
{
|
|||
|
uint32_t rval = mci_readl(host, SDXC_REG_GCTRL);
|
|||
|
|
|||
|
rval &= ~SDXC_DebounceEnb;
|
|||
|
if (onoff)
|
|||
|
rval |= SDXC_DebounceEnb;
|
|||
|
mci_writel(rval, host, SDXC_REG_GCTRL);
|
|||
|
SDC_LOGD("%s,%d,%ld\n",__FUNCTION__,__LINE__, HAL_PR_SZ_L(onoff));
|
|||
|
}
|
|||
|
|
|||
|
uint32_t HAL_SDC_Is_Busy(struct mmc_host *host)
|
|||
|
{
|
|||
|
return mci_readl(host, SDXC_REG_STAS) & SDXC_CardBusy;
|
|||
|
}
|
|||
|
|
|||
|
static int32_t __mci_check_busy_over(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t i;
|
|||
|
for(i = 0; i< SDC_BUSY_WAIT_LOOP; i++){
|
|||
|
if(!(mci_readl(host, SDXC_REG_STAS) & SDXC_CardBusy)){
|
|||
|
return 0;
|
|||
|
}
|
|||
|
if(i>(SDC_BUSY_WAIT_LOOP/8)) {
|
|||
|
mmc_mdelay(10);
|
|||
|
if(i%8)
|
|||
|
SDC_LOGW("Waiting reg %x bitmap %x clear v %x,i %x\n",\
|
|||
|
HAL_PR_SZ(HAL_PT_TO_U(host->reg_base)) + SDXC_REG_STAS,\
|
|||
|
(unsigned int)SDXC_CardBusy,\
|
|||
|
(unsigned int)mci_readl(host, SDXC_CardBusy),\
|
|||
|
(unsigned int)i);
|
|||
|
}
|
|||
|
SDC_LOGD("Waiting reg %x bitmap %x clear v %x,i %x\n",\
|
|||
|
HAL_PR_SZ(HAL_PT_TO_U(host->reg_base)) + SDXC_REG_STAS,\
|
|||
|
(unsigned int)SDXC_CardBusy,\
|
|||
|
(unsigned int)mci_readl(host, SDXC_CardBusy),\
|
|||
|
(unsigned int)i);
|
|||
|
}
|
|||
|
SDC_LOGE("Wait busy timeout %x,%x\n",
|
|||
|
(unsigned int)mci_readl(host, SDXC_REG_STAS), (unsigned int)i);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
int32_t __mci_check_bit_clear(struct mmc_host *host, uint32_t reg_offset, uint32_t bit_map)
|
|||
|
{
|
|||
|
uint32_t i;
|
|||
|
for(i = 0; i< SDC_BUSY_WAIT_LOOP; i++){
|
|||
|
if(!(mci_readl(host, reg_offset) & bit_map)){
|
|||
|
SDC_LOGD("Wait reg %p bitmap %x clear v %lx,i %x ok\n",\
|
|||
|
(host->reg_base) + reg_offset,\
|
|||
|
(unsigned int)bit_map,\
|
|||
|
HAL_PR_SZ_L(mci_readl(host, reg_offset)),\
|
|||
|
(unsigned int)i);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
if(i>(SDC_BUSY_WAIT_LOOP/8)) {
|
|||
|
mmc_mdelay(10);
|
|||
|
if(i%8)
|
|||
|
SDC_LOGW("Waiting reg %p bitmap %x clear v %lx,i %x\n",\
|
|||
|
(host->reg_base) + reg_offset,\
|
|||
|
(unsigned int)bit_map,\
|
|||
|
HAL_PR_SZ_L(mci_readl(host, reg_offset)),\
|
|||
|
(unsigned int)i);
|
|||
|
}
|
|||
|
}
|
|||
|
SDC_LOGE("Wait reg %p bitmap %x clear timeout v %lx,i %x\n",\
|
|||
|
(host->reg_base) + reg_offset,\
|
|||
|
(unsigned int) bit_map,\
|
|||
|
HAL_PR_SZ_L(mci_readl(host, reg_offset)),\
|
|||
|
(unsigned int)i);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void HAL_SDC_Set_BusWidth(struct mmc_host *host, uint32_t width)
|
|||
|
{
|
|||
|
if (!host) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__);
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
switch (width) {
|
|||
|
case MMC_BUS_WIDTH_1:
|
|||
|
mci_writel(SDXC_WIDTH1, host, SDXC_REG_WIDTH);
|
|||
|
break;
|
|||
|
case MMC_BUS_WIDTH_4:
|
|||
|
mci_writel(SDXC_WIDTH4, host, SDXC_REG_WIDTH);
|
|||
|
break;
|
|||
|
#ifdef CONFIG_USE_MMC
|
|||
|
case MMC_BUS_WIDTH_8:
|
|||
|
mci_writel(SDXC_WIDTH8, host, SDXC_REG_WIDTH);
|
|||
|
break;
|
|||
|
#endif
|
|||
|
default:
|
|||
|
SDC_BUG_ON(1);
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
host->buswidth = width;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_send_cmd(struct mmc_host *host, struct mmc_command *cmd)
|
|||
|
{
|
|||
|
uint32_t imask = SDXC_IntErrBit;
|
|||
|
uint32_t cmd_val = SDXC_Start | (cmd->opcode & 0x3f);
|
|||
|
unsigned long iflags;
|
|||
|
uint32_t wait = SDC_WAIT_CMD_DONE;
|
|||
|
struct mmc_data *data = cmd->data;
|
|||
|
|
|||
|
if (cmd->opcode == MMC_GO_IDLE_STATE) {
|
|||
|
cmd_val |= SDXC_SendInitSeq;
|
|||
|
imask |= SDXC_CmdDone;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_SUPPORT_1V8
|
|||
|
if (cmd->opcode == SD_SWITCH_VOLTAGE) {
|
|||
|
cmd_val |= SDXC_VolSwitch;
|
|||
|
imask |= SDXC_VolChgDone;
|
|||
|
host->voltage_switching = 1;
|
|||
|
wait = SDC_WAIT_SWITCH1V8;
|
|||
|
/* switch controller to high power mode */
|
|||
|
HAL_SDC_Clk_PWR_Opt(host, 1, 0);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (cmd->flags & MMC_RSP_PRESENT) { /* with response */
|
|||
|
cmd_val |= SDXC_RspExp;
|
|||
|
if (cmd->flags & MMC_RSP_136) /* long response */
|
|||
|
cmd_val |= SDXC_LongRsp;
|
|||
|
if (cmd->flags & MMC_RSP_CRC)
|
|||
|
cmd_val |= SDXC_CheckRspCRC;
|
|||
|
|
|||
|
if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { /* with data */
|
|||
|
if (!data) {
|
|||
|
SDC_LOGE("%s,%d no data exist!\n", __func__, __LINE__);
|
|||
|
return ;
|
|||
|
}
|
|||
|
cmd_val |= SDXC_DataExp | SDXC_WaitPreOver;
|
|||
|
wait = SDC_WAIT_DATA_OVER;
|
|||
|
if (data->flags & MMC_DATA_STREAM) { /* sequence mode */
|
|||
|
imask |= SDXC_AutoCMDDone;
|
|||
|
cmd_val |= SDXC_Seqmod | SDXC_SendAutoStop;
|
|||
|
wait = SDC_WAIT_AUTOCMD_DONE;
|
|||
|
}
|
|||
|
if (cmd->stop) {
|
|||
|
imask |= SDXC_AutoCMDDone;
|
|||
|
cmd_val |= SDXC_SendAutoStop;
|
|||
|
wait = SDC_WAIT_AUTOCMD_DONE;
|
|||
|
} else
|
|||
|
imask |= SDXC_DataOver;
|
|||
|
|
|||
|
if (data->flags & MMC_DATA_WRITE) {
|
|||
|
cmd_val |= SDXC_Write;
|
|||
|
} else if (host->dma_hdle) {
|
|||
|
wait |= SDC_WAIT_IDMA_DONE;
|
|||
|
}
|
|||
|
SDC_LOGD("blk_size:%lu, sg len:%lu\n",HAL_PR_SZ_L(data->blksz), HAL_PR_SZ_L(data->sg->len));
|
|||
|
} else
|
|||
|
imask |= SDXC_CmdDone;
|
|||
|
} else
|
|||
|
imask |= SDXC_CmdDone;
|
|||
|
|
|||
|
SDC_LOGD("sdc cmd:%ld(%lx), arg:%lx ie:%lx wt:%lx len:%lu\n",
|
|||
|
HAL_PR_SZ_L(cmd_val & SDXC_CMD_OPCODE), HAL_PR_SZ_L(cmd_val), HAL_PR_SZ_L(cmd->arg), HAL_PR_SZ_L(imask), HAL_PR_SZ_L(wait),
|
|||
|
HAL_PR_SZ_L(cmd->data ? cmd->data->blksz * cmd->data->blocks : 0));
|
|||
|
|
|||
|
iflags = HAL_EnterCriticalSection();
|
|||
|
host->smc_cmd = cmd_val;
|
|||
|
host->wait = wait;
|
|||
|
|
|||
|
mci_writel(imask | host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
|
|||
|
if (cmd_val & SDXC_SendAutoStop)
|
|||
|
mci_writel(0, host, SDXC_REG_A12A);
|
|||
|
else
|
|||
|
mci_writel(0xffff, host, SDXC_REG_A12A);
|
|||
|
|
|||
|
mci_writel(cmd->arg, host, SDXC_REG_CARG);
|
|||
|
HAL_WMB();
|
|||
|
mci_writel(cmd_val, host, SDXC_REG_CMDR);
|
|||
|
|
|||
|
|
|||
|
HAL_ExitCriticalSection(iflags);
|
|||
|
if (data && NULL == host->dma_hdle) {
|
|||
|
__mci_trans_by_ahb(host, data);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#ifdef SD_PERF_TRACE_ON
|
|||
|
static void __mci_start_data_time_stats(struct mmc_host *host, struct mmc_request *mrq)
|
|||
|
{
|
|||
|
if((mrq->data) && (mmc_cmd_type(mrq->cmd) == MMC_CMD_ADTC)){
|
|||
|
if( (mrq->data->blksz * mrq->data->blocks) > 4 )
|
|||
|
host->start_times_us = HAL_GetTimeUs();
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/*this func can not be called by irq_server_function;
|
|||
|
*because there are using printf(only printf support u64).
|
|||
|
*if you want to use it in irq_server_funciton,printf to printk
|
|||
|
* */
|
|||
|
static void __mci_end_data_time_stats(struct mmc_host *host, struct mmc_request *mrq)
|
|||
|
{
|
|||
|
if((mrq->data) && (mmc_cmd_type(mrq->cmd) == MMC_CMD_ADTC) \
|
|||
|
&& ((mrq->data->blksz * mrq->data->blocks) > 4)){
|
|||
|
uint64_t time_use_us = (uint64_t)HAL_GetTimeUs() - host->start_times_us;
|
|||
|
if((mrq->data->flags) & MMC_DATA_WRITE ) {
|
|||
|
host->wbytes += mrq->data->blksz * mrq->data->blocks ;
|
|||
|
host->wtimes_us += time_use_us;
|
|||
|
host->wcount ++;
|
|||
|
if(host->wcount && !(host->wcount % SD_PERF_TRACE_COUNT)) {
|
|||
|
printf("Stats Total write:bytes %lld, time us %lu, count %lld, %lld KB\n",\
|
|||
|
host->wbytes, host->wtimes_us, host->wcount,\
|
|||
|
__mci_get_rate(host->wbytes, host->wtimes_us)/1024);
|
|||
|
//host->wtimes_us = 0;
|
|||
|
//host->wbytes = 0;
|
|||
|
//host->wcount = 0;
|
|||
|
}
|
|||
|
} else if((mrq->data->flags) & MMC_DATA_READ) {
|
|||
|
host->rbytes += mrq->data->blksz * mrq->data->blocks;
|
|||
|
host->rtimes_us += time_use_us;
|
|||
|
host->rcount++;
|
|||
|
if( host->rcount &&!(host->rcount % SD_PERF_TRACE_COUNT)) {
|
|||
|
printf("Stats Total read: byte %lld, time us %lu, count %lld, %lldKB\n",\
|
|||
|
host->rbytes, host->rtimes_us, host->rcount,\
|
|||
|
__mci_get_rate(host->rbytes, host->rtimes_us)/1024);
|
|||
|
//host->rtimes_us = 0;
|
|||
|
//host->rbytes = 0;
|
|||
|
//host->rcount = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
int32_t do_rom_HAL_SDC_Request(struct mmc_host *host, struct mmc_request *mrq)
|
|||
|
{
|
|||
|
int32_t ret = 0;
|
|||
|
struct mmc_command *cmd = mrq->cmd;
|
|||
|
struct mmc_data *data = mrq->data;
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
uint32_t sdc_use_dma = host->dma_use;
|
|||
|
#else
|
|||
|
uint32_t sdc_use_dma = 0;
|
|||
|
#endif
|
|||
|
|
|||
|
if (!host->present) {
|
|||
|
SDC_LOGW("sdc:%p no medium present\n", host);
|
|||
|
SDC_SemRest((&host->lock));
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_SD_PM
|
|||
|
if (host->suspend) {
|
|||
|
SDC_LOGE("sdc:%p has suspended!\n", host);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
#endif
|
|||
|
#ifdef SD_PERF_TRACE_ON
|
|||
|
__mci_start_data_time_stats(host, mrq);
|
|||
|
#endif
|
|||
|
__mci_check_busy_over(host);
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_GCTRL, SDXC_HWReset);
|
|||
|
|
|||
|
SDC_MutexLock(&host->thread_lock, SDC_THREAD_TIMEOUT);
|
|||
|
|
|||
|
/* disable debounce */
|
|||
|
__mci_debounce_onoff(host, 0);
|
|||
|
|
|||
|
host->mrq = mrq;
|
|||
|
|
|||
|
if (data) {
|
|||
|
uint32_t i;
|
|||
|
uint32_t byte_cnt = 0;
|
|||
|
struct scatterlist *sg = data->sg;
|
|||
|
uint32_t sg_len = data->sg_len;
|
|||
|
unsigned long addr = 0;
|
|||
|
uint32_t len = 0;
|
|||
|
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
addr = HAL_PT_TO_U(sg[i].buffer);
|
|||
|
len = sg[i].len;
|
|||
|
byte_cnt += sg[i].len;
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
if ((addr & 0x03)) {
|
|||
|
sdc_use_dma = 0;
|
|||
|
SDC_LOGW("unalign addr %lx, len %ld wr %lx\n", HAL_PR_SZ_L(addr), HAL_PR_SZ_L(len), HAL_PR_SZ_L(data->flags & MMC_DATA_WRITE));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if((addr & (OS_CACHE_ALIGN_BYTES - 1))\
|
|||
|
|| (len & (OS_CACHE_ALIGN_BYTES - 1))) {
|
|||
|
SDC_LOGD("unalign addr %lx, len %ld wr %lx\n", HAL_PR_SZ_L(addr), HAL_PR_SZ_L(len), HAL_PR_SZ_L(data->flags & MMC_DATA_WRITE));
|
|||
|
}
|
|||
|
|
|||
|
HAL_FlushDcacheRegion((unsigned long)sg[i].buffer, HAL_ALIGN(sg[i].len, OS_CACHE_ALIGN_BYTES));
|
|||
|
#endif
|
|||
|
}
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
if (byte_cnt <= SDC_MAX_CPU_TRANS_LEN) {
|
|||
|
sdc_use_dma = 0;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (byte_cnt != (data->blksz * data->blocks)) {
|
|||
|
SDC_LOGE("sg data len %ld not equel data's len %ld\n", HAL_PR_SZ_L(byte_cnt), HAL_PR_SZ_L(data->blksz * data->blocks));
|
|||
|
}
|
|||
|
|
|||
|
mci_writel(data->blksz, host, SDXC_REG_BLKSZ);
|
|||
|
mci_writel(byte_cnt, host, SDXC_REG_BCNTR);
|
|||
|
|
|||
|
if (sdc_use_dma && byte_cnt > SDC_MAX_CPU_TRANS_LEN) { /* transfer by idma */
|
|||
|
__mci_sel_access_mode(host, SDXC_ACCESS_BY_DMA);
|
|||
|
host->dma_hdle = __mci_prepare_dma(host, data);
|
|||
|
if (NULL == host->dma_hdle) {
|
|||
|
SDC_LOGW("SDC prepare DMA failed\n");
|
|||
|
__mci_sel_access_mode(host, SDXC_ACCESS_BY_AHB);
|
|||
|
}
|
|||
|
} else {
|
|||
|
/* switch data bus to ahb */
|
|||
|
__mci_sel_access_mode(host, SDXC_ACCESS_BY_AHB);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
__mci_send_cmd(host, cmd);
|
|||
|
|
|||
|
#if defined(CONFIG_SOC_SUN20IW1) && defined(CONFIG_OS_MELIS)
|
|||
|
struct timespec64 time0 ={0}, time1={0};
|
|||
|
|
|||
|
do_gettimeofday(&time0);
|
|||
|
ret = SDC_SemPend(&host->lock, SDC_DMA_TIMEOUT);
|
|||
|
do_gettimeofday(&time1);
|
|||
|
|
|||
|
if ((ret != HAL_OK && host->present) && \
|
|||
|
(((time1.tv_sec*1000+time1.tv_nsec/1000000) - (time0.tv_sec*1000+time0.tv_nsec/1000000)) < SDC_DMA_TIMEOUT))
|
|||
|
{
|
|||
|
//增加这里的原因是防止读写sdmmc的task被esKRNL_TimeDlyResume,出现这种情况,会导致信号量提前退出
|
|||
|
//如果是正常的timeout则不会跑到这里面
|
|||
|
SDC_LOGE("===SDC_SemPend abnormal===\n");
|
|||
|
ret = SDC_SemPend(&host->lock, SDC_DMA_TIMEOUT);
|
|||
|
}
|
|||
|
#else
|
|||
|
ret = SDC_SemPend(&host->lock, SDC_DMA_TIMEOUT);
|
|||
|
#endif
|
|||
|
|
|||
|
if (ret != HAL_OK && host->present){
|
|||
|
uint32_t sg_len = data->sg_len;
|
|||
|
uint32_t i;
|
|||
|
uint32_t rval = 0;
|
|||
|
|
|||
|
SDC_LOGE("sdc cmd:%ld, wait command done timeout !!\n",
|
|||
|
HAL_PR_SZ_L(host->smc_cmd & SDXC_CMD_OPCODE));
|
|||
|
host->debug_mask |= ROM_DUMP_MASK | ROM_ERR_MASK;
|
|||
|
#if 1
|
|||
|
__mci_force_dump_host_info(host);
|
|||
|
if (data) {
|
|||
|
SDC_LOGE("dump data blksz %ld,blocks %ld,flags %lx\n", HAL_PR_SZ_L(data->blksz), HAL_PR_SZ_L(data->blocks), HAL_PR_SZ_L(data->flags));
|
|||
|
}
|
|||
|
#endif
|
|||
|
SDC_LOGE("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
struct scatterlist *sg = data->sg;
|
|||
|
uint32_t *buf_temp = (uint32_t *)sg[i].buffer;
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
if (HAL_PT_TO_U(sg[i].buffer) & 0x03) {
|
|||
|
sdc_use_dma = 0;
|
|||
|
SDC_LOGW("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
break;
|
|||
|
}
|
|||
|
SDC_LOGE("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
HAL_InvalidDcacheRegion((unsigned long )(sg[i].buffer), HAL_ALIGN(sg[i].len, OS_CACHE_ALIGN_BYTES));
|
|||
|
SDC_LOGE("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
SDC_LOGE("buf addr %lx buffer0 %x buffer1 %x\n", HAL_PR_SZ_L(sg[i].buffer), (unsigned int)buf_temp[0],(unsigned int) buf_temp[1]);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
SDC_LOGE("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
mci_writel(0xdeb, host, SDXC_REG_TMOUT);
|
|||
|
SDC_LOGE("*force wr smc timeout reg %x*\n",(unsigned int)mci_readl(host, SDXC_REG_TMOUT));
|
|||
|
#if 1
|
|||
|
SDC_LOGE("*force dump sram*\n");
|
|||
|
rval = readl(0x03000000+0x0048);
|
|||
|
rval |= 1 << 4;
|
|||
|
writel(rval, 0x03000000+0x0048);
|
|||
|
sdc_hex_dump_word((void *)SMC1_BASE ,0x100);
|
|||
|
#endif
|
|||
|
SDC_LOGE("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
|
|||
|
SDC_BUG_ON(1);
|
|||
|
sys_abort();
|
|||
|
/*sdc_hex_dump_word((void *)0x4002000 ,0x200);*/
|
|||
|
host->debug_mask &= ~ROM_DUMP_MASK;
|
|||
|
goto out;
|
|||
|
}
|
|||
|
|
|||
|
ret = __mci_request_done(host);
|
|||
|
if (ret) {
|
|||
|
goto out;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
out:
|
|||
|
/* enable debounce */
|
|||
|
__mci_debounce_onoff(host, 1);
|
|||
|
|
|||
|
if(data && (data->flags & MMC_DATA_READ )){
|
|||
|
uint32_t i;
|
|||
|
uint32_t byte_cnt = 0;
|
|||
|
struct scatterlist *sg = data->sg;
|
|||
|
uint32_t sg_len = data->sg_len;
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
byte_cnt += sg[i].len;
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
if (HAL_PT_TO_U(sg[i].buffer) & 0x03) {
|
|||
|
sdc_use_dma = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
HAL_InvalidDcacheRegion((unsigned long)(sg[i].buffer), HAL_ALIGN(sg[i].len, OS_CACHE_ALIGN_BYTES));
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SDC_MutexUnlock(&host->thread_lock);
|
|||
|
|
|||
|
#ifdef SD_PERF_TRACE_ON
|
|||
|
__mci_end_data_time_stats(host, mrq);
|
|||
|
#endif
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
int32_t rom_HAL_SDC_Request(struct mmc_host *host, struct mmc_request *mrq)
|
|||
|
{
|
|||
|
int32_t ret = 0;
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
uint32_t sdc_use_dma_buf = 0;
|
|||
|
struct scatterlist sg_dma = {0};
|
|||
|
struct scatterlist *sg = NULL;
|
|||
|
uint32_t sg_len = 0;
|
|||
|
struct mmc_data *data;
|
|||
|
uint32_t i = 0;
|
|||
|
uint32_t byte_cnt = 0;
|
|||
|
unsigned long addr = 0;
|
|||
|
uint32_t len = 0;
|
|||
|
|
|||
|
|
|||
|
if (mrq->data) {
|
|||
|
data = mrq->data;
|
|||
|
sg_len = data->sg_len;
|
|||
|
sg = data->sg;
|
|||
|
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
addr = HAL_PT_TO_U(sg[i].buffer);
|
|||
|
len = sg[i].len;
|
|||
|
byte_cnt += sg[i].len;
|
|||
|
if ((addr & 0x03)\
|
|||
|
|| (addr & (OS_CACHE_ALIGN_BYTES - 1))
|
|||
|
|| (len & (OS_CACHE_ALIGN_BYTES - 1))) {
|
|||
|
sdc_use_dma_buf = 1;
|
|||
|
SDC_LOGD("try to use dma debounce buff, addr %lx, len %ld\n", \
|
|||
|
HAL_PR_SZ_L(addr), HAL_PR_SZ_L(byte_cnt));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (sdc_use_dma_buf) {
|
|||
|
if (byte_cnt > SDC_ALIGN_DMA_BUF_SIZE) {
|
|||
|
SDC_LOGE("byte count %ld over dma debounce buf size %d\n", \
|
|||
|
HAL_PR_SZ_L(byte_cnt), SDC_ALIGN_DMA_BUF_SIZE);
|
|||
|
return -1;
|
|||
|
} else if (byte_cnt < SDC_MAX_CPU_TRANS_LEN) {
|
|||
|
SDC_LOGD("byte cnt %ld is too small not use dma align buf\n", \
|
|||
|
HAL_PR_SZ_L(byte_cnt));
|
|||
|
sdc_use_dma_buf = 0;
|
|||
|
} else {
|
|||
|
uint32_t total_len = 0;
|
|||
|
if (data->flags & MMC_DATA_WRITE) {
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
addr = HAL_PT_TO_U(sg[i].buffer);
|
|||
|
len = sg[i].len;
|
|||
|
HAL_Memcpy((char *)(host->align_dma_buf + total_len), (char *)addr, len);
|
|||
|
total_len += len;
|
|||
|
}
|
|||
|
}
|
|||
|
sg_dma.buffer = host->align_dma_buf;
|
|||
|
sg_dma.len = byte_cnt;
|
|||
|
data->sg = &sg_dma;
|
|||
|
data->sg_len = 1;
|
|||
|
SDC_LOGD("use dma debounce buff addr %lx, len %d, align_dma_buf %lx\n", \
|
|||
|
HAL_PT_TO_U(sg[0].buffer),\
|
|||
|
(unsigned int)byte_cnt,\
|
|||
|
HAL_PT_TO_U(host->align_dma_buf));
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
ret = do_rom_HAL_SDC_Request(host, mrq);
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_DMA_USED
|
|||
|
if(!ret && data && sdc_use_dma_buf) {
|
|||
|
if (data->flags & MMC_DATA_READ) {
|
|||
|
uint32_t total_len = 0;
|
|||
|
for (i = 0; i < sg_len; i++) {
|
|||
|
addr = HAL_PT_TO_U(sg[i].buffer);
|
|||
|
len = sg[i].len;
|
|||
|
HAL_Memcpy((char *)addr, (char *)(host->align_dma_buf + total_len), len);
|
|||
|
total_len += len;
|
|||
|
}
|
|||
|
SDC_LOGD("copy back to dst buffer%ld\n", HAL_PR_SZ_L(byte_cnt));
|
|||
|
}
|
|||
|
data->sg = sg;
|
|||
|
data->sg_len = sg_len;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_EXCLUSIVE_HOST
|
|||
|
/**
|
|||
|
* HAL_SDC_Claim_Host - exclusively claim a host
|
|||
|
* @host: mmc host to claim
|
|||
|
*
|
|||
|
* Claim a host for a set of operations.
|
|||
|
*/
|
|||
|
int32_t HAL_SDC_Claim_Host(struct mmc_host *host)
|
|||
|
{
|
|||
|
return (SDC_SemPend(&host->exclusive_lock, OS_WAIT_FOREVER) == OS_OK ? 0 : -1);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* HAL_SDC_Release_Host - release a host
|
|||
|
* @host: mmc host to release
|
|||
|
*
|
|||
|
* Release a MMC host, allowing others to claim the host
|
|||
|
* for their operations.
|
|||
|
*/
|
|||
|
void HAL_SDC_Release_Host(struct mmc_host *host)
|
|||
|
{
|
|||
|
SDC_SemPost(&host->exclusive_lock);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_READONLY_USED
|
|||
|
int32_t HAL_SDC_Get_ReadOnly(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t wp_val;
|
|||
|
GPIO_PinMuxParam *ro_gpio = &host->ro_gpio;
|
|||
|
|
|||
|
wp_val = (GPIO_PIN_HIGH == HAL_GPIO_ReadPin(ro_gpio->port, ro_gpio->pin)) ? 1 : 0;
|
|||
|
SDC_LOGN("sdc fetch card wp pin status: %u\n", (unsigned int)wp_val);
|
|||
|
|
|||
|
if (!wp_val) {
|
|||
|
host->read_only = 0;
|
|||
|
return 0;
|
|||
|
} else {
|
|||
|
SDC_LOGN("Card is write-protected\n");
|
|||
|
host->read_only = 1;
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
|
|||
|
static irqreturn_t __mci_cd_irq(int unuse, void *arg);
|
|||
|
static void __mci_enable_cd_pin_irq(struct mmc_host *host)
|
|||
|
{
|
|||
|
//SDC_LOGD("Not implement %s,%d\n", __FUNCTION__,__LINE__);
|
|||
|
//SDC_ENABLE_IRQ(host->cd_irq);
|
|||
|
hal_gpio_irq_enable(host->cd_irq);
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_disable_cd_pin_irq(struct mmc_host *host)
|
|||
|
{
|
|||
|
// HAL_GPIO_DisableIRQ(host->cd_port, host->cd_pin);
|
|||
|
// SDC_LOGE("Not implement %s,%d\n", __FUNCTION__,__LINE__);
|
|||
|
|
|||
|
//SDC_DISABLE_IRQ(host->cd_irq);
|
|||
|
hal_gpio_irq_disable(host->cd_irq);
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_voltage_stable_det(void *arg)
|
|||
|
{
|
|||
|
struct mmc_host *host = (struct mmc_host *)arg;
|
|||
|
|
|||
|
if (!host->present || host->wait_voltage_stable || !host->cd_delay) {
|
|||
|
host->wait_voltage_stable = 0;
|
|||
|
__mci_enable_cd_pin_irq(host);
|
|||
|
host->param.cd_cb(host->present);
|
|||
|
} else {
|
|||
|
SDC_ModTimer(&host->cd_timer, host->cd_delay);
|
|||
|
host->wait_voltage_stable = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_cd_timer(void *arg)
|
|||
|
{
|
|||
|
struct mmc_host *host = (struct mmc_host *)arg;
|
|||
|
uint32_t gpio_val = 0;
|
|||
|
uint32_t present;
|
|||
|
gpio_val = (host->cd_pin_present_val == HAL_GPIO_ReadPin(host->cd_gpio_pin, &gpio_val)) ? 1 : 0;
|
|||
|
//SDC_LOGE("Not implement %s,%d\n", __FUNCTION__,__LINE__);
|
|||
|
if (gpio_val) {
|
|||
|
present = 1;
|
|||
|
} else {
|
|||
|
present = 0;
|
|||
|
}
|
|||
|
|
|||
|
SDC_LOGD("cd %lu, host present %lu, cur present %lu\n",
|
|||
|
HAL_PR_SZ_L(gpio_val), HAL_PR_SZ_L(host->present), HAL_PR_SZ_L(present));
|
|||
|
if (host->present ^ present || host->wait_voltage_stable) {
|
|||
|
SDC_LOGD("sdc detect change, present %lu\n", HAL_PR_SZ_L(present));
|
|||
|
host->present = present;
|
|||
|
__mci_voltage_stable_det(host);
|
|||
|
}
|
|||
|
else {
|
|||
|
__mci_enable_cd_pin_irq(host);
|
|||
|
}
|
|||
|
__sdc_init_timeout_flags = 1;
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_dat3_det(void *arg)
|
|||
|
{
|
|||
|
struct mmc_host *host = (struct mmc_host *)arg;
|
|||
|
|
|||
|
SDC_LOGD("***dat3 det***\n");
|
|||
|
|
|||
|
__mci_voltage_stable_det(host);
|
|||
|
}
|
|||
|
|
|||
|
static irqreturn_t __mci_cd_irq(int unuse, void *arg)
|
|||
|
{
|
|||
|
struct mmc_host *host = (struct mmc_host *)arg;
|
|||
|
|
|||
|
SDC_LOGD("***in cd***\n");
|
|||
|
if (!SDC_TimerIsActive(&host->cd_timer) || host->wait_voltage_stable) {
|
|||
|
host->wait_voltage_stable = 0;
|
|||
|
SDC_ModTimer(&host->cd_timer, 10);
|
|||
|
__mci_disable_cd_pin_irq(host);
|
|||
|
}
|
|||
|
return (irqreturn_t)NULL;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
int32_t rom_HAL_SDC_PowerOn(struct mmc_host *host)
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
if (!host) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
SDC_LOGD("MMC Driver init host\n");
|
|||
|
|
|||
|
__mci_restore_io(host);
|
|||
|
__mci_clk_prepare_enable(host);
|
|||
|
|
|||
|
|
|||
|
/* delay 1ms ? */
|
|||
|
__mci_update_clock(host, 400000);
|
|||
|
host->clk = 400000;
|
|||
|
|
|||
|
/* reset controller*/
|
|||
|
rval = mci_readl(host, SDXC_REG_GCTRL)|SDXC_HWReset|SDXC_INTEnb|
|
|||
|
SDXC_AccessDoneDirect;
|
|||
|
mci_writel(rval, host, SDXC_REG_GCTRL);
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_GCTRL, SDXC_HWReset);
|
|||
|
SDC_LOGD("%s,%d\n",__FUNCTION__,__LINE__);
|
|||
|
|
|||
|
mci_writel(0xffffffff, host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
mci_writel(SDXC_CardInsert|SDXC_CardRemove|host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
} else
|
|||
|
#endif
|
|||
|
{
|
|||
|
mci_writel(host->sdio_irq_mask, host, SDXC_REG_IMASK);
|
|||
|
}
|
|||
|
|
|||
|
#define SDMC_DATA_TIMEOUT 0x0ffffffU
|
|||
|
#define SDMC_RESP_TIMEOUT 0xffU
|
|||
|
/* Set Data & Response Timeout Value */
|
|||
|
mci_writel((SDMC_DATA_TIMEOUT<<8)|SDMC_RESP_TIMEOUT, host, SDXC_REG_TMOUT);
|
|||
|
#undef SDMC_RESP_TIMEOUT
|
|||
|
#undef SDMC_DATA_TIMEOUT
|
|||
|
|
|||
|
HAL_SDC_Set_BusWidth(host, MMC_BUS_WIDTH_1);
|
|||
|
|
|||
|
#ifdef SDC_DEBUG
|
|||
|
mci_writel(0xdeb, host, SDXC_REG_DBGC);
|
|||
|
mci_writel(0xceaa0000, host, SDXC_REG_FUNS);
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3){
|
|||
|
rval |= SDXC_DebounceEnb;
|
|||
|
}
|
|||
|
mci_writel(rval, host, SDXC_REG_GCTRL);
|
|||
|
#endif
|
|||
|
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC_ENABLE_IRQ(SDC0_IRQn);
|
|||
|
}
|
|||
|
#if SDC1_SUPPORT
|
|||
|
else if (host->sdc_id == 1)
|
|||
|
SDC_ENABLE_IRQ(SDC1_IRQn);
|
|||
|
#endif
|
|||
|
|
|||
|
host->power_on = 1;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int32_t rom_HAL_SDC_PowerOff(struct mmc_host *host)
|
|||
|
{
|
|||
|
if (!host) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode != CARD_DETECT_BY_D3)
|
|||
|
#endif
|
|||
|
{
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
if (host->sdc_id == 0)
|
|||
|
SDC_DISABLE_IRQ(SDC0_IRQn);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
else if (host->sdc_id == 1)
|
|||
|
SDC_DISABLE_IRQ(SDC1_IRQn);
|
|||
|
#endif
|
|||
|
|
|||
|
rval = mci_readl(host, SDXC_REG_GCTRL) | SDXC_HWReset;
|
|||
|
mci_writel(rval, host, SDXC_REG_GCTRL);
|
|||
|
__mci_check_bit_clear(host, SDXC_REG_GCTRL, SDXC_HWReset);
|
|||
|
rval = mci_readl(host, SDXC_REG_MISTA);
|
|||
|
mci_writel(rval & (~SDXC_SDIOInt), host, SDXC_REG_RINTR);
|
|||
|
|
|||
|
if (host->sdc_id == 0)
|
|||
|
SDC_CLEAR_IRQPINGD(SDC0_IRQn);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
else if (host->sdc_id == 1)
|
|||
|
SDC_CLEAR_IRQPINGD(SDC1_IRQn);
|
|||
|
#endif
|
|||
|
|
|||
|
__mci_clk_disable_unprepare(host);
|
|||
|
|
|||
|
__mci_hold_io(host);
|
|||
|
host->power_on = 0;
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_SD_PM
|
|||
|
|
|||
|
static void __mci_regs_save(struct mmc_host *host)
|
|||
|
{
|
|||
|
struct __mci_ctrl_regs *bak_regs = &host->regs_back;
|
|||
|
|
|||
|
bak_regs->gctrl = mci_readl(host, SDXC_REG_GCTRL);
|
|||
|
bak_regs->clkc = mci_readl(host, SDXC_REG_CLKCR);
|
|||
|
bak_regs->timeout = mci_readl(host, SDXC_REG_TMOUT);
|
|||
|
bak_regs->buswid = mci_readl(host, SDXC_REG_WIDTH);
|
|||
|
bak_regs->waterlvl = mci_readl(host, SDXC_REG_FTRGL);
|
|||
|
bak_regs->funcsel = mci_readl(host, SDXC_REG_FUNS);
|
|||
|
bak_regs->idmacc = mci_readl(host, SDXC_REG_DMAC);
|
|||
|
}
|
|||
|
|
|||
|
static void __mci_regs_restore(struct mmc_host *host)
|
|||
|
{
|
|||
|
struct __mci_ctrl_regs* bak_regs = &host->regs_back;
|
|||
|
|
|||
|
mci_writel(bak_regs->gctrl, host, SDXC_REG_GCTRL);
|
|||
|
mci_writel(bak_regs->clkc, host, SDXC_REG_CLKCR);
|
|||
|
mci_writel(bak_regs->timeout, host, SDXC_REG_TMOUT);
|
|||
|
mci_writel(bak_regs->buswid, host, SDXC_REG_WIDTH);
|
|||
|
mci_writel(bak_regs->waterlvl, host, SDXC_REG_FTRGL);
|
|||
|
mci_writel(bak_regs->funcsel, host, SDXC_REG_FUNS);
|
|||
|
#ifdef SDC_DEBUG
|
|||
|
mci_writel(0xdeb, host, SDXC_REG_DBGC);
|
|||
|
mci_writel(0xceaa0000, host, SDXC_REG_FUNS);
|
|||
|
#endif
|
|||
|
mci_writel(bak_regs->idmacc, host, SDXC_REG_DMAC);
|
|||
|
}
|
|||
|
|
|||
|
static int __mci_suspend(struct soc_device *dev, enum suspend_state_t state)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
struct mmc_host *host = dev->platform_data;
|
|||
|
uint32_t _timeout = HAL_Ticks() + HAL_MSecsToTicks(SDC_DMA_TIMEOUT) + 1;
|
|||
|
|
|||
|
if (host->bus_ops && host->bus_ops->suspend)
|
|||
|
ret = host->bus_ops->suspend(host);
|
|||
|
if (ret) {
|
|||
|
if (host->bus_ops->resume)
|
|||
|
host->bus_ops->resume(host);
|
|||
|
SDC_LOGE("%s bus id:%d faild\n", __func__, host->sdc_id);
|
|||
|
goto err;
|
|||
|
}
|
|||
|
|
|||
|
host->suspend = 1;
|
|||
|
while ((host->wait != SDC_WAIT_NONE) && HAL_TimeBefore(HAL_Ticks(), _timeout)) {
|
|||
|
}
|
|||
|
if (HAL_TimeAfterEqual(HAL_Ticks(), _timeout) && (host->wait != SDC_WAIT_NONE)) {
|
|||
|
ret = -1;
|
|||
|
host->suspend = 0;
|
|||
|
if (host->bus_ops && host->bus_ops->resume)
|
|||
|
ret = host->bus_ops->resume(host);
|
|||
|
SDC_LOGE("%s id:%d faild\n", __func__, host->sdc_id);
|
|||
|
goto err;
|
|||
|
}
|
|||
|
__mci_regs_save(host);
|
|||
|
|
|||
|
/* gate clock for lower power */
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_DisableMClock();
|
|||
|
SDC0_CCM_BusForceReset();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_DisableMClock();
|
|||
|
SDC1_CCM_BusForceReset();
|
|||
|
#endif
|
|||
|
}
|
|||
|
__mci_clk_disable_unprepare(host);
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
__mci_exit_host(host);
|
|||
|
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_DisableMClock();
|
|||
|
SDC0_CCM_BusForceReset();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_DisableMClock();
|
|||
|
SDC1_CCM_BusForceReset();
|
|||
|
#endif
|
|||
|
}
|
|||
|
__mci_hold_io(host);
|
|||
|
|
|||
|
SDC_LOGD("sdc card_power_off ok\n");
|
|||
|
|
|||
|
//__mci_set_vddio(host, SDC_WOLTAGE_OFF);
|
|||
|
//usleep_range(1000, 1500);
|
|||
|
host->power_on = 0;
|
|||
|
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
SDC_LOGD("%s id:%d ok\n", __func__, host->sdc_id);
|
|||
|
|
|||
|
err:
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
static int __mci_resume(struct soc_device *dev, enum suspend_state_t state)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
struct mmc_host *host = dev->platform_data;
|
|||
|
uint32_t clk = host->clk;
|
|||
|
|
|||
|
__mci_restore_io(host);
|
|||
|
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_CCM_BusForceReset();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_CCM_BusForceReset();
|
|||
|
#endif
|
|||
|
}
|
|||
|
__mci_clk_disable_unprepare(host);
|
|||
|
mmc_udelay(35);
|
|||
|
|
|||
|
/* enable clock for resotre */
|
|||
|
__mci_clk_prepare_enable(host);
|
|||
|
mmc_udelay(50);
|
|||
|
__mci_update_clock(host, clk);
|
|||
|
mmc_udelay(100);
|
|||
|
|
|||
|
__mci_regs_restore(host);
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
#else
|
|||
|
mci_writel(SDXC_CardInsert, host, SDXC_REG_RINTR);
|
|||
|
#endif
|
|||
|
__mci_update_clk(host);
|
|||
|
|
|||
|
/* register IRQ */
|
|||
|
if (host->sdc_id == 0)
|
|||
|
SDC_CONFIG_IRQ(SDC0_IRQn, &SDC0_IRQHandler, NVIC_PERIPH_PRIO_DEFAULT);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
else if (host->sdc_id == 1)
|
|||
|
SDC_CONFIG_IRQ(SDC1_IRQn, &SDC1_IRQHandler, NVIC_PERIPH_PRIO_DEFAULT);
|
|||
|
#endif
|
|||
|
mmc_udelay(100);
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_GPIO_IRQ)
|
|||
|
__mci_cd_timer(host);
|
|||
|
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
uint32_t rval = 0;
|
|||
|
|
|||
|
//__mci_set_vddio(host, host->regulator_voltage);
|
|||
|
//usleep_range(1000, 1500);
|
|||
|
host->power_on = 1;
|
|||
|
|
|||
|
__mci_restore_io(host);
|
|||
|
__mci_clk_prepare_enable(host);
|
|||
|
|
|||
|
mmc_mdelay(1);
|
|||
|
rval = mci_readl(host, SDXC_REG_RINTR);
|
|||
|
SDC_LOGD(">> REG_RINTR=0x%x\n", (unsigned int)rval);
|
|||
|
(void)rval;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
host->suspend = 0;
|
|||
|
|
|||
|
if (host->bus_ops && host->bus_ops->resume)
|
|||
|
ret = host->bus_ops->resume(host);
|
|||
|
|
|||
|
SDC_LOGD("%s id:%d ok\n", __func__, host->sdc_id);
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
static const struct soc_device_driver sdc_drv = {
|
|||
|
.name = "sdc",
|
|||
|
.suspend = __mci_suspend,
|
|||
|
.resume = __mci_resume,
|
|||
|
};
|
|||
|
|
|||
|
static struct soc_device sdc_dev[SDC_NUM] = {
|
|||
|
{ .name = "sdc0", .driver = &sdc_drv, },
|
|||
|
{ .name = "sdc1", .driver = &sdc_drv, }
|
|||
|
};
|
|||
|
|
|||
|
#define SDC_DEV(id) (&sdc_dev[id])
|
|||
|
|
|||
|
#endif /* CONFIG_SD_PM */
|
|||
|
|
|||
|
int hal_sdc_init_timeout(void)
|
|||
|
{
|
|||
|
return __sdc_init_timeout_flags;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief Initializes the SDC peripheral.
|
|||
|
* @param sdc_id:
|
|||
|
* @arg sdc_id->SDC ID.
|
|||
|
* @param param:
|
|||
|
* @arg param->[in] The configuration information.
|
|||
|
* @retval SDC handler.
|
|||
|
*/
|
|||
|
struct mmc_host *hal_sdc_init(struct mmc_host *host)
|
|||
|
{
|
|||
|
__sdc_init_timeout_flags = 0;
|
|||
|
|
|||
|
#ifdef __CONFIG_ARCH_APP_CORE
|
|||
|
const HAL_SDCGPIOCfg *sd_gpio_cfg = NULL;
|
|||
|
const HAL_SDCGPIOCfg sd_gpio_cfg_entry;
|
|||
|
sd_gpio_cfg = &sd_gpio_cfg_entry;
|
|||
|
#endif
|
|||
|
int ret = 0;
|
|||
|
|
|||
|
if (host->State != SDC_STATE_RESET) {
|
|||
|
SDC_LOGW("%s----%d reinit sdc!\n", __func__,__LINE__);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
host->reg_base = (volatile void *)SMC0_BASE;
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
host->reg_base = (volatile void *)SMC1_BASE;
|
|||
|
#endif
|
|||
|
} else {
|
|||
|
SDC_LOGW("%s unsupport sdc id:%d!\n", __func__, host->sdc_id);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef __CONFIG_PLATFORM_FPGA
|
|||
|
host->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY |
|
|||
|
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50;
|
|||
|
if (HAL_GetDevClock() > 25000000) {
|
|||
|
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
|||
|
}
|
|||
|
#else
|
|||
|
host->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY | \
|
|||
|
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50|MMC_CAP_SDIO_IRQ;
|
|||
|
if (host->param.low_speed)
|
|||
|
host->caps &= ~(MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED);
|
|||
|
#endif
|
|||
|
#ifdef CONFIG_SD_PM
|
|||
|
host->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef __CONFIG_ARCH_APP_CORE
|
|||
|
#ifdef NUSE_STANDARD_INTERFACE
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
#ifndef SDC_FPGA
|
|||
|
sdmmc_pinctrl_init(host);
|
|||
|
#endif
|
|||
|
host->caps |= MMC_CAP_4_BIT_DATA;
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
sdmmc_pinctrl_init(host);
|
|||
|
#if 0
|
|||
|
SDC1_SET_GPIO_PULL();
|
|||
|
SDC1_SET_GPIO_DRV();
|
|||
|
SDC1_SET_GPIO_MUX();
|
|||
|
#endif
|
|||
|
host->caps &= ~MMC_CAP_4_BIT_DATA;
|
|||
|
}
|
|||
|
#else
|
|||
|
HAL_BoardIoctl(HAL_BIR_GET_CFG, HAL_MKDEV(HAL_DEV_MAJOR_SDC, host->sdc_id),
|
|||
|
(uint32_t)&sd_gpio_cfg);
|
|||
|
/*test gpio_detect by gpio irq*/
|
|||
|
sd_gpio_cfg->has_detect_gpio = 1;
|
|||
|
if (!sd_gpio_cfg)
|
|||
|
host->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
|
|||
|
else if (sd_gpio_cfg->data_bits == 8)
|
|||
|
host->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
|
|||
|
else if (sd_gpio_cfg->data_bits == 4)
|
|||
|
host->caps |= MMC_CAP_4_BIT_DATA;
|
|||
|
#endif
|
|||
|
#else
|
|||
|
host->caps |= MMC_CAP_4_BIT_DATA;
|
|||
|
#endif
|
|||
|
|
|||
|
__mci_restore_io(host);
|
|||
|
host->clk = 400000;
|
|||
|
|
|||
|
/* register IRQ */
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
ret = SDC_REQUEST_IRQ(SDC0_IRQn, SDC0_IRQHandler, host);
|
|||
|
if (ret != 0) {
|
|||
|
SDC_LOGE("%s,%d err:%d\n",__func__, __LINE__, ret);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
SDC_SetPriority(SDC0_IRQn, NVIC_PERIPH_PRIO_DEFAULT);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
ret = SDC_REQUEST_IRQ(SDC1_IRQn, SDC1_IRQHandler, host);
|
|||
|
if (ret != 0) {
|
|||
|
SDC_LOGE("%s,%d err:%d\n",__func__, __LINE__, ret);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
SDC_SetPriority(SDC1_IRQn, NVIC_PERIPH_PRIO_DEFAULT);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_ALWAYS_PRESENT) {
|
|||
|
host->present = 1;
|
|||
|
} else if (host->param.cd_mode == CARD_DETECT_BY_GPIO_IRQ) {
|
|||
|
#if 0
|
|||
|
if (!sd_gpio_cfg || (!sd_gpio_cfg->has_detect_gpio)) {
|
|||
|
SDC_LOGE("%s,%d cd_mode:%ld with no detect_gpio!\n",
|
|||
|
__func__, __LINE__, host->param.cd_mode);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//host->cd_port = sd_gpio_cfg->detect_port;
|
|||
|
//host->cd_pin = sd_gpio_cfg->detect_pin;
|
|||
|
//host->cd_pin_present_val = sd_gpio_cfg->detect_pin_present_val;
|
|||
|
#ifndef CONFIG_DRIVERS_SDC_CDPIN_PRESENT_VAL
|
|||
|
#define CONFIG_DRIVERS_SDC_CDPIN_PRESENT_VAL 0
|
|||
|
#endif
|
|||
|
host->cd_pin_present_val = CONFIG_DRIVERS_SDC_CDPIN_PRESENT_VAL;
|
|||
|
//HAL_BoardIoctl(HAL_BIR_PINMUX_INIT, HAL_MKDEV(HAL_DEV_MAJOR_SDC,
|
|||
|
// host->sdc_id), SDCGPIO_DET);
|
|||
|
SDC_LOGN("%s,%d no imp\n",__func__, __LINE__);
|
|||
|
|
|||
|
//host->cd_delay = sd_gpio_cfg->detect_delay;
|
|||
|
host->cd_delay = 10; /* short delay */
|
|||
|
SDC_InitTimer(&host->cd_timer, &__mci_cd_timer, host, 10);
|
|||
|
|
|||
|
//HAL_GPIO_SetDebounce(&Irq_param, (2U << 4) | 1); /* set debounce clock */
|
|||
|
__mci_enable_cd_pin_irq(host);
|
|||
|
SDC_LOGN("%s,%d no imp\n",__func__, __LINE__);
|
|||
|
host->present = (host->cd_pin_present_val ==
|
|||
|
HAL_GPIO_ReadPin(host->cd_gpio_pin, &host->present)) ? 1 : 0;
|
|||
|
//host->present = 1;
|
|||
|
|
|||
|
} else if (host->param.cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
uint32_t rval;
|
|||
|
|
|||
|
//host->cd_delay = sd_gpio_cfg->detect_delay;
|
|||
|
host->cd_delay = 100;
|
|||
|
|
|||
|
__mci_clk_prepare_enable(host);
|
|||
|
mmc_mdelay(1);
|
|||
|
host->present = 1;
|
|||
|
rval = mci_readl(host, SDXC_REG_RINTR);
|
|||
|
SDC_LOGD("sdc +> REG_RINTR=0x%x\n", (unsigned int)rval);
|
|||
|
if ((rval & SDXC_CardRemove)) {
|
|||
|
SDC_LOGD("sdc data[3] detect Card Remove\n");
|
|||
|
host->present = 0;
|
|||
|
}
|
|||
|
SDC_InitTimer(&host->cd_timer, &__mci_dat3_det, host, 300);
|
|||
|
}
|
|||
|
#else
|
|||
|
host->present = 1;
|
|||
|
#endif
|
|||
|
host->align_dma_buf = HAL_MallocAlign(SDC_ALIGN_DMA_BUF_SIZE);
|
|||
|
host->idma_des = HAL_MallocAlign(HAL_ALIGN(SDXC_MAX_DES_NUM * sizeof(smc_idma_des), OS_CACHE_ALIGN_BYTES));
|
|||
|
if (HAL_PT_TO_U(host->idma_des) & 0x07U) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s malloc not aligned by 8B\n", __func__);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
SDC_LOGD("idma_des %lx\n",HAL_PR_SZ_L(host->idma_des));
|
|||
|
|
|||
|
host->max_blk_count = 8192;
|
|||
|
host->max_blk_size = 4096;
|
|||
|
host->max_req_size = host->max_blk_size * host->max_blk_count;
|
|||
|
host->max_seg_size = host->max_req_size;
|
|||
|
host->max_segs = 128;
|
|||
|
host->ocr_avail = MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32
|
|||
|
| MMC_VDD_32_33 | MMC_VDD_33_34;
|
|||
|
|
|||
|
SDC_LOGN("SDC Host Capability:0x%x Ocr avail:0x%x\n", (unsigned int)host->caps, (unsigned int)host->ocr_avail);
|
|||
|
|
|||
|
/* init semaphore */
|
|||
|
SDC_SemCreate(&host->lock, 0);
|
|||
|
SDC_MutexCreate(&host->thread_lock);
|
|||
|
#ifdef CONFIG_SDC_EXCLUSIVE_HOST
|
|||
|
SDC_SemCreate(&host->exclusive_lock, 1);
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (host->param.cd_mode == CARD_DETECT_BY_D3 && host->present == 0) {
|
|||
|
SDC_LOGD("SDC power init.\n");
|
|||
|
HAL_SDC_PowerOn(host);
|
|||
|
} else if (host->present == 0) {
|
|||
|
/* if card is not present and the card detect mode is not CARD_DETECT_BY_D3,
|
|||
|
* we shutdown io voltage to save power. */
|
|||
|
SDC_LOGD("SDC no card detected, shutdown io voltage.\n");
|
|||
|
__mci_hold_io(host);
|
|||
|
//__mci_set_vddio(host, SDC_VOLTAGE_OFF);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_SD_PM
|
|||
|
SDC_DEV(host->sdc_id)->platform_data = host;
|
|||
|
pm_register_ops(SDC_DEV(host->sdc_id));
|
|||
|
#endif
|
|||
|
|
|||
|
host->State = SDC_STATE_READY;
|
|||
|
host->wait = SDC_WAIT_NONE;
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
//if (host->param.cd_mode != CARD_ALWAYS_PRESENT && host->present) {
|
|||
|
if (host->param.cd_mode != CARD_ALWAYS_PRESENT) {
|
|||
|
host->wait_voltage_stable = 1;
|
|||
|
if (host->cd_delay == 0) {
|
|||
|
SDC_ModTimer(&host->cd_timer, 10);
|
|||
|
} else {
|
|||
|
SDC_ModTimer(&host->cd_timer, host->cd_delay);
|
|||
|
}
|
|||
|
}
|
|||
|
SDC_LOGN("SDC cd_mode:%d present_val:%d\n", (unsigned int)host->param.cd_mode,
|
|||
|
(unsigned int)host->cd_pin_present_val);
|
|||
|
#endif
|
|||
|
SDC_LOGN("SDC id:%d dma_use:%d present:%d\n driver version %s init ok.\n", (unsigned int)host->sdc_id,
|
|||
|
(unsigned int)host->dma_use, (unsigned int)host->present ,SDMMC_DRIVER_VERSION);
|
|||
|
#ifdef SDC_FPGA
|
|||
|
SDC_LOGN("SDC ***Warning: use FPGA config,Are you sure?***\n wmb,cache unsupport now\n");
|
|||
|
#endif
|
|||
|
sdc_hex_dump_word((const void *)(SDC_GPIO_BASE+0xb0),0x400);
|
|||
|
sdc_hex_dump_word((const void *)0x4002000, 0x200);
|
|||
|
|
|||
|
return host;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief DeInitializes the SDC peripheral.
|
|||
|
* @param sdc_id:
|
|||
|
* @arg sdc_id-> SDC ID.
|
|||
|
* @retval None.
|
|||
|
*/
|
|||
|
int32_t hal_sdc_deinit(uint32_t sdc_id)
|
|||
|
{
|
|||
|
struct mmc_host *host = _mci_host[sdc_id];
|
|||
|
|
|||
|
if (!host) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d err", __func__, __LINE__);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
host->param.cd_mode = 0;
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_SD_PM
|
|||
|
pm_unregister_ops(SDC_DEV(host->sdc_id));
|
|||
|
#endif
|
|||
|
|
|||
|
__mci_exit_host(host);
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC0_DisableMClock();
|
|||
|
SDC0_CCM_BusForceReset();
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC1_DisableMClock();
|
|||
|
SDC1_CCM_BusForceReset();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
HAL_BoardIoctl(HAL_BIR_PINMUX_DEINIT, HAL_MKDEV(HAL_DEV_MAJOR_SDC,
|
|||
|
host->sdc_id), SDCGPIO_DET);
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef CONFIG_SDC_EXCLUSIVE_HOST
|
|||
|
SDC_SemDel(&host->exclusive_lock);
|
|||
|
#endif
|
|||
|
SDC_MutexDelete(&host->thread_lock);
|
|||
|
SDC_SemDel(&host->lock);
|
|||
|
|
|||
|
HAL_FreeAlign(host->idma_des);
|
|||
|
HAL_FreeAlign(host->align_dma_buf);
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if ((host->param.cd_mode == CARD_DETECT_BY_GPIO_IRQ)||
|
|||
|
(host->param.cd_mode == CARD_DETECT_BY_D3)) {
|
|||
|
SDC_DelTimer(&host->cd_timer);
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (host->sdc_id == 0) {
|
|||
|
SDC_FREE_IRQ(SDC0_IRQn, host);
|
|||
|
#if SDC1_SUPPORT
|
|||
|
} else if (host->sdc_id == 1) {
|
|||
|
SDC_FREE_IRQ(SDC1_IRQn, host);
|
|||
|
#endif
|
|||
|
}
|
|||
|
SDC_LOGD("sdc:%ld deinit ok.\n", HAL_PR_SZ_L(sdc_id));
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief malloc for sd host.
|
|||
|
* @param sdc_id:
|
|||
|
* @arg host ID.
|
|||
|
* @retval 0 if success or other if failed.
|
|||
|
*/
|
|||
|
struct mmc_host *hal_sdc_create(uint32_t sdc_id, SDC_InitTypeDef *param)
|
|||
|
{
|
|||
|
struct mmc_host *host = _mci_host[sdc_id];
|
|||
|
int ret;
|
|||
|
|
|||
|
rt_kprintf("hal_sdc_create %d\n",sdc_id);
|
|||
|
|
|||
|
if (host) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s has already created!\n", __func__);
|
|||
|
return host;
|
|||
|
}
|
|||
|
|
|||
|
host = HAL_Malloc(sizeof(struct mmc_host));
|
|||
|
if (host == NULL) {
|
|||
|
SDC_LOGE_RAW(ROM_ERR_MASK, "%s malloc fail\n", __func__);
|
|||
|
} else {
|
|||
|
SDC_Memset(host, 0, sizeof(struct mmc_host));
|
|||
|
host->sdc_id = sdc_id;
|
|||
|
host->ref = 0;
|
|||
|
#ifdef __CONFIG_ARCH_APP_CORE
|
|||
|
memcpy(&host->param, param, sizeof(SDC_InitTypeDef));
|
|||
|
host->debug_mask = param->debug_mask;
|
|||
|
host->dma_use = param->dma_use;
|
|||
|
#ifdef CONFIG_DETECT_CARD
|
|||
|
if (param->cd_mode == CARD_DETECT_BY_GPIO_IRQ || param->cd_mode == CARD_DETECT_BY_D3) {
|
|||
|
host->cd_gpio_isr = __mci_cd_irq;
|
|||
|
ret = mmc_gpiod_request_cd_irq(host);
|
|||
|
if (!param->cd_cb && ret < 0) {
|
|||
|
HAL_Free(host);
|
|||
|
SDC_LOGE("%s,%d cd_mode:%ld with no cb!\n",
|
|||
|
__func__, __LINE__, HAL_PR_SZ_L(param->cd_mode));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
_mci_host[sdc_id] = host;
|
|||
|
SDC_LOGN("%s host:%p id:%d\n", __func__, host, host->sdc_id);
|
|||
|
}
|
|||
|
|
|||
|
return host;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief free for sd host.
|
|||
|
* @param host:
|
|||
|
* @arg host ID.
|
|||
|
* @param flg:
|
|||
|
* @arg 0:normal delete, 1:unnormal delete, internal use.
|
|||
|
* @retval 0 if success or other if failed.
|
|||
|
*/
|
|||
|
int32_t hal_sdc_destroy(struct mmc_host *host)
|
|||
|
{
|
|||
|
if (host == NULL) {
|
|||
|
SDC_LOGW_RAW(ROM_WRN_MASK, "%s host not exit!\n", __func__);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
if (host->ref != 0) {
|
|||
|
SDC_LOGW("%s fail, ref:%d\n", __func__, host->ref);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
_mci_host[host->sdc_id] = NULL;
|
|||
|
SDC_LOGD("%s host:%p id:%d\n", __func__, host, host->sdc_id);
|
|||
|
HAL_Free(host);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief get pointer of mmc_host.
|
|||
|
* @param sdc_id:
|
|||
|
* @arg host ID.
|
|||
|
* @retval pointer of mmc_card if success or NULL if failed.
|
|||
|
*/
|
|||
|
struct mmc_host *hal_sdc_open(uint32_t sdc_id)
|
|||
|
{
|
|||
|
struct mmc_host *host = _mci_host[sdc_id];
|
|||
|
|
|||
|
if (host == NULL || host->sdc_id != sdc_id) {
|
|||
|
SDC_LOGW_RAW(ROM_WRN_MASK, "%s host not exit! id:%d,host:%x\n", __func__, (unsigned int)sdc_id, HAL_PR_SZ(HAL_PT_TO_U(host)));
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
host->ref++;
|
|||
|
|
|||
|
return host;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief close mmc_host.
|
|||
|
* @param host_id:
|
|||
|
* @arg host ID.
|
|||
|
* @retval 0 if success or other if failed.
|
|||
|
*/
|
|||
|
uint32_t hal_sdc_close(uint32_t sdc_id)
|
|||
|
{
|
|||
|
struct mmc_host *host = _mci_host[sdc_id];
|
|||
|
|
|||
|
if (host == NULL || host->sdc_id != sdc_id || host->ref < 1) {
|
|||
|
SDC_LOGW_RAW(ROM_WRN_MASK, "%s fail! id:%ld\n", __func__, HAL_PR_SZ_L(sdc_id));
|
|||
|
return -1;
|
|||
|
}
|
|||
|
host->ref--;
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|