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:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user