diff --git a/arch/arm/dts/ipq40xx-dk01-c2.dts b/arch/arm/dts/ipq40xx-dk01-c2.dts index f22130dfd4..e3ae212773 100644 --- a/arch/arm/dts/ipq40xx-dk01-c2.dts +++ b/arch/arm/dts/ipq40xx-dk01-c2.dts @@ -56,4 +56,22 @@ }; }; + spi { + spi0 { + cs1 { + gpio59_CS { + gpio = <59>; + func = <0>; + out = ; + pull = ; + drvstr = ; + oe = ; + vm = ; + od_en = ; + pu_res = ; + + }; + }; + }; + }; }; diff --git a/arch/arm/dts/ipq40xx-dk04-c5.dts b/arch/arm/dts/ipq40xx-dk04-c5.dts index 38b4540bf8..89eb1bb701 100644 --- a/arch/arm/dts/ipq40xx-dk04-c5.dts +++ b/arch/arm/dts/ipq40xx-dk04-c5.dts @@ -57,4 +57,23 @@ }; }; }; + + spi { + spi0 { + cs1 { + gpio45_CS { + gpio = <45>; + func = <0>; + out = ; + pull = ; + drvstr = ; + oe = ; + vm = ; + od_en = ; + pu_res = ; + + }; + }; + }; + }; }; diff --git a/arch/arm/dts/ipq40xx-soc.dtsi b/arch/arm/dts/ipq40xx-soc.dtsi index d4b8d0098b..2b2ea1ffd7 100644 --- a/arch/arm/dts/ipq40xx-soc.dtsi +++ b/arch/arm/dts/ipq40xx-soc.dtsi @@ -12,7 +12,7 @@ */ #include "skeleton.dtsi" - +#include / { 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 = ; + pull = ; + drvstr = ; + oe = ; + vm = ; + od_en = ; + pu_res = ; + + }; + }; + }; + }; nand@79B0000 { diff --git a/drivers/spi/qca_qup_spi_bam.c b/drivers/spi/qca_qup_spi_bam.c index b5668d39e1..cc4ed46309 100644 --- a/drivers/spi/qca_qup_spi_bam.c +++ b/drivers/spi/qca_qup_spi_bam.c @@ -35,6 +35,7 @@ #include #include #include "qca_qup_spi_bam.h" +#include 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; diff --git a/drivers/spi/qca_qup_spi_bam.h b/drivers/spi/qca_qup_spi_bam.h index 93077f700a..e752a5adde 100644 --- a/drivers/spi/qca_qup_spi_bam.h +++ b/drivers/spi/qca_qup_spi_bam.h @@ -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_ */ diff --git a/include/configs/ipq40xx.h b/include/configs/ipq40xx.h index 65b4fb9079..c42582b92b 100644 --- a/include/configs/ipq40xx.h +++ b/include/configs/ipq40xx.h @@ -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 */