memory: rockchip: dsmc: fix io width config error

The io_width in diff cs should set the same value at the same time.

Change-Id: I2a872ba487bde9aa56f0a3490acbb526a1521475
Signed-off-by: Zhihuan He <huan.he@rock-chips.com>
This commit is contained in:
Zhihuan He
2024-12-18 17:00:54 +08:00
committed by Tao Huang
parent 629b36c6b3
commit 58231cec6b
2 changed files with 118 additions and 59 deletions

View File

@@ -4,6 +4,7 @@
*/
#include <linux/cacheflush.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -110,19 +111,21 @@ static uint32_t cap_2_dev_size(uint32_t cap)
static int dsmc_psram_id_detect(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t tmp, i;
uint32_t tmp[DSMC_MAX_SLAVE_NUM], i;
int ret = -1;
struct dsmc_map *region_map = &dsmc->cs_map[cs].region_map[0];
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
tmp = readl(dsmc->regs + DSMC_MCR(cs));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++) {
tmp[i] = readl(dsmc->regs + DSMC_MCR(i));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(i),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
}
if (cfg->protcl == OPI_XCCELA_PSRAM) {
uint8_t mid;
@@ -157,15 +160,17 @@ static int dsmc_psram_id_detect(struct rockchip_dsmc *dsmc, uint32_t cs)
}
}
/* config to memory space */
writel(tmp, dsmc->regs + DSMC_MCR(cs));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
/* config to memory space */
writel(tmp[i], dsmc->regs + DSMC_MCR(i));
return ret;
}
static void dsmc_psram_bw_detect(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t tmp, col;
uint32_t i;
uint32_t tmp[DSMC_MAX_SLAVE_NUM], col;
uint16_t ir0_ir1;
struct dsmc_map *region_map = &dsmc->cs_map[cs].region_map[0];
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
@@ -177,13 +182,15 @@ static void dsmc_psram_bw_detect(struct rockchip_dsmc *dsmc, uint32_t cs)
else
cfg->io_width = MCR_IOWIDTH_X8;
} else {
tmp = readl(dsmc->regs + DSMC_MCR(cs));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++) {
tmp[i] = readl(dsmc->regs + DSMC_MCR(i));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(i),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
}
/* hyper psram get IR0 */
ir0_ir1 = hyper_read_mr(region_map, HYPER_PSRAM_IR0);
@@ -195,8 +202,9 @@ static void dsmc_psram_bw_detect(struct rockchip_dsmc *dsmc, uint32_t cs)
else
cfg->io_width = MCR_IOWIDTH_X8;
/* config to memory space */
writel(tmp, dsmc->regs + DSMC_MCR(cs));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
/* config to memory space */
writel(tmp[i], dsmc->regs + DSMC_MCR(i));
}
cfg->col = col;
@@ -206,6 +214,7 @@ static int dsmc_psram_dectect(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t i = 0;
int ret = -1;
struct device *dev = dsmc->dev;
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
/* axi read do not response error */
@@ -229,7 +238,7 @@ static int dsmc_psram_dectect(struct rockchip_dsmc *dsmc, uint32_t cs)
cfg->protcl = psram_info[i].protcl;
cfg->mtr_timing = psram_info[i].mtr_timing;
if (!dsmc_psram_id_detect(dsmc, cs)) {
pr_info("DSMC: The cs%d %s PSRAM ID: 0x%x\n", cs,
dev_info(dev, "The cs%d %s PSRAM ID: 0x%x\n", cs,
(cfg->protcl == OPI_XCCELA_PSRAM) ? "XCCELA" : "HYPER",
psram_info[i].id);
ret = 0;
@@ -237,7 +246,7 @@ static int dsmc_psram_dectect(struct rockchip_dsmc *dsmc, uint32_t cs)
}
}
if (i == ARRAY_SIZE(psram_info)) {
pr_err("DSMC: Unknown PSRAM device\n");
dev_err(dev, "Unknown PSRAM device\n");
ret = -1;
} else {
dsmc_psram_bw_detect(dsmc, cs);
@@ -315,6 +324,7 @@ static int dsmc_slv_cmn_rgn_config(struct rockchip_dsmc *dsmc,
uint32_t rgn, uint32_t cs)
{
uint32_t tmp;
struct device *dev = dsmc->dev;
struct dsmc_map *region_map = &dsmc->cs_map[cs].region_map[0];
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
@@ -324,21 +334,21 @@ static int dsmc_slv_cmn_rgn_config(struct rockchip_dsmc *dsmc,
} else if (slv_rgn->dummy_clk_num == 1) {
tmp |= slv_rgn->dummy_clk_num << WR_DATA_CYC_EXTENDED_SHIFT;
} else {
pr_err("DSMC: lb slave: dummy clk too large\n");
dev_err(dev, "lb slave: dummy clk too large\n");
return -1;
}
tmp &= ~(RD_LATENCY_CYC_MASK << RD_LATENCY_CYC_SHIFT);
if ((cfg->rd_latency == 1) || (cfg->rd_latency == 2)) {
tmp |= cfg->rd_latency << RD_LATENCY_CYC_SHIFT;
} else {
pr_err("DSMC: lb slave: read latency value error\n");
dev_err(dev, "lb slave: read latency value error\n");
return -1;
}
tmp &= ~(WR_LATENCY_CYC_MASK << WR_LATENCY_CYC_SHIFT);
if ((cfg->wr_latency == 1) || (cfg->wr_latency == 2)) {
tmp |= cfg->wr_latency << WR_LATENCY_CYC_SHIFT;
} else {
pr_err("DSMC: lb slave: write latency value error\n");
dev_err(dev, "lb slave: write latency value error\n");
return -1;
}
tmp &= ~(CA_CYC_MASK << CA_CYC_SHIFT);
@@ -356,6 +366,7 @@ static int dsmc_slv_cmn_config(struct rockchip_dsmc *dsmc,
struct regions_config *slv_rgn, uint32_t cs)
{
uint32_t tmp;
struct device *dev = dsmc->dev;
struct dsmc_map *region_map = &dsmc->cs_map[cs].region_map[0];
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
@@ -371,7 +382,7 @@ static int dsmc_slv_cmn_config(struct rockchip_dsmc *dsmc,
} else if (slv_rgn->dummy_clk_num == 1) {
tmp |= slv_rgn->dummy_clk_num << WR_DATA_CYC_EXTENDED_SHIFT;
} else {
pr_err("DSMC: lb slave: dummy clk too large\n");
dev_err(dev, "lb slave: dummy clk too large\n");
return -1;
}
@@ -388,18 +399,20 @@ static int dsmc_slv_cmn_config(struct rockchip_dsmc *dsmc,
static int dsmc_lb_cmn_config(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t tmp, i;
uint32_t tmp[DSMC_MAX_SLAVE_NUM], i;
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
struct regions_config *slv_rgn;
int ret = 0;
tmp = readl(dsmc->regs + DSMC_MCR(cs));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++) {
tmp[i] = readl(dsmc->regs + DSMC_MCR(i));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(i),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
}
for (i = 0; i < DSMC_LB_MAX_RGN; i++) {
slv_rgn = &cfg->slv_rgn[i];
@@ -413,8 +426,9 @@ static int dsmc_lb_cmn_config(struct rockchip_dsmc *dsmc, uint32_t cs)
slv_rgn = &cfg->slv_rgn[0];
ret = dsmc_slv_cmn_config(dsmc, slv_rgn, cs);
/* config to memory space */
writel(tmp, dsmc->regs + DSMC_MCR(cs));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
/* config to memory space */
writel(tmp[i], dsmc->regs + DSMC_MCR(i));
for (i = 0; i < DSMC_LB_MAX_RGN; i++) {
slv_rgn = &cfg->slv_rgn[i];
@@ -472,17 +486,20 @@ static void dsmc_cfg_latency(uint32_t rd_ltcy, uint32_t wr_ltcy,
static int dsmc_psram_cfg(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t latency, mcr, tmp;
uint32_t i;
uint32_t latency, mcr[DSMC_MAX_SLAVE_NUM], tmp;
struct dsmc_map *region_map = &dsmc->cs_map[cs].region_map[0];
struct dsmc_config_cs *cs_cfg = &dsmc->cfg.cs_cfg[cs];
mcr = readl(dsmc->regs + DSMC_MCR(cs));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++) {
mcr[i] = readl(dsmc->regs + DSMC_MCR(i));
/* config to CR space */
REG_CLRSETBITS(dsmc, DSMC_MCR(i),
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_MASK << MCR_CRT_SHIFT),
(MCR_IOWIDTH_X8 << MCR_IOWIDTH_SHIFT) |
(MCR_CRT_CR_SPACE << MCR_CRT_SHIFT));
}
if (cs_cfg->protcl == OPI_XCCELA_PSRAM) {
/* Xccela psram init */
uint8_t mr_tmp, rbxen;
@@ -586,8 +603,9 @@ static int dsmc_psram_cfg(struct rockchip_dsmc *dsmc, uint32_t cs)
(CR1_CLOCK_TYPE_DIFF_CLK << CR1_CLOCK_TYPE_SHIFT);
hyper_write_mr(region_map, HYPER_PSRAM_CR1, cr_tmp);
}
/* config to memory space */
writel(mcr, dsmc->regs + DSMC_MCR(cs));
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
/* config to memory space */
writel(mcr[i], dsmc->regs + DSMC_MCR(i));
return 0;
}
@@ -596,6 +614,7 @@ static int dsmc_psram_cfg(struct rockchip_dsmc *dsmc, uint32_t cs)
static int dsmc_psram_init(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t latency;
struct device *dev = dsmc->dev;
struct dsmc_config_cs *cs_cfg = &dsmc->cfg.cs_cfg[cs];
uint32_t mhz = dsmc->cfg.freq_hz / MHZ;
@@ -610,7 +629,7 @@ static int dsmc_psram_init(struct rockchip_dsmc *dsmc, uint32_t cs)
} else if (mhz <= 200) {
latency = 7;
} else {
pr_err("DSMC: PSRAM frequency do not support!\n");
dev_err(dev, "PSRAM frequency do not support!\n");
return -1;
}
@@ -649,6 +668,7 @@ static int dsmc_ctrller_cfg_for_psram(struct rockchip_dsmc *dsmc, uint32_t cs)
static void dsmc_psram_remodify_timing(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t i;
uint32_t max_length = 511, tcmd = 3;
uint32_t tcsm, tmp;
uint32_t mhz = dsmc->cfg.freq_hz / MHZ;
@@ -673,13 +693,16 @@ static void dsmc_psram_remodify_timing(struct rockchip_dsmc *dsmc, uint32_t cs)
if (tmp > max_length)
tmp = max_length;
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
REG_CLRSETBITS(dsmc, DSMC_MCR(i),
MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT,
cs_cfg->io_width << MCR_IOWIDTH_SHIFT);
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_MAXEN_MASK << MCR_MAXEN_SHIFT) |
(MCR_MAXLEN_MASK << MCR_MAXLEN_SHIFT) |
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT),
(MCR_MAXLEN_MASK << MCR_MAXLEN_SHIFT),
(MCR_MAX_LENGTH_EN << MCR_MAXEN_SHIFT) |
(tmp << MCR_MAXLEN_SHIFT) |
(cs_cfg->io_width << MCR_IOWIDTH_SHIFT));
(tmp << MCR_MAXLEN_SHIFT));
if (cs_cfg->io_width == MCR_IOWIDTH_X16)
tmp = cs_cfg->col - 2;
@@ -797,6 +820,7 @@ int rockchip_dsmc_dll_training(struct rockchip_dsmc_device *priv)
int dll, dll_step = 10;
struct dsmc_config_cs *cfg;
struct rockchip_dsmc *dsmc = &priv->dsmc;
struct device *dev = dsmc->dev;
int ret;
for (cs = 0; cs < DSMC_MAX_SLAVE_NUM; cs++) {
@@ -832,11 +856,11 @@ int rockchip_dsmc_dll_training(struct rockchip_dsmc_device *priv)
}
dll = (dll_max + dll_min) / 2;
if ((dll >= 0xff) || (dll <= 0)) {
pr_err("DSMC: cs%d byte%d dll training error(0x%x)\n",
dev_err(dev, "DSMC: cs%d byte%d dll training error(0x%x)\n",
cs, byte, dll);
return -1;
}
pr_info("DSMC: cs%d byte%d dll delay line result 0x%x\n", cs, byte, dll);
dev_info(dev, "cs%d byte%d dll delay line result 0x%x\n", cs, byte, dll);
REG_CLRSETBITS(dsmc, DSMC_RDS_DLL_CTL(cs, byte),
RDS_DLL0_CTL_RDS_0_CLK_DELAY_NUM_MASK,
dll << RDS_DLL0_CTL_RDS_0_CLK_DELAY_NUM_SHIFT);
@@ -945,6 +969,7 @@ EXPORT_SYMBOL(rockchip_dsmc_psram_reinit);
int rockchip_dsmc_ctrller_init(struct rockchip_dsmc *dsmc, uint32_t cs)
{
uint32_t i;
struct dsmc_config_cs *cfg = &dsmc->cfg.cs_cfg[cs];
writel(MRGTCR_READ_WRITE_MERGE_EN,
@@ -956,17 +981,21 @@ int rockchip_dsmc_ctrller_init(struct rockchip_dsmc *dsmc, uint32_t cs)
(cfg->dll_num[1] << RDS_DLL1_CTL_RDS_1_CLK_DELAY_NUM_SHIFT),
dsmc->regs + DSMC_RDS_DLL1_CTL(cs));
/* all io_width should set the same value in diff cs */
for (i = 0; i < DSMC_MAX_SLAVE_NUM; i++)
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT,
cfg->io_width << MCR_IOWIDTH_SHIFT);
REG_CLRSETBITS(dsmc, DSMC_MCR(cs),
(MCR_ACS_MASK << MCR_ACS_SHIFT) |
(MCR_DEVTYPE_MASK << MCR_DEVTYPE_SHIFT) |
(MCR_IOWIDTH_MASK << MCR_IOWIDTH_SHIFT) |
(MCR_EXCLUSIVE_DQS_MASK << MCR_EXCLUSIVE_DQS_SHIFT) |
(MCR_WRAPSIZE_MASK << MCR_WRAPSIZE_SHIFT) |
(MCR_MAXEN_MASK << MCR_MAXEN_SHIFT) |
(MCR_MAXLEN_MASK << MCR_MAXLEN_SHIFT),
(cfg->acs << MCR_ACS_SHIFT) |
(MCR_DEVTYPE_HYPERRAM << MCR_DEVTYPE_SHIFT) |
(cfg->io_width << MCR_IOWIDTH_SHIFT) |
(cfg->exclusive_dqs << MCR_EXCLUSIVE_DQS_SHIFT) |
(cfg->wrap_size << MCR_WRAPSIZE_SHIFT) |
(cfg->max_length_en << MCR_MAXEN_SHIFT) |

View File

@@ -526,6 +526,7 @@ static int dsmc_write(struct rockchip_dsmc_device *dsmc_dev, uint32_t cs, uint32
static void dsmc_lb_dma_hw_mode_en(struct rockchip_dsmc *dsmc, uint32_t cs)
{
struct device *dev = dsmc->dev;
struct dsmc_transfer *xfer = &dsmc->xfer;
size_t size = xfer->transfer_size;
uint32_t burst_byte = xfer->brst_len * xfer->brst_size;
@@ -533,7 +534,7 @@ static void dsmc_lb_dma_hw_mode_en(struct rockchip_dsmc *dsmc, uint32_t cs)
dma_req_num = size / burst_byte;
if (size % burst_byte) {
pr_warn("DSMC: DMA size is unaligned\n");
dev_warn(dev, "DMA size is unaligned\n");
dma_req_num++;
}
writel(dma_req_num, dsmc->regs + DSMC_DMA_REQ_NUM(cs));
@@ -683,7 +684,7 @@ static int dsmc_copy_from(struct rockchip_dsmc_device *dsmc_dev, uint32_t cs, ui
struct rockchip_dsmc *dsmc = &dsmc_dev->dsmc;
if (atomic_read(&dsmc->xfer.state) & (RXDMA | TXDMA)) {
pr_warn("DSMC: copy_from: the transfer is busy!\n");
dev_warn(dev, "copy_from: the transfer is busy!\n");
return -EBUSY;
}
@@ -721,7 +722,7 @@ static int dsmc_copy_to(struct rockchip_dsmc_device *dsmc_dev, uint32_t cs, uint
struct rockchip_dsmc *dsmc = &dsmc_dev->dsmc;
if (atomic_read(&dsmc->xfer.state) & (RXDMA | TXDMA)) {
pr_warn("DSMC: copy_to: the transfer is busy!\n");
dev_warn(dev, "copy_to: the transfer is busy!\n");
return -EBUSY;
}
@@ -785,6 +786,29 @@ static void dsmc_data_init(struct rockchip_dsmc *dsmc)
}
}
static int dsmc_check_mult_psram_cap(struct rockchip_dsmc *dsmc)
{
uint32_t cs;
uint32_t io_width = 0xffffffff;
struct device *dev = dsmc->dev;
struct dsmc_ctrl_config *cfg = &dsmc->cfg;
for (cs = 0; cs < DSMC_MAX_SLAVE_NUM; cs++) {
if (cfg->cs_cfg[cs].device_type == DSMC_UNKNOWN_DEVICE)
continue;
if (io_width == 0xffffffff) {
io_width = dsmc->cfg.cs_cfg[cs].io_width;
} else {
if (io_width != dsmc->cfg.cs_cfg[cs].io_width) {
dev_err(dev, "The io width error for mult rank!\n");
return -1;
}
}
}
return 0;
}
static void dsmc_reset_ctrl(struct rockchip_dsmc *dsmc)
{
reset_control_assert(dsmc->areset);
@@ -797,6 +821,7 @@ static void dsmc_reset_ctrl(struct rockchip_dsmc *dsmc)
static int dsmc_init(struct rockchip_dsmc *dsmc)
{
uint32_t cs;
struct device *dev = dsmc->dev;
struct dsmc_ctrl_config *cfg = &dsmc->cfg;
struct dsmc_config_cs *cs_cfg;
uint32_t ret = 0;
@@ -812,13 +837,18 @@ static int dsmc_init(struct rockchip_dsmc *dsmc)
return ret;
}
}
ret = dsmc_check_mult_psram_cap(dsmc);
if (ret)
return ret;
dsmc_reset_ctrl(dsmc);
for (cs = 0; cs < DSMC_MAX_SLAVE_NUM; cs++) {
if (cfg->cs_cfg[cs].device_type == DSMC_UNKNOWN_DEVICE)
continue;
cs_cfg = &dsmc->cfg.cs_cfg[cs];
pr_info("DSMC: init cs%d %s device\n",
dev_info(dev, "init cs%d %s device\n",
cs, (cs_cfg->device_type == DSMC_LB_DEVICE) ? "LB" : "PSRAM");
rockchip_dsmc_ctrller_init(dsmc, cs);
if (cs_cfg->device_type == OPI_XCCELA_PSRAM)