|
@@ -58,6 +58,7 @@ struct cqspi_flash_pdata {
|
|
u8 data_width;
|
|
u8 data_width;
|
|
u8 cs;
|
|
u8 cs;
|
|
bool registered;
|
|
bool registered;
|
|
|
|
+ bool use_direct_mode;
|
|
};
|
|
};
|
|
|
|
|
|
struct cqspi_st {
|
|
struct cqspi_st {
|
|
@@ -68,6 +69,7 @@ struct cqspi_st {
|
|
|
|
|
|
void __iomem *iobase;
|
|
void __iomem *iobase;
|
|
void __iomem *ahb_base;
|
|
void __iomem *ahb_base;
|
|
|
|
+ resource_size_t ahb_size;
|
|
struct completion transfer_complete;
|
|
struct completion transfer_complete;
|
|
struct mutex bus_mutex;
|
|
struct mutex bus_mutex;
|
|
|
|
|
|
@@ -103,6 +105,7 @@ struct cqspi_st {
|
|
/* Register map */
|
|
/* Register map */
|
|
#define CQSPI_REG_CONFIG 0x00
|
|
#define CQSPI_REG_CONFIG 0x00
|
|
#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
|
|
#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
|
|
|
|
+#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7)
|
|
#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
|
|
#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
|
|
#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
|
|
#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
|
|
#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
|
|
#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
|
|
@@ -890,6 +893,8 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
|
|
static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
|
|
static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
|
|
size_t len, const u_char *buf)
|
|
size_t len, const u_char *buf)
|
|
{
|
|
{
|
|
|
|
+ struct cqspi_flash_pdata *f_pdata = nor->priv;
|
|
|
|
+ struct cqspi_st *cqspi = f_pdata->cqspi;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = cqspi_set_protocol(nor, 0);
|
|
ret = cqspi_set_protocol(nor, 0);
|
|
@@ -900,7 +905,10 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = cqspi_indirect_write_execute(nor, to, buf, len);
|
|
|
|
|
|
+ if (f_pdata->use_direct_mode)
|
|
|
|
+ memcpy_toio(cqspi->ahb_base + to, buf, len);
|
|
|
|
+ else
|
|
|
|
+ ret = cqspi_indirect_write_execute(nor, to, buf, len);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
@@ -910,6 +918,8 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
|
|
static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
|
|
static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
|
|
size_t len, u_char *buf)
|
|
size_t len, u_char *buf)
|
|
{
|
|
{
|
|
|
|
+ struct cqspi_flash_pdata *f_pdata = nor->priv;
|
|
|
|
+ struct cqspi_st *cqspi = f_pdata->cqspi;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
ret = cqspi_set_protocol(nor, 1);
|
|
ret = cqspi_set_protocol(nor, 1);
|
|
@@ -920,7 +930,10 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = cqspi_indirect_read_execute(nor, buf, from, len);
|
|
|
|
|
|
+ if (f_pdata->use_direct_mode)
|
|
|
|
+ memcpy_fromio(buf, cqspi->ahb_base + from, len);
|
|
|
|
+ else
|
|
|
|
+ ret = cqspi_indirect_read_execute(nor, buf, from, len);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
@@ -1055,6 +1068,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev)
|
|
|
|
|
|
static void cqspi_controller_init(struct cqspi_st *cqspi)
|
|
static void cqspi_controller_init(struct cqspi_st *cqspi)
|
|
{
|
|
{
|
|
|
|
+ u32 reg;
|
|
|
|
+
|
|
cqspi_controller_enable(cqspi, 0);
|
|
cqspi_controller_enable(cqspi, 0);
|
|
|
|
|
|
/* Configure the remap address register, no remap */
|
|
/* Configure the remap address register, no remap */
|
|
@@ -1077,6 +1092,11 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
|
|
writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
|
|
writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
|
|
cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
|
|
cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
|
|
|
|
|
|
|
|
+ /* Enable Direct Access Controller */
|
|
|
|
+ reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
|
|
|
|
+ reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
|
|
|
|
+ writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
|
|
|
+
|
|
cqspi_controller_enable(cqspi, 1);
|
|
cqspi_controller_enable(cqspi, 1);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1152,6 +1172,12 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
|
|
goto err;
|
|
goto err;
|
|
|
|
|
|
f_pdata->registered = true;
|
|
f_pdata->registered = true;
|
|
|
|
+
|
|
|
|
+ if (mtd->size <= cqspi->ahb_size) {
|
|
|
|
+ f_pdata->use_direct_mode = true;
|
|
|
|
+ dev_dbg(nor->dev, "using direct mode for %s\n",
|
|
|
|
+ mtd->name);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -1211,6 +1237,7 @@ static int cqspi_probe(struct platform_device *pdev)
|
|
dev_err(dev, "Cannot remap AHB address.\n");
|
|
dev_err(dev, "Cannot remap AHB address.\n");
|
|
return PTR_ERR(cqspi->ahb_base);
|
|
return PTR_ERR(cqspi->ahb_base);
|
|
}
|
|
}
|
|
|
|
+ cqspi->ahb_size = resource_size(res_ahb);
|
|
|
|
|
|
init_completion(&cqspi->transfer_complete);
|
|
init_completion(&cqspi->transfer_complete);
|
|
|
|
|