ipq40xx: enable SPI NAND support

This patch enables SPI-NAND support for DK and making
chip select gpio configurable from DTS.

Change-Id: I2ca7d3021fa27da1d83e2a787a1dc626919124f8
Signed-off-by: Rajkumar Ayyasamy <arajkuma@codeaurora.org>
This commit is contained in:
Rajkumar Ayyasamy 2018-01-04 18:59:19 +05:30
parent cc3573b68a
commit 8d368edb1a
6 changed files with 158 additions and 3 deletions

View file

@ -56,4 +56,22 @@
};
};
spi {
spi0 {
cs1 {
gpio59_CS {
gpio = <59>;
func = <0>;
out = <GPIO_OUTPUT>;
pull = <GPIO_PULL_UP>;
drvstr = <GPIO_10MA>;
oe = <GPIO_OE_ENABLE>;
vm = <GPIO_VM_DISABLE>;
od_en = <GPIO_OD_DISABLE>;
pu_res = <GPIO_PULL_RES0>;
};
};
};
};
};

View file

@ -57,4 +57,23 @@
};
};
};
spi {
spi0 {
cs1 {
gpio45_CS {
gpio = <45>;
func = <0>;
out = <GPIO_OUTPUT>;
pull = <GPIO_PULL_UP>;
drvstr = <GPIO_10MA>;
oe = <GPIO_OE_ENABLE>;
vm = <GPIO_VM_DISABLE>;
od_en = <GPIO_OD_DISABLE>;
pu_res = <GPIO_PULL_RES0>;
};
};
};
};
};

View file

@ -12,7 +12,7 @@
*/
#include "skeleton.dtsi"
#include <dt-bindings/qcom/gpio-ipq40xx.h>
/ {
serial@78af000 {
compatible = "qca,ipq-uartdm";
@ -46,6 +46,24 @@
rd_pipe_0 = <5>;
wr_pipe_1 = <6>;
rd_pipe_1 = <7>;
spi0 {
cs0 {
gpio54_CS {
gpio = <54>;
func = <0>;
out = <GPIO_OUTPUT>;
pull = <GPIO_PULL_UP>;
drvstr = <GPIO_10MA>;
oe = <GPIO_OE_ENABLE>;
vm = <GPIO_VM_DISABLE>;
od_en = <GPIO_OD_DISABLE>;
pu_res = <GPIO_PULL_RES0>;
};
};
};
};
nand@79B0000 {

View file

@ -35,6 +35,7 @@
#include <asm/errno.h>
#include <asm/arch-qca-common/bam.h>
#include "qca_qup_spi_bam.h"
#include <asm/arch-qca-common/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@ -191,6 +192,71 @@ static void qup_pipe_init()
}
}
/*
* Function to assert and De-assert chip select
*/
static void CS_change(int port_num, int cs_num, int enable)
{
unsigned int cs_gpio = 0;
uint32_t addr = 0;
uint32_t val = 0;
char spi_node_path[32];
int spi_cs_node = 0, spi_cs_gpio_node = 0;
snprintf(spi_node_path, sizeof(spi_node_path),
"/spi/spi%d/cs%d", port_num, cs_num);
spi_cs_node = fdt_path_offset(gd->fdt_blob, spi_node_path);
spi_cs_gpio_node = fdt_first_subnode(gd->fdt_blob, spi_cs_node);
cs_gpio = fdtdec_get_uint(gd->fdt_blob, spi_cs_gpio_node, "gpio", 0);
addr = GPIO_IN_OUT_ADDR(cs_gpio);
val = readl(addr);
val &= (~(GPIO_OUT));
if (!enable)
val |= (GPIO_OUT);
writel(val, addr);
}
/*
* BLSP TLMM configuration
*/
int blsp_pin_config(unsigned int port_num, int cs_num)
{
char spi_node_path[32];
int spi_node = 0;
snprintf(spi_node_path, sizeof(spi_node_path),
"/spi/spi%d/cs%d", port_num, cs_num);
spi_node = fdt_path_offset(gd->fdt_blob, spi_node_path);
if (spi_node >= 0) {
qca_gpio_init(spi_node);
} else {
printf("SPI : Node not found, skipping initialization\n");
return -1;
}
return 0;
}
int cs_is_valid(unsigned int port_num, int cs_num)
{
char spi_node_path[32];
int spi_node = 0;
snprintf(spi_node_path, sizeof(spi_node_path),
"/spi/spi%d/cs%d", port_num, cs_num);
spi_node = fdt_path_offset(gd->fdt_blob, spi_node_path);
if (spi_node >= 0)
return 1;
else
return 0;
}
int qup_bam_init(struct ipq_spi_slave *ds)
{
uint8_t read_pipe_grp = QUP0_DATA_PRODUCER_PIPE_GRP;
@ -317,6 +383,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
/* DMA mode */
ds->use_dma = CONFIG_QUP_SPI_USE_DMA;
if (ds->slave.cs == 1 &&
cs_is_valid(ds->slave.bus, ds->slave.cs)) {
/* GPIO Configuration for SPI NAND */
blsp_pin_config(ds->slave.bus, ds->slave.cs);
CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT);
}
return &ds->slave;
err:
free(ds);
@ -910,7 +983,14 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
return ret;
}
write_force_cs(slave, 1);
if (ds->slave.cs == 1 &&
cs_is_valid(ds->slave.bus, ds->slave.cs)) {
/* SPI NAND CS Settings */
setbits_le32(ds->regs->io_control, CS_POLARITY_MASK);
CS_change(ds->slave.bus, ds->slave.cs, CS_ASSERT);
} else {
write_force_cs(slave, 1);
}
}
if (dout != NULL) {
@ -926,7 +1006,14 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
}
if (flags & SPI_XFER_END) {
write_force_cs(slave, 0);
if (ds->slave.cs == 1 &&
cs_is_valid(ds->slave.bus, ds->slave.cs)) {
/* SPI NAND CS Settings */
clrbits_le32(ds->regs->io_control, CS_POLARITY_MASK);
CS_change(ds->slave.bus, ds->slave.cs, CS_DEASSERT);
} else {
write_force_cs(slave, 0);
}
}
return ret;

View file

@ -121,6 +121,7 @@
#define SLAVE_OPERATION (0 << 5)
#define CLK_ALWAYS_ON (0 << 9)
#define MX_CS_MODE (1 << 8)
#define CS_POLARITY_MASK (1 << 4)
#define NO_TRI_STATE (1 << 0)
#define FORCE_CS_MSK (1 << 11)
#define FORCE_CS_EN (1 << 11)
@ -297,5 +298,7 @@ static inline struct ipq_spi_slave *to_ipq_spi(struct spi_slave *slave)
static struct bam_instance bam;
struct bam_desc qup_spi_data_desc_fifo[QUP_BAM_DATA_FIFO_SIZE] __attribute__ ((aligned(BAM_DESC_SIZE)));
#define CS_ASSERT 1
#define CS_DEASSERT 0
#endif /* _IPQ_SPI_BAM_H_ */

View file

@ -153,7 +153,17 @@ typedef struct {
#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
#endif
/*
* SPI NAND SUPPORT
*/
#define CONFIG_IPQ40XX_SPI_NAND
#ifdef CONFIG_IPQ40XX_SPI_NAND
#define CONFIG_SPI_NAND
#define CONFIG_SF_SPI_NAND_CS 1
#define CONFIG_IPQ_SPI_NAND_INFO_IDX 1
#endif
#define CONFIG_QUP_SPI_USE_DMA 1
/* L1 cache line size is 64 bytes, L2 cache line size is 128 bytes
* Cache flush and invalidation based on L1 cache, so the cache line
* size is configured to 64 */