drivers: sdhc: add cdns sdhc/combophy driver files
Add SDHC driver files with new SD framework changes SDHC driver includes combophy configurations. Added mmc binding yaml file Signed-off-by: Murlidhar Roy <murlidhar.roy@intel.com>
This commit is contained in:
parent
9a642caebb
commit
eb006b992f
|
@ -9,4 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_SDIF mcux_sdif.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SAM_HSMCI sam_hsmci.c)
|
zephyr_library_sources_ifdef(CONFIG_SAM_HSMCI sam_hsmci.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_INTEL_EMMC_HOST intel_emmc_host.c)
|
zephyr_library_sources_ifdef(CONFIG_INTEL_EMMC_HOST intel_emmc_host.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c)
|
zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_CDNS_SDHC sdhc_cdns_ll.c sdhc_cdns.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -14,6 +14,7 @@ source "drivers/sdhc/Kconfig.spi"
|
||||||
source "drivers/sdhc/Kconfig.mcux_sdif"
|
source "drivers/sdhc/Kconfig.mcux_sdif"
|
||||||
source "drivers/sdhc/Kconfig.sam_hsmci"
|
source "drivers/sdhc/Kconfig.sam_hsmci"
|
||||||
source "drivers/sdhc/Kconfig.intel"
|
source "drivers/sdhc/Kconfig.intel"
|
||||||
|
source "drivers/sdhc/Kconfig.sdhc_cdns"
|
||||||
|
|
||||||
config SDHC_INIT_PRIORITY
|
config SDHC_INIT_PRIORITY
|
||||||
int "SDHC driver init priority"
|
int "SDHC driver init priority"
|
||||||
|
|
26
drivers/sdhc/Kconfig.sdhc_cdns
Normal file
26
drivers/sdhc/Kconfig.sdhc_cdns
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Copyright (c) 2023 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config CDNS_SDHC
|
||||||
|
bool "CDNS SDHC"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_CDNS_SDHC_ENABLED
|
||||||
|
select SDHC_SUPPORTS_NATIVE_MODE
|
||||||
|
help
|
||||||
|
Enable Cadence SDMMC Host Controller.
|
||||||
|
|
||||||
|
if CDNS_SDHC
|
||||||
|
|
||||||
|
# Cadence SDHC DMA needs 64 bit aligned buffers
|
||||||
|
config SDHC_BUFFER_ALIGNMENT
|
||||||
|
default 8
|
||||||
|
|
||||||
|
config CDNS_DESC_COUNT
|
||||||
|
int "Allocate number of descriptors"
|
||||||
|
default 8
|
||||||
|
help
|
||||||
|
SD host controllers require DMA preparation for read and write operation.
|
||||||
|
Creates static descriptors which can be used by ADMA. Devices should
|
||||||
|
configure this flag if they require to transfer more than 8*64Kb of data.
|
||||||
|
|
||||||
|
endif # CDNS_SDHC
|
301
drivers/sdhc/sdhc_cdns.c
Normal file
301
drivers/sdhc/sdhc_cdns.c
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT cdns_sdhc
|
||||||
|
|
||||||
|
#include <zephyr/drivers/sdhc.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/drivers/clock_control.h>
|
||||||
|
#include <zephyr/drivers/reset.h>
|
||||||
|
|
||||||
|
#include "sdhc_cdns_ll.h"
|
||||||
|
|
||||||
|
#define SDHC_CDNS_DESC_SIZE (1<<20)
|
||||||
|
#define COMBOPHY_ADDR_MASK 0x0000FFFFU
|
||||||
|
|
||||||
|
#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config)
|
||||||
|
#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data)
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* SDMMC operations FPs are the element of structure*/
|
||||||
|
static const struct sdhc_cdns_ops *cdns_sdmmc_ops;
|
||||||
|
|
||||||
|
struct sdhc_cdns_config {
|
||||||
|
DEVICE_MMIO_NAMED_ROM(reg_base);
|
||||||
|
DEVICE_MMIO_NAMED_ROM(combo_phy);
|
||||||
|
/* Clock rate for host */
|
||||||
|
uint32_t clk_rate;
|
||||||
|
/* power delay prop for host */
|
||||||
|
uint32_t power_delay_ms;
|
||||||
|
/* run time device structure */
|
||||||
|
const struct device *cdns_clk_dev;
|
||||||
|
/* type to identify a clock controller sub-system */
|
||||||
|
clock_control_subsys_t clkid;
|
||||||
|
/* Reset controller device configuration. */
|
||||||
|
const struct reset_dt_spec reset_sdmmc;
|
||||||
|
const struct reset_dt_spec reset_sdmmcocp;
|
||||||
|
const struct reset_dt_spec reset_softphy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_data {
|
||||||
|
DEVICE_MMIO_NAMED_RAM(reg_base);
|
||||||
|
DEVICE_MMIO_NAMED_RAM(combo_phy);
|
||||||
|
/* Host controller parameters */
|
||||||
|
struct sdhc_cdns_params params;
|
||||||
|
/* sdmmc device informartaion for host */
|
||||||
|
struct sdmmc_device_info info;
|
||||||
|
/* Input/Output configuration */
|
||||||
|
struct sdhc_io host_io;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sdhc_cdns_request(const struct device *dev,
|
||||||
|
struct sdhc_command *cmd,
|
||||||
|
struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sdmmc_cmd cdns_sdmmc_cmd;
|
||||||
|
|
||||||
|
if (cmd == NULL) {
|
||||||
|
LOG_ERR("Wrong CMD parameter");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialization of command structure */
|
||||||
|
cdns_sdmmc_cmd.cmd_idx = cmd->opcode;
|
||||||
|
cdns_sdmmc_cmd.cmd_arg = cmd->arg;
|
||||||
|
cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK);
|
||||||
|
|
||||||
|
/* Sending command as per the data or non data */
|
||||||
|
if (data) {
|
||||||
|
ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data,
|
||||||
|
data);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("DMA Prepare failed");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR ||
|
||||||
|
cmd->opcode == SD_READ_MULTIPLE_BLOCK) {
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
LOG_ERR("Invalid data parameter");
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data,
|
||||||
|
data->block_size);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* copying all responses as per response type */
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
cmd->response[i] = cdns_sdmmc_cmd.resp_data[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_get_card_present(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->card_present();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_card_busy(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_get_host_props(const struct device *dev,
|
||||||
|
struct sdhc_host_props *props)
|
||||||
|
{
|
||||||
|
const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
|
||||||
|
|
||||||
|
memset(props, 0, sizeof(struct sdhc_host_props));
|
||||||
|
props->f_min = SDMMC_CLOCK_400KHZ;
|
||||||
|
/*
|
||||||
|
* default max speed is 25MHZ, as per SCR register
|
||||||
|
* it will switch accordingly
|
||||||
|
*/
|
||||||
|
props->f_max = SD_CLOCK_25MHZ;
|
||||||
|
props->power_delay = sdhc_config->power_delay_ms;
|
||||||
|
props->host_caps.vol_330_support = true;
|
||||||
|
props->is_spi = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_reset(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_data *const data = DEV_DATA(dev);
|
||||||
|
const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* SDHC reg base */
|
||||||
|
DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);
|
||||||
|
/* ComboPhy reg base */
|
||||||
|
DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE);
|
||||||
|
|
||||||
|
/* clock setting */
|
||||||
|
if (sdhc_config->clk_rate == 0U) {
|
||||||
|
if (!device_is_ready(sdhc_config->cdns_clk_dev)) {
|
||||||
|
LOG_ERR("Clock controller device is not ready");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clock_control_get_rate(sdhc_config->cdns_clk_dev,
|
||||||
|
sdhc_config->clkid, &data->params.clk_rate);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data->params.clk_rate = sdhc_config->clk_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setting regbase */
|
||||||
|
data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||||
|
data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy);
|
||||||
|
data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev),
|
||||||
|
combo_phy)->phys_addr);
|
||||||
|
data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK);
|
||||||
|
|
||||||
|
/* resetting the lines */
|
||||||
|
if (sdhc_config->reset_sdmmc.dev != NULL) {
|
||||||
|
if (!device_is_ready(sdhc_config->reset_sdmmc.dev) ||
|
||||||
|
!device_is_ready(sdhc_config->reset_sdmmcocp.dev) ||
|
||||||
|
!device_is_ready(sdhc_config->reset_softphy.dev)) {
|
||||||
|
LOG_ERR("Reset device not found");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_softphy.dev,
|
||||||
|
sdhc_config->reset_softphy.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("Softphy Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev,
|
||||||
|
sdhc_config->reset_sdmmc.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("sdmmc Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev,
|
||||||
|
sdhc_config->reset_sdmmcocp.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("sdmmcocp Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init function to call lower layer file */
|
||||||
|
sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops);
|
||||||
|
|
||||||
|
ret = sdhc_cdns_reset(dev);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Card reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init operation called for register initialisation */
|
||||||
|
ret = cdns_sdmmc_ops->init();
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Card initialization failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_data *data = dev->data;
|
||||||
|
struct sdhc_io *host_io = &data->host_io;
|
||||||
|
|
||||||
|
if (host_io->bus_width != ios->bus_width || host_io->clock !=
|
||||||
|
ios->clock) {
|
||||||
|
host_io->bus_width = ios->bus_width;
|
||||||
|
host_io->clock = ios->clock;
|
||||||
|
return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sdhc_driver_api sdhc_cdns_api = {
|
||||||
|
.request = sdhc_cdns_request,
|
||||||
|
.set_io = sdhc_cdns_set_io,
|
||||||
|
.get_host_props = sdhc_cdns_get_host_props,
|
||||||
|
.get_card_present = sdhc_cdns_get_card_present,
|
||||||
|
.reset = sdhc_cdns_reset,
|
||||||
|
.card_busy = sdhc_cdns_card_busy,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \
|
||||||
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \
|
||||||
|
( \
|
||||||
|
.clk_rate = DT_INST_PROP(inst, clock_frequency), \
|
||||||
|
.cdns_clk_dev = NULL, \
|
||||||
|
.clkid = (clock_control_subsys_t)0, \
|
||||||
|
), \
|
||||||
|
( \
|
||||||
|
.clk_rate = 0, \
|
||||||
|
.cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
|
||||||
|
.clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define SDHC_CDNS_RESET_SPEC_INIT(inst) \
|
||||||
|
.reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \
|
||||||
|
.reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\
|
||||||
|
.reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2),
|
||||||
|
|
||||||
|
#define SDHC_CDNS_INIT(inst) \
|
||||||
|
static struct sdhc_cdns_desc cdns_desc \
|
||||||
|
[CONFIG_CDNS_DESC_COUNT]; \
|
||||||
|
\
|
||||||
|
static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\
|
||||||
|
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \
|
||||||
|
reg_base, DT_DRV_INST(inst)), \
|
||||||
|
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \
|
||||||
|
combo_phy, DT_DRV_INST(inst)), \
|
||||||
|
SDHC_CDNS_CLOCK_RATE_INIT(inst) \
|
||||||
|
IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \
|
||||||
|
(SDHC_CDNS_RESET_SPEC_INIT(inst))) \
|
||||||
|
.power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \
|
||||||
|
}; \
|
||||||
|
static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \
|
||||||
|
.params = { \
|
||||||
|
.bus_width = SDHC_BUS_WIDTH1BIT, \
|
||||||
|
.desc_base = (uintptr_t) &cdns_desc, \
|
||||||
|
.desc_size = SDHC_CDNS_DESC_SIZE, \
|
||||||
|
.flags = 0, \
|
||||||
|
}, \
|
||||||
|
.info = { \
|
||||||
|
.cdn_sdmmc_dev_type = SD_DS, \
|
||||||
|
.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \
|
||||||
|
}, \
|
||||||
|
}; \
|
||||||
|
DEVICE_DT_INST_DEFINE(inst, \
|
||||||
|
&sdhc_cdns_init, \
|
||||||
|
NULL, \
|
||||||
|
&sdhc_cdns_data_##inst, \
|
||||||
|
&sdhc_cdns_config_##inst, \
|
||||||
|
POST_KERNEL, \
|
||||||
|
CONFIG_SDHC_INIT_PRIORITY, \
|
||||||
|
&sdhc_cdns_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT)
|
301
drivers/sdhc/sdhc_cdns/sdhc_cdns.c
Normal file
301
drivers/sdhc/sdhc_cdns/sdhc_cdns.c
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT cdns_sdhc
|
||||||
|
|
||||||
|
#include <zephyr/drivers/sdhc.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/drivers/clock_control.h>
|
||||||
|
#include <zephyr/drivers/reset.h>
|
||||||
|
|
||||||
|
#include "sdhc_cdns_ll.h"
|
||||||
|
|
||||||
|
#define SDHC_CDNS_DESC_SIZE (1<<20)
|
||||||
|
#define COMBOPHY_ADDR_MASK 0x0000FFFFU
|
||||||
|
|
||||||
|
#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config)
|
||||||
|
#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data)
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* SDMMC operations FPs are the element of structure*/
|
||||||
|
static const struct sdhc_cdns_ops *cdns_sdmmc_ops;
|
||||||
|
|
||||||
|
struct sdhc_cdns_config {
|
||||||
|
DEVICE_MMIO_NAMED_ROM(reg_base);
|
||||||
|
DEVICE_MMIO_NAMED_ROM(combo_phy);
|
||||||
|
/* Clock rate for host */
|
||||||
|
uint32_t clk_rate;
|
||||||
|
/* power delay prop for host */
|
||||||
|
uint32_t power_delay_ms;
|
||||||
|
/* run time device structure */
|
||||||
|
const struct device *cdns_clk_dev;
|
||||||
|
/* type to identify a clock controller sub-system */
|
||||||
|
clock_control_subsys_t clkid;
|
||||||
|
/* Reset controller device configuration. */
|
||||||
|
const struct reset_dt_spec reset_sdmmc;
|
||||||
|
const struct reset_dt_spec reset_sdmmcocp;
|
||||||
|
const struct reset_dt_spec reset_softphy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_data {
|
||||||
|
DEVICE_MMIO_NAMED_RAM(reg_base);
|
||||||
|
DEVICE_MMIO_NAMED_RAM(combo_phy);
|
||||||
|
/* Host controller parameters */
|
||||||
|
struct sdhc_cdns_params params;
|
||||||
|
/* sdmmc device informartaion for host */
|
||||||
|
struct sdmmc_device_info info;
|
||||||
|
/* Input/Output configuration */
|
||||||
|
struct sdhc_io host_io;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sdhc_cdns_request(const struct device *dev,
|
||||||
|
struct sdhc_command *cmd,
|
||||||
|
struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct sdmmc_cmd cdns_sdmmc_cmd;
|
||||||
|
|
||||||
|
if (cmd == NULL) {
|
||||||
|
LOG_ERR("Wrong CMD parameter");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialization of command structure */
|
||||||
|
cdns_sdmmc_cmd.cmd_idx = cmd->opcode;
|
||||||
|
cdns_sdmmc_cmd.cmd_arg = cmd->arg;
|
||||||
|
cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK);
|
||||||
|
|
||||||
|
/* Sending command as per the data or non data */
|
||||||
|
if (data) {
|
||||||
|
ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data,
|
||||||
|
data);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("DMA Prepare failed");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR ||
|
||||||
|
cmd->opcode == SD_READ_MULTIPLE_BLOCK) {
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
LOG_ERR("Invalid data parameter");
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data,
|
||||||
|
data->block_size);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* copying all responses as per response type */
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
cmd->response[i] = cdns_sdmmc_cmd.resp_data[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_get_card_present(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->card_present();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_card_busy(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_get_host_props(const struct device *dev,
|
||||||
|
struct sdhc_host_props *props)
|
||||||
|
{
|
||||||
|
const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
|
||||||
|
|
||||||
|
memset(props, 0, sizeof(struct sdhc_host_props));
|
||||||
|
props->f_min = SDMMC_CLOCK_400KHZ;
|
||||||
|
/*
|
||||||
|
* default max speed is 25MHZ, as per SCR register
|
||||||
|
* it will switch accordingly
|
||||||
|
*/
|
||||||
|
props->f_max = SD_CLOCK_25MHZ;
|
||||||
|
props->power_delay = sdhc_config->power_delay_ms;
|
||||||
|
props->host_caps.vol_330_support = true;
|
||||||
|
props->is_spi = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_reset(const struct device *dev)
|
||||||
|
{
|
||||||
|
return cdns_sdmmc_ops->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_data *const data = DEV_DATA(dev);
|
||||||
|
const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* SDHC reg base */
|
||||||
|
DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);
|
||||||
|
/* ComboPhy reg base */
|
||||||
|
DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE);
|
||||||
|
|
||||||
|
/* clock setting */
|
||||||
|
if (sdhc_config->clk_rate == 0U) {
|
||||||
|
if (!device_is_ready(sdhc_config->cdns_clk_dev)) {
|
||||||
|
LOG_ERR("Clock controller device is not ready");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clock_control_get_rate(sdhc_config->cdns_clk_dev,
|
||||||
|
sdhc_config->clkid, &data->params.clk_rate);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data->params.clk_rate = sdhc_config->clk_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setting regbase */
|
||||||
|
data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||||
|
data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy);
|
||||||
|
data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev),
|
||||||
|
combo_phy)->phys_addr);
|
||||||
|
data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK);
|
||||||
|
|
||||||
|
/* resetting the lines */
|
||||||
|
if (sdhc_config->reset_sdmmc.dev != NULL) {
|
||||||
|
if (!device_is_ready(sdhc_config->reset_sdmmc.dev) ||
|
||||||
|
!device_is_ready(sdhc_config->reset_sdmmcocp.dev) ||
|
||||||
|
!device_is_ready(sdhc_config->reset_softphy.dev)) {
|
||||||
|
LOG_ERR("Reset device not found");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_softphy.dev,
|
||||||
|
sdhc_config->reset_softphy.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("Softphy Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev,
|
||||||
|
sdhc_config->reset_sdmmc.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("sdmmc Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev,
|
||||||
|
sdhc_config->reset_sdmmcocp.id);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("sdmmcocp Reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init function to call lower layer file */
|
||||||
|
sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops);
|
||||||
|
|
||||||
|
ret = sdhc_cdns_reset(dev);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Card reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init operation called for register initialisation */
|
||||||
|
ret = cdns_sdmmc_ops->init();
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Card initialization failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_data *data = dev->data;
|
||||||
|
struct sdhc_io *host_io = &data->host_io;
|
||||||
|
|
||||||
|
if (host_io->bus_width != ios->bus_width || host_io->clock !=
|
||||||
|
ios->clock) {
|
||||||
|
host_io->bus_width = ios->bus_width;
|
||||||
|
host_io->clock = ios->clock;
|
||||||
|
return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sdhc_driver_api sdhc_cdns_api = {
|
||||||
|
.request = sdhc_cdns_request,
|
||||||
|
.set_io = sdhc_cdns_set_io,
|
||||||
|
.get_host_props = sdhc_cdns_get_host_props,
|
||||||
|
.get_card_present = sdhc_cdns_get_card_present,
|
||||||
|
.reset = sdhc_cdns_reset,
|
||||||
|
.card_busy = sdhc_cdns_card_busy,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \
|
||||||
|
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \
|
||||||
|
( \
|
||||||
|
.clk_rate = DT_INST_PROP(inst, clock_frequency), \
|
||||||
|
.cdns_clk_dev = NULL, \
|
||||||
|
.clkid = (clock_control_subsys_t)0, \
|
||||||
|
), \
|
||||||
|
( \
|
||||||
|
.clk_rate = 0, \
|
||||||
|
.cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
|
||||||
|
.clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define SDHC_CDNS_RESET_SPEC_INIT(inst) \
|
||||||
|
.reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \
|
||||||
|
.reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\
|
||||||
|
.reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2),
|
||||||
|
|
||||||
|
#define SDHC_CDNS_INIT(inst) \
|
||||||
|
static struct sdhc_cdns_desc cdns_desc \
|
||||||
|
[CONFIG_CDNS_DESC_COUNT]; \
|
||||||
|
\
|
||||||
|
static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\
|
||||||
|
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \
|
||||||
|
reg_base, DT_DRV_INST(inst)), \
|
||||||
|
DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \
|
||||||
|
combo_phy, DT_DRV_INST(inst)), \
|
||||||
|
SDHC_CDNS_CLOCK_RATE_INIT(inst) \
|
||||||
|
IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \
|
||||||
|
(SDHC_CDNS_RESET_SPEC_INIT(inst))) \
|
||||||
|
.power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \
|
||||||
|
}; \
|
||||||
|
static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \
|
||||||
|
.params = { \
|
||||||
|
.bus_width = SDHC_BUS_WIDTH1BIT, \
|
||||||
|
.desc_base = (uintptr_t) &cdns_desc, \
|
||||||
|
.desc_size = SDHC_CDNS_DESC_SIZE, \
|
||||||
|
.flags = 0, \
|
||||||
|
}, \
|
||||||
|
.info = { \
|
||||||
|
.cdn_sdmmc_dev_type = SD_DS, \
|
||||||
|
.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \
|
||||||
|
}, \
|
||||||
|
}; \
|
||||||
|
DEVICE_DT_INST_DEFINE(inst, \
|
||||||
|
&sdhc_cdns_init, \
|
||||||
|
NULL, \
|
||||||
|
&sdhc_cdns_data_##inst, \
|
||||||
|
&sdhc_cdns_config_##inst, \
|
||||||
|
POST_KERNEL, \
|
||||||
|
CONFIG_SDHC_INIT_PRIORITY, \
|
||||||
|
&sdhc_cdns_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT)
|
791
drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c
Normal file
791
drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.c
Normal file
|
@ -0,0 +1,791 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "sdhc_cdns_ll.h"
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* card busy and present */
|
||||||
|
#define CARD_BUSY 1
|
||||||
|
#define CARD_NOT_BUSY 0
|
||||||
|
#define CARD_PRESENT 1
|
||||||
|
|
||||||
|
/* SRS12 error mask */
|
||||||
|
#define CDNS_SRS12_ERR_MASK 0xFFFF8000U
|
||||||
|
#define CDNS_CSD_BYTE_MASK 0x000000FFU
|
||||||
|
|
||||||
|
/* General define */
|
||||||
|
#define SDHC_REG_MASK 0xFFFFFFFFU
|
||||||
|
#define SD_HOST_BLOCK_SIZE 0x200
|
||||||
|
|
||||||
|
#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024)
|
||||||
|
#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1)
|
||||||
|
|
||||||
|
#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH)
|
||||||
|
#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH)
|
||||||
|
#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE)
|
||||||
|
#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE)
|
||||||
|
#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE)
|
||||||
|
#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE)
|
||||||
|
#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE)
|
||||||
|
|
||||||
|
#define CARD_REG_TIME_DELAY_US 100000
|
||||||
|
#define WAIT_ICS_TIME_DELAY_US 5000
|
||||||
|
#define RESET_SRS14 0x00000000
|
||||||
|
|
||||||
|
static struct sdhc_cdns_params cdns_params;
|
||||||
|
static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info;
|
||||||
|
static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info;
|
||||||
|
|
||||||
|
/* Function to write general phy registers */
|
||||||
|
static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value,
|
||||||
|
uint32_t phy_reg_data, uint32_t phy_reg_data_value)
|
||||||
|
{
|
||||||
|
uint32_t data = 0;
|
||||||
|
|
||||||
|
/* Set PHY register address, write HRS04*/
|
||||||
|
sys_write32(phy_reg_addr_value, phy_reg_addr);
|
||||||
|
|
||||||
|
/* Set PHY register data, write HRS05 */
|
||||||
|
sys_write32(phy_reg_data_value, phy_reg_data);
|
||||||
|
data = sys_read32(phy_reg_data);
|
||||||
|
|
||||||
|
if (data != phy_reg_data_value) {
|
||||||
|
LOG_ERR("PHY_REG_DATA is not set properly");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res)
|
||||||
|
{
|
||||||
|
/* Wait status command response ready */
|
||||||
|
if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS)
|
||||||
|
== CDNS_SRS11_ICS), timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Timed out waiting for ICS response");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_busy(void)
|
||||||
|
{
|
||||||
|
unsigned int data;
|
||||||
|
|
||||||
|
data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09);
|
||||||
|
return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_card_present(void)
|
||||||
|
{
|
||||||
|
uint32_t timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
|
||||||
|
if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09))
|
||||||
|
& CDNS_SRS09_CI) == CDNS_SRS09_CI),
|
||||||
|
timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Card detection timeout");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CARD_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_vol_reset(void)
|
||||||
|
{
|
||||||
|
/* Reset embedded card */
|
||||||
|
sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP),
|
||||||
|
(cdns_params.reg_base + SDHC_CDNS_SRS10));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Turn on supply voltage
|
||||||
|
* CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode
|
||||||
|
*/
|
||||||
|
sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP),
|
||||||
|
(cdns_params.reg_base + SDHC_CDNS_SRS10));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Values are taken from IP documents and calc_setting.py script
|
||||||
|
* with input value- mode sd_ds,
|
||||||
|
* sdmclk 5000,
|
||||||
|
* sdclk 10000,
|
||||||
|
* iocell_input_delay 2500,
|
||||||
|
* iocell_output_delay 2500 and
|
||||||
|
* delay_element 24
|
||||||
|
*/
|
||||||
|
void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
/* Values are taken by the reference of cadence IP documents */
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_sync_method = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1;
|
||||||
|
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phy register programing for phy init */
|
||||||
|
static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DQS_TIMING_REG
|
||||||
|
* This register controls the DQS related timing
|
||||||
|
*/
|
||||||
|
value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs))
|
||||||
|
| (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs))
|
||||||
|
| (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs))
|
||||||
|
| (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DQS_TIMING_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_GATE_LPBK_CTRL_REG
|
||||||
|
* This register controls the gate and loopback control related timing.
|
||||||
|
*/
|
||||||
|
value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method))
|
||||||
|
| (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift))
|
||||||
|
| (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel))
|
||||||
|
| (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress))
|
||||||
|
| (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming");
|
||||||
|
return -ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DLL_MASTER_CTRL_REG
|
||||||
|
* This register holds the control for the Master DLL logic.
|
||||||
|
*/
|
||||||
|
value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode))
|
||||||
|
| (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DLL_SLAVE_CTRL_REG
|
||||||
|
* This register holds the control for the slave DLL logic.
|
||||||
|
*/
|
||||||
|
value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay))
|
||||||
|
| (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay))
|
||||||
|
| (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay))
|
||||||
|
| (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_CTRL_REG
|
||||||
|
* This register handles the global control settings for the PHY.
|
||||||
|
*/
|
||||||
|
sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS04);
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05);
|
||||||
|
|
||||||
|
/* phony_dqs_timing=0 */
|
||||||
|
value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT);
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05);
|
||||||
|
|
||||||
|
/* switch off DLL_RESET */
|
||||||
|
do {
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
value |= CDNS_HRS09_PHY_SW_RESET;
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
/* polling PHY_INIT_COMPLETE */
|
||||||
|
} while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DQ_TIMING_REG
|
||||||
|
* This register controls the DQ related timing.
|
||||||
|
*/
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U;
|
||||||
|
value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on))
|
||||||
|
| (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end))
|
||||||
|
| (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start))
|
||||||
|
| (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end));
|
||||||
|
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DQ_TIMING_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = arch_dcache_invd_range((void *)buf, size);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DMA preparation for the read and write operation */
|
||||||
|
static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff,
|
||||||
|
struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_desc *desc;
|
||||||
|
uint32_t desc_cnt, i;
|
||||||
|
uintptr_t base;
|
||||||
|
uint64_t desc_base;
|
||||||
|
uint32_t size = data->blocks * data->block_size;
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) &&
|
||||||
|
(cdns_params.desc_size > 0) &&
|
||||||
|
((cdns_params.desc_size & MMC_BLOCK_MASK) == 0));
|
||||||
|
|
||||||
|
arch_dcache_flush_range((void *)dma_buff, size);
|
||||||
|
|
||||||
|
desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) /
|
||||||
|
(SDMMC_DMA_MAX_BUFFER_SIZE);
|
||||||
|
__ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) <
|
||||||
|
cdns_params.desc_size);
|
||||||
|
|
||||||
|
if (desc_cnt > CONFIG_CDNS_DESC_COUNT) {
|
||||||
|
LOG_ERR("Requested data transfer length %u greater than configured length %u",
|
||||||
|
size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creating descriptor as per the desc_count and linked list of
|
||||||
|
* descriptor for contiguous desc alignment
|
||||||
|
*/
|
||||||
|
base = cdns_params.reg_base;
|
||||||
|
desc = (struct sdhc_cdns_desc *)cdns_params.desc_base;
|
||||||
|
desc_base = (uint64_t)desc;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while ((i+1) < desc_cnt) {
|
||||||
|
desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
|
||||||
|
desc->reserved = 0;
|
||||||
|
desc->len = MAX_64KB_PAGE;
|
||||||
|
desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i);
|
||||||
|
desc->addr_hi = (dma_buff >> 32) & 0xffffffff;
|
||||||
|
size -= SDMMC_DMA_MAX_BUFFER_SIZE;
|
||||||
|
desc++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA |
|
||||||
|
ADMA_DESC_ATTR_END;
|
||||||
|
desc->reserved = 0;
|
||||||
|
desc->len = size;
|
||||||
|
desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i);
|
||||||
|
desc->addr_hi = (dma_buff >> 32) & 0xffffffff;
|
||||||
|
|
||||||
|
sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22);
|
||||||
|
sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23);
|
||||||
|
arch_dcache_flush_range((void *)cdns_params.desc_base,
|
||||||
|
desc_cnt * sizeof(struct sdhc_cdns_desc));
|
||||||
|
|
||||||
|
sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE |
|
||||||
|
data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS01);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_host_set_clk(int clk)
|
||||||
|
{
|
||||||
|
uint32_t sdclkfsval = 0;
|
||||||
|
uint32_t dtcvval = 0xe;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
sdclkfsval = (cdns_params.clk_rate / 2000) / clk;
|
||||||
|
sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) |
|
||||||
|
(1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable DLL reset */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0);
|
||||||
|
/* Set extended_wr_mode */
|
||||||
|
sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09)
|
||||||
|
& 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS09));
|
||||||
|
/* Release DLL reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN));
|
||||||
|
|
||||||
|
sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS)
|
||||||
|
| (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (width) {
|
||||||
|
case SDHC_BUS_WIDTH1BIT:
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1);
|
||||||
|
break;
|
||||||
|
case SDHC_BUS_WIDTH4BIT:
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4);
|
||||||
|
break;
|
||||||
|
case SDHC_BUS_WIDTH8BIT:
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__ASSERT_NO_MSG(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform clock configuration when SD clock is not gated */
|
||||||
|
if (clk != 0) {
|
||||||
|
ret = sdhc_cdns_host_set_clk(clk);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("%s: Clock configuration failed", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Programming HRS register for initialisation */
|
||||||
|
static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS09, register 42
|
||||||
|
* PHY Control and Status Register
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en))
|
||||||
|
| (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en))
|
||||||
|
| (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode))
|
||||||
|
| (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS10, register 43
|
||||||
|
* Host Controller SDCLK start point adjustment
|
||||||
|
*/
|
||||||
|
value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS16, register 48
|
||||||
|
* CMD/DAT output delay
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS07, register 40
|
||||||
|
* IO Delay Information Register
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate))
|
||||||
|
| (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params)
|
||||||
|
{
|
||||||
|
uint32_t dtcvval, sdclkfsval;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dtcvval = DTC_VAL;
|
||||||
|
sdclkfsval = 0;
|
||||||
|
|
||||||
|
/* Condition for Default speed mode and SDR12 and SDR_BC */
|
||||||
|
if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) {
|
||||||
|
sdclkfsval = 4;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) {
|
||||||
|
sdclkfsval = 2;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) {
|
||||||
|
sdclkfsval = 1;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) {
|
||||||
|
sdclkfsval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabling SD clock enable */
|
||||||
|
sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
sys_write32((dtcvval << CDNS_SRS11_DTCV) |
|
||||||
|
(sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable DLL reset */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0);
|
||||||
|
/* Set extended_wr_mode */
|
||||||
|
sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) &
|
||||||
|
0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS09));
|
||||||
|
/* Release DLL reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN));
|
||||||
|
|
||||||
|
sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) |
|
||||||
|
(1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_reset(void)
|
||||||
|
{
|
||||||
|
int32_t timeout;
|
||||||
|
|
||||||
|
sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF);
|
||||||
|
|
||||||
|
/* Software reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR);
|
||||||
|
|
||||||
|
/* Wait status command response ready */
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) &
|
||||||
|
CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Software reset is not completed...timedout");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 1, switch on DLL_RESET */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_init(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("SoftPhy register configuration failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Configuration for HRS IO reg failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_card_present();
|
||||||
|
if (ret != CARD_PRESENT) {
|
||||||
|
LOG_ERR("SD card does not detect");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_vol_reset();
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("SD/MMC card reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_set_clk(&cdns_params);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Host controller set clk failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
uint32_t op = 0;
|
||||||
|
uint32_t value;
|
||||||
|
uintptr_t base;
|
||||||
|
int32_t timeout;
|
||||||
|
uint32_t cmd_indx;
|
||||||
|
uint32_t status_check = 0;
|
||||||
|
|
||||||
|
__ASSERT(cmd, "Assert %s function call", __func__);
|
||||||
|
base = cdns_params.reg_base;
|
||||||
|
cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
switch (cmd->cmd_idx) {
|
||||||
|
case SD_SWITCH:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_WRITE_SINGLE_BLOCK:
|
||||||
|
case SD_READ_SINGLE_BLOCK:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR);
|
||||||
|
sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_WRITE_MULTIPLE_BLOCK:
|
||||||
|
case SD_READ_MULTIPLE_BLOCK:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR);
|
||||||
|
sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_APP_SEND_SCR:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (cmd->cmd_idx) {
|
||||||
|
case SD_GO_IDLE_STATE:
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_ALL_SEND_CID:
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SEND_IF_COND:
|
||||||
|
op = CDNS_SRS03_CMD_IDX_CHK_EN;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_STOP_TRANSMISSION:
|
||||||
|
op = CMD_STOP_ABORT_CMD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SEND_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SELECT_CARD:
|
||||||
|
op = CDNS_SRS03_MULTI_BLK_READ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd->resp_type) {
|
||||||
|
case SD_RSP_TYPE_NONE:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R2:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN |
|
||||||
|
RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R3:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R1:
|
||||||
|
if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx
|
||||||
|
== SD_WRITE_MULTIPLE_BLOCK)) {
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48
|
||||||
|
| CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
} else {
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ
|
||||||
|
| RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ |
|
||||||
|
CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC |
|
||||||
|
CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) {
|
||||||
|
k_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12);
|
||||||
|
|
||||||
|
sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02);
|
||||||
|
sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14);
|
||||||
|
sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03);
|
||||||
|
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) &
|
||||||
|
CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base +
|
||||||
|
SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) {
|
||||||
|
LOG_ERR("Response timeout SRS12");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12);
|
||||||
|
status_check = value & CDNS_SRS12_ERR_MASK;
|
||||||
|
if (status_check != 0U) {
|
||||||
|
LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) {
|
||||||
|
cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04);
|
||||||
|
if (op & RES_TYPE_SEL_136) {
|
||||||
|
cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05);
|
||||||
|
cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06);
|
||||||
|
cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07);
|
||||||
|
|
||||||
|
/* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0],
|
||||||
|
* RESP2[31:0], RESP1[31:0], RESP0[31:0]
|
||||||
|
* Subsystem expects 128 bits response but cadence SDHC sends
|
||||||
|
* 120 bits response from R[127:8]. Bits manupulation to address
|
||||||
|
* the correct responses for the 136 bit response type.
|
||||||
|
*/
|
||||||
|
cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[0] = (cmd->resp_data[0] << 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sdhc_cdns_ops cdns_sdmmc_ops = {
|
||||||
|
.init = sdhc_cdns_init,
|
||||||
|
.send_cmd = sdhc_cdns_send_cmd,
|
||||||
|
.card_present = sdhc_cdns_card_present,
|
||||||
|
.set_ios = sdhc_cdns_set_ios,
|
||||||
|
.prepare = sdhc_cdns_prepare,
|
||||||
|
.cache_invd = sdhc_cdns_cache_invd,
|
||||||
|
.busy = sdhc_cdns_busy,
|
||||||
|
.reset = sdhc_cdns_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info,
|
||||||
|
const struct sdhc_cdns_ops **cb_sdmmc_ops)
|
||||||
|
{
|
||||||
|
__ASSERT_NO_MSG((params != NULL) &&
|
||||||
|
((params->reg_base & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
((params->desc_size & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
((params->reg_phy & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
(params->desc_size > 0) &&
|
||||||
|
(params->clk_rate > 0) &&
|
||||||
|
((params->bus_width == MMC_BUS_WIDTH_1) ||
|
||||||
|
(params->bus_width == MMC_BUS_WIDTH_4) ||
|
||||||
|
(params->bus_width == MMC_BUS_WIDTH_8)));
|
||||||
|
|
||||||
|
memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params));
|
||||||
|
cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type;
|
||||||
|
*cb_sdmmc_ops = &cdns_sdmmc_ops;
|
||||||
|
|
||||||
|
cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
}
|
489
drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h
Normal file
489
drivers/sdhc/sdhc_cdns/sdhc_cdns_ll.h
Normal file
|
@ -0,0 +1,489 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/cache.h>
|
||||||
|
#include <zephyr/drivers/sdhc.h>
|
||||||
|
|
||||||
|
/* HRS09 */
|
||||||
|
#define CDNS_HRS09_PHY_SW_RESET BIT(0)
|
||||||
|
#define CDNS_HRS09_PHY_INIT_COMP BIT(1)
|
||||||
|
#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2)
|
||||||
|
#define CDNS_HRS09_EXT_WR_MODE 3
|
||||||
|
#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3)
|
||||||
|
#define CDNS_HRS09_RDCMD_EN 15
|
||||||
|
#define CDNS_HRS09_RDCMD(x) ((x) << 15)
|
||||||
|
#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* HRS00 */
|
||||||
|
#define CDNS_HRS00_SWR BIT(0)
|
||||||
|
|
||||||
|
/* CMD_DATA_OUTPUT */
|
||||||
|
#define SDHC_CDNS_HRS16 0x40
|
||||||
|
|
||||||
|
/* SRS09 */
|
||||||
|
#define CDNS_SRS09_STAT_DAT_BUSY BIT(2)
|
||||||
|
#define CDNS_SRS09_CI BIT(16)
|
||||||
|
|
||||||
|
/* SRS10 */
|
||||||
|
#define CDNS_SRS10_DTW 1
|
||||||
|
#define CDNS_SRS10_EDTW 5
|
||||||
|
#define CDNS_SRS10_BP 8
|
||||||
|
#define CDNS_SRS10_BVS 9
|
||||||
|
|
||||||
|
/* data bus width */
|
||||||
|
#define WIDTH_BIT1 CDNS_SRS10_DTW
|
||||||
|
#define WIDTH_BIT4 CDNS_SRS10_DTW
|
||||||
|
#define WIDTH_BIT8 CDNS_SRS10_EDTW
|
||||||
|
|
||||||
|
/* SRS11 */
|
||||||
|
#define CDNS_SRS11_ICE BIT(0)
|
||||||
|
#define CDNS_SRS11_ICS BIT(1)
|
||||||
|
#define CDNS_SRS11_SDCE BIT(2)
|
||||||
|
#define CDNS_SRS11_USDCLKFS 6
|
||||||
|
#define CDNS_SRS11_SDCLKFS 8
|
||||||
|
#define CDNS_SRS11_DTCV 16
|
||||||
|
#define CDNS_SRS11_SRFA BIT(24)
|
||||||
|
#define CDNS_SRS11_SRCMD BIT(25)
|
||||||
|
#define CDNS_SRS11_SRDAT BIT(26)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This value determines the interval by which DAT line timeouts are detected
|
||||||
|
* The interval can be computed as below:
|
||||||
|
* • 1111b - Reserved
|
||||||
|
* • 1110b - t_sdmclk*2(27+2)
|
||||||
|
* • 1101b - t_sdmclk*2(26+2)
|
||||||
|
*/
|
||||||
|
#define READ_CLK (0xa << 16)
|
||||||
|
#define WRITE_CLK (0xe << 16)
|
||||||
|
#define DTC_VAL 0xE
|
||||||
|
|
||||||
|
/* SRS12 */
|
||||||
|
#define CDNS_SRS12_CC 0U
|
||||||
|
#define CDNS_SRS12_TC 1
|
||||||
|
#define CDNS_SRS12_EINT 15
|
||||||
|
|
||||||
|
/* SRS01 */
|
||||||
|
#define CDNS_SRS01_BLK_SIZE 0U
|
||||||
|
#define CDNS_SRS01_SDMA_BUF 7 << 12
|
||||||
|
#define CDNS_SRS01_BLK_COUNT_CT 16
|
||||||
|
|
||||||
|
/* SRS15 Registers */
|
||||||
|
#define CDNS_SRS15_SDR12 0U
|
||||||
|
#define CDNS_SRS15_SDR25 BIT(16)
|
||||||
|
#define CDNS_SRS15_SDR50 (2 << 16)
|
||||||
|
#define CDNS_SRS15_SDR104 (3 << 16)
|
||||||
|
#define CDNS_SRS15_DDR50 (4 << 16)
|
||||||
|
/* V18SE is 0 for DS and HS, 1 for UHS-I */
|
||||||
|
#define CDNS_SRS15_V18SE BIT(19)
|
||||||
|
#define CDNS_SRS15_CMD23_EN BIT(27)
|
||||||
|
/* HC4E is 0 means version 3.0 and 1 means v 4.0 */
|
||||||
|
#define CDNS_SRS15_HV4E BIT(28)
|
||||||
|
#define CDNS_SRS15_BIT_AD_32 0U
|
||||||
|
#define CDNS_SRS15_BIT_AD_64 BIT(29)
|
||||||
|
#define CDNS_SRS15_PVE BIT(31)
|
||||||
|
|
||||||
|
/* Combo PHY */
|
||||||
|
#define PHY_DQ_TIMING_REG 0x0
|
||||||
|
#define PHY_DQS_TIMING_REG 0x04
|
||||||
|
#define PHY_GATE_LPBK_CTRL_REG 0x08
|
||||||
|
#define PHY_DLL_MASTER_CTRL_REG 0x0C
|
||||||
|
#define PHY_DLL_SLAVE_CTRL_REG 0x10
|
||||||
|
#define PHY_CTRL_REG 0x80
|
||||||
|
|
||||||
|
#define PERIPHERAL_SDMMC_MASK 0x60
|
||||||
|
#define PERIPHERAL_SDMMC_OFFSET 6
|
||||||
|
#define DFI_INTF_MASK 0x1
|
||||||
|
|
||||||
|
/* PHY_DQS_TIMING_REG */
|
||||||
|
#define CP_USE_EXT_LPBK_DQS(x) (x << 22)
|
||||||
|
#define CP_USE_LPBK_DQS(x) (x << 21)
|
||||||
|
#define CP_USE_PHONY_DQS(x) (x << 20)
|
||||||
|
#define CP_USE_PHONY_DQS_CMD(x) (x << 19)
|
||||||
|
|
||||||
|
/* PHY_GATE_LPBK_CTRL_REG */
|
||||||
|
#define CP_SYNC_METHOD(x) ((x) << 31)
|
||||||
|
#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28)
|
||||||
|
#define CP_RD_DEL_SEL(x) ((x) << 19)
|
||||||
|
#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18)
|
||||||
|
#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6)
|
||||||
|
|
||||||
|
/* PHY_DLL_MASTER_CTRL_REG */
|
||||||
|
#define CP_DLL_BYPASS_MODE(x) ((x) << 23)
|
||||||
|
#define CP_DLL_START_POINT(x) ((x) << 0)
|
||||||
|
|
||||||
|
/* PHY_DLL_SLAVE_CTRL_REG */
|
||||||
|
#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24)
|
||||||
|
#define CP_CLK_WRDQS_DELAY(x) ((x) << 16)
|
||||||
|
#define CP_CLK_WR_DELAY(x) ((x) << 8)
|
||||||
|
#define CP_READ_DQS_DELAY(x) (x)
|
||||||
|
|
||||||
|
/* PHY_DQ_TIMING_REG */
|
||||||
|
#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31)
|
||||||
|
#define CP_IO_MASK_END(x) ((x) << 27)
|
||||||
|
#define CP_IO_MASK_START(x) ((x) << 24)
|
||||||
|
#define CP_DATA_SELECT_OE_END(x) (x)
|
||||||
|
|
||||||
|
/* SW RESET REG */
|
||||||
|
#define SDHC_CDNS_HRS00 (0x00)
|
||||||
|
#define CDNS_HRS00_SWR BIT(0)
|
||||||
|
|
||||||
|
/* PHY access port */
|
||||||
|
#define SDHC_CDNS_HRS04 0x10
|
||||||
|
#define CDNS_HRS04_ADDR GENMASK(5, 0)
|
||||||
|
|
||||||
|
/* PHY data access port */
|
||||||
|
#define SDHC_CDNS_HRS05 0x14
|
||||||
|
|
||||||
|
/* eMMC control registers */
|
||||||
|
#define SDHC_CDNS_HRS06 0x18
|
||||||
|
|
||||||
|
/* PHY_CTRL_REG */
|
||||||
|
#define CP_PHONY_DQS_TIMING_MASK 0x3F
|
||||||
|
#define CP_PHONY_DQS_TIMING_SHIFT 4
|
||||||
|
|
||||||
|
/* SRS */
|
||||||
|
#define SDHC_CDNS_SRS00 0x200
|
||||||
|
#define SDHC_CDNS_SRS01 0x204
|
||||||
|
#define SDHC_CDNS_SRS02 0x208
|
||||||
|
#define SDHC_CDNS_SRS03 0x20c
|
||||||
|
#define SDHC_CDNS_SRS04 0x210
|
||||||
|
#define SDHC_CDNS_SRS05 0x214
|
||||||
|
#define SDHC_CDNS_SRS06 0x218
|
||||||
|
#define SDHC_CDNS_SRS07 0x21C
|
||||||
|
#define SDHC_CDNS_SRS08 0x220
|
||||||
|
#define SDHC_CDNS_SRS09 0x224
|
||||||
|
#define SDHC_CDNS_SRS10 0x228
|
||||||
|
#define SDHC_CDNS_SRS11 0x22C
|
||||||
|
#define SDHC_CDNS_SRS12 0x230
|
||||||
|
#define SDHC_CDNS_SRS13 0x234
|
||||||
|
#define SDHC_CDNS_SRS14 0x238
|
||||||
|
#define SDHC_CDNS_SRS15 0x23c
|
||||||
|
#define SDHC_CDNS_SRS21 0x254
|
||||||
|
#define SDHC_CDNS_SRS22 0x258
|
||||||
|
#define SDHC_CDNS_SRS23 0x25c
|
||||||
|
|
||||||
|
/* SRS00 */
|
||||||
|
#define CDNS_SRS00_SAAR 1
|
||||||
|
|
||||||
|
/* SRS03 */
|
||||||
|
#define CDNS_SRS03_CMD_START BIT(31)
|
||||||
|
#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29)
|
||||||
|
#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21)
|
||||||
|
#define CDNS_SRS03_CMD_SEND_INIT BIT(15)
|
||||||
|
/* Command type */
|
||||||
|
#define CDNS_SRS03_CMD_TYPE BIT(22)
|
||||||
|
#define CMD_STOP_ABORT_CMD (3 << 22)
|
||||||
|
#define CMD_RESUME_CMD (2 << 22)
|
||||||
|
#define CMD_SUSPEND_CMD BIT(22)
|
||||||
|
#define CDNS_SRS03_DATA_PRSNT BIT(21)
|
||||||
|
#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20)
|
||||||
|
#define CDNS_SRS03_CMD_READ BIT(4)
|
||||||
|
#define CDNS_SRS03_MULTI_BLK_READ BIT(5)
|
||||||
|
#define CDNS_SRS03_RESP_ERR BIT(7)
|
||||||
|
#define CDNS_SRS03_RESP_CRC BIT(19)
|
||||||
|
#define CDNS_SRS03_CMD_DONE BIT(0)
|
||||||
|
/* Response type select */
|
||||||
|
#define CDNS_SRS03_RES_TYPE_SEL BIT(16)
|
||||||
|
#define RES_TYPE_SEL_48 (2 << 16)
|
||||||
|
#define RES_TYPE_SEL_136 (1 << 16)
|
||||||
|
#define RES_TYPE_SEL_48_B (3 << 16)
|
||||||
|
#define RES_TYPE_SEL_NO (0 << 16)
|
||||||
|
/* Auto CMD Enable */
|
||||||
|
#define CDNS_SRS03_AUTO_CMD_EN BIT(2)
|
||||||
|
#define AUTO_CMD23 (2 << 2)
|
||||||
|
#define AUTO_CMD12 BIT(2)
|
||||||
|
#define AUTO_CMD_AUTO (3 << 2)
|
||||||
|
#define CDNS_SRS03_COM_IDX 24
|
||||||
|
#define ERROR_INT BIT(15)
|
||||||
|
#define CDNS_SRS03_DMA_EN BIT(0)
|
||||||
|
#define CDNS_SRS03_BLK_CNT_EN BIT(1)
|
||||||
|
|
||||||
|
/* HRS07 */
|
||||||
|
#define SDHC_CDNS_HRS07 0x1c
|
||||||
|
#define CDNS_HRS07_IDELAY_VAL(x) (x)
|
||||||
|
#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* PHY reset port */
|
||||||
|
#define SDHC_CDNS_HRS09 0x24
|
||||||
|
|
||||||
|
/* HRS10 */
|
||||||
|
/* PHY reset port */
|
||||||
|
#define SDHC_CDNS_HRS10 0x28
|
||||||
|
|
||||||
|
/* HCSDCLKADJ DATA; DDR Mode */
|
||||||
|
#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* HRS16 */
|
||||||
|
#define CDNS_HRS16_WRCMD0_DLY(x) (x)
|
||||||
|
#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4)
|
||||||
|
#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8)
|
||||||
|
#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12)
|
||||||
|
#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16)
|
||||||
|
#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20)
|
||||||
|
#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24)
|
||||||
|
#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28)
|
||||||
|
|
||||||
|
/* Shared Macros */
|
||||||
|
#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \
|
||||||
|
(SDMMC_CDN_##_reg))
|
||||||
|
|
||||||
|
/* MMC Peripheral Definition */
|
||||||
|
#define MMC_BLOCK_SIZE 512U
|
||||||
|
#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1)
|
||||||
|
#define MMC_BOOT_CLK_RATE (400 * 1000)
|
||||||
|
|
||||||
|
#define OCR_POWERUP BIT(31)
|
||||||
|
#define OCR_HCS BIT(30)
|
||||||
|
|
||||||
|
#define OCR_3_5_3_6 BIT(23)
|
||||||
|
#define OCR_3_4_3_5 BIT(22)
|
||||||
|
#define OCR_3_3_3_4 BIT(21)
|
||||||
|
#define OCR_3_2_3_3 BIT(20)
|
||||||
|
#define OCR_3_1_3_2 BIT(19)
|
||||||
|
#define OCR_3_0_3_1 BIT(18)
|
||||||
|
#define OCR_2_9_3_0 BIT(17)
|
||||||
|
#define OCR_2_8_2_9 BIT(16)
|
||||||
|
#define OCR_2_7_2_8 BIT(15)
|
||||||
|
#define OCR_VDD_MIN_2V7 GENMASK(23, 15)
|
||||||
|
#define OCR_VDD_MIN_2V0 GENMASK(14, 8)
|
||||||
|
#define OCR_VDD_MIN_1V7 BIT(7)
|
||||||
|
|
||||||
|
#define MMC_RSP_48 BIT(0)
|
||||||
|
#define MMC_RSP_136 BIT(1) /* 136 bit response */
|
||||||
|
#define MMC_RSP_CRC BIT(2) /* expect valid crc */
|
||||||
|
#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */
|
||||||
|
#define MMC_RSP_BUSY BIT(4) /* device may be busy */
|
||||||
|
|
||||||
|
/* JEDEC 4.51 chapter 6.12 */
|
||||||
|
#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY)
|
||||||
|
#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_R3 (MMC_RSP_48)
|
||||||
|
#define MMC_RESPONSE_R4 (MMC_RSP_48)
|
||||||
|
#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX)
|
||||||
|
#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX)
|
||||||
|
#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_NONE 0
|
||||||
|
|
||||||
|
/* Value randomly chosen for eMMC RCA, it should be > 1 */
|
||||||
|
#define MMC_FIX_RCA 6
|
||||||
|
#define RCA_SHIFT_OFFSET 16
|
||||||
|
|
||||||
|
#define CMD_EXTCSD_PARTITION_CONFIG 179
|
||||||
|
#define CMD_EXTCSD_BUS_WIDTH 183
|
||||||
|
#define CMD_EXTCSD_HS_TIMING 185
|
||||||
|
#define CMD_EXTCSD_SEC_CNT 212
|
||||||
|
|
||||||
|
#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3)
|
||||||
|
#define PART_CFG_PARTITION1_ACCESS 1
|
||||||
|
|
||||||
|
/* Values in EXT CSD register */
|
||||||
|
#define MMC_BUS_WIDTH_1 0
|
||||||
|
#define MMC_BUS_WIDTH_4 1
|
||||||
|
#define MMC_BUS_WIDTH_8 2
|
||||||
|
#define MMC_BUS_WIDTH_DDR_4 5
|
||||||
|
#define MMC_BUS_WIDTH_DDR_8 6
|
||||||
|
#define MMC_BOOT_MODE_BACKWARD 0
|
||||||
|
#define MMC_BOOT_MODE_HS_TIMING BIT(3)
|
||||||
|
#define MMC_BOOT_MODE_DDR (2 << 3)
|
||||||
|
|
||||||
|
#define EXTCSD_SET_CMD 0
|
||||||
|
#define EXTCSD_SET_BITS BIT(24)
|
||||||
|
#define EXTCSD_CLR_BITS (2 << 24)
|
||||||
|
#define EXTCSD_WRITE_BYTES (3 << 24)
|
||||||
|
#define EXTCSD_CMD(x) (((x) & 0xff) << 16)
|
||||||
|
#define EXTCSD_VALUE(x) (((x) & 0xff) << 8)
|
||||||
|
#define EXTCSD_CMD_SET_NORMAL 1
|
||||||
|
|
||||||
|
#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0)
|
||||||
|
#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3)
|
||||||
|
#define CSD_TRAN_SPEED_MULT_SHIFT 3
|
||||||
|
|
||||||
|
#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9)
|
||||||
|
#define STATUS_READY_FOR_DATA BIT(8)
|
||||||
|
#define STATUS_SWITCH_ERROR BIT(7)
|
||||||
|
#define MMC_GET_STATE(x) (((x) >> 9) & 0xf)
|
||||||
|
#define MMC_STATE_IDLE 0
|
||||||
|
#define MMC_STATE_READY 1
|
||||||
|
#define MMC_STATE_IDENT 2
|
||||||
|
#define MMC_STATE_STBY 3
|
||||||
|
#define MMC_STATE_TRAN 4
|
||||||
|
#define MMC_STATE_DATA 5
|
||||||
|
#define MMC_STATE_RCV 6
|
||||||
|
#define MMC_STATE_PRG 7
|
||||||
|
#define MMC_STATE_DIS 8
|
||||||
|
#define MMC_STATE_BTST 9
|
||||||
|
#define MMC_STATE_SLP 10
|
||||||
|
|
||||||
|
#define MMC_FLAG_CMD23 1
|
||||||
|
|
||||||
|
#define CMD8_CHECK_PATTERN 0xAA
|
||||||
|
#define VHS_2_7_3_6_V BIT(8)
|
||||||
|
|
||||||
|
#define SD_SCR_BUS_WIDTH_1 BIT(8)
|
||||||
|
#define SD_SCR_BUS_WIDTH_4 BIT(10)
|
||||||
|
|
||||||
|
/* ADMA table component */
|
||||||
|
#define ADMA_DESC_ATTR_VALID BIT(0)
|
||||||
|
#define ADMA_DESC_ATTR_END BIT(1)
|
||||||
|
#define ADMA_DESC_ATTR_INT BIT(2)
|
||||||
|
#define ADMA_DESC_ATTR_ACT1 BIT(4)
|
||||||
|
#define ADMA_DESC_ATTR_ACT2 BIT(5)
|
||||||
|
#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2
|
||||||
|
|
||||||
|
/* SRS10 Register */
|
||||||
|
#define LEDC BIT(0)
|
||||||
|
#define DT_WIDTH BIT(1)
|
||||||
|
#define HS_EN BIT(2)
|
||||||
|
/* Conf depends on SRS15.HV4E */
|
||||||
|
#define SDMA 0
|
||||||
|
#define ADMA2_32 (2 << 3)
|
||||||
|
#define ADMA2_64 (3 << 3)
|
||||||
|
/* here 0 defines the 64 Kb size */
|
||||||
|
#define MAX_64KB_PAGE 0
|
||||||
|
|
||||||
|
struct sdmmc_cmd {
|
||||||
|
unsigned int cmd_idx;
|
||||||
|
unsigned int cmd_arg;
|
||||||
|
unsigned int resp_type;
|
||||||
|
unsigned int resp_data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_ops {
|
||||||
|
/* init function for card */
|
||||||
|
int (*init)(void);
|
||||||
|
/* busy check function for card */
|
||||||
|
int (*busy)(void);
|
||||||
|
/* card_present function check for card */
|
||||||
|
int (*card_present)(void);
|
||||||
|
/* reset the card */
|
||||||
|
int (*reset)(void);
|
||||||
|
/* send command and respective argument */
|
||||||
|
int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data);
|
||||||
|
/* io set up for card */
|
||||||
|
int (*set_ios)(unsigned int clk, unsigned int width);
|
||||||
|
/* prepare dma descriptors */
|
||||||
|
int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data);
|
||||||
|
/* cache invd api */
|
||||||
|
int (*cache_invd)(int lba, uintptr_t buf, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Combo Phy reg */
|
||||||
|
struct sdhc_cdns_combo_phy {
|
||||||
|
uint32_t cp_clk_wr_delay;
|
||||||
|
uint32_t cp_clk_wrdqs_delay;
|
||||||
|
uint32_t cp_data_select_oe_end;
|
||||||
|
uint32_t cp_dll_bypass_mode;
|
||||||
|
uint32_t cp_dll_locked_mode;
|
||||||
|
uint32_t cp_dll_start_point;
|
||||||
|
uint32_t cp_gate_cfg_always_on;
|
||||||
|
uint32_t cp_io_mask_always_on;
|
||||||
|
uint32_t cp_io_mask_end;
|
||||||
|
uint32_t cp_io_mask_start;
|
||||||
|
uint32_t cp_rd_del_sel;
|
||||||
|
uint32_t cp_read_dqs_cmd_delay;
|
||||||
|
uint32_t cp_read_dqs_delay;
|
||||||
|
uint32_t cp_sw_half_cycle_shift;
|
||||||
|
uint32_t cp_sync_method;
|
||||||
|
uint32_t cp_underrun_suppress;
|
||||||
|
uint32_t cp_use_ext_lpbk_dqs;
|
||||||
|
uint32_t cp_use_lpbk_dqs;
|
||||||
|
uint32_t cp_use_phony_dqs;
|
||||||
|
uint32_t cp_use_phony_dqs_cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sdmmc reg */
|
||||||
|
struct sdhc_cdns_sdmmc {
|
||||||
|
uint32_t sdhc_extended_rd_mode;
|
||||||
|
uint32_t sdhc_extended_wr_mode;
|
||||||
|
uint32_t sdhc_hcsdclkadj;
|
||||||
|
uint32_t sdhc_idelay_val;
|
||||||
|
uint32_t sdhc_rdcmd_en;
|
||||||
|
uint32_t sdhc_rddata_en;
|
||||||
|
uint32_t sdhc_rw_compensate;
|
||||||
|
uint32_t sdhc_sdcfsh;
|
||||||
|
uint32_t sdhc_sdcfsl;
|
||||||
|
uint32_t sdhc_wrcmd0_dly;
|
||||||
|
uint32_t sdhc_wrcmd0_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrcmd1_dly;
|
||||||
|
uint32_t sdhc_wrcmd1_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrdata0_dly;
|
||||||
|
uint32_t sdhc_wrdata0_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrdata1_dly;
|
||||||
|
uint32_t sdhc_wrdata1_sdclk_dly;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sdmmc_device_mode {
|
||||||
|
/* Identification */
|
||||||
|
SD_DS_ID,
|
||||||
|
/* Default speed */
|
||||||
|
SD_DS,
|
||||||
|
/* High speed */
|
||||||
|
SD_HS,
|
||||||
|
/* Ultra high speed SDR12 */
|
||||||
|
SD_UHS_SDR12,
|
||||||
|
/* Ultra high speed SDR25 */
|
||||||
|
SD_UHS_SDR25,
|
||||||
|
/* Ultra high speed SDR`50 */
|
||||||
|
SD_UHS_SDR50,
|
||||||
|
/* Ultra high speed SDR104 */
|
||||||
|
SD_UHS_SDR104,
|
||||||
|
/* Ultra high speed DDR50 */
|
||||||
|
SD_UHS_DDR50,
|
||||||
|
/* SDR backward compatible */
|
||||||
|
EMMC_SDR_BC,
|
||||||
|
/* SDR */
|
||||||
|
EMMC_SDR,
|
||||||
|
/* DDR */
|
||||||
|
EMMC_DDR,
|
||||||
|
/* High speed 200Mhz in SDR */
|
||||||
|
EMMC_HS200,
|
||||||
|
/* High speed 200Mhz in DDR */
|
||||||
|
EMMC_HS400,
|
||||||
|
/* High speed 200Mhz in SDR with enhanced strobe */
|
||||||
|
EMMC_HS400ES,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_params {
|
||||||
|
uintptr_t reg_base;
|
||||||
|
uintptr_t reg_phy;
|
||||||
|
uintptr_t desc_base;
|
||||||
|
size_t desc_size;
|
||||||
|
int clk_rate;
|
||||||
|
int bus_width;
|
||||||
|
unsigned int flags;
|
||||||
|
enum sdmmc_device_mode cdn_sdmmc_dev_type;
|
||||||
|
uint32_t combophy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdmmc_device_info {
|
||||||
|
/* Size of device in bytes */
|
||||||
|
unsigned long long device_size;
|
||||||
|
/* Block size in bytes */
|
||||||
|
unsigned int block_size;
|
||||||
|
/* Max bus freq in Hz */
|
||||||
|
unsigned int max_bus_freq;
|
||||||
|
/* OCR voltage */
|
||||||
|
unsigned int ocr_voltage;
|
||||||
|
/* Type of MMC */
|
||||||
|
enum sdmmc_device_mode cdn_sdmmc_dev_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*descriptor structure with 8 byte alignment*/
|
||||||
|
struct sdhc_cdns_desc {
|
||||||
|
/* 8 bit attribute */
|
||||||
|
uint8_t attr;
|
||||||
|
/* reserved bits in desc */
|
||||||
|
uint8_t reserved;
|
||||||
|
/* page length for the descriptor */
|
||||||
|
uint16_t len;
|
||||||
|
/* lower 32 bits for buffer (64 bit addressing) */
|
||||||
|
uint32_t addr_lo;
|
||||||
|
/* higher 32 bits for buffer (64 bit addressing) */
|
||||||
|
uint32_t addr_hi;
|
||||||
|
} __aligned(8);
|
||||||
|
|
||||||
|
void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info,
|
||||||
|
const struct sdhc_cdns_ops **cb_sdmmc_ops);
|
791
drivers/sdhc/sdhc_cdns_ll.c
Normal file
791
drivers/sdhc/sdhc_cdns_ll.c
Normal file
|
@ -0,0 +1,791 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "sdhc_cdns_ll.h"
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* card busy and present */
|
||||||
|
#define CARD_BUSY 1
|
||||||
|
#define CARD_NOT_BUSY 0
|
||||||
|
#define CARD_PRESENT 1
|
||||||
|
|
||||||
|
/* SRS12 error mask */
|
||||||
|
#define CDNS_SRS12_ERR_MASK 0xFFFF8000U
|
||||||
|
#define CDNS_CSD_BYTE_MASK 0x000000FFU
|
||||||
|
|
||||||
|
/* General define */
|
||||||
|
#define SDHC_REG_MASK 0xFFFFFFFFU
|
||||||
|
#define SD_HOST_BLOCK_SIZE 0x200
|
||||||
|
|
||||||
|
#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024)
|
||||||
|
#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1)
|
||||||
|
|
||||||
|
#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH)
|
||||||
|
#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH)
|
||||||
|
#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE)
|
||||||
|
#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE)
|
||||||
|
#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE)
|
||||||
|
#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE)
|
||||||
|
#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE)
|
||||||
|
|
||||||
|
#define CARD_REG_TIME_DELAY_US 100000
|
||||||
|
#define WAIT_ICS_TIME_DELAY_US 5000
|
||||||
|
#define RESET_SRS14 0x00000000
|
||||||
|
|
||||||
|
static struct sdhc_cdns_params cdns_params;
|
||||||
|
static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info;
|
||||||
|
static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info;
|
||||||
|
|
||||||
|
/* Function to write general phy registers */
|
||||||
|
static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value,
|
||||||
|
uint32_t phy_reg_data, uint32_t phy_reg_data_value)
|
||||||
|
{
|
||||||
|
uint32_t data = 0;
|
||||||
|
|
||||||
|
/* Set PHY register address, write HRS04*/
|
||||||
|
sys_write32(phy_reg_addr_value, phy_reg_addr);
|
||||||
|
|
||||||
|
/* Set PHY register data, write HRS05 */
|
||||||
|
sys_write32(phy_reg_data_value, phy_reg_data);
|
||||||
|
data = sys_read32(phy_reg_data);
|
||||||
|
|
||||||
|
if (data != phy_reg_data_value) {
|
||||||
|
LOG_ERR("PHY_REG_DATA is not set properly");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res)
|
||||||
|
{
|
||||||
|
/* Wait status command response ready */
|
||||||
|
if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS)
|
||||||
|
== CDNS_SRS11_ICS), timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Timed out waiting for ICS response");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_busy(void)
|
||||||
|
{
|
||||||
|
unsigned int data;
|
||||||
|
|
||||||
|
data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09);
|
||||||
|
return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_card_present(void)
|
||||||
|
{
|
||||||
|
uint32_t timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
|
||||||
|
if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09))
|
||||||
|
& CDNS_SRS09_CI) == CDNS_SRS09_CI),
|
||||||
|
timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Card detection timeout");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CARD_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_vol_reset(void)
|
||||||
|
{
|
||||||
|
/* Reset embedded card */
|
||||||
|
sys_write32((7 << CDNS_SRS10_BVS) | (0 << CDNS_SRS10_BP),
|
||||||
|
(cdns_params.reg_base + SDHC_CDNS_SRS10));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Turn on supply voltage
|
||||||
|
* CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode
|
||||||
|
*/
|
||||||
|
sys_write32((7 << CDNS_SRS10_BVS) | (1 << CDNS_SRS10_BP),
|
||||||
|
(cdns_params.reg_base + SDHC_CDNS_SRS10));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Values are taken from IP documents and calc_setting.py script
|
||||||
|
* with input value- mode sd_ds,
|
||||||
|
* sdmclk 5000,
|
||||||
|
* sdclk 10000,
|
||||||
|
* iocell_input_delay 2500,
|
||||||
|
* iocell_output_delay 2500 and
|
||||||
|
* delay_element 24
|
||||||
|
*/
|
||||||
|
void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
/* Values are taken by the reference of cadence IP documents */
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_sync_method = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1;
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1;
|
||||||
|
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0;
|
||||||
|
sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phy register programing for phy init */
|
||||||
|
static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DQS_TIMING_REG
|
||||||
|
* This register controls the DQS related timing
|
||||||
|
*/
|
||||||
|
value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs))
|
||||||
|
| (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs))
|
||||||
|
| (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs))
|
||||||
|
| (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DQS_TIMING_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_GATE_LPBK_CTRL_REG
|
||||||
|
* This register controls the gate and loopback control related timing.
|
||||||
|
*/
|
||||||
|
value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method))
|
||||||
|
| (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift))
|
||||||
|
| (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel))
|
||||||
|
| (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress))
|
||||||
|
| (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming");
|
||||||
|
return -ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DLL_MASTER_CTRL_REG
|
||||||
|
* This register holds the control for the Master DLL logic.
|
||||||
|
*/
|
||||||
|
value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode))
|
||||||
|
| (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DLL_SLAVE_CTRL_REG
|
||||||
|
* This register holds the control for the slave DLL logic.
|
||||||
|
*/
|
||||||
|
value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay))
|
||||||
|
| (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay))
|
||||||
|
| (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay))
|
||||||
|
| (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay));
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_CTRL_REG
|
||||||
|
* This register handles the global control settings for the PHY.
|
||||||
|
*/
|
||||||
|
sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS04);
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05);
|
||||||
|
|
||||||
|
/* phony_dqs_timing=0 */
|
||||||
|
value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT);
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05);
|
||||||
|
|
||||||
|
/* switch off DLL_RESET */
|
||||||
|
do {
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
value |= CDNS_HRS09_PHY_SW_RESET;
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
/* polling PHY_INIT_COMPLETE */
|
||||||
|
} while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program PHY_DQ_TIMING_REG
|
||||||
|
* This register controls the DQ related timing.
|
||||||
|
*/
|
||||||
|
sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U;
|
||||||
|
value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on))
|
||||||
|
| (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end))
|
||||||
|
| (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start))
|
||||||
|
| (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end));
|
||||||
|
|
||||||
|
ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04,
|
||||||
|
cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS05, value);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Error in PHY_DQ_TIMING_REG programming");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = arch_dcache_invd_range((void *)buf, size);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DMA preparation for the read and write operation */
|
||||||
|
static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff,
|
||||||
|
struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
struct sdhc_cdns_desc *desc;
|
||||||
|
uint32_t desc_cnt, i;
|
||||||
|
uintptr_t base;
|
||||||
|
uint64_t desc_base;
|
||||||
|
uint32_t size = data->blocks * data->block_size;
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) &&
|
||||||
|
(cdns_params.desc_size > 0) &&
|
||||||
|
((cdns_params.desc_size & MMC_BLOCK_MASK) == 0));
|
||||||
|
|
||||||
|
arch_dcache_flush_range((void *)dma_buff, size);
|
||||||
|
|
||||||
|
desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) /
|
||||||
|
(SDMMC_DMA_MAX_BUFFER_SIZE);
|
||||||
|
__ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) <
|
||||||
|
cdns_params.desc_size);
|
||||||
|
|
||||||
|
if (desc_cnt > CONFIG_CDNS_DESC_COUNT) {
|
||||||
|
LOG_ERR("Requested data transfer length %u greater than configured length %u",
|
||||||
|
size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creating descriptor as per the desc_count and linked list of
|
||||||
|
* descriptor for contiguous desc alignment
|
||||||
|
*/
|
||||||
|
base = cdns_params.reg_base;
|
||||||
|
desc = (struct sdhc_cdns_desc *)cdns_params.desc_base;
|
||||||
|
desc_base = (uint64_t)desc;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while ((i+1) < desc_cnt) {
|
||||||
|
desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
|
||||||
|
desc->reserved = 0;
|
||||||
|
desc->len = MAX_64KB_PAGE;
|
||||||
|
desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i);
|
||||||
|
desc->addr_hi = (dma_buff >> 32) & 0xffffffff;
|
||||||
|
size -= SDMMC_DMA_MAX_BUFFER_SIZE;
|
||||||
|
desc++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA |
|
||||||
|
ADMA_DESC_ATTR_END;
|
||||||
|
desc->reserved = 0;
|
||||||
|
desc->len = size;
|
||||||
|
desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i);
|
||||||
|
desc->addr_hi = (dma_buff >> 32) & 0xffffffff;
|
||||||
|
|
||||||
|
sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22);
|
||||||
|
sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23);
|
||||||
|
arch_dcache_flush_range((void *)cdns_params.desc_base,
|
||||||
|
desc_cnt * sizeof(struct sdhc_cdns_desc));
|
||||||
|
|
||||||
|
sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE |
|
||||||
|
data->blocks << CDNS_SRS01_BLK_COUNT_CT | CDNS_SRS01_SDMA_BUF),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS01);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_host_set_clk(int clk)
|
||||||
|
{
|
||||||
|
uint32_t sdclkfsval = 0;
|
||||||
|
uint32_t dtcvval = 0xe;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
sdclkfsval = (cdns_params.clk_rate / 2000) / clk;
|
||||||
|
sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) |
|
||||||
|
(1 << CDNS_SRS11_ICE)), cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable DLL reset */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0);
|
||||||
|
/* Set extended_wr_mode */
|
||||||
|
sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09)
|
||||||
|
& 0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS09));
|
||||||
|
/* Release DLL reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN));
|
||||||
|
|
||||||
|
sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS)
|
||||||
|
| (1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE)),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (width) {
|
||||||
|
case SDHC_BUS_WIDTH1BIT:
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1);
|
||||||
|
break;
|
||||||
|
case SDHC_BUS_WIDTH4BIT:
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4);
|
||||||
|
break;
|
||||||
|
case SDHC_BUS_WIDTH8BIT:
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__ASSERT_NO_MSG(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform clock configuration when SD clock is not gated */
|
||||||
|
if (clk != 0) {
|
||||||
|
ret = sdhc_cdns_host_set_clk(clk);
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("%s: Clock configuration failed", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Programming HRS register for initialisation */
|
||||||
|
static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg,
|
||||||
|
struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg)
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS09, register 42
|
||||||
|
* PHY Control and Status Register
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en))
|
||||||
|
| (CDNS_HRS09_RDCMD(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en))
|
||||||
|
| (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode))
|
||||||
|
| (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS10, register 43
|
||||||
|
* Host Controller SDCLK start point adjustment
|
||||||
|
*/
|
||||||
|
value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS16, register 48
|
||||||
|
* CMD/DAT output delay
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly))
|
||||||
|
| (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly))
|
||||||
|
| (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* program HRS07, register 40
|
||||||
|
* IO Delay Information Register
|
||||||
|
*/
|
||||||
|
value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate))
|
||||||
|
| (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val));
|
||||||
|
sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params)
|
||||||
|
{
|
||||||
|
uint32_t dtcvval, sdclkfsval;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dtcvval = DTC_VAL;
|
||||||
|
sdclkfsval = 0;
|
||||||
|
|
||||||
|
/* Condition for Default speed mode and SDR12 and SDR_BC */
|
||||||
|
if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) {
|
||||||
|
sdclkfsval = 4;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) {
|
||||||
|
sdclkfsval = 2;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) {
|
||||||
|
sdclkfsval = 1;
|
||||||
|
} else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) ||
|
||||||
|
(cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) {
|
||||||
|
sdclkfsval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabling SD clock enable */
|
||||||
|
sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
sys_write32((dtcvval << CDNS_SRS11_DTCV) |
|
||||||
|
(sdclkfsval << CDNS_SRS11_SDCLKFS) | (1 << CDNS_SRS11_ICE),
|
||||||
|
cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable DLL reset */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0);
|
||||||
|
/* Set extended_wr_mode */
|
||||||
|
sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) &
|
||||||
|
0xFFFFFFF7) | (1 << CDNS_HRS09_EXT_WR_MODE)), (cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_HRS09));
|
||||||
|
/* Release DLL reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 1);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, (3 << CDNS_HRS09_RDCMD_EN));
|
||||||
|
|
||||||
|
sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) |
|
||||||
|
(1 << CDNS_SRS11_ICE) | (1 << CDNS_SRS11_SDCE), cdns_params.reg_base
|
||||||
|
+ SDHC_CDNS_SRS11);
|
||||||
|
|
||||||
|
sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_reset(void)
|
||||||
|
{
|
||||||
|
int32_t timeout;
|
||||||
|
|
||||||
|
sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF);
|
||||||
|
|
||||||
|
/* Software reset */
|
||||||
|
sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR);
|
||||||
|
|
||||||
|
/* Wait status command response ready */
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) &
|
||||||
|
CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) {
|
||||||
|
LOG_ERR("Software reset is not completed...timedout");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 1, switch on DLL_RESET */
|
||||||
|
sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_init(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("SoftPhy register configuration failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Configuration for HRS IO reg failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_card_present();
|
||||||
|
if (ret != CARD_PRESENT) {
|
||||||
|
LOG_ERR("SD card does not detect");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_vol_reset();
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("SD/MMC card reset failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sdhc_cdns_set_clk(&cdns_params);
|
||||||
|
if (ret != 0U) {
|
||||||
|
LOG_ERR("Host controller set clk failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data)
|
||||||
|
{
|
||||||
|
uint32_t op = 0;
|
||||||
|
uint32_t value;
|
||||||
|
uintptr_t base;
|
||||||
|
int32_t timeout;
|
||||||
|
uint32_t cmd_indx;
|
||||||
|
uint32_t status_check = 0;
|
||||||
|
|
||||||
|
__ASSERT(cmd, "Assert %s function call", __func__);
|
||||||
|
base = cdns_params.reg_base;
|
||||||
|
cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
switch (cmd->cmd_idx) {
|
||||||
|
case SD_SWITCH:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_WRITE_SINGLE_BLOCK:
|
||||||
|
case SD_READ_SINGLE_BLOCK:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR);
|
||||||
|
sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_WRITE_MULTIPLE_BLOCK:
|
||||||
|
case SD_READ_MULTIPLE_BLOCK:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR);
|
||||||
|
sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_APP_SEND_SCR:
|
||||||
|
op = CDNS_SRS03_DATA_PRSNT;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (cmd->cmd_idx) {
|
||||||
|
case SD_GO_IDLE_STATE:
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_ALL_SEND_CID:
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SEND_IF_COND:
|
||||||
|
op = CDNS_SRS03_CMD_IDX_CHK_EN;
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN);
|
||||||
|
sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_STOP_TRANSMISSION:
|
||||||
|
op = CMD_STOP_ABORT_CMD;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SEND_STATUS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_SELECT_CARD:
|
||||||
|
op = CDNS_SRS03_MULTI_BLK_READ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd->resp_type) {
|
||||||
|
case SD_RSP_TYPE_NONE:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R2:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN |
|
||||||
|
RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R3:
|
||||||
|
op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ |
|
||||||
|
CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_RSP_TYPE_R1:
|
||||||
|
if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx
|
||||||
|
== SD_WRITE_MULTIPLE_BLOCK)) {
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48
|
||||||
|
| CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
} else {
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ
|
||||||
|
| RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC | CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ |
|
||||||
|
CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRC |
|
||||||
|
CDNS_SRS03_CMD_IDX_CHK_EN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) {
|
||||||
|
k_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12);
|
||||||
|
|
||||||
|
sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02);
|
||||||
|
sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14);
|
||||||
|
sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03);
|
||||||
|
|
||||||
|
timeout = CARD_REG_TIME_DELAY_US;
|
||||||
|
if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) &
|
||||||
|
CDNS_SRS03_CMD_DONE) == 1) | (((sys_read32(cdns_params.reg_base +
|
||||||
|
SDHC_CDNS_SRS12)) & ERROR_INT) == ERROR_INT)), timeout, k_busy_wait(1))) {
|
||||||
|
LOG_ERR("Response timeout SRS12");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12);
|
||||||
|
status_check = value & CDNS_SRS12_ERR_MASK;
|
||||||
|
if (status_check != 0U) {
|
||||||
|
LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) {
|
||||||
|
cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04);
|
||||||
|
if (op & RES_TYPE_SEL_136) {
|
||||||
|
cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05);
|
||||||
|
cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06);
|
||||||
|
cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07);
|
||||||
|
|
||||||
|
/* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0],
|
||||||
|
* RESP2[31:0], RESP1[31:0], RESP0[31:0]
|
||||||
|
* Subsystem expects 128 bits response but cadence SDHC sends
|
||||||
|
* 120 bits response from R[127:8]. Bits manupulation to address
|
||||||
|
* the correct responses for the 136 bit response type.
|
||||||
|
*/
|
||||||
|
cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24)
|
||||||
|
& CDNS_CSD_BYTE_MASK));
|
||||||
|
cmd->resp_data[0] = (cmd->resp_data[0] << 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sdhc_cdns_ops cdns_sdmmc_ops = {
|
||||||
|
.init = sdhc_cdns_init,
|
||||||
|
.send_cmd = sdhc_cdns_send_cmd,
|
||||||
|
.card_present = sdhc_cdns_card_present,
|
||||||
|
.set_ios = sdhc_cdns_set_ios,
|
||||||
|
.prepare = sdhc_cdns_prepare,
|
||||||
|
.cache_invd = sdhc_cdns_cache_invd,
|
||||||
|
.busy = sdhc_cdns_busy,
|
||||||
|
.reset = sdhc_cdns_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info,
|
||||||
|
const struct sdhc_cdns_ops **cb_sdmmc_ops)
|
||||||
|
{
|
||||||
|
__ASSERT_NO_MSG((params != NULL) &&
|
||||||
|
((params->reg_base & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
((params->desc_size & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
((params->reg_phy & MMC_BLOCK_MASK) == 0) &&
|
||||||
|
(params->desc_size > 0) &&
|
||||||
|
(params->clk_rate > 0) &&
|
||||||
|
((params->bus_width == MMC_BUS_WIDTH_1) ||
|
||||||
|
(params->bus_width == MMC_BUS_WIDTH_4) ||
|
||||||
|
(params->bus_width == MMC_BUS_WIDTH_8)));
|
||||||
|
|
||||||
|
memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params));
|
||||||
|
cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type;
|
||||||
|
*cb_sdmmc_ops = &cdns_sdmmc_ops;
|
||||||
|
|
||||||
|
cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info);
|
||||||
|
}
|
489
drivers/sdhc/sdhc_cdns_ll.h
Normal file
489
drivers/sdhc/sdhc_cdns_ll.h
Normal file
|
@ -0,0 +1,489 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/cache.h>
|
||||||
|
#include <zephyr/drivers/sdhc.h>
|
||||||
|
|
||||||
|
/* HRS09 */
|
||||||
|
#define CDNS_HRS09_PHY_SW_RESET BIT(0)
|
||||||
|
#define CDNS_HRS09_PHY_INIT_COMP BIT(1)
|
||||||
|
#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2)
|
||||||
|
#define CDNS_HRS09_EXT_WR_MODE 3
|
||||||
|
#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3)
|
||||||
|
#define CDNS_HRS09_RDCMD_EN 15
|
||||||
|
#define CDNS_HRS09_RDCMD(x) ((x) << 15)
|
||||||
|
#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* HRS00 */
|
||||||
|
#define CDNS_HRS00_SWR BIT(0)
|
||||||
|
|
||||||
|
/* CMD_DATA_OUTPUT */
|
||||||
|
#define SDHC_CDNS_HRS16 0x40
|
||||||
|
|
||||||
|
/* SRS09 */
|
||||||
|
#define CDNS_SRS09_STAT_DAT_BUSY BIT(2)
|
||||||
|
#define CDNS_SRS09_CI BIT(16)
|
||||||
|
|
||||||
|
/* SRS10 */
|
||||||
|
#define CDNS_SRS10_DTW 1
|
||||||
|
#define CDNS_SRS10_EDTW 5
|
||||||
|
#define CDNS_SRS10_BP 8
|
||||||
|
#define CDNS_SRS10_BVS 9
|
||||||
|
|
||||||
|
/* data bus width */
|
||||||
|
#define WIDTH_BIT1 CDNS_SRS10_DTW
|
||||||
|
#define WIDTH_BIT4 CDNS_SRS10_DTW
|
||||||
|
#define WIDTH_BIT8 CDNS_SRS10_EDTW
|
||||||
|
|
||||||
|
/* SRS11 */
|
||||||
|
#define CDNS_SRS11_ICE BIT(0)
|
||||||
|
#define CDNS_SRS11_ICS BIT(1)
|
||||||
|
#define CDNS_SRS11_SDCE BIT(2)
|
||||||
|
#define CDNS_SRS11_USDCLKFS 6
|
||||||
|
#define CDNS_SRS11_SDCLKFS 8
|
||||||
|
#define CDNS_SRS11_DTCV 16
|
||||||
|
#define CDNS_SRS11_SRFA BIT(24)
|
||||||
|
#define CDNS_SRS11_SRCMD BIT(25)
|
||||||
|
#define CDNS_SRS11_SRDAT BIT(26)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This value determines the interval by which DAT line timeouts are detected
|
||||||
|
* The interval can be computed as below:
|
||||||
|
* • 1111b - Reserved
|
||||||
|
* • 1110b - t_sdmclk*2(27+2)
|
||||||
|
* • 1101b - t_sdmclk*2(26+2)
|
||||||
|
*/
|
||||||
|
#define READ_CLK (0xa << 16)
|
||||||
|
#define WRITE_CLK (0xe << 16)
|
||||||
|
#define DTC_VAL 0xE
|
||||||
|
|
||||||
|
/* SRS12 */
|
||||||
|
#define CDNS_SRS12_CC 0U
|
||||||
|
#define CDNS_SRS12_TC 1
|
||||||
|
#define CDNS_SRS12_EINT 15
|
||||||
|
|
||||||
|
/* SRS01 */
|
||||||
|
#define CDNS_SRS01_BLK_SIZE 0U
|
||||||
|
#define CDNS_SRS01_SDMA_BUF 7 << 12
|
||||||
|
#define CDNS_SRS01_BLK_COUNT_CT 16
|
||||||
|
|
||||||
|
/* SRS15 Registers */
|
||||||
|
#define CDNS_SRS15_SDR12 0U
|
||||||
|
#define CDNS_SRS15_SDR25 BIT(16)
|
||||||
|
#define CDNS_SRS15_SDR50 (2 << 16)
|
||||||
|
#define CDNS_SRS15_SDR104 (3 << 16)
|
||||||
|
#define CDNS_SRS15_DDR50 (4 << 16)
|
||||||
|
/* V18SE is 0 for DS and HS, 1 for UHS-I */
|
||||||
|
#define CDNS_SRS15_V18SE BIT(19)
|
||||||
|
#define CDNS_SRS15_CMD23_EN BIT(27)
|
||||||
|
/* HC4E is 0 means version 3.0 and 1 means v 4.0 */
|
||||||
|
#define CDNS_SRS15_HV4E BIT(28)
|
||||||
|
#define CDNS_SRS15_BIT_AD_32 0U
|
||||||
|
#define CDNS_SRS15_BIT_AD_64 BIT(29)
|
||||||
|
#define CDNS_SRS15_PVE BIT(31)
|
||||||
|
|
||||||
|
/* Combo PHY */
|
||||||
|
#define PHY_DQ_TIMING_REG 0x0
|
||||||
|
#define PHY_DQS_TIMING_REG 0x04
|
||||||
|
#define PHY_GATE_LPBK_CTRL_REG 0x08
|
||||||
|
#define PHY_DLL_MASTER_CTRL_REG 0x0C
|
||||||
|
#define PHY_DLL_SLAVE_CTRL_REG 0x10
|
||||||
|
#define PHY_CTRL_REG 0x80
|
||||||
|
|
||||||
|
#define PERIPHERAL_SDMMC_MASK 0x60
|
||||||
|
#define PERIPHERAL_SDMMC_OFFSET 6
|
||||||
|
#define DFI_INTF_MASK 0x1
|
||||||
|
|
||||||
|
/* PHY_DQS_TIMING_REG */
|
||||||
|
#define CP_USE_EXT_LPBK_DQS(x) (x << 22)
|
||||||
|
#define CP_USE_LPBK_DQS(x) (x << 21)
|
||||||
|
#define CP_USE_PHONY_DQS(x) (x << 20)
|
||||||
|
#define CP_USE_PHONY_DQS_CMD(x) (x << 19)
|
||||||
|
|
||||||
|
/* PHY_GATE_LPBK_CTRL_REG */
|
||||||
|
#define CP_SYNC_METHOD(x) ((x) << 31)
|
||||||
|
#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28)
|
||||||
|
#define CP_RD_DEL_SEL(x) ((x) << 19)
|
||||||
|
#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18)
|
||||||
|
#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6)
|
||||||
|
|
||||||
|
/* PHY_DLL_MASTER_CTRL_REG */
|
||||||
|
#define CP_DLL_BYPASS_MODE(x) ((x) << 23)
|
||||||
|
#define CP_DLL_START_POINT(x) ((x) << 0)
|
||||||
|
|
||||||
|
/* PHY_DLL_SLAVE_CTRL_REG */
|
||||||
|
#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24)
|
||||||
|
#define CP_CLK_WRDQS_DELAY(x) ((x) << 16)
|
||||||
|
#define CP_CLK_WR_DELAY(x) ((x) << 8)
|
||||||
|
#define CP_READ_DQS_DELAY(x) (x)
|
||||||
|
|
||||||
|
/* PHY_DQ_TIMING_REG */
|
||||||
|
#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31)
|
||||||
|
#define CP_IO_MASK_END(x) ((x) << 27)
|
||||||
|
#define CP_IO_MASK_START(x) ((x) << 24)
|
||||||
|
#define CP_DATA_SELECT_OE_END(x) (x)
|
||||||
|
|
||||||
|
/* SW RESET REG */
|
||||||
|
#define SDHC_CDNS_HRS00 (0x00)
|
||||||
|
#define CDNS_HRS00_SWR BIT(0)
|
||||||
|
|
||||||
|
/* PHY access port */
|
||||||
|
#define SDHC_CDNS_HRS04 0x10
|
||||||
|
#define CDNS_HRS04_ADDR GENMASK(5, 0)
|
||||||
|
|
||||||
|
/* PHY data access port */
|
||||||
|
#define SDHC_CDNS_HRS05 0x14
|
||||||
|
|
||||||
|
/* eMMC control registers */
|
||||||
|
#define SDHC_CDNS_HRS06 0x18
|
||||||
|
|
||||||
|
/* PHY_CTRL_REG */
|
||||||
|
#define CP_PHONY_DQS_TIMING_MASK 0x3F
|
||||||
|
#define CP_PHONY_DQS_TIMING_SHIFT 4
|
||||||
|
|
||||||
|
/* SRS */
|
||||||
|
#define SDHC_CDNS_SRS00 0x200
|
||||||
|
#define SDHC_CDNS_SRS01 0x204
|
||||||
|
#define SDHC_CDNS_SRS02 0x208
|
||||||
|
#define SDHC_CDNS_SRS03 0x20c
|
||||||
|
#define SDHC_CDNS_SRS04 0x210
|
||||||
|
#define SDHC_CDNS_SRS05 0x214
|
||||||
|
#define SDHC_CDNS_SRS06 0x218
|
||||||
|
#define SDHC_CDNS_SRS07 0x21C
|
||||||
|
#define SDHC_CDNS_SRS08 0x220
|
||||||
|
#define SDHC_CDNS_SRS09 0x224
|
||||||
|
#define SDHC_CDNS_SRS10 0x228
|
||||||
|
#define SDHC_CDNS_SRS11 0x22C
|
||||||
|
#define SDHC_CDNS_SRS12 0x230
|
||||||
|
#define SDHC_CDNS_SRS13 0x234
|
||||||
|
#define SDHC_CDNS_SRS14 0x238
|
||||||
|
#define SDHC_CDNS_SRS15 0x23c
|
||||||
|
#define SDHC_CDNS_SRS21 0x254
|
||||||
|
#define SDHC_CDNS_SRS22 0x258
|
||||||
|
#define SDHC_CDNS_SRS23 0x25c
|
||||||
|
|
||||||
|
/* SRS00 */
|
||||||
|
#define CDNS_SRS00_SAAR 1
|
||||||
|
|
||||||
|
/* SRS03 */
|
||||||
|
#define CDNS_SRS03_CMD_START BIT(31)
|
||||||
|
#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29)
|
||||||
|
#define CDNS_SRS03_CMD_UPDATE_CLK_ONLY BIT(21)
|
||||||
|
#define CDNS_SRS03_CMD_SEND_INIT BIT(15)
|
||||||
|
/* Command type */
|
||||||
|
#define CDNS_SRS03_CMD_TYPE BIT(22)
|
||||||
|
#define CMD_STOP_ABORT_CMD (3 << 22)
|
||||||
|
#define CMD_RESUME_CMD (2 << 22)
|
||||||
|
#define CMD_SUSPEND_CMD BIT(22)
|
||||||
|
#define CDNS_SRS03_DATA_PRSNT BIT(21)
|
||||||
|
#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20)
|
||||||
|
#define CDNS_SRS03_CMD_READ BIT(4)
|
||||||
|
#define CDNS_SRS03_MULTI_BLK_READ BIT(5)
|
||||||
|
#define CDNS_SRS03_RESP_ERR BIT(7)
|
||||||
|
#define CDNS_SRS03_RESP_CRC BIT(19)
|
||||||
|
#define CDNS_SRS03_CMD_DONE BIT(0)
|
||||||
|
/* Response type select */
|
||||||
|
#define CDNS_SRS03_RES_TYPE_SEL BIT(16)
|
||||||
|
#define RES_TYPE_SEL_48 (2 << 16)
|
||||||
|
#define RES_TYPE_SEL_136 (1 << 16)
|
||||||
|
#define RES_TYPE_SEL_48_B (3 << 16)
|
||||||
|
#define RES_TYPE_SEL_NO (0 << 16)
|
||||||
|
/* Auto CMD Enable */
|
||||||
|
#define CDNS_SRS03_AUTO_CMD_EN BIT(2)
|
||||||
|
#define AUTO_CMD23 (2 << 2)
|
||||||
|
#define AUTO_CMD12 BIT(2)
|
||||||
|
#define AUTO_CMD_AUTO (3 << 2)
|
||||||
|
#define CDNS_SRS03_COM_IDX 24
|
||||||
|
#define ERROR_INT BIT(15)
|
||||||
|
#define CDNS_SRS03_DMA_EN BIT(0)
|
||||||
|
#define CDNS_SRS03_BLK_CNT_EN BIT(1)
|
||||||
|
|
||||||
|
/* HRS07 */
|
||||||
|
#define SDHC_CDNS_HRS07 0x1c
|
||||||
|
#define CDNS_HRS07_IDELAY_VAL(x) (x)
|
||||||
|
#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* PHY reset port */
|
||||||
|
#define SDHC_CDNS_HRS09 0x24
|
||||||
|
|
||||||
|
/* HRS10 */
|
||||||
|
/* PHY reset port */
|
||||||
|
#define SDHC_CDNS_HRS10 0x28
|
||||||
|
|
||||||
|
/* HCSDCLKADJ DATA; DDR Mode */
|
||||||
|
#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16)
|
||||||
|
|
||||||
|
/* HRS16 */
|
||||||
|
#define CDNS_HRS16_WRCMD0_DLY(x) (x)
|
||||||
|
#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4)
|
||||||
|
#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8)
|
||||||
|
#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12)
|
||||||
|
#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16)
|
||||||
|
#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20)
|
||||||
|
#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24)
|
||||||
|
#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28)
|
||||||
|
|
||||||
|
/* Shared Macros */
|
||||||
|
#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \
|
||||||
|
(SDMMC_CDN_##_reg))
|
||||||
|
|
||||||
|
/* MMC Peripheral Definition */
|
||||||
|
#define MMC_BLOCK_SIZE 512U
|
||||||
|
#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1)
|
||||||
|
#define MMC_BOOT_CLK_RATE (400 * 1000)
|
||||||
|
|
||||||
|
#define OCR_POWERUP BIT(31)
|
||||||
|
#define OCR_HCS BIT(30)
|
||||||
|
|
||||||
|
#define OCR_3_5_3_6 BIT(23)
|
||||||
|
#define OCR_3_4_3_5 BIT(22)
|
||||||
|
#define OCR_3_3_3_4 BIT(21)
|
||||||
|
#define OCR_3_2_3_3 BIT(20)
|
||||||
|
#define OCR_3_1_3_2 BIT(19)
|
||||||
|
#define OCR_3_0_3_1 BIT(18)
|
||||||
|
#define OCR_2_9_3_0 BIT(17)
|
||||||
|
#define OCR_2_8_2_9 BIT(16)
|
||||||
|
#define OCR_2_7_2_8 BIT(15)
|
||||||
|
#define OCR_VDD_MIN_2V7 GENMASK(23, 15)
|
||||||
|
#define OCR_VDD_MIN_2V0 GENMASK(14, 8)
|
||||||
|
#define OCR_VDD_MIN_1V7 BIT(7)
|
||||||
|
|
||||||
|
#define MMC_RSP_48 BIT(0)
|
||||||
|
#define MMC_RSP_136 BIT(1) /* 136 bit response */
|
||||||
|
#define MMC_RSP_CRC BIT(2) /* expect valid crc */
|
||||||
|
#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */
|
||||||
|
#define MMC_RSP_BUSY BIT(4) /* device may be busy */
|
||||||
|
|
||||||
|
/* JEDEC 4.51 chapter 6.12 */
|
||||||
|
#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY)
|
||||||
|
#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_R3 (MMC_RSP_48)
|
||||||
|
#define MMC_RESPONSE_R4 (MMC_RSP_48)
|
||||||
|
#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX)
|
||||||
|
#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX)
|
||||||
|
#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC)
|
||||||
|
#define MMC_RESPONSE_NONE 0
|
||||||
|
|
||||||
|
/* Value randomly chosen for eMMC RCA, it should be > 1 */
|
||||||
|
#define MMC_FIX_RCA 6
|
||||||
|
#define RCA_SHIFT_OFFSET 16
|
||||||
|
|
||||||
|
#define CMD_EXTCSD_PARTITION_CONFIG 179
|
||||||
|
#define CMD_EXTCSD_BUS_WIDTH 183
|
||||||
|
#define CMD_EXTCSD_HS_TIMING 185
|
||||||
|
#define CMD_EXTCSD_SEC_CNT 212
|
||||||
|
|
||||||
|
#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3)
|
||||||
|
#define PART_CFG_PARTITION1_ACCESS 1
|
||||||
|
|
||||||
|
/* Values in EXT CSD register */
|
||||||
|
#define MMC_BUS_WIDTH_1 0
|
||||||
|
#define MMC_BUS_WIDTH_4 1
|
||||||
|
#define MMC_BUS_WIDTH_8 2
|
||||||
|
#define MMC_BUS_WIDTH_DDR_4 5
|
||||||
|
#define MMC_BUS_WIDTH_DDR_8 6
|
||||||
|
#define MMC_BOOT_MODE_BACKWARD 0
|
||||||
|
#define MMC_BOOT_MODE_HS_TIMING BIT(3)
|
||||||
|
#define MMC_BOOT_MODE_DDR (2 << 3)
|
||||||
|
|
||||||
|
#define EXTCSD_SET_CMD 0
|
||||||
|
#define EXTCSD_SET_BITS BIT(24)
|
||||||
|
#define EXTCSD_CLR_BITS (2 << 24)
|
||||||
|
#define EXTCSD_WRITE_BYTES (3 << 24)
|
||||||
|
#define EXTCSD_CMD(x) (((x) & 0xff) << 16)
|
||||||
|
#define EXTCSD_VALUE(x) (((x) & 0xff) << 8)
|
||||||
|
#define EXTCSD_CMD_SET_NORMAL 1
|
||||||
|
|
||||||
|
#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0)
|
||||||
|
#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3)
|
||||||
|
#define CSD_TRAN_SPEED_MULT_SHIFT 3
|
||||||
|
|
||||||
|
#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9)
|
||||||
|
#define STATUS_READY_FOR_DATA BIT(8)
|
||||||
|
#define STATUS_SWITCH_ERROR BIT(7)
|
||||||
|
#define MMC_GET_STATE(x) (((x) >> 9) & 0xf)
|
||||||
|
#define MMC_STATE_IDLE 0
|
||||||
|
#define MMC_STATE_READY 1
|
||||||
|
#define MMC_STATE_IDENT 2
|
||||||
|
#define MMC_STATE_STBY 3
|
||||||
|
#define MMC_STATE_TRAN 4
|
||||||
|
#define MMC_STATE_DATA 5
|
||||||
|
#define MMC_STATE_RCV 6
|
||||||
|
#define MMC_STATE_PRG 7
|
||||||
|
#define MMC_STATE_DIS 8
|
||||||
|
#define MMC_STATE_BTST 9
|
||||||
|
#define MMC_STATE_SLP 10
|
||||||
|
|
||||||
|
#define MMC_FLAG_CMD23 1
|
||||||
|
|
||||||
|
#define CMD8_CHECK_PATTERN 0xAA
|
||||||
|
#define VHS_2_7_3_6_V BIT(8)
|
||||||
|
|
||||||
|
#define SD_SCR_BUS_WIDTH_1 BIT(8)
|
||||||
|
#define SD_SCR_BUS_WIDTH_4 BIT(10)
|
||||||
|
|
||||||
|
/* ADMA table component */
|
||||||
|
#define ADMA_DESC_ATTR_VALID BIT(0)
|
||||||
|
#define ADMA_DESC_ATTR_END BIT(1)
|
||||||
|
#define ADMA_DESC_ATTR_INT BIT(2)
|
||||||
|
#define ADMA_DESC_ATTR_ACT1 BIT(4)
|
||||||
|
#define ADMA_DESC_ATTR_ACT2 BIT(5)
|
||||||
|
#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2
|
||||||
|
|
||||||
|
/* SRS10 Register */
|
||||||
|
#define LEDC BIT(0)
|
||||||
|
#define DT_WIDTH BIT(1)
|
||||||
|
#define HS_EN BIT(2)
|
||||||
|
/* Conf depends on SRS15.HV4E */
|
||||||
|
#define SDMA 0
|
||||||
|
#define ADMA2_32 (2 << 3)
|
||||||
|
#define ADMA2_64 (3 << 3)
|
||||||
|
/* here 0 defines the 64 Kb size */
|
||||||
|
#define MAX_64KB_PAGE 0
|
||||||
|
|
||||||
|
struct sdmmc_cmd {
|
||||||
|
unsigned int cmd_idx;
|
||||||
|
unsigned int cmd_arg;
|
||||||
|
unsigned int resp_type;
|
||||||
|
unsigned int resp_data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_ops {
|
||||||
|
/* init function for card */
|
||||||
|
int (*init)(void);
|
||||||
|
/* busy check function for card */
|
||||||
|
int (*busy)(void);
|
||||||
|
/* card_present function check for card */
|
||||||
|
int (*card_present)(void);
|
||||||
|
/* reset the card */
|
||||||
|
int (*reset)(void);
|
||||||
|
/* send command and respective argument */
|
||||||
|
int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data);
|
||||||
|
/* io set up for card */
|
||||||
|
int (*set_ios)(unsigned int clk, unsigned int width);
|
||||||
|
/* prepare dma descriptors */
|
||||||
|
int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data);
|
||||||
|
/* cache invd api */
|
||||||
|
int (*cache_invd)(int lba, uintptr_t buf, size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Combo Phy reg */
|
||||||
|
struct sdhc_cdns_combo_phy {
|
||||||
|
uint32_t cp_clk_wr_delay;
|
||||||
|
uint32_t cp_clk_wrdqs_delay;
|
||||||
|
uint32_t cp_data_select_oe_end;
|
||||||
|
uint32_t cp_dll_bypass_mode;
|
||||||
|
uint32_t cp_dll_locked_mode;
|
||||||
|
uint32_t cp_dll_start_point;
|
||||||
|
uint32_t cp_gate_cfg_always_on;
|
||||||
|
uint32_t cp_io_mask_always_on;
|
||||||
|
uint32_t cp_io_mask_end;
|
||||||
|
uint32_t cp_io_mask_start;
|
||||||
|
uint32_t cp_rd_del_sel;
|
||||||
|
uint32_t cp_read_dqs_cmd_delay;
|
||||||
|
uint32_t cp_read_dqs_delay;
|
||||||
|
uint32_t cp_sw_half_cycle_shift;
|
||||||
|
uint32_t cp_sync_method;
|
||||||
|
uint32_t cp_underrun_suppress;
|
||||||
|
uint32_t cp_use_ext_lpbk_dqs;
|
||||||
|
uint32_t cp_use_lpbk_dqs;
|
||||||
|
uint32_t cp_use_phony_dqs;
|
||||||
|
uint32_t cp_use_phony_dqs_cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sdmmc reg */
|
||||||
|
struct sdhc_cdns_sdmmc {
|
||||||
|
uint32_t sdhc_extended_rd_mode;
|
||||||
|
uint32_t sdhc_extended_wr_mode;
|
||||||
|
uint32_t sdhc_hcsdclkadj;
|
||||||
|
uint32_t sdhc_idelay_val;
|
||||||
|
uint32_t sdhc_rdcmd_en;
|
||||||
|
uint32_t sdhc_rddata_en;
|
||||||
|
uint32_t sdhc_rw_compensate;
|
||||||
|
uint32_t sdhc_sdcfsh;
|
||||||
|
uint32_t sdhc_sdcfsl;
|
||||||
|
uint32_t sdhc_wrcmd0_dly;
|
||||||
|
uint32_t sdhc_wrcmd0_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrcmd1_dly;
|
||||||
|
uint32_t sdhc_wrcmd1_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrdata0_dly;
|
||||||
|
uint32_t sdhc_wrdata0_sdclk_dly;
|
||||||
|
uint32_t sdhc_wrdata1_dly;
|
||||||
|
uint32_t sdhc_wrdata1_sdclk_dly;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sdmmc_device_mode {
|
||||||
|
/* Identification */
|
||||||
|
SD_DS_ID,
|
||||||
|
/* Default speed */
|
||||||
|
SD_DS,
|
||||||
|
/* High speed */
|
||||||
|
SD_HS,
|
||||||
|
/* Ultra high speed SDR12 */
|
||||||
|
SD_UHS_SDR12,
|
||||||
|
/* Ultra high speed SDR25 */
|
||||||
|
SD_UHS_SDR25,
|
||||||
|
/* Ultra high speed SDR`50 */
|
||||||
|
SD_UHS_SDR50,
|
||||||
|
/* Ultra high speed SDR104 */
|
||||||
|
SD_UHS_SDR104,
|
||||||
|
/* Ultra high speed DDR50 */
|
||||||
|
SD_UHS_DDR50,
|
||||||
|
/* SDR backward compatible */
|
||||||
|
EMMC_SDR_BC,
|
||||||
|
/* SDR */
|
||||||
|
EMMC_SDR,
|
||||||
|
/* DDR */
|
||||||
|
EMMC_DDR,
|
||||||
|
/* High speed 200Mhz in SDR */
|
||||||
|
EMMC_HS200,
|
||||||
|
/* High speed 200Mhz in DDR */
|
||||||
|
EMMC_HS400,
|
||||||
|
/* High speed 200Mhz in SDR with enhanced strobe */
|
||||||
|
EMMC_HS400ES,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdhc_cdns_params {
|
||||||
|
uintptr_t reg_base;
|
||||||
|
uintptr_t reg_phy;
|
||||||
|
uintptr_t desc_base;
|
||||||
|
size_t desc_size;
|
||||||
|
int clk_rate;
|
||||||
|
int bus_width;
|
||||||
|
unsigned int flags;
|
||||||
|
enum sdmmc_device_mode cdn_sdmmc_dev_type;
|
||||||
|
uint32_t combophy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sdmmc_device_info {
|
||||||
|
/* Size of device in bytes */
|
||||||
|
unsigned long long device_size;
|
||||||
|
/* Block size in bytes */
|
||||||
|
unsigned int block_size;
|
||||||
|
/* Max bus freq in Hz */
|
||||||
|
unsigned int max_bus_freq;
|
||||||
|
/* OCR voltage */
|
||||||
|
unsigned int ocr_voltage;
|
||||||
|
/* Type of MMC */
|
||||||
|
enum sdmmc_device_mode cdn_sdmmc_dev_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*descriptor structure with 8 byte alignment*/
|
||||||
|
struct sdhc_cdns_desc {
|
||||||
|
/* 8 bit attribute */
|
||||||
|
uint8_t attr;
|
||||||
|
/* reserved bits in desc */
|
||||||
|
uint8_t reserved;
|
||||||
|
/* page length for the descriptor */
|
||||||
|
uint16_t len;
|
||||||
|
/* lower 32 bits for buffer (64 bit addressing) */
|
||||||
|
uint32_t addr_lo;
|
||||||
|
/* higher 32 bits for buffer (64 bit addressing) */
|
||||||
|
uint32_t addr_hi;
|
||||||
|
} __aligned(8);
|
||||||
|
|
||||||
|
void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info,
|
||||||
|
const struct sdhc_cdns_ops **cb_sdmmc_ops);
|
20
dts/bindings/sdhc/cdns,sdhc.yaml
Normal file
20
dts/bindings/sdhc/cdns,sdhc.yaml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright (c) 2023 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: Cadence SDHC Controller node
|
||||||
|
|
||||||
|
compatible: "cdns,sdhc"
|
||||||
|
|
||||||
|
include: [sdhc.yaml, reset-device.yaml]
|
||||||
|
|
||||||
|
properties:
|
||||||
|
clock-frequency:
|
||||||
|
type: int
|
||||||
|
description: clock-frequency for SDHC
|
||||||
|
reg:
|
||||||
|
required: true
|
||||||
|
description: register space
|
||||||
|
power_delay_ms:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: delay required to switch on the SDHC
|
Loading…
Reference in a new issue