/** * @file sdrv_xspi_mst.c * @brief sdrv_xspi_mst driver * * @copyright Copyright (c) 2021 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #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; }