rkflash: Support sfc DLL api
Change-Id: Ibe8cd0d1e72e8dc871466dcb1014e6817b184e80 Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
parent
5b0bc49177
commit
49eba1a38a
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue