331 lines
10 KiB
C
331 lines
10 KiB
C
/**
|
|
* @file sdrv_xspi_mst.c
|
|
* @brief sdrv_xspi_mst driver
|
|
*
|
|
* @copyright Copyright (c) 2021 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <compiler.h>
|
|
#include <debug.h>
|
|
#include <param.h>
|
|
#include <reg.h>
|
|
#include <string.h>
|
|
|
|
#include "sdrv_xspi_mst_reg.h"
|
|
#include "regs_base.h"
|
|
#include "sdrv_xspi_mst.h"
|
|
#include "udelay/udelay.h"
|
|
|
|
#define XSPI_MODE_CTRL (0x0u)
|
|
#define XSPI_SCLK_CTRL (0xC0u)
|
|
#define XSPI_DLL_CTRL (0xE0u)
|
|
#define XSPI_DLL1_CTRL (0xE8u)
|
|
|
|
|
|
static const char *ms_int_st[] = {
|
|
"read timeout",
|
|
"read axi id mismatch",
|
|
"read user check fail",
|
|
"read sid check fail",
|
|
"read crc check fail",
|
|
"read length check fail",
|
|
"reserved",
|
|
"reserved",
|
|
"write timeout",
|
|
"write aid check fail",
|
|
"write usr check fail",
|
|
"write sid check fail",
|
|
"write crc check fail",
|
|
"reserved",
|
|
"reserved",
|
|
"reserved",
|
|
"slave axi write utid error", // 16~29 generate master bus error
|
|
"slave axi write mismatch error",
|
|
"slave write error",
|
|
"slave write sid error",
|
|
"slave write crc check error",
|
|
"slave axi address access illegal",
|
|
"slave write len error",
|
|
"reserved",
|
|
"slave axi read utid error",
|
|
"slave axi read mismatch error", // OT error
|
|
"slave read error", // slave bus error
|
|
"slave read sid error", // sequence id (4bits) error
|
|
"slave read crc check error",
|
|
"slave axi address access illegal",
|
|
"reserved",
|
|
"reserved"
|
|
};
|
|
|
|
status_t sdrv_xspi_mst_fail_reason(struct sdrv_xspi_mst *xspi)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = sdrv_xspi_mst_get_attr(xspi, XSPI_MST_MS_INT_ST, ®);
|
|
|
|
for (uint32_t i = 0; i < sizeof(ms_int_st) / sizeof(ms_int_st[0]); i++) {
|
|
if ((0x1u << i) & reg) {
|
|
ssdk_printf(SSDK_ERR, "xspi ms int status: %s\n", ms_int_st[i]);
|
|
}
|
|
}
|
|
|
|
return reg;
|
|
}
|
|
|
|
|
|
static status_t xspi_wait_for_bit_times(addr_t reg, const uint32_t mask, bool clear,
|
|
uint32_t times)
|
|
{
|
|
uint32_t val;
|
|
uint32_t count = 0;
|
|
|
|
while (count < times) {
|
|
val = readl(reg);
|
|
if (clear) {
|
|
val = ~val;
|
|
}
|
|
val &= mask;
|
|
|
|
if (val == mask) {
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_LOCKED_ERR;
|
|
}
|
|
static status_t sdrv_xspi_dll_enable(paddr_t apb_base, int dll_num, int value,
|
|
bool enable)
|
|
{
|
|
uint32_t reg = 0u;
|
|
int ret = SDRV_STATUS_FAIL;
|
|
uint32_t addr;
|
|
|
|
addr = dll_num ? XSPI_DLL1_CTRL : XSPI_DLL_CTRL;
|
|
|
|
if (enable) {
|
|
writel(reg, apb_base + addr);
|
|
reg |= value << 1;
|
|
writel(reg, apb_base + addr);
|
|
reg |= 1;
|
|
writel(reg, apb_base + addr);
|
|
|
|
ret = xspi_wait_for_bit_times(apb_base + addr + 4, 1 << 16, false, 100000);
|
|
if (ret != SDRV_STATUS_OK) {
|
|
ssdk_printf(SSDK_ERR, "dll enable err\n");
|
|
return ret;
|
|
}
|
|
RMWREG32(apb_base + addr, 31, 1, 1);//open update gate
|
|
}
|
|
|
|
RMWREG32(apb_base + XSPI_MODE_CTRL, 31, 1, 1);
|
|
udelay(1);
|
|
RMWREG32(apb_base + XSPI_MODE_CTRL, 31, 1, 0);
|
|
while (sdrv_xspi_master_is_busy(apb_base));
|
|
|
|
/* set dll_en */
|
|
RMWREG32(apb_base + XSPI_SCLK_CTRL, 1, 1, enable ? 1 : 0);
|
|
return ret;
|
|
}
|
|
|
|
static void sdrv_xspi_mst_training(paddr_t apb_base)
|
|
{
|
|
sdrv_xspi_dll_enable(apb_base, 0u, 0xf, true);
|
|
}
|
|
|
|
static status_t sdrv_xspi_mst_check_bit(struct sdrv_xspi_mst *master, uint32_t reg,
|
|
uint8_t offset, bool value, uint32_t count)
|
|
{
|
|
ASSERT(master);
|
|
|
|
while (count--) {
|
|
uint32_t tmp = readl(master->base + reg);
|
|
if (!!((1u << offset) & tmp) == value) {
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
}
|
|
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_CHECK_BIT_ERR;
|
|
}
|
|
|
|
status_t sdrv_xspi_mst_init(struct sdrv_xspi_mst *master,
|
|
const struct sdrv_xspi_mst_conf *conf)
|
|
{
|
|
ASSERT(master && conf);
|
|
|
|
memset(master, 0, sizeof(*master));
|
|
|
|
master->base = conf->base;
|
|
master->irq = conf->irq;
|
|
|
|
sdrv_xspi_master_sw_rst(master->base);
|
|
|
|
if (sdrv_xspi_mst_check_bit(master, XSPI_MASTER_MODE_CTRL_BASE,
|
|
XSPI_MASTER_MODE_CTRL_IDLE_OFFSET, 1, 10000)) {
|
|
ssdk_printf(SSDK_EMERG, "xspi mst busy\r\n");
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_MODE_CTRL_BUSY_ERR;
|
|
}
|
|
|
|
sdrv_xspi_master_set_ms_mode(master->base, 1);
|
|
sdrv_xspi_master_sw_rst_pad(master->base);
|
|
|
|
sdrv_xspi_master_set_addr_offset_en(master->base, conf->offset.enable);
|
|
sdrv_xspi_master_set_addr_offset_val(master->base, conf->offset.addr_offset);
|
|
|
|
/* rx dqs */
|
|
sdrv_xspi_master_set_sclk_rx_sel(master->base, 2);
|
|
sdrv_xspi_master_set_sclk_dll_en(master->base, 1);
|
|
|
|
sdrv_xspi_master_set_cs_sw(master->base, 0);
|
|
|
|
if (conf->cs <= 1) {
|
|
sdrv_xspi_master_set_cs_sel(master->base, conf->cs ? 4 : 8);
|
|
} else {
|
|
ssdk_printf(SSDK_EMERG, "cs error: %d\r\n", conf->cs);
|
|
}
|
|
|
|
sdrv_xspi_master_set_dll_enable(master->base, 1);
|
|
sdrv_xspi_master_set_dll_slv_target(master->base, 0xf);
|
|
if (sdrv_xspi_mst_check_bit(master, XSPI_MASTER_DLL_ST_BASE,
|
|
XSPI_MASTER_DLL_ST_SLV_LOCK_OFFSET, 1, 10000)) {
|
|
ssdk_printf(SSDK_EMERG, "xspi dll err\r\n");
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_LOCKED_ERR;
|
|
}
|
|
|
|
if (sdrv_xspi_mst_check_bit(master, XSPI_MASTER_MS_CTRL_BASE,
|
|
XSPI_MASTER_MS_CTRL_IDLE_OFFSET, 1, 10000)) {
|
|
ssdk_printf(SSDK_EMERG, "xspi mst busy\r\n");
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_CTRL_BUSY_ERR;
|
|
}
|
|
|
|
sdrv_xspi_master_set_timeout_thrd(master->base, 40000u);
|
|
sdrv_xspi_master_set_crc_en(master->base, conf->crc_en);
|
|
sdrv_xspi_master_set_slv_err_resp_en(master->base, conf->slv_err_resp_en);
|
|
sdrv_xspi_master_set_dummy(master->base, conf->dummy);
|
|
sdrv_xspi_master_set_rate(master->base, conf->is_ddr);
|
|
sdrv_xspi_master_set_line(master->base, conf->line);
|
|
sdrv_xspi_master_set_cs_time(master->base, 10, 7, 6);
|
|
sdrv_xspi_master_set_rxmode(master->base, 1);
|
|
sdrv_xspi_master_set_rxenable_mode(master->base, 1);
|
|
sdrv_xspi_master_clr_ms_int_en(master->base, 0xffffffffu);
|
|
sdrv_xspi_master_set_ms_int_en(master->base, 0x1fffu);
|
|
|
|
if(conf->is_training){
|
|
sdrv_xspi_mst_training(master->base);
|
|
}
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
status_t sdrv_xspi_mst_set_attr(struct sdrv_xspi_mst *master,
|
|
enum sdrv_xspi_mst_ioctl_flag flag, const void *buf)
|
|
{
|
|
ASSERT(master && flag < XSPI_MST_FLAG_MAX && buf);
|
|
|
|
const struct sdrv_xspi_mst_addr_offset_conf *offset_conf;
|
|
|
|
switch (flag) {
|
|
case XSPI_MST_FLAG_ADDR_OFFSET:
|
|
offset_conf = buf;
|
|
sdrv_xspi_master_set_addr_offset_en(master->base, offset_conf->enable);
|
|
sdrv_xspi_master_set_addr_offset_val(master->base,
|
|
offset_conf->addr_offset);
|
|
break;
|
|
case XSPI_MST_FLAG_SLV_ERR_RESP:
|
|
sdrv_xspi_master_set_slv_err_resp_en(master->base, *(bool *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_CRC_EN:
|
|
sdrv_xspi_master_set_crc_en(master->base, *(bool *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_DUMMY:
|
|
sdrv_xspi_master_set_dummy(master->base, *(uint8_t *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_RATE:
|
|
sdrv_xspi_master_set_rate(master->base, *(bool *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_LINE:
|
|
sdrv_xspi_master_set_line(master->base, *(enum sdrv_xspi_mst_line *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_TIMEOUT:
|
|
sdrv_xspi_master_set_timeout_thrd(master->base, *(uint32_t *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_INT_ST:
|
|
sdrv_xspi_master_clr_int_st_fuc(master->base, *(uint32_t *)buf);
|
|
break;
|
|
case XSPI_MST_FLAG_INT_EN:
|
|
sdrv_xspi_master_set_int_en_fuc(master->base, *(uint32_t *)buf);
|
|
break;
|
|
case XSPI_MST_MS_INT_ST:
|
|
sdrv_xspi_master_clr_ms_int_st(master->base, *(uint32_t *)buf);
|
|
break;
|
|
default:
|
|
ssdk_printf(SSDK_EMERG, "set flag error: %d\r\n", flag);
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_SET_FLAG_ATTR_ERR;
|
|
}
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
status_t sdrv_xspi_mst_get_attr(struct sdrv_xspi_mst *master,
|
|
enum sdrv_xspi_mst_ioctl_flag flag, void *buf)
|
|
{
|
|
ASSERT(master && flag < XSPI_MST_FLAG_MAX && buf);
|
|
|
|
struct sdrv_xspi_mst_addr_offset_conf *offset_conf;
|
|
|
|
switch (flag) {
|
|
case XSPI_MST_FLAG_ADDR_OFFSET:
|
|
offset_conf = buf;
|
|
offset_conf->enable = sdrv_xspi_master_get_addr_offset_en(
|
|
master->base);
|
|
offset_conf->addr_offset = sdrv_xspi_master_get_addr_offset_val(
|
|
master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_SLV_ERR_RESP:
|
|
*(bool *)buf = sdrv_xspi_master_get_slv_err_resp_en(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_CRC_EN:
|
|
*(bool *)buf = sdrv_xspi_master_get_crc_en(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_DUMMY:
|
|
*(uint8_t *)buf = sdrv_xspi_master_get_dummy(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_RATE:
|
|
*(bool *)buf = sdrv_xspi_master_get_rate(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_LINE:
|
|
*(enum sdrv_xspi_mst_line *)buf = (enum sdrv_xspi_mst_line)sdrv_xspi_master_get_line(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_WAIT_TIME:
|
|
*(uint32_t *)buf = sdrv_xspi_master_get_wait_time_cycle(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_TIMEOUT:
|
|
*(uint32_t *)buf = sdrv_xspi_master_get_timeout_thrd(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_INT_ST:
|
|
*(uint32_t *)buf = sdrv_xspi_master_get_int_st_fuc(master->base);
|
|
break;
|
|
case XSPI_MST_FLAG_INT_EN:
|
|
*(uint32_t *)buf = sdrv_xspi_master_get_int_en_fuc(master->base);
|
|
break;
|
|
case XSPI_MST_MS_INT_ST:
|
|
*(uint32_t *)buf = sdrv_xspi_master_get_ms_int_st(master->base);
|
|
break;
|
|
default:
|
|
ssdk_printf(SSDK_EMERG, "set flag error: %d\r\n", flag);
|
|
return SSDRV_STATUS_GROUP_XSPI_MASTER_GET_FLAG_ATTR_ERR;
|
|
}
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
|
|
status_t sdrv_xspi_mst_deinit(struct sdrv_xspi_mst *master)
|
|
{
|
|
ASSERT(master);
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
|