drivers: rkflash: Ajudst the dll strategy

1.max_dll_cells is 0x1FF when sfc_ver_4
2.sfc_set_delay_lines to zero means disable dll
3.bypass dll training when there is no device
4.Adjust the dll_value to from the middle of the dll window to
the better one
5.Change RKSFC_DLL_THRESHOLD_RATE to ">50MHz"

Change-Id: Ibd669420899925272c74e190fee8c62c09db8d14
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
Jon Lin
2021-07-22 14:22:32 +08:00
parent 75b1344eee
commit d047f245b8
3 changed files with 77 additions and 34 deletions
+56 -22
View File
@@ -23,7 +23,7 @@
#define RKSFC_VERSION_AND_DATE "rksfc_base v1.1 2016-01-08"
#define RKSFC_CLK_MAX_RATE (150 * 1000 * 1000)
#define RKSFC_DLL_THRESHOLD_RATE (100 * 1000 * 1000)
#define RKSFC_DLL_THRESHOLD_RATE (50 * 1000 * 1000)
struct rksfc_info {
void __iomem *reg_base;
@@ -97,40 +97,75 @@ static int rksfc_irq_deinit(void)
static void rksfc_delay_lines_tuning(void)
{
u8 id[3], id_temp[3];
int right, left = -1;
struct rk_sfc_op op;
u16 cell_max = SCLK_SMP_SEL_MAX_V4;
u16 cell_max = (u16)sfc_get_max_dll_cells();
u16 right, left = 0;
u16 step = SFC_DLL_TRANING_STEP;
bool dll_valid = false;
if (sfc_get_version() >= SFC_VER_5)
cell_max = SCLK_SMP_SEL_MAX_V5;
op.sfcmd.d32 = 0;
op.sfcmd.b.cmd = 0x9F;
op.sfctrl.d32 = 0;
clk_set_rate(g_sfc_info.clk, RKSFC_DLL_THRESHOLD_RATE);
sfc_request(&op, 0, id, 3);
if ((0xFF == id[0] && 0xFF == id[1]) ||
(0x00 == id[0] && 0x00 == id[1])) {
dev_dbg(g_sfc_dev, "no dev, dll by pass\n");
clk_set_rate(g_sfc_info.clk, g_sfc_info.clk_rate);
clk_set_rate(g_sfc_info.clk, g_sfc_info.clk_rate);
for (right = 10; right <= cell_max; right += 10) {
sfc_set_delay_lines((u16)right);
sfc_request(&op, 0, id_temp, 3);
if (left == -1 && !memcmp(&id, &id_temp, 3))
left = right;
else if (left >= 0 && memcmp(&id, &id_temp, 3))
break;
return;
}
if (left >= 0 && (right - left > 50)) {
g_sfc_info.dll_cells = (u16)(right + left) / 2;
sfc_set_delay_lines(g_sfc_info.dll_cells);
clk_set_rate(g_sfc_info.clk, g_sfc_info.clk_rate);
for (right = 0; right <= cell_max; right += step) {
int ret;
sfc_set_delay_lines(right);
sfc_request(&op, 0, id_temp, 3);
dev_dbg(g_sfc_dev, "dll read flash id:%x %x %x\n",
id_temp[0], id_temp[1], id_temp[2]);
ret = memcmp(&id, &id_temp, 3);
if (dll_valid && ret) {
right -= step;
break;
}
if (!dll_valid && !ret)
left = right;
if (!ret)
dll_valid = true;
/* Add cell_max to loop */
if (right == cell_max)
break;
if (right + step > cell_max)
right = cell_max - step;
}
if (dll_valid && (right - left) >= SFC_DLL_TRANING_VALID_WINDOW) {
if (left == 0 && right < cell_max)
g_sfc_info.dll_cells = left + (right - left) * 2 / 5;
else
g_sfc_info.dll_cells = left + (right - left) / 2;
} else {
g_sfc_info.dll_cells = 0;
sfc_disable_delay_lines();
}
if (g_sfc_info.dll_cells) {
dev_dbg(g_sfc_dev, "%d %d %d dll training success in %dMHz max_cells=%u sfc_ver=%d\n",
left, right, g_sfc_info.dll_cells, g_sfc_info.clk_rate,
sfc_get_max_dll_cells(), sfc_get_version());
sfc_set_delay_lines((u16)g_sfc_info.dll_cells);
} else {
dev_err(g_sfc_dev, "%d %d dll training failed in %dMHz, reduce the frequency\n",
left, right, g_sfc_info.clk_rate);
sfc_set_delay_lines(0);
clk_set_rate(g_sfc_info.clk, RKSFC_DLL_THRESHOLD_RATE);
g_sfc_info.clk_rate = clk_get_rate(g_sfc_info.clk);
}
pr_info("%s clk rate = %d\n", __func__, g_sfc_info.clk_rate);
}
static int rksfc_probe(struct platform_device *pdev)
@@ -186,11 +221,10 @@ static int rksfc_probe(struct platform_device *pdev)
#endif
sfc_init(g_sfc_info.reg_base);
if (sfc_get_version() >= SFC_VER_4 &&
g_sfc_info.clk_rate > RKSFC_DLL_THRESHOLD_RATE)
if (sfc_get_version() >= SFC_VER_4 && g_sfc_info.clk_rate > RKSFC_DLL_THRESHOLD_RATE)
rksfc_delay_lines_tuning();
else if (sfc_get_version() >= SFC_VER_4)
sfc_disable_delay_lines();
sfc_set_delay_lines(0);
#ifdef CONFIG_RK_SFC_NOR
dev_result = rkflash_dev_init(g_sfc_info.reg_base, FLASH_TYPE_SFC_NOR, &sfc_nor_ops);
+15 -9
View File
@@ -40,22 +40,28 @@ u32 sfc_get_max_iosize(void)
return SFC_MAX_IOSIZE_VER3;
}
u32 sfc_get_max_dll_cells(void)
{
if (sfc_get_version() == SFC_VER_5)
return SCLK_SMP_SEL_MAX_V5;
else if (sfc_get_version() == SFC_VER_4)
return SCLK_SMP_SEL_MAX_V4;
else
return 0;
}
void sfc_set_delay_lines(u16 cells)
{
u16 cell_max = SCLK_SMP_SEL_MAX_V4;
if (sfc_get_version() >= SFC_VER_5)
cell_max = SCLK_SMP_SEL_MAX_V5;
u16 cell_max = (u16)sfc_get_max_dll_cells();
u32 val = 0;
if (cells > cell_max)
cells = cell_max;
writel(SCLK_SMP_SEL_EN | cells, g_sfc_reg + SFC_DLL_CTRL0);
}
if (cells)
val = SCLK_SMP_SEL_EN | cells;
void sfc_disable_delay_lines(void)
{
writel(0, g_sfc_reg + SFC_DLL_CTRL0);
writel(val, g_sfc_reg + SFC_DLL_CTRL0);
}
int sfc_init(void __iomem *reg_addr)
+6 -3
View File
@@ -68,8 +68,11 @@
/* SFC_DLL_CTRL Register */
#define SCLK_SMP_SEL_EN BIT(15) /* SCLK Sampling Selection */
#define SCLK_SMP_SEL_MAX_V4 0xFF /* SCLK Sampling Selection */
#define SCLK_SMP_SEL_MAX_V5 0x1FF /* SCLK Sampling Selection */
#define SCLK_SMP_SEL_MAX_V4 0x1FF
#define SCLK_SMP_SEL_MAX_V5 0xFF
#define SFC_DLL_TRANING_STEP 10 /* Training step */
#define SFC_DLL_TRANING_VALID_WINDOW 80 /* Valid DLL winbow */
/* SFC_SR Register */
/* sfc busy flag. When busy, don't try to set the control register */
@@ -215,10 +218,10 @@ u16 sfc_get_version(void);
void sfc_clean_irq(void);
u32 sfc_get_max_iosize(void);
void sfc_set_delay_lines(u16 cells);
void sfc_disable_delay_lines(void);
void sfc_handle_irq(void);
unsigned long rksfc_dma_map_single(unsigned long ptr, int size, int dir);
void rksfc_dma_unmap_single(unsigned long ptr, int size, int dir);
void rksfc_irq_flag_init(void);
void rksfc_wait_for_irq_completed(void);
u32 sfc_get_max_dll_cells(void);
#endif