mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'spi-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown: "This is quite a quiet release for SPI, there's been a bit of cleanup to the core from Uwe but nothing functionality wise. We have added several new drivers, Cadence XSPI, Ingenic JZ47xx, Qualcomm SC7280 and SC7180 and Xilinx Versal OSPI" * tag 'spi-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (41 commits) spi: Convert NXP flexspi to json schema spi: spi-geni-qcom: Add support for GPI dma spi: fsi: Fix contention in the FSI2SPI engine spi: spi-rpc-if: Check return value of rpcif_sw_init() spi: tegra210-quad: Put device into suspend on driver removal spi: tegra20-slink: Put device into suspend on driver removal spi: bcm-qspi: Fix missing clk_disable_unprepare() on error in bcm_qspi_probe() spi: at91-usart: replacing legacy gpio interface for gpiod spi: replace snprintf in show functions with sysfs_emit spi: cadence: Add of_node_put() before return spi: orion: Add of_node_put() before goto spi: cadence-quadspi: fix dma_unmap_single() call spi: tegra20: fix build with CONFIG_PM_SLEEP=n spi: bcm-qspi: add support for 3-wire mode for half duplex transfer spi: bcm-qspi: Add mspi spcr3 32/64-bits xfer mode spi: Make several public functions private to spi.c spi: Reorder functions to simplify the next commit spi: Remove unused function spi_busnum_to_master() spi: Move comment about chipselect check to the right place spi: fsi: Print status on error ...
This commit is contained in:
@@ -11,6 +11,14 @@ maintainers:
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: xlnx,versal-ospi-1.0
|
||||
then:
|
||||
required:
|
||||
- power-domains
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -20,6 +28,7 @@ properties:
|
||||
- ti,k2g-qspi
|
||||
- ti,am654-ospi
|
||||
- intel,lgm-qspi
|
||||
- xlnx,versal-ospi-1.0
|
||||
- const: cdns,qspi-nor
|
||||
- const: cdns,qspi-nor
|
||||
|
||||
@@ -65,6 +74,9 @@ properties:
|
||||
data rather than the QSPI clock. Make sure that QSPI return clock
|
||||
is populated on the board before using this property.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
|
||||
77
Documentation/devicetree/bindings/spi/cdns,xspi.yaml
Normal file
77
Documentation/devicetree/bindings/spi/cdns,xspi.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2020-21 Cadence
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/cdns,xspi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Cadence XSPI Controller
|
||||
|
||||
maintainers:
|
||||
- Parshuram Thombare <pthombar@cadence.com>
|
||||
|
||||
description: |
|
||||
The XSPI controller allows SPI protocol communication in
|
||||
single, dual, quad or octal wire transmission modes for
|
||||
read/write access to slaves such as SPI-NOR flash.
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: cdns,xspi-nor
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: address and length of the controller register set
|
||||
- description: address and length of the Slave DMA data port
|
||||
- description: address and length of the auxiliary registers
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: io
|
||||
- const: sdma
|
||||
- const: aux
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
bus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
xspi: spi@a0010000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "cdns,xspi-nor";
|
||||
reg = <0x0 0xa0010000 0x0 0x1040>,
|
||||
<0x0 0xb0000000 0x0 0x1000>,
|
||||
<0x0 0xa0020000 0x0 0x100>;
|
||||
reg-names = "io", "sdma", "aux";
|
||||
interrupts = <0 90 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-parent = <&gic>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <75000000>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
flash@1 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <75000000>;
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
72
Documentation/devicetree/bindings/spi/ingenic,spi.yaml
Normal file
72
Documentation/devicetree/bindings/spi/ingenic,spi.yaml
Normal file
@@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/ingenic,spi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Ingenic SoCs SPI controller devicetree bindings
|
||||
|
||||
maintainers:
|
||||
- Artur Rojek <contact@artur-rojek.eu>
|
||||
- Paul Cercueil <paul@crapouillou.net>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- ingenic,jz4750-spi
|
||||
- ingenic,jz4780-spi
|
||||
- items:
|
||||
- enum:
|
||||
- ingenic,jz4760-spi
|
||||
- ingenic,jz4770-spi
|
||||
- const: ingenic,jz4750-spi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 2
|
||||
minItems: 2
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- dmas
|
||||
- dma-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/jz4770-cgu.h>
|
||||
spi@10043000 {
|
||||
compatible = "ingenic,jz4770-spi", "ingenic,jz4750-spi";
|
||||
reg = <0x10043000 0x1c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <8>;
|
||||
|
||||
clocks = <&cgu JZ4770_CLK_SSI0>;
|
||||
|
||||
dmas = <&dmac1 23 0xffffffff>, <&dmac1 22 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
@@ -21,7 +21,11 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: qcom,sdm845-qspi
|
||||
- enum:
|
||||
- qcom,sc7180-qspi
|
||||
- qcom,sc7280-qspi
|
||||
- qcom,sdm845-qspi
|
||||
|
||||
- const: qcom,qspi-v1
|
||||
|
||||
reg:
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
* NXP Flex Serial Peripheral Interface (FSPI)
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "nxp,lx2160a-fspi"
|
||||
"nxp,imx8qxp-fspi"
|
||||
"nxp,imx8mm-fspi"
|
||||
"nxp,imx8mp-fspi"
|
||||
"nxp,imx8dxl-fspi"
|
||||
|
||||
- reg : First contains the register location and length,
|
||||
Second contains the memory mapping address and length
|
||||
- reg-names : Should contain the resource reg names:
|
||||
- fspi_base: configuration register address space
|
||||
- fspi_mmap: memory mapped address space
|
||||
- interrupts : Should contain the interrupt for the device
|
||||
|
||||
Required SPI slave node properties:
|
||||
- reg : There are two buses (A and B) with two chip selects each.
|
||||
This encodes to which bus and CS the flash is connected:
|
||||
- <0>: Bus A, CS 0
|
||||
- <1>: Bus A, CS 1
|
||||
- <2>: Bus B, CS 0
|
||||
- <3>: Bus B, CS 1
|
||||
|
||||
Example showing the usage of two SPI NOR slave devices on bus A:
|
||||
|
||||
fspi0: spi@20c0000 {
|
||||
compatible = "nxp,lx2160a-fspi";
|
||||
reg = <0x0 0x20c0000 0x0 0x10000>, <0x0 0x20000000 0x0 0x10000000>;
|
||||
reg-names = "fspi_base", "fspi_mmap";
|
||||
interrupts = <0 25 0x4>; /* Level high type */
|
||||
clocks = <&clockgen 4 3>, <&clockgen 4 3>;
|
||||
clock-names = "fspi_en", "fspi";
|
||||
|
||||
mt35xu512aba0: flash@0 {
|
||||
reg = <0>;
|
||||
....
|
||||
};
|
||||
|
||||
mt35xu512aba1: flash@1 {
|
||||
reg = <1>;
|
||||
....
|
||||
};
|
||||
};
|
||||
86
Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml
Normal file
86
Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml
Normal file
@@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-nxp-fspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP Flex Serial Peripheral Interface (FSPI)
|
||||
|
||||
maintainers:
|
||||
- Kuldeep Singh <kuldeep.singh@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,imx8dxl-fspi
|
||||
- nxp,imx8mm-fspi
|
||||
- nxp,imx8mp-fspi
|
||||
- nxp,imx8qxp-fspi
|
||||
- nxp,lx2160a-fspi
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: registers address space
|
||||
- description: memory mapped address space
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: fspi_base
|
||||
- const: fspi_mmap
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: SPI bus clock
|
||||
- description: SPI serial clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: fspi_en
|
||||
- const: fspi
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
spi@20c0000 {
|
||||
compatible = "nxp,lx2160a-fspi";
|
||||
reg = <0x0 0x20c0000 0x0 0x100000>,
|
||||
<0x0 0x20000000 0x0 0x10000000>;
|
||||
reg-names = "fspi_base", "fspi_mmap";
|
||||
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(4)>,
|
||||
<&clockgen QORIQ_CLK_PLATFORM_PLL QORIQ_CLK_PLL_DIV(4)>;
|
||||
clock-names = "fspi_en", "fspi";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
reg = <0>;
|
||||
spi-rx-bus-width = <8>;
|
||||
spi-tx-bus-width = <8>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -336,14 +336,6 @@ certainly includes SPI devices hooked up through the card connectors!
|
||||
Non-static Configurations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Developer boards often play by different rules than product boards, and one
|
||||
example is the potential need to hotplug SPI devices and/or controllers.
|
||||
|
||||
For those cases you might need to use spi_busnum_to_master() to look
|
||||
up the spi bus master, and will likely need spi_new_device() to provide the
|
||||
board info based on the board that was hotplugged. Of course, you'd later
|
||||
call at least spi_unregister_device() when that board is removed.
|
||||
|
||||
When Linux includes support for MMC/SD/SDIO/DataFlash cards through SPI, those
|
||||
configurations will also be dynamic. Fortunately, such devices all support
|
||||
basic device identification probes, so they should hotplug normally.
|
||||
|
||||
@@ -13488,7 +13488,7 @@ M: Ashish Kumar <ashish.kumar@nxp.com>
|
||||
R: Yogesh Gaur <yogeshgaur.83@gmail.com>
|
||||
L: linux-spi@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
|
||||
F: Documentation/devicetree/bindings/spi/spi-nxp-fspi.yaml
|
||||
F: drivers/spi/spi-nxp-fspi.c
|
||||
|
||||
NXP FXAS21002C DRIVER
|
||||
|
||||
@@ -113,9 +113,12 @@
|
||||
* Use the 32.768 kHz oscillator as the parent of the RTC for a higher
|
||||
* precision.
|
||||
*/
|
||||
assigned-clocks = <&cgu JZ4780_CLK_OTGPHY>, <&cgu JZ4780_CLK_RTC>;
|
||||
assigned-clock-parents = <0>, <&cgu JZ4780_CLK_RTCLK>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
assigned-clocks = <&cgu JZ4780_CLK_OTGPHY>, <&cgu JZ4780_CLK_RTC>,
|
||||
<&cgu JZ4780_CLK_SSIPLL>, <&cgu JZ4780_CLK_SSI>;
|
||||
assigned-clock-parents = <0>, <&cgu JZ4780_CLK_RTCLK>,
|
||||
<&cgu JZ4780_CLK_MPLL>,
|
||||
<&cgu JZ4780_CLK_SSIPLL>;
|
||||
assigned-clock-rates = <48000000>, <0>, <54000000>;
|
||||
};
|
||||
|
||||
&tcu {
|
||||
|
||||
@@ -255,22 +255,23 @@
|
||||
};
|
||||
};
|
||||
|
||||
spi_gpio {
|
||||
compatible = "spi-gpio";
|
||||
spi0: spi@10043000 {
|
||||
compatible = "ingenic,jz4780-spi";
|
||||
reg = <0x10043000 0x1c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
num-chipselects = <2>;
|
||||
|
||||
gpio-miso = <&gpe 14 0>;
|
||||
gpio-sck = <&gpe 15 0>;
|
||||
gpio-mosi = <&gpe 17 0>;
|
||||
cs-gpios = <&gpe 16 0>, <&gpe 18 0>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <8>;
|
||||
|
||||
spidev@0 {
|
||||
compatible = "spidev";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
||||
clocks = <&cgu JZ4780_CLK_SSI0>;
|
||||
clock-names = "spi";
|
||||
|
||||
dmas = <&dma JZ4780_DMA_SSI0_RX 0xffffffff>,
|
||||
<&dma JZ4780_DMA_SSI0_TX 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart0: serial@10030000 {
|
||||
@@ -338,6 +339,25 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi1: spi@10044000 {
|
||||
compatible = "ingenic,jz4780-spi";
|
||||
reg = <0x10044000 0x1c>;
|
||||
#address-cells = <1>;
|
||||
#size-sells = <0>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <7>;
|
||||
|
||||
clocks = <&cgu JZ4780_CLK_SSI1>;
|
||||
clock-names = "spi";
|
||||
|
||||
dmas = <&dma JZ4780_DMA_SSI1_RX 0xffffffff>,
|
||||
<&dma JZ4780_DMA_SSI1_TX 0xffffffff>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2c0: i2c@10050000 {
|
||||
compatible = "ingenic,jz4780-i2c", "ingenic,jz4770-i2c";
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -647,6 +647,23 @@ int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_ospi_mux_select() - OSPI Mux selection
|
||||
*
|
||||
* @dev_id: Device Id of the OSPI device.
|
||||
* @select: OSPI Mux select value.
|
||||
*
|
||||
* This function select the OSPI Mux.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_IOCTL, dev_id, IOCTL_OSPI_MUX_SELECT,
|
||||
select, 0, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);
|
||||
|
||||
/**
|
||||
* zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)
|
||||
* @index: GGS register index
|
||||
|
||||
@@ -228,6 +228,18 @@ config SPI_CADENCE_QUADSPI
|
||||
device with a Cadence QSPI controller and want to access the
|
||||
Flash as an MTD device.
|
||||
|
||||
config SPI_CADENCE_XSPI
|
||||
tristate "Cadence XSPI controller"
|
||||
depends on (OF || COMPILE_TEST) && HAS_IOMEM
|
||||
depends on SPI_MEM
|
||||
help
|
||||
Enable support for the Cadence XSPI Flash controller.
|
||||
|
||||
Cadence XSPI is a specialized controller for connecting an SPI
|
||||
Flash over upto 8bit wide bus. Enable this option if you have a
|
||||
device with a Cadence XSPI controller and want to access the
|
||||
Flash as an MTD device.
|
||||
|
||||
config SPI_CLPS711X
|
||||
tristate "CLPS711X host SPI controller"
|
||||
depends on ARCH_CLPS711X || COMPILE_TEST
|
||||
@@ -406,6 +418,15 @@ config SPI_IMX
|
||||
help
|
||||
This enables support for the Freescale i.MX SPI controllers.
|
||||
|
||||
config SPI_INGENIC
|
||||
tristate "Ingenic JZ47xx SoCs SPI controller"
|
||||
depends on MACH_INGENIC || COMPILE_TEST
|
||||
help
|
||||
This enables support for the Ingenic JZ47xx SoCs SPI controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called spi-ingenic.
|
||||
|
||||
config SPI_JCORE
|
||||
tristate "J-Core SPI Master"
|
||||
depends on OF && (SUPERH || COMPILE_TEST)
|
||||
@@ -738,10 +759,11 @@ config SPI_S3C24XX_FIQ
|
||||
TX and RX data paths.
|
||||
|
||||
config SPI_S3C64XX
|
||||
tristate "Samsung S3C64XX series type SPI"
|
||||
tristate "Samsung S3C64XX/Exynos SoC series type SPI"
|
||||
depends on (PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST)
|
||||
help
|
||||
SPI driver for Samsung S3C64XX and newer SoCs.
|
||||
SPI driver for Samsung S3C64XX, S5Pv210 and Exynos SoCs.
|
||||
Choose Y/M here only if you build for such Samsung SoC.
|
||||
|
||||
config SPI_SC18IS602
|
||||
tristate "NXP SC18IS602/602B/603 I2C to SPI bridge"
|
||||
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
|
||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
|
||||
obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
|
||||
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
|
||||
obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o
|
||||
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
|
||||
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
|
||||
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
|
||||
@@ -59,6 +60,7 @@ obj-$(CONFIG_SPI_HISI_KUNPENG) += spi-hisi-kunpeng.o
|
||||
obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o
|
||||
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
|
||||
obj-$(CONFIG_SPI_IMX) += spi-imx.o
|
||||
obj-$(CONFIG_SPI_INGENIC) += spi-ingenic.o
|
||||
obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o
|
||||
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
|
||||
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
|
||||
|
||||
@@ -310,7 +310,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
||||
return mode;
|
||||
ifr |= atmel_qspi_modes[mode].config;
|
||||
|
||||
if (op->dummy.buswidth && op->dummy.nbytes)
|
||||
if (op->dummy.nbytes)
|
||||
dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
|
||||
|
||||
/*
|
||||
|
||||
@@ -38,126 +38,102 @@ struct amd_spi {
|
||||
void __iomem *io_remap_addr;
|
||||
unsigned long io_base_addr;
|
||||
u32 rom_addr;
|
||||
u8 chip_select;
|
||||
};
|
||||
|
||||
static inline u8 amd_spi_readreg8(struct spi_master *master, int idx)
|
||||
static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
|
||||
return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx);
|
||||
}
|
||||
|
||||
static inline void amd_spi_writereg8(struct spi_master *master, int idx,
|
||||
u8 val)
|
||||
static inline void amd_spi_writereg8(struct amd_spi *amd_spi, int idx, u8 val)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
|
||||
iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
|
||||
}
|
||||
|
||||
static inline void amd_spi_setclear_reg8(struct spi_master *master, int idx,
|
||||
u8 set, u8 clear)
|
||||
static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 clear)
|
||||
{
|
||||
u8 tmp = amd_spi_readreg8(master, idx);
|
||||
u8 tmp = amd_spi_readreg8(amd_spi, idx);
|
||||
|
||||
tmp = (tmp & ~clear) | set;
|
||||
amd_spi_writereg8(master, idx, tmp);
|
||||
amd_spi_writereg8(amd_spi, idx, tmp);
|
||||
}
|
||||
|
||||
static inline u32 amd_spi_readreg32(struct spi_master *master, int idx)
|
||||
static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
|
||||
return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx);
|
||||
}
|
||||
|
||||
static inline void amd_spi_writereg32(struct spi_master *master, int idx,
|
||||
u32 val)
|
||||
static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
|
||||
iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
|
||||
}
|
||||
|
||||
static inline void amd_spi_setclear_reg32(struct spi_master *master, int idx,
|
||||
u32 set, u32 clear)
|
||||
static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear)
|
||||
{
|
||||
u32 tmp = amd_spi_readreg32(master, idx);
|
||||
u32 tmp = amd_spi_readreg32(amd_spi, idx);
|
||||
|
||||
tmp = (tmp & ~clear) | set;
|
||||
amd_spi_writereg32(master, idx, tmp);
|
||||
amd_spi_writereg32(amd_spi, idx, tmp);
|
||||
}
|
||||
|
||||
static void amd_spi_select_chip(struct spi_master *master)
|
||||
static void amd_spi_select_chip(struct amd_spi *amd_spi, u8 cs)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
u8 chip_select = amd_spi->chip_select;
|
||||
|
||||
amd_spi_setclear_reg8(master, AMD_SPI_ALT_CS_REG, chip_select,
|
||||
AMD_SPI_ALT_CS_MASK);
|
||||
amd_spi_setclear_reg8(amd_spi, AMD_SPI_ALT_CS_REG, cs, AMD_SPI_ALT_CS_MASK);
|
||||
}
|
||||
|
||||
static void amd_spi_clear_fifo_ptr(struct spi_master *master)
|
||||
static void amd_spi_clear_fifo_ptr(struct amd_spi *amd_spi)
|
||||
{
|
||||
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_FIFO_CLEAR,
|
||||
AMD_SPI_FIFO_CLEAR);
|
||||
amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, AMD_SPI_FIFO_CLEAR, AMD_SPI_FIFO_CLEAR);
|
||||
}
|
||||
|
||||
static void amd_spi_set_opcode(struct spi_master *master, u8 cmd_opcode)
|
||||
static void amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode)
|
||||
{
|
||||
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, cmd_opcode,
|
||||
AMD_SPI_OPCODE_MASK);
|
||||
amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, cmd_opcode, AMD_SPI_OPCODE_MASK);
|
||||
}
|
||||
|
||||
static inline void amd_spi_set_rx_count(struct spi_master *master,
|
||||
u8 rx_count)
|
||||
static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count)
|
||||
{
|
||||
amd_spi_setclear_reg8(master, AMD_SPI_RX_COUNT_REG, rx_count, 0xff);
|
||||
amd_spi_setclear_reg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count, 0xff);
|
||||
}
|
||||
|
||||
static inline void amd_spi_set_tx_count(struct spi_master *master,
|
||||
u8 tx_count)
|
||||
static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count)
|
||||
{
|
||||
amd_spi_setclear_reg8(master, AMD_SPI_TX_COUNT_REG, tx_count, 0xff);
|
||||
amd_spi_setclear_reg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count, 0xff);
|
||||
}
|
||||
|
||||
static inline int amd_spi_busy_wait(struct amd_spi *amd_spi)
|
||||
static int amd_spi_busy_wait(struct amd_spi *amd_spi)
|
||||
{
|
||||
bool spi_busy;
|
||||
int timeout = 100000;
|
||||
|
||||
/* poll for SPI bus to become idle */
|
||||
spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr +
|
||||
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
|
||||
while (spi_busy) {
|
||||
while (amd_spi_readreg32(amd_spi, AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) {
|
||||
usleep_range(10, 20);
|
||||
if (timeout-- < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr +
|
||||
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_spi_execute_opcode(struct spi_master *master)
|
||||
static int amd_spi_execute_opcode(struct amd_spi *amd_spi)
|
||||
{
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = amd_spi_busy_wait(amd_spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set ExecuteOpCode bit in the CTRL0 register */
|
||||
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD,
|
||||
AMD_SPI_EXEC_CMD);
|
||||
amd_spi_setclear_reg32(amd_spi, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD, AMD_SPI_EXEC_CMD);
|
||||
|
||||
amd_spi_busy_wait(amd_spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_spi_master_setup(struct spi_device *spi)
|
||||
{
|
||||
struct spi_master *master = spi->master;
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(spi->master);
|
||||
|
||||
amd_spi_clear_fifo_ptr(master);
|
||||
amd_spi_clear_fifo_ptr(amd_spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -185,19 +161,18 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
|
||||
tx_len = xfer->len - 1;
|
||||
cmd_opcode = *(u8 *)xfer->tx_buf;
|
||||
buf++;
|
||||
amd_spi_set_opcode(master, cmd_opcode);
|
||||
amd_spi_set_opcode(amd_spi, cmd_opcode);
|
||||
|
||||
/* Write data into the FIFO. */
|
||||
for (i = 0; i < tx_len; i++) {
|
||||
iowrite8(buf[i],
|
||||
((u8 __iomem *)amd_spi->io_remap_addr +
|
||||
iowrite8(buf[i], ((u8 __iomem *)amd_spi->io_remap_addr +
|
||||
AMD_SPI_FIFO_BASE + i));
|
||||
}
|
||||
|
||||
amd_spi_set_tx_count(master, tx_len);
|
||||
amd_spi_clear_fifo_ptr(master);
|
||||
amd_spi_set_tx_count(amd_spi, tx_len);
|
||||
amd_spi_clear_fifo_ptr(amd_spi);
|
||||
/* Execute command */
|
||||
amd_spi_execute_opcode(master);
|
||||
amd_spi_execute_opcode(amd_spi);
|
||||
}
|
||||
if (m_cmd & AMD_SPI_XFER_RX) {
|
||||
/*
|
||||
@@ -206,15 +181,14 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
|
||||
*/
|
||||
rx_len = xfer->len;
|
||||
buf = (u8 *)xfer->rx_buf;
|
||||
amd_spi_set_rx_count(master, rx_len);
|
||||
amd_spi_clear_fifo_ptr(master);
|
||||
amd_spi_set_rx_count(amd_spi, rx_len);
|
||||
amd_spi_clear_fifo_ptr(amd_spi);
|
||||
/* Execute command */
|
||||
amd_spi_execute_opcode(master);
|
||||
amd_spi_execute_opcode(amd_spi);
|
||||
amd_spi_busy_wait(amd_spi);
|
||||
/* Read data from FIFO to receive buffer */
|
||||
for (i = 0; i < rx_len; i++)
|
||||
buf[i] = amd_spi_readreg8(master,
|
||||
AMD_SPI_FIFO_BASE +
|
||||
tx_len + i);
|
||||
buf[i] = amd_spi_readreg8(amd_spi, AMD_SPI_FIFO_BASE + tx_len + i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,8 +207,7 @@ static int amd_spi_master_transfer(struct spi_master *master,
|
||||
struct amd_spi *amd_spi = spi_master_get_devdata(master);
|
||||
struct spi_device *spi = msg->spi;
|
||||
|
||||
amd_spi->chip_select = spi->chip_select;
|
||||
amd_spi_select_chip(master);
|
||||
amd_spi_select_chip(amd_spi, spi->chip_select);
|
||||
|
||||
/*
|
||||
* Extract spi_transfers from the spi message and
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -482,29 +482,12 @@ static void at91_usart_spi_init(struct at91_usart_spi *aus)
|
||||
|
||||
static int at91_usart_gpio_setup(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
int i;
|
||||
int ret;
|
||||
int nb;
|
||||
struct gpio_descs *cs_gpios;
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
cs_gpios = devm_gpiod_get_array_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
|
||||
|
||||
nb = of_gpio_named_count(np, "cs-gpios");
|
||||
for (i = 0; i < nb; i++) {
|
||||
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
|
||||
|
||||
if (cs_gpio < 0)
|
||||
return cs_gpio;
|
||||
|
||||
if (gpio_is_valid(cs_gpio)) {
|
||||
ret = devm_gpio_request_one(&pdev->dev, cs_gpio,
|
||||
GPIOF_DIR_OUT,
|
||||
dev_name(&pdev->dev));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (IS_ERR(cs_gpios))
|
||||
return PTR_ERR(cs_gpios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@
|
||||
/* MSPI register offsets */
|
||||
#define MSPI_SPCR0_LSB 0x000
|
||||
#define MSPI_SPCR0_MSB 0x004
|
||||
#define MSPI_SPCR0_MSB_CPHA BIT(0)
|
||||
#define MSPI_SPCR0_MSB_CPOL BIT(1)
|
||||
#define MSPI_SPCR0_MSB_BITS_SHIFT 0x2
|
||||
#define MSPI_SPCR1_LSB 0x008
|
||||
#define MSPI_SPCR1_MSB 0x00c
|
||||
#define MSPI_NEWQP 0x010
|
||||
@@ -100,8 +103,10 @@
|
||||
#define MSPI_MASTER_BIT BIT(7)
|
||||
|
||||
#define MSPI_NUM_CDRAM 16
|
||||
#define MSPI_CDRAM_OUTP BIT(8)
|
||||
#define MSPI_CDRAM_CONT_BIT BIT(7)
|
||||
#define MSPI_CDRAM_BITSE_BIT BIT(6)
|
||||
#define MSPI_CDRAM_DT_BIT BIT(5)
|
||||
#define MSPI_CDRAM_PCS 0xf
|
||||
|
||||
#define MSPI_SPCR2_SPE BIT(6)
|
||||
@@ -114,6 +119,14 @@
|
||||
~(BIT(10) | BIT(11)))
|
||||
#define MSPI_SPCR3_SYSCLKSEL_108 (MSPI_SPCR3_SYSCLKSEL_MASK & \
|
||||
BIT(11))
|
||||
#define MSPI_SPCR3_TXRXDAM_MASK GENMASK(4, 2)
|
||||
#define MSPI_SPCR3_DAM_8BYTE 0
|
||||
#define MSPI_SPCR3_DAM_16BYTE (BIT(2) | BIT(4))
|
||||
#define MSPI_SPCR3_DAM_32BYTE (BIT(3) | BIT(5))
|
||||
#define MSPI_SPCR3_HALFDUPLEX BIT(6)
|
||||
#define MSPI_SPCR3_HDOUTTYPE BIT(7)
|
||||
#define MSPI_SPCR3_DATA_REG_SZ BIT(8)
|
||||
#define MSPI_SPCR3_CPHARX BIT(9)
|
||||
|
||||
#define MSPI_MSPI_STATUS_SPIF BIT(0)
|
||||
|
||||
@@ -153,6 +166,14 @@
|
||||
#define TRANS_STATUS_BREAK_DESELECT (TRANS_STATUS_BREAK_EOM | \
|
||||
TRANS_STATUS_BREAK_CS_CHANGE)
|
||||
|
||||
/*
|
||||
* Used for writing and reading data in the right order
|
||||
* to TXRAM and RXRAM when used as 32-bit registers respectively
|
||||
*/
|
||||
#define swap4bytes(__val) \
|
||||
((((__val) >> 24) & 0x000000FF) | (((__val) >> 8) & 0x0000FF00) | \
|
||||
(((__val) << 8) & 0x00FF0000) | (((__val) << 24) & 0xFF000000))
|
||||
|
||||
struct bcm_qspi_parms {
|
||||
u32 speed_hz;
|
||||
u8 mode;
|
||||
@@ -261,7 +282,7 @@ static inline bool bcm_qspi_has_sysclk_108(struct bcm_qspi *qspi)
|
||||
static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
|
||||
{
|
||||
if (bcm_qspi_has_fastbr(qspi))
|
||||
return 1;
|
||||
return (bcm_qspi_has_sysclk_108(qspi) ? 4 : 1);
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
@@ -395,7 +416,8 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
|
||||
if (addrlen == BSPI_ADDRLEN_4BYTES)
|
||||
bpp = BSPI_BPP_ADDR_SELECT_MASK;
|
||||
|
||||
bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
|
||||
if (op->dummy.nbytes)
|
||||
bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
|
||||
|
||||
switch (width) {
|
||||
case SPI_NBITS_SINGLE:
|
||||
@@ -570,23 +592,23 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||
{
|
||||
u32 spcr, spbr = 0;
|
||||
|
||||
if (xp->speed_hz)
|
||||
spbr = qspi->base_clk / (2 * xp->speed_hz);
|
||||
|
||||
spcr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spcr);
|
||||
|
||||
if (!qspi->mspi_maj_rev)
|
||||
/* legacy controller */
|
||||
spcr = MSPI_MASTER_BIT;
|
||||
else
|
||||
spcr = 0;
|
||||
|
||||
/* for 16 bit the data should be zero */
|
||||
if (xp->bits_per_word != 16)
|
||||
spcr |= xp->bits_per_word << 2;
|
||||
spcr |= xp->mode & 3;
|
||||
/*
|
||||
* Bits per transfer. BITS determines the number of data bits
|
||||
* transferred if the command control bit (BITSE of a
|
||||
* CDRAM Register) is equal to 1.
|
||||
* If CDRAM BITSE is equal to 0, 8 data bits are transferred
|
||||
* regardless
|
||||
*/
|
||||
if (xp->bits_per_word != 16 && xp->bits_per_word != 64)
|
||||
spcr |= xp->bits_per_word << MSPI_SPCR0_MSB_BITS_SHIFT;
|
||||
|
||||
spcr |= xp->mode & (MSPI_SPCR0_MSB_CPHA | MSPI_SPCR0_MSB_CPOL);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr);
|
||||
|
||||
if (bcm_qspi_has_fastbr(qspi)) {
|
||||
@@ -595,17 +617,44 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
|
||||
/* enable fastbr */
|
||||
spcr |= MSPI_SPCR3_FASTBR;
|
||||
|
||||
if (xp->mode & SPI_3WIRE)
|
||||
spcr |= MSPI_SPCR3_HALFDUPLEX | MSPI_SPCR3_HDOUTTYPE;
|
||||
|
||||
if (bcm_qspi_has_sysclk_108(qspi)) {
|
||||
/* SYSCLK_108 */
|
||||
spcr |= MSPI_SPCR3_SYSCLKSEL_108;
|
||||
qspi->base_clk = MSPI_BASE_FREQ * 4;
|
||||
/* Change spbr as we changed sysclk */
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, 4);
|
||||
}
|
||||
|
||||
if (xp->bits_per_word > 16) {
|
||||
/* data_reg_size 1 (64bit) */
|
||||
spcr |= MSPI_SPCR3_DATA_REG_SZ;
|
||||
/* TxRx RAM data access mode 2 for 32B and set fastdt */
|
||||
spcr |= MSPI_SPCR3_DAM_32BYTE | MSPI_SPCR3_FASTDT;
|
||||
/*
|
||||
* Set length of delay after transfer
|
||||
* DTL from 0(256) to 1
|
||||
*/
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_LSB, 1);
|
||||
} else {
|
||||
/* data_reg_size[8] = 0 */
|
||||
spcr &= ~(MSPI_SPCR3_DATA_REG_SZ);
|
||||
|
||||
/*
|
||||
* TxRx RAM access mode 8B
|
||||
* and disable fastdt
|
||||
*/
|
||||
spcr &= ~(MSPI_SPCR3_DAM_32BYTE);
|
||||
}
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
|
||||
}
|
||||
|
||||
if (xp->speed_hz)
|
||||
spbr = qspi->base_clk / (2 * xp->speed_hz);
|
||||
|
||||
spbr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spbr);
|
||||
|
||||
qspi->last_parms = *xp;
|
||||
}
|
||||
|
||||
@@ -626,7 +675,7 @@ static int bcm_qspi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct bcm_qspi_parms *xp;
|
||||
|
||||
if (spi->bits_per_word > 16)
|
||||
if (spi->bits_per_word > 64)
|
||||
return -EINVAL;
|
||||
|
||||
xp = spi_get_ctldata(spi);
|
||||
@@ -665,8 +714,12 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
|
||||
/* count the last transferred bytes */
|
||||
if (qt->trans->bits_per_word <= 8)
|
||||
qt->byte++;
|
||||
else
|
||||
else if (qt->trans->bits_per_word <= 16)
|
||||
qt->byte += 2;
|
||||
else if (qt->trans->bits_per_word <= 32)
|
||||
qt->byte += 4;
|
||||
else if (qt->trans->bits_per_word <= 64)
|
||||
qt->byte += 8;
|
||||
|
||||
if (qt->byte >= qt->trans->len) {
|
||||
/* we're at the end of the spi_transfer */
|
||||
@@ -709,6 +762,33 @@ static inline u16 read_rxram_slot_u16(struct bcm_qspi *qspi, int slot)
|
||||
((bcm_qspi_read(qspi, MSPI, msb_offset) & 0xff) << 8);
|
||||
}
|
||||
|
||||
static inline u32 read_rxram_slot_u32(struct bcm_qspi *qspi, int slot)
|
||||
{
|
||||
u32 reg_offset = MSPI_RXRAM;
|
||||
u32 offset = reg_offset + (slot << 3);
|
||||
u32 val;
|
||||
|
||||
val = bcm_qspi_read(qspi, MSPI, offset);
|
||||
val = swap4bytes(val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 read_rxram_slot_u64(struct bcm_qspi *qspi, int slot)
|
||||
{
|
||||
u32 reg_offset = MSPI_RXRAM;
|
||||
u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
|
||||
u32 msb_offset = reg_offset + (slot << 3);
|
||||
u32 msb, lsb;
|
||||
|
||||
msb = bcm_qspi_read(qspi, MSPI, msb_offset);
|
||||
msb = swap4bytes(msb);
|
||||
lsb = bcm_qspi_read(qspi, MSPI, lsb_offset);
|
||||
lsb = swap4bytes(lsb);
|
||||
|
||||
return ((u64)msb << 32 | lsb);
|
||||
}
|
||||
|
||||
static void read_from_hw(struct bcm_qspi *qspi, int slots)
|
||||
{
|
||||
struct qspi_trans tp;
|
||||
@@ -732,7 +812,7 @@ static void read_from_hw(struct bcm_qspi *qspi, int slots)
|
||||
buf[tp.byte] = read_rxram_slot_u8(qspi, slot);
|
||||
dev_dbg(&qspi->pdev->dev, "RD %02x\n",
|
||||
buf ? buf[tp.byte] : 0x0);
|
||||
} else {
|
||||
} else if (tp.trans->bits_per_word <= 16) {
|
||||
u16 *buf = tp.trans->rx_buf;
|
||||
|
||||
if (buf)
|
||||
@@ -740,6 +820,25 @@ static void read_from_hw(struct bcm_qspi *qspi, int slots)
|
||||
slot);
|
||||
dev_dbg(&qspi->pdev->dev, "RD %04x\n",
|
||||
buf ? buf[tp.byte / 2] : 0x0);
|
||||
} else if (tp.trans->bits_per_word <= 32) {
|
||||
u32 *buf = tp.trans->rx_buf;
|
||||
|
||||
if (buf)
|
||||
buf[tp.byte / 4] = read_rxram_slot_u32(qspi,
|
||||
slot);
|
||||
dev_dbg(&qspi->pdev->dev, "RD %08x\n",
|
||||
buf ? buf[tp.byte / 4] : 0x0);
|
||||
|
||||
} else if (tp.trans->bits_per_word <= 64) {
|
||||
u64 *buf = tp.trans->rx_buf;
|
||||
|
||||
if (buf)
|
||||
buf[tp.byte / 8] = read_rxram_slot_u64(qspi,
|
||||
slot);
|
||||
dev_dbg(&qspi->pdev->dev, "RD %llx\n",
|
||||
buf ? buf[tp.byte / 8] : 0x0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
update_qspi_trans_byte_count(qspi, &tp,
|
||||
@@ -769,6 +868,28 @@ static inline void write_txram_slot_u16(struct bcm_qspi *qspi, int slot,
|
||||
bcm_qspi_write(qspi, MSPI, lsb_offset, (val & 0xff));
|
||||
}
|
||||
|
||||
static inline void write_txram_slot_u32(struct bcm_qspi *qspi, int slot,
|
||||
u32 val)
|
||||
{
|
||||
u32 reg_offset = MSPI_TXRAM;
|
||||
u32 msb_offset = reg_offset + (slot << 3);
|
||||
|
||||
bcm_qspi_write(qspi, MSPI, msb_offset, swap4bytes(val));
|
||||
}
|
||||
|
||||
static inline void write_txram_slot_u64(struct bcm_qspi *qspi, int slot,
|
||||
u64 val)
|
||||
{
|
||||
u32 reg_offset = MSPI_TXRAM;
|
||||
u32 msb_offset = reg_offset + (slot << 3);
|
||||
u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
|
||||
u32 msb = upper_32_bits(val);
|
||||
u32 lsb = lower_32_bits(val);
|
||||
|
||||
bcm_qspi_write(qspi, MSPI, msb_offset, swap4bytes(msb));
|
||||
bcm_qspi_write(qspi, MSPI, lsb_offset, swap4bytes(lsb));
|
||||
}
|
||||
|
||||
static inline u32 read_cdram_slot(struct bcm_qspi *qspi, int slot)
|
||||
{
|
||||
return bcm_qspi_read(qspi, MSPI, MSPI_CDRAM + (slot << 2));
|
||||
@@ -792,20 +913,43 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
|
||||
|
||||
/* Run until end of transfer or reached the max data */
|
||||
while (!tstatus && slot < MSPI_NUM_CDRAM) {
|
||||
mspi_cdram = MSPI_CDRAM_CONT_BIT;
|
||||
if (tp.trans->bits_per_word <= 8) {
|
||||
const u8 *buf = tp.trans->tx_buf;
|
||||
u8 val = buf ? buf[tp.byte] : 0x00;
|
||||
|
||||
write_txram_slot_u8(qspi, slot, val);
|
||||
dev_dbg(&qspi->pdev->dev, "WR %02x\n", val);
|
||||
} else {
|
||||
} else if (tp.trans->bits_per_word <= 16) {
|
||||
const u16 *buf = tp.trans->tx_buf;
|
||||
u16 val = buf ? buf[tp.byte / 2] : 0x0000;
|
||||
|
||||
write_txram_slot_u16(qspi, slot, val);
|
||||
dev_dbg(&qspi->pdev->dev, "WR %04x\n", val);
|
||||
} else if (tp.trans->bits_per_word <= 32) {
|
||||
const u32 *buf = tp.trans->tx_buf;
|
||||
u32 val = buf ? buf[tp.byte/4] : 0x0;
|
||||
|
||||
write_txram_slot_u32(qspi, slot, val);
|
||||
dev_dbg(&qspi->pdev->dev, "WR %08x\n", val);
|
||||
} else if (tp.trans->bits_per_word <= 64) {
|
||||
const u64 *buf = tp.trans->tx_buf;
|
||||
u64 val = (buf ? buf[tp.byte/8] : 0x0);
|
||||
|
||||
/* use the length of delay from SPCR1_LSB */
|
||||
if (bcm_qspi_has_fastbr(qspi))
|
||||
mspi_cdram |= MSPI_CDRAM_DT_BIT;
|
||||
|
||||
write_txram_slot_u64(qspi, slot, val);
|
||||
dev_dbg(&qspi->pdev->dev, "WR %llx\n", val);
|
||||
}
|
||||
mspi_cdram = MSPI_CDRAM_CONT_BIT;
|
||||
|
||||
mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
|
||||
MSPI_CDRAM_BITSE_BIT);
|
||||
|
||||
/* set 3wrire halfduplex mode data from master to slave */
|
||||
if ((spi->mode & SPI_3WIRE) && tp.trans->tx_buf)
|
||||
mspi_cdram |= MSPI_CDRAM_OUTP;
|
||||
|
||||
if (has_bspi(qspi))
|
||||
mspi_cdram &= ~1;
|
||||
@@ -813,9 +957,6 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
|
||||
mspi_cdram |= (~(1 << spi->chip_select) &
|
||||
MSPI_CDRAM_PCS);
|
||||
|
||||
mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
|
||||
MSPI_CDRAM_BITSE_BIT);
|
||||
|
||||
write_cdram_slot(qspi, slot, mspi_cdram);
|
||||
|
||||
tstatus = update_qspi_trans_byte_count(qspi, &tp,
|
||||
@@ -1350,7 +1491,8 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
qspi->master = master;
|
||||
|
||||
master->bus_num = -1;
|
||||
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
|
||||
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
|
||||
SPI_3WIRE;
|
||||
master->setup = bcm_qspi_setup;
|
||||
master->transfer_one = bcm_qspi_transfer_one;
|
||||
master->mem_ops = &bcm_qspi_mem_ops;
|
||||
@@ -1460,7 +1602,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
&qspi->dev_ids[val]);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "IRQ %s not found\n", name);
|
||||
goto qspi_probe_err;
|
||||
goto qspi_unprepare_err;
|
||||
}
|
||||
|
||||
qspi->dev_ids[val].dev = qspi;
|
||||
@@ -1475,7 +1617,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
if (!num_ints) {
|
||||
dev_err(&pdev->dev, "no IRQs registered, cannot init driver\n");
|
||||
ret = -EINVAL;
|
||||
goto qspi_probe_err;
|
||||
goto qspi_unprepare_err;
|
||||
}
|
||||
|
||||
bcm_qspi_hw_init(qspi);
|
||||
@@ -1499,6 +1641,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
|
||||
qspi_reg_err:
|
||||
bcm_qspi_hw_uninit(qspi);
|
||||
qspi_unprepare_err:
|
||||
clk_disable_unprepare(qspi->clk);
|
||||
qspi_probe_err:
|
||||
kfree(qspi->dev_ids);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
@@ -35,6 +36,7 @@
|
||||
/* Quirks */
|
||||
#define CQSPI_NEEDS_WR_DELAY BIT(0)
|
||||
#define CQSPI_DISABLE_DAC_MODE BIT(1)
|
||||
#define CQSPI_SUPPORT_EXTERNAL_DMA BIT(2)
|
||||
|
||||
/* Capabilities */
|
||||
#define CQSPI_SUPPORTS_OCTAL BIT(0)
|
||||
@@ -82,11 +84,16 @@ struct cqspi_st {
|
||||
u32 wr_delay;
|
||||
bool use_direct_mode;
|
||||
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
|
||||
bool use_dma_read;
|
||||
u32 pd_dev_id;
|
||||
};
|
||||
|
||||
struct cqspi_driver_platdata {
|
||||
u32 hwcaps_mask;
|
||||
u8 quirks;
|
||||
int (*indirect_read_dma)(struct cqspi_flash_pdata *f_pdata,
|
||||
u_char *rxbuf, loff_t from_addr, size_t n_rx);
|
||||
u32 (*get_dma_status)(struct cqspi_st *cqspi);
|
||||
};
|
||||
|
||||
/* Operation timeout value */
|
||||
@@ -217,6 +224,8 @@ struct cqspi_driver_platdata {
|
||||
#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
|
||||
#define CQSPI_REG_INDIRECTWRBYTES 0x7C
|
||||
|
||||
#define CQSPI_REG_INDTRIG_ADDRRANGE 0x80
|
||||
|
||||
#define CQSPI_REG_CMDADDRESS 0x94
|
||||
#define CQSPI_REG_CMDREADDATALOWER 0xA0
|
||||
#define CQSPI_REG_CMDREADDATAUPPER 0xA4
|
||||
@@ -231,6 +240,23 @@ struct cqspi_driver_platdata {
|
||||
#define CQSPI_REG_OP_EXT_WRITE_LSB 16
|
||||
#define CQSPI_REG_OP_EXT_STIG_LSB 0
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_SRC_ADDR 0x1000
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_ADDR 0x1800
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_SIZE 0x1804
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_CTRL 0x180C
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_I_STS 0x1814
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_I_EN 0x1818
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_I_DIS 0x181C
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_DONE_MASK BIT(1)
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_ADDR_MSB 0x1828
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_DST_CTRL_VAL 0xF43FFA00
|
||||
#define CQSPI_REG_VERSAL_ADDRRANGE_WIDTH_VAL 0x6
|
||||
|
||||
/* Interrupt status bits */
|
||||
#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
|
||||
#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
|
||||
@@ -250,6 +276,9 @@ struct cqspi_driver_platdata {
|
||||
CQSPI_REG_IRQ_UNDERFLOW)
|
||||
|
||||
#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
|
||||
#define CQSPI_DMA_UNALIGN 0x3
|
||||
|
||||
#define CQSPI_REG_VERSAL_DMA_VAL 0x602
|
||||
|
||||
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
|
||||
{
|
||||
@@ -275,10 +304,26 @@ static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
|
||||
return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
|
||||
}
|
||||
|
||||
static u32 cqspi_get_versal_dma_status(struct cqspi_st *cqspi)
|
||||
{
|
||||
u32 dma_status;
|
||||
|
||||
dma_status = readl(cqspi->iobase +
|
||||
CQSPI_REG_VERSAL_DMA_DST_I_STS);
|
||||
writel(dma_status, cqspi->iobase +
|
||||
CQSPI_REG_VERSAL_DMA_DST_I_STS);
|
||||
|
||||
return dma_status & CQSPI_REG_VERSAL_DMA_DST_DONE_MASK;
|
||||
}
|
||||
|
||||
static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
|
||||
{
|
||||
struct cqspi_st *cqspi = dev;
|
||||
unsigned int irq_status;
|
||||
struct device *device = &cqspi->pdev->dev;
|
||||
const struct cqspi_driver_platdata *ddata;
|
||||
|
||||
ddata = of_device_get_match_data(device);
|
||||
|
||||
/* Read interrupt status */
|
||||
irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
|
||||
@@ -286,6 +331,13 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
|
||||
/* Clear interrupt */
|
||||
writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);
|
||||
|
||||
if (cqspi->use_dma_read && ddata && ddata->get_dma_status) {
|
||||
if (ddata->get_dma_status(cqspi)) {
|
||||
complete(&cqspi->transfer_complete);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
|
||||
|
||||
if (irq_status)
|
||||
@@ -781,6 +833,131 @@ failrd:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cqspi_versal_indirect_read_dma(struct cqspi_flash_pdata *f_pdata,
|
||||
u_char *rxbuf, loff_t from_addr,
|
||||
size_t n_rx)
|
||||
{
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
struct device *dev = &cqspi->pdev->dev;
|
||||
void __iomem *reg_base = cqspi->iobase;
|
||||
u32 reg, bytes_to_dma;
|
||||
loff_t addr = from_addr;
|
||||
void *buf = rxbuf;
|
||||
dma_addr_t dma_addr;
|
||||
u8 bytes_rem;
|
||||
int ret = 0;
|
||||
|
||||
bytes_rem = n_rx % 4;
|
||||
bytes_to_dma = (n_rx - bytes_rem);
|
||||
|
||||
if (!bytes_to_dma)
|
||||
goto nondmard;
|
||||
|
||||
ret = zynqmp_pm_ospi_mux_select(cqspi->pd_dev_id, PM_OSPI_MUX_SEL_DMA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
reg |= CQSPI_REG_CONFIG_DMA_MASK;
|
||||
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
|
||||
dma_addr = dma_map_single(dev, rxbuf, bytes_to_dma, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, dma_addr)) {
|
||||
dev_err(dev, "dma mapping failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
|
||||
writel(bytes_to_dma, reg_base + CQSPI_REG_INDIRECTRDBYTES);
|
||||
writel(CQSPI_REG_VERSAL_ADDRRANGE_WIDTH_VAL,
|
||||
reg_base + CQSPI_REG_INDTRIG_ADDRRANGE);
|
||||
|
||||
/* Clear all interrupts. */
|
||||
writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
|
||||
|
||||
/* Enable DMA done interrupt */
|
||||
writel(CQSPI_REG_VERSAL_DMA_DST_DONE_MASK,
|
||||
reg_base + CQSPI_REG_VERSAL_DMA_DST_I_EN);
|
||||
|
||||
/* Default DMA periph configuration */
|
||||
writel(CQSPI_REG_VERSAL_DMA_VAL, reg_base + CQSPI_REG_DMA);
|
||||
|
||||
/* Configure DMA Dst address */
|
||||
writel(lower_32_bits(dma_addr),
|
||||
reg_base + CQSPI_REG_VERSAL_DMA_DST_ADDR);
|
||||
writel(upper_32_bits(dma_addr),
|
||||
reg_base + CQSPI_REG_VERSAL_DMA_DST_ADDR_MSB);
|
||||
|
||||
/* Configure DMA Src address */
|
||||
writel(cqspi->trigger_address, reg_base +
|
||||
CQSPI_REG_VERSAL_DMA_SRC_ADDR);
|
||||
|
||||
/* Set DMA destination size */
|
||||
writel(bytes_to_dma, reg_base + CQSPI_REG_VERSAL_DMA_DST_SIZE);
|
||||
|
||||
/* Set DMA destination control */
|
||||
writel(CQSPI_REG_VERSAL_DMA_DST_CTRL_VAL,
|
||||
reg_base + CQSPI_REG_VERSAL_DMA_DST_CTRL);
|
||||
|
||||
writel(CQSPI_REG_INDIRECTRD_START_MASK,
|
||||
reg_base + CQSPI_REG_INDIRECTRD);
|
||||
|
||||
reinit_completion(&cqspi->transfer_complete);
|
||||
|
||||
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
|
||||
msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto failrd;
|
||||
}
|
||||
|
||||
/* Disable DMA interrupt */
|
||||
writel(0x0, cqspi->iobase + CQSPI_REG_VERSAL_DMA_DST_I_DIS);
|
||||
|
||||
/* Clear indirect completion status */
|
||||
writel(CQSPI_REG_INDIRECTRD_DONE_MASK,
|
||||
cqspi->iobase + CQSPI_REG_INDIRECTRD);
|
||||
dma_unmap_single(dev, dma_addr, bytes_to_dma, DMA_FROM_DEVICE);
|
||||
|
||||
reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
reg &= ~CQSPI_REG_CONFIG_DMA_MASK;
|
||||
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
|
||||
ret = zynqmp_pm_ospi_mux_select(cqspi->pd_dev_id,
|
||||
PM_OSPI_MUX_SEL_LINEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
nondmard:
|
||||
if (bytes_rem) {
|
||||
addr += bytes_to_dma;
|
||||
buf += bytes_to_dma;
|
||||
ret = cqspi_indirect_read_execute(f_pdata, buf, addr,
|
||||
bytes_rem);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failrd:
|
||||
/* Disable DMA interrupt */
|
||||
writel(0x0, reg_base + CQSPI_REG_VERSAL_DMA_DST_I_DIS);
|
||||
|
||||
/* Cancel the indirect read */
|
||||
writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
|
||||
reg_base + CQSPI_REG_INDIRECTRD);
|
||||
|
||||
dma_unmap_single(dev, dma_addr, bytes_to_dma, DMA_FROM_DEVICE);
|
||||
|
||||
reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
reg &= ~CQSPI_REG_CONFIG_DMA_MASK;
|
||||
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
|
||||
zynqmp_pm_ospi_mux_select(cqspi->pd_dev_id, PM_OSPI_MUX_SEL_LINEAR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
@@ -1180,11 +1357,15 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
struct device *dev = &cqspi->pdev->dev;
|
||||
const struct cqspi_driver_platdata *ddata;
|
||||
loff_t from = op->addr.val;
|
||||
size_t len = op->data.nbytes;
|
||||
u_char *buf = op->data.buf.in;
|
||||
u64 dma_align = (u64)(uintptr_t)buf;
|
||||
int ret;
|
||||
|
||||
ddata = of_device_get_match_data(dev);
|
||||
ret = cqspi_set_protocol(f_pdata, op);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1196,6 +1377,10 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
|
||||
if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size))
|
||||
return cqspi_direct_read_execute(f_pdata, buf, from, len);
|
||||
|
||||
if (cqspi->use_dma_read && ddata && ddata->indirect_read_dma &&
|
||||
virt_addr_valid(buf) && ((dma_align & CQSPI_DMA_UNALIGN) == 0))
|
||||
return ddata->indirect_read_dma(f_pdata, buf, from, len);
|
||||
|
||||
return cqspi_indirect_read_execute(f_pdata, buf, from, len);
|
||||
}
|
||||
|
||||
@@ -1299,6 +1484,7 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi)
|
||||
{
|
||||
struct device *dev = &cqspi->pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 id[2];
|
||||
|
||||
cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
|
||||
|
||||
@@ -1323,6 +1509,10 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi)
|
||||
|
||||
cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en");
|
||||
|
||||
if (!of_property_read_u32_array(np, "power-domains", id,
|
||||
ARRAY_SIZE(id)))
|
||||
cqspi->pd_dev_id = id[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1359,6 +1549,13 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
|
||||
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
}
|
||||
|
||||
/* Enable DMA interface */
|
||||
if (cqspi->use_dma_read) {
|
||||
reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
reg |= CQSPI_REG_CONFIG_DMA_MASK;
|
||||
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
|
||||
}
|
||||
|
||||
cqspi_controller_enable(cqspi, 1);
|
||||
}
|
||||
|
||||
@@ -1548,6 +1745,12 @@ static int cqspi_probe(struct platform_device *pdev)
|
||||
master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
|
||||
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE))
|
||||
cqspi->use_direct_mode = true;
|
||||
if (ddata->quirks & CQSPI_SUPPORT_EXTERNAL_DMA)
|
||||
cqspi->use_dma_read = true;
|
||||
|
||||
if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"xlnx,versal-ospi-1.0"))
|
||||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
|
||||
@@ -1656,6 +1859,13 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = {
|
||||
.quirks = CQSPI_DISABLE_DAC_MODE,
|
||||
};
|
||||
|
||||
static const struct cqspi_driver_platdata versal_ospi = {
|
||||
.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
|
||||
.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA,
|
||||
.indirect_read_dma = cqspi_versal_indirect_read_dma,
|
||||
.get_dma_status = cqspi_get_versal_dma_status,
|
||||
};
|
||||
|
||||
static const struct of_device_id cqspi_dt_ids[] = {
|
||||
{
|
||||
.compatible = "cdns,qspi-nor",
|
||||
@@ -1673,6 +1883,10 @@ static const struct of_device_id cqspi_dt_ids[] = {
|
||||
.compatible = "intel,lgm-qspi",
|
||||
.data = &intel_lgm_qspi,
|
||||
},
|
||||
{
|
||||
.compatible = "xlnx,versal-ospi-1.0",
|
||||
.data = (void *)&versal_ospi,
|
||||
},
|
||||
{ /* end of table */ }
|
||||
};
|
||||
|
||||
|
||||
642
drivers/spi/spi-cadence-xspi.c
Normal file
642
drivers/spi/spi-cadence-xspi.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -67,9 +67,14 @@
|
||||
SPI_FSI_STATUS_RDR_OVERRUN)
|
||||
#define SPI_FSI_PORT_CTRL 0x9
|
||||
|
||||
struct fsi2spi {
|
||||
struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
|
||||
struct mutex lock; /* lock access to the device */
|
||||
};
|
||||
|
||||
struct fsi_spi {
|
||||
struct device *dev; /* SPI controller device */
|
||||
struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
|
||||
struct fsi2spi *bridge; /* FSI2SPI device */
|
||||
u32 base;
|
||||
};
|
||||
|
||||
@@ -104,7 +109,7 @@ static int fsi_spi_check_status(struct fsi_spi *ctx)
|
||||
u32 sts;
|
||||
__be32 sts_be;
|
||||
|
||||
rc = fsi_device_read(ctx->fsi, FSI2SPI_STATUS, &sts_be,
|
||||
rc = fsi_device_read(ctx->bridge->fsi, FSI2SPI_STATUS, &sts_be,
|
||||
sizeof(sts_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -120,73 +125,91 @@ static int fsi_spi_check_status(struct fsi_spi *ctx)
|
||||
|
||||
static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
__be32 cmd_be;
|
||||
__be32 data_be;
|
||||
u32 cmd = offset + ctx->base;
|
||||
struct fsi2spi *bridge = ctx->bridge;
|
||||
|
||||
*value = 0ULL;
|
||||
|
||||
if (cmd & FSI2SPI_CMD_WRITE)
|
||||
return -EINVAL;
|
||||
|
||||
cmd_be = cpu_to_be32(cmd);
|
||||
rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
|
||||
rc = mutex_lock_interruptible(&bridge->lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cmd_be = cpu_to_be32(cmd);
|
||||
rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,
|
||||
sizeof(cmd_be));
|
||||
if (rc)
|
||||
goto unlock;
|
||||
|
||||
rc = fsi_spi_check_status(ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA0, &data_be,
|
||||
rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA0, &data_be,
|
||||
sizeof(data_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
*value |= (u64)be32_to_cpu(data_be) << 32;
|
||||
|
||||
rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA1, &data_be,
|
||||
rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA1, &data_be,
|
||||
sizeof(data_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
*value |= (u64)be32_to_cpu(data_be);
|
||||
dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value);
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
mutex_unlock(&bridge->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
__be32 cmd_be;
|
||||
__be32 data_be;
|
||||
u32 cmd = offset + ctx->base;
|
||||
struct fsi2spi *bridge = ctx->bridge;
|
||||
|
||||
if (cmd & FSI2SPI_CMD_WRITE)
|
||||
return -EINVAL;
|
||||
|
||||
rc = mutex_lock_interruptible(&bridge->lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value);
|
||||
|
||||
data_be = cpu_to_be32(upper_32_bits(value));
|
||||
rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA0, &data_be,
|
||||
rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA0, &data_be,
|
||||
sizeof(data_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
data_be = cpu_to_be32(lower_32_bits(value));
|
||||
rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA1, &data_be,
|
||||
rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA1, &data_be,
|
||||
sizeof(data_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE);
|
||||
rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
|
||||
rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,
|
||||
sizeof(cmd_be));
|
||||
if (rc)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
return fsi_spi_check_status(ctx);
|
||||
rc = fsi_spi_check_status(ctx);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&bridge->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fsi_spi_data_in(u64 in, u8 *rx, int len)
|
||||
@@ -234,6 +257,26 @@ static int fsi_spi_reset(struct fsi_spi *ctx)
|
||||
return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL);
|
||||
}
|
||||
|
||||
static int fsi_spi_status(struct fsi_spi *ctx, u64 *status, const char *dir)
|
||||
{
|
||||
int rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, status);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (*status & SPI_FSI_STATUS_ANY_ERROR) {
|
||||
dev_err(ctx->dev, "%s error: %016llx\n", dir, *status);
|
||||
|
||||
rc = fsi_spi_reset(ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)
|
||||
{
|
||||
/*
|
||||
@@ -273,18 +316,9 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
|
||||
return rc;
|
||||
|
||||
do {
|
||||
rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
|
||||
&status);
|
||||
rc = fsi_spi_status(ctx, &status, "TX");
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (status & SPI_FSI_STATUS_ANY_ERROR) {
|
||||
rc = fsi_spi_reset(ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
} while (status & SPI_FSI_STATUS_TDR_FULL);
|
||||
|
||||
sent += nb;
|
||||
@@ -296,18 +330,9 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
|
||||
|
||||
while (transfer->len > recv) {
|
||||
do {
|
||||
rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
|
||||
&status);
|
||||
rc = fsi_spi_status(ctx, &status, "RX");
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (status & SPI_FSI_STATUS_ANY_ERROR) {
|
||||
rc = fsi_spi_reset(ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
} while (!(status & SPI_FSI_STATUS_RDR_FULL));
|
||||
|
||||
rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in);
|
||||
@@ -348,8 +373,12 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx)
|
||||
if (status & (SPI_FSI_STATUS_ANY_ERROR |
|
||||
SPI_FSI_STATUS_TDR_FULL |
|
||||
SPI_FSI_STATUS_RDR_FULL)) {
|
||||
if (reset)
|
||||
if (reset) {
|
||||
dev_err(ctx->dev,
|
||||
"Initialization error: %08llx\n",
|
||||
status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = fsi_spi_reset(ctx);
|
||||
if (rc)
|
||||
@@ -388,7 +417,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
struct spi_transfer *transfer;
|
||||
struct fsi_spi *ctx = spi_controller_get_devdata(ctlr);
|
||||
|
||||
rc = fsi_spi_check_mux(ctx->fsi, ctx->dev);
|
||||
rc = fsi_spi_check_mux(ctx->bridge->fsi, ctx->dev);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
@@ -478,12 +507,20 @@ static int fsi_spi_probe(struct device *dev)
|
||||
int rc;
|
||||
struct device_node *np;
|
||||
int num_controllers_registered = 0;
|
||||
struct fsi2spi *bridge;
|
||||
struct fsi_device *fsi = to_fsi_dev(dev);
|
||||
|
||||
rc = fsi_spi_check_mux(fsi, dev);
|
||||
if (rc)
|
||||
return -ENODEV;
|
||||
|
||||
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge->fsi = fsi;
|
||||
mutex_init(&bridge->lock);
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, np) {
|
||||
u32 base;
|
||||
struct fsi_spi *ctx;
|
||||
@@ -506,7 +543,7 @@ static int fsi_spi_probe(struct device *dev)
|
||||
|
||||
ctx = spi_controller_get_devdata(ctlr);
|
||||
ctx->dev = &ctlr->dev;
|
||||
ctx->fsi = fsi;
|
||||
ctx->bridge = bridge;
|
||||
ctx->base = base + SPI_FSI_BASE;
|
||||
|
||||
rc = devm_spi_register_controller(dev, ctlr);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user