diff options
51 files changed, 1430 insertions, 416 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml index 2a2756d19681..b4be9bd8ddde 100644 --- a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml +++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml @@ -23,6 +23,8 @@ properties: reg: true reset-gpios: true + spi-3wire: true + required: - compatible - power-supply diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml index 817a9bed7d5a..ebdca5f5a001 100644 --- a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml @@ -24,6 +24,8 @@ properties: reg: true reset-gpios: true + spi-3wire: true + required: - compatible - power-supply diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml index 940f7f88526f..6f1fc7469f07 100644 --- a/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml @@ -24,6 +24,10 @@ properties: default-brightness: true max-brightness: true + spi-3wire: true + spi-cpha: true + spi-cpol: true + vdd3-supply: description: VDD regulator diff --git a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml index 7326c0a28d16..1051690e3753 100644 --- a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml +++ b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml @@ -4,7 +4,11 @@ $id: http://devicetree.org/schemas/spi/microchip,mpfs-spi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Microchip MPFS {Q,}SPI Controller Device Tree Bindings +title: Microchip FPGA {Q,}SPI Controllers + +description: + SPI and QSPI controllers on Microchip PolarFire SoC and the "soft"/ + fabric IP cores they are based on maintainers: - Conor Dooley <conor.dooley@microchip.com> @@ -14,9 +18,12 @@ allOf: properties: compatible: - enum: - - microchip,mpfs-spi - - microchip,mpfs-qspi + oneOf: + - items: + - const: microchip,mpfs-qspi + - const: microchip,coreqspi-rtl-v2 + - const: microchip,coreqspi-rtl-v2 #FPGA QSPI + - const: microchip,mpfs-spi reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt index b98203ca656d..a4e72e52af59 100644 --- a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt +++ b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt @@ -3,7 +3,8 @@ Nuvoton NPCM Peripheral Serial Peripheral Interface(PSPI) controller driver Nuvoton NPCM7xx SOC support two PSPI channels. Required properties: - - compatible : "nuvoton,npcm750-pspi" for NPCM7XX BMC + - compatible : "nuvoton,npcm750-pspi" for Poleg NPCM7XX. + "nuvoton,npcm845-pspi" for Arbel NPCM8XX. - #address-cells : should be 1. see spi-bus.txt - #size-cells : should be 0. see spi-bus.txt - specifies physical base address and size of the register. diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml index 24e0c2181d25..2c3cada75339 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml @@ -29,5 +29,4 @@ properties: minimum: 0 maximum: 255 -unevaluatedProperties: true - +additionalProperties: true diff --git a/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml b/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml new file mode 100644 index 000000000000..22879f7dcb77 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/ralink,mt7621-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +maintainers: + - Sergio Paracuellos <sergio.paracuellos@gmail.com> + +title: Mediatek MT7621/MT7628 SPI controller + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +properties: + compatible: + const: ralink,mt7621-spi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: spi + + resets: + maxItems: 1 + + reset-names: + const: spi + +required: + - compatible + - reg + - resets + - "#address-cells" + - "#size-cells" + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/mt7621-clk.h> + #include <dt-bindings/reset/mt7621-reset.h> + + spi@b00 { + compatible = "ralink,mt7621-spi"; + reg = <0xb00 0x100>; + clocks = <&sysc MT7621_CLK_SPI>; + clock-names = "spi"; + resets = <&sysc MT7621_RST_SPI>; + reset-names = "spi"; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + }; diff --git a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml index 5de710adfa63..491a695a2deb 100644 --- a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml @@ -47,10 +47,16 @@ properties: - renesas,msiof-r8a77980 # R-Car V3H - renesas,msiof-r8a77990 # R-Car E3 - renesas,msiof-r8a77995 # R-Car D3 - - renesas,msiof-r8a779a0 # R-Car V3U - const: renesas,rcar-gen3-msiof # generic R-Car Gen3 and RZ/G2 # compatible device - items: + - enum: + - renesas,msiof-r8a779a0 # R-Car V3U + - renesas,msiof-r8a779f0 # R-Car S4-8 + - renesas,msiof-r8a779g0 # R-Car V4H + - const: renesas,rcar-gen4-msiof # generic R-Car Gen4 + # compatible device + - items: - const: renesas,sh-msiof # deprecated reg: @@ -69,6 +75,12 @@ properties: clocks: maxItems: 1 + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + num-cs: description: | Total number of chip selects (default is 1). diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index 37c3c272407d..d33b72fabc5d 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -104,7 +104,6 @@ properties: const: spi reg-io-width: - $ref: /schemas/types.yaml#/definitions/uint32 description: I/O register width (in bytes) implemented by this device default: 4 enum: [ 2, 4 ] diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 655713fba7e2..01042a7f382e 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -96,6 +96,11 @@ patternProperties: $ref: spi-peripheral-props.yaml properties: + spi-3wire: + $ref: /schemas/types.yaml#/definitions/flag + description: + The device requires 3-wire mode. + spi-cpha: $ref: /schemas/types.yaml#/definitions/flag description: diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml index 1d46877fe46a..8b44284d30c6 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml @@ -19,7 +19,9 @@ properties: - fsl,imx7ulp-spi - fsl,imx8qxp-spi - items: - - const: fsl,imx8ulp-spi + - enum: + - fsl,imx8ulp-spi + - fsl,imx93-spi - const: fsl,imx7ulp-spi reg: maxItems: 1 @@ -37,6 +39,16 @@ properties: - const: per - const: ipg + dmas: + items: + - description: TX DMA Channel + - description: RX DMA Channel + + dma-names: + items: + - const: tx + - const: rx + fsl,spi-only-use-cs1-sel: description: spi common code does not support use of CS signals discontinuously. diff --git a/Documentation/devicetree/bindings/spi/spi-mt7621.txt b/Documentation/devicetree/bindings/spi/spi-mt7621.txt deleted file mode 100644 index d5baec0fa56e..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-mt7621.txt +++ /dev/null @@ -1,26 +0,0 @@ -Binding for MTK SPI controller (MT7621 MIPS) - -Required properties: -- compatible: Should be one of the following: - - "ralink,mt7621-spi": for mt7621/mt7628/mt7688 platforms -- #address-cells: should be 1. -- #size-cells: should be 0. -- reg: Address and length of the register set for the device -- resets: phandle to the reset controller asserting this device in - reset - See ../reset/reset.txt for details. - -Optional properties: -- cs-gpios: see spi-bus.txt. - -Example: - -- SoC Specific Portion: -spi0: spi@b00 { - compatible = "ralink,mt7621-spi"; - reg = <0xb00 0x100>; - #address-cells = <1>; - #size-cells = <0>; - resets = <&rstctrl 18>; - reset-names = "spi"; -}; diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml index a4abe1588005..dca677f9e1b9 100644 --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml @@ -29,11 +29,6 @@ properties: description: Chip select used by the device. - spi-3wire: - $ref: /schemas/types.yaml#/definitions/flag - description: - The device requires 3-wire mode. - spi-cs-high: $ref: /schemas/types.yaml#/definitions/flag description: diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml index 52a78a2e362e..66e49947b703 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml @@ -27,6 +27,7 @@ properties: - items: - enum: - rockchip,px30-spi + - rockchip,rk3128-spi - rockchip,rk3188-spi - rockchip,rk3288-spi - rockchip,rk3308-spi @@ -34,6 +35,7 @@ properties: - rockchip,rk3368-spi - rockchip,rk3399-spi - rockchip,rk3568-spi + - rockchip,rk3588-spi - rockchip,rv1126-spi - const: rockchip,rk3066-spi @@ -80,6 +82,9 @@ properties: where the "sleep" configuration may describe the state the pins should be in during system suspend. + power-domains: + maxItems: 1 + required: - compatible - reg diff --git a/MAINTAINERS b/MAINTAINERS index ce066179edc3..8656ab794786 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17568,6 +17568,7 @@ F: drivers/mailbox/mailbox-mpfs.c F: drivers/pci/controller/pcie-microchip-host.c F: drivers/rtc/rtc-mpfs.c F: drivers/soc/microchip/ +F: drivers/spi/spi-microchip-core-qspi.c F: drivers/spi/spi-microchip-core.c F: drivers/usb/musb/mpfs.c F: include/soc/microchip/mpfs.h diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e32f6a2058ae..d1bb62f7368b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -591,6 +591,15 @@ config SPI_MICROCHIP_CORE PolarFire SoC. If built as a module, it will be called spi-microchip-core. +config SPI_MICROCHIP_CORE_QSPI + tristate "Microchip FPGA QSPI controllers" + depends on SPI_MASTER + help + This enables the QSPI driver for Microchip FPGA QSPI controllers. + Say Y or M here if you want to use the QSPI controllers on + PolarFire SoC. + If built as a module, it will be called spi-microchip-core-qspi. + config SPI_MT65XX tristate "MediaTek SPI controller" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 15d2f3835e45..4b34e855c841 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o obj-$(CONFIG_SPI_MICROCHIP_CORE) += spi-microchip-core.o +obj-$(CONFIG_SPI_MICROCHIP_CORE_QSPI) += spi-microchip-core-qspi.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 08df4f8d0531..e23121456c70 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -36,9 +36,17 @@ #define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_MEM_SIZE 200 -/* M_CMD OP codes for SPI */ -#define AMD_SPI_XFER_TX 1 -#define AMD_SPI_XFER_RX 2 +#define AMD_SPI_ENA_REG 0x20 +#define AMD_SPI_ALT_SPD_SHIFT 20 +#define AMD_SPI_ALT_SPD_MASK GENMASK(23, AMD_SPI_ALT_SPD_SHIFT) +#define AMD_SPI_SPI100_SHIFT 0 +#define AMD_SPI_SPI100_MASK GENMASK(AMD_SPI_SPI100_SHIFT, AMD_SPI_SPI100_SHIFT) +#define AMD_SPI_SPEED_REG 0x6C +#define AMD_SPI_SPD7_SHIFT 8 +#define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT) + +#define AMD_SPI_MAX_HZ 100000000 +#define AMD_SPI_MIN_HZ 800000 /** * enum amd_spi_versions - SPI controller versions @@ -50,14 +58,41 @@ enum amd_spi_versions { AMD_SPI_V2, }; +enum amd_spi_speed { + F_66_66MHz, + F_33_33MHz, + F_22_22MHz, + F_16_66MHz, + F_100MHz, + F_800KHz, + SPI_SPD7, + F_50MHz = 0x4, + F_4MHz = 0x32, + F_3_17MHz = 0x3F +}; + +/** + * struct amd_spi_freq - Matches device speed with values to write in regs + * @speed_hz: Device frequency + * @enable_val: Value to be written to "enable register" + * @spd7_val: Some frequencies requires to have a value written at SPISPEED register + */ +struct amd_spi_freq { + u32 speed_hz; + u32 enable_val; + u32 spd7_val; +}; + /** * struct amd_spi - SPI driver instance * @io_remap_addr: Start address of the SPI controller registers * @version: SPI controller hardware version + * @speed_hz: Device frequency */ struct amd_spi { void __iomem *io_remap_addr; enum amd_spi_versions version; + unsigned int speed_hz; }; static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx) @@ -189,65 +224,125 @@ static int amd_spi_master_setup(struct spi_device *spi) return 0; } +static const struct amd_spi_freq amd_spi_freq[] = { + { AMD_SPI_MAX_HZ, F_100MHz, 0}, + { 66660000, F_66_66MHz, 0}, + { 50000000, SPI_SPD7, F_50MHz}, + { 33330000, F_33_33MHz, 0}, + { 22220000, F_22_22MHz, 0}, + { 16660000, F_16_66MHz, 0}, + { 4000000, SPI_SPD7, F_4MHz}, + { 3170000, SPI_SPD7, F_3_17MHz}, + { AMD_SPI_MIN_HZ, F_800KHz, 0}, +}; + +static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz) +{ + unsigned int i, spd7_val, alt_spd; + + if (speed_hz < AMD_SPI_MIN_HZ) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++) + if (speed_hz >= amd_spi_freq[i].speed_hz) + break; + + if (amd_spi->speed_hz == amd_spi_freq[i].speed_hz) + return 0; + + amd_spi->speed_hz = amd_spi_freq[i].speed_hz; + + alt_spd = (amd_spi_freq[i].enable_val << AMD_SPI_ALT_SPD_SHIFT) + & AMD_SPI_ALT_SPD_MASK; + amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, alt_spd, + AMD_SPI_ALT_SPD_MASK); + + if (amd_spi->speed_hz == AMD_SPI_MAX_HZ) + amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, 1, + AMD_SPI_SPI100_MASK); + + if (amd_spi_freq[i].spd7_val) { + spd7_val = (amd_spi_freq[i].spd7_val << AMD_SPI_SPD7_SHIFT) + & AMD_SPI_SPD7_MASK; + amd_spi_setclear_reg32(amd_spi, AMD_SPI_SPEED_REG, spd7_val, + AMD_SPI_SPD7_MASK); + } + + return 0; +} + static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, struct spi_master *master, struct spi_message *message) { struct spi_transfer *xfer = NULL; - u8 cmd_opcode; + struct spi_device *spi = message->spi; + u8 cmd_opcode = 0, fifo_pos = AMD_SPI_FIFO_BASE; u8 *buf = NULL; - u32 m_cmd = 0; u32 i = 0; u32 tx_len = 0, rx_len = 0; list_for_each_entry(xfer, &message->transfers, transfer_list) { - if (xfer->rx_buf) - m_cmd = AMD_SPI_XFER_RX; - if (xfer->tx_buf) - m_cmd = AMD_SPI_XFER_TX; + if (xfer->speed_hz) + amd_set_spi_freq(amd_spi, xfer->speed_hz); + else + amd_set_spi_freq(amd_spi, spi->max_speed_hz); - if (m_cmd & AMD_SPI_XFER_TX) { + if (xfer->tx_buf) { buf = (u8 *)xfer->tx_buf; - tx_len = xfer->len - 1; - cmd_opcode = *(u8 *)xfer->tx_buf; - buf++; - amd_spi_set_opcode(amd_spi, cmd_opcode); + if (!tx_len) { + cmd_opcode = *(u8 *)xfer->tx_buf; + buf++; + xfer->len--; + } + tx_len += xfer->len; /* Write data into the FIFO. */ - for (i = 0; i < tx_len; i++) { - iowrite8(buf[i], ((u8 __iomem *)amd_spi->io_remap_addr + - AMD_SPI_FIFO_BASE + i)); - } + for (i = 0; i < xfer->len; i++) + amd_spi_writereg8(amd_spi, fifo_pos + i, buf[i]); - amd_spi_set_tx_count(amd_spi, tx_len); - amd_spi_clear_fifo_ptr(amd_spi); - /* Execute command */ - amd_spi_execute_opcode(amd_spi); - } - if (m_cmd & AMD_SPI_XFER_RX) { - /* - * Store no. of bytes to be received from - * FIFO - */ - rx_len = xfer->len; - buf = (u8 *)xfer->rx_buf; - amd_spi_set_rx_count(amd_spi, rx_len); - amd_spi_clear_fifo_ptr(amd_spi); - /* Execute command */ - 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(amd_spi, AMD_SPI_FIFO_BASE + tx_len + i); + fifo_pos += xfer->len; } + + /* Store no. of bytes to be received from FIFO */ + if (xfer->rx_buf) + rx_len += xfer->len; + } + + if (!buf) { + message->status = -EINVAL; + goto fin_msg; + } + + amd_spi_set_opcode(amd_spi, cmd_opcode); + amd_spi_set_tx_count(amd_spi, tx_len); + amd_spi_set_rx_count(amd_spi, rx_len); + + /* Execute command */ + message->status = amd_spi_execute_opcode(amd_spi); + if (message->status) + goto fin_msg; + + if (rx_len) { + message->status = amd_spi_busy_wait(amd_spi); + if (message->status) + goto fin_msg; + + list_for_each_entry(xfer, &message->transfers, transfer_list) + if (xfer->rx_buf) { + buf = (u8 *)xfer->rx_buf; + /* Read data from FIFO to receive buffer */ + for (i = 0; i < xfer->len; i++) + buf[i] = amd_spi_readreg8(amd_spi, fifo_pos + i); + fifo_pos += xfer->len; + } } /* Update statistics */ message->actual_length = tx_len + rx_len + 1; - /* complete the transaction */ - message->status = 0; +fin_msg: switch (amd_spi->version) { case AMD_SPI_V1: break; @@ -260,7 +355,7 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, spi_finalize_current_message(master); - return 0; + return message->status; } static int amd_spi_master_transfer(struct spi_master *master, @@ -275,9 +370,7 @@ static int amd_spi_master_transfer(struct spi_master *master, * Extract spi_transfers from the spi message and * program the controller. */ - amd_spi_fifo_xfer(amd_spi, master, msg); - - return 0; + return amd_spi_fifo_xfer(amd_spi, master, msg); } static size_t amd_spi_max_transfer_size(struct spi_device *spi) @@ -312,6 +405,8 @@ static int amd_spi_probe(struct platform_device *pdev) master->num_chipselect = 4; master->mode_bits = 0; master->flags = SPI_MASTER_HALF_DUPLEX; + master->max_speed_hz = AMD_SPI_MAX_HZ; + master->min_speed_hz = AMD_SPI_MIN_HZ; master->setup = amd_spi_master_setup; master->transfer_one_message = amd_spi_master_transfer; master->max_transfer_size = amd_spi_max_transfer_size; diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 3e891bf22470..a334e89add86 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -736,10 +736,8 @@ static int aspeed_spi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); aspi->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(aspi->regs)) { - dev_err(dev, "missing AHB register window\n"); + if (IS_ERR(aspi->regs)) return PTR_ERR(aspi->regs); - } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); aspi->ahb_base = devm_ioremap_resource(dev, res); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index e12ab5b43f34..447230547945 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1645,7 +1645,7 @@ static int cqspi_probe(struct platform_device *pdev) pm_runtime_enable(dev); ret = pm_runtime_resume_and_get(dev); if (ret < 0) - return ret; + goto probe_pm_failed; ret = clk_prepare_enable(cqspi->clk); if (ret) { @@ -1740,6 +1740,7 @@ probe_reset_failed: clk_disable_unprepare(cqspi->clk); probe_clk_failed: pm_runtime_put_sync(dev); +probe_pm_failed: pm_runtime_disable(dev); return ret; } diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 3ab19be83095..9e187f9c6c95 100644 --- a/drivers/spi/spi-cadence-xspi.c +++ b/drivers/spi/spi-cadence-xspi.c @@ -565,10 +565,8 @@ static int cdns_xspi_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sdma"); cdns_xspi->sdmabase = devm_ioremap_resource(dev, res); - if (IS_ERR(cdns_xspi->sdmabase)) { - dev_err(dev, "Failed to remap SDMA address\n"); + if (IS_ERR(cdns_xspi->sdmabase)) return PTR_ERR(cdns_xspi->sdmabase); - } cdns_xspi->sdmasize = resource_size(res); cdns_xspi->auxbase = devm_platform_ioremap_resource_byname(pdev, "aux"); diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index c06553416123..3fb89dee595e 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -293,8 +293,10 @@ static int dw_spi_bt1_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = dw_spi_add_host(&pdev->dev, dws); - if (ret) + if (ret) { + pm_runtime_disable(&pdev->dev); goto err_disable_clk; + } platform_set_drvdata(pdev, dwsbt1); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index f87d97ccd2d6..99edddf9958b 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -955,7 +955,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ret = spi_register_controller(master); if (ret) { - dev_err(&master->dev, "problem registering spi master\n"); + dev_err_probe(dev, ret, "problem registering spi master\n"); goto err_dma_exit; } diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index fd004c9db9dc..a33e547b7d39 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1294,8 +1294,7 @@ static int dspi_probe(struct platform_device *pdev) else ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) { ret = PTR_ERR(base); goto out_ctlr_put; diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 19b1f3d881b0..e8c1c8a4c6c8 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -855,8 +855,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) init_completion(&fsl_lpspi->xfer_done); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fsl_lpspi->base = devm_ioremap_resource(&pdev->dev, res); + fsl_lpspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(fsl_lpspi->base)) { ret = PTR_ERR(fsl_lpspi->base); goto out_controller_put; @@ -912,7 +911,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { - dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret); + dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n"); goto free_dma; } @@ -947,11 +946,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev) static int __maybe_unused fsl_lpspi_suspend(struct device *dev) { - int ret; - pinctrl_pm_select_sleep_state(dev); - ret = pm_runtime_force_suspend(dev); - return ret; + return pm_runtime_force_suspend(dev); } static int __maybe_unused fsl_lpspi_resume(struct device *dev) diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 46ae46a944c5..85cc71ba624a 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -867,8 +867,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, q); /* find the resources */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); - q->iobase = devm_ioremap_resource(dev, res); + q->iobase = devm_platform_ioremap_resource_byname(pdev, "QuadSPI"); if (IS_ERR(q->iobase)) { ret = PTR_ERR(q->iobase); goto err_put_ctrl; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index bdf94cc7be1a..731624f157fc 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -111,32 +111,6 @@ static void fsl_spi_change_mode(struct spi_device *spi) local_irq_restore(flags); } -static void fsl_spi_chipselect(struct spi_device *spi, int value) -{ - struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - struct fsl_spi_platform_data *pdata; - struct spi_mpc8xxx_cs *cs = spi->controller_state; - - pdata = spi->dev.parent->parent->platform_data; - - if (value == BITBANG_CS_INACTIVE) { - if (pdata->cs_control) - pdata->cs_control(spi, false); - } - - if (value == BITBANG_CS_ACTIVE) { - mpc8xxx_spi->rx_shift = cs->rx_shift; - mpc8xxx_spi->tx_shift = cs->tx_shift; - mpc8xxx_spi->get_rx = cs->get_rx; - mpc8xxx_spi->get_tx = cs->get_tx; - - fsl_spi_change_mode(spi); - - if (pdata->cs_control) - pdata->cs_control(spi, true); - } -} - static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift, int bits_per_word, int msb_first) { @@ -354,15 +328,11 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, return mpc8xxx_spi->count; } -static int fsl_spi_do_one_msg(struct spi_master *master, - struct spi_message *m) +static int fsl_spi_prepare_message(struct spi_controller *ctlr, + struct spi_message *m) { - struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); - struct spi_device *spi = m->spi; - struct spi_transfer *t, *first; - unsigned int cs_change; - const int nsecs = 50; - int status, last_bpw; + struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(ctlr); + struct spi_transfer *t; /* * In CPU mode, optimize large byte transfers to use larger @@ -378,62 +348,30 @@ static int fsl_spi_do_one_msg(struct spi_master *master, t->bits_per_word = 16; } } + return 0; +} - /* Don't allow changes if CS is active */ - cs_change = 1; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (cs_change) - first = t; - cs_change = t->cs_change; - if (first->speed_hz != t->speed_hz) { - dev_err(&spi->dev, - "speed_hz cannot change while CS is active\n"); - return -EINVAL; - } - } - - last_bpw = -1; - cs_change = 1; - status = -EINVAL; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (cs_change || last_bpw != t->bits_per_word) - status = fsl_spi_setup_transfer(spi, t); - if (status < 0) - break; - last_bpw = t->bits_per_word; - - if (cs_change) { - fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (t->len) - status = fsl_spi_bufs(spi, t, m->is_dma_mapped); - if (status) { - status = -EMSGSIZE; - break; - } - m->actual_length += t->len; - - spi_transfer_delay_exec(t); - - if (cs_change) { - ndelay(nsecs); - fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } - } +static int fsl_spi_transfer_one(struct spi_controller *controller, + struct spi_device *spi, + struct spi_transfer *t) +{ + int status; - m->status = status; + status = fsl_spi_setup_transfer(spi, t); + if (status < 0) + return status; + if (t->len) + status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma); + if (status > 0) + return -EMSGSIZE; - if (status || !cs_change) { - ndelay(nsecs); - fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); - } + return status; +} - fsl_spi_setup_transfer(spi, NULL); - spi_finalize_current_message(master); - return 0; +static int fsl_spi_unprepare_message(struct spi_controller *controller, + struct spi_message *msg) +{ + return fsl_spi_setup_transfer(msg->spi, NULL); } static int fsl_spi_setup(struct spi_device *spi) @@ -482,9 +420,6 @@ static int fsl_spi_setup(struct spi_device *spi) return retval; } - /* Initialize chipselect - might be active for SPI_CS_HIGH mode */ - fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); - return 0; } @@ -557,9 +492,7 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) u32 slvsel; u16 cs = spi->chip_select; - if (spi->cs_gpiod) { - gpiod_set_value(spi->cs_gpiod, on); - } else if (cs < mpc8xxx_spi->native_chipselects) { + if (cs < mpc8xxx_spi->native_chipselects) { slvsel = mpc8xxx_spi_read_reg(®_base->slvsel); slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); mpc8xxx_spi_write_reg(®_base->slvsel, slvsel); @@ -568,7 +501,6 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) static void fsl_spi_grlib_probe(struct device *dev) { - struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base; @@ -588,7 +520,18 @@ static void fsl_spi_grlib_probe(struct device *dev) mpc8xxx_spi_write_reg(®_base->slvsel, 0xffffffff); } master->num_chipselect = mpc8xxx_spi->native_chipselects; - pdata->cs_control = fsl_spi_grlib_cs_control; + master->set_cs = fsl_spi_grlib_cs_control; +} + +static void fsl_spi_cs_control(struct spi_device *spi, bool on) +{ + struct device *dev = spi->dev.parent->parent; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); + + if (WARN_ON_ONCE(!pinfo->immr_spi_cs)) + return; + iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs); } static struct spi_master *fsl_spi_probe(struct device *dev, @@ -613,8 +556,11 @@ static struct spi_master *fsl_spi_probe(struct device *dev, master->setup = fsl_spi_setup; master->cleanup = fsl_spi_cleanup; - master->transfer_one_message = fsl_spi_do_one_msg; + master->prepare_message = fsl_spi_prepare_message; + master->transfer_one = fsl_spi_transfer_one; + master->unprepare_message = fsl_spi_unprepare_message; master->use_gpio_descriptors = true; + master->set_cs = fsl_spi_cs_control; mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi->max_bits_per_word = 32; @@ -688,21 +634,6 @@ err: return ERR_PTR(ret); } -static void fsl_spi_cs_control(struct spi_device *spi, bool on) -{ - if (spi->cs_gpiod) { - gpiod_set_value(spi->cs_gpiod, on); - } else { - struct device *dev = spi->dev.parent->parent; - struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); - - if (WARN_ON_ONCE(!pinfo->immr_spi_cs)) - return; - iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs); - } -} - static int of_fsl_spi_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; @@ -744,12 +675,10 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) ret = gpiod_count(dev, "cs"); if (ret < 0) ret = 0; - if (ret == 0 && !spisel_boot) { + if (ret == 0 && !spisel_boot) pdata->max_chipselect = 1; - } else { + else pdata->max_chipselect = ret + spisel_boot; - pdata->cs_control = fsl_spi_cs_control; - } } ret = of_address_to_resource(np, 0, &mem); diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c index 9ea355f7d64f..15b110183839 100644 --- a/drivers/spi/spi-gxp.c +++ b/drivers/spi/spi-gxp.c @@ -254,7 +254,6 @@ static int gxp_spifi_probe(struct platform_device *pdev) const struct gxp_spi_data *data; struct spi_controller *ctlr; struct gxp_spi *spifi; - struct resource *res; int ret; data = of_device_get_match_data(&pdev->dev); @@ -269,18 +268,15 @@ static int gxp_spifi_probe(struct platform_device *pdev) spifi->data = data; spifi->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - spifi->reg_base = devm_ioremap_resource(&pdev->dev, res); + spifi->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(spifi->reg_base)) return PTR_ERR(spifi->reg_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - spifi->dat_base = devm_ioremap_resource(&pdev->dev, res); + spifi->dat_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(spifi->dat_base)) return PTR_ERR(spifi->dat_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - spifi->dir_base = devm_ioremap_resource(&pdev->dev, res); + spifi->dir_base = devm_platform_ioremap_resource(pdev, 2); if (IS_ERR(spifi->dir_base)) return PTR_ERR(spifi->dir_base); diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 71376b6df89d..bfd12247f173 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -730,11 +730,9 @@ static int img_spfi_resume(struct device *dev) struct img_spfi *spfi = spi_master_get_devdata(master); int ret; - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put_noidle(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } spfi_reset(spfi); pm_runtime_put(dev); diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 66063687ae27..55f4ee2db002 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -116,6 +116,22 @@ #define ERASE_64K_OPCODE_SHIFT 16 #define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT) +/* Flash descriptor fields */ +#define FLVALSIG_MAGIC 0x0ff0a55a +#define FLMAP0_NC_MASK GENMASK(9, 8) +#define FLMAP0_NC_SHIFT 8 +#define FLMAP0_FCBA_MASK GENMASK(7, 0) + +#define FLCOMP_C0DEN_MASK GENMASK(3, 0) +#define FLCOMP_C0DEN_512K 0x00 +#define FLCOMP_C0DEN_1M 0x01 +#define FLCOMP_C0DEN_2M 0x02 +#define FLCOMP_C0DEN_4M 0x03 +#define FLCOMP_C0DEN_8M 0x04 +#define FLCOMP_C0DEN_16M 0x05 +#define FLCOMP_C0DEN_32M 0x06 +#define FLCOMP_C0DEN_64M 0x07 + #define INTEL_SPI_TIMEOUT 5000 /* ms */ #define INTEL_SPI_FIFO_SZ 64 @@ -129,6 +145,7 @@ * @master: Pointer to the SPI controller structure * @nregions: Maximum number of regions * @pr_num: Maximum number of protected range registers + * @chip0_size: Size of the first flash chip in bytes * @locked: Is SPI setting locked * @swseq_reg: Use SW sequencer in register reads/writes * @swseq_erase: Use SW sequencer in erase operation @@ -146,6 +163,7 @@ struct intel_spi { struct spi_controller *master; size_t nregions; size_t pr_num; + size_t chip0_size; bool locked; bool swseq_reg; bool swseq_erase; @@ -158,6 +176,7 @@ struct intel_spi_mem_op { struct spi_mem_op mem_op; u32 replacement_op; int (*exec_op)(struct intel_spi *ispi, + const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op); }; @@ -441,7 +460,16 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len, return 0; } -static int intel_spi_read_reg(struct intel_spi *ispi, +static u32 intel_spi_chip_addr(const struct intel_spi *ispi, + const struct spi_mem *mem) +{ + /* Pick up the correct start address */ + if (!mem) + return 0; + return mem->spi->chip_select == 1 ? ispi->chip0_size : 0; +} + +static int intel_spi_read_reg(struct intel_spi *ispi, const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op) { @@ -449,8 +477,7 @@ static int intel_spi_read_reg(struct intel_spi *ispi, u8 opcode = op->cmd.opcode; int ret; - /* Address of the first chip */ - writel(0, ispi->base + FADDR); + writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR); if (ispi->swseq_reg) ret = intel_spi_sw_cycle(ispi, opcode, nbytes, @@ -464,7 +491,7 @@ static int intel_spi_read_reg(struct intel_spi *ispi, return intel_spi_read_block(ispi, op->data.buf.in, nbytes); } -static int intel_spi_write_reg(struct intel_spi *ispi, +static int intel_spi_write_reg(struct intel_spi *ispi, const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op) { @@ -511,7 +538,7 @@ static int intel_spi_write_reg(struct intel_spi *ispi, if (opcode == SPINOR_OP_WRDI) return 0; - writel(0, ispi->base + FADDR); + writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR); /* Write the value beforehand */ ret = intel_spi_write_block(ispi, op->data.buf.out, nbytes); @@ -524,13 +551,13 @@ static int intel_spi_write_reg(struct intel_spi *ispi, return intel_spi_hw_cycle(ispi, opcode, nbytes); } -static int intel_spi_read(struct intel_spi *ispi, +static int intel_spi_read(struct intel_spi *ispi, const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op) { - void *read_buf = op->data.buf.in; + u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val; size_t block_size, nbytes = op->data.nbytes; - u32 addr = op->addr.val; + void *read_buf = op->data.buf.in; u32 val, status; int ret; @@ -585,13 +612,13 @@ static int intel_spi_read(struct intel_spi *ispi, return 0; } -static int intel_spi_write(struct intel_spi *ispi, +static int intel_spi_write(struct intel_spi *ispi, const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op) { + u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val; size_t block_size, nbytes = op->data.nbytes; const void *write_buf = op->data.buf.out; - u32 addr = op->addr.val; u32 val, status; int ret; @@ -648,12 +675,12 @@ static int intel_spi_write(struct intel_spi *ispi, return 0; } -static int intel_spi_erase(struct intel_spi *ispi, +static int intel_spi_erase(struct intel_spi *ispi, const struct spi_mem *mem, const struct intel_spi_mem_op *iop, const struct spi_mem_op *op) { + u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val; u8 opcode = op->cmd.opcode; - u32 addr = op->addr.val; u32 val, status; int ret; @@ -765,7 +792,7 @@ static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *o if (!iop) return -EOPNOTSUPP; - return iop->exec_op(ispi, iop, op); + return iop->exec_op(ispi, mem, iop, op); } static const char *intel_spi_get_name(struct spi_mem *mem) @@ -805,7 +832,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, op.data.nbytes = len; op.data.buf.in = buf; - ret = iop->exec_op(ispi, iop, &op); + ret = iop->exec_op(ispi, desc->mem, iop, &op); return ret ? ret : len; } @@ -821,7 +848,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs op.data.nbytes = len; op.data.buf.out = buf; - ret = iop->exec_op(ispi, iop, &op); + ret = iop->exec_op(ispi, desc->mem, iop, &op); return ret ? ret : len; } @@ -1073,6 +1100,7 @@ static int intel_spi_init(struct intel_spi *ispi) ispi->pregs = ispi->base + CNL_PR; ispi->nregions = CNL_FREG_NUM; ispi->pr_num = CNL_PR_NUM; + erase_64k = true; break; default: @@ -1226,10 +1254,98 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, } } +static int intel_spi_read_desc(struct intel_spi *ispi) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 0), + SPI_MEM_OP_ADDR(3, 0, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(0, NULL, 0)); + u32 buf[2], nc, fcba, flcomp; + ssize_t ret; + + op.addr.val = 0x10; + op.data.buf.in = buf; + op.data.nbytes = sizeof(buf); + + ret = intel_spi_read(ispi, NULL, NULL, &op); + if (ret) { + dev_warn(ispi->dev, "failed to read descriptor\n"); + return ret; + } + + dev_dbg(ispi->dev, "FLVALSIG=0x%08x\n", buf[0]); + dev_dbg(ispi->dev, "FLMAP0=0x%08x\n", buf[1]); + + if (buf[0] != FLVALSIG_MAGIC) { + dev_warn(ispi->dev, "descriptor signature not valid\n"); + return -ENODEV; + } + + fcba = (buf[1] & FLMAP0_FCBA_MASK) << 4; + dev_dbg(ispi->dev, "FCBA=%#x\n", fcba); + + op.addr.val = fcba; + op.data.buf.in = &flcomp; + op.data.nbytes = sizeof(flcomp); + + ret = intel_spi_read(ispi, NULL, NULL, &op); + if (ret) { + dev_warn(ispi->dev, "failed to read FLCOMP\n"); + return -ENODEV; + } + + dev_dbg(ispi->dev, "FLCOMP=0x%08x\n", flcomp); + + switch (flcomp & FLCOMP_C0DEN_MASK) { + case FLCOMP_C0DEN_512K: + ispi->chip0_size = SZ_512K; + break; + case FLCOMP_C0DEN_1M: + ispi->chip0_size = SZ_1M; + break; + case FLCOMP_C0DEN_2M: + ispi->chip0_size = SZ_2M; + break; + case FLCOMP_C0DEN_4M: + ispi->chip0_size = SZ_4M; + break; + case FLCOMP_C0DEN_8M: + ispi->chip0_size = SZ_8M; + break; + case FLCOMP_C0DEN_16M: + ispi->chip0_size = SZ_16M; + break; + case FLCOMP_C0DEN_32M: + ispi->chip0_size = SZ_32M; + break; + case FLCOMP_C0DEN_64M: + ispi->chip0_size = SZ_64M; + break; + default: + return -EINVAL; + } + + dev_dbg(ispi->dev, "chip0 size %zd KB\n", ispi->chip0_size / SZ_1K); + + nc = (buf[1] & FLMAP0_NC_MASK) >> FLMAP0_NC_SHIFT; + if (!nc) + ispi->master->num_chipselect = 1; + else if (nc == 1) + ispi->master->num_chipselect = 2; + else + return -EINVAL; + + dev_dbg(ispi->dev, "%u flash components found\n", + ispi->master->num_chipselect); + return 0; +} + static int intel_spi_populate_chip(struct intel_spi *ispi) { struct flash_platform_data *pdata; struct spi_board_info chip; + int ret; pdata = devm_kzalloc(ispi->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1247,7 +1363,23 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) snprintf(chip.modalias, 8, "spi-nor"); chip.platform_data = pdata; - return spi_new_device(ispi->master, &chip) ? 0 : -ENODEV; + if (!spi_new_device(ispi->master, &chip)) + return -ENODEV; + + /* Add the second chip if present */ + if (ispi->master->num_chipselect < 2) + return 0; + + ret = intel_spi_read_desc(ispi); + if (ret) + return ret; + + chip.platform_data = NULL; + chip.chip_select = 1; + + if (!spi_new_device(ispi->master, &chip)) + return -ENODEV; + return 0; } /** diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 4d4f77a186a9..dd7de8fa37d0 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -313,6 +313,33 @@ static struct spi_test spi_tests[] = { }, }, }, + { + .description = "three tx+rx transfers with overlapping cache lines", + .fill_option = FILL_COUNT_8, + /* + * This should be large enough for the controller driver to + * choose to transfer it with DMA. + */ + .iterate_len = { 512, -1 }, + .iterate_transfer_mask = BIT(1), + .transfer_count = 3, + .transfers = { + { + .len = 1, + .tx_buf = TX(0), + .rx_buf = RX(0), + }, + { + .tx_buf = TX(1), + .rx_buf = RX(1), + }, + { + .len = 1, + .tx_buf = TX(513), + .rx_buf = RX(513), + }, + }, + }, { /* end of tests sequence */ } }; diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index e4cb52e1fe26..bad201510a99 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -537,7 +537,7 @@ static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw, struct clk_divider *divider = to_clk_divider(hw); struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); - if (!spicc->master->cur_msg || !spicc->master->busy) + if (!spicc->master->cur_msg) return 0; return clk_divider_ops.recalc_rate(hw, parent_rate); @@ -549,7 +549,7 @@ static int meson_spicc_pow2_determine_rate(struct clk_hw *hw, struct clk_divider *divider = to_clk_divider(hw); struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); - if (!spicc->master->cur_msg || !spicc->master->busy) + if (!spicc->master->cur_msg) return -EINVAL; return clk_divider_ops.determine_rate(hw, req); @@ -561,13 +561,13 @@ static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_divider *divider = to_clk_divider(hw); struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider); - if (!spicc->master->cur_msg || !spicc->master->busy) + if (!spicc->master->cur_msg) return -EINVAL; return clk_divider_ops.set_rate(hw, rate, parent_rate); } -const struct clk_ops meson_spicc_pow2_clk_ops = { +static const struct clk_ops meson_spicc_pow2_clk_ops = { .recalc_rate = meson_spicc_pow2_recalc_rate, .determine_rate = meson_spicc_pow2_determine_rate, .set_rate = meson_spicc_pow2_set_rate, diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c new file mode 100644 index 000000000000..19a6a46829f6 --- /dev/null +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Microchip coreQSPI QSPI controller driver + * + * Copyright (C) 2018-2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Naga Sureshkumar Relli <nagasuresh.relli@microchip.com> + * + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + +/* + * QSPI Control register mask defines + */ +#define CONTROL_ENABLE BIT(0) +#define CONTROL_MASTER BIT(1) +#define CONTROL_XIP BIT(2) +#define CONTROL_XIPADDR BIT(3) +#define CONTROL_CLKIDLE BIT(10) +#define CONTROL_SAMPLE_MASK GENMASK(12, 11) +#define CONTROL_MODE0 BIT(13) +#define CONTROL_MODE12_MASK GENMASK(15, 14) +#define CONTROL_MODE12_EX_RO BIT(14) +#define CONTROL_MODE12_EX_RW BIT(15) +#define CONTROL_MODE12_FULL GENMASK(15, 14) +#define CONTROL_FLAGSX4 BIT(16) +#define CONTROL_CLKRATE_MASK GENMASK(27, 24) +#define CONTROL_CLKRATE_SHIFT 24 + +/* + * QSPI Frames register mask defines + */ +#define FRAMES_TOTALBYTES_MASK GENMASK(15, 0) +#define FRAMES_CMDBYTES_MASK GENMASK(24, 16) +#define FRAMES_CMDBYTES_SHIFT 16 +#define FRAMES_SHIFT 25 +#define FRAMES_IDLE_MASK GENMASK(29, 26) +#define FRAMES_IDLE_SHIFT 26 +#define FRAMES_FLAGBYTE BIT(30) +#define FRAMES_FLAGWORD BIT(31) + +/* + * QSPI Interrupt Enable register mask defines + */ +#define IEN_TXDONE BIT(0) +#define IEN_RXDONE BIT(1) +#define IEN_RXAVAILABLE BIT(2) +#define IEN_TXAVAILABLE BIT(3) +#define IEN_RXFIFOEMPTY BIT(4) +#define IEN_TXFIFOFULL BIT(5) + +/* + * QSPI Status register mask defines + */ +#define STATUS_TXDONE BIT(0) +#define STATUS_RXDONE BIT(1) +#define STATUS_RXAVAILABLE BIT(2) +#define STATUS_TXAVAILABLE BIT(3) +#define STATUS_RXFIFOEMPTY BIT(4) +#define STATUS_TXFIFOFULL BIT(5) +#define STATUS_READY BIT(7) +#define STATUS_FLAGSX4 BIT(8) +#define STATUS_MASK GENMASK(8, 0) + +#define BYTESUPPER_MASK GENMASK(31, 16) +#define BYTESLOWER_MASK GENMASK(15, 0) + +#define MAX_DIVIDER 16 +#define MIN_DIVIDER 0 +#define MAX_DATA_CMD_LEN 256 + +/* QSPI ready time out value */ +#define TIMEOUT_MS 500 + +/* + * QSPI Register offsets. + */ +#define REG_CONTROL (0x00) +#define REG_FRAMES (0x04) +#define REG_IEN (0x0c) +#define REG_STATUS (0x10) +#define REG_DIRECT_ACCESS (0x14) +#define REG_UPPER_ACCESS (0x18) +#define REG_RX_DATA (0x40) +#define REG_TX_DATA (0x44) +#define REG_X4_RX_DATA (0x48) +#define REG_X4_TX_DATA (0x4c) +#define REG_FRAMESUP (0x50) + +/** + * struct mchp_coreqspi - Defines qspi driver instance + * @regs: Virtual address of the QSPI controller registers + * @clk: QSPI Operating clock + * @data_completion: completion structure + * @op_lock: lock access to the device + * @txbuf: TX buffer + * @rxbuf: RX buffer + * @irq: IRQ number + * @tx_len: Number of bytes left to transfer + * @rx_len: Number of bytes left to receive + */ +struct mchp_coreqspi { + void __iomem *regs; + struct clk *clk; + struct completion data_completion; + struct mutex op_lock; /* lock access to the device */ + u8 *txbuf; + u8 *rxbuf; + int irq; + int tx_len; + int rx_len; +}; + +static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) +{ + u32 control = readl_relaxed(qspi->regs + REG_CONTROL); + + /* + * The operating mode can be configured based on the command that needs to be send. + * bits[15:14]: Sets whether multiple bit SPI operates in normal, extended or full modes. + * 00: Normal (single DQ0 TX and single DQ1 RX lines) + * 01: Extended RO (command and address bytes on DQ0 only) + * 10: Extended RW (command byte on DQ0 only) + * 11: Full. (command and address are on all DQ lines) + * bit[13]: Sets whether multiple bit SPI uses 2 or 4 bits of data + * 0: 2-bits (BSPI) + * 1: 4-bits (QSPI) + */ + if (op->data.buswidth == 4 || op->data.buswidth == 2) { + control &= ~CONTROL_MODE12_MASK; + if (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0)) + control |= CONTROL_MODE12_EX_RO; + else if (op->cmd.buswidth == 1) + control |= CONTROL_MODE12_EX_RW; + else + control |= CONTROL_MODE12_FULL; + + control |= CONTROL_MODE0; + } else { + control &= ~(CONTROL_MODE12_MASK | + CONTROL_MODE0); + } + + writel_relaxed(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi) +{ + u32 control, data; + + if (!qspi->rx_len) + return; + + control = readl_relaxed(qspi->regs + REG_CONTROL); + + /* + * Read 4-bytes from the SPI FIFO in single transaction and then read + * the reamaining data byte wise. + */ + control |= CONTROL_FLAGSX4; + writel_relaxed(control, qspi->regs + REG_CONTROL); + + while (qspi->rx_len >= 4) { + while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) + ; + data = readl_relaxed(qspi->regs + REG_X4_RX_DATA); + *(u32 *)qspi->rxbuf = data; + qspi->rxbuf += 4; + qspi->rx_len -= 4; + } + + control &= ~CONTROL_FLAGSX4; + writel_relaxed(control, qspi->regs + REG_CONTROL); + + while (qspi->rx_len--) { + while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) + ; + data = readl_relaxed(qspi->regs + REG_RX_DATA); + *qspi->rxbuf++ = (data & 0xFF); + } +} + +static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) +{ + u32 control, data; + + control = readl_relaxed(qspi->regs + REG_CONTROL); + control |= CONTROL_FLAGSX4; + writel_relaxed(control, qspi->regs + REG_CONTROL); + + while (qspi->tx_len >= 4) { + while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) + ; + data = *(u32 *)qspi->txbuf; + qspi->txbuf += 4; + qspi->tx_len -= 4; + writel_relaxed(data, qspi->regs + REG_X4_TX_DATA); + } + + control &= ~CONTROL_FLAGSX4; + writel_relaxed(control, qspi->regs + REG_CONTROL); + + while (qspi->tx_len--) { + while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) + ; + data = *qspi->txbuf++; + writel_relaxed(data, qspi->regs + REG_TX_DATA); + } +} + +static void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi) +{ + u32 mask = IEN_TXDONE | + IEN_RXDONE | + IEN_RXAVAILABLE; + + writel_relaxed(mask, qspi->regs + REG_IEN); +} + +static void mchp_coreqspi_disable_ints(struct mchp_coreqspi *qspi) +{ + writel_relaxed(0, qspi->regs + REG_IEN); +} + +static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id) +{ + struct mchp_coreqspi *qspi = (struct mchp_coreqspi *)dev_id; + irqreturn_t ret = IRQ_NONE; + int intfield = readl_relaxed(qspi->regs + REG_STATUS) & STATUS_MASK; + + if (intfield == 0) + return ret; + + if (intfield & IEN_TXDONE) { + writel_relaxed(IEN_TXDONE, qspi->regs + REG_STATUS); + ret = IRQ_HANDLED; + } + + if (intfield & IEN_RXAVAILABLE) { + writel_relaxed(IEN_RXAVAILABLE, qspi->regs + REG_STATUS); + mchp_coreqspi_read_op(qspi); + ret = IRQ_HANDLED; + } + + if (intfield & IEN_RXDONE) { + writel_relaxed(IEN_RXDONE, qspi->regs + REG_STATUS); + complete(&qspi->data_completion); + ret = IRQ_HANDLED; + } + + return ret; +} + +static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi) +{ + unsigned long clk_hz; + u32 control, baud_rate_val = 0; + + clk_hz = clk_get_rate(qspi->clk); + if (!clk_hz) + return -EINVAL; + + baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz); + if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) { + dev_err(&spi->dev, + "could not configure the clock for spi clock %d Hz & system clock %ld Hz\n", + spi->max_speed_hz, clk_hz); + return -EINVAL; + } + + control = readl_relaxed(qspi->regs + REG_CONTROL); + control |= baud_rate_val << CONTROL_CLKRATE_SHIFT; + writel_relaxed(control, qspi->regs + REG_CONTROL); + control = readl_relaxed(qspi->regs + REG_CONTROL); + + if ((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) + control |= CONTROL_CLKIDLE; + else + control &= ~CONTROL_CLKIDLE; + + writel_relaxed(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static int mchp_coreqspi_setup_op(struct spi_device *spi_dev) +{ + struct spi_controller *ctlr = spi_dev->master; + struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr); + u32 control = readl_relaxed(qspi->regs + REG_CONTROL); + + control |= (CONTROL_MASTER | CONTROL_ENABLE); + control &= ~CONTROL_CLKIDLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) +{ + u32 idle_cycles = 0; + int total_bytes, cmd_bytes, frames, ctrl; + + cmd_bytes = op->cmd.nbytes + op->addr.nbytes; + total_bytes = cmd_bytes + op->data.nbytes; + + /* + * As per the coreQSPI IP spec,the number of command and data bytes are + * controlled by the frames register for each SPI sequence. This supports + * the SPI flash memory read and writes sequences as below. so configure + * the cmd and total bytes accordingly. + * --------------------------------------------------------------------- + * TOTAL BYTES | CMD BYTES | What happens | + * ______________________________________________________________________ + * | | | + * 1 | 1 | The SPI core will transmit a single byte | + * | | and receive data is discarded | + * | | | + * 1 | 0 | The SPI core will transmit a single byte | + * | | and return a single byte | + * | | | + * 10 | 4 | The SPI core will transmit 4 command | + * | | bytes discarding the receive data and | + * | | transmits 6 dummy bytes returning the 6 | + * | | received bytes and return a single byte | + * | | | + * 10 | 10 | The SPI core will transmit 10 command | + * | | | + * 10 | 0 | The SPI core will transmit 10 command | + * | | bytes and returning 10 received bytes | + * ______________________________________________________________________ + */ + if (!(op->data.dir == SPI_MEM_DATA_IN)) + cmd_bytes = total_bytes; + + frames = total_bytes & BYTESUPPER_MASK; + writel_relaxed(frames, qspi->regs + REG_FRAMESUP); + frames = total_bytes & BYTESLOWER_MASK; + frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT; + + if (op->dummy.buswidth) + idle_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; + + frames |= idle_cycles << FRAMES_IDLE_SHIFT; + ctrl = readl_relaxed(qspi->regs + REG_CONTROL); + + if (ctrl & CONTROL_MODE12_MASK) + frames |= (1 << FRAMES_SHIFT); + + frames |= FRAMES_FLAGWORD; + writel_relaxed(frames, qspi->regs + REG_FRAMES); +} + +static int mchp_qspi_wait_for_ready(struct spi_mem *mem) +{ + struct mchp_coreqspi *qspi = spi_controller_get_devdata + (mem->spi->master); + u32 status; + int ret; + + ret = readl_poll_timeout(qspi->regs + REG_STATUS, status, + (status & STATUS_READY), 0, + TIMEOUT_MS); + if (ret) { + dev_err(&mem->spi->dev, + "Timeout waiting on QSPI ready.\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct mchp_coreqspi *qspi = spi_controller_get_devdata + (mem->spi->master); + u32 address = op->addr.val; + u8 opcode = op->cmd.opcode; + u8 opaddr[5]; + int err, i; + + mutex_lock(&qspi->op_lock); + err = mchp_qspi_wait_for_ready(mem); + if (err) + goto error; + + err = mchp_coreqspi_setup_clock(qspi, mem->spi); + if (err) + goto error; + + err = mchp_coreqspi_set_mode(qspi, op); + if (err) + goto error; + + reinit_completion(&qspi->data_completion); + mchp_coreqspi_config_op(qspi, op); + if (op->cmd.opcode) { + qspi->txbuf = &opcode; + qspi->rxbuf = NULL; + qspi->tx_len = op->cmd.nbytes; + qspi->rx_len = 0; + mchp_coreqspi_write_op(qspi, false); + } + + qspi->txbuf = &opaddr[0]; + if (op->addr.nbytes) { + for (i = 0; i < op->addr.nbytes; i++) + qspi->txbuf[i] = address >> (8 * (op->addr.nbytes - i - 1)); + + qspi->rxbuf = NULL; + qspi->tx_len = op->addr.nbytes; + qspi->rx_len = 0; + mchp_coreqspi_write_op(qspi, false); + } + + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_OUT) { + qspi->txbuf = (u8 *)op->data.buf.out; + qspi->rxbuf = NULL; + qspi->rx_len = 0; + qspi->tx_len = op->data.nbytes; + mchp_coreqspi_write_op(qspi, true); + } else { + qspi->txbuf = NULL; + qspi->rxbuf = (u8 *)op->data.buf.in; + qspi->rx_len = op->data.nbytes; + qspi->tx_len = 0; + } + } + + mchp_coreqspi_enable_ints(qspi); + + if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(1000))) + err = -ETIMEDOUT; + +error: + mutex_unlock(&qspi->op_lock); + mchp_coreqspi_disable_ints(qspi); + + return err; +} + +static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + + if ((op->data.buswidth == 4 || op->data.buswidth == 2) && + (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0))) { + /* + * If the command and address are on DQ0 only, then this + * controller doesn't support sending data on dual and + * quad lines. but it supports reading data on dual and + * quad lines with same configuration as command and + * address on DQ0. + * i.e. The control register[15:13] :EX_RO(read only) is + * meant only for the command and address are on DQ0 but + * not to write data, it is just to read. + * Ex: 0x34h is Quad Load Program Data which is not + * supported. Then the spi-mem layer will iterate over + * each command and it will chose the supported one. + */ + if (op->data.dir == SPI_MEM_DATA_OUT) + return false; + } + + return true; +} + +static int mchp_coreqspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + if (op->data.dir == SPI_MEM_DATA_OUT || op->data.dir == SPI_MEM_DATA_IN) { + if (op->data.nbytes > MAX_DATA_CMD_LEN) + op->data.nbytes = MAX_DATA_CMD_LEN; + } + + return 0; +} + +static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { + .adjust_op_size = mchp_coreqspi_adjust_op_size, + .supports_op = mchp_coreqspi_supports_op, + .exec_op = mchp_coreqspi_exec_op, +}; + +static int mchp_coreqspi_probe(struct platform_device *pdev) +{ + struct spi_controller *ctlr; + struct mchp_coreqspi *qspi; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + int ret; + + ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*qspi)); + if (!ctlr) + return dev_err_probe(&pdev->dev, -ENOMEM, + "unable to allocate master for QSPI controller\n"); + + qspi = spi_controller_get_devdata(ctlr); + platform_set_drvdata(pdev, qspi); + + qspi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qspi->regs)) + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs), + "failed to map registers\n"); + + qspi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(qspi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk), + "could not get clock\n"); + + ret = clk_prepare_enable(qspi->clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to enable clock\n"); + + init_completion(&qspi->data_completion); + mutex_init(&qspi->op_lock); + + qspi->irq = platform_get_irq(pdev, 0); + if (qspi->irq < 0) { + ret = qspi->irq; + goto out; + } + + ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr, + IRQF_SHARED, pdev->name, qspi); + if (ret) { + dev_err(&pdev->dev, "request_irq failed %d\n", ret); + goto out; + } + + ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + ctlr->mem_ops = &mchp_coreqspi_mem_ops; + ctlr->setup = mchp_coreqspi_setup_op; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD | + SPI_TX_DUAL | SPI_TX_QUAD; + ctlr->dev.of_node = np; + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret) { + dev_err_probe(&pdev->dev, ret, + "spi_register_controller failed\n"); + goto out; + } + + return 0; + +out: + clk_disable_unprepare(qspi->clk); + + return ret; +} + +static int mchp_coreqspi_remove(struct platform_device *pdev) +{ + struct mchp_coreqspi *qspi = platform_get_drvdata(pdev); + u32 control = readl_relaxed(qspi->regs + REG_CONTROL); + + mchp_coreqspi_disable_ints(qspi); + control &= ~CONTROL_ENABLE; + writel_relaxed(control, qspi->regs + REG_CONTROL); + clk_disable_unprepare(qspi->clk); + + return 0; +} + +static const struct of_device_id mchp_coreqspi_of_match[] = { + { .compatible = "microchip,coreqspi-rtl-v2" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mchp_coreqspi_of_match); + +static struct platform_driver mchp_coreqspi_driver = { + .probe = mchp_coreqspi_probe, + .driver = { + .name = "microchip,coreqspi", + .of_match_table = mchp_coreqspi_of_match, + }, + .remove = mchp_coreqspi_remove, +}; +module_platform_driver(mchp_coreqspi_driver); + +MODULE_AUTHOR("Naga Sureshkumar Relli <nagasuresh.relli@microchip.com"); +MODULE_DESCRIPTION("Microchip coreQSPI QSPI controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index ce4385330b19..d352844c798c 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -548,12 +548,12 @@ static int mchp_corespi_probe(struct platform_device *pdev) IRQF_SHARED, dev_name(&pdev->dev), master); if (ret) return dev_err_probe(&pdev->dev, ret, - "could not request irq: %d\n", ret); + "could not request irq\n"); spi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(spi->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), - "could not get clk: %d\n", ret); + "could not get clk\n"); ret = clk_prepare_enable(spi->clk); if (ret) diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index bc5e36fd4288..cb075c1acbee 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -11,13 +11,14 @@ */ #include <linux/module.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/of_platform.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/spi/spi.h> #include <linux/io.h> -#include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -89,7 +90,7 @@ struct mpc52xx_spi { const u8 *tx_buf; int cs_change; int gpio_cs_count; - unsigned int *gpio_cs; + struct gpio_desc **gpio_cs; }; /* @@ -101,9 +102,10 @@ static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value) if (ms->gpio_cs_count > 0) { cs = ms->message->spi->chip_select; - gpio_set_value(ms->gpio_cs[cs], value ? 0 : 1); - } else + gpiod_set_value(ms->gpio_cs[cs], value); + } else { out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08); + } } /* @@ -385,10 +387,10 @@ static int mpc52xx_spi_probe(struct platform_device *op) { struct spi_master *master; struct mpc52xx_spi *ms; + struct gpio_desc *gpio_cs; void __iomem *regs; u8 ctrl1; int rc, i = 0; - int gpio_cs; /* MMIO registers */ dev_dbg(&op->dev, "probing mpc5200 SPI device\n"); @@ -438,7 +440,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) ms->irq1 = irq_of_parse_and_map(op->dev.of_node, 1); ms->state = mpc52xx_spi_fsmstate_idle; ms->ipb_freq = mpc5xxx_get_bus_frequency(&op->dev); - ms->gpio_cs_count = of_gpio_count(op->dev.of_node); + ms->gpio_cs_count = gpiod_count(&op->dev, NULL); if (ms->gpio_cs_count > 0) { master->num_chipselect = ms->gpio_cs_count; ms->gpio_cs = kmalloc_array(ms->gpio_cs_count, @@ -450,23 +452,16 @@ static int mpc52xx_spi_probe(struct platform_device *op) } for (i = 0; i < ms->gpio_cs_count; i++) { - gpio_cs = of_get_gpio(op->dev.of_node, i); - if (!gpio_is_valid(gpio_cs)) { - dev_err(&op->dev, - "could not parse the gpio field in oftree\n"); - rc = -ENODEV; - goto err_gpio; - } - - rc = gpio_request(gpio_cs, dev_name(&op->dev)); + gpio_cs = gpiod_get_index(&op->dev, + NULL, i, GPIOD_OUT_LOW); + rc = PTR_ERR_OR_ZERO(gpio_cs); if (rc) { dev_err(&op->dev, - "can't request spi cs gpio #%d on gpio line %d\n", - i, gpio_cs); + "failed to get spi cs gpio #%d: %d\n", + i, rc); goto err_gpio; } - gpio_direction_output(gpio_cs, 1); ms->gpio_cs[i] = gpio_cs; } } @@ -507,7 +502,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) dev_err(&ms->master->dev, "initialization failed\n"); err_gpio: while (i-- > 0) - gpio_free(ms->gpio_cs[i]); + gpiod_put(ms->gpio_cs[i]); kfree(ms->gpio_cs); err_alloc_gpio: @@ -528,7 +523,7 @@ static int mpc52xx_spi_remove(struct platform_device *op) free_irq(ms->irq1, ms); for (i = 0; i < ms->gpio_cs_count; i++) - gpio_free(ms->gpio_cs[i]); + gpiod_put(ms->gpio_cs[i]); kfree(ms->gpio_cs); spi_unregister_master(master); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 0a3b9f7eed30..11aeae7fe7fc 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1184,6 +1184,11 @@ static int mtk_spi_probe(struct platform_device *pdev) if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; + if (mdata->dev_comp->ipm_design) + dma_set_max_seg_size(dev, SZ_16M); + else + dma_set_max_seg_size(dev, SZ_256K); + ret = devm_request_irq(dev, irq, mtk_spi_interrupt, IRQF_TRIGGER_NONE, dev_name(dev), master); if (ret) diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c index b4b9b7309b5e..c4cc8e2f85e2 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -55,7 +55,6 @@ struct mt7621_spi { void __iomem *base; unsigned int sys_freq; unsigned int speed; - struct clk *clk; int pending_write; }; @@ -327,7 +326,6 @@ static int mt7621_spi_probe(struct platform_device *pdev) struct spi_controller *master; struct mt7621_spi *rs; void __iomem *base; - int status = 0; struct clk *clk; int ret; @@ -339,21 +337,14 @@ static int mt7621_spi_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n", - status); - return PTR_ERR(clk); - } - - status = clk_prepare_enable(clk); - if (status) - return status; + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "unable to get SYS clock\n"); master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs)); if (!master) { dev_info(&pdev->dev, "master allocation failed\n"); - clk_disable_unprepare(clk); return -ENOMEM; } @@ -369,38 +360,18 @@ static int mt7621_spi_probe(struct platform_device *pdev) rs = spi_controller_get_devdata(master); rs->base = base; - rs->clk = clk; rs->master = master; - rs->sys_freq = clk_get_rate(rs->clk); + rs->sys_freq = clk_get_rate(clk); rs->pending_write = 0; dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); ret = device_reset(&pdev->dev); if (ret) { dev_err(&pdev->dev, "SPI reset failed!\n"); - clk_disable_unprepare(clk); return ret; } - ret = spi_register_controller(master); - if (ret) - clk_disable_unprepare(clk); - - return ret; -} - -static int mt7621_spi_remove(struct platform_device *pdev) -{ - struct spi_controller *master; - struct mt7621_spi *rs; - - master = dev_get_drvdata(&pdev->dev); - rs = spi_controller_get_devdata(master); - - spi_unregister_controller(master); - clk_disable_unprepare(rs->clk); - - return 0; + return devm_spi_register_controller(&pdev->dev, master); } MODULE_ALIAS("platform:" DRIVER_NAME); @@ -411,7 +382,6 @@ static struct platform_driver mt7621_spi_driver = { .of_match_table = mt7621_spi_match, }, .probe = mt7621_spi_probe, - .remove = mt7621_spi_remove, }; module_platform_driver(mt7621_spi_driver); diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index 1668a347e003..7f2e4d1b0d43 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -443,6 +443,7 @@ static int npcm_pspi_remove(struct platform_device *pdev) static const struct of_device_id npcm_pspi_match[] = { { .compatible = "nuvoton,npcm750-pspi", .data = NULL }, + { .compatible = "nuvoton,npcm845-pspi", .data = NULL }, {} }; MODULE_DEVICE_TABLE(of, npcm_pspi_match); diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 2b0301fc971c..d6a65a989ef8 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -588,7 +588,7 @@ static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f) { int ret; - if (is_acpi_node(f->dev->fwnode)) + if (is_acpi_node(dev_fwnode(f->dev))) return 0; ret = clk_prepare_enable(f->clk_en); @@ -606,7 +606,7 @@ static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f) static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f) { - if (is_acpi_node(f->dev->fwnode)) + if (is_acpi_node(dev_fwnode(f->dev))) return 0; clk_disable_unprepare(f->clk); @@ -1100,7 +1100,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, f); /* find the resources - configuration register address space */ - if (is_acpi_node(f->dev->fwnode)) + if (is_acpi_node(dev_fwnode(f->dev))) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); else res = platform_get_resource_byname(pdev, @@ -1113,7 +1113,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) } /* find the resources - controller memory mapped space */ - if (is_acpi_node(f->dev->fwnode)) + if (is_acpi_node(dev_fwnode(f->dev))) res = platform_get_resource(pdev, IORESOURCE_MEM, 1); else res = platform_get_resource_byname(pdev, diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 20b047172965..061f7394e5b9 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -412,6 +412,7 @@ static int omap1_spi100k_probe(struct platform_device *pdev) return status; err_fck: + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(spi100k->fck); err_ick: clk_disable_unprepare(spi100k->ick); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index c42e59df38fe..6ba9b0d7710b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1509,10 +1509,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) } status = platform_get_irq(pdev, 0); - if (status == -EPROBE_DEFER) - goto free_master; if (status < 0) { - dev_err(&pdev->dev, "no irq resource found\n"); + dev_err_probe(&pdev->dev, status, "no irq resource found\n"); goto free_master; } init_completion(&mcspi->txdone); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index c8e079d7e541..2bf21c2e7a52 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1856,10 +1856,8 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev) static int pxa2xx_spi_runtime_resume(struct device *dev) { struct driver_data *drv_data = dev_get_drvdata(dev); - int status; - status = clk_prepare_enable(drv_data->ssp->clk); - return status; + return clk_prepare_enable(drv_data->ssp->clk); } #endif diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 00d6084306b4..7d89510dc3f0 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1198,8 +1198,10 @@ static int spi_qup_pm_resume_runtime(struct device *device) return ret; ret = clk_prepare_enable(controller->cclk); - if (ret) + if (ret) { + clk_disable_unprepare(controller->iclk); return ret; + } /* Disable clocks auto gaiting */ config = readl_relaxed(controller->base + QUP_CONFIG); @@ -1245,14 +1247,25 @@ static int spi_qup_resume(struct device *device) return ret; ret = clk_prepare_enable(controller->cclk); - if (ret) + if (ret) { + clk_disable_unprepare(controller->iclk); return ret; + } ret = spi_qup_set_state(controller, QUP_STATE_RESET); if (ret) - return ret; + goto disable_clk; - return spi_master_resume(master); + ret = spi_master_resume(master); + if (ret) + goto disable_clk; + + return 0; + +disable_clk: + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + return ret; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 660aa866af06..ef25b5e93900 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -449,7 +449,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) struct spi_master *master; int err = 0; - master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) { dev_err(&pdev->dev, "No memory for spi_master\n"); return -ENOMEM; @@ -463,8 +463,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) if (pdata == NULL) { dev_err(&pdev->dev, "No platform data supplied\n"); - err = -ENOENT; - goto err_no_pdata; + return -ENOENT; } platform_set_drvdata(pdev, hw); @@ -499,29 +498,24 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) /* find and map our resources */ hw->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hw->regs)) { - err = PTR_ERR(hw->regs); - goto err_no_pdata; - } + if (IS_ERR(hw->regs)) + return PTR_ERR(hw->regs); hw->irq = platform_get_irq(pdev, 0); - if (hw->irq < 0) { - err = -ENOENT; - goto err_no_pdata; - } + if (hw->irq < 0) + return -ENOENT; err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_no_pdata; + return err; } hw->clk = devm_clk_get(&pdev->dev, "spi"); if (IS_ERR(hw->clk)) { dev_err(&pdev->dev, "No clock for device\n"); - err = PTR_ERR(hw->clk); - goto err_no_pdata; + return PTR_ERR(hw->clk); } s3c24xx_spi_initialsetup(hw); @@ -539,8 +533,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) err_register: clk_disable(hw->clk); - err_no_pdata: - spi_master_put(hw->master); return err; } diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 7f346866614a..71d324ec9a70 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -84,6 +84,7 @@ #define S3C64XX_SPI_ST_TX_FIFORDY (1<<0) #define S3C64XX_SPI_PACKET_CNT_EN (1<<16) +#define S3C64XX_SPI_PACKET_CNT_MASK GENMASK(15, 0) #define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4) #define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3) @@ -389,8 +390,8 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) if (sdd->rx_dma.ch && sdd->tx_dma.ch) { dma_release_channel(sdd->rx_dma.ch); dma_release_channel(sdd->tx_dma.ch); - sdd->rx_dma.ch = 0; - sdd->tx_dma.ch = 0; + sdd->rx_dma.ch = NULL; + sdd->tx_dma.ch = NULL; } return 0; @@ -711,6 +712,13 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, return 0; } +static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi) +{ + struct spi_controller *ctlr = spi->controller; + + return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX; +} + static int s3c64xx_spi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -1152,6 +1160,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; + master->max_transfer_size = s3c64xx_spi_max_transfer_size; master->num_chipselect = sci->num_cs; master->use_gpio_descriptors = true; master->dma_alignment = 8; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index d0012b30410c..9bca3d076f05 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1085,6 +1085,7 @@ static const struct of_device_id sh_msiof_match[] = { { .compatible = "renesas,rcar-gen2-msiof", .data = &rcar_gen2_data }, { .compatible = "renesas,msiof-r8a7796", .data = &rcar_gen3_data }, { .compatible = "renesas,rcar-gen3-msiof", .data = &rcar_gen3_data }, + { .compatible = "renesas,rcar-gen4-msiof", .data = &rcar_gen3_data }, { .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */ {}, }; diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index f3fe92300639..9131660c1afb 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -15,6 +15,7 @@ #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> #include <linux/platform_device.h> @@ -355,10 +356,10 @@ static int stm32_qspi_get_mode(u8 buswidth) return buswidth; } -static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) +static int stm32_qspi_send(struct spi_device *spi, const struct spi_mem_op *op) { - struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); - struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; + struct stm32_qspi *qspi = spi_controller_get_devdata(spi->master); + struct stm32_qspi_flash *flash = &qspi->flash[spi->chip_select]; u32 ccr, cr; int timeout, err = 0, err_poll_status = 0; @@ -465,7 +466,7 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op * qspi->fmode = CCR_FMODE_APM; qspi->status_timeout = timeout_ms; - ret = stm32_qspi_send(mem, op); + ret = stm32_qspi_send(mem->spi, op); mutex_unlock(&qspi->lock); pm_runtime_mark_last_busy(qspi->dev); @@ -489,7 +490,7 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) else qspi->fmode = CCR_FMODE_INDW; - ret = stm32_qspi_send(mem, op); + ret = stm32_qspi_send(mem->spi, op); mutex_unlock(&qspi->lock); pm_runtime_mark_last_busy(qspi->dev); @@ -545,7 +546,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, else qspi->fmode = CCR_FMODE_INDR; - ret = stm32_qspi_send(desc->mem, &op); + ret = stm32_qspi_send(desc->mem->spi, &op); mutex_unlock(&qspi->lock); pm_runtime_mark_last_busy(qspi->dev); @@ -554,12 +555,96 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, return ret ?: len; } +static int stm32_qspi_transfer_one_message(struct spi_controller *ctrl, + struct spi_message *msg) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); + struct spi_transfer *transfer; + struct spi_device *spi = msg->spi; + struct spi_mem_op op; + int ret = 0; + + if (!spi->cs_gpiod) + return -EOPNOTSUPP; + + ret = pm_runtime_resume_and_get(qspi->dev); + if (ret < 0) + return ret; + + mutex_lock(&qspi->lock); + + gpiod_set_value_cansleep(spi->cs_gpiod, true); + + list_for_each_entry(transfer, &msg->transfers, transfer_list) { + u8 dummy_bytes = 0; + + memset(&op, 0, sizeof(op)); + + dev_dbg(qspi->dev, "tx_buf:%p tx_nbits:%d rx_buf:%p rx_nbits:%d len:%d dummy_data:%d\n", + transfer->tx_buf, transfer->tx_nbits, + transfer->rx_buf, transfer->rx_nbits, + transfer->len, transfer->dummy_data); + + /* + * QSPI hardware supports dummy bytes transfer. + * If current transfer is dummy byte, merge it with the next + * transfer in order to take into account QSPI block constraint + */ + if (transfer->dummy_data) { + op.dummy.buswidth = transfer->tx_nbits; + op.dummy.nbytes = transfer->len; + dummy_bytes = transfer->len; + + /* if happens, means that message is not correctly built */ + if (list_is_last(&transfer->transfer_list, &msg->transfers)) { + ret = -EINVAL; + goto end_of_transfer; + } + + transfer = list_next_entry(transfer, transfer_list); + } + + op.data.nbytes = transfer->len; + + if (transfer->rx_buf) { + qspi->fmode = CCR_FMODE_INDR; + op.data.buswidth = transfer->rx_nbits; + op.data.dir = SPI_MEM_DATA_IN; + op.data.buf.in = transfer->rx_buf; + } else { + qspi->fmode = CCR_FMODE_INDW; + op.data.buswidth = transfer->tx_nbits; + op.data.dir = SPI_MEM_DATA_OUT; + op.data.buf.out = transfer->tx_buf; + } + + ret = stm32_qspi_send(spi, &op); + if (ret) + goto end_of_transfer; + + msg->actual_length += transfer->len + dummy_bytes; + } + +end_of_transfer: + gpiod_set_value_cansleep(spi->cs_gpiod, false); + + mutex_unlock(&qspi->lock); + + msg->status = ret; + spi_finalize_current_message(ctrl); + + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + + return ret; +} + static int stm32_qspi_setup(struct spi_device *spi) { struct spi_controller *ctrl = spi->master; struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); struct stm32_qspi_flash *flash; - u32 presc; + u32 presc, mode; int ret; if (ctrl->busy) @@ -568,6 +653,16 @@ static int stm32_qspi_setup(struct spi_device *spi) if (!spi->max_speed_hz) return -EINVAL; + mode = spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL); + if ((mode == SPI_TX_OCTAL || mode == SPI_RX_OCTAL) || + ((mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) && + gpiod_count(qspi->dev, "cs") == -ENOENT)) { + dev_err(qspi->dev, "spi-rx-bus-width\\/spi-tx-bus-width\\/cs-gpios\n"); + dev_err(qspi->dev, "configuration not supported\n"); + + return -EINVAL; + } + ret = pm_runtime_resume_and_get(qspi->dev); if (ret < 0) return ret; @@ -580,6 +675,16 @@ static int stm32_qspi_setup(struct spi_device *spi) mutex_lock(&qspi->lock); qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; + + /* + * Dual flash mode is only enable in case SPI_TX_OCTAL and SPI_TX_OCTAL + * are both set in spi->mode and "cs-gpios" properties is found in DT + */ + if (mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) { + qspi->cr_reg |= CR_DFM; + dev_dbg(qspi->dev, "Dual flash mode enable"); + } + writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); /* set dcr fsize to max address */ @@ -741,11 +846,13 @@ static int stm32_qspi_probe(struct platform_device *pdev) mutex_init(&qspi->lock); - ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD - | SPI_TX_DUAL | SPI_TX_QUAD; + ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL + | SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_OCTAL; ctrl->setup = stm32_qspi_setup; ctrl->bus_num = -1; ctrl->mem_ops = &stm32_qspi_mem_ops; + ctrl->use_gpio_descriptors = true; + ctrl->transfer_one_message = stm32_qspi_transfer_one_message; ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; ctrl->dev.of_node = dev->of_node; diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 523edfdf5dcd..7377d3b81302 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -421,7 +421,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -EINVAL; } - master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) return -ENODEV; @@ -439,10 +439,8 @@ static int xilinx_spi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); xspi->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(xspi->regs)) { - ret = PTR_ERR(xspi->regs); - goto put_master; - } + if (IS_ERR(xspi->regs)) + return PTR_ERR(xspi->regs); master->bus_num = pdev->id; master->num_chipselect = num_cs; @@ -472,14 +470,13 @@ static int xilinx_spi_probe(struct platform_device *pdev) xspi->irq = platform_get_irq(pdev, 0); if (xspi->irq < 0 && xspi->irq != -ENXIO) { - ret = xspi->irq; - goto put_master; + return xspi->irq; } else if (xspi->irq >= 0) { /* Register for SPI Interrupt */ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, dev_name(&pdev->dev), xspi); if (ret) - goto put_master; + return ret; } /* SPI controller initializations */ @@ -488,7 +485,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) ret = spi_bitbang_start(&xspi->bitbang); if (ret) { dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); - goto put_master; + return ret; } dev_info(&pdev->dev, "at %pR, irq=%d\n", res, xspi->irq); @@ -500,11 +497,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); return 0; - -put_master: - spi_master_put(master); - - return ret; } static int xilinx_spi_remove(struct platform_device *pdev) diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index fc2b5eb7d614..2fa7608f94cd 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -83,7 +83,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev) int ret; struct spi_master *master; - master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi)); + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi)); if (!master) return -ENOMEM; @@ -97,30 +97,24 @@ static int xtfpga_spi_probe(struct platform_device *pdev) xspi->bitbang.chipselect = xtfpga_spi_chipselect; xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word; xspi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(xspi->regs)) { - ret = PTR_ERR(xspi->regs); - goto err; - } + if (IS_ERR(xspi->regs)) + return PTR_ERR(xspi->regs); xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); usleep_range(1000, 2000); if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) { dev_err(&pdev->dev, "Device stuck in busy state\n"); - ret = -EBUSY; - goto err; + return -EBUSY; } ret = spi_bitbang_start(&xspi->bitbang); if (ret < 0) { dev_err(&pdev->dev, "spi_bitbang_start failed\n"); - goto err; + return ret; } platform_set_drvdata(pdev, master); return 0; -err: - spi_master_put(master); - return ret; } static int xtfpga_spi_remove(struct platform_device *pdev) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 30e82f968639..5f9aedd1f0b6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -753,7 +753,7 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, proxy->max_speed_hz = chip->max_speed_hz; proxy->mode = chip->mode; proxy->irq = chip->irq; - strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); + strscpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); proxy->dev.platform_data = (void *) chip->platform_data; proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; @@ -1010,9 +1010,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) } #ifdef CONFIG_HAS_DMA -int spi_map_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, void *buf, size_t len, - enum dma_data_direction dir) +static int spi_map_buf_attrs(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir, unsigned long attrs) { const bool vmalloced_buf = is_vmalloc_addr(buf); unsigned int max_seg_size = dma_get_max_seg_size(dev); @@ -1078,28 +1078,41 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev, sg = sg_next(sg); } - ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir); - if (!ret) - ret = -ENOMEM; + ret = dma_map_sgtable(dev, sgt, dir, attrs); if (ret < 0) { sg_free_table(sgt); return ret; } - sgt->nents = ret; - return 0; } -void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, - struct sg_table *sgt, enum dma_data_direction dir) +int spi_map_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) +{ + return spi_map_buf_attrs(ctlr, dev, sgt, buf, len, dir, 0); +} + +static void spi_unmap_buf_attrs(struct spi_controller *ctlr, + struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir, + unsigned long attrs) { if (sgt->orig_nents) { - dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir); + dma_unmap_sgtable(dev, sgt, dir, attrs); sg_free_table(sgt); + sgt->orig_nents = 0; + sgt->nents = 0; } } +void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir) +{ + spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0); +} + static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) { struct device *tx_dev, *rx_dev; @@ -1124,29 +1137,37 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) rx_dev = ctlr->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* The sync is done before each transfer. */ + unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) continue; if (xfer->tx_buf != NULL) { - ret = spi_map_buf(ctlr, tx_dev, &xfer->tx_sg, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); + ret = spi_map_buf_attrs(ctlr, tx_dev, &xfer->tx_sg, + (void *)xfer->tx_buf, + xfer->len, DMA_TO_DEVICE, + attrs); if (ret != 0) return ret; } if (xfer->rx_buf != NULL) { - ret = spi_map_buf(ctlr, rx_dev, &xfer->rx_sg, - xfer->rx_buf, xfer->len, - DMA_FROM_DEVICE); + ret = spi_map_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, + xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE, attrs); if (ret != 0) { - spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, - DMA_TO_DEVICE); + spi_unmap_buf_attrs(ctlr, tx_dev, + &xfer->tx_sg, DMA_TO_DEVICE, + attrs); + return ret; } } } + ctlr->cur_rx_dma_dev = rx_dev; + ctlr->cur_tx_dma_dev = tx_dev; ctlr->cur_msg_mapped = true; return 0; @@ -1154,38 +1175,60 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) { + struct device *rx_dev = ctlr->cur_rx_dma_dev; + struct device *tx_dev = ctlr->cur_tx_dma_dev; struct spi_transfer *xfer; - struct device *tx_dev, *rx_dev; if (!ctlr->cur_msg_mapped || !ctlr->can_dma) return 0; - if (ctlr->dma_tx) - tx_dev = ctlr->dma_tx->device->dev; - else if (ctlr->dma_map_dev) - tx_dev = ctlr->dma_map_dev; - else - tx_dev = ctlr->dev.parent; - - if (ctlr->dma_rx) - rx_dev = ctlr->dma_rx->device->dev; - else if (ctlr->dma_map_dev) - rx_dev = ctlr->dma_map_dev; - else - rx_dev = ctlr->dev.parent; - list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* The sync has already been done after each transfer. */ + unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; + if (!ctlr->can_dma(ctlr, msg->spi, xfer)) continue; - spi_unmap_buf(ctlr, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, + DMA_FROM_DEVICE, attrs); + spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg, + DMA_TO_DEVICE, attrs); } ctlr->cur_msg_mapped = false; return 0; } + +static void spi_dma_sync_for_device(struct spi_controller *ctlr, + struct spi_transfer *xfer) +{ + struct device *rx_dev = ctlr->cur_rx_dma_dev; + struct device *tx_dev = ctlr->cur_tx_dma_dev; + + if (!ctlr->cur_msg_mapped) + return; + + if (xfer->tx_sg.orig_nents) + dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); + if (xfer->rx_sg.orig_nents) + dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); +} + +static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, + struct spi_transfer *xfer) +{ + struct device *rx_dev = ctlr->cur_rx_dma_dev; + struct device *tx_dev = ctlr->cur_tx_dma_dev; + + if (!ctlr->cur_msg_mapped) + return; + + if (xfer->rx_sg.orig_nents) + dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + if (xfer->tx_sg.orig_nents) + dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); +} #else /* !CONFIG_HAS_DMA */ static inline int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) @@ -1198,6 +1241,16 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr, { return 0; } + +static void spi_dma_sync_for_device(struct spi_controller *ctrl, + struct spi_transfer *xfer) +{ +} + +static void spi_dma_sync_for_cpu(struct spi_controller *ctrl, + struct spi_transfer *xfer) +{ +} #endif /* !CONFIG_HAS_DMA */ static inline int spi_unmap_msg(struct spi_controller *ctlr, @@ -1435,7 +1488,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, struct spi_statistics __percpu *statm = ctlr->pcpu_statistics; struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics; - spi_set_cs(msg->spi, true, false); + xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list); + spi_set_cs(msg->spi, !xfer->cs_off, false); SPI_STATISTICS_INCREMENT_FIELD(statm, messages); SPI_STATISTICS_INCREMENT_FIELD(stats, messages); @@ -1455,8 +1509,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, reinit_completion(&ctlr->xfer_completion); fallback_pio: + spi_dma_sync_for_device(ctlr, xfer); ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { + spi_dma_sync_for_cpu(ctlr, xfer); + if (ctlr->cur_msg_mapped && (xfer->error & SPI_TRANS_FAIL_NO_START)) { __spi_unmap_msg(ctlr, msg); @@ -1479,6 +1536,8 @@ fallback_pio: if (ret < 0) msg->status = ret; } + + spi_dma_sync_for_cpu(ctlr, xfer); } else { if (xfer->len) dev_err(&msg->spi->dev, @@ -1503,10 +1562,15 @@ fallback_pio: &msg->transfers)) { keep_cs = true; } else { - spi_set_cs(msg->spi, false, false); + if (!xfer->cs_off) + spi_set_cs(msg->spi, false, false); _spi_transfer_cs_change_delay(msg, xfer); - spi_set_cs(msg->spi, true, false); + if (!list_next_entry(xfer, transfer_list)->cs_off) + spi_set_cs(msg->spi, true, false); } + } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) && + xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) { + spi_set_cs(msg->spi, xfer->cs_off, false); } msg->actual_length += xfer->len; @@ -1587,6 +1651,15 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr, trace_spi_message_start(msg); + ret = spi_split_transfers_maxsize(ctlr, msg, + spi_max_transfer_size(msg->spi), + GFP_KERNEL | GFP_DMA); + if (ret) { + msg->status = ret; + spi_finalize_current_message(ctlr); + return ret; + } + if (ctlr->prepare_message) { ret = ctlr->prepare_message(ctlr, msg); if (ret) { @@ -2329,7 +2402,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi, goto err_out; } - strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias)); + strscpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias)); /* Use provided chip-select for ancillary device */ ancillary->chip_select = chip_select; @@ -2725,7 +2798,7 @@ static ssize_t slave_store(struct device *dev, struct device_attribute *attr, if (!spi) return -ENOMEM; - strlcpy(spi->modalias, name, sizeof(spi->modalias)); + strscpy(spi->modalias, name, sizeof(spi->modalias)); rc = spi_add_device(spi); if (rc) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f089ee1ead58..fbf8c0d95968 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -378,6 +378,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * @cleanup: frees controller-specific state * @can_dma: determine whether this controller supports DMA * @dma_map_dev: device which can be used for DMA mapping + * @cur_rx_dma_dev: device which is currently used for RX DMA mapping + * @cur_tx_dma_dev: device which is currently used for TX DMA mapping * @queued: whether this controller is providing an internal message queue * @kworker: pointer to thread struct for message pump * @pump_messages: work struct for scheduling work to the message pump @@ -610,6 +612,8 @@ struct spi_controller { struct spi_device *spi, struct spi_transfer *xfer); struct device *dma_map_dev; + struct device *cur_rx_dma_dev; + struct device *cur_tx_dma_dev; /* * These hooks are for drivers that want to use the generic @@ -848,6 +852,7 @@ struct spi_res { * @bits_per_word: select a bits_per_word other than the device default * for this transfer. If 0 the default (from @spi_device) is used. * @dummy_data: indicates transfer is dummy bytes transfer. + * @cs_off: performs the transfer with chipselect off. * @cs_change: affects chipselect after this transfer completes * @cs_change_delay: delay between cs deassert and assert when * @cs_change is set and @spi_transfer is not the last in @spi_message @@ -958,6 +963,7 @@ struct spi_transfer { struct sg_table rx_sg; unsigned dummy_data:1; + unsigned cs_off:1; unsigned cs_change:1; unsigned tx_nbits:3; unsigned rx_nbits:3; |