Re: [PATCH v5 0/5] Add memory mapped read support for ti-qspi
Hi Brian, On 12/11/2015 09:39 AM, Vignesh R wrote: > Changes since v4: > Use syscon to access system control module register in ti-qspi driver. > Gentle ping... Are you ok with MTD side changes of this patch series? > Changes since v3: > Rework to introduce spi_flash_read_message struct. > Support different opcode/addr/data formats as per Brian's suggestion > here: https://lkml.org/lkml/2015/11/11/454 > > Changes since v2: > Remove mmap_lock_mutex. > Optimize enable/disable of mmap mode. > > Changes since v1: > Introduce API in SPI core that MTD flash driver can call for mmap read > instead of directly calling spi-master driver callback. This API makes > sure that SPI core msg queue is locked during mmap transfers. > v1: https://lkml.org/lkml/2015/9/4/103 > > > Cover letter: > > This patch series adds support for memory mapped read port of ti-qspi. > ti-qspi has a special memory mapped port through which SPI flash > memories can be accessed directly via SoC specific memory region. > > First patch adds a method to pass flash specific information like read > opcode, dummy bytes etc and to request mmap read. Second patch > implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to > use mmap read method before trying normal SPI transfer. Patch 4 and 5 > add memory map region DT entries for DRA7xx and AM43xx SoCs. > > This patch series is based on the discussions here: > http://www.spinics.net/lists/linux-spi/msg04796.html > > Tested on DRA74 EVM and AM437x-SK. > Read performance increases from ~100kB/s to ~2.5MB/s. > > Vignesh R (5): > spi: introduce accelerated read support for spi flash devices > spi: spi-ti-qspi: add mmap mode read support > mtd: devices: m25p80: add support for mmap read request > ARM: dts: DRA7: add entry for qspi mmap region > ARM: dts: AM4372: add entry for qspi mmap region > > Documentation/devicetree/bindings/spi/ti_qspi.txt | 22 +++- > arch/arm/boot/dts/am4372.dtsi | 4 +- > arch/arm/boot/dts/dra7.dtsi | 6 +- > drivers/mtd/devices/m25p80.c | 20 > drivers/spi/spi-ti-qspi.c | 139 > +- > drivers/spi/spi.c | 45 +++ > include/linux/spi/spi.h | 41 +++ > 7 files changed, 243 insertions(+), 34 deletions(-) > -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 0/5] Add memory mapped read support for ti-qspi
On 12/11/2015 09:39 AM, Vignesh R wrote: > Changes since v4: > Use syscon to access system control module register in ti-qspi driver. > > Changes since v3: > Rework to introduce spi_flash_read_message struct. > Support different opcode/addr/data formats as per Brian's suggestion > here: https://lkml.org/lkml/2015/11/11/454 > Gentle Ping on the series... > Changes since v2: > Remove mmap_lock_mutex. > Optimize enable/disable of mmap mode. > > Changes since v1: > Introduce API in SPI core that MTD flash driver can call for mmap read > instead of directly calling spi-master driver callback. This API makes > sure that SPI core msg queue is locked during mmap transfers. > v1: https://lkml.org/lkml/2015/9/4/103 > > > Cover letter: > > This patch series adds support for memory mapped read port of ti-qspi. > ti-qspi has a special memory mapped port through which SPI flash > memories can be accessed directly via SoC specific memory region. > > First patch adds a method to pass flash specific information like read > opcode, dummy bytes etc and to request mmap read. Second patch > implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to > use mmap read method before trying normal SPI transfer. Patch 4 and 5 > add memory map region DT entries for DRA7xx and AM43xx SoCs. > > This patch series is based on the discussions here: > http://www.spinics.net/lists/linux-spi/msg04796.html > > Tested on DRA74 EVM and AM437x-SK. > Read performance increases from ~100kB/s to ~2.5MB/s. > > Vignesh R (5): > spi: introduce accelerated read support for spi flash devices > spi: spi-ti-qspi: add mmap mode read support > mtd: devices: m25p80: add support for mmap read request > ARM: dts: DRA7: add entry for qspi mmap region > ARM: dts: AM4372: add entry for qspi mmap region > > Documentation/devicetree/bindings/spi/ti_qspi.txt | 22 +++- > arch/arm/boot/dts/am4372.dtsi | 4 +- > arch/arm/boot/dts/dra7.dtsi | 6 +- > drivers/mtd/devices/m25p80.c | 20 > drivers/spi/spi-ti-qspi.c | 139 > +- > drivers/spi/spi.c | 45 +++ > include/linux/spi/spi.h | 41 +++ > 7 files changed, 243 insertions(+), 34 deletions(-) > -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 4/5] ARM: dts: DRA7: add entry for qspi mmap region
On 12/18/2015 12:15 AM, Tony Lindgren wrote: > * Rob Herring <r...@kernel.org> [151211 07:10]: >> On Fri, Dec 11, 2015 at 09:39:59AM +0530, Vignesh R wrote: >>> Add qspi memory mapped region entries for DRA7xx based SoCs. Also, >>> update the binding documents for the controller to document this change. >>> >>> Signed-off-by: Vignesh R <vigne...@ti.com> >> >> Acked-by: Rob Herring <r...@kernel.org> > > Vignes, are patches 4 and 5 safe to apply separately already or > do things break if we do that? Yes, 4 and 5 can be applied separately w/o driver changes. -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 2/5] spi: spi-ti-qspi: add mmap mode read support
ti-qspi controller provides mmap port to read data from SPI flashes. mmap port is enabled in QSPI_SPI_SWITCH_REG. ctrl module register may also need to be accessed for some SoCs. The QSPI_SPI_SETUP_REGx needs to be populated with flash specific information like read opcode, read mode(quad, dual, normal), address width and dummy bytes. Once, controller is in mmap mode, the whole flash memory is available as a memory region at SoC specific address. This region can be accessed using normal memcpy() (or mem-to-mem dma copy). The ti-qspi controller hardware will internally communicate with SPI flash over SPI bus and get the requested data. Implement spi_flash_read() callback to support mmap read over SPI flash devices. With this, the read throughput increases from ~100kB/s to ~2.5 MB/s. Signed-off-by: Vignesh R <vigne...@ti.com> --- v5: * use syscon to access ctrl_mod register. drivers/spi/spi-ti-qspi.c | 139 -- 1 file changed, 110 insertions(+), 29 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 64318fcfacf2..eac3c960b2de 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include @@ -44,8 +46,9 @@ struct ti_qspi { struct spi_master *master; void __iomem*base; - void __iomem*ctrl_base; void __iomem*mmap_base; + struct regmap *ctrl_base; + unsigned intctrl_reg; struct clk *fclk; struct device *dev; @@ -55,7 +58,7 @@ struct ti_qspi { u32 cmd; u32 dc; - bool ctrl_mod; + bool mmap_enabled; }; #define QSPI_PID (0x0) @@ -65,11 +68,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -109,6 +109,17 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) +#define MEM_CS_MASK(7 << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -366,6 +377,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) { + regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, + MEM_CS_EN(spi->chip_select), + MEM_CS_MASK); + } + qspi->mmap_enabled = true; +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_base) + regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, + 0, MEM_CS_MASK); + qspi->mmap_enabled = false; +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 memval = msg->read_opcode; + + switch (msg->data_nbits) { + case SPI_NBITS_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_NBITS_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static int ti_qspi_spi_flash_read(struct spi_device *spi, + struc
[PATCH v5 3/5] mtd: devices: m25p80: add support for mmap read request
Certain spi controllers may provide accelerated interface to read from m25p80 type flash devices. This interface provides better read performance than regular SPI interface. Call spi_flash_read(), if supported, to make use of such interface. Signed-off-by: Vignesh R <vigne...@ti.com> --- v5: No changes drivers/mtd/devices/m25p80.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index fe9ceb7b5405..00094a668c62 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -131,6 +131,26 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, /* convert the dummy cycles to the number of bytes */ dummy /= 8; + if (spi_flash_read_supported(spi)) { + struct spi_flash_read_message msg; + int ret; + + msg.buf = buf; + msg.from = from; + msg.len = len; + msg.read_opcode = nor->read_opcode; + msg.addr_width = nor->addr_width; + msg.dummy_bytes = dummy; + /* TODO: Support other combinations */ + msg.opcode_nbits = SPI_NBITS_SINGLE; + msg.addr_nbits = SPI_NBITS_SINGLE; + msg.data_nbits = m25p80_rx_nbits(nor); + + ret = spi_flash_read(spi, ); + *retlen = msg.retlen; + return ret; + } + spi_message_init(); memset(t, 0, (sizeof t)); -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 0/5] Add memory mapped read support for ti-qspi
Changes since v4: Use syscon to access system control module register in ti-qspi driver. Changes since v3: Rework to introduce spi_flash_read_message struct. Support different opcode/addr/data formats as per Brian's suggestion here: https://lkml.org/lkml/2015/11/11/454 Changes since v2: Remove mmap_lock_mutex. Optimize enable/disable of mmap mode. Changes since v1: Introduce API in SPI core that MTD flash driver can call for mmap read instead of directly calling spi-master driver callback. This API makes sure that SPI core msg queue is locked during mmap transfers. v1: https://lkml.org/lkml/2015/9/4/103 Cover letter: This patch series adds support for memory mapped read port of ti-qspi. ti-qspi has a special memory mapped port through which SPI flash memories can be accessed directly via SoC specific memory region. First patch adds a method to pass flash specific information like read opcode, dummy bytes etc and to request mmap read. Second patch implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to use mmap read method before trying normal SPI transfer. Patch 4 and 5 add memory map region DT entries for DRA7xx and AM43xx SoCs. This patch series is based on the discussions here: http://www.spinics.net/lists/linux-spi/msg04796.html Tested on DRA74 EVM and AM437x-SK. Read performance increases from ~100kB/s to ~2.5MB/s. Vignesh R (5): spi: introduce accelerated read support for spi flash devices spi: spi-ti-qspi: add mmap mode read support mtd: devices: m25p80: add support for mmap read request ARM: dts: DRA7: add entry for qspi mmap region ARM: dts: AM4372: add entry for qspi mmap region Documentation/devicetree/bindings/spi/ti_qspi.txt | 22 +++- arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 6 +- drivers/mtd/devices/m25p80.c | 20 drivers/spi/spi-ti-qspi.c | 139 +- drivers/spi/spi.c | 45 +++ include/linux/spi/spi.h | 41 +++ 7 files changed, 243 insertions(+), 34 deletions(-) -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 1/5] spi: introduce accelerated read support for spi flash devices
In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special port (like memory mapped port) that are optimized to improve SPI flash read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, SPI controller needs to know flash specific information like read command to use, dummy bytes and address width. Introduce spi_flash_read() interface to support accelerated read over SPI flash devices. SPI master drivers can implement this callback to support interfaces such as memory mapped read etc. m25p80 flash driver and other flash drivers can call this make use of such interfaces. The interface should only be used with SPI flashes and cannot be used with other SPI devices. Signed-off-by: Vignesh R <vigne...@ti.com> --- v5: No changes. drivers/spi/spi.c | 45 + include/linux/spi/spi.h | 41 + 2 files changed, 86 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e2415be209d5..cc2b54139352 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1134,6 +1134,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) } } + mutex_lock(>bus_lock_mutex); trace_spi_message_start(master->cur_msg); if (master->prepare_message) { @@ -1143,6 +1144,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) "failed to prepare message: %d\n", ret); master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } master->cur_msg_prepared = true; @@ -1152,6 +1154,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } @@ -1159,8 +1162,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { dev_err(>dev, "failed to transfer one message from queue\n"); + mutex_unlock(>bus_lock_mutex); return; } + mutex_unlock(>bus_lock_mutex); } /** @@ -2327,6 +2332,46 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) EXPORT_SYMBOL_GPL(spi_async_locked); +int spi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) + +{ + struct spi_master *master = spi->master; + int ret; + + if ((msg->opcode_nbits == SPI_NBITS_DUAL || +msg->addr_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) + return -EINVAL; + if ((msg->opcode_nbits == SPI_NBITS_QUAD || +msg->addr_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_TX_QUAD)) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_DUAL && + !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_QUAD && + !(spi->mode & SPI_RX_QUAD)) + return -EINVAL; + + if (master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(>dev, "Failed to power device: %d\n", + ret); + return ret; + } + } + mutex_lock(>bus_lock_mutex); + ret = master->spi_flash_read(spi, msg); + mutex_unlock(>bus_lock_mutex); + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); + + return ret; +} +EXPORT_SYMBOL_GPL(spi_flash_read); + /*-*/ /* Utility methods for SPI master protocol drivers, layered on diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index cce80e6dc7d1..246d7d519f3f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -25,6 +25,7 @@ struct dma_chan; struct spi_master; struct spi_transfer; +struct spi_flash_read_message; /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -361,6 +362,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @handle_err: the subsystem calls the driver to handle an error that occurs * in the generic implementation of transfer_one_message(). * @un
[PATCH v5 5/5] ARM: dts: AM4372: add entry for qspi mmap region
Add qspi memory mapped region entries for AM43xx based SoCs. Also, update the binding documents for the controller to document this change. Acked-by: Rob Herring <r...@kernel.org> Signed-off-by: Vignesh R <vigne...@ti.com> --- v5: No changes. Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- arch/arm/boot/dts/am4372.dtsi | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 809c3f334316..cc8304aa64ac 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -21,9 +21,10 @@ Optional properties: Example: +For am4372: qspi: qspi@4b30 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4790 0x100>, <0x3000 0x3ff>; + compatible = "ti,am4372-qspi"; + reg = <0x4790 0x100>, <0x3000 0x400>; reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d83ff9c9701e..e32d164102d1 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -963,7 +963,9 @@ qspi: qspi@4790 { compatible = "ti,am4372-qspi"; - reg = <0x4790 0x100>; + reg = <0x4790 0x100>, + <0x3000 0x400>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 4/5] ARM: dts: DRA7: add entry for qspi mmap region
Add qspi memory mapped region entries for DRA7xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> --- v5: use syscon to access scm register. Documentation/devicetree/bindings/spi/ti_qspi.txt | 17 + arch/arm/boot/dts/dra7.dtsi | 6 -- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 601a360531a5..809c3f334316 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -15,6 +15,10 @@ Recommended properties: - spi-max-frequency: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt +Optional properties: +- syscon-chipselects: Handle to system control region contains QSPI + chipselect register and offset of that register. + Example: qspi: qspi@4b30 { @@ -26,3 +30,16 @@ qspi: qspi@4b30 { spi-max-frequency = <2500>; ti,hwmods = "qspi"; }; + +For dra7xx: +qspi: qspi@4b30 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>, + reg-names = "qspi_base", "qspi_mmap"; + syscon-chipselects = <_conf 0x558>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4800>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index fe99231cbde5..be91c7781c07 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1153,8 +1153,10 @@ qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b30 0x100>; - reg-names = "qspi_base"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>; + reg-names = "qspi_base", "qspi_mmap"; + syscon-chipselects = <_conf 0x558>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 4/5] ARM: dts: DRA7: add entry for qspi mmap region
On 12/03/2015 03:51 PM, Vignesh R wrote: > > > On 12/01/2015 10:09 PM, Tony Lindgren wrote: >> * Vignesh R <vigne...@ti.com> [151130 20:46]: >>> On 12/01/2015 04:04 AM, Tony Lindgren wrote: >>>> ... >> >> OK. They are both on L3 main so that won't cause any issues for separate >> interconnect driver instances. As they are still separate targets flushing >> a posted write to one area will not flush anything to the other. >> > > I didn't quite understand what you meant by interconnect driver instance. > qspi_base and qspi_mmap region are tightly bound to each other and both > needs to be accessed by ti-qspi driver (though different targets). > Besides qspi_mmap region is only used to read data, there will not be > any write accesses to this target. Are you saying this binding is not > viable? > As I stated above qspi_base and qspi_mmap region are tightly bound, there is no way to use qspi_mmap region w/o accessing qspi_base. So I am planning to keep them as it is. I will move qspi_ctrlmod to use syscon. Something like: qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; reg = <0x4b30 0x100>, <0x5c00 0x400>, reg-names = "qspi_base", "qspi_mmap"; syscon-chipselects = <_conf 0x558>; #address-cells = <1>; #size-cells = <0>; spi-max-frequency = <4800>; ti,hwmods = "qspi"; }; Do you think this is not viable in future? -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 4/5] ARM: dts: DRA7: add entry for qspi mmap region
On 12/01/2015 10:09 PM, Tony Lindgren wrote: > * Vignesh R <vigne...@ti.com> [151130 20:46]: >> On 12/01/2015 04:04 AM, Tony Lindgren wrote: >>> >>> Actually none of the IO areas above are within the same interconnect target: >>> >>> 0x4b30 QSPI0 address space in L3 main interconnect >>> 0x5c00 QSPI1 address space in L3 main interconnect >> >> >> First address range (configuration port: 0x4b30) corresponds to QSPI >> registers space. These registers alone are sufficient for generic SPI >> communication (serial flash as well as non-flash SPI devices). > > OK > >> In order to speed up SPI flash reads SFI_MM_IF(SPI memory mapped >> interface) is provided by QSPI IP. This _cannot_ be used with non-flash >> devices. > > OK > >> The second address range (0x5c00) corresponds to memory-mapped >> region of SFI_MM_IF, through which SPI flash memories can be read as if >> though they were RAM addresses (i.e using readl/memcpy). The SFI_MM_IF >> block that takes care of communicating over SPI bus and getting the data >> from flash device. > > OK > >> But SFI_MM_IF block needs to know some flash specific information(such >> as read opcode, address bytes, dummy bytes, mode). This information must >> first be populated in QSPI_SPI_SETUP*_REG(0x4B300054-60) before >> accessing SFI_MM_IF address range via readl. >> Both addresses space belong to same instance of the driver, one >> corresponds to register space and other is memory-mapped region. >> Therefore both regions are claimed by the same driver. > > OK > >>> 0x4a002558 CTRL_CORE_CONTROL_IO_2 in System Control Module (SCM) in L4_CFG >>> >>> The first two address spaces should be two separate instances of this >>> driver. >> >> Not actually two instances. > > OK. They are both on L3 main so that won't cause any issues for separate > interconnect driver instances. As they are still separate targets flushing > a posted write to one area will not flush anything to the other. > I didn't quite understand what you meant by interconnect driver instance. qspi_base and qspi_mmap region are tightly bound to each other and both needs to be accessed by ti-qspi driver (though different targets). Besides qspi_mmap region is only used to read data, there will not be any write accesses to this target. Are you saying this binding is not viable? >>> The CTRL_CORE_CONTROL_IO_2 needs seems like a shared clock register that >>> needs to be accessed using the clock framework most likely. >>> >> >> Not shared clock. >> The CTRL_CORE_CONTROL_IO_2[10:8] QSPI_MEMMAPPED_CS bit fields provides a >> functionality for remapping the previously described address space which >> starts at 0x5C00 L3_MAIN address to one of the four supported chip >> selects. >> How about using syscon to access CTRL_CORE_CONTROL_IO_2? > > A separate driver implementing some Linux generic framework would be idael :) > > But if that does not fit, yeah then syscon makes sense as that IO range > will be on separate interconnect driver (and clock and possibly power domain) > instances eventually. > I will go ahead with syscon for accessing CTRL_CORE_CONTROL_IO_2 register. -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 3/5] mtd: devices: m25p80: add support for mmap read request
Hi, On 12/03/2015 03:12 PM, Cyrille Pitchen wrote: > Hi Vignesh, > > Le 30/11/2015 06:15, Vignesh R a écrit : >> Certain spi controllers may provide accelerated interface to read from >> m25p80 type flash devices. This interface provides better read >> performance than regular SPI interface. >> Call spi_flash_read(), if supported, to make use of such interface. >> >> Signed-off-by: Vignesh R <vigne...@ti.com> >> --- >> >> v4: >> * Use spi_flash_read_message struct to pass args. >> * support passing of opcode/addr/data nbits. >> >> drivers/mtd/devices/m25p80.c | 20 >> 1 file changed, 20 insertions(+) >> >> diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c >> index fe9ceb7b5405..00094a668c62 100644 >> --- a/drivers/mtd/devices/m25p80.c >> +++ b/drivers/mtd/devices/m25p80.c >> @@ -131,6 +131,26 @@ static int m25p80_read(struct spi_nor *nor, loff_t >> from, size_t len, >> /* convert the dummy cycles to the number of bytes */ >> dummy /= 8; >> >> +if (spi_flash_read_supported(spi)) { >> +struct spi_flash_read_message msg; >> +int ret; >> + >> +msg.buf = buf; >> +msg.from = from; >> +msg.len = len; >> +msg.read_opcode = nor->read_opcode; >> +msg.addr_width = nor->addr_width; >> +msg.dummy_bytes = dummy; >> +/* TODO: Support other combinations */ >> +msg.opcode_nbits = SPI_NBITS_SINGLE; >> +msg.addr_nbits = SPI_NBITS_SINGLE; >> +msg.data_nbits = m25p80_rx_nbits(nor); > > I wanted to let you know that the support of other SPI protocols has already > been implemented by this series: > http://lists.infradead.org/pipermail/linux-arm-kernel/2015-September/371170.html > > patches 2 & 3 handle the probing of the (Q)SPI memory in spi_nor_scan() and > select the right protocols for register read/write, memory read, memory write, > and memory erase operations. The choice is done according to both the memory > and SPI controller capabilities. > > patch 4 updates the m25p80 driver to take advantage of the bandwidth increase > allowed by QSPI protocols. For instance, the Atmel QSPI controller, like TI > one, maps the SPI NOR memory to the system bus. Yesterday I ran mtd_speedtest > to compare Fast Read 1-1-1 (0x0b) and Fast Read 1-1-4 (0x6b). The SPI clock > frequency was limited to 83MHz. The QSPI memory is a Micron n25q128a13. > > I only had to change the mode argument of spi_nor_scan() from SPI_NOR_QUAD to > SPI_NOR_FAST in the atmel_quadspi driver (based on fsl-quadspi driver from > Freescale since Atmel's driver also uses the system bus mapping for memory > write operations) to force the spi-nor framework to choose the SPI 1-1-1 > protocol instead of the SPI-1-1-4. > > 1 - Fast Read 1-1-1 > > mtd_speedtest: testing eraseblock write speed > mtd_speedtest: eraseblock read speed is 9319 KiB/s > [...] > mtd_speedtest: testing page read speed > mtd_speedtest: page read speed is 6649 KiB/s > [...] > mtd_speedtest: testing 2 page read speed > mtd_speedtest: 2 page read speed is 7757 KiB/s > > 2 - Fast Read 1-1-4 > > mtd_speedtest: testing eraseblock read speed > mtd_speedtest: eraseblock read speed is 30117 KiB/s > [...] > mtd_speedtest: testing page read speed > mtd_speedtest: page read speed is 13096 KiB/s > [...] > mtd_speedtest: testing 2 page read speed > mtd_speedtest: 2 page read speed is 18224 KiB/s > > So the performance improvements are: > eraseblock read speed (65536 bytes) : +223% > page read speed (512 bytes) : +97% > 2 page read speed (1024 bytes) : +135% > > > That's why I believe that you could take advantage of these performance > improvements in the TI (Q)SPI controller driver. > Well, I based my patches on linux-next as per Brian's suggestion. If patches to support other flash protocol modes are accepted, I would be happy to rebase and make use of other modes. It would just be the matter of populating msg.{opcode/addr}_n_bits correctly. > > Also please note that you may have to add in the struct spi_flash_read_message > two other fields for the number of option/mode cycles and their value. > Option/mode cycles are sent between the address and dummy cycles. They are > used by some memory manufacturers such as Spansion, Micron and Macronix to > enter/leave their continuous read mode. > So if uninitialized dummy cycles are interpreted by the QSPI memory as > option/mode cycles, depending on the actual value, the memory may enter by > mista
Re: [PATCH v4 4/5] ARM: dts: DRA7: add entry for qspi mmap region
On 12/01/2015 04:04 AM, Tony Lindgren wrote: > * Vignesh R <vigne...@ti.com> [151129 21:16]: >> Add qspi memory mapped region entries for DRA7xx based SoCs. Also, >> update the binding documents for the controller to document this change. >> >> Acked-by: Rob Herring <r...@kernel.org> >> Signed-off-by: Vignesh R <vigne...@ti.com> > ... >> --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt >> +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt >> @@ -26,3 +26,17 @@ qspi: qspi@4b30 { >> spi-max-frequency = <2500>; >> ti,hwmods = "qspi"; >> }; >> + >> +For dra7xx: >> +qspi: qspi@4b30 { >> +compatible = "ti,dra7xxx-qspi"; >> +reg = <0x4b30 0x100>, >> + <0x5c00 0x400>, >> + <0x4a002558 0x4>; >> +reg-names = "qspi_base", "qspi_mmap", >> +"qspi_ctrlmod"; >> +#address-cells = <1>; >> +#size-cells = <0>; >> +spi-max-frequency = <4800>; >> +ti,hwmods = "qspi"; >> +}; > > Actually none of the IO areas above are within the same interconnect target: > > 0x4b30 QSPI0 address space in L3 main interconnect > 0x5c00 QSPI1 address space in L3 main interconnect First address range (configuration port: 0x4b30) corresponds to QSPI registers space. These registers alone are sufficient for generic SPI communication (serial flash as well as non-flash SPI devices). In order to speed up SPI flash reads SFI_MM_IF(SPI memory mapped interface) is provided by QSPI IP. This _cannot_ be used with non-flash devices. The second address range (0x5c00) corresponds to memory-mapped region of SFI_MM_IF, through which SPI flash memories can be read as if though they were RAM addresses (i.e using readl/memcpy). The SFI_MM_IF block that takes care of communicating over SPI bus and getting the data from flash device. But SFI_MM_IF block needs to know some flash specific information(such as read opcode, address bytes, dummy bytes, mode). This information must first be populated in QSPI_SPI_SETUP*_REG(0x4B300054-60) before accessing SFI_MM_IF address range via readl. Both addresses space belong to same instance of the driver, one corresponds to register space and other is memory-mapped region. Therefore both regions are claimed by the same driver. > 0x4a002558 CTRL_CORE_CONTROL_IO_2 in System Control Module (SCM) in L4_CFG > > The first two address spaces should be two separate instances of this driver. Not actually two instances. > The CTRL_CORE_CONTROL_IO_2 needs seems like a shared clock register that > needs to be accessed using the clock framework most likely. > Not shared clock. The CTRL_CORE_CONTROL_IO_2[10:8] QSPI_MEMMAPPED_CS bit fields provides a functionality for remapping the previously described address space which starts at 0x5C00 L3_MAIN address to one of the four supported chip selects. How about using syscon to access CTRL_CORE_CONTROL_IO_2? -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 2/5] spi: spi-ti-qspi: add mmap mode read support
Hi Felipe, On 12/01/2015 04:05 AM, Balbi, Felipe wrote: > > Hi, > > Vignesh R <vigne...@ti.com> writes: [...] >> +} >> + >> +static int ti_qspi_spi_flash_read(struct spi_device *spi, >> + struct spi_flash_read_message *msg) >> +{ >> +struct ti_qspi *qspi = spi_master_get_devdata(spi->master); >> +int ret = 0; >> + >> +mutex_lock(>list_lock); >> + >> +if (!qspi->mmap_enabled) >> +ti_qspi_enable_memory_map(spi); >> +ti_qspi_setup_mmap_read(spi, msg); >> +memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); >> +msg->retlen = msg->len; > > the way I have always expected this to work was that spi controller > would setup the mmap region (using ranges?) and pass the base address to > the SPI NOR flash instead, so that could call standard > write[bwl]/read[bwl] functions. > > I mean, when we're dealing with AXI, AHB, PCI, OCP, whatever we > completely ignore these details, why should SPI be different ? If it's > memory mapped, the SW view of the thing is a piece of memory and that > should be accessible with standard {read,write}[bwl]() calls. > This is just an acceleration provided to improve flash read speeds. Whenever there is an access to QSPI memory map region, there is a SFI_MM_IF block in QSPI IP that generates SPI bus signals in order fetch the data from flash. This SFI_MM_IF must first be configured with flash specific information like read opcode, read mode, dummy bytes etc (which may vary from flash to flash), by writing to QSPI_SPI_SETUP*_REG also, SFI_MM_IF needs to be selected by writing to QSPI_SPI_SWITCH_REG. IMO, there has to be a call from spi-nor to ti-qspi before using standard {read,write}[bwl]() calls for populating flash info, power mgmt and locking SPI bus. > I really think $subject is not a good way forward because it gives too > much responsibility to the SPI controller driver; note that this driver > is the one actually accessing the memory map region, instead of simply > setting it up and passing it along. > How would you propose to setup mmap transfers while taking care of SPI bus locking and passing of flash info to ti-qspi? > So the way I see it, the DTS should be like so: > > qspi@XYZ { > reg = ; > [...] > ranges = <0 0 0x3000 $size>; > > flash@0,0 { >compatible = "mp2580"; >reg = <0 0 $flash_size>; > }; > }; > > > if you have more than one device sitting on this SPI bus using different > chip selects, that's easy too, just change your ranges property: > > qspi@XYZ { > reg = ; > [...] > ranges = <0 0 0x3000 0x1000 >1 0 0x30001000 0x1000 >2 0 0x30002000 0x1000>; > > flash@0,0 { > [...] > }; > > flash@1,0 { >[...] > }; > > flash@2,0 { >[...] > }; > }; > No, even if there are multiple slaves, all slaves map to the same start address (0x3000 in above example). Based on the chip-select line that is asserted (selected by writing to a particular CTRL_MODULE register field), the corresponding slave responds. Different slaves cannot be mapped to different address ranges inside mmap address space. The ranges property will always be the same for all slaves and all chip-selects. > and so on. From ti-qspi perspective, you should just setup the memory > map and from mp25p80 you would check if your reg property pointed to an > address that looks like memory, then ioremap it and use tradicional > {read,write}[bwl]() accessors. Any reasons why that wasn't done the way > pointed out above ? > There might be a SPI controller that provides accelerated interface for SPI flash read not as a memory mapping but some-other way. Brian Norris has pointed out that there is at least one other controller which provides such acceleration w/o memory mapping[1] May be Brian can explain that better? [1]https://lkml.org/lkml/2015/11/10/618 -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 1/5] spi: introduce accelerated read support for spi flash devices
In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special port (like memory mapped port) that are optimized to improve SPI flash read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, SPI controller needs to know flash specific information like read command to use, dummy bytes and address width. Introduce spi_flash_read() interface to support accelerated read over SPI flash devices. SPI master drivers can implement this callback to support interfaces such as memory mapped read etc. m25p80 flash driver and other flash drivers can call this make use of such interfaces. The interface should only be used with SPI flashes and cannot be used with other SPI devices. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi.c | 45 + include/linux/spi/spi.h | 41 + 2 files changed, 86 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e2415be209d5..cc2b54139352 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1134,6 +1134,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) } } + mutex_lock(>bus_lock_mutex); trace_spi_message_start(master->cur_msg); if (master->prepare_message) { @@ -1143,6 +1144,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) "failed to prepare message: %d\n", ret); master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } master->cur_msg_prepared = true; @@ -1152,6 +1154,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } @@ -1159,8 +1162,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { dev_err(>dev, "failed to transfer one message from queue\n"); + mutex_unlock(>bus_lock_mutex); return; } + mutex_unlock(>bus_lock_mutex); } /** @@ -2327,6 +2332,46 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) EXPORT_SYMBOL_GPL(spi_async_locked); +int spi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) + +{ + struct spi_master *master = spi->master; + int ret; + + if ((msg->opcode_nbits == SPI_NBITS_DUAL || +msg->addr_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) + return -EINVAL; + if ((msg->opcode_nbits == SPI_NBITS_QUAD || +msg->addr_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_TX_QUAD)) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_DUAL && + !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_QUAD && + !(spi->mode & SPI_RX_QUAD)) + return -EINVAL; + + if (master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(>dev, "Failed to power device: %d\n", + ret); + return ret; + } + } + mutex_lock(>bus_lock_mutex); + ret = master->spi_flash_read(spi, msg); + mutex_unlock(>bus_lock_mutex); + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); + + return ret; +} +EXPORT_SYMBOL_GPL(spi_flash_read); + /*-*/ /* Utility methods for SPI master protocol drivers, layered on diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index cce80e6dc7d1..246d7d519f3f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -25,6 +25,7 @@ struct dma_chan; struct spi_master; struct spi_transfer; +struct spi_flash_read_message; /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -361,6 +362,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @handle_err: the subsystem calls the driver to handle an error that occurs * in the generic implementation of transfer_one_message(). * @unprepare_messag
[PATCH v4 0/5] Add memory mapped read support for ti-qspi
Changes since v3: Rework to introduce spi_flash_read_message struct. Support different opcode/addr/data formats as per Brian's suggestion here: https://lkml.org/lkml/2015/11/11/454 Changes since v2: Remove mmap_lock_mutex. Optimize enable/disable of mmap mode. Changes since v1: Introduce API in SPI core that MTD flash driver can call for mmap read instead of directly calling spi-master driver callback. This API makes sure that SPI core msg queue is locked during mmap transfers. v1: https://lkml.org/lkml/2015/9/4/103 Cover letter: This patch series adds support for memory mapped read port of ti-qspi. ti-qspi has a special memory mapped port through which SPI flash memories can be accessed directly via SoC specific memory region. First patch adds a method to pass flash specific information like read opcode, dummy bytes etc and to request mmap read. Second patch implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to use mmap read method before trying normal SPI transfer. Patch 4 and 5 add memory map region DT entries for DRA7xx and AM43xx SoCs. This patch series is based on the discussions here: http://www.spinics.net/lists/linux-spi/msg04796.html Tested on DRA74 EVM and AM437x-SK. Read performance increases from ~100kB/s to ~2.5MB/s. Vignesh R (5): spi: introduce accelerated read support for spi flash devices spi: spi-ti-qspi: add mmap mode read support mtd: devices: m25p80: add support for mmap read request ARM: dts: DRA7: add entry for qspi mmap region ARM: dts: AM4372: add entry for qspi mmap region Documentation/devicetree/bindings/spi/ti_qspi.txt | 19 +++- arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 7 +- drivers/mtd/devices/m25p80.c | 20 + drivers/spi/spi-ti-qspi.c | 101 -- drivers/spi/spi.c | 45 ++ include/linux/spi/spi.h | 41 + 7 files changed, 225 insertions(+), 12 deletions(-) -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 3/5] mtd: devices: m25p80: add support for mmap read request
Certain spi controllers may provide accelerated interface to read from m25p80 type flash devices. This interface provides better read performance than regular SPI interface. Call spi_flash_read(), if supported, to make use of such interface. Signed-off-by: Vignesh R <vigne...@ti.com> --- v4: * Use spi_flash_read_message struct to pass args. * support passing of opcode/addr/data nbits. drivers/mtd/devices/m25p80.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index fe9ceb7b5405..00094a668c62 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -131,6 +131,26 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, /* convert the dummy cycles to the number of bytes */ dummy /= 8; + if (spi_flash_read_supported(spi)) { + struct spi_flash_read_message msg; + int ret; + + msg.buf = buf; + msg.from = from; + msg.len = len; + msg.read_opcode = nor->read_opcode; + msg.addr_width = nor->addr_width; + msg.dummy_bytes = dummy; + /* TODO: Support other combinations */ + msg.opcode_nbits = SPI_NBITS_SINGLE; + msg.addr_nbits = SPI_NBITS_SINGLE; + msg.data_nbits = m25p80_rx_nbits(nor); + + ret = spi_flash_read(spi, ); + *retlen = msg.retlen; + return ret; + } + spi_message_init(); memset(t, 0, (sizeof t)); -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 2/5] spi: spi-ti-qspi: add mmap mode read support
ti-qspi controller provides mmap port to read data from SPI flashes. mmap port is enabled in QSPI_SPI_SWITCH_REG. ctrl module register may also need to be accessed for some SoCs. The QSPI_SPI_SETUP_REGx needs to be populated with flash specific information like read opcode, read mode(quad, dual, normal), address width and dummy bytes. Once, controller is in mmap mode, the whole flash memory is available as a memory region at SoC specific address. This region can be accessed using normal memcpy() (or mem-to-mem dma copy). The ti-qspi controller hardware will internally communicate with SPI flash over SPI bus and get the requested data. Implement spi_flash_read() callback to support mmap read over SPI flash devices. With this, the read throughput increases from ~100kB/s to ~2.5 MB/s. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi-ti-qspi.c | 101 ++ 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 64318fcfacf2..cd4e63f45e65 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -56,6 +56,7 @@ struct ti_qspi { u32 dc; bool ctrl_mod; + bool mmap_enabled; }; #define QSPI_PID (0x0) @@ -65,11 +66,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -109,6 +107,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -366,6 +374,78 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val |= MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + /* dummy readl to ensure bus sync */ + readl(qspi->ctrl_base); + } + qspi->mmap_enabled = true; +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val &= ~MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } + qspi->mmap_enabled = false; +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 memval = msg->read_opcode; + + switch (msg->data_nbits) { + case SPI_NBITS_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_NBITS_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static int ti_qspi_spi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + int ret = 0; + + mutex_lock(>list_lock); + + if (!qspi->mmap_enabled) + ti_qspi_enable_memory_map(spi); + ti_qspi_setup_mmap_read(spi, msg); + memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); + msg->retlen = msg->len; + + mutex_unlock(>list_lock
[PATCH v4 5/5] ARM: dts: AM4372: add entry for qspi mmap region
Add qspi memory mapped region entries for AM43xx based SoCs. Also, update the binding documents for the controller to document this change. Acked-by: Rob Herring <r...@kernel.org> Signed-off-by: Vignesh R <vigne...@ti.com> --- v4: No changes. Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- arch/arm/boot/dts/am4372.dtsi | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 334aa3f32cbc..5a1542eda387 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -17,9 +17,10 @@ Recommended properties: Example: +For am4372: qspi: qspi@4b30 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4790 0x100>, <0x3000 0x3ff>; + compatible = "ti,am4372-qspi"; + reg = <0x4790 0x100>, <0x3000 0x400>; reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d83ff9c9701e..e32d164102d1 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -963,7 +963,9 @@ qspi: qspi@4790 { compatible = "ti,am4372-qspi"; - reg = <0x4790 0x100>; + reg = <0x4790 0x100>, + <0x3000 0x400>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 4/5] ARM: dts: DRA7: add entry for qspi mmap region
Add qspi memory mapped region entries for DRA7xx based SoCs. Also, update the binding documents for the controller to document this change. Acked-by: Rob Herring <r...@kernel.org> Signed-off-by: Vignesh R <vigne...@ti.com> --- v4: No changes. Documentation/devicetree/bindings/spi/ti_qspi.txt | 14 ++ arch/arm/boot/dts/dra7.dtsi | 7 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 601a360531a5..334aa3f32cbc 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -26,3 +26,17 @@ qspi: qspi@4b30 { spi-max-frequency = <2500>; ti,hwmods = "qspi"; }; + +For dra7xx: +qspi: qspi@4b30 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>, + <0x4a002558 0x4>; + reg-names = "qspi_base", "qspi_mmap", + "qspi_ctrlmod"; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4800>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index fe99231cbde5..debe7523643d 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1153,8 +1153,11 @@ qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b30 0x100>; - reg-names = "qspi_base"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>, + <0x4a002558 0x4>; + reg-names = "qspi_base", "qspi_mmap", + "qspi_ctrlmod"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] ARM: dts: dra72-evm: Mark uart1 rxd as wakeup capable
Uart1 rxd is wakeup capable on DRA72 EVM. Hence, mark rxd line as wakeup capable. This is similar to commit 66b0436977e2c ("ARM: dts: dra7-evm: Mark uart1 rxd as wakeup capable") for DRA74 EVM. Signed-off-by: Vignesh R <vigne...@ti.com> --- arch/arm/boot/dts/dra72-evm.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts index d6104d5f0c01..8bf36b0b3c33 100644 --- a/arch/arm/boot/dts/dra72-evm.dts +++ b/arch/arm/boot/dts/dra72-evm.dts @@ -478,6 +478,8 @@ { status = "okay"; + interrupts-extended = <_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, + <_pmx_core 0x3e0>; }; { -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/5] spi: introduce mmap read support for spi flash devices
Hi Brian, On 11/13/2015 09:35 PM, Cyrille Pitchen wrote: [...] > > In September I've sent a series of patches to enhance the support of QSPI > flash > memories. Patch 4 was dedicated to the m25p80 driver and set the > rx_nbits / tx_nbits fields of spi_transfer struct(s) in order to configure the > number of I/O lines independently for the opcode, address and data parts. > The work was done for m25p80_read() but also for _read_reg(), _write_reg() and > _write(). > The patched m25p80 driver was then tested with an at25 memory to check non- > regression. > > This series of patches also added 4 enum spi_protocol fields inside struct > spi_nor so the spi-nor framework can tell the (Q)SPI controller driver what > SPI > protocol should be use for erase, read, write and register read/write > operations, depending on the memory manufacturer and the command opcode. > This was done to better support Micron, Spansion and Macronix QSPI memories. > > I have tested the series with Micron QSPI memories and Atmel QSPI controller > and I guess Marek also tested it on his side with Spansion QSPI memories and > another QSPI controller. > > So if it can help other developers to develop QSPI controller drivers, the > series is still available there: > > for the whole series: > http://lists.infradead.org/pipermail/linux-arm-kernel/2015-September/371170.html > > for patch 4 (depends on patch 2 for enum spi_protocol): > http://lists.infradead.org/pipermail/linux-arm-kernel/2015-September/371173.html > Should I rebase my next version on top of above patches by Cyrille or shall I post on top of 4.4-rc1? -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/5] spi: introduce mmap read support for spi flash devices
Hi Brian, On 11/12/2015 12:54 AM, Brian Norris wrote: > In addition to my other comments: > [...] >> +int (*spi_mtd_mmap_read)(struct spi_device *spi, >> + loff_t from, size_t len, >> + size_t *retlen, u_char *buf, >> + u8 read_opcode, u8 addr_width, >> + u8 dummy_bytes); > > This is seeming to be a longer and longer list of arguments. I know MTD > has a bad habit of long argument lists (which then cause a ton of > unnecessary churn when things need changed in the API), but perhaps we > can limit the damage to the SPI layer. Perhaps this deserves a struct to > encapsulate all the flash read arguments? Like: > > struct spi_flash_read_message { > loff_t from; > size_t len; > size_t *retlen; > void *buf; > u8 read_opcode; > u8 addr_width; > u8 dummy_bits; > // additional fields to describe rx_nbits for opcode/addr/data > }; > > struct spi_master { > ... > int (*spi_flash_read)(struct spi_device *spi, > struct spi_flash_message *msg); > }; Yeah.. I think struct encapsulation helps, this can also be used to pass sg lists for dma in future. I will rework the series with your suggestion to include nbits for opcode/addr/data. Also, will add validation logic (similar to __spi_validate()) to check whether master supports dual/quad mode for opcode/addr/data. I am planning to add this validation code to spi_flash_read_validate(in place of spi_mmap_read_supported()) Thanks! -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 2/5] spi: spi-ti-qspi: add mmap mode read support
ti-qspi controller provides mmap port to read data from SPI flashes. mmap port is enabled in QSPI_SPI_SWITCH_REG. ctrl module register may also need to be accessed for some SoCs. The QSPI_SPI_SETUP_REGx needs to be populated with flash specific information like read opcode, read mode(quad, dual, normal), address width and dummy bytes. Once, controller is in mmap mode, the whole flash memory is available as a memory region at SoC specific address. This region can be accessed using normal memcpy() (or mem-to-mem dma copy). The ti-qspi controller hardware will internally communicate with SPI flash over SPI bus and get the requested data. Implement spi_mtd_mmap_read() callback to support mmap read over SPI flash devices. With this, the read throughput increases from ~100kB/s to ~2.5 MB/s. Signed-off-by: Vignesh R <vigne...@ti.com> --- v3: * optimize enable/disable of mmap mode drivers/spi/spi-ti-qspi.c | 99 +-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 64318fcfacf2..295c11f48440 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -56,6 +56,7 @@ struct ti_qspi { u32 dc; bool ctrl_mod; + bool mmap_enabled; }; #define QSPI_PID (0x0) @@ -65,11 +66,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -109,6 +107,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -366,6 +374,84 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val |= MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + /* dummy readl to ensure bus sync */ + readl(qspi->ctrl_base); + } + qspi->mmap_enabled = true; +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val &= ~MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } + qspi->mmap_enabled = false; +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, + u8 read_opcode, u8 addr_width, + u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 mode = spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD); + u32 memval = read_opcode; + + switch (mode) { + case SPI_RX_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_RX_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static int ti_qspi_spi_mtd_mmap_read(struct spi_device *spi, +loff_t from, size_t len, +size_t *retlen, u_char *buf, +u8 read_opcode, u8 addr_width, +u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + int ret = 0; + + mut
[PATCH v3 1/5] spi: introduce mmap read support for spi flash devices
In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special memory mapped port to accesses SPI flash devices in order to increase read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, spi controller needs to know flash specific information like read command to use, dummy bytes and address width. Once these settings are populated in hardware registers, any read accesses to flash's memory map region(SoC specific) through memcpy (or mem-to mem DMA copy) will be handled by controller hardware. The hardware will automatically generate SPI signals required to read data from flash and present it to CPU/DMA. Introduce spi_mtd_mmap_read() interface to support memory mapped read over SPI flash devices. SPI master drivers can implement this callback to support memory mapped read interfaces. m25p80 flash driver and other flash drivers can call this to request memory mapped read. The interface should only be used MTD flashes and cannot be used with other SPI devices. Signed-off-by: Vignesh R <vigne...@ti.com> --- v3: * Remove use of mmap_lock_mutex, use bus_lock_mutex instead. drivers/spi/spi.c | 34 ++ include/linux/spi/spi.h | 20 2 files changed, 54 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e2415be209d5..0448d29fefc8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1134,6 +1134,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) } } + mutex_lock(>bus_lock_mutex); trace_spi_message_start(master->cur_msg); if (master->prepare_message) { @@ -1143,6 +1144,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) "failed to prepare message: %d\n", ret); master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } master->cur_msg_prepared = true; @@ -1152,6 +1154,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>bus_lock_mutex); return; } @@ -1159,8 +1162,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { dev_err(>dev, "failed to transfer one message from queue\n"); + mutex_unlock(>bus_lock_mutex); return; } + mutex_unlock(>bus_lock_mutex); } /** @@ -2327,6 +2332,35 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) EXPORT_SYMBOL_GPL(spi_async_locked); +int spi_mtd_mmap_read(struct spi_device *spi, loff_t from, size_t len, + size_t *retlen, u_char *buf, u8 read_opcode, + u8 addr_width, u8 dummy_bytes) + +{ + struct spi_master *master = spi->master; + int ret; + + if (master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(>dev, "Failed to power device: %d\n", + ret); + goto err; + } + } + mutex_lock(>bus_lock_mutex); + ret = master->spi_mtd_mmap_read(spi, from, len, retlen, buf, + read_opcode, addr_width, + dummy_bytes); + mutex_unlock(>bus_lock_mutex); + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); + +err: + return ret; +} +EXPORT_SYMBOL_GPL(spi_mtd_mmap_read); + /*-*/ /* Utility methods for SPI master protocol drivers, layered on diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index cce80e6dc7d1..2f2c431b8917 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -361,6 +361,11 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @handle_err: the subsystem calls the driver to handle an error that occurs * in the generic implementation of transfer_one_message(). * @unprepare_message: undo any work done by prepare_message(). + * @spi_mtd_mmap_read: some spi-controller hardwares provide memory. + * Flash drivers (like m25p80) can request memory + * mapped read via this method. This interface + * should only be used by mtd flashes and
[PATCH v3 3/5] mtd: devices: m25p80: add support for mmap read request
Certain spi controllers may support memory mapped interface to read from m25p80 type flash devices. This interface provides better read performance than regular SPI interface. Call spi_mtd_mmap_read() interface, if supported, to make use of memory-mapped interface. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/mtd/devices/m25p80.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index fe9ceb7b5405..7ef0c5009ead 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -131,6 +131,11 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, /* convert the dummy cycles to the number of bytes */ dummy /= 8; + if (spi_mmap_read_supported(spi)) + return spi_mtd_mmap_read(spi, from, len, retlen, buf, +nor->read_opcode, +nor->addr_width, dummy); + spi_message_init(); memset(t, 0, (sizeof t)); -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 0/5] Add memory mapped read support for ti-qspi
Changes since v2: Remove mmap_lock_mutex. Optimize enable/disable of mmap mode. Changes since v1: Introduce API in SPI core that MTD flash driver can call for mmap read instead of directly calling spi-master driver callback. This API makes sure that SPI core msg queue is locked during mmap transfers. v1: https://lkml.org/lkml/2015/9/4/103 Cover letter: This patch series adds support for memory mapped read port of ti-qspi. ti-qspi has a special memory mapped port through which SPI flash memories can be accessed directly via SoC specific memory region. First patch adds a method to pass flash specific information like read opcode, dummy bytes etc and to request mmap read. Second patch implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to use mmap read method before trying normal SPI transfer. Patch 4 and 5 add memory map region DT entries for DRA7xx and AM43xx SoCs. This patch series is based on the discussions here: http://www.spinics.net/lists/linux-spi/msg04796.html Tested on DRA74 EVM and AM437x-SK. Read performance increases from ~100kB/s to ~2.5MB/s. Vignesh R (5): spi: introduce mmap read support for spi flash devices spi: spi-ti-qspi: add mmap mode read support mtd: devices: m25p80: add support for mmap read request ARM: dts: DRA7: add entry for qspi mmap region ARM: dts: AM4372: add entry for qspi mmap region Documentation/devicetree/bindings/spi/ti_qspi.txt | 19 - arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 7 +- drivers/mtd/devices/m25p80.c | 5 ++ drivers/spi/spi-ti-qspi.c | 99 ++- drivers/spi/spi.c | 34 include/linux/spi/spi.h | 20 + 7 files changed, 179 insertions(+), 9 deletions(-) -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 5/5] ARM: dts: AM4372: add entry for qspi mmap region
Add qspi memory mapped region entries for AM43xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> Acked-by: Rob Herring <r...@kernel.org> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- arch/arm/boot/dts/am4372.dtsi | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 334aa3f32cbc..5a1542eda387 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -17,9 +17,10 @@ Recommended properties: Example: +For am4372: qspi: qspi@4b30 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4790 0x100>, <0x3000 0x3ff>; + compatible = "ti,am4372-qspi"; + reg = <0x4790 0x100>, <0x3000 0x400>; reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index d83ff9c9701e..e32d164102d1 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -963,7 +963,9 @@ qspi: qspi@4790 { compatible = "ti,am4372-qspi"; - reg = <0x4790 0x100>; + reg = <0x4790 0x100>, + <0x3000 0x400>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 4/5] ARM: dts: DRA7: add entry for qspi mmap region
Add qspi memory mapped region entries for DRA7xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> Acked-by: Rob Herring <r...@kernel.org> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 14 ++ arch/arm/boot/dts/dra7.dtsi | 7 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 601a360531a5..334aa3f32cbc 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -26,3 +26,17 @@ qspi: qspi@4b30 { spi-max-frequency = <2500>; ti,hwmods = "qspi"; }; + +For dra7xx: +qspi: qspi@4b30 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>, + <0x4a002558 0x4>; + reg-names = "qspi_base", "qspi_mmap", + "qspi_ctrlmod"; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4800>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 8fedddc35999..ad93fe2ccab8 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1108,8 +1108,11 @@ qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b30 0x100>; - reg-names = "qspi_base"; + reg = <0x4b30 0x100>, + <0x5c00 0x400>, + <0x4a002558 0x4>; + reg-names = "qspi_base", "qspi_mmap", + "qspi_ctrlmod"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 5/5] ARM: dts: AM4372: add entry for qspi mmap region
On 11/06/2015 10:44 AM, Felipe Balbi wrote: > > Hi, > > Rob Herring <r...@kernel.org> writes: >> On Tue, Nov 03, 2015 at 03:36:14PM +0530, Vignesh R wrote: >>> Add qspi memory mapped region entries for AM43xx based SoCs. Also, >>> update the binding documents for the controller to document this change. >>> >>> Signed-off-by: Vignesh R <vigne...@ti.com> >> >> Acked-by: Rob Herring <r...@kernel.org> >> >>> --- >>> Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- >>> arch/arm/boot/dts/am4372.dtsi | 4 +++- >>> 2 files changed, 6 insertions(+), 3 deletions(-) >>> >>> diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt >>> b/Documentation/devicetree/bindings/spi/ti_qspi.txt >>> index f05dd631bef1..05488970060b 100644 >>> --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt >>> +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt >>> @@ -17,9 +17,10 @@ Recommended properties: >>> >>> Example: >>> >>> +For am4372: >>> qspi: qspi@4b30 { >>> - compatible = "ti,dra7xxx-qspi"; >>> - reg = <0x4790 0x100>, <0x3000 0x3ff>; >>> + compatible = "ti,am4372-qspi"; >>> + reg = <0x4790 0x100>, <0x3000 0x400>; >>> reg-names = "qspi_base", "qspi_mmap"; >>> #address-cells = <1>; >>> #size-cells = <0>; > > and how does the user for this look like ? Don't you need to give this a > proper 'ranges' binding ? > There are no other users of qspi_mmap region except ti-qspi driver itself: In probe: res_mmap = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); qspi->mmap_base = devm_ioremap_resource(>dev, res_mmap); and for reading from mmap region: memcpy_fromio(buf, qspi->mmap_base + from, len); -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/5] spi: introduce mmap read support for spi flash devices
On 11/04/2015 08:09 PM, Mark Brown wrote: > On Tue, Nov 03, 2015 at 03:36:10PM +0530, Vignesh R wrote: > >> +} >> +mutex_lock(>mmap_lock_mutex); >> +ret = master->spi_mtd_mmap_read(spi, from, len, retlen, buf, >> +read_opcode, addr_width, >> +dummy_bytes); >> +mutex_unlock(>mmap_lock_mutex); >> +if (master->auto_runtime_pm) >> +pm_runtime_put(master->dev.parent); > > It's a bit worrying that this doesn't sync with the message queue except > via the mutex: this means that we might be out of order with respect to > any asynchronous transfers that are happening on the device. I'm not > sure that this is a practical problem, though there is some risk of > unfair scheduling that would have to be under extreme load and it might > make sense to prioritise reads anyway. > Since mmap interface is used only by mtd flash drivers and since almost all mtd flash devices use synchronous transfers (spi_sync()), IMO, there wont be out of order problem wrt mtd flashes. But mmap read might delay transfers queued for non mtd flash devices. It is difficult to wait for all transfers already queued to be pumped out by __spi_pump_messages() and then do the mmap transfer. Do you have any thoughts on how to sync with message queue? -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/5] spi: spi-ti-qspi: add mmap mode read support
On 11/04/2015 08:11 PM, Mark Brown wrote: > On Tue, Nov 03, 2015 at 03:36:11PM +0530, Vignesh R wrote: > >> +ti_qspi_enable_memory_map(spi); >> +ti_qspi_setup_mmap_read(spi, read_opcode, addr_width, >> +dummy_bytes); >> +memcpy_fromio(buf, qspi->mmap_base + from, len); >> +*retlen = len; >> +ti_qspi_disable_memory_map(spi); > > We'll be constantly enabling and disabling memory mapping with this. > I'm not sure that's a meaningful cost given that it doesn't actually > remap anything but rather just switches hardware modes, we can always > optimise it later if it is. > Hmm, I will move the ti_qspi_disable_memory_map() call to ti_qspi_start_transfer_one(), so that mmap mode is disabled only when normal SPI bus transfer is requested. Further, "mmap_enabled" status flag can be used to determine whether mode switch is required or not. This should help to overcome enabling and disabling memory mapping between successive mmap read requests. -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/5] spi: introduce mmap read support for spi flash devices
In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special memory mapped port to accesses SPI flash devices in order to increase read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, spi controller needs to know flash specific information like read command to use, dummy bytes and address width. Once these settings are populated in hardware registers, any read accesses to flash's memory map region(SoC specific) through memcpy (or mem-to mem DMA copy) will be handled by controller hardware. The hardware will automatically generate SPI signals required to read data from flash and present it to CPU/DMA. Introduce spi_mtd_mmap_read() interface to support memory mapped read over SPI flash devices. SPI master drivers can implement this callback to support memory mapped read interfaces. m25p80 flash driver and other flash drivers can call this to request memory mapped read. The interface should only be used MTD flashes and cannot be used with other SPI devices. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi.c | 35 +++ include/linux/spi/spi.h | 23 +++ 2 files changed, 58 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a5f53de813d3..5a5c7a7d47f2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1059,6 +1059,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) } } + mutex_lock(>mmap_lock_mutex); trace_spi_message_start(master->cur_msg); if (master->prepare_message) { @@ -1068,6 +1069,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) "failed to prepare message: %d\n", ret); master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>mmap_lock_mutex); return; } master->cur_msg_prepared = true; @@ -1077,6 +1079,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(>mmap_lock_mutex); return; } @@ -1084,8 +1087,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { dev_err(>dev, "failed to transfer one message from queue\n"); + mutex_unlock(>mmap_lock_mutex); return; } + mutex_unlock(>mmap_lock_mutex); } /** @@ -1732,6 +1737,7 @@ int spi_register_master(struct spi_master *master) spin_lock_init(>queue_lock); spin_lock_init(>bus_lock_spinlock); mutex_init(>bus_lock_mutex); + mutex_init(>mmap_lock_mutex); master->bus_lock_flag = 0; init_completion(>xfer_completion); if (!master->max_dma_len) @@ -2237,6 +2243,35 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) EXPORT_SYMBOL_GPL(spi_async_locked); +int spi_mtd_mmap_read(struct spi_device *spi, loff_t from, size_t len, + size_t *retlen, u_char *buf, u8 read_opcode, + u8 addr_width, u8 dummy_bytes) + +{ + struct spi_master *master = spi->master; + int ret; + + if (master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(>dev, "Failed to power device: %d\n", + ret); + goto err; + } + } + mutex_lock(>mmap_lock_mutex); + ret = master->spi_mtd_mmap_read(spi, from, len, retlen, buf, + read_opcode, addr_width, + dummy_bytes); + mutex_unlock(>mmap_lock_mutex); + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); + +err: + return ret; +} +EXPORT_SYMBOL_GPL(spi_mtd_mmap_read); + /*-*/ /* Utility methods for SPI master protocol drivers, layered on diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 6b00f18f5e6b..0a6d8ad57357 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -297,6 +297,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @flags: other constraints relevant to this driver * @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_mutex: mutex for SPI bus locking + * @mmap_lock_mutex: mutex for l
[PATCH v2 4/5] ARM: dts: DRA7: add entry for qspi mmap region
Add qspi memory mapped region entries for DRA7xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 13 + arch/arm/boot/dts/dra7.dtsi | 6 -- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 601a360531a5..f05dd631bef1 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -26,3 +26,16 @@ qspi: qspi@4b30 { spi-max-frequency = <2500>; ti,hwmods = "qspi"; }; + +For dra7xx: +qspi: qspi@4b30 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b30 0x100>, <0x4a002558 0x4>, + <0x5c00 0x400>; + reg-names = "qspi_base", "qspi_ctrlmod", + "qspi_mmap"; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4800>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index e289c706d27d..13c2f10ec217 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1108,8 +1108,10 @@ qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b30 0x100>; - reg-names = "qspi_base"; + reg = <0x4b30 0x100>, <0x4a002558 0x4>, + <0x5c00 0x400>; + reg-names = "qspi_base", "qspi_ctrlmod", + "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/5] mtd: devices: m25p80: add support for mmap read request
Certain spi controllers may support memory mapped interface to read from m25p80 type flash devices. This interface provides better read performance than regular SPI interface. Call spi_mtd_mmap_read() interface, if supported, to make use of memory-mapped interface. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/mtd/devices/m25p80.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 9cd3631170ef..3978bcb513b9 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -133,6 +133,11 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, /* convert the dummy cycles to the number of bytes */ dummy /= 8; + if (spi_mmap_read_supported(spi)) + return spi_mtd_mmap_read(spi, from, len, retlen, buf, +nor->read_opcode, +nor->addr_width, dummy); + spi_message_init(); memset(t, 0, (sizeof t)); -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/5] spi: spi-ti-qspi: add mmap mode read support
ti-qspi controller provides mmap port to read data from SPI flashes. mmap port is enabled in QSPI_SPI_SWITCH_REG. ctrl module register may also need to be accessed for some SoCs. The QSPI_SPI_SETUP_REGx needs to be populated with flash specific information like read opcode, read mode(quad, dual, normal), address width and dummy bytes. Once, controller is in mmap mode, the whole flash memory is available as a memory region at SoC specific address. This region can be accessed using normal memcpy() (or mem-to-mem dma copy). The ti-qspi controller hardware will internally communicate with SPI flash over SPI bus and get the requested data. Implement spi_mtd_mmap_read() callback to support mmap read over SPI flash devices. With this, the read throughput increases from ~100kB/s to ~2.5 MB/s. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi-ti-qspi.c | 92 --- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 69c1a95b0615..2f58fb7eb410 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -65,11 +65,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -109,6 +106,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -366,6 +373,82 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val |= MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + /* dummy readl to ensure bus sync */ + readl(qspi->ctrl_base); + } +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val &= ~MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, + u8 read_opcode, u8 addr_width, + u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 mode = spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD); + u32 memval = read_opcode; + + switch (mode) { + case SPI_RX_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_RX_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static int ti_qspi_spi_mtd_mmap_read(struct spi_device *spi, +loff_t from, size_t len, +size_t *retlen, u_char *buf, +u8 read_opcode, u8 addr_width, +u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + int ret = 0; + + mutex_lock(>list_lock); + + ti_qspi_enable_memory_map(spi); + ti_qspi_setup_mmap_read(spi, read_opcode, addr_width, + dummy_bytes); + memcpy_fromio(buf, qspi->mmap_base + from, len); + *retlen = len; + ti_qsp
[PATCH v2 5/5] ARM: dts: AM4372: add entry for qspi mmap region
Add qspi memory mapped region entries for AM43xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- arch/arm/boot/dts/am4372.dtsi | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index f05dd631bef1..05488970060b 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -17,9 +17,10 @@ Recommended properties: Example: +For am4372: qspi: qspi@4b30 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4790 0x100>, <0x3000 0x3ff>; + compatible = "ti,am4372-qspi"; + reg = <0x4790 0x100>, <0x3000 0x400>; reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 0447c04a40cc..1b2c545f3f2c 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -962,7 +962,9 @@ qspi: qspi@4790 { compatible = "ti,am4372-qspi"; - reg = <0x4790 0x100>; + reg = <0x4790 0x100>, + <0x3000 0x400>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/5] Add memory mapped read support for ti-qspi
Changes since v1: Introduce API in SPI core that MTD flash driver can call for mmap read instead of directly calling spi-master driver callback. This API makes sure that SPI core msg queue is locked during mmap transfers. v1: https://lkml.org/lkml/2015/9/4/103 Cover letter: This patch series adds support for memory mapped read port of ti-qspi. ti-qspi has a special memory mapped port through which SPI flash memories can be accessed directly via SoC specific memory region. First patch adds a method to pass flash specific information like read opcode, dummy bytes etc and to request mmap read. Second patch implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to use mmap read method before trying normal SPI transfer. Patch 4 and 5 add memory map region DT entries for DRA7xx and AM43xx SoCs. This patch series is based on the discussions here: http://www.spinics.net/lists/linux-spi/msg04796.html Tested on DRA74 EVM and AM437x-SK. Read performance increases from ~100kB/s to ~2.5MB/s. Vignesh R (5): spi: introduce mmap read support for spi flash devices spi: spi-ti-qspi: add mmap mode read support mtd: devices: m25p80: add support for mmap read request ARM: dts: DRA7: add entry for qspi mmap region ARM: dts: AM4372: add entry for qspi mmap region Documentation/devicetree/bindings/spi/ti_qspi.txt | 18 - arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 6 +- drivers/mtd/devices/m25p80.c | 5 ++ drivers/spi/spi-ti-qspi.c | 92 ++- drivers/spi/spi.c | 35 + include/linux/spi/spi.h | 23 ++ 7 files changed, 174 insertions(+), 9 deletions(-) -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/5] spi: introduce mmap read support for spi flash devices
Hi, On 11/03/2015 04:49 PM, Michal Suchanek wrote: > On 3 November 2015 at 11:06, Vignesh R <vigne...@ti.com> wrote: >> In addition to providing direct access to SPI bus, some spi controller >> hardwares (like ti-qspi) provide special memory mapped port >> to accesses SPI flash devices in order to increase read performance. >> This means the controller can automatically send the SPI signals >> required to read data from the SPI flash device. >> For this, spi controller needs to know flash specific information like >> read command to use, dummy bytes and address width. Once these settings >> are populated in hardware registers, any read accesses to flash's memory >> map region(SoC specific) through memcpy (or mem-to mem DMA copy) will be >> handled by controller hardware. The hardware will automatically generate >> SPI signals required to read data from flash and present it to CPU/DMA. >> >> Introduce spi_mtd_mmap_read() interface to support memory mapped read >> over SPI flash devices. SPI master drivers can implement this callback to >> support memory mapped read interfaces. m25p80 flash driver and other >> flash drivers can call this to request memory mapped read. The interface >> should only be used MTD flashes and cannot be used with other SPI devices. >> >> Signed-off-by: Vignesh R <vigne...@ti.com> >> --- >> drivers/spi/spi.c | 35 +++ >> include/linux/spi/spi.h | 23 +++ >> 2 files changed, 58 insertions(+) >> >> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c >> index a5f53de813d3..5a5c7a7d47f2 100644 >> --- a/drivers/spi/spi.c >> +++ b/drivers/spi/spi.c >> @@ -1059,6 +1059,7 @@ static void __spi_pump_messages(struct spi_master >> *master, bool in_kthread) >> } >> } >> >> + mutex_lock(>mmap_lock_mutex); >> trace_spi_message_start(master->cur_msg); >> >> if (master->prepare_message) { >> @@ -1068,6 +1069,7 @@ static void __spi_pump_messages(struct spi_master >> *master, bool in_kthread) >> "failed to prepare message: %d\n", ret); >> master->cur_msg->status = ret; >> spi_finalize_current_message(master); >> + mutex_unlock(>mmap_lock_mutex); >> return; >> } >> master->cur_msg_prepared = true; >> @@ -1077,6 +1079,7 @@ static void __spi_pump_messages(struct spi_master >> *master, bool in_kthread) >> if (ret) { >> master->cur_msg->status = ret; >> spi_finalize_current_message(master); >> + mutex_unlock(>mmap_lock_mutex); >> return; >> } >> >> @@ -1084,8 +1087,10 @@ static void __spi_pump_messages(struct spi_master >> *master, bool in_kthread) >> if (ret) { >> dev_err(>dev, >> "failed to transfer one message from queue\n"); >> + mutex_unlock(>mmap_lock_mutex); >> return; >> } >> + mutex_unlock(>mmap_lock_mutex); >> } >> >> /** >> @@ -1732,6 +1737,7 @@ int spi_register_master(struct spi_master *master) >> spin_lock_init(>queue_lock); >> spin_lock_init(>bus_lock_spinlock); >> mutex_init(>bus_lock_mutex); >> + mutex_init(>mmap_lock_mutex); >> master->bus_lock_flag = 0; >> init_completion(>xfer_completion); >> if (!master->max_dma_len) >> @@ -2237,6 +2243,35 @@ int spi_async_locked(struct spi_device *spi, struct >> spi_message *message) >> EXPORT_SYMBOL_GPL(spi_async_locked); >> >> >> +int spi_mtd_mmap_read(struct spi_device *spi, loff_t from, size_t len, >> + size_t *retlen, u_char *buf, u8 read_opcode, >> + u8 addr_width, u8 dummy_bytes) >> + >> +{ >> + struct spi_master *master = spi->master; >> + int ret; >> + >> + if (master->auto_runtime_pm) { >> + ret = pm_runtime_get_sync(master->dev.parent); >> + if (ret < 0) { >> + dev_err(>dev, "Failed to power device: %d\n", >> + ret); >> + goto err; >> + } >> + } >> + mutex_lock(>mmap_lock_mutex); &
Re: [PATCH] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_ts
On 10/14/2015 02:16 PM, Roger Quadros wrote: > > On 14/10/15 08:52, Vignesh R wrote: >> On am437x-gp-evm, pixcir_i2c_ts can wakeup the system from lower power >> state via pinctrl and IO daisy chain using generic wakeirq framework. >> With commit 3fffd1283927 ("i2c: allow specifying separate wakeup >> interrupt in device tree") i2c core allows optional wakeirq to be >> specified via device tree. Add wakeup irq entry to enable pixcir_i2c_ts >> to wake the system from low power state. >> >> Signed-off-by: Vignesh R <vigne...@ti.com> >> --- >> arch/arm/boot/dts/am437x-gp-evm.dts | 5 + >> 1 file changed, 5 insertions(+) >> >> diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts >> b/arch/arm/boot/dts/am437x-gp-evm.dts >> index 22038f21f228..69e93af7df0d 100644 >> --- a/arch/arm/boot/dts/am437x-gp-evm.dts >> +++ b/arch/arm/boot/dts/am437x-gp-evm.dts >> @@ -581,8 +581,13 @@ >> >> attb-gpio = < 22 GPIO_ACTIVE_HIGH>; >> >> +interrupts-extended = < 22 GPIO_ACTIVE_HIGH>, >> + <_pinmux 0x264>; > > How does this work? > > interrupts-extended property must have > 1) interrupt parent > 2) interrupt number > 3) interrupt flags > > Your change doesn't seem to comply with those requirements. AFAIU, interrupts-extended has two parts: interrupt parent phandle and interrupt specifier. The number of cells in interrupt specifier is determined by interrupt-cells property of interrupt parent node. In above case, gpio3 has interrupt-cells = 2 hence interrupt specifier has interrupt number and interrupt flag field. But in case am43xx_pinmux node, interrupt-cells is 1 hence has no interrupt flag field. -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_ts
On 10/14/2015 04:34 PM, Roger Quadros wrote: > Vignesh, > > On 14/10/15 12:12, Vignesh R wrote: >> >> >> On 10/14/2015 02:16 PM, Roger Quadros wrote: >> >>> >>> On 14/10/15 08:52, Vignesh R wrote: >>>> On am437x-gp-evm, pixcir_i2c_ts can wakeup the system from lower power >>>> state via pinctrl and IO daisy chain using generic wakeirq framework. >>>> With commit 3fffd1283927 ("i2c: allow specifying separate wakeup >>>> interrupt in device tree") i2c core allows optional wakeirq to be >>>> specified via device tree. Add wakeup irq entry to enable pixcir_i2c_ts >>>> to wake the system from low power state. >>>> >>>> Signed-off-by: Vignesh R <vigne...@ti.com> >>>> --- >>>> arch/arm/boot/dts/am437x-gp-evm.dts | 5 + >>>> 1 file changed, 5 insertions(+) >>>> >>>> diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts >>>> b/arch/arm/boot/dts/am437x-gp-evm.dts >>>> index 22038f21f228..69e93af7df0d 100644 >>>> --- a/arch/arm/boot/dts/am437x-gp-evm.dts >>>> +++ b/arch/arm/boot/dts/am437x-gp-evm.dts >>>> @@ -581,8 +581,13 @@ >>>> >>>>attb-gpio = < 22 GPIO_ACTIVE_HIGH>; >>>> >>>> + interrupts-extended = < 22 GPIO_ACTIVE_HIGH>, >>>> +<_pinmux 0x264>; >>> >>> How does this work? >>> >>> interrupts-extended property must have >>> 1) interrupt parent >>> 2) interrupt number >>> 3) interrupt flags >>> >>> Your change doesn't seem to comply with those requirements. >> >> AFAIU, interrupts-extended has two parts: interrupt parent phandle and >> interrupt specifier. >> The number of cells in interrupt specifier is determined by >> interrupt-cells property of interrupt parent node. > > Got it. > >> In above case, gpio3 has interrupt-cells = 2 hence interrupt specifier >> has interrupt number and interrupt flag field. > > But is GPIO_ACTIVE_HIGH an interrupt flag? Oops.. I will change it to IRQ_TYPE_NONE as represented in interrupts property. > >> But in case am43xx_pinmux node, interrupt-cells is 1 hence has no >> interrupt flag field. >> > Understood, thanks. Might be worth adding a comment as to what 0x264 means > though. > Will add a one line comment indicating its the offset of gpio3_22 padconf register from am43xx_pinmux base. > cheers, > -roger > -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_ts
On am437x-gp-evm, pixcir_i2c_ts can wakeup the system from low power state via pinctrl and IO daisy chain using generic wakeirq framework. With commit 3fffd1283927 ("i2c: allow specifying separate wakeup interrupt in device tree") i2c core allows optional wakeirq to be specified via device tree. Add wakeup irq entry to enable pixcir_i2c_ts to wake the system from low power state. Signed-off-by: Vignesh R <vigne...@ti.com> --- Since v1: - correct interrupt flag. - add comment wrt wakeup interrupt. arch/arm/boot/dts/am437x-gp-evm.dts | 9 + 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 22038f21f228..9c324b5f09ac 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -581,8 +581,17 @@ attb-gpio = < 22 GPIO_ACTIVE_HIGH>; + /* +* 0x264 represents the offset of padconf register of +* gpio3_22 from am43xx_pinmux base. +*/ + interrupts-extended = < 22 IRQ_TYPE_NONE>, + <_pinmux 0x264>; + interrupt-names = "tsc", "wakeup"; + touchscreen-size-x = <1024>; touchscreen-size-y = <600>; + wakeup-source; }; ov2659@30 { -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_ts
On am437x-gp-evm, pixcir_i2c_ts can wakeup the system from lower power state via pinctrl and IO daisy chain using generic wakeirq framework. With commit 3fffd1283927 ("i2c: allow specifying separate wakeup interrupt in device tree") i2c core allows optional wakeirq to be specified via device tree. Add wakeup irq entry to enable pixcir_i2c_ts to wake the system from low power state. Signed-off-by: Vignesh R <vigne...@ti.com> --- arch/arm/boot/dts/am437x-gp-evm.dts | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 22038f21f228..69e93af7df0d 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -581,8 +581,13 @@ attb-gpio = < 22 GPIO_ACTIVE_HIGH>; + interrupts-extended = < 22 GPIO_ACTIVE_HIGH>, + <_pinmux 0x264>; + interrupt-names = "tsc", "wakeup"; + touchscreen-size-x = <1024>; touchscreen-size-y = <600>; + wakeup-source; }; ov2659@30 { -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] spi: spi-ti-qspi: switch to polling mode for better r/w performance
Currently word completion interrupt is fired for transfer of every word(8bit to 128bit in size). This adds a lot of overhead, and decreases r/w throughput. It hardly takes 3us(@48MHz) for 128bit r/w to complete, hence its better to poll on word complete bit to be set in QSPI_SPI_STATUS_REG instead of using interrupts. This increases the throughput by 30% in both read and write case. So, switch to polling mode instead of interrupts to determine completion of word transfer. Signed-off-by: Vignesh R <vigne...@ti.com> --- Tested on DRA74 Rev G EVM. drivers/spi/spi-ti-qspi.c | 74 +-- 1 file changed, 20 insertions(+), 54 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 81b84858cfee..69c1a95b0615 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -39,8 +39,6 @@ struct ti_qspi_regs { }; struct ti_qspi { - struct completion transfer_complete; - /* list synchronization */ struct mutexlist_lock; @@ -62,10 +60,6 @@ struct ti_qspi { #define QSPI_PID (0x0) #define QSPI_SYSCONFIG (0x10) -#define QSPI_INTR_STATUS_RAW_SET (0x20) -#define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24) -#define QSPI_INTR_ENABLE_SET_REG (0x28) -#define QSPI_INTR_ENABLE_CLEAR_REG (0x2c) #define QSPI_SPI_CLOCK_CNTRL_REG (0x40) #define QSPI_SPI_DC_REG(0x44) #define QSPI_SPI_CMD_REG (0x48) @@ -97,7 +91,6 @@ struct ti_qspi { #define QSPI_RD_DUAL (3 << 16) #define QSPI_RD_QUAD (7 << 16) #define QSPI_INVAL (4 << 16) -#define QSPI_WC_CMD_INT_EN (1 << 14) #define QSPI_FLEN(n) ((n - 1) << 0) #define QSPI_WLEN_MAX_BITS 128 #define QSPI_WLEN_MAX_BYTES16 @@ -106,10 +99,6 @@ struct ti_qspi { #define BUSY 0x01 #define WC 0x02 -/* INTERRUPT REGISTER */ -#define QSPI_WC_INT_EN (1 << 1) -#define QSPI_WC_INT_DISABLE(1 << 1) - /* Device Control */ #define QSPI_DD(m, n) (m << (3 + n * 8)) #define QSPI_CKPHA(n) (1 << (2 + n * 8)) @@ -217,6 +206,24 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi) return stat & BUSY; } +static inline int ti_qspi_poll_wc(struct ti_qspi *qspi) +{ + u32 stat; + unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; + + do { + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + if (stat & WC) + return 0; + cpu_relax(); + } while (time_after(timeout, jiffies)); + + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + if (stat & WC) + return 0; + return -ETIMEDOUT; +} + static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) { int wlen, count, xfer_len; @@ -275,8 +282,7 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) } ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - if (!wait_for_completion_timeout(>transfer_complete, -QSPI_COMPLETION_TIMEOUT)) { + if (ti_qspi_poll_wc(qspi)) { dev_err(qspi->dev, "write timed out\n"); return -ETIMEDOUT; } @@ -315,8 +321,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) return -EBUSY; ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); - if (!wait_for_completion_timeout(>transfer_complete, -QSPI_COMPLETION_TIMEOUT)) { + if (ti_qspi_poll_wc(qspi)) { dev_err(qspi->dev, "read timed out\n"); return -ETIMEDOUT; } @@ -388,9 +393,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, qspi->cmd = 0; qspi->cmd |= QSPI_EN_CS(spi->chip_select); qspi->cmd |= QSPI_FLEN(frame_length); - qspi->cmd |= QSPI_WC_CMD_INT_EN; - ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); mutex_lock(>list_lock); @@ -417,31 +420,6 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, return status; } -static irqreturn_t ti_qspi_isr(int irq, void *dev_id) -{ - struct ti_qspi *qspi = dev_id; - u16 int_stat; - u32 stat; - - irqreturn_t ret = IRQ_HANDLED; - - int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); - stat = ti_qspi_read(qspi, QSPI_SPI_STA
[PATCH] spi: ti-qspi: Fix data corruption seen on r/w stress test
Writing invalid command to QSPI_SPI_CMD_REG will terminate current transfer and de-assert the chip select. This has to be done before calling spi_finalize_current_message(). Because spi_finalize_current_message() will mark the end of current message transfer and schedule the next transfer. If the chipselect is not de-asserted before calling spi_finalize_current_message() then the next transfer will overlap with the previous transfer leading to data corruption. __spi_pump_message() can be called either from kthread worker context or directly from the calling process's context. It is possible that these two calls can race against each other. But race is serialized by checking whether master->cur_msg == NULL (pointer to msg being handled by transfer_one() at present). The master->cur_msg is set to NULL when spi_finalize_current_message() is called on that message, which means calling spi_finalize_current_message() allows __spi_sync() to pump next message in calling process context. Now if spi-ti-qspi calls spi_finalize_current_message() before we terminate transfer at hardware side, if __spi_pump_message() is called from process context then the successive transactions can overlap. Fix this by moving writing invalid command to QSPI_SPI_CMD_REG to before calling spi_finalize_current_message() call. Cc: sta...@vger.kernel.org # v3.12+ Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi-ti-qspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index aa6d284131e0..81b84858cfee 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -410,11 +410,10 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, mutex_unlock(>list_lock); + ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); m->status = status; spi_finalize_current_message(master); - ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); - return status; } -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/5] spi: introduce mmap read support for spi flash devices
On 09/16/2015 04:26 PM, Mark Brown wrote: > On Wed, Sep 16, 2015 at 03:38:09PM +0530, Vignesh R wrote: > >> But, I didn't get how to integrate with existing message queue. Memory >> mapped read by-passes message queue of SPI core. Could you please >> explain a bit more on integrating with message queue? Did you mean >> locking the existing message queue when memory mapped read is being >> requested? > > Yes, and also making sure that we don't everything gets processed in > order so memory mapped requests come after any commands needed to set > them up and don't starve other work. > Ok, thanks for the clarification! -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/5] mtd: devices: m25p80: add support for mmap read request
On 09/14/2015 11:57 PM, Mark Brown wrote: > On Fri, Sep 04, 2015 at 02:00:00PM +0530, Vignesh R wrote: > >> +if (spi->master->spi_mtd_mmap_read) { >> +return spi->master->spi_mtd_mmap_read(spi, from, len, >> + retlen, buf, >> + nor->read_opcode, >> + nor->addr_width, >> + dummy); >> +} > > We should be calling some API provided by the SPI core here, not peering > directly into the ops struture. > Ok.. -- Regards Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/5] spi: introduce mmap read support for spi flash devices
On 09/15/2015 12:07 AM, Mark Brown wrote: > On Fri, Sep 04, 2015 at 01:59:58PM +0530, Vignesh R wrote: >> In addition to providing direct access to SPI bus, some spi controller >> hardwares (like ti-qspi) provide special memory mapped port >> to accesses SPI flash devices in order to increase read performance. >> This means the controller can automatically send the SPI signals >> required to read data from the SPI flash device. > > Sorry, also meant to say here: as I kind of indicated in response to the > flash patch I'd expect to see the SPI core know something about this and > export an API for this which is integrated with things like the existing > message queue. > Adding an API to SPI core makes sense to me. This can take care of spi bus locking and runtime pm. But, I didn't get how to integrate with existing message queue. Memory mapped read by-passes message queue of SPI core. Could you please explain a bit more on integrating with message queue? Did you mean locking the existing message queue when memory mapped read is being requested? Thanks, Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/5] spi: introduce mmap read support for spi flash devices
On 09/15/2015 12:05 AM, Mark Brown wrote: > On Fri, Sep 04, 2015 at 04:55:33PM +0530, Jagan Teki wrote: >> On 4 September 2015 at 13:59, Vignesh R <vigne...@ti.com> wrote: > >>> + * @spi_mtd_mmap_read: some spi-controller hardwares provide memory >>> + * mapped interface to communicate with mtd flashes. >>> + * For this, spi controller needs to know flash >>> + * memory settings like read command to use, dummy >>> + * bytes and address width. Once these settings are >>> + * populated in hardware registers, any read >>> + * accesses to flash's memory map region(as defined >>> + * by SoC) through memcpy or mem-to-mem DMA copy >>> + * will be handled by controller hardware. The >>> + * hardware will automatically generate spi signals >>> + * required to read data from flash and present it >>> + * to CPU or DMA. SPI master drivers can use this >>> + * callback to implement memory mapped read >>> + * interface. Flash driver (like m25p80) requests >>> + * memory mapped read via this method. The interface >>> + * should only be used mtd flashes and cannot be >>> + * used with other spi devices. > > This comment is *way* too verbose - probably you just need up to the > "Once" here. > Ok, I will move the extra text to commit log. -- Thanks, Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/5] spi: spi-ti-qspi: add mmap mode read support
On 09/14/2015 11:56 PM, Mark Brown wrote: > On Fri, Sep 04, 2015 at 01:59:59PM +0530, Vignesh R wrote: > >> +static int ti_qspi_spi_mtd_mmap_read(struct spi_device *spi, >> + loff_t from, size_t len, >> + size_t *retlen, u_char *buf, >> + u8 read_opcode, u8 addr_width, >> + u8 dummy_bytes) >> +{ >> +struct ti_qspi *qspi = spi_master_get_devdata(spi->master); >> +int ret = 0; >> + >> +spi_bus_lock(qspi->master); > > I suspect I'm going to see the answer to this in another patch but the > fact that we're having to take this lock in a driver when it's an op the > core should be calling. > Agree.. >> +ret = pm_runtime_get_sync(qspi->dev); >> +if (ret < 0) { >> +dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); >> +return ret; >> +} > > This would be better outside the lock, there's no need to have the lock > before we power on and this fixes the fact that you don't release the > lock here. Will take care of this in SPI core API > >> +memcpy(buf, (__force void *)(qspi->mmap_base + from), len); > > The fact that you're having to cast here should be a warning that > there's someting wrong here. I think you're looking for > memcpy_fromio(). Ok, will change to memcpy_fromio() > >> @@ -479,6 +576,7 @@ static int ti_qspi_probe(struct platform_device *pdev) >> master->setup = ti_qspi_setup; >> master->auto_runtime_pm = true; >> master->transfer_one_message = ti_qspi_start_transfer_one; >> +master->spi_mtd_mmap_read = ti_qspi_spi_mtd_mmap_read; >> master->dev.of_node = pdev->dev.of_node; >> master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | >> SPI_BPW_MASK(8); > > Don't we need to map a resource somewhere? > The current driver code already does the resource mapping: res_mmap = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); -- Thanks, Vignesh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/5] ARM: dts: AM4372: add entry for qspi mmap region
Add qspi memory mapped region entries for AM43xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 5 +++-- arch/arm/boot/dts/am4372.dtsi | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index f05dd631bef1..05488970060b 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -17,9 +17,10 @@ Recommended properties: Example: +For am4372: qspi: qspi@4b30 { - compatible = "ti,dra7xxx-qspi"; - reg = <0x4790 0x100>, <0x3000 0x3ff>; + compatible = "ti,am4372-qspi"; + reg = <0x4790 0x100>, <0x3000 0x400>; reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index ade28c790f4b..52cf4846b8e1 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -902,7 +902,9 @@ qspi: qspi@4790 { compatible = "ti,am4372-qspi"; - reg = <0x4790 0x100>; + reg = <0x4790 0x100>, + <0x3000 0x400>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/5] mtd: devices: m25p80: add support for mmap read request
Certain spi controllers may support memory mapped interface to read from m25p80 type flash devices. This interface provides better read performance than regular SPI interface. Call spi_mtd_mmap_read() function, if available, to make use of memory-mapped interface. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/mtd/devices/m25p80.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b96c..b8b391aab331 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -133,6 +133,14 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, /* convert the dummy cycles to the number of bytes */ dummy /= 8; + if (spi->master->spi_mtd_mmap_read) { + return spi->master->spi_mtd_mmap_read(spi, from, len, + retlen, buf, + nor->read_opcode, + nor->addr_width, + dummy); + } + spi_message_init(); memset(t, 0, (sizeof t)); -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/5] ARM: dts: DRA7: add entry for qspi mmap region
Add qspi memory mapped region entries for DRA7xx based SoCs. Also, update the binding documents for the controller to document this change. Signed-off-by: Vignesh R <vigne...@ti.com> --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 13 + arch/arm/boot/dts/dra7.dtsi | 6 -- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 601a360531a5..f05dd631bef1 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -26,3 +26,16 @@ qspi: qspi@4b30 { spi-max-frequency = <2500>; ti,hwmods = "qspi"; }; + +For dra7xx: +qspi: qspi@4b30 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b30 0x100>, <0x4a002558 0x4>, + <0x5c00 0x400>; + reg-names = "qspi_base", "qspi_ctrlmod", + "qspi_mmap"; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4800>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 1e29ccf77ea2..f6798d6ecd60 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1103,8 +1103,10 @@ qspi: qspi@4b30 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b30 0x100>; - reg-names = "qspi_base"; + reg = <0x4b30 0x100>, <0x4a002558 0x4>, + <0x5c00 0x400>; + reg-names = "qspi_base", "qspi_ctrlmod", + "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "qspi"; -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/5] spi: introduce mmap read support for spi flash devices
In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special memory mapped port to accesses SPI flash devices in order to increase read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, spi controller needs to know flash specific information like read command to use, dummy bytes and address width. Once these settings are populated in hardware registers, any read accesses to flash's memory map region(SoC specific) through memcpy or mem-to-mem DMA copy will be handled by controller hardware. The hardware will automatically generate spi signals required to read data from flash and present it to CPU or DMA engine. Introduce spi_mtd_mmap_read() method to support memory mapped read over SPI flash devices. SPI master drivers can implement this method to support memory mapped read interfaces. m25p80 flash driver and other flash drivers can call this to request memory mapped read. The interface should only be used mtd flashes and cannot be used with other spi devices. Signed-off-by: Vignesh R <vigne...@ti.com> --- include/linux/spi/spi.h | 21 + 1 file changed, 21 insertions(+) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d673072346f2..b74a3f169fc2 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -293,6 +293,23 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @handle_err: the subsystem calls the driver to handle an error that occurs * in the generic implementation of transfer_one_message(). * @unprepare_message: undo any work done by prepare_message(). + * @spi_mtd_mmap_read: some spi-controller hardwares provide memory + * mapped interface to communicate with mtd flashes. + * For this, spi controller needs to know flash + * memory settings like read command to use, dummy + * bytes and address width. Once these settings are + * populated in hardware registers, any read + * accesses to flash's memory map region(as defined + * by SoC) through memcpy or mem-to-mem DMA copy + * will be handled by controller hardware. The + * hardware will automatically generate spi signals + * required to read data from flash and present it + * to CPU or DMA. SPI master drivers can use this + * callback to implement memory mapped read + * interface. Flash driver (like m25p80) requests + * memory mapped read via this method. The interface + * should only be used mtd flashes and cannot be + * used with other spi devices. * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that * are not GPIOs (driven by the SPI controller itself). @@ -438,6 +455,10 @@ struct spi_master { struct spi_message *message); int (*unprepare_message)(struct spi_master *master, struct spi_message *message); + int (*spi_mtd_mmap_read)(struct spi_device *spi, +loff_t from, size_t len, size_t *retlen, +u_char *buf, u8 read_opcode, +u8 addr_width, u8 dummy_bytes); /* * These hooks are for drivers that use a generic implementation -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/5] spi: spi-ti-qspi: add mmap mode read support
ti-qspi controller provides mmap port to read data from SPI flashes. mmap port is enabled in QSPI_SPI_SWITCH_REG (ctrl module bits may also need to be updated for some SoCs). The QSPI_SPI_SETUP_REGx needs to be populated with flash specific information like read opcode, read mode(quad, dual, normal), address width and dummy bytes. Once, controller is in mmap mode, the whole flash memory is available as a memory region at SoC specific address. This region can be accessed using normal memcpy() or mem-to-mem dma copy. The ti-qspi controller hardware will internally communicate with SPI flash over SPI bus and get the requested data. Implement spi_mtd_mmap_read() method to support mmap read over SPI flash devices. With this, the read throughput increases from ~100kB/s to ~2.5 MB/s. Signed-off-by: Vignesh R <vigne...@ti.com> --- drivers/spi/spi-ti-qspi.c | 106 -- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index aa6d284131e0..a07610b84bc9 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -71,11 +71,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n)) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -120,6 +117,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) << 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 << 12) +#define QSPI_SETUP_RD_DUAL (0x1 << 12) +#define QSPI_SETUP_RD_QUAD (0x3 << 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -361,6 +368,96 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val |= MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi->ctrl_mod) { + val = readl(qspi->ctrl_base); + val &= ~MEM_CS_EN(spi->chip_select); + writel(val, qspi->ctrl_base); + } +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, + u8 read_opcode, u8 addr_width, + u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + u32 mode = spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD); + u32 memval = read_opcode; + + switch (mode) { + case SPI_RX_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_RX_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT | + dummy_bytes << QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi->chip_select)); +} + +static int ti_qspi_spi_mtd_mmap_read(struct spi_device *spi, +loff_t from, size_t len, +size_t *retlen, u_char *buf, +u8 read_opcode, u8 addr_width, +u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + int ret = 0; + + spi_bus_lock(qspi->master); + mutex_lock(>list_lock); + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) { + dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); + return ret; + } + + /* disable WC interrupt during memcpy */ + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_EN
[PATCH 0/5] Add memory mapped read support for ti-qspi
Hi, This patch series adds support for memory mapped read port of ti-qspi. ti-qspi has a special memory mapped port through which SPI flash memories can be accessed directly via SoC specific memory region. First patch adds a method to pass flash specific information like read opcode, dummy bytes etc and to request mmap read. Second patch implements mmap read method in ti-qspi driver. Patch 3 adapts m25p80 to use mmap read method before trying normal SPI transfer. Patch 4 and 5 add memory map region DT entries for DRA7xx and AM43xx SoCs. This patch series is based on the discussions here: http://www.spinics.net/lists/linux-spi/msg04796.html Tested on DRA74 EVM and AM437x-SK. Read performance increases from ~100kB/s to ~2.5MB/s. Vignesh R (5): spi: introduce mmap read support for spi flash devices spi: spi-ti-qspi: add mmap mode read support mtd: devices: m25p80: add support for mmap read request ARM: dts: DRA7: add entry for qspi mmap region ARM: dts: AM4372: add entry for qspi mmap region Documentation/devicetree/bindings/spi/ti_qspi.txt | 18 +++- arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 6 +- drivers/mtd/devices/m25p80.c | 8 ++ drivers/spi/spi-ti-qspi.c | 106 +- include/linux/spi/spi.h | 21 + 6 files changed, 154 insertions(+), 9 deletions(-) -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] spi: ti-qspi: use 128 bit transfer mode for writing to flash
On 08/20/2015 11:25 PM, Mark Brown wrote: On Thu, Aug 20, 2015 at 04:00:59PM +0530, Vignesh R wrote: -writeb(*txbuf, qspi-base + QSPI_SPI_DATA_REG); +if (count = QSPI_WLEN_MAX_BYTES) { +u32 *txp = (u32 *)txbuf; + +data = cpu_to_be32(*txp++); +writel(data, qspi-base + + QSPI_SPI_DATA_REG_3); +data = cpu_to_be32(*txp++); +writel(data, qspi-base + + QSPI_SPI_DATA_REG_2); +data = cpu_to_be32(*txp++); +writel(data, qspi-base + + QSPI_SPI_DATA_REG_1); +data = cpu_to_be32(*txp++); +writel(data, qspi-base + + QSPI_SPI_DATA_REG); +xfer_len = QSPI_WLEN_MAX_BYTES; +cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); +} else { +writeb(*txbuf, qspi-base + QSPI_SPI_DATA_REG); +cmd = qspi-cmd | QSPI_WR_SNGL; +xfer_len = wlen; +cmd |= QSPI_WLEN(wlen); +} It's a bit sad that this isn't able to do a Duff's device type thing and only kicks in for the full 128 bit FIFO size, it looks like it could do any number of words. Yes, any number of bytes can be transfered (max 16 bytes). I will try to work on your suggestion. Thanks! -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] spi: ti-qspi: use 128 bit transfer mode for writing to flash
TI QSPI has four 32 bit data regsiters which can be used to transfer 16 bytes of data at once. The register group QSPI_SPI_DATA_REG_3, QSPI_SPI_DATA_REG_2, QSPI_SPI_DATA_REG_1 and QSPI_SPI_DATA_REG is treated as a single 128-bit word for shifting data in and out. The bit at QSPI_SPI_DATA_REG_3[31] position is the first bit to be shifted out in case of 128 bit transfer mode. Therefore the first byte to be written to flash should be at QSPI_SPI_DATA_REG_3[31-25] position. Instead of writing 1 byte at a time when interacting with spi-nor flash, make use of all the four registers so that 16 bytes can be transferred in one go. This reduces number of register writes and Word Complete interrupts for a given transfer message size, thereby increasing the write performance. Without this patch the raw flash write speed is ~100KB/s, with this patch the write speed increases to ~400 kB/s on DRA74 EVM. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/spi/spi-ti-qspi.c | 34 ++ 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 45844a227c5e..f4cea6834fad 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -96,6 +96,8 @@ struct ti_qspi { #define QSPI_INVAL (4 16) #define QSPI_WC_CMD_INT_EN (1 14) #define QSPI_FLEN(n) ((n - 1) 0) +#define QSPI_WLEN_MAX_BITS 128 +#define QSPI_WLEN_MAX_BYTES16 /* STATUS REGISTER */ #define BUSY 0x01 @@ -224,14 +226,16 @@ static inline u32 qspi_is_busy(struct ti_qspi *qspi) static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) { - int wlen, count; + int wlen, count, xfer_len; unsigned int cmd; const u8 *txbuf; + u32 data; txbuf = t-tx_buf; cmd = qspi-cmd | QSPI_WR_SNGL; count = t-len; wlen = t-bits_per_word 3; /* in bytes */ + xfer_len = wlen; while (count) { if (qspi_is_busy(qspi)) @@ -241,7 +245,29 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) case 1: dev_dbg(qspi-dev, tx cmd %08x dc %08x data %02x\n, cmd, qspi-dc, *txbuf); - writeb(*txbuf, qspi-base + QSPI_SPI_DATA_REG); + if (count = QSPI_WLEN_MAX_BYTES) { + u32 *txp = (u32 *)txbuf; + + data = cpu_to_be32(*txp++); + writel(data, qspi-base + + QSPI_SPI_DATA_REG_3); + data = cpu_to_be32(*txp++); + writel(data, qspi-base + + QSPI_SPI_DATA_REG_2); + data = cpu_to_be32(*txp++); + writel(data, qspi-base + + QSPI_SPI_DATA_REG_1); + data = cpu_to_be32(*txp++); + writel(data, qspi-base + + QSPI_SPI_DATA_REG); + xfer_len = QSPI_WLEN_MAX_BYTES; + cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); + } else { + writeb(*txbuf, qspi-base + QSPI_SPI_DATA_REG); + cmd = qspi-cmd | QSPI_WR_SNGL; + xfer_len = wlen; + cmd |= QSPI_WLEN(wlen); + } break; case 2: dev_dbg(qspi-dev, tx cmd %08x dc %08x data %04x\n, @@ -261,8 +287,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) dev_err(qspi-dev, write timed out\n); return -ETIMEDOUT; } - txbuf += wlen; - count -= wlen; + txbuf += xfer_len; + count -= xfer_len; } return 0; -- 2.5.0 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/5] spi: introduce flag for memory mapped read
On 08/07/2015 03:46 PM, Michal Suchanek wrote: [snip] On 7 August 2015 at 10:35, Vignesh R vigne...@ti.com wrote: On 08/07/2015 01:08 PM, Michal Suchanek wrote: Now since the description is clearer it's obvious that ti-qspi cannot work fully mmapped as fsl-qspi does because the setup has to be done over normal spi access and using non-m25p80 devices on the same bus is a requirement. The place where it is known if a transfer can use the mmap access is m25p80.c So my suggestion is - add a new method for spi master that gets the read opcode, dummy length, address, address length, buffer, buffer length and performs read from the flash memory in a hardware-specific way - add a check in m25p80.c that the master supports this feature and if so use it (eg check that the method is non-null) Presumably if some new SPI controllers with similar feature are supported in the future they can use the same inteface because you pass on everything the m25p80 read knows. Ok... Do you mean something like this? I will take m25p80 as example but can be expanded for any flash. In include/linux/mtd.h: struct spi_mtd_config_info { struct spi_device *spi; u32 page_size; u8 addr_width; u8 erase_opcode; u8 read_opcode; u8 read_dummy; u8 program_opcode; enum read_mode flash_read; } /* subset of struct spi_nor */ I would just pass these as separate arguments to the function but whatver. In m25p80.c: static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_mtd_config_info info; struct spi_device *spi; if (spi-master-spi_mtd_mmap_read) { /* Populate spi_mtd_config_info */ spi-master-spi_mtd_mmap_read(info, from, len, retlen, buf); } else { /* no mtd specific acceleration supported try normal * SPI way of communicating with flash * continue with current code * set up spi_message and call spi_sync() */ } } In spi-ti-qspi.c: Implement spi_mtd_mmap_read while holding master-bus_lock mutex. I will re-submit patches based on the above idea, if there are no further comments.. -- Thanks Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/5] spi: introduce flag for memory mapped read
On 08/07/2015 01:08 PM, Michal Suchanek wrote: Now since the description is clearer it's obvious that ti-qspi cannot work fully mmapped as fsl-qspi does because the setup has to be done over normal spi access and using non-m25p80 devices on the same bus is a requirement. The place where it is known if a transfer can use the mmap access is m25p80.c So my suggestion is - add a new method for spi master that gets the read opcode, dummy length, address, address length, buffer, buffer length and performs read from the flash memory in a hardware-specific way - add a check in m25p80.c that the master supports this feature and if so use it (eg check that the method is non-null) Presumably if some new SPI controllers with similar feature are supported in the future they can use the same inteface because you pass on everything the m25p80 read knows. Ok... Do you mean something like this? I will take m25p80 as example but can be expanded for any flash. In include/linux/mtd.h: struct spi_mtd_config_info { struct spi_device *spi; u32 page_size; u8 addr_width; u8 erase_opcode; u8 read_opcode; u8 read_dummy; u8 program_opcode; enum read_mode flash_read; } /* subset of struct spi_nor */ In m25p80.c: static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_mtd_config_info info; struct spi_device *spi; if (spi-master-spi_mtd_mmap_read) { /* Populate spi_mtd_config_info */ spi-master-spi_mtd_mmap_read(info, from, len, retlen, buf); } else { /* no mtd specific acceleration supported try normal * SPI way of communicating with flash * continue with current code * set up spi_message and call spi_sync() */ } } In spi-ti-qspi.c: Implement spi_mtd_mmap_read while holding master-bus_lock mutex. -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/5] spi: introduce flag for memory mapped read
On 08/06/2015 03:52 PM, Russell King - ARM Linux wrote: On Thu, Aug 06, 2015 at 12:01:37PM +0200, Michal Suchanek wrote: Disclaimer: I am not familiar with the hardware for which this patch adds support. However, I am familiar m25p80.c and as I understand it the controller is basically supposed to implement m25p80.c in hardware when this flag is set. That, to me, sounds like what you have is: ---m25p80 specific interface---SPI bus---m25p80 device Where the m25p80 specific interface does not expose direct access to the SPI bus? Let me give overview of ti-qspi controller: There are two interfaces in the controller, one exposes direct access to SPI bus and the other doesn't. It is possible to dynamically switch between these ports by writing to QSPI_SPI_SWITCH_REG. The two interface are [1]: 1) Generic SPI interface: (config port): with this interface, ti-qspi controller can communicate with *any* spi device (flash and non-flash). This interface is provides direct access to SPI bus. 2) SPI memory mapped interface (memory mapped port): This is m25p80 specific interface which can be use to read data from flash. But if the flash has to be configured to some particular mode like QUAD READ MODE, then the controller needs to be put in to config port to read and modify serial flash's config register and then switch to memory mapped port in order to read data stored on flash. For example on DRA74 evm, if a 64 MB flash is connected as a slave, entire flash memory is visible from 0x5C00 to 0x5FFF L3_MAIN address. In order to read using memory mapped port following will be the sequence: 1.Write to flash config register via config port to switch to QUAD MODE (or any mode that flash supports). 2. Populate QSPI_SPI_SETUP_REGx with flash read command, number of address bytes to use and dummy bytes required. 3. Switch to memory mapped port by writing to QSPI_SPI_SWITCH_REG. 4. Now, its possible to perform read from 0x5C00 to 0x5FFF using memcpy. The qspi controller hardware will communicate over SPI bus and get the data. This data is directly sent to RAM via SoC's interconnect. Advantages of memory mapped port are: improved read performance, MEM_TO_MEM DMA support can be added (ti-qspi hardware as such does not provide DMA events). Advantages of config port: can be used to communicate with *any* SPI device, provides direct read/write access to SPI bus. On the whole following are my requirements: 1. to be able to communicate with non -flash SPI devices via config port ( this functionality is supported by current driver, I dont want to break it). Or pump any spi_message on to SPI bus directly. 2. take advantage of memory mapped port in order to increase read throughput( and use dma in future) when the slave is a m25p80 type flash. 3. handle m25p80 as well as other slave on multiple chipselects. I just need to know whether the user that requested the transfer is m25p80 driver. If yes, ti-qspi driver can take advantage of memory mapped interface, else just use config port to access SPI bus directly. Writing separate driver based on spi-nor framework to interface with m25p80 is not an option because, I would lose the ability to interface with non-flash devices. The spi_message that is received in transfer_one_message() is too generic to imply the slave device that is on the other side of the wire. IMO, the read command does not imply that the slave is m25p80 flash (besides the read opcodes vary across vendors of m25p80 and across modes). As Michal suggested, adding a flag to spi_device to distinguish whether the slave is a m25p80 flash type will help spi master to handle optimizations specific to m25p80s while being generic enough to handle all other spi devices. Is that ok? Is there any other way to imply what slave as at the other end? [1] TRM: http://www.ti.com/lit/ug/spruhz6/spruhz6.pdf 24.5.4 QSPI Functional Description -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/5] spi: introduce flag for memory mapped read
On 08/05/2015 10:51 AM, Michal Suchanek wrote: Hello, On 4 August 2015 at 19:59, R, Vignesh vigne...@ti.com wrote: On 8/4/2015 9:21 PM, Mark Brown wrote: On Mon, Aug 03, 2015 at 10:27:19AM +0530, Vignesh R wrote: @use_mmap_mode: Some SPI controller chips are optimized for interacting with serial flash memories. These chips have memory mapped interface, through which entire serial flash memory slave can be read/written as if though they are physical memories (like RAM). Using this interface, flash can be accessed using memcpy() function and the spi controller hardware will take care of communicating with serial flash over SPI. Setting this flag will indicate the SPI controller driver that the spi_message is from mtd layer to read from/write to flash. The SPI master driver can then appropriately switch the controller to memory mapped interface to read from/write to flash, based on this flag (See drivers/spi/spi-ti-qspi.c for example). NOTE: If the SPI controller chip lacks memory mapped interface, then the driver will ignore this flag and use normal SPI protocol to read from/write to flash. Communication with non-flash SPI devices is not possible using the memory mapped interface. I still can't tell from the above what this interface is supposed to do. It sounds like the use of memory mapped mode is supposed to be transparent to users, it should just affect how the controller interacts with the hardware, but if that's the case why do we need to expose it to users at all? Shouldn't the driver just use memory mapped mode if it's faster? TI QSPI controller has two blocks: 1. SPI_CORE: This is generic(normal) spi mode. This can be used to communicate with any SPI devices (serial flashes as well as non-flash devices like touchscreen). 2. SFI_MM_IF(SPI memory mapped interface): The SFI_MM_IF block only allows reading and writing to an SPI flash device only. Used to speed up flash reads. It _cannot_ be used to communicate with non flash devices. Now, the spi_message that ti-qspi receives in transfer_one() callback can be from mtd device(in which case SFI_MM_IF can be used) or from any other non flash SPI device (in which case SFI_MM_IF must not be used instead SPI_CORE is to be used) but there is no way(is there?) to distinguish where spi_message is from. Therefore I introduced flag (use_mmap_mode) to struct spi_message. mtd driver will set flag to true, this helps the ti-qspi driver to determine that the user is flash device and thus can do read via SFI_MM_IF. If this flag is not set then the user is assumed to be non flash SPI driver and will use SPI_CORE block to communicate. On the whole, I just need a way to determine that the user is a flash device in order to switch to memory mapped interface. Maybe it can be set on the SPI slave rather than each message. You mean to add flag to spi_device struct? That's ok for me. -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/5] spi: introduce flag for memory mapped read
Hi, On 7/31/2015 11:47 PM, Mark Brown wrote: On Tue, Jul 28, 2015 at 02:11:12PM +0530, Vignesh R wrote: Introduce use_mmap_read field in spi_message struct. This can be set by mtd devices (m25p80) to indicate to spi-master (ti-qspi) to perform memory mapped read. This helps to distinguish whether the spi-message is from mtd layer(hence mmap read is possible) or by other spi devices. Based on this description and... + * @use_mmap_mode: Indicate to spi master to perform memory mapped + * read if possible. ...the internal documentation I unable to tell what is meant by perform a memory mapped read, at least to the extent where it is visible outside of the driver. This means we can't really use this as a generic API since other people won't be able to tell what it does. Will the following documentation provide better idea regarding the flag: @use_mmap_mode: Some SPI controller chips are optimized for interacting with serial flash memories. These chips have memory mapped interface, through which entire serial flash memory slave can be read/written as if though they are physical memories (like RAM). Using this interface, flash can be accessed using memcpy() function and the spi controller hardware will take care of communicating with serial flash over SPI. Setting this flag will indicate the SPI controller driver that the spi_message is from mtd layer to read from/write to flash. The SPI master driver can then appropriately switch the controller to memory mapped interface to read from/write to flash, based on this flag (See drivers/spi/spi-ti-qspi.c for example). NOTE: If the SPI controller chip lacks memory mapped interface, then the driver will ignore this flag and use normal SPI protocol to read from/write to flash. Communication with non-flash SPI devices is not possible using the memory mapped interface. I can update the patch commit message and documentation accordingly? Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 4/5] ARM: dts: DRA7: Add memory map region entries for qspi
On 07/31/2015 11:49 PM, Mark Brown wrote: On Tue, Jul 28, 2015 at 02:11:15PM +0530, Vignesh R wrote: Add qspi memory mapped region entries for DRA7xx based SoCs. Signed-off-by: Vignesh R vigne...@ti.com qspi: qspi@4790 { compatible = ti,am4372-qspi; -reg = 0x4790 0x100; +reg = 0x4790 0x100, + 0x3000 0x3ff; +reg-names = qspi_base, qspi_mmap; The DT binding document for the controller needs to be extended to document this change in the binding. DT bindings are already documented at Documentation/devicetree/bindings/spi/ti_qspi.txt. Did you mean to add this node as an example in that file? -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 4/5] ARM: dts: DRA7: Add memory map region entries for qspi
On 08/01/2015 02:58 AM, Brian Norris wrote: On Tue, Jul 28, 2015 at 02:11:15PM +0530, Vignesh R wrote: Add qspi memory mapped region entries for DRA7xx based SoCs. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/boot/dts/am4372.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index ade28c790f4b..5317a0f24ab9 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -902,7 +902,9 @@ qspi: qspi@4790 { compatible = ti,am4372-qspi; -reg = 0x4790 0x100; +reg = 0x4790 0x100, + 0x3000 0x3ff; Are you sure this region is 1 byte shy of 64MB in length? Same question for patch 5. Oops, my bad... Its 64MB in length, I entered offset of last byte instead of length. Will correct this in the actual patch. +reg-names = qspi_base, qspi_mmap; #address-cells = 1; #size-cells = 0; ti,hwmods = qspi; -- 2.4.6 -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 4/5] ARM: dts: DRA7: Add memory map region entries for qspi
On 07/31/2015 07:18 PM, Sekhar Nori wrote: On Tuesday 28 July 2015 02:11 PM, Vignesh R wrote: Add qspi memory mapped region entries for DRA7xx based SoCs. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/boot/dts/am4372.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index ade28c790f4b..5317a0f24ab9 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi The patch talks about DRA7x in subject and description but you modify AM437x here. You have got commit text mixed up between 4/5 and 5/5. Probably not the kind of feedback you are looking for an RFC, but since I noticed it.. Oh, my bad.. I will correct $subject when I submit actual patch series. -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/5] ARM: OMAP2+: DRA7: Add hwmod entries for PWMSS
On 07/23/2015 09:05 PM, R, Vignesh wrote: On 7/16/2015 9:01 PM, R, Vignesh wrote: Hi, On 07/16/2015 03:24 AM, Paul Walmsley wrote: Hi, some comments. On Wed, 3 Jun 2015, Vignesh R wrote: Add hwmod entries for the PWMSS on DRA7. Set l4_root_clk_div as the main_clk of PWMSS. It is fixed-factored clock equal to L4PER2_L3_GICLK/2(l3_iclk_div/2). As per AM57x TRM SPRUHZ6[1], October 2014, Section 29.1.3 Table 29-4, clock source to PWMSS is L4PER2_L3_GICLK. But it is actually L4PER2_L3_GICLK/2. The TRM does not show the division by 2. Is the divide-by-two coming from PWMSS_EPWM.EPWM_TBCTL[HSPCLKDIV]? Or is HSPCLKDIV a separate divider after the divide-by-2 you mention above? No, it not related to HSPCLKDIV. The TRM wrongly states L4PER2_L3_GICLK as clock input for PWMSS. But actually L4PER2_L4_GICLK(=L3_GICLK/2) is the clock input for PWMSS. This will be updated in TRM soon. [1] www.ti.com/lit/ug/spruhz6/spruhz6.pdf Signed-off-by: Vignesh R vigne...@ti.com --- v2: * add TRM references. arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 239 ++ 1 file changed, 239 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 0e64c2fac0b5..86a7ac9a3138 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -362,6 +362,149 @@ static struct omap_hwmod dra7xx_dcan2_hwmod = { }, }; +/* pwmss */ +static struct omap_hwmod_class_sysconfig dra7xx_epwmss_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x4, + .sysc_flags = SYSC_HAS_SIDLEMODE | SYSC_HAS_RESET_STATUS, This doesn't match SPRUHZ6 Table 29-13 PWMSS_SYSCONFIG. There's no RESETSTATUS bit. There is a SOFTRESET bit. Could you please confirm whether this is intentional? sorry my bad... I will change this in v3. + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields= omap_hwmod_sysc_type2, +}; + +struct omap_hwmod_class dra7xx_epwmss_hwmod_class = { + .name = epwmss, + .sysc = dra7xx_epwmss_sysc, +}; + +static struct omap_hwmod_class dra7xx_ecap_hwmod_class = { + .name = ecap, +}; + +static struct omap_hwmod_class dra7xx_eqep_hwmod_class = { + .name = eqep, +}; + +struct omap_hwmod_class dra7xx_ehrpwm_hwmod_class = { + .name = ehrpwm, +}; + +/* epwmss0 */ +struct omap_hwmod dra7xx_epwmss0_hwmod = { + .name = epwmss0, + .class = dra7xx_epwmss_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = DRA7XX_CM_L4PER2_PWMSS1_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_PWMSS1_CONTEXT_OFFSET, + }, + }, Per my comment on the previous patch, sounds like it might be better to mark this as HWMOD_SWSUP_SIDLE? Then again, see the next comment below re: main_clk. +}; + +/* ecap0 */ +struct omap_hwmod dra7xx_ecap0_hwmod = { + .name = ecap0, + .class = dra7xx_ecap_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, Looking at SPRUHZ6 Section 29.1.4.2 PWMSS Modules Local Clock Gating, there appears to be a local mini-PRCM for the PWMSS which implements clock gating and reports back on the status of what I'd guess is the local clock gating FSM. So from that point of view, you should probably create a clock driver that manages both the clock gate request bit and the FSM status bit. It should be something that can be reused for the other PWMSS IP blocks. Then you'd create per-IP block clock nodes and set the main_clk to point to that node. Since, this register is within the config space of PWMSS, the individual gating and reporting for the modules within PWMSS (PWMSS_CLKCONFIG) is currently being taken care by pwm-tipwmss.c(almost the sole function this driver is doing). It has been the same since am335x. Adding new clock nodes will result in driver changes and also changes to am335x, am437x (and other platforms) hwmod files. It also involves adding new nodes to clocks.dtsi and it will be difficult to maintain backward compatibility for older platforms. Is it not better to keep this as is, in order to maintain consistency (with am335x, am437x etc) and also that these clock bits are within IP's config space? ping... I really want PWMSS support to go into v4.3... I see two options: 1. Drop pwm-tipwmss.c that is currently managing PWMSS Modules Local Clock Gating and change am335x, am437x and dra7 to use new main_clk and update clocks.dtsi (Breaks DT backward compatibility for am335x, am437x) 2. Or stick with $subject approach to maintain consistency. I prefer second option, Shall I send a v3 fixing other comments
[RFC PATCH 5/5] ARM: dts: AM4372: Add memory map region entries for qspi
Add qspi memory mapped region entries for AM43xx based SoCs. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/boot/dts/dra7.dtsi | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 8f1e25bcecbd..75a17c78b0ad 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1103,8 +1103,10 @@ qspi: qspi@4b30 { compatible = ti,dra7xxx-qspi; - reg = 0x4b30 0x100; - reg-names = qspi_base; + reg = 0x4b30 0x100, 0x4a002558 0x4, + 0x5c00 0x3ff; + reg-names = qspi_base, qspi_ctrlmod, + qspi_mmap; #address-cells = 1; #size-cells = 0; ti,hwmods = qspi; -- 2.4.6 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 3/5] mtd: devices: m25p80: set flag to request memory mapped read
Set use_mmap_read flag to true, to indicate to spi-master that the spi-message is from mtd layer. This helps spi-master to do memory mapped reads over SPI flash memories, when hardware support is available. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/mtd/devices/m25p80.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b96c..aac2121c5454 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -148,6 +148,9 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, t[1].len = len; spi_message_add_tail(t[1], m); + m.spi = spi; + m.use_mmap_mode = true; + spi_sync(spi, m); *retlen = m.actual_length - m25p_cmdsz(nor) - dummy; -- 2.4.6 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 0/5] Add memory mapped read support for TI QSPI.
This patch series adds support for memory mapped reads for TI QSPI driver. TI QSPI controller has memory mapped port (SFI translator interface [1]) through which SPI flash memories can be read using memcpy call. SFI translator takes care of generating appropriate SPI signals to read data from flash. This interface works only with SPI flash memories and cannot be used with other SPI devices. To use memory mapped port, the controller is switched to memory mapped interface by writing to QSPI_SPI_SWITCH_REG. The read_opcode, read mode, dummy bytes are set in QSPI_SPI_SETUPx_REG. Once switched, the SPI flash is available to SoC to read at specific address. This interface is disabled once memory mapped read is complete. For write, erase and interaction with non-flash SPI devices normal SPI interface is used. The m25p80 driver sets use_mmap_read flag in spi-message struct passed to spi-ti-qspi so as to indicate the read request is from mtd layer. spi-ti-qspi driver switches to memory mapped mode and does memcpy based on use_mmap_read flag. The read performace increased from ~100kB/s to ~2.5MB/s on DRA74 EVM. Tested on DRA74 EVM with spansion S25FL256S flash. Tested on AM437x sk evm with macronix MX66l51235l flash. [1] http://www.ti.com/lit/ug/spruhz6/spruhz6.pdf Section 24.5.4 QSPI Functional Description Vignesh R (5): spi: introduce flag for memory mapped read spi: spi-ti-qspi: Add memory mapped read support mtd: devices: m25p80: set flag to request memory mapped read ARM: dts: DRA7: Add memory map region entries for qspi ARM: dts: AM4372: Add memory map region entries for qspi arch/arm/boot/dts/am4372.dtsi | 4 +- arch/arm/boot/dts/dra7.dtsi | 6 +- drivers/mtd/devices/m25p80.c | 3 + drivers/spi/spi-ti-qspi.c | 129 -- include/linux/spi/spi.h | 3 + 5 files changed, 138 insertions(+), 7 deletions(-) -- 2.4.6 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 4/5] ARM: dts: DRA7: Add memory map region entries for qspi
Add qspi memory mapped region entries for DRA7xx based SoCs. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/boot/dts/am4372.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index ade28c790f4b..5317a0f24ab9 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -902,7 +902,9 @@ qspi: qspi@4790 { compatible = ti,am4372-qspi; - reg = 0x4790 0x100; + reg = 0x4790 0x100, + 0x3000 0x3ff; + reg-names = qspi_base, qspi_mmap; #address-cells = 1; #size-cells = 0; ti,hwmods = qspi; -- 2.4.6 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 2/5] spi: spi-ti-qspi: Add memory mapped read support
TI QSPI controller has memory mapped port through which SPI flash memories can be read using memcpy call. This patch adds support for memory mapped read based on use_mmap_read flag. When use_mmap_read flag is set, the controller is switched to memory mapped interface by writing to QSPI_SPI_SWITCH_REG. The read_opcode, read mode, dummy bytes are configured in QSPI_SPI_SETUPx_REG, then memcpy is called to copy the requested data from flash to the rx_buf. With this patch, the read speed increased from ~100kB/s to ~2.5MB/s on DRA74 EVM. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/spi/spi-ti-qspi.c | 129 -- 1 file changed, 125 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 5c0616870358..45844a227c5e 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -71,11 +71,8 @@ struct ti_qspi { #define QSPI_SPI_CMD_REG (0x48) #define QSPI_SPI_STATUS_REG(0x4c) #define QSPI_SPI_DATA_REG (0x50) -#define QSPI_SPI_SETUP0_REG(0x54) +#define QSPI_SPI_SETUP_REG(n) (0x54 + 4 * n) #define QSPI_SPI_SWITCH_REG(0x64) -#define QSPI_SPI_SETUP1_REG(0x58) -#define QSPI_SPI_SETUP2_REG(0x5c) -#define QSPI_SPI_SETUP3_REG(0x60) #define QSPI_SPI_DATA_REG_1(0x68) #define QSPI_SPI_DATA_REG_2(0x6c) #define QSPI_SPI_DATA_REG_3(0x70) @@ -118,6 +115,16 @@ struct ti_qspi { #define QSPI_AUTOSUSPEND_TIMEOUT 2000 +#define MEM_CS_EN(n) ((n + 1) 8) + +#define MM_SWITCH 0x1 + +#define QSPI_SETUP_RD_NORMAL (0x0 12) +#define QSPI_SETUP_RD_DUAL (0x1 12) +#define QSPI_SETUP_RD_QUAD (0x3 12) +#define QSPI_SETUP_ADDR_SHIFT 8 +#define QSPI_SETUP_DUMMY_SHIFT 10 + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -335,6 +342,117 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void ti_qspi_enable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi-master); + u32 val; + + ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG); + if (qspi-ctrl_mod) { + val = readl(qspi-ctrl_base); + val |= MEM_CS_EN(spi-chip_select); + writel(val, qspi-ctrl_base); + } +} + +static void ti_qspi_disable_memory_map(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi-master); + u32 val; + + ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG); + if (qspi-ctrl_mod) { + val = readl(qspi-ctrl_base); + val = ~MEM_CS_EN(spi-chip_select); + writel(val, qspi-ctrl_base); + } +} + +static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 + read_opcode, u8 addr_width, + u8 dummy_bytes) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi-master); + u32 mode = spi-mode (SPI_RX_DUAL | SPI_RX_QUAD); + u32 memval = read_opcode; + + switch (mode) { + case SPI_RX_QUAD: + memval |= QSPI_SETUP_RD_QUAD; + break; + case SPI_RX_DUAL: + memval |= QSPI_SETUP_RD_DUAL; + break; + default: + memval |= QSPI_SETUP_RD_NORMAL; + break; + } + memval |= ((addr_width - 1) QSPI_SETUP_ADDR_SHIFT | + dummy_bytes QSPI_SETUP_DUMMY_SHIFT); + ti_qspi_write(qspi, memval, + QSPI_SPI_SETUP_REG(spi-chip_select)); +} + +static unsigned int ti_qspi_cmd2addr(u8 *cmd, u8 addr_width) +{ + u32 addr; + + /* cmd[0] is read opcode */ + addr = cmd[1] ((addr_width - 1) * 8); + addr |= cmd[2] ((addr_width - 2) * 8); + addr |= cmd[3] ((addr_width - 3) * 8); + addr |= cmd[4] ((addr_width - 4) * 8); + + return addr; +} + +static int ti_qspi_mmap_read(struct spi_master *master, +struct spi_message *m) +{ + struct ti_qspi *qspi = spi_master_get_devdata(master); + struct spi_device *spi = m-spi; + struct spi_transfer *t; + u8 read_opcode = 0x3; /* Default normal read */ + void *to = NULL; + u8 addr_width = 4, dummy_bytes = 0; + unsigned int len = 0, from = 0; + int status = 0; + + mutex_lock(qspi-list_lock); + + /* disable WC interrupt during memcpy */ + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); + ti_qspi_enable_memory_map(spi); + list_for_each_entry(t, m-transfers, transfer_list) { + if (t-tx_buf) { + read_opcode = *((u8 *)t-tx_buf); + dummy_bytes = t-len
[RFC PATCH 1/5] spi: introduce flag for memory mapped read
TI QSPI controller has SFI translator which exposes entire flash memory as memory mapped region for read. With this interface, the CPU can copy data from flash using normal memcpy call. SFI translator takes care of generating appropriate SPI signals to read data from flash. This interface works only with SPI flash memories and cannot be used with other SPI devices. Introduce use_mmap_read field in spi_message struct. This can be set by mtd devices (m25p80) to indicate to spi-master (ti-qspi) to perform memory mapped read. This helps to distinguish whether the spi-message is from mtd layer(hence mmap read is possible) or by other spi devices. Signed-off-by: Vignesh R vigne...@ti.com --- include/linux/spi/spi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d673072346f2..f1a0329ee63f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -640,6 +640,8 @@ struct spi_transfer { * @actual_length: the total number of bytes that were transferred in all * successful segments * @status: zero for success, else negative errno + * @use_mmap_mode: Indicate to spi master to perform memory mapped + * read if possible. * @queue: for use by whichever driver currently owns the message * @state: for use by whichever driver currently owns the message * @@ -681,6 +683,7 @@ struct spi_message { unsignedframe_length; unsignedactual_length; int status; + booluse_mmap_mode; /* for optional use by whatever driver currently owns the * spi_message ... between calls to spi_async and then later -- 2.4.6 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
On 07/27/2015 04:19 PM, Roger Quadros wrote: Hi, On 23/07/15 17:54, Vignesh R wrote: On am437x-gp-evm, pixcir touchscreen can wake the system from low power state by generating wake-up interrupt via pinctrl and IO daisy chain. Add support for optional wakeup interrupt source by regsitering to automated wake IRQ framework introduced by commit 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling). This is similar in approach to commit 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Signed-off-by: Vignesh R vigne...@ti.com --- v3: * handle error code returned by of_irq_get_byname() v2: * use of_irq_get_byname() * remove enable/disable_wake_irq() drivers/input/touchscreen/pixcir_i2c_ts.c | 22 ++ include/linux/input/pixcir_ts.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..3a4ab358bf52 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,6 +29,8 @@ #include linux/of.h #include linux/of_gpio.h #include linux/of_device.h +#include linux/of_irq.h +#include linux/pm_wakeirq.h #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -364,8 +366,6 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) goto unlock; } } - -enable_irq_wake(client-irq); } else if (input-users) { ret = pixcir_stop(ts); } @@ -386,8 +386,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(input-mutex); if (device_may_wakeup(client-dev)) { -disable_irq_wake(client-irq); - if (!input-users) { ret = pixcir_stop(ts); if (ret) { @@ -445,6 +443,13 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) dev_dbg(dev, %s: x %d, y %d, gpio %d\n, __func__, pdata-x_max + 1, pdata-y_max + 1, pdata-gpio_attb); +pdata-wakeirq = of_irq_get_byname(dev-of_node, wakeup); +if (pdata-wakeirq 0 pdata-wakeirq != -ENODATA +pdata-wakeirq != -EINVAL) { +dev_err(dev, Failed to get wakeirq\n); +return ERR_PTR(pdata-wakeirq); +} + return pdata; } #else @@ -564,11 +569,20 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); device_init_wakeup(client-dev, 1); +/* Register wakeirq */ +error = (pdata-wakeirq 0) ? +dev_pm_set_dedicated_wake_irq(dev, pdata-wakeirq) : +dev_pm_set_wake_irq(dev, client-irq); Can 0 be a valid wakeirq or client-irq? If yes then this logic is broken. AFAIK, IRQ 0 is always assigned to system timer interrupt (cannot find reliable source to quote). I would set wakeirq to -EINVAL or something if it is not available during probe and check for that condition. Not sure, if I understand you correctly pdata-wakeirq will have -ENODATA or -EINVAL(as returned by of_irq_get_byname()), if wakeirq is not available. Do you want me to check for these two conditions specifically rather than (pdata-wakeirq 0) ? -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
On am437x-gp-evm, pixcir touchscreen can wake the system from low power state by generating wake-up interrupt via pinctrl and IO daisy chain. Add support for optional wakeup interrupt source by regsitering to automated wake IRQ framework introduced by commit 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling). This is similar in approach to commit 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Signed-off-by: Vignesh R vigne...@ti.com --- v3: * handle error code returned by of_irq_get_byname() v2: * use of_irq_get_byname() * remove enable/disable_wake_irq() drivers/input/touchscreen/pixcir_i2c_ts.c | 22 ++ include/linux/input/pixcir_ts.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..3a4ab358bf52 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,6 +29,8 @@ #include linux/of.h #include linux/of_gpio.h #include linux/of_device.h +#include linux/of_irq.h +#include linux/pm_wakeirq.h #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -364,8 +366,6 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) goto unlock; } } - - enable_irq_wake(client-irq); } else if (input-users) { ret = pixcir_stop(ts); } @@ -386,8 +386,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(input-mutex); if (device_may_wakeup(client-dev)) { - disable_irq_wake(client-irq); - if (!input-users) { ret = pixcir_stop(ts); if (ret) { @@ -445,6 +443,13 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) dev_dbg(dev, %s: x %d, y %d, gpio %d\n, __func__, pdata-x_max + 1, pdata-y_max + 1, pdata-gpio_attb); + pdata-wakeirq = of_irq_get_byname(dev-of_node, wakeup); + if (pdata-wakeirq 0 pdata-wakeirq != -ENODATA + pdata-wakeirq != -EINVAL) { + dev_err(dev, Failed to get wakeirq\n); + return ERR_PTR(pdata-wakeirq); + } + return pdata; } #else @@ -564,11 +569,20 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); device_init_wakeup(client-dev, 1); + /* Register wakeirq */ + error = (pdata-wakeirq 0) ? + dev_pm_set_dedicated_wake_irq(dev, pdata-wakeirq) : + dev_pm_set_wake_irq(dev, client-irq); + if (error) + dev_info(dev, unable to setup wakeirq %d\n, +error); + return 0; } static int pixcir_i2c_ts_remove(struct i2c_client *client) { + dev_pm_clear_wake_irq(client-dev); device_init_wakeup(client-dev, 0); return 0; diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7bae83b7c396..da573de5a5ee 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -58,6 +58,7 @@ struct pixcir_ts_platform_data { int x_max; int y_max; int gpio_attb; /* GPIO connected to ATTB line */ + int wakeirq; struct pixcir_i2c_chip_data chip; }; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 2/2] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc
Pixcir_i2c_tsc driver can now wakeup the system from lower power state via pinctrl and IO daisy chain using generic wakeirq framwework. Add optional wakeup irq entry to allow pixcir_i2c_tsc to wake system from low power state. Signed-off-by: Vignesh R vigne...@ti.com --- v3: * Drop irq suffix from interrupt-names. v2: * Add interrupt-names property. arch/arm/boot/dts/am437x-gp-evm.dts | 4 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 84aa30c3235a..99209a137c63 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -503,6 +503,10 @@ attb-gpio = gpio3 22 GPIO_ACTIVE_HIGH; + interrupts-extended = gpio3 22 GPIO_ACTIVE_HIGH, + am43xx_pinmux 0x264; + interrupt-names = tsc, wakeup; + touchscreen-size-x = 1024; touchscreen-size-y = 600; }; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 0/2] pixcir_i2c_ts: Add optional wakeup irq support
This is the v3 of the patch series to add optional wake irq support for pixcir_i2c_tsc. Tested on am437x-gp-evm, with some out of tree patches to support suspend/resume on am437x. Vignesh R (2): input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc arch/arm/boot/dts/am437x-gp-evm.dts | 4 drivers/input/touchscreen/pixcir_i2c_ts.c | 22 ++ include/linux/input/pixcir_ts.h | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/3] mmc: host: omap_hsmmc: Add custom card detect irq handler
Hi Andreas, On 07/21/2015 01:46 PM, Andreas Fenkart wrote: Hi Vignesh, Generally I don't like this patch, it will make it harder, not easier, to maintain the omap hsmmc driver. Also given that the bug occurs rarely, people will be reluctant to clean it up later or accept patches. see also comments below [snip] 2015-06-22 15:18 GMT+02:00 Vignesh R vigne...@ti.com: But calls to omap_hsmmc_card_init or omap_hsmmc_get_cd are in the same mmc_rescan thread. Hence, moving the recovery code to init_card does not help. what about clearing any pending transfer in - mmc_gpio_cd_irqt, or - mmc_detect_change e.g. trigger the later mentioned .card_event callback from those functions, instead mmc_rescan? Then you can install your omap_hsmmc_request_clear as the card_event callback. This makes your custom isr handler redundant, actually your isr handler became standard. I looked at the commit fa372a51cb5f93800f711473e5a36e0e0c9a8f00 which moved .card_event out of mmc_gpio_cd_irqt. It points to two threads where discussion to move .card_event to mmc_rescan happened[1][2]. The concern there was this callback was being called from atomic context but, I don't understand how threaded irq is atomic context. (I am not sure, if this is because those drivers have irqs disabled till threaded irq is complete) But, I believe moving card_event callback back to mmc_gpio_cd_irqt may break some drivers. I will look into this further. Do you have any insight on this commit? Thanks! [1]https://lkml.org/lkml/2014/3/19/79 [2]https://lkml.org/lkml/2013/8/19/539 -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
Hi Dmitry, On 07/20/2015 11:54 AM, Dmitry Torokhov wrote: On Sun, Jul 19, 2015 at 11:09:30PM -0700, Tony Lindgren wrote: * Vignesh R vigne...@ti.com [150719 21:53]: @@ -445,6 +443,8 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) dev_dbg(dev, %s: x %d, y %d, gpio %d\n, __func__, pdata-x_max + 1, pdata-y_max + 1, pdata-gpio_attb); + pdata-wakeirq = of_irq_get_byname(dev-of_node, wakeupirq); + return pdata; What about handling -EPROVE_DEFER here? At least pinctrl-single can be be a loadable module for the dedicated wakeirqs. Right. I think we should only allow -ENODATA to continue and return error in all other cases. -EINVAL will be returned if interrupt-names is not specified. I will make execption for -ENODATA -EINVAL, and return error in all other cases? Also, I think irq suffix on name is redundant. Ok, will drop irq suffix: + interrupt-names = tsc, wakeup; Thanks. -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
On am437x-gp-evm, pixcir touchscreen can wake the system from low power state by generating wake-up interrupt via pinctrl and IO daisy chain. Add support for optional wakeup interrupt source by regsitering to automated wake IRQ framework introduced by commit 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling). This is similar in approach to commit 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Signed-off-by: Vignesh R vigne...@ti.com --- v2: * use of_irq_get_byname() * remove enable/disable_wake_irq() drivers/input/touchscreen/pixcir_i2c_ts.c | 17 + include/linux/input/pixcir_ts.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..b9cebf274678 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,6 +29,8 @@ #include linux/of.h #include linux/of_gpio.h #include linux/of_device.h +#include linux/of_irq.h +#include linux/pm_wakeirq.h #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -364,8 +366,6 @@ static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev) goto unlock; } } - - enable_irq_wake(client-irq); } else if (input-users) { ret = pixcir_stop(ts); } @@ -386,8 +386,6 @@ static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev) mutex_lock(input-mutex); if (device_may_wakeup(client-dev)) { - disable_irq_wake(client-irq); - if (!input-users) { ret = pixcir_stop(ts); if (ret) { @@ -445,6 +443,8 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) dev_dbg(dev, %s: x %d, y %d, gpio %d\n, __func__, pdata-x_max + 1, pdata-y_max + 1, pdata-gpio_attb); + pdata-wakeirq = of_irq_get_byname(dev-of_node, wakeupirq); + return pdata; } #else @@ -564,11 +564,20 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); device_init_wakeup(client-dev, 1); + /* Register wakeirq */ + error = pdata-wakeirq ? + dev_pm_set_dedicated_wake_irq(dev, pdata-wakeirq) : + dev_pm_set_wake_irq(dev, client-irq); + if (error) + dev_info(dev, unable to get wakeirq %d\n, +error); + return 0; } static int pixcir_i2c_ts_remove(struct i2c_client *client) { + dev_pm_clear_wake_irq(client-dev); device_init_wakeup(client-dev, 0); return 0; diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7bae83b7c396..da573de5a5ee 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -58,6 +58,7 @@ struct pixcir_ts_platform_data { int x_max; int y_max; int gpio_attb; /* GPIO connected to ATTB line */ + int wakeirq; struct pixcir_i2c_chip_data chip; }; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/2] ARM: dts: AM437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc
Pixcir_i2c_tsc driver can now wakeup the system from lower power state via pinctrl and IO daisy chain using generic wakeirq framwework. Add optional wakeup irq entry to allow pixcir_i2c_tsc to wake system from low power state. Signed-off-by: Vignesh R vigne...@ti.com --- v2: * Add interrupt-names property arch/arm/boot/dts/am437x-gp-evm.dts | 4 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 84aa30c3235a..2184ac5426cd 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -503,6 +503,10 @@ attb-gpio = gpio3 22 GPIO_ACTIVE_HIGH; + interrupts-extended = gpio3 22 GPIO_ACTIVE_HIGH, + am43xx_pinmux 0x264; + interrupt-names = tscirq, wakeupirq; + touchscreen-size-x = 1024; touchscreen-size-y = 600; }; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/2] pixcir_i2c_ts: Add optional wakeup irq support
On am437x-gp-evm, pixcir_i2c_tsc can wake-up system from low power state via pinctrl and IO daisy chain mechanism. This patch series add support for such optional wake up interrupt to be handled via recently introduced generic wake irq handling framework. Tested on am437x-gp-evm, with some out of tree patches to support suspend/resume on am437x. Vignesh R (2): input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt ARM: dts: AM437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc arch/arm/boot/dts/am437x-gp-evm.dts | 4 drivers/input/touchscreen/pixcir_i2c_ts.c | 17 + include/linux/input/pixcir_ts.h | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
Hi Dmitry, On 7/18/2015 3:21 AM, Dmitry Torokhov wrote: Hi Vignesh, On Fri, Jul 17, 2015 at 12:10:40PM +0530, Vignesh R wrote: On am437x-gp-evm, pixcir touchscreen can wake the system from low power state by generating wake-up interrupt via pinctrl and IO daisy chain. Add support for optional wakeup interrupt source by regsitering to automated wake IRQ framework introduced by commit 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling). This is similar in approach to commit 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Signed-off-by: Vignesh R vigne...@ti.com --- drivers/input/touchscreen/pixcir_i2c_ts.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..f7c602027fbd 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,6 +29,8 @@ #include linux/of.h #include linux/of_gpio.h #include linux/of_device.h +#include linux/of_irq.h +#include linux/pm_wakeirq.h #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -38,6 +40,7 @@ struct pixcir_i2c_ts_data { const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers;/* Max fingers supported in this instance */ +int wakeirq; }; struct pixcir_touch { @@ -564,11 +567,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); device_init_wakeup(client-dev, 1); +/* Register wakeirq, if available */ +tsdata-wakeirq = of_irq_get(dev-of_node, 1); Can we put this in platform data and parse in pixcir_parse_dt() please? Also, why not of_irq_get_byname()? Ok. +if (tsdata-wakeirq) { +error = dev_pm_set_dedicated_wake_irq(dev, + tsdata-wakeirq); +if (error) +dev_dbg(dev, unable to get wakeirq %d\n, +error); +} Shouldn't his actually be: error = tsdata-wakeirq ? dev_pm_set_dedicated_wake_irq(dev, tsdata-wakeirq) : dev_pm_set_wake_irq(dev, client-irq); if (error) { ... } and then we can get rid of enable_irq_wake()/disable_irq_wake() in pixcir_i2c_ts_suspend() and pixcir_i2c_ts_resume(). Yes, I will do this in v2. + return 0; } static int pixcir_i2c_ts_remove(struct i2c_client *client) { +dev_pm_clear_wake_irq(client-dev); device_init_wakeup(client-dev, 0); I wonder if driver core should be responsible for clearing wake irq and also for clearing wakeup flag. AFAICU, wakeup flag is deleted when struct device is deleted, hence, device_init_wakeup() call may not be required in .remove(). But, dev_pm_clear_wake_irq() can be moved to driver core. Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt
On am437x-gp-evm, pixcir touchscreen can wake the system from low power state by generating wake-up interrupt via pinctrl and IO daisy chain. Add support for optional wakeup interrupt source by regsitering to automated wake IRQ framework introduced by commit 4990d4fe327b (PM / Wakeirq: Add automated device wake IRQ handling). This is similar in approach to commit 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Signed-off-by: Vignesh R vigne...@ti.com --- drivers/input/touchscreen/pixcir_i2c_ts.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8f3e243a62bf..f7c602027fbd 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,6 +29,8 @@ #include linux/of.h #include linux/of_gpio.h #include linux/of_device.h +#include linux/of_irq.h +#include linux/pm_wakeirq.h #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -38,6 +40,7 @@ struct pixcir_i2c_ts_data { const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers;/* Max fingers supported in this instance */ + int wakeirq; }; struct pixcir_touch { @@ -564,11 +567,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); device_init_wakeup(client-dev, 1); + /* Register wakeirq, if available */ + tsdata-wakeirq = of_irq_get(dev-of_node, 1); + if (tsdata-wakeirq) { + error = dev_pm_set_dedicated_wake_irq(dev, + tsdata-wakeirq); + if (error) + dev_dbg(dev, unable to get wakeirq %d\n, + error); + } + return 0; } static int pixcir_i2c_ts_remove(struct i2c_client *client) { + dev_pm_clear_wake_irq(client-dev); device_init_wakeup(client-dev, 0); return 0; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] pixcir_i2c_ts: Add optional wakeup irq support
On am437x-gp-evm, pixcir_i2c_tsc can wake-up system from low power state via pinctrl and IO daisy chain mechanism. This patch series add support for such optional wake up interrupt to be handled via recently introduced generic wake irq handling framework. Tested on am437x-gp-evm, with some out of tree patches to support suspend/resume on am437x. Vignesh R (2): input: touchscreen: pixcir_i2c_ts: Add support for optional wakeup interrupt ARM: dts: AM437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc arch/arm/boot/dts/am437x-gp-evm.dts | 3 +++ drivers/input/touchscreen/pixcir_i2c_ts.c | 14 ++ 2 files changed, 17 insertions(+) -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] ARM: dts: am437x-gp-evm: Add wakeup interrupt source for pixcir_i2c_tsc
Pixcir_i2c_tsc driver can now wakeup the system from lower power state via pinctrl and IO daisy chain using generic wakeirq framwework. Add optional wakeup irq entry to allow pixcir_i2c_tsc to wake system from low power state. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/boot/dts/am437x-gp-evm.dts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 84aa30c3235a..04f7667c604e 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -503,6 +503,9 @@ attb-gpio = gpio3 22 GPIO_ACTIVE_HIGH; + interrupts-extended = gpio3 22 GPIO_ACTIVE_HIGH, + am43xx_pinmux 0x264; + touchscreen-size-x = 1024; touchscreen-size-y = 600; }; -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] i2c: busses: i2c-omap: Increase timeout for i2c interrupt
Hi, On 07/10/2015 06:56 PM, Alexander Sverdlin wrote: Hi! On 10/07/15 15:17, ext Vignesh R wrote: I would propose you to throw away spinlocks. Convert threaded IRQ to just one hardirq handler. And continue debugging. You will reduce the load of the system with the above measures, maybe it will not happen any more, maybe you'll figure out that problem is somewhere else. Or this. I am not convinced with moving entire code at hardirq context. I believe its better to keep hardirq as small as possible. How deep is the controller's FIFO? 1 byte? 2 bytes? As per AM57x TRM[1] section 24.1.4.8 max FIFO depth can be 64bytes. [1] http://www.ti.com/lit/ug/spruhz6/spruhz6.pdf -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] i2c: busses: i2c-omap: Increase timeout for i2c interrupt
On 07/10/2015 02:39 PM, Wolfram Sang wrote: 60 s sounds way too much and actually I simply don't believe this is the root cause. If I take a look into the driver, then I see, that I agree, this is just a workaround. Yes, this is a workaround. I thought this is simpler change and can go into -rc while I work on the better fix. As you can see, the other suggestions need quite a significant change to the isr code. the design is not really the best. The whole IRQ handling could be actually performed in hard IRQ handler, without threading overhead. Putting even 2 bytes in the controller FIFO should not be too heavy for the hard IRQ handler. Then these ridiculous spin_lock()s. What is the reason behind? The IRQ is flagged with ONESHOT, so thread and hardirq handler are anyway mutually excluded. But if this thread ever runs longer than it's allowed in IRQ context, then it anyway produces this IRQ latency because it locks spin_lock_irqsave() for the whole time! So the whole point of threaded interrupt is missing. Furthermore, this combination of threaded_irq and struct completion seems bogus to me. If you just want to ensure the irq happened before timeout, you just complete when the irq happened and do the bottom half after the completion returned? This sounds good to me. I will try to implement this option. Thanks for the suggestion. I would propose you to throw away spinlocks. Convert threaded IRQ to just one hardirq handler. And continue debugging. You will reduce the load of the system with the above measures, maybe it will not happen any more, maybe you'll figure out that problem is somewhere else. Or this. I am not convinced with moving entire code at hardirq context. I believe its better to keep hardirq as small as possible. -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH] i2c: busses: i2c-omap: Increase timeout for i2c interrupt
When system is under load and there is an i2c transaction running following warning appears on the console: [ 730.003617] omap_i2c 4807.i2c: controller timed out [ 731.023643] omap_i2c 4807.i2c: controller timed out This is because, the completion() call, which is done in bottom half of the interrupt handler, happens after the timeout period(1s) has elapsed for the wait_for_completion_timeout() in omap_i2c_xfer_msg(). The interrupt is raised within a second but due to system load (or other interrupts), the bottom half does not get scheduled within a second. Hence even though the interrupt has happened within required time frame, due to delayed scheduling of bottom half, spurious timeout errors are reported on the console and i2c controller is reset. i2c timeout is a rare condition, hence increase timeout to 60s in order to avoid reporting false timeout events under load. Signed-off-by: Vignesh R vigne...@ti.com --- I reproduced this while running i2cdump in a loop and reading from flash using dd command. drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d1c22e3fdd14..fa7758f0302c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -50,7 +50,7 @@ #define OMAP_I2C_REV_ON_4430_PLUS 0x5042 /* timeout waiting for the controller to respond */ -#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) +#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(60 * 1000)) /* timeout for pm runtime autosuspend */ #define OMAP_I2C_PM_TIMEOUT1000/* ms */ -- 2.4.5 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/3] omap_hsmmc: Fix card enumeration failure on
On Tuesday 16 June 2015 04:07 PM, Vignesh R wrote: Hi, When using omap_hsmmc driver, if sd-card repeatedly plug unplugged multiple times quickly, card enumeration stops after few iterations. This can be easily reproduced on DRA74X EVM which uses omap_hsmmc driver. This patch series addresses the above problem. The first patch fixes irq handler to report all DTOs to mmc-core. Second patch adds handling for BADA, DEB and CEB interrupts. The last patch introduces driver specific card detect irq handler to cleanup pending requests before card removal. Tested on DRA74X amd DRA72X and AM437X-GP EVMs, by repeated intense plug/unplug iterations. Gentle ping... -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 0/5] Add support for PWMSS on DRA7
On Wednesday 03 June 2015 05:21 PM, Vignesh R wrote: Hi, This patch series adds support for PWMSS on DRA7. The IP is same as that present in AM33XX and AM43XX. The first patch changes clock domain in which PWMSS is present (l4per2_7xx_clkdm) to SW_WKUP. This is because legacy IPs like PWM does'nt support HW_AUTO prorperly. Hence, switch clock domain to SW_WKUP. This is based on the input from the hardware team. The rest of the patches add hwmod and dt entries and enable PWMSS on DRA7 based SoCs. Gentle ping... -- Regards Vignesh -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/3] mmc: host: omap_hsmmc: Add custom card detect irq handler
Hi Andreas, Thanks for testing out these patches. On Sunday 21 June 2015 04:15 AM, Andreas Fenkart wrote: I haven't managed to produce a hang without this patch Reproducing this hang is not straight forward. It takes 40-50 card insertion/removal to see this case (sometimes even 100 tries). see also comments below 2015-06-16 12:37 GMT+02:00 Vignesh R vigne...@ti.com: Usually when there is an error in transfer, DTO/CTO or other error interrupts are raised. But if the card is unplugged in the middle of a data transfer, it is observed that, neither completion(success) or timeout(error) interrupts are raised. Hence, the mmc-core is waiting for-ever for the transfer to complete. This results failure to recognise sd card on the next insertion. The only way to solve this is to introduce code to detect this condition and recover on card insertion (in hsmmc specific cd_irq). Hence, introduce cd_irq and add code to clear mmc_request that is pending from the failed transaction. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/mmc/host/omap_hsmmc.c | 73 ++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index fb4bfefd9250..ec1fff3c0c9c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -221,6 +221,12 @@ struct omap_hsmmc_host { #define HSMMC_WAKE_IRQ_ENABLED (1 2) struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data*pdata; + /* +* flag to determine whether card was removed during data +* transfer +*/ + booltransfer_incomplete; + /* return MMC cover switch state, can be NULL if not supported. * @@ -867,6 +873,26 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req } /* + * Cleanup incomplete card removal sequence. This will make sure the + * next card enumeration is clean. + */ +static void omap_hsmmc_request_clear(struct omap_hsmmc_host *host, +struct mmc_request *mrq) +{ + unsigned long flags; + + spin_lock_irqsave(host-irq_lock, flags); + host-req_in_progress = 0; + host-dma_ch = -1; + spin_unlock_irqrestore(host-irq_lock, flags); + + mmc_request_done(host-mmc, mrq); + if (host-mmc-card) + mmc_card_set_removed(host-mmc-card); + host-mrq = NULL; +} + +/* * Notify the transfer complete to MMC core */ static void @@ -1248,6 +1274,47 @@ static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * irq handler to notify the core about card insertion/removal + */ +static irqreturn_t omap_hsmmc_cd_irq(int irq, void *dev_id) +{ Move this code to 'omap_hsmmc_get_cd' function. Or rather clear any pending transfer upon '.init_card/omap_hsmmc_init_card' I tried using omap_hsmmc_init initially, but here is the problem: card inserted -- cd_irq_isr-- schedule mmc_rescan() --- after some time --- mmc_rescan() -- mmc_sd_alive() -- -- card removed --- mmc_send_status -- mmc_wait_for_req()-- wait_for_completion() ^^^ Here the mmc_rescan thread waits forever because, it doesn't get timeout interrupt for the cmd/req it sent (because card was removed). But calls to omap_hsmmc_card_init or omap_hsmmc_get_cd are in the same mmc_rescan thread. Hence, moving the recovery code to init_card does not help. I guess other hosts also have some housekeeping upon unexpected card removals. So I guess there is some generic code to this problem. Did you check? I did try to find generic code in mmc-core, but couldn't find any. However, I did see some driver specific cleanups related to unexpected card removal in sdhci.c. sdhci handles this in .card_event call back. This does not help in my case as .card_event is also called from mmc_rescan. I think cleanup code (in sdhci driver) for unexpected card removal was introduced when .card_event call was outside mmc_rescan. + struct omap_hsmmc_host *host = mmc_priv(dev_id); + int carddetect = mmc_gpio_get_cd(host-mmc); + struct mmc_request *mrq = host-mrq; + + /* +* If the card was removed in the middle of data transfer last +* time, the TC/CC/timeout interrupt is not raised due to which +* mmc_request is not cleared. Hence, this card insertion will +* still see pending mmc_request. Clear the request to make sure +* that this card enumeration is successful. +*/ + if (!carddetect mrq host-transfer_incomplete) { + omap_hsmmc_disable_irq(host); + dev_info(host-dev, +card removed during transfer last time\n); + hsmmc_command_incomplete(host, -ENOMEDIUM, 1); + omap_hsmmc_request_clear(host, host-mrq
[PATCH 1/3] mmc: host: omap_hsmmc: Fix DTO and DCRC handling
From: Kishon Vijay Abraham I kis...@ti.com DTO/DCRC errors were not being informed to the mmc core since commit ae4bf788ee9b (mmc: omap_hsmmc: consolidate error report handling of HSMMC IRQ). This commit made sure 'end_trans' is never set on DTO/DCRC errors. This is because after this commit 'host-data' is checked after it has been cleared to NULL by omap_hsmmc_dma_cleanup(). Because 'end_trans' is never set, omap_hsmmc_xfer_done() is never invoked making core layer not to be aware of DTO/DCRC errors. Because of this any command invoked after DTO/DCRC error leads to a hang. Fix this by checking for 'host-data' before it is actually cleared. Fixes: ae4bf788ee9b (mmc: omap_hsmmc: consolidate error report handling of HSMMC IRQ) CC: sta...@vger.kernel.org Signed-off-by: Kishon Vijay Abraham I kis...@ti.com Signed-off-by: Vignesh R vigne...@ti.com --- drivers/mmc/host/omap_hsmmc.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9df2b6801f76..d0abdffb0d7c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1062,6 +1062,10 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) if (status (CTO_EN | CCRC_EN)) end_cmd = 1; + if (host-data || host-response_busy) { + end_trans = !end_cmd; + host-response_busy = 0; + } if (status (CTO_EN | DTO_EN)) hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); else if (status (CCRC_EN | DCRC_EN)) @@ -1081,10 +1085,6 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } dev_dbg(mmc_dev(host-mmc), AC12 err: 0x%x\n, ac12); } - if (host-data || host-response_busy) { - end_trans = !end_cmd; - host-response_busy = 0; - } } OMAP_HSMMC_WRITE(host-base, STAT, status); -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/3] omap_hsmmc: Fix card enumeration failure on
Hi, When using omap_hsmmc driver, if sd-card repeatedly plug unplugged multiple times quickly, card enumeration stops after few iterations. This can be easily reproduced on DRA74X EVM which uses omap_hsmmc driver. This patch series addresses the above problem. The first patch fixes irq handler to report all DTOs to mmc-core. Second patch adds handling for BADA, DEB and CEB interrupts. The last patch introduces driver specific card detect irq handler to cleanup pending requests before card removal. Tested on DRA74X amd DRA72X and AM437X-GP EVMs, by repeated intense plug/unplug iterations. Kishon Vijay Abraham I (1): mmc: host: omap_hsmmc: Fix DTO and DCRC handling Vignesh R (2): mmc: host: omap_hsmmc: Handle BADA, DEB and CEB interrupts mmc: host: omap_hsmmc: Add custom card detect irq handler drivers/mmc/host/omap_hsmmc.c | 84 --- 1 file changed, 78 insertions(+), 6 deletions(-) -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/3] mmc: host: omap_hsmmc: Add custom card detect irq handler
Usually when there is an error in transfer, DTO/CTO or other error interrupts are raised. But if the card is unplugged in the middle of a data transfer, it is observed that, neither completion(success) or timeout(error) interrupts are raised. Hence, the mmc-core is waiting for-ever for the transfer to complete. This results failure to recognise sd card on the next insertion. The only way to solve this is to introduce code to detect this condition and recover on card insertion (in hsmmc specific cd_irq). Hence, introduce cd_irq and add code to clear mmc_request that is pending from the failed transaction. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/mmc/host/omap_hsmmc.c | 73 ++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index fb4bfefd9250..ec1fff3c0c9c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -221,6 +221,12 @@ struct omap_hsmmc_host { #define HSMMC_WAKE_IRQ_ENABLED (1 2) struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data*pdata; + /* +* flag to determine whether card was removed during data +* transfer +*/ + booltransfer_incomplete; + /* return MMC cover switch state, can be NULL if not supported. * @@ -867,6 +873,26 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req } /* + * Cleanup incomplete card removal sequence. This will make sure the + * next card enumeration is clean. + */ +static void omap_hsmmc_request_clear(struct omap_hsmmc_host *host, +struct mmc_request *mrq) +{ + unsigned long flags; + + spin_lock_irqsave(host-irq_lock, flags); + host-req_in_progress = 0; + host-dma_ch = -1; + spin_unlock_irqrestore(host-irq_lock, flags); + + mmc_request_done(host-mmc, mrq); + if (host-mmc-card) + mmc_card_set_removed(host-mmc-card); + host-mrq = NULL; +} + +/* * Notify the transfer complete to MMC core */ static void @@ -1248,6 +1274,47 @@ static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * irq handler to notify the core about card insertion/removal + */ +static irqreturn_t omap_hsmmc_cd_irq(int irq, void *dev_id) +{ + struct omap_hsmmc_host *host = mmc_priv(dev_id); + int carddetect = mmc_gpio_get_cd(host-mmc); + struct mmc_request *mrq = host-mrq; + + /* +* If the card was removed in the middle of data transfer last +* time, the TC/CC/timeout interrupt is not raised due to which +* mmc_request is not cleared. Hence, this card insertion will +* still see pending mmc_request. Clear the request to make sure +* that this card enumeration is successful. +*/ + if (!carddetect mrq host-transfer_incomplete) { + omap_hsmmc_disable_irq(host); + dev_info(host-dev, +card removed during transfer last time\n); + hsmmc_command_incomplete(host, -ENOMEDIUM, 1); + omap_hsmmc_request_clear(host, host-mrq); + dev_info(host-dev, recovery done\n); + } + host-transfer_incomplete = false; + + mmc_detect_change(host-mmc, (HZ * 200) / 1000); + + /* +* The current mmc_request is usually null before card removal +* sequence is complete. It may not be null if TC/CC interrupt +* never happens due to removal of card during a data +* transfer. Set a flag to indicate mmc_request was not null +* in order to do cleanup on next card insertion. +*/ + if (carddetect mrq) + host-transfer_incomplete = true; + + return IRQ_HANDLED; +} + static void omap_hsmmc_dma_callback(void *param) { struct omap_hsmmc_host *host = param; @@ -1918,7 +1985,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; - int ret, irq; + int ret, irq, len; const struct of_device_id *match; dma_cap_mask_t mask; unsigned tx_req, rx_req; @@ -1980,6 +2047,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (ret) goto err_gpio; + /* register cd_irq, if cd-gpios property is specified in dt */ + if (of_find_property(host-dev-of_node, cd-gpios, len)) + mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cd_irq); + platform_set_drvdata(pdev, host); if (pdev-dev.of_node) -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/3] mmc: host: omap_hsmmc: Handle BADA, DEB and CEB interrupts
Sometimes BADA, DEB or CEB error interrupts occur when sd card is unplugged during data transfer. These interrupts are currently ignored by the interrupt handler. But, this results in card not being recognised on subsequent insertion. This is because mmcqd is waiting forever for the data transfer(for which error occurred) to complete. Fix this, by reporting BADA, DEB, CEB errors to mmc-core as -EILSEQ, so that the core can do appropriate handling. Signed-off-by: Vignesh R vigne...@ti.com --- drivers/mmc/host/omap_hsmmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d0abdffb0d7c..fb4bfefd9250 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1068,7 +1068,8 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } if (status (CTO_EN | DTO_EN)) hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); - else if (status (CCRC_EN | DCRC_EN)) + else if (status (CCRC_EN | DCRC_EN | DEB_EN | CEB_EN | + BADA_EN)) hsmmc_command_incomplete(host, -EILSEQ, end_cmd); if (status ACE_EN) { -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/5] ARM: OMAP2+: DRA7: Add hwmod entries for PWMSS
Add hwmod entries for the PWMSS on DRA7. Set l4_root_clk_div as the main_clk of PWMSS. It is fixed-factored clock equal to L4PER2_L3_GICLK/2(l3_iclk_div/2). As per AM57x TRM SPRUHZ6[1], October 2014, Section 29.1.3 Table 29-4, clock source to PWMSS is L4PER2_L3_GICLK. But it is actually L4PER2_L3_GICLK/2. The TRM does not show the division by 2. [1] www.ti.com/lit/ug/spruhz6/spruhz6.pdf Signed-off-by: Vignesh R vigne...@ti.com --- v2: * add TRM references. arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 239 ++ 1 file changed, 239 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 0e64c2fac0b5..86a7ac9a3138 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -362,6 +362,149 @@ static struct omap_hwmod dra7xx_dcan2_hwmod = { }, }; +/* pwmss */ +static struct omap_hwmod_class_sysconfig dra7xx_epwmss_sysc = { + .rev_offs = 0x0, + .sysc_offs = 0x4, + .sysc_flags = SYSC_HAS_SIDLEMODE | SYSC_HAS_RESET_STATUS, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART), + .sysc_fields= omap_hwmod_sysc_type2, +}; + +struct omap_hwmod_class dra7xx_epwmss_hwmod_class = { + .name = epwmss, + .sysc = dra7xx_epwmss_sysc, +}; + +static struct omap_hwmod_class dra7xx_ecap_hwmod_class = { + .name = ecap, +}; + +static struct omap_hwmod_class dra7xx_eqep_hwmod_class = { + .name = eqep, +}; + +struct omap_hwmod_class dra7xx_ehrpwm_hwmod_class = { + .name = ehrpwm, +}; + +/* epwmss0 */ +struct omap_hwmod dra7xx_epwmss0_hwmod = { + .name = epwmss0, + .class = dra7xx_epwmss_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = DRA7XX_CM_L4PER2_PWMSS1_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_PWMSS1_CONTEXT_OFFSET, + }, + }, +}; + +/* ecap0 */ +struct omap_hwmod dra7xx_ecap0_hwmod = { + .name = ecap0, + .class = dra7xx_ecap_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* eqep0 */ +struct omap_hwmod dra7xx_eqep0_hwmod = { + .name = eqep0, + .class = dra7xx_eqep_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* ehrpwm0 */ +struct omap_hwmod dra7xx_ehrpwm0_hwmod = { + .name = ehrpwm0, + .class = dra7xx_ehrpwm_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* epwmss1 */ +struct omap_hwmod dra7xx_epwmss1_hwmod = { + .name = epwmss1, + .class = dra7xx_epwmss_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = DRA7XX_CM_L4PER2_PWMSS2_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_PWMSS2_CONTEXT_OFFSET, + }, + }, +}; + +/* ecap1 */ +struct omap_hwmod dra7xx_ecap1_hwmod = { + .name = ecap1, + .class = dra7xx_ecap_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* eqep1 */ +struct omap_hwmod dra7xx_eqep1_hwmod = { + .name = eqep1, + .class = dra7xx_eqep_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* ehrpwm1 */ +struct omap_hwmod dra7xx_ehrpwm1_hwmod = { + .name = ehrpwm1, + .class = dra7xx_ehrpwm_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* epwmss2 */ +struct omap_hwmod dra7xx_epwmss2_hwmod = { + .name = epwmss2, + .class = dra7xx_epwmss_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, + .prcm = { + .omap4 = { + .modulemode = MODULEMODE_SWCTRL, + .clkctrl_offs = DRA7XX_CM_L4PER2_PWMSS3_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_PWMSS3_CONTEXT_OFFSET, + }, + }, +}; + +/* ecap2 */ +struct omap_hwmod dra7xx_ecap2_hwmod = { + .name = ecap2, + .class = dra7xx_ecap_hwmod_class, + .clkdm_name = l4per2_clkdm, + .main_clk = l4_root_clk_div, +}; + +/* eqep2 */ +struct omap_hwmod dra7xx_eqep2_hwmod = { + .name
[PATCH v2 1/5] ARM: OMAP2+: DRA7: clockdomain: change l4per2_7xx_clkdm to SW_WKUP
Legacy IPs like PWMSS, present under l4per2_7xx_clkdm, cannot support smart-idle when its clock domain is in HW_AUTO on DRA7 SoCs. Hence, program clock domain to SW_WKUP. Signed-off-by: Vignesh R vigne...@ti.com --- arch/arm/mach-omap2/clockdomains7xx_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c index 57d5df0c1fbd..7581e036bda6 100644 --- a/arch/arm/mach-omap2/clockdomains7xx_data.c +++ b/arch/arm/mach-omap2/clockdomains7xx_data.c @@ -331,7 +331,7 @@ static struct clockdomain l4per2_7xx_clkdm = { .dep_bit = DRA7XX_L4PER2_STATDEP_SHIFT, .wkdep_srcs = l4per2_wkup_sleep_deps, .sleepdep_srcs= l4per2_wkup_sleep_deps, - .flags= CLKDM_CAN_HWSUP_SWSUP, + .flags= CLKDM_CAN_SWSUP, }; static struct clockdomain mpu0_7xx_clkdm = { -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 0/5] Add support for PWMSS on DRA7
Hi, This patch series adds support for PWMSS on DRA7. The IP is same as that present in AM33XX and AM43XX. The first patch changes clock domain in which PWMSS is present (l4per2_7xx_clkdm) to SW_WKUP. This is because legacy IPs like PWM does'nt support HW_AUTO prorperly. Hence, switch clock domain to SW_WKUP. This is based on the input from the hardware team. The rest of the patches add hwmod and dt entries and enable PWMSS on DRA7 based SoCs. Vignesh R (5): ARM: OMAP2+: DRA7: clockdomain: change l4per2_7xx_clkdm to SW_WKUP ARM: OMAP2+: DRA7: Add hwmod entries for PWMSS ARM: dts: DRA7: Add TBCLK for PWMSS clk: ti: DRA7: Add tbclk data for ehrpwm ARM: dts: DRA7: Add dt nodes for PWMSS .../devicetree/bindings/pwm/pwm-tiehrpwm.txt | 8 + .../devicetree/bindings/pwm/pwm-tipwmss.txt| 17 +- arch/arm/boot/dts/dra7.dtsi| 69 ++ arch/arm/boot/dts/dra7xx-clocks.dtsi | 26 +++ arch/arm/mach-omap2/clockdomains7xx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 239 +++ drivers/clk/ti/clk-7xx.c | 3 + 7 files changed, 362 insertions(+), 2 deletions(-) -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 3/5] ARM: dts: DRA7: Add TBCLK for PWMSS
tbclk is used by ehrpwm to generate PWM waveform on DRA7 SoC. Add Linux clock to control ehrpwm tbclk. The TRM says, tbclk is derived from SYSCLKOUT. SYSCLKOUT is nothing but ehrpwm functional clock derived from the gateable interface and functional clock of PWMSS(l4_root_clk_div). Refer AM57x TRM SPRUHZ6[1], October 2014, Table 29-4 and Section 29.2.2.1, Table 29-19 and the NOTE at the end of the table. [1] www.ti.com/lit/ug/spruhz6/spruhz6.pdf Signed-off-by: Vignesh R vigne...@ti.com --- v2: * add TRM references. arch/arm/boot/dts/dra7.dtsi | 5 + arch/arm/boot/dts/dra7xx-clocks.dtsi | 26 ++ 2 files changed, 31 insertions(+) diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index f03a091cd076..387c76ca41f9 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -131,6 +131,11 @@ regulator-max-microvolt = 300; }; }; + + scm_conf_clocks: clocks { + #address-cells = 1; + #size-cells = 0; + }; }; dra7_pmx_core: pinmux@1400 { diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi index 3b933f74d000..92452d61cf58 100644 --- a/arch/arm/boot/dts/dra7xx-clocks.dtsi +++ b/arch/arm/boot/dts/dra7xx-clocks.dtsi @@ -2136,3 +2136,29 @@ clocks = dpll_usb_ck; }; }; + +scm_conf_clocks { + ehrpwm0_tbclk: ehrpwm0_tbclk { + #clock-cells = 0; + compatible = ti,gate-clock; + clocks = l4_root_clk_div; + ti,bit-shift = 20; + reg = 0x0558; + }; + + ehrpwm1_tbclk: ehrpwm1_tbclk { + #clock-cells = 0; + compatible = ti,gate-clock; + clocks = l4_root_clk_div; + ti,bit-shift = 21; + reg = 0x0558; + }; + + ehrpwm2_tbclk: ehrpwm2_tbclk { + #clock-cells = 0; + compatible = ti,gate-clock; + clocks = l4_root_clk_div; + ti,bit-shift = 22; + reg = 0x0558; + }; +}; -- 2.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-omap in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html