321 lines
7.5 KiB
C
321 lines
7.5 KiB
C
/*
|
|
* Copyright (c) 2006-2024 RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2024-08-16 zhujiale first version
|
|
*/
|
|
#include <rtthread.h>
|
|
#include "sdhci.h"
|
|
#include <rtdbg.h>
|
|
#include <mmu.h>
|
|
#include <drivers/core/dm.h>
|
|
|
|
|
|
static void rt_plat_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
|
|
{
|
|
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
|
rt_uint32_t flags = req->cmd->flags;
|
|
|
|
switch (flags & RESP_MASK)
|
|
{
|
|
case RESP_NONE:
|
|
flags |= MMC_RSP_NONE;
|
|
break;
|
|
case RESP_R1:
|
|
flags |= MMC_RSP_R1;
|
|
break;
|
|
case RESP_R1B:
|
|
flags |= MMC_RSP_R1B;
|
|
break;
|
|
case RESP_R2:
|
|
flags |= MMC_RSP_R2;
|
|
break;
|
|
case RESP_R3:
|
|
flags |= MMC_RSP_R3;
|
|
break;
|
|
case RESP_R4:
|
|
flags |= MMC_RSP_R4;
|
|
break;
|
|
case RESP_R5:
|
|
flags |= MMC_RSP_R5;
|
|
break;
|
|
case RESP_R6:
|
|
flags |= MMC_RSP_R6;
|
|
break;
|
|
case RESP_R7:
|
|
flags |= MMC_RSP_R7;
|
|
break;
|
|
}
|
|
if (req->data)
|
|
{
|
|
if ((rt_uint64_t)rt_kmem_v2p(req->data->buf) > 0xffffffff)
|
|
{
|
|
void *dma_buffer = rt_malloc(req->data->blks * req->data->blksize);
|
|
void *req_buf = NULL;
|
|
|
|
if (req->data->flags & DATA_DIR_WRITE)
|
|
{
|
|
rt_memcpy(dma_buffer, req->data->buf, req->data->blks * req->data->blksize);
|
|
req_buf = req->data->buf;
|
|
req->data->buf = dma_buffer;
|
|
}
|
|
else if (req->data->flags & DATA_DIR_READ)
|
|
{
|
|
req_buf = req->data->buf;
|
|
req->data->buf = dma_buffer;
|
|
}
|
|
req->cmd->flags |= flags;
|
|
mmc->ops->request(mmc, req);
|
|
|
|
rt_sem_take(&host->sem_ack, RT_WAITING_FOREVER);
|
|
|
|
if (req->data->flags & DATA_DIR_READ)
|
|
{
|
|
rt_memcpy(req_buf, dma_buffer, req->data->blksize * req->data->blks);
|
|
req->data->buf = req_buf;
|
|
}else{
|
|
req->data->buf = req_buf;
|
|
}
|
|
|
|
rt_free(dma_buffer);
|
|
rt_sem_release(&host->sem_ack);
|
|
}
|
|
else
|
|
{
|
|
req->cmd->flags |= flags;
|
|
mmc->ops->request(mmc, req);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
req->cmd->flags |= flags;
|
|
mmc->ops->request(mmc, req);
|
|
}
|
|
}
|
|
|
|
static void rt_plat_set_ioconfig(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *iocfg)
|
|
{
|
|
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
|
|
|
LOG_D("clock:%d,width:%d,power:%d,vdd:%d,timing:%d\n",
|
|
iocfg->clock, iocfg->bus_width,
|
|
iocfg->power_mode, iocfg->vdd, iocfg->timing);
|
|
|
|
mmc->ops->set_ios(mmc, iocfg);
|
|
}
|
|
|
|
static rt_int32_t rt_plat_get_card_status(struct rt_mmcsd_host *host)
|
|
{
|
|
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
|
|
|
return mmc->ops->get_cd(mmc);
|
|
}
|
|
|
|
static rt_int32_t rt_plat_execute_tuning(struct rt_mmcsd_host *host, rt_int32_t opcode)
|
|
{
|
|
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
|
|
|
return mmc->ops->execute_tuning(mmc, opcode);
|
|
}
|
|
|
|
static void rt_plat_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en)
|
|
{
|
|
struct rt_mmc_host *mmc = (struct rt_mmc_host *)host;
|
|
|
|
return mmc->ops->enable_sdio_irq(mmc, en);
|
|
}
|
|
|
|
|
|
static const struct rt_mmcsd_host_ops rt_mmcsd_ops = {
|
|
.request = rt_plat_request,
|
|
.set_iocfg = rt_plat_set_ioconfig,
|
|
.get_card_status = rt_plat_get_card_status,
|
|
.enable_sdio_irq = rt_plat_enable_sdio_irq,
|
|
.execute_tuning = rt_plat_execute_tuning,
|
|
};
|
|
|
|
|
|
void rt_mmc_request_done(struct rt_mmc_host *host, struct rt_mmcsd_req *mrq)
|
|
{
|
|
mmcsd_req_complete(&host->rthost);
|
|
}
|
|
|
|
/*add host in rtt while sdhci complete*/
|
|
int rt_mmc_add_host(struct rt_mmc_host *mmc)
|
|
{
|
|
mmc->rthost.ops = &rt_mmcsd_ops;
|
|
mmc->rthost.flags = mmc->caps;
|
|
mmc->rthost.freq_max = mmc->f_max;
|
|
mmc->rthost.freq_min = 400000;
|
|
mmc->rthost.max_dma_segs = mmc->max_segs;
|
|
mmc->rthost.max_seg_size = mmc->max_seg_size;
|
|
mmc->rthost.max_blk_size = mmc->max_blk_size;
|
|
mmc->rthost.max_blk_count = mmc->max_blk_count;
|
|
mmc->rthost.valid_ocr = VDD_165_195|VDD_20_21|VDD_21_22|VDD_22_23|VDD_24_25|VDD_25_26|VDD_26_27|VDD_27_28|VDD_28_29|VDD_29_30|VDD_30_31|VDD_32_33|VDD_33_34|VDD_34_35|VDD_35_36;
|
|
|
|
|
|
mmcsd_change(&mmc->rthost);
|
|
return 0;
|
|
}
|
|
|
|
struct rt_mmc_host *rt_mmc_alloc_host(int extra, struct rt_device *dev)
|
|
{
|
|
struct rt_mmc_host *mmc;
|
|
|
|
mmc = rt_malloc(sizeof(*mmc) + extra);
|
|
if (mmc)
|
|
{
|
|
rt_memset(mmc, 0, sizeof(*mmc) + extra);
|
|
mmc->parent = dev;
|
|
mmcsd_host_init(&mmc->rthost);
|
|
}
|
|
|
|
return mmc;
|
|
}
|
|
|
|
void rt_mmc_remove_host(struct rt_mmc_host *host)
|
|
{
|
|
rt_free(host);
|
|
}
|
|
|
|
int rt_mmc_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rt_mmc_gpio_get_cd(struct rt_mmc_host *host)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
void rt_mmc_detect_change(struct rt_mmc_host *host, unsigned long delay)
|
|
{
|
|
}
|
|
|
|
|
|
int rt_mmc_regulator_set_vqmmc(struct rt_mmc_host *mmc, struct rt_mmcsd_io_cfg *ios)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
rt_bool_t rt_mmc_can_gpio_ro(struct rt_mmc_host *host)
|
|
{
|
|
return RT_FALSE;
|
|
}
|
|
|
|
int rt_mmc_gpio_get_ro(struct rt_mmc_host *host)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int rt_mmc_send_abort_tuning(struct rt_mmc_host *host, rt_uint32_t opcode)
|
|
{
|
|
return 0;
|
|
}
|
|
int rt_mmc_of_parse(struct rt_mmc_host *host)
|
|
{
|
|
struct rt_device *dev = host->parent;
|
|
rt_uint32_t bus_width;
|
|
|
|
if (!dev || !dev->ofw_node)
|
|
return 0;
|
|
|
|
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
|
|
if (rt_dm_dev_prop_read_u32(dev, "bus-width", &bus_width) < 0)
|
|
{
|
|
bus_width = 1;
|
|
}
|
|
|
|
switch (bus_width)
|
|
{
|
|
case 8:
|
|
host->caps |= MMC_CAP_8_BIT_DATA;
|
|
break; /* Hosts capable of 8-bit can also do 4 bits */
|
|
case 4:
|
|
host->caps |= MMC_CAP_4_BIT_DATA;
|
|
break;
|
|
case 1:
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* f_max is obtained from the optional "max-frequency" property */
|
|
rt_dm_dev_prop_read_u32(dev, "max-frequency", &host->f_max);
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "cap-mmc-highspeed"))
|
|
{
|
|
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "mmc-hs200-1_8v"))
|
|
{
|
|
host->caps |= MMC_CAP2_HS200_1_8V_SDR;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "non-removable"))
|
|
{
|
|
host->caps |= MMC_CAP_NONREMOVABLE;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "no-sdio"))
|
|
{
|
|
host->caps2 |= MMC_CAP2_NO_SDIO;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "no-sd"))
|
|
{
|
|
host->caps2 |= MMC_CAP2_NO_SD;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-3_3v"))
|
|
{
|
|
host->caps |= MMC_CAP_3_3V_DDR;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_8v"))
|
|
{
|
|
host->caps |= MMC_CAP_1_8V_DDR;
|
|
}
|
|
|
|
if (rt_dm_dev_prop_read_bool(dev, "mmc-ddr-1_2v"))
|
|
{
|
|
host->caps |= MMC_CAP_1_2V_DDR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void rt_mmc_free_host(struct rt_mmc_host *host)
|
|
{
|
|
}
|
|
|
|
rt_bool_t rt_mmc_can_gpio_cd(struct rt_mmc_host *host)
|
|
{
|
|
return RT_FALSE;
|
|
}
|
|
|
|
int mmc_regulator_get_supply(struct rt_mmc_host *mmc)
|
|
{
|
|
mmc->supply.vmmc = -RT_NULL;
|
|
mmc->supply.vqmmc = -RT_NULL;
|
|
|
|
return 0;
|
|
}
|
|
int regulator_get_current_limit(struct regulator *regulator)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int regulator_is_supported_voltage(struct regulator *regulator,
|
|
|
|
int min_uV, int max_uV)
|
|
{
|
|
return 0;
|
|
}
|