rkflash: Support sfc DLL api

Change-Id: Ibe8cd0d1e72e8dc871466dcb1014e6817b184e80
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
Jon Lin 2020-12-03 19:10:56 +08:00 committed by Jianhong Chen
parent 5b0bc49177
commit 49eba1a38a
2 changed files with 62 additions and 1 deletions

View File

@ -21,10 +21,12 @@ static void sfc_reset(void)
int timeout = 10000; int timeout = 10000;
writel(SFC_RESET, g_sfc_reg + SFC_RCVR); writel(SFC_RESET, g_sfc_reg + SFC_RCVR);
while ((readl(g_sfc_reg + SFC_RCVR) == SFC_RESET) && (timeout > 0)) { while ((readl(g_sfc_reg + SFC_RCVR) == SFC_RESET) && (timeout > 0)) {
sfc_delay(1); sfc_delay(1);
timeout--; timeout--;
} }
writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
} }
@ -41,10 +43,29 @@ u32 sfc_get_max_iosize(void)
return SFC_MAX_IOSIZE_VER3; return SFC_MAX_IOSIZE_VER3;
} }
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;
if (cells > cell_max)
cells = cell_max;
writel(SCLK_SMP_SEL_EN | cells, g_sfc_reg + SFC_DLL_CTRL0);
}
void sfc_disable_delay_lines(void)
{
writel(0, g_sfc_reg + SFC_DLL_CTRL0);
}
int sfc_init(void __iomem *reg_addr) int sfc_init(void __iomem *reg_addr)
{ {
g_sfc_reg = reg_addr; g_sfc_reg = reg_addr;
writel(0, g_sfc_reg + SFC_CTRL); writel(0, g_sfc_reg + SFC_CTRL);
if (sfc_get_version() >= SFC_VER_4) if (sfc_get_version() >= SFC_VER_4)
writel(1, g_sfc_reg + SFC_LEN_CTRL); writel(1, g_sfc_reg + SFC_LEN_CTRL);
@ -65,23 +86,29 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
int timeout = 0; int timeout = 0;
reg = readl(g_sfc_reg + SFC_FSR); reg = readl(g_sfc_reg + SFC_FSR);
if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) || if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) ||
(readl(g_sfc_reg + SFC_SR) & SFC_BUSY)) (readl(g_sfc_reg + SFC_SR) & SFC_BUSY))
sfc_reset(); sfc_reset();
cmd.d32 = op->sfcmd.d32; cmd.d32 = op->sfcmd.d32;
if (cmd.b.addrbits == SFC_ADDR_XBITS) { if (cmd.b.addrbits == SFC_ADDR_XBITS) {
union SFCCTRL_DATA ctrl; union SFCCTRL_DATA ctrl;
ctrl.d32 = op->sfctrl.d32; ctrl.d32 = op->sfctrl.d32;
if (!ctrl.b.addrbits) if (!ctrl.b.addrbits)
return SFC_PARAM_ERR; return SFC_PARAM_ERR;
/* Controller plus 1 automatically */ /* Controller plus 1 automatically */
writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT); writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT);
} }
/* shift in the data at negedge sclk_out */ /* shift in the data at negedge sclk_out */
op->sfctrl.d32 |= 0x2; op->sfctrl.d32 |= 0x2;
cmd.b.datasize = size; cmd.b.datasize = size;
if (sfc_get_version() >= SFC_VER_4) if (sfc_get_version() >= SFC_VER_4)
writel(size, g_sfc_reg + SFC_LEN_EXT); writel(size, g_sfc_reg + SFC_LEN_EXT);
else else
@ -89,10 +116,13 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL); writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL);
writel(cmd.d32, g_sfc_reg + SFC_CMD); writel(cmd.d32, g_sfc_reg + SFC_CMD);
if (cmd.b.addrbits) if (cmd.b.addrbits)
writel(addr, g_sfc_reg + SFC_ADDR); writel(addr, g_sfc_reg + SFC_ADDR);
if (!size) if (!size)
goto exit_wait; goto exit_wait;
if (op->sfctrl.b.enbledma) { if (op->sfctrl.b.enbledma) {
struct bounce_buffer bb; struct bounce_buffer bb;
unsigned int bb_flags; unsigned int bb_flags;
@ -112,10 +142,13 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER); writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER);
timeout = size * 10; timeout = size * 10;
while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) && while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) &&
(timeout-- > 0)) (timeout-- > 0))
sfc_delay(1); sfc_delay(1);
writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
if (timeout <= 0) if (timeout <= 0)
ret = SFC_WAIT_TIMEOUT; ret = SFC_WAIT_TIMEOUT;
bounce_buffer_stop(&bb); bounce_buffer_stop(&bb);
@ -126,21 +159,27 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
if (cmd.b.rw == SFC_WRITE) { if (cmd.b.rw == SFC_WRITE) {
words = (size + 3) >> 2; words = (size + 3) >> 2;
while (words) { while (words) {
fifostat.d32 = readl(g_sfc_reg + SFC_FSR); fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
if (fifostat.b.txlevel > 0) { if (fifostat.b.txlevel > 0) {
count = words < fifostat.b.txlevel ? count = words < fifostat.b.txlevel ?
words : fifostat.b.txlevel; words : fifostat.b.txlevel;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
writel(*p_data++, writel(*p_data++,
g_sfc_reg + SFC_DATA); g_sfc_reg + SFC_DATA);
words--; words--;
} }
if (words == 0) if (words == 0)
break; break;
timeout = 0; timeout = 0;
} else { } else {
sfc_delay(1); sfc_delay(1);
if (timeout++ > 10000) { if (timeout++ > 10000) {
ret = SFC_TX_TIMEOUT; ret = SFC_TX_TIMEOUT;
break; break;
@ -151,8 +190,10 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
/* SFC_READ == cmd.b.rw */ /* SFC_READ == cmd.b.rw */
bytes = size & 0x3; bytes = size & 0x3;
words = size >> 2; words = size >> 2;
while (words) { while (words) {
fifostat.d32 = readl(g_sfc_reg + SFC_FSR); fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
if (fifostat.b.rxlevel > 0) { if (fifostat.b.rxlevel > 0) {
u32 count; u32 count;
@ -164,11 +205,14 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
SFC_DATA); SFC_DATA);
words--; words--;
} }
if (words == 0) if (words == 0)
break; break;
timeout = 0; timeout = 0;
} else { } else {
sfc_delay(1); sfc_delay(1);
if (timeout++ > 10000) { if (timeout++ > 10000) {
ret = SFC_RX_TIMEOUT; ret = SFC_RX_TIMEOUT;
break; break;
@ -177,19 +221,24 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
} }
timeout = 0; timeout = 0;
while (bytes) { while (bytes) {
fifostat.d32 = readl(g_sfc_reg + SFC_FSR); fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
if (fifostat.b.rxlevel > 0) { if (fifostat.b.rxlevel > 0) {
u8 *p_data1 = (u8 *)p_data; u8 *p_data1 = (u8 *)p_data;
words = readl(g_sfc_reg + SFC_DATA); words = readl(g_sfc_reg + SFC_DATA);
for (i = 0; i < bytes; i++) for (i = 0; i < bytes; i++)
p_data1[i] = p_data1[i] =
(u8)((words >> (i * 8)) & 0xFF); (u8)((words >> (i * 8)) & 0xFF);
break; break;
} }
sfc_delay(1); sfc_delay(1);
if (timeout++ > 10000) { if (timeout++ > 10000) {
ret = SFC_RX_TIMEOUT; ret = SFC_RX_TIMEOUT;
break; break;
@ -200,13 +249,16 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
exit_wait: exit_wait:
timeout = 0; /* wait cmd or data send complete */ timeout = 0; /* wait cmd or data send complete */
while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) { while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) {
sfc_delay(1); sfc_delay(1);
if (timeout++ > 100000) { /* wait 100ms */ if (timeout++ > 100000) { /* wait 100ms */
ret = SFC_TX_TIMEOUT; ret = SFC_TX_TIMEOUT;
break; break;
} }
} }
sfc_delay(1); /* CS# High Time (read/write) >100ns */ sfc_delay(1); /* CS# High Time (read/write) >100ns */
return ret; return ret;
} }

View File

@ -9,6 +9,7 @@
#define SFC_VER_3 0x3 #define SFC_VER_3 0x3
#define SFC_VER_4 0x4 #define SFC_VER_4 0x4
#define SFC_VER_5 0x5
#define SFC_EN_INT (0) /* enable interrupt */ #define SFC_EN_INT (0) /* enable interrupt */
#define SFC_EN_DMA (1) /* enable dma */ #define SFC_EN_DMA (1) /* enable dma */
@ -67,6 +68,11 @@
/* SFC_RCVR Register */ /* SFC_RCVR Register */
#define SFC_RESET BIT(0) /* controller reset */ #define SFC_RESET BIT(0) /* controller reset */
/* 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 */
/* SFC_SR Register */ /* SFC_SR Register */
/* sfc busy flag. When busy, don't try to set the control register */ /* sfc busy flag. When busy, don't try to set the control register */
#define SFC_BUSY BIT(0) #define SFC_BUSY BIT(0)
@ -88,6 +94,7 @@
#define SFC_RAWISR 0x28 #define SFC_RAWISR 0x28
#define SFC_VER 0x2C #define SFC_VER 0x2C
#define SFC_QOP 0x30 #define SFC_QOP 0x30
#define SFC_DLL_CTRL0 0x3C
#define SFC_DMA_TRIGGER 0x80 #define SFC_DMA_TRIGGER 0x80
#define SFC_DMA_ADDR 0x84 #define SFC_DMA_ADDR 0x84
#define SFC_LEN_CTRL 0x88 #define SFC_LEN_CTRL 0x88
@ -209,6 +216,8 @@ int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size);
u16 sfc_get_version(void); u16 sfc_get_version(void);
void sfc_clean_irq(void); void sfc_clean_irq(void);
u32 sfc_get_max_iosize(void); u32 sfc_get_max_iosize(void);
void sfc_set_delay_lines(u16 cells);
void sfc_disable_delay_lines(void);
int rksfc_get_reg_addr(unsigned long *p_sfc_addr); int rksfc_get_reg_addr(unsigned long *p_sfc_addr);
#endif #endif