diff --git a/Documentation/devicetree/bindings/spi/atmel,quadspi.yaml b/Documentation/devicetree/bindings/spi/atmel,quadspi.yaml index 30ab42c95c08..36c698ced99b 100644 --- a/Documentation/devicetree/bindings/spi/atmel,quadspi.yaml +++ b/Documentation/devicetree/bindings/spi/atmel,quadspi.yaml @@ -22,6 +22,7 @@ properties: - microchip,sama7d65-ospi - microchip,sama7g5-qspi - microchip,sama7g5-ospi + - microchip,lan9691-qspi reg: items: diff --git a/Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml b/Documentation/devicetree/bindings/spi/cavium,octeon-3010-spi.yaml new file mode 100644 index 000000000000..f0b708e1ccbb --- /dev/null +++ b/Documentation/devicetree/bindings/spi/cavium,octeon-3010-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/cavium,octeon-3010-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cavium, Inc. OCTEON SoC SPI master controller + +description: + The Cavium OCTEON SPI controller is an SPI master controller found in + OCTEON SoCs. + +maintainers: + - Rob Herring + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + const: cavium,octeon-3010-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + spi@1070000001000 { + compatible = "cavium,octeon-3010-spi"; + reg = <0x10700 0x00001000 0x0 0x100>; + interrupts = <0 58>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + compatible = "st,m95256", "atmel,at25"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml b/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml index 16a0598c6d03..ccf841f194c0 100644 --- a/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml +++ b/Documentation/devicetree/bindings/spi/nxp,imx94-xspi.yaml @@ -30,6 +30,16 @@ properties: - const: base - const: mmap + dmas: + items: + - description: Transmit DMA + - description: Receive DMA + + dma-names: + items: + - const: tx + - const: rx + interrupts: items: - description: interrupt for EENV0 diff --git a/Documentation/devicetree/bindings/spi/qcom,sa8255p-geni-spi.yaml b/Documentation/devicetree/bindings/spi/qcom,sa8255p-geni-spi.yaml new file mode 100644 index 000000000000..6552303a4f52 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/qcom,sa8255p-geni-spi.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/qcom,sa8255p-geni-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GENI based Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) + +maintainers: + - Praveen Talari + +properties: + compatible: + oneOf: + - const: qcom,sa8255p-geni-spi + - items: + - const: qcom,sa8797p-geni-spi + - const: qcom,sa8255p-geni-spi + + reg: + maxItems: 1 + + dmas: + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 2 + + power-domain-names: + items: + - const: power + - const: perf + +required: + - compatible + - reg + - interrupts + - power-domains + - power-domain-names + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@888000 { + compatible = "qcom,sa8255p-geni-spi"; + reg = <0x888000 0x4000>; + interrupts = ; + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dma-names = "tx", "rx"; + power-domains = <&scmi0_pd 0>, <&scmi0_dvfs 0>; + power-domain-names = "power", "perf"; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-octeon.txt b/Documentation/devicetree/bindings/spi/spi-octeon.txt deleted file mode 100644 index 431add192342..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-octeon.txt +++ /dev/null @@ -1,33 +0,0 @@ -Cavium, Inc. OCTEON SOC SPI master controller. - -Required properties: -- compatible : "cavium,octeon-3010-spi" -- reg : The register base for the controller. -- interrupts : One interrupt, used by the controller. -- #address-cells : <1>, as required by generic SPI binding. -- #size-cells : <0>, also as required by generic SPI binding. - -Child nodes as per the generic SPI binding. - -Example: - - spi@1070000001000 { - compatible = "cavium,octeon-3010-spi"; - reg = <0x10700 0x00001000 0x0 0x100>; - interrupts = <0 58>; - #address-cells = <1>; - #size-cells = <0>; - - eeprom@0 { - compatible = "st,m95256", "atmel,at25"; - reg = <0>; - spi-max-frequency = <5000000>; - spi-cpha; - spi-cpol; - - pagesize = <64>; - size = <32768>; - address-width = <16>; - }; - }; - diff --git a/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml index 3f1a27efff80..ee57739b73b8 100644 --- a/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml +++ b/Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml @@ -50,6 +50,9 @@ properties: minItems: 1 maxItems: 2 + power-domains: + maxItems: 1 + required: - compatible - reg diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 107fa2057654..873bfbd6b2b7 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -7,6 +7,11 @@ /* Disable MMIO tracing to prevent excessive logging of unwanted MMIO traces */ #define __DISABLE_TRACE_MMIO__ +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL_GPL(geni_se_regs); + #include #include #include diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8782514bb89b..bb3773f99ad9 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -189,7 +189,7 @@ config SPI_AT91_USART config SPI_ATMEL_QUADSPI tristate "Atmel Quad SPI Controller" - depends on ARCH_AT91 || COMPILE_TEST + depends on ARCH_MICROCHIP || COMPILE_TEST depends on OF && HAS_IOMEM help This enables support for the Quad SPI controller in master mode. diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index aaf7f4c46b22..98369091eef7 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -256,8 +256,11 @@ static const struct atmel_qspi_pcal pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE] = { {200000000, 7}, }; +struct atmel_qspi; + struct atmel_qspi_caps { u32 max_speed_hz; + int (*init)(struct atmel_qspi *aq); bool has_qspick; bool has_gclk; bool has_ricr; @@ -1149,6 +1152,58 @@ static int atmel_qspi_sama7g5_init(struct atmel_qspi *aq) return ret; } +static int atmel_qspi_lan969x_init(struct atmel_qspi *aq) +{ + u32 val; + int ret; + + atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR); + ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, + !(val & QSPI_SR2_DLOCK), 40, + ATMEL_QSPI_TIMEOUT); + if (ret) + return ret; + + ret = atmel_qspi_set_gclk(aq); + if (ret) + return ret; + + /* Start the DLL before resetting the controller. */ + atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR); + ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, + (val & QSPI_SR2_DLOCK) && + !(val & QSPI_SR2_CALBSY), 40, + ATMEL_QSPI_TIMEOUT); + if (ret) + return ret; + + atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); + ret = atmel_qspi_reg_sync(aq); + if (ret) + return ret; + + atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR); + ret = atmel_qspi_reg_sync(aq); + if (ret) + return ret; + + ret = atmel_qspi_set_pad_calibration(aq); + if (ret) + return ret; + + aq->mr = 0; + aq->scr = 0; + + ret = atmel_qspi_set_serial_memory_mode(aq); + if (ret) + return ret; + + atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); + return readl_poll_timeout(aq->regs + QSPI_SR2, val, + (val & QSPI_SR2_QSPIENS), 40, + ATMEL_QSPI_TIMEOUT); +} + static int atmel_qspi_sama7g5_setup(struct spi_device *spi) { struct atmel_qspi *aq = spi_controller_get_devdata(spi->controller); @@ -1156,7 +1211,7 @@ static int atmel_qspi_sama7g5_setup(struct spi_device *spi) /* The controller can communicate with a single peripheral device (target). */ aq->target_max_speed_hz = spi->max_speed_hz; - return atmel_qspi_sama7g5_init(aq); + return aq->caps->init(aq); } static int atmel_qspi_setup(struct spi_device *spi) @@ -1347,20 +1402,21 @@ static const struct atmel_qspi_ops atmel_qspi_sama7g5_ops = { static int atmel_qspi_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct spi_controller *ctrl; struct atmel_qspi *aq; struct resource *res; int irq, err = 0; - ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*aq)); + ctrl = devm_spi_alloc_host(dev, sizeof(*aq)); if (!ctrl) return -ENOMEM; aq = spi_controller_get_devdata(ctrl); - aq->caps = of_device_get_match_data(&pdev->dev); + aq->caps = of_device_get_match_data(dev); if (!aq->caps) { - dev_err(&pdev->dev, "Could not retrieve QSPI caps\n"); + dev_err(dev, "Could not retrieve QSPI caps\n"); return -EINVAL; } @@ -1387,45 +1443,40 @@ static int atmel_qspi_probe(struct platform_device *pdev) /* Map the registers */ aq->regs = devm_platform_ioremap_resource_byname(pdev, "qspi_base"); if (IS_ERR(aq->regs)) - return dev_err_probe(&pdev->dev, PTR_ERR(aq->regs), + return dev_err_probe(dev, PTR_ERR(aq->regs), "missing registers\n"); /* Map the AHB memory */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap"); - aq->mem = devm_ioremap_resource(&pdev->dev, res); + aq->mem = devm_ioremap_resource(dev, res); if (IS_ERR(aq->mem)) - return dev_err_probe(&pdev->dev, PTR_ERR(aq->mem), + return dev_err_probe(dev, PTR_ERR(aq->mem), "missing AHB memory\n"); aq->mmap_size = resource_size(res); aq->mmap_phys_base = (dma_addr_t)res->start; /* Get the peripheral clock */ - aq->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); + aq->pclk = devm_clk_get_enabled(dev, "pclk"); if (IS_ERR(aq->pclk)) - aq->pclk = devm_clk_get_enabled(&pdev->dev, NULL); + aq->pclk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(aq->pclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(aq->pclk), + return dev_err_probe(dev, PTR_ERR(aq->pclk), "missing peripheral clock\n"); if (aq->caps->has_qspick) { /* Get the QSPI system clock */ - aq->qspick = devm_clk_get_enabled(&pdev->dev, "qspick"); - if (IS_ERR(aq->qspick)) { - dev_err(&pdev->dev, "missing system clock\n"); - err = PTR_ERR(aq->qspick); - return err; - } - + aq->qspick = devm_clk_get_enabled(dev, "qspick"); + if (IS_ERR(aq->qspick)) + return dev_err_probe(dev, PTR_ERR(aq->qspick), + "missing system clock\n"); } else if (aq->caps->has_gclk) { /* Get the QSPI generic clock */ - aq->gclk = devm_clk_get(&pdev->dev, "gclk"); - if (IS_ERR(aq->gclk)) { - dev_err(&pdev->dev, "missing Generic clock\n"); - err = PTR_ERR(aq->gclk); - return err; - } + aq->gclk = devm_clk_get(dev, "gclk"); + if (IS_ERR(aq->gclk)) + return dev_err_probe(dev, PTR_ERR(aq->gclk), + "missing Generic clock\n"); } if (aq->caps->has_dma) { @@ -1439,15 +1490,15 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (irq < 0) return irq; - err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt, - 0, dev_name(&pdev->dev), aq); + err = devm_request_irq(dev, irq, atmel_qspi_interrupt, + 0, dev_name(dev), aq); if (err) return err; - pm_runtime_set_autosuspend_delay(&pdev->dev, 500); - pm_runtime_use_autosuspend(&pdev->dev); - devm_pm_runtime_set_active_enabled(&pdev->dev); - devm_pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_autosuspend_delay(dev, 500); + pm_runtime_use_autosuspend(dev); + devm_pm_runtime_set_active_enabled(dev); + devm_pm_runtime_get_noresume(dev); err = atmel_qspi_init(aq); if (err) @@ -1457,7 +1508,7 @@ static int atmel_qspi_probe(struct platform_device *pdev) if (err) return err; - pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(dev); return 0; } @@ -1571,7 +1622,7 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) } if (aq->caps->has_gclk) - return atmel_qspi_sama7g5_init(aq); + return aq->caps->init(aq); ret = pm_runtime_force_resume(dev); if (ret < 0) @@ -1629,6 +1680,7 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = { static const struct atmel_qspi_caps atmel_sam9x7_ospi_caps = { .max_speed_hz = SAM9X7_QSPI_MAX_SPEED_HZ, + .init = atmel_qspi_sama7g5_init, .has_gclk = true, .octal = true, .has_dma = true, @@ -1639,6 +1691,7 @@ static const struct atmel_qspi_caps atmel_sam9x7_ospi_caps = { static const struct atmel_qspi_caps atmel_sama7d65_ospi_caps = { .max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ, + .init = atmel_qspi_sama7g5_init, .has_gclk = true, .octal = true, .has_dma = true, @@ -1649,6 +1702,7 @@ static const struct atmel_qspi_caps atmel_sama7d65_ospi_caps = { static const struct atmel_qspi_caps atmel_sama7d65_qspi_caps = { .max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ, + .init = atmel_qspi_sama7g5_init, .has_gclk = true, .has_dma = true, .has_2xgclk = true, @@ -1657,6 +1711,7 @@ static const struct atmel_qspi_caps atmel_sama7d65_qspi_caps = { static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = { .max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ, + .init = atmel_qspi_sama7g5_init, .has_gclk = true, .octal = true, .has_dma = true, @@ -1666,11 +1721,21 @@ static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = { static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = { .max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ, + .init = atmel_qspi_sama7g5_init, .has_gclk = true, .has_dma = true, .has_dllon = true, }; +static const struct atmel_qspi_caps atmel_lan969x_qspi_caps = { + .max_speed_hz = SAM9X7_QSPI_MAX_SPEED_HZ, + .init = atmel_qspi_lan969x_init, + .has_gclk = true, + .has_dma = true, + .has_padcalib = true, + .has_dllon = true, +}; + static const struct of_device_id atmel_qspi_dt_ids[] = { { .compatible = "atmel,sama5d2-qspi", @@ -1700,7 +1765,10 @@ static const struct of_device_id atmel_qspi_dt_ids[] = { .compatible = "microchip,sama7d65-qspi", .data = &atmel_sama7d65_qspi_caps, }, - + { + .compatible = "microchip,lan9691-qspi", + .data = &atmel_lan969x_qspi_caps, + }, { /* sentinel */ } }; diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c index 3de7df73f216..4fe69ce9da16 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -77,10 +77,8 @@ static int altera_spi_probe(struct platform_device *pdev) struct resource *regoff; hw->regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!hw->regmap) { - dev_err(&pdev->dev, "get regmap failed\n"); - return -ENODEV; - } + if (!hw->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, "get regmap failed\n"); regoff = platform_get_resource(pdev, IORESOURCE_REG, 0); if (regoff) @@ -94,10 +92,9 @@ static int altera_spi_probe(struct platform_device *pdev) hw->regmap = devm_regmap_init_mmio(&pdev->dev, res, &spi_altera_config); - if (IS_ERR(hw->regmap)) { - dev_err(&pdev->dev, "regmap mmio init failed\n"); - return PTR_ERR(hw->regmap); - } + if (IS_ERR(hw->regmap)) + return dev_err_probe(&pdev->dev, PTR_ERR(hw->regmap), + "regmap mmio init failed\n"); } altera_spi_init_host(host); diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c index 3c5098421ba3..b6ea8e556335 100644 --- a/drivers/spi/spi-atcspi200.c +++ b/drivers/spi/spi-atcspi200.c @@ -598,8 +598,11 @@ static int atcspi_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct atcspi_dev *spi = spi_controller_get_devdata(host); + int ret; - spi_controller_suspend(host); + ret = spi_controller_suspend(host); + if (ret) + return ret; clk_disable_unprepare(spi->clk); diff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c index 649f149617ce..25561aa9f76f 100644 --- a/drivers/spi/spi-axiado.c +++ b/drivers/spi/spi-axiado.c @@ -213,7 +213,7 @@ static void ax_spi_fill_tx_fifo(struct ax_spi *xspi) } /** - * ax_spi_get_rx_byte - Gets a byte from the RX FIFO buffer + * ax_spi_get_rx_byte_for_irq - Gets a byte from the RX FIFO buffer * @xspi: Controller private data (struct ax_spi *) * * This function handles the logic of extracting bytes from the 32-bit RX FIFO. @@ -246,9 +246,13 @@ static u8 ax_spi_get_rx_byte_for_irq(struct ax_spi *xspi) } /** + * ax_spi_process_rx_and_finalize - Process RX bytes and check for completion + * @ctlr: Pointer to spi_controller structure + * * Helper function to process received bytes and check for transfer completion. * This avoids code duplication and centralizes the completion logic. - * Returns true if the transfer was finalized. + * + * Return: true if the transfer was finalized. */ static bool ax_spi_process_rx_and_finalize(struct spi_controller *ctlr) { @@ -430,15 +434,11 @@ static int ax_transfer_one(struct spi_controller *ctlr, /* TX mode: discard all received data */ xspi->rx_discard = transfer->len; xspi->rx_copy_remaining = 0; - } else if ((!transfer->tx_buf && transfer->rx_buf) || - (transfer->tx_buf && transfer->rx_buf)) { - /* RX mode: generate clock by filling TX FIFO with dummy bytes - * Full-duplex mode: generate clock by filling TX FIFO - */ - xspi->rx_discard = 0; - xspi->rx_copy_remaining = transfer->len; } else { - /* No TX and RX */ + /* RX-only or full-duplex mode: copy received data, with the + * clock generated by filling the TX FIFO (with dummy bytes + * in RX-only mode) + */ xspi->rx_discard = 0; xspi->rx_copy_remaining = transfer->len; } diff --git a/drivers/spi/spi-axiado.h b/drivers/spi/spi-axiado.h index 6cf0e5bf5879..d24d31c3a446 100644 --- a/drivers/spi/spi-axiado.h +++ b/drivers/spi/spi-axiado.h @@ -98,9 +98,10 @@ * @regs: Virtual address of the SPI controller registers * @ref_clk: Pointer to the peripheral clock * @pclk: Pointer to the APB clock + * @clk_rate: Reference clock rate in Hz * @speed_hz: Current SPI bus clock speed in Hz - * @txbuf: Pointer to the TX buffer - * @rxbuf: Pointer to the RX buffer + * @tx_buf: Pointer to the TX buffer + * @rx_buf: Pointer to the RX buffer * @tx_bytes: Number of bytes left to transfer * @rx_bytes: Number of bytes requested * @tx_fifo_depth: Depth of the TX FIFO diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index dcade7b99cef..ae1ffe13fa46 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1692,13 +1692,17 @@ EXPORT_SYMBOL_GPL(bcm_qspi_remove); static int __maybe_unused bcm_qspi_suspend(struct device *dev) { struct bcm_qspi *qspi = dev_get_drvdata(dev); + int ret; /* store the override strap value */ if (!bcm_qspi_bspi_ver_three(qspi)) qspi->s3_strap_override_ctrl = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL); - spi_controller_suspend(qspi->host); + ret = spi_controller_suspend(qspi->host); + if (ret) + return ret; + clk_disable_unprepare(qspi->clk); bcm_qspi_hw_uninit(qspi); diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index ff94482fefcc..8f8715809c7c 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1226,7 +1226,7 @@ static int bcm2835_spi_setup(struct spi_device *spi) struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); struct bcm2835_spidev *target = spi_get_ctldata(spi); struct gpiod_lookup_table *lookup __free(kfree) = NULL; - const char *pinctrl_compats[] = { + static const char * const pinctrl_compats[] = { "brcm,bcm2835-gpio", "brcm,bcm2711-gpio", "brcm,bcm7211-gpio", diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 58012e1b5ae7..37b3534d0b0a 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -889,8 +889,12 @@ static int bcm63xx_hsspi_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host); + int ret; + + ret = spi_controller_suspend(host); + if (ret) + return ret; - spi_controller_suspend(host); clk_disable_unprepare(bs->pll_clk); clk_disable_unprepare(bs->clk); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 43d7b54e3ae8..8cef725aab26 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -632,8 +632,11 @@ static int bcm63xx_spi_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct bcm63xx_spi *bs = spi_controller_get_devdata(host); + int ret; - spi_controller_suspend(host); + ret = spi_controller_suspend(host); + if (ret) + return ret; clk_disable_unprepare(bs->clk); diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index 09c1472ae4fa..af88ce04948b 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -568,8 +568,12 @@ static int bcmbca_hsspi_suspend(struct device *dev) { struct spi_controller *host = dev_get_drvdata(dev); struct bcmbca_hsspi *bs = spi_controller_get_devdata(host); + int ret; + + ret = spi_controller_suspend(host); + if (ret) + return ret; - spi_controller_suspend(host); clk_disable_unprepare(bs->pll_clk); clk_disable_unprepare(bs->clk); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index da7f2ae3a570..087735ed9c80 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -928,7 +928,7 @@ static int davinci_spi_probe(struct platform_device *pdev) int ret = 0; u32 spipc0; - host = spi_alloc_host(&pdev->dev, sizeof(struct davinci_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct davinci_spi)); if (host == NULL) { ret = -ENOMEM; goto err; @@ -1057,7 +1057,6 @@ free_dma: dma_release_channel(dspi->dma_tx); } free_host: - spi_controller_put(host); err: return ret; } @@ -1081,6 +1080,8 @@ static void davinci_spi_remove(struct platform_device *pdev) spi_bitbang_stop(&dspi->bitbang); + devm_free_irq(&pdev->dev, dspi->irq, dspi); + /* This bit needs to be cleared to disable dpsi->clk */ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); @@ -1088,8 +1089,6 @@ static void davinci_spi_remove(struct platform_device *pdev) dma_release_channel(dspi->dma_rx); dma_release_channel(dspi->dma_tx); } - - spi_controller_put(host); } static struct platform_driver davinci_spi_driver = { diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 019d05cdefe6..c2d283876ef8 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1464,10 +1464,18 @@ static int dspi_init(struct fsl_dspi *dspi) static int dspi_suspend(struct device *dev) { struct fsl_dspi *dspi = dev_get_drvdata(dev); + int ret; if (dspi->irq) disable_irq(dspi->irq); - spi_controller_suspend(dspi->ctlr); + + ret = spi_controller_suspend(dspi->ctlr); + if (ret) { + if (dspi->irq) + enable_irq(dspi->irq); + return ret; + } + clk_disable_unprepare(dspi->clk); pinctrl_pm_select_sleep_state(dev); @@ -1485,12 +1493,15 @@ static int dspi_resume(struct device *dev) ret = clk_prepare_enable(dspi->clk); if (ret) return ret; - spi_controller_resume(dspi->ctlr); + + ret = spi_controller_resume(dspi->ctlr); + if (ret) + goto disable_clk; ret = dspi_init(dspi); if (ret) { dev_err(dev, "failed to initialize dspi during resume\n"); - return ret; + goto disable_clk; } dspi_set_mtf(dspi); @@ -1499,6 +1510,10 @@ static int dspi_resume(struct device *dev) enable_irq(dspi->irq); return 0; + +disable_clk: + clk_disable_unprepare(dspi->clk); + return ret; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 26e723cfea61..6566975eb24f 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux foundation. All rights reserved. +#include + #define CREATE_TRACE_POINTS #include @@ -78,6 +80,13 @@ #define GSI_CPHA BIT(4) #define GSI_CPOL BIT(5) +struct geni_spi_desc { + int (*resources_init)(struct geni_se *se); + int (*set_rate)(struct geni_se *se, unsigned long clk_freq); + int (*power_on)(struct geni_se *se); + int (*power_off)(struct geni_se *se); +}; + struct spi_geni_master { struct geni_se se; struct device *dev; @@ -105,6 +114,7 @@ struct spi_geni_master { struct dma_chan *tx; struct dma_chan *rx; int cur_xfer_mode; + const struct geni_spi_desc *dev_data; }; static void spi_slv_setup(struct spi_geni_master *mas) @@ -184,6 +194,7 @@ static void handle_se_timeout(struct spi_controller *spi) time_left = wait_for_completion_timeout(&mas->abort_done, HZ); if (!time_left) { dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); + trace_geni_se_regs(se); /* * No need for a lock since SPI core has a lock and we never @@ -201,8 +212,10 @@ reset_if_dma: writel(1, se->base + SE_DMA_TX_FSM_RST); spin_unlock_irq(&mas->lock); time_left = wait_for_completion_timeout(&mas->tx_reset_done, HZ); - if (!time_left) + if (!time_left) { dev_err(mas->dev, "DMA TX RESET failed\n"); + trace_geni_se_regs(se); + } } if (xfer->rx_buf) { spin_lock_irq(&mas->lock); @@ -210,8 +223,10 @@ reset_if_dma: writel(1, se->base + SE_DMA_RX_FSM_RST); spin_unlock_irq(&mas->lock); time_left = wait_for_completion_timeout(&mas->rx_reset_done, HZ); - if (!time_left) + if (!time_left) { dev_err(mas->dev, "DMA RX RESET failed\n"); + trace_geni_se_regs(se); + } } } else { /* @@ -305,11 +320,12 @@ static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, writel(word_len, se->base + SE_SPI_WORD_LEN); } -static int geni_spi_set_clock_and_bw(struct spi_geni_master *mas, - unsigned long clk_hz) +static int geni_spi_set_clock_and_bw(struct geni_se *se, + unsigned long clk_hz) { + struct spi_controller *spi = dev_get_drvdata(se->dev); + struct spi_geni_master *mas = spi_controller_get_devdata(spi); u32 clk_sel, m_clk_cfg, idx, div; - struct geni_se *se = &mas->se; int ret; if (clk_hz == mas->cur_speed_hz) @@ -382,10 +398,12 @@ static void spi_gsi_callback_result(void *cb, const struct dmaengine_result *result) { struct spi_controller *spi = cb; + struct spi_geni_master *mas = spi_controller_get_devdata(spi); spi->cur_msg->status = -EIO; if (result->result != DMA_TRANS_NOERROR) { dev_err(&spi->dev, "DMA txn failed: %d\n", result->result); + trace_geni_se_regs(&mas->se); spi_finalize_current_transfer(spi); return; } @@ -395,6 +413,7 @@ spi_gsi_callback_result(void *cb, const struct dmaengine_result *result) dev_dbg(&spi->dev, "DMA txn completed\n"); } else { dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue); + trace_geni_se_regs(&mas->se); } spi_finalize_current_transfer(spi); @@ -613,25 +632,30 @@ static int spi_geni_init(struct spi_geni_master *mas) u32 spi_tx_cfg, fifo_disable; int ret = -ENXIO; - pm_runtime_get_sync(mas->dev); + PM_RUNTIME_ACQUIRE_IF_ENABLED(mas->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret < 0) { + dev_err(mas->dev, "Failed to resume and get %d\n", ret); + return ret; + } proto = geni_se_read_proto(se); if (spi->target) { if (proto != GENI_SE_SPI_SLAVE) { dev_err(mas->dev, "Invalid proto %d\n", proto); - goto out_pm; + return -EINVAL; } spi_slv_setup(mas); } else if (proto == GENI_SE_INVALID_PROTO) { ret = geni_load_se_firmware(se, GENI_SE_SPI); if (ret) { dev_err(mas->dev, "spi master firmware load failed ret: %d\n", ret); - goto out_pm; + return ret; } } else if (proto != GENI_SE_SPI) { dev_err(mas->dev, "Invalid proto %d\n", proto); - goto out_pm; + return -EINVAL; } mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); @@ -664,7 +688,7 @@ static int spi_geni_init(struct spi_geni_master *mas) dev_dbg(mas->dev, "Using GPI DMA mode for SPI\n"); break; } else if (ret == -EPROBE_DEFER) { - goto out_pm; + return ret; } /* * in case of failure to get gpi dma channel, we can still do the @@ -693,8 +717,6 @@ static int spi_geni_init(struct spi_geni_master *mas) writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); } -out_pm: - pm_runtime_put(mas->dev); return ret; } @@ -825,7 +847,7 @@ static int setup_se_xfer(struct spi_transfer *xfer, } /* Speed and bits per word can be overridden per transfer */ - ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz); + ret = mas->dev_data->set_rate(&mas->se, xfer->speed_hz); if (ret) return ret; @@ -941,8 +963,10 @@ static irqreturn_t geni_spi_isr(int irq, void *data) if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | - M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) + M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) { dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq); + trace_geni_se_regs(se); + } spin_lock(&mas->lock); @@ -971,13 +995,16 @@ static irqreturn_t geni_spi_isr(int irq, void *data) * weren't written correctly. */ if (mas->tx_rem_bytes) { + trace_geni_se_regs(se); writel(0, se->base + SE_GENI_TX_WATERMARK_REG); dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", mas->tx_rem_bytes, mas->cur_bits_per_word); } - if (mas->rx_rem_bytes) + if (mas->rx_rem_bytes) { dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", mas->rx_rem_bytes, mas->cur_bits_per_word); + trace_geni_se_regs(se); + } } else { complete(&mas->cs_done); } @@ -1045,7 +1072,6 @@ static int spi_geni_probe(struct platform_device *pdev) struct spi_controller *spi; struct spi_geni_master *mas; void __iomem *base; - struct clk *clk; struct device *dev = &pdev->dev; irq = platform_get_irq(pdev, 0); @@ -1060,10 +1086,6 @@ static int spi_geni_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - clk = devm_clk_get(dev, "se"); - if (IS_ERR(clk)) - return PTR_ERR(clk); - if (device_property_read_bool(dev, "spi-slave")) spi = devm_spi_alloc_target(dev, sizeof(*mas)); else @@ -1079,17 +1101,14 @@ static int spi_geni_probe(struct platform_device *pdev) mas->se.dev = dev; mas->se.wrapper = dev_get_drvdata(dev->parent); mas->se.base = base; - mas->se.clk = clk; - ret = devm_pm_opp_set_clkname(&pdev->dev, "se"); + mas->dev_data = device_get_match_data(&pdev->dev); + if (!mas->dev_data) + return -EINVAL; + + ret = mas->dev_data->resources_init(&mas->se); if (ret) return ret; - /* OPP table is optional */ - ret = devm_pm_opp_of_add_table(&pdev->dev); - if (ret && ret != -ENODEV) { - dev_err(&pdev->dev, "invalid OPP table in device tree\n"); - return ret; - } spi->bus_num = -1; spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; @@ -1115,24 +1134,12 @@ static int spi_geni_probe(struct platform_device *pdev) if (spi->target) spi->target_abort = spi_geni_target_abort; - ret = geni_icc_get(&mas->se, NULL); - if (ret) - return ret; - pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 250); ret = devm_pm_runtime_enable(dev); if (ret) return ret; - /* Set the bus quota to a reasonable value for register access */ - mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ); - mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; - - ret = geni_icc_set_bw(&mas->se); - if (ret) - return ret; - ret = spi_geni_init(mas); if (ret) return ret; @@ -1154,16 +1161,9 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) { struct spi_controller *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_controller_get_devdata(spi); - int ret; - /* Drop the performance state vote */ - dev_pm_opp_set_rate(dev, 0); - - ret = geni_se_resources_off(&mas->se); - if (ret) - return ret; - - return geni_icc_disable(&mas->se); + return mas->dev_data->power_off ? + mas->dev_data->power_off(&mas->se) : 0; } static int __maybe_unused spi_geni_runtime_resume(struct device *dev) @@ -1172,15 +1172,16 @@ static int __maybe_unused spi_geni_runtime_resume(struct device *dev) struct spi_geni_master *mas = spi_controller_get_devdata(spi); int ret; - ret = geni_icc_enable(&mas->se); - if (ret) - return ret; + if (mas->dev_data->power_on) { + ret = mas->dev_data->power_on(&mas->se); + if (ret) + return ret; + } - ret = geni_se_resources_on(&mas->se); - if (ret) - return ret; + if (mas->se.has_opp) + return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz); - return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz); + return 0; } static int __maybe_unused spi_geni_suspend(struct device *dev) @@ -1221,8 +1222,21 @@ static const struct dev_pm_ops spi_geni_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume) }; +static const struct geni_spi_desc geni_spi = { + .resources_init = geni_se_resources_init, + .set_rate = geni_spi_set_clock_and_bw, + .power_on = geni_se_resources_activate, + .power_off = geni_se_resources_deactivate, +}; + +static const struct geni_spi_desc sa8255p_geni_spi = { + .resources_init = geni_se_domain_attach, + .set_rate = geni_se_set_perf_opp, +}; + static const struct of_device_id spi_geni_dt_match[] = { - { .compatible = "qcom,geni-spi" }, + { .compatible = "qcom,geni-spi", .data = &geni_spi }, + { .compatible = "qcom,sa8255p-geni-spi", .data = &sa8255p_geni_spi }, {} }; MODULE_DEVICE_TABLE(of, spi_geni_dt_match); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 70d8e17e8c43..563b1f627be9 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -392,6 +392,18 @@ static int mpc52xx_spi_probe(struct platform_device *op) void __iomem *regs; u8 ctrl1; int rc, i = 0; + int irq0; + int irq1; + + irq0 = platform_get_irq_optional(op, 0); + if (irq0 == -EPROBE_DEFER) + return irq0; + irq0 = max(irq0, 0); + + irq1 = platform_get_irq_optional(op, 1); + if (irq1 == -EPROBE_DEFER) + return irq1; + irq1 = max(irq1, 0); /* MMIO registers */ dev_dbg(&op->dev, "probing mpc5200 SPI device\n"); @@ -436,8 +448,8 @@ static int mpc52xx_spi_probe(struct platform_device *op) ms = spi_controller_get_devdata(host); ms->host = host; ms->regs = regs; - ms->irq0 = irq_of_parse_and_map(op->dev.of_node, 0); - ms->irq1 = irq_of_parse_and_map(op->dev.of_node, 1); + ms->irq0 = irq0; + ms->irq1 = irq1; ms->state = mpc52xx_spi_fsmstate_idle; ms->ipb_freq = mpc5xxx_get_bus_frequency(&op->dev); ms->gpio_cs_count = gpiod_count(&op->dev, NULL); diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 4b825044038b..96dfef4d9067 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -393,7 +393,7 @@ static int npcm_fiu_uma_write(struct spi_mem *mem, { struct npcm_fiu_spi *fiu = spi_controller_get_devdata(mem->spi->controller); - u32 uma_cfg = BIT(10); + u32 uma_cfg = cmd ? BIT(10) : 0; u32 data_reg[4] = {0}; u32 val; u32 i; @@ -403,8 +403,11 @@ static int npcm_fiu_uma_write(struct spi_mem *mem, (spi_get_chipselect(mem->spi, 0) << NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT)); - regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, - NPCM_FIU_UMA_CMD_CMD, cmd); + if (cmd) + regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, + NPCM_FIU_UMA_CMD_CMD, cmd); + else + uma_cfg |= ilog2(op->data.buswidth) << NPCM_FIU_UMA_CFG_WDBPCK_SHIFT; if (data_size) { memcpy(data_reg, data, data_size); @@ -464,8 +467,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem, /* Starting the data writing loop in multiples of 8 */ for (idx = 0; idx < num_data_chunks; ++idx) { - ret = npcm_fiu_uma_write(mem, op, data[0], false, - &data[1], CHUNK_SIZE - 1); + ret = npcm_fiu_uma_write(mem, op, 0, false, &data[0], CHUNK_SIZE); if (ret) return ret; @@ -474,8 +476,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem, /* Handling chunk remains */ if (remain_data > 0) { - ret = npcm_fiu_uma_write(mem, op, data[0], false, - &data[1], remain_data - 1); + ret = npcm_fiu_uma_write(mem, op, 0, false, &data[0], remain_data); if (ret) return ret; } diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 4425132432ec..67d991dd249d 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1458,9 +1458,11 @@ static int nxp_fspi_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(dev); /* enable clock */ - ret = pm_runtime_get_sync(f->dev); - if (ret < 0) - return dev_err_probe(dev, ret, "Failed to enable clock"); + ret = pm_runtime_resume_and_get(f->dev); + if (ret < 0) { + ret = dev_err_probe(dev, ret, "Failed to enable clock"); + goto err_disable_pm; + } /* Clear potential interrupts */ reg = fspi_readl(f, f->iobase + FSPI_INTR); @@ -1470,18 +1472,24 @@ static int nxp_fspi_probe(struct platform_device *pdev) nxp_fspi_default_setup(f); ret = pm_runtime_put_sync(dev); - if (ret < 0) - return dev_err_probe(dev, ret, "Failed to disable clock"); + if (ret < 0) { + ret = dev_err_probe(dev, ret, "Failed to disable clock"); + goto err_disable_pm; + } init_completion(&f->c); ret = devm_request_irq(dev, irq, nxp_fspi_irq_handler, 0, pdev->name, f); - if (ret) - return dev_err_probe(dev, ret, "Failed to request irq\n"); + if (ret) { + ret = dev_err_probe(dev, ret, "Failed to request irq\n"); + goto err_disable_pm; + } ret = devm_mutex_init(dev, &f->lock); - if (ret) - return dev_err_probe(dev, ret, "Failed to initialize lock\n"); + if (ret) { + ret = dev_err_probe(dev, ret, "Failed to initialize lock\n"); + goto err_disable_pm; + } ctlr->bus_num = -1; ctlr->num_chipselect = NXP_FSPI_MAX_CHIPSELECT; @@ -1497,6 +1505,11 @@ static int nxp_fspi_probe(struct platform_device *pdev) return ret; return devm_spi_register_controller(&pdev->dev, ctlr); + +err_disable_pm: + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); + return ret; } static int nxp_fspi_runtime_suspend(struct device *dev) diff --git a/drivers/spi/spi-nxp-xspi.c b/drivers/spi/spi-nxp-xspi.c index 037eac24e6fd..70cbc3ef658b 100644 --- a/drivers/spi/spi-nxp-xspi.c +++ b/drivers/spi/spi-nxp-xspi.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -303,6 +305,12 @@ (opr)) << (((idx) % 2) * OPRND_SHIFT)) #define NXP_XSPI_MIN_IOMAP SZ_4M +/* + * It takes 0.5s to access the entire area with DMA, + * leaving a 10x safety margin + */ +#define NXP_XSPI_DMA_TOUT_MS 5000 +#define NXP_XSPI_DMA_TOUT msecs_to_jiffies(NXP_XSPI_DMA_TOUT_MS) #define NXP_XSPI_MAX_CHIPSELECT 2 #define POLL_TOUT_US 5000 @@ -336,6 +344,9 @@ struct nxp_xspi { /* mutex lock for each operation */ struct mutex lock; int selected; + int dma_copy_align; + struct dma_chan *dma_rx; + struct completion dma_rx_c; #define XSPI_DTR_PROTO BIT(0) int flags; /* Save the previous operation clock rate */ @@ -796,6 +807,95 @@ static int nxp_xspi_ahb_read(struct nxp_xspi *xspi, const struct spi_mem_op *op) return 0; } +static int nxp_xspi_dma_init(struct device *dev, struct nxp_xspi *xspi) +{ + struct dma_chan *rx; + + rx = dma_request_chan(dev, "rx"); + if (IS_ERR(rx)) { + int ret = PTR_ERR(rx); + + if (ret == -EPROBE_DEFER) + return ret; + dev_dbg(dev, "NO DMA RX channel, falling back to CPU read\n"); + xspi->dma_copy_align = 1; + return 0; + } + + xspi->dma_rx = rx; + init_completion(&xspi->dma_rx_c); + xspi->dma_copy_align = 1 << rx->device->copy_align; + + return 0; +} + +static void nxp_xspi_dma_rx_callback(void *data) +{ + struct nxp_xspi *xspi = data; + + complete(&xspi->dma_rx_c); +} + +static int nxp_xspi_ahb_dma_read(struct nxp_xspi *xspi, + const struct spi_mem_op *op) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = xspi->dma_rx; + unsigned long timeout; + dma_addr_t src_addr, dst_addr; + int ret = 0; + + dst_addr = dma_map_single(chan->device->dev, + op->data.buf.in, op->data.nbytes, + DMA_FROM_DEVICE); + if (dma_mapping_error(chan->device->dev, dst_addr)) { + dev_err(xspi->dev, "failed to map DMA dst buffer\n"); + return -ENOMEM; + } + + src_addr = dma_map_resource(chan->device->dev, + (phys_addr_t)xspi->memmap_phy + op->addr.val, + op->data.nbytes, + DMA_TO_DEVICE, 0); + if (dma_mapping_error(chan->device->dev, src_addr)) { + dev_err(xspi->dev, "failed to map DMA src resource\n"); + ret = -ENOMEM; + goto err_unmap_dst; + } + + desc = dmaengine_prep_dma_memcpy(chan, dst_addr, src_addr, + op->data.nbytes, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(xspi->dev, "failed to prepare AHB RX DMA descriptor\n"); + ret = -EIO; + goto err_unmap_src; + } + + desc->callback = nxp_xspi_dma_rx_callback; + desc->callback_param = xspi; + reinit_completion(&xspi->dma_rx_c); + dmaengine_submit(desc); + dma_async_issue_pending(chan); + + timeout = wait_for_completion_timeout(&xspi->dma_rx_c, NXP_XSPI_DMA_TOUT); + if (!timeout) { + dev_err(xspi->dev, "AHB RX DMA timeout\n"); + dmaengine_terminate_sync(chan); + ret = -ETIMEDOUT; + } + +err_unmap_src: + dma_unmap_resource(chan->device->dev, src_addr, + op->data.nbytes, DMA_TO_DEVICE, 0); + +err_unmap_dst: + dma_unmap_single(chan->device->dev, dst_addr, + op->data.nbytes, DMA_FROM_DEVICE); + + return ret; +} + static int nxp_xspi_fill_txfifo(struct nxp_xspi *xspi, const struct spi_mem_op *op) { @@ -1016,10 +1116,21 @@ static int nxp_xspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) * all use IP write. */ if ((op->data.dir == SPI_MEM_DATA_IN) && !needs_ip_only(xspi) - && ((op->addr.val + op->data.nbytes) <= xspi->memmap_phy_size)) - err = nxp_xspi_ahb_read(xspi, op); - else + && ((op->addr.val + op->data.nbytes) <= xspi->memmap_phy_size)) { + /* use DMA for transfers no less than ahb_buf_size, when DMA is available */ + if (xspi->dma_rx && op->data.nbytes >= xspi->devtype_data->ahb_buf_size) { + err = nxp_xspi_ahb_dma_read(xspi, op); + if (err) { + dev_warn_ratelimited(xspi->dev, + "DMA read failed (%d), falling back to CPU read\n", err); + err = nxp_xspi_ahb_read(xspi, op); + } + } else { + err = nxp_xspi_ahb_read(xspi, op); + } + } else { err = nxp_xspi_do_op(xspi, op); + } nxp_xspi_sw_reset(xspi); @@ -1029,6 +1140,7 @@ static int nxp_xspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) static int nxp_xspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { struct nxp_xspi *xspi = spi_controller_get_devdata(mem->spi->controller); + int alignment = xspi->dma_copy_align; if (op->data.dir == SPI_MEM_DATA_OUT) { if (op->data.nbytes > xspi->devtype_data->txfifo) @@ -1042,6 +1154,22 @@ static int nxp_xspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) if (!needs_ip_only(xspi) && (op->addr.val < xspi->memmap_phy_size) && ((op->addr.val + op->data.nbytes) > xspi->memmap_phy_size)) op->data.nbytes = xspi->memmap_phy_size - op->addr.val; + + /* + * For AHB DMA read, align the transfer to the DMA alignment + * boundaries. If the start address is unaligned, shorten this + * transfer so the next one starts on an aligned boundary. + * Otherwise, if the length is unaligned, round it down. + */ + if (xspi->dma_rx && !needs_ip_only(xspi) && + (op->data.nbytes >= xspi->devtype_data->ahb_buf_size)) { + if (op->addr.val & (alignment - 1)) + op->data.nbytes = + ALIGN(op->addr.val, alignment) - op->addr.val; + else if (op->data.nbytes & (alignment - 1)) + op->data.nbytes = + ALIGN_DOWN(op->data.nbytes, alignment); + } } return 0; @@ -1203,6 +1331,10 @@ static void nxp_xspi_cleanup(void *data) if (xspi->ahb_addr) iounmap(xspi->ahb_addr); + if (xspi->dma_rx) { + dmaengine_terminate_sync(xspi->dma_rx); + dma_release_channel(xspi->dma_rx); + } } static int nxp_xspi_probe(struct platform_device *pdev) @@ -1283,6 +1415,11 @@ static int nxp_xspi_probe(struct platform_device *pdev) if (ret) return ret; + /* DMA is optional, failure(other than -EPROBE_DEFER) falls back to CPU */ + ret = nxp_xspi_dma_init(dev, xspi); + if (ret == -EPROBE_DEFER) + return ret; + ctlr->bus_num = -1; ctlr->num_chipselect = NXP_XSPI_MAX_CHIPSELECT; ctlr->mem_ops = &nxp_xspi_mem_ops; diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 29333b1f82d7..1cd2a934c032 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -210,11 +210,11 @@ static int tiny_spi_probe(struct platform_device *pdev) struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct tiny_spi *hw; struct spi_controller *host; - int err = -ENODEV; + int err; - host = spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi)); if (!host) - return err; + return -ENOMEM; /* setup the host state. */ host->bus_num = pdev->id; @@ -232,10 +232,8 @@ static int tiny_spi_probe(struct platform_device *pdev) /* find and map our resources */ hw->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hw->base)) { - err = PTR_ERR(hw->base); - goto exit; - } + if (IS_ERR(hw->base)) + return PTR_ERR(hw->base); /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); if (hw->irq >= 0) { @@ -243,7 +241,7 @@ static int tiny_spi_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, hw->irq, tiny_spi_irq, 0, pdev->name, hw); if (err) - goto exit; + return err; } /* find platform data */ if (platp) { @@ -252,29 +250,23 @@ static int tiny_spi_probe(struct platform_device *pdev) } else { err = tiny_spi_of_probe(pdev); if (err) - goto exit; + return err; } /* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); if (err) - goto exit; + return err; dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); return 0; - -exit: - spi_controller_put(host); - return err; } static void tiny_spi_remove(struct platform_device *pdev) { struct tiny_spi *hw = platform_get_drvdata(pdev); - struct spi_controller *host = hw->bitbang.ctlr; spi_bitbang_stop(&hw->bitbang); - spi_controller_put(host); } #ifdef CONFIG_OF diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 265708a94984..e5e05512a1fd 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -691,12 +691,9 @@ static int orion_spi_probe(struct platform_device *pdev) return PTR_ERR(spi->clk); /* The following clock is only used by some SoCs */ - spi->axi_clk = devm_clk_get(&pdev->dev, "axi"); - if (PTR_ERR(spi->axi_clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!IS_ERR(spi->axi_clk)) - clk_prepare_enable(spi->axi_clk); + spi->axi_clk = devm_clk_get_optional_enabled(&pdev->dev, "axi"); + if (IS_ERR(spi->axi_clk)) + return PTR_ERR(spi->axi_clk); tclk_hz = clk_get_rate(spi->clk); @@ -719,10 +716,8 @@ static int orion_spi_probe(struct platform_device *pdev) host->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor); spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(spi->base)) { - status = PTR_ERR(spi->base); - goto out_rel_axi_clk; - } + if (IS_ERR(spi->base)) + return PTR_ERR(spi->base); for_each_available_child_of_node(pdev->dev.of_node, np) { struct orion_direct_acc *dir_acc; @@ -757,9 +752,8 @@ static int orion_spi_probe(struct platform_device *pdev) dir_acc = &spi->child[cs].direct_access; dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); if (!dir_acc->vaddr) { - status = -ENOMEM; of_node_put(np); - goto out_rel_axi_clk; + return -ENOMEM; } dir_acc->size = PAGE_SIZE; @@ -789,8 +783,6 @@ out_rel_pm: pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); -out_rel_axi_clk: - clk_disable_unprepare(spi->axi_clk); return status; } @@ -799,12 +791,10 @@ out_rel_axi_clk: static void orion_spi_remove(struct platform_device *pdev) { struct spi_controller *host = platform_get_drvdata(pdev); - struct orion_spi *spi = spi_controller_get_devdata(host); spi_unregister_controller(host); pm_runtime_get_sync(&pdev->dev); - clk_disable_unprepare(spi->axi_clk); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); @@ -830,8 +820,7 @@ static int orion_spi_runtime_resume(struct device *dev) struct spi_controller *host = dev_get_drvdata(dev); struct orion_spi *spi = spi_controller_get_devdata(host); - if (!IS_ERR(spi->axi_clk)) - clk_prepare_enable(spi->axi_clk); + clk_prepare_enable(spi->axi_clk); return clk_prepare_enable(spi->clk); } #endif diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 46ac58dfb3fc..8a7d5aec12c1 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -112,9 +112,6 @@ struct ppc4xx_spi { struct spi_bitbang bitbang; struct completion done; - u64 mapbase; - u64 mapsize; - int irqnum; /* need this to set the SPI clock */ unsigned int opb_freq; @@ -337,14 +334,24 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) struct ppc4xx_spi *hw; struct spi_controller *host; struct spi_bitbang *bbp; - struct resource resource; struct device_node *np = op->dev.of_node; struct device *dev = &op->dev; struct device_node *opbnp; int ret; - const unsigned int *clk; + unsigned int opb_freq; + void __iomem *regs; + int irqnum; - host = spi_alloc_host(dev, sizeof(*hw)); + regs = devm_platform_ioremap_resource(op, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + /* Request IRQ */ + irqnum = platform_get_irq(op, 0); + if (irqnum < 0) + return irqnum; + + host = devm_spi_alloc_host(dev, sizeof(*hw)); if (host == NULL) return -ENOMEM; host->dev.of_node = np; @@ -379,88 +386,30 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb"); if (opbnp == NULL) { dev_err(dev, "OPB: cannot find node\n"); - ret = -ENODEV; - goto free_host; + return -ENODEV; } /* Get the clock (Hz) for the OPB */ - clk = of_get_property(opbnp, "clock-frequency", NULL); - if (clk == NULL) { - dev_err(dev, "OPB: no clock-frequency property set\n"); - of_node_put(opbnp); - ret = -ENODEV; - goto free_host; - } - hw->opb_freq = *clk; - hw->opb_freq >>= 2; + ret = of_property_read_u32(opbnp, "clock-frequency", &opb_freq); of_node_put(opbnp); - - ret = of_address_to_resource(np, 0, &resource); if (ret) { - dev_err(dev, "error while parsing device node resource\n"); - goto free_host; - } - hw->mapbase = resource.start; - hw->mapsize = resource_size(&resource); - - /* Sanity check */ - if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) { - dev_err(dev, "too small to map registers\n"); - ret = -EINVAL; - goto free_host; + dev_err(dev, "OPB: no clock-frequency property set\n"); + return -ENODEV; } - /* Request IRQ */ - ret = platform_get_irq(op, 0); - if (ret < 0) - goto free_host; - hw->irqnum = ret; + hw->opb_freq = opb_freq; + hw->opb_freq >>= 2; + hw->regs = regs; - ret = request_irq(hw->irqnum, spi_ppc4xx_int, - 0, "spi_ppc4xx_of", (void *)hw); - if (ret) { - dev_err(dev, "unable to allocate interrupt\n"); - goto free_host; - } - - if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) { - dev_err(dev, "resource unavailable\n"); - ret = -EBUSY; - goto request_mem_error; - } - - hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs)); - - if (!hw->regs) { - dev_err(dev, "unable to memory map registers\n"); - ret = -ENXIO; - goto map_io_error; - } + ret = devm_request_irq(&op->dev, irqnum, spi_ppc4xx_int, + 0, "spi_ppc4xx_of", hw); + if (ret) + return ret; spi_ppc4xx_enable(hw); /* Finally register our spi controller */ dev->dma_mask = 0; - ret = spi_bitbang_start(bbp); - if (ret) { - dev_err(dev, "failed to register SPI host\n"); - goto unmap_regs; - } - - dev_info(dev, "driver initialized\n"); - - return 0; - -unmap_regs: - iounmap(hw->regs); -map_io_error: - release_mem_region(hw->mapbase, hw->mapsize); -request_mem_error: - free_irq(hw->irqnum, hw); -free_host: - spi_controller_put(host); - - dev_err(dev, "initialization failed\n"); - return ret; + return spi_bitbang_start(bbp); } static void spi_ppc4xx_of_remove(struct platform_device *op) @@ -469,10 +418,6 @@ static void spi_ppc4xx_of_remove(struct platform_device *op) struct ppc4xx_spi *hw = spi_controller_get_devdata(host); spi_bitbang_stop(&hw->bitbang); - release_mem_region(hw->mapbase, hw->mapsize); - free_irq(hw->irqnum, hw); - iounmap(hw->regs); - spi_controller_put(host); } static const struct of_device_id spi_ppc4xx_of_match[] = { diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index b6c58d9cfe14..1e2fc875cd66 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -274,6 +274,19 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg->strength = 4; } + /* + * Override ECC strength based on OOB size to avoid weak ECC warning. + * If OOB size is more than 128 bytes, use 8-bit ECC for better + * error correction capability, which is required by chips with + * larger OOB areas like Macronix SPI NAND with 256 bytes OOB. + */ + if (mtd->oobsize >= 128 && ecc_cfg->strength < 8) { + dev_info(snandc->dev, + "Upgrading ECC strength from %d to 8 bits (OOB size: %d bytes)\n", + ecc_cfg->strength, mtd->oobsize); + ecc_cfg->strength = 8; + } + if (ecc_cfg->step_size != NANDC_STEP_SIZE) { dev_err(snandc->dev, "only %u bytes ECC step size is supported\n", @@ -394,14 +407,19 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) return 0; err_free_ecc_cfg: + kfree(snandc->qspi->oob_buf); + snandc->qspi->oob_buf = NULL; kfree(ecc_cfg); return ret; } static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) { + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); + kfree(snandc->qspi->oob_buf); + snandc->qspi->oob_buf = NULL; kfree(ecc_cfg); } @@ -1659,4 +1677,3 @@ module_platform_driver(qcom_spi_driver); MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores"); MODULE_AUTHOR("Md Sadre Alam "); MODULE_LICENSE("GPL"); - diff --git a/drivers/spi/spi-realtek-rtl.c b/drivers/spi/spi-realtek-rtl.c index 73065c8934dc..e1c40ff2e49d 100644 --- a/drivers/spi/spi-realtek-rtl.c +++ b/drivers/spi/spi-realtek-rtl.c @@ -35,58 +35,58 @@ static void rt_set_cs(struct spi_device *spi, bool active) u32 value; /* CS0 bit is active low */ - value = readl(REG(RTL_SPI_SFCSR)); + value = __raw_readl(REG(RTL_SPI_SFCSR)); if (active) value |= RTL_SPI_SFCSR_CSB0; else value &= ~RTL_SPI_SFCSR_CSB0; - writel(value, REG(RTL_SPI_SFCSR)); + __raw_writel(value, REG(RTL_SPI_SFCSR)); } static void set_size(struct rtspi *rtspi, int size) { u32 value; - value = readl(REG(RTL_SPI_SFCSR)); + value = __raw_readl(REG(RTL_SPI_SFCSR)); value &= RTL_SPI_SFCSR_LEN_MASK; if (size == 4) value |= RTL_SPI_SFCSR_LEN4; else if (size == 1) value |= RTL_SPI_SFCSR_LEN1; - writel(value, REG(RTL_SPI_SFCSR)); + __raw_writel(value, REG(RTL_SPI_SFCSR)); } static inline void wait_ready(struct rtspi *rtspi) { - while (!(readl(REG(RTL_SPI_SFCSR)) & RTL_SPI_SFCSR_RDY)) + while (!(__raw_readl(REG(RTL_SPI_SFCSR)) & RTL_SPI_SFCSR_RDY)) cpu_relax(); } static void send4(struct rtspi *rtspi, const u32 *buf) { wait_ready(rtspi); set_size(rtspi, 4); - writel(*buf, REG(RTL_SPI_SFDR)); + __raw_writel(*buf, REG(RTL_SPI_SFDR)); } static void send1(struct rtspi *rtspi, const u8 *buf) { wait_ready(rtspi); set_size(rtspi, 1); - writel(buf[0] << 24, REG(RTL_SPI_SFDR)); + __raw_writel(buf[0] << 24, REG(RTL_SPI_SFDR)); } static void rcv4(struct rtspi *rtspi, u32 *buf) { wait_ready(rtspi); set_size(rtspi, 4); - *buf = readl(REG(RTL_SPI_SFDR)); + *buf = __raw_readl(REG(RTL_SPI_SFDR)); } static void rcv1(struct rtspi *rtspi, u8 *buf) { wait_ready(rtspi); set_size(rtspi, 1); - *buf = readl(REG(RTL_SPI_SFDR)) >> 24; + *buf = __raw_readl(REG(RTL_SPI_SFDR)) >> 24; } static int transfer_one(struct spi_controller *ctrl, struct spi_device *spi, @@ -134,16 +134,16 @@ static void init_hw(struct rtspi *rtspi) u32 value; /* Turn on big-endian byte ordering */ - value = readl(REG(RTL_SPI_SFCR)); + value = __raw_readl(REG(RTL_SPI_SFCR)); value |= RTL_SPI_SFCR_RBO | RTL_SPI_SFCR_WBO; - writel(value, REG(RTL_SPI_SFCR)); + __raw_writel(value, REG(RTL_SPI_SFCR)); - value = readl(REG(RTL_SPI_SFCSR)); + value = __raw_readl(REG(RTL_SPI_SFCSR)); /* Permanently disable CS1, since it's never used */ value |= RTL_SPI_SFCSR_CSB1; /* Select CS0 for use */ value &= RTL_SPI_SFCSR_CS; - writel(value, REG(RTL_SPI_SFCSR)); + __raw_writel(value, REG(RTL_SPI_SFCSR)); } static int realtek_rtl_spi_probe(struct platform_device *pdev) diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index b63c7856e758..9a740342d0f7 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -161,6 +161,8 @@ static int rpcif_spi_probe(struct platform_device *pdev) ctlr->dev.of_node = parent->of_node; + pm_runtime_set_autosuspend_delay(rpc->dev, 200); + pm_runtime_use_autosuspend(rpc->dev); pm_runtime_enable(rpc->dev); ctlr->num_chipselect = 1; @@ -183,6 +185,7 @@ static int rpcif_spi_probe(struct platform_device *pdev) return 0; out_disable_rpm: + pm_runtime_dont_use_autosuspend(rpc->dev); pm_runtime_disable(rpc->dev); return error; } @@ -193,6 +196,7 @@ static void rpcif_spi_remove(struct platform_device *pdev) struct rpcif *rpc = spi_controller_get_devdata(ctlr); spi_unregister_controller(ctlr); + pm_runtime_dont_use_autosuspend(rpc->dev); pm_runtime_disable(rpc->dev); } diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c index fd5893a92e59..d03a93d149ec 100644 --- a/drivers/spi/spi-spacemit-k1.c +++ b/drivers/spi/spi-spacemit-k1.c @@ -286,10 +286,12 @@ static int k1_spi_dma_one(struct spi_controller *host, struct spi_device *spi, if (!txdesc) goto fallback; - /* Prepare the RX descriptor */ + /* Prepare the RX descriptor and submit it */ rxdesc = k1_spi_dma_prep(drv_data, transfer, false); - if (!rxdesc) + if (!rxdesc) { + dmaengine_terminate_sync(host->dma_tx); goto fallback; + } /* When RX is complete we also know TX has completed */ rxdesc->callback = k1_spi_dma_callback; @@ -735,12 +737,12 @@ static int k1_spi_probe(struct platform_device *pdev) drv_data->irq = platform_get_irq(pdev, 0); if (drv_data->irq < 0) - return dev_err_probe(dev, drv_data->irq, "error getting IRQ\n"); + return drv_data->irq; ret = devm_request_irq(dev, drv_data->irq, k1_spi_ssp_isr, IRQF_SHARED, dev_name(dev), drv_data); if (ret < 0) - return dev_err_probe(dev, ret, "error requesting IRQ\n"); + return ret; /* Initialize the host structure, then register it */ host->dev.of_node = dev_of_node(dev); diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 0991ef7ec092..29a53bbc0dd4 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -81,13 +81,16 @@ struct geni_se { }; /* Common SE registers */ +#define GENI_GENERAL_CFG 0x10 #define GENI_FORCE_DEFAULT_REG 0x20 #define GENI_OUTPUT_CTRL 0x24 #define SE_GENI_STATUS 0x40 #define GENI_SER_M_CLK_CFG 0x48 #define GENI_SER_S_CLK_CFG 0x4c +#define GENI_CLK_CTRL_RO 0x60 #define GENI_IF_DISABLE_RO 0x64 #define GENI_FW_REVISION_RO 0x68 +#define GENI_FW_MULTILOCK_MSA_RO 0x74 #define SE_GENI_CLK_SEL 0x7c #define SE_GENI_CFG_SEQ_START 0x84 #define SE_GENI_DMA_MODE_EN 0x258 @@ -98,6 +101,8 @@ struct geni_se { #define SE_GENI_M_IRQ_CLEAR 0x618 #define SE_GENI_M_IRQ_EN_SET 0x61c #define SE_GENI_M_IRQ_EN_CLEAR 0x620 +#define M_CMD_ERR_STATUS 0x624 +#define M_FW_ERR_STATUS 0x628 #define SE_GENI_S_CMD0 0x630 #define SE_GENI_S_CMD_CTRL_REG 0x634 #define SE_GENI_S_IRQ_STATUS 0x640 @@ -115,16 +120,43 @@ struct geni_se { #define SE_GENI_IOS 0x908 #define SE_GENI_M_GP_LENGTH 0x910 #define SE_GENI_S_GP_LENGTH 0x914 +/* TX DMA registers */ +#define SE_DMA_TX_PTR_L 0xc30 +#define SE_DMA_TX_PTR_H 0xc34 +#define SE_DMA_TX_ATTR 0xc38 +#define SE_DMA_TX_LEN 0xc3c #define SE_DMA_TX_IRQ_STAT 0xc40 #define SE_DMA_TX_IRQ_CLR 0xc44 +#define SE_DMA_TX_IRQ_EN 0xc48 +#define SE_DMA_TX_IRQ_EN_SET 0xc4c +#define SE_DMA_TX_IRQ_EN_CLR 0xc50 +#define SE_DMA_TX_LEN_IN 0xc54 #define SE_DMA_TX_FSM_RST 0xc58 +#define SE_DMA_TX_MAX_BURST 0xc5c +/* RX DMA registers */ +#define SE_DMA_RX_PTR_L 0xd30 +#define SE_DMA_RX_PTR_H 0xd34 +#define SE_DMA_RX_ATTR 0xd38 +#define SE_DMA_RX_LEN 0xd3c #define SE_DMA_RX_IRQ_STAT 0xd40 #define SE_DMA_RX_IRQ_CLR 0xd44 +#define SE_DMA_RX_IRQ_EN 0xd48 +#define SE_DMA_RX_IRQ_EN_SET 0xd4c +#define SE_DMA_RX_IRQ_EN_CLR 0xd50 #define SE_DMA_RX_LEN_IN 0xd54 #define SE_DMA_RX_FSM_RST 0xd58 +#define SE_DMA_RX_MAX_BURST 0xd5c +/* DMA general / debug registers */ +#define SE_GSI_EVENT_EN 0xe18 +#define SE_IRQ_EN 0xe1c +#define DMA_IF_EN_RO 0xe20 #define SE_HW_PARAM_0 0xe24 #define SE_HW_PARAM_1 0xe28 #define SE_HW_PARAM_2 0xe2c +#define DMA_GENERAL_CFG 0xe30 +#define SE_DMA_QSB_TRANS_CFG 0xe38 +#define SE_DMA_DEBUG_REG0 0xe40 +#define SE_DMA_IF_EN 0x2004 /* GENI_FORCE_DEFAULT_REG fields */ #define FORCE_DEFAULT BIT(0) @@ -270,6 +302,12 @@ struct geni_se { #define RX_GENI_GP_IRQ_EXT GENMASK(13, 12) #define RX_GENI_CANCEL_IRQ BIT(14) +/* SE_DMA_DEBUG_REG0 fields */ +#define DMA_TX_ACTIVE BIT(0) +#define DMA_RX_ACTIVE BIT(1) +#define DMA_TX_STATE GENMASK(7, 4) +#define DMA_RX_STATE GENMASK(11, 8) + /* SE_HW_PARAM_0 fields */ #define TX_FIFO_WIDTH_MSK GENMASK(29, 24) #define TX_FIFO_WIDTH_SHFT 24 diff --git a/include/trace/events/qcom_geni_se.h b/include/trace/events/qcom_geni_se.h new file mode 100644 index 000000000000..4a6e1ba2d147 --- /dev/null +++ b/include/trace/events/qcom_geni_se.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_geni_se + +#if !defined(_TRACE_QCOM_GENI_SE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_QCOM_GENI_SE_H + +#include +#include +#include + +TRACE_EVENT(geni_se_regs, + TP_PROTO(struct geni_se *se), + + TP_ARGS(se), + + TP_STRUCT__entry(__string(geni_se_name, dev_name(se->dev)) + __field(u32, geni_se_m_cmd0) + __field(u32, geni_se_m_irq_status) + __field(u32, geni_se_s_cmd0) + __field(u32, geni_se_s_irq_status) + __field(u32, geni_se_status) + __field(u32, geni_se_ios) + __field(u32, geni_se_m_cmd_ctrl) + __field(u32, geni_se_m_cmd_err) + __field(u32, geni_se_m_fw_err) + __field(u32, geni_se_tx_fifo_status) + __field(u32, geni_se_rx_fifo_status) + __field(u32, geni_se_tx_watermark) + __field(u32, geni_se_rx_watermark) + __field(u32, geni_se_rx_watermark_rfr) + __field(u32, geni_se_m_gp_length) + __field(u32, geni_se_s_gp_length) + __field(u32, geni_se_dma_tx_irq) + __field(u32, geni_se_dma_rx_irq) + __field(u32, geni_se_dma_tx_irq_en) + __field(u32, geni_se_dma_rx_irq_en) + __field(u32, geni_se_dma_rx_len) + __field(u32, geni_se_dma_rx_len_in) + __field(u32, geni_se_dma_tx_len) + __field(u32, geni_se_dma_tx_len_in) + __field(u32, geni_se_dma_tx_ptr_l) + __field(u32, geni_se_dma_tx_ptr_h) + __field(u32, geni_se_dma_rx_ptr_l) + __field(u32, geni_se_dma_rx_ptr_h) + __field(u32, geni_se_dma_tx_attr) + __field(u32, geni_se_dma_tx_max_burst) + __field(u32, geni_se_dma_rx_attr) + __field(u32, geni_se_dma_rx_max_burst) + __field(u32, geni_se_dma_if_en) + __field(u32, geni_se_dma_if_en_ro) + __field(u32, geni_se_dma_general_cfg) + __field(u32, geni_se_dma_qsb_trans_cfg) + __field(u32, geni_se_dma_dbg) + __field(u32, geni_se_m_irq_en) + __field(u32, geni_se_s_irq_en) + __field(u32, geni_se_gsi_event_en) + __field(u32, geni_se_irq_en) + __field(u32, geni_se_ser_m_clk_cfg) + __field(u32, geni_se_ser_s_clk_cfg) + __field(u32, geni_se_general_cfg) + __field(u32, geni_se_output_ctrl) + __field(u32, geni_se_clk_ctrl_ro) + __field(u32, geni_se_fifo_if_disable) + __field(u32, geni_se_fw_multilock_msa) + __field(u32, geni_se_clk_sel) + ), + + TP_fast_assign(__assign_str(geni_se_name); + __entry->geni_se_m_cmd0 = readl(se->base + SE_GENI_M_CMD0); + __entry->geni_se_m_irq_status = readl(se->base + SE_GENI_M_IRQ_STATUS); + __entry->geni_se_s_cmd0 = readl(se->base + SE_GENI_S_CMD0); + __entry->geni_se_s_irq_status = readl(se->base + SE_GENI_S_IRQ_STATUS); + __entry->geni_se_status = readl(se->base + SE_GENI_STATUS); + __entry->geni_se_ios = readl(se->base + SE_GENI_IOS); + __entry->geni_se_m_cmd_ctrl = readl(se->base + SE_GENI_M_CMD_CTRL_REG); + __entry->geni_se_m_cmd_err = readl(se->base + M_CMD_ERR_STATUS); + __entry->geni_se_m_fw_err = readl(se->base + M_FW_ERR_STATUS); + __entry->geni_se_tx_fifo_status = readl(se->base + SE_GENI_TX_FIFO_STATUS); + __entry->geni_se_rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS); + __entry->geni_se_tx_watermark = readl(se->base + SE_GENI_TX_WATERMARK_REG); + __entry->geni_se_rx_watermark = readl(se->base + SE_GENI_RX_WATERMARK_REG); + __entry->geni_se_rx_watermark_rfr = readl(se->base + SE_GENI_RX_RFR_WATERMARK_REG); + __entry->geni_se_m_gp_length = readl(se->base + SE_GENI_M_GP_LENGTH); + __entry->geni_se_s_gp_length = readl(se->base + SE_GENI_S_GP_LENGTH); + __entry->geni_se_dma_tx_irq = readl(se->base + SE_DMA_TX_IRQ_STAT); + __entry->geni_se_dma_rx_irq = readl(se->base + SE_DMA_RX_IRQ_STAT); + __entry->geni_se_dma_tx_irq_en = readl(se->base + SE_DMA_TX_IRQ_EN); + __entry->geni_se_dma_rx_irq_en = readl(se->base + SE_DMA_RX_IRQ_EN); + __entry->geni_se_dma_rx_len = readl(se->base + SE_DMA_RX_LEN); + __entry->geni_se_dma_rx_len_in = readl(se->base + SE_DMA_RX_LEN_IN); + __entry->geni_se_dma_tx_len = readl(se->base + SE_DMA_TX_LEN); + __entry->geni_se_dma_tx_len_in = readl(se->base + SE_DMA_TX_LEN_IN); + __entry->geni_se_dma_tx_ptr_l = readl(se->base + SE_DMA_TX_PTR_L); + __entry->geni_se_dma_tx_ptr_h = readl(se->base + SE_DMA_TX_PTR_H); + __entry->geni_se_dma_rx_ptr_l = readl(se->base + SE_DMA_RX_PTR_L); + __entry->geni_se_dma_rx_ptr_h = readl(se->base + SE_DMA_RX_PTR_H); + __entry->geni_se_dma_tx_attr = readl(se->base + SE_DMA_TX_ATTR); + __entry->geni_se_dma_tx_max_burst = readl(se->base + SE_DMA_TX_MAX_BURST); + __entry->geni_se_dma_rx_attr = readl(se->base + SE_DMA_RX_ATTR); + __entry->geni_se_dma_rx_max_burst = readl(se->base + SE_DMA_RX_MAX_BURST); + __entry->geni_se_dma_if_en = readl(se->base + SE_DMA_IF_EN); + __entry->geni_se_dma_if_en_ro = readl(se->base + DMA_IF_EN_RO); + __entry->geni_se_dma_general_cfg = readl(se->base + DMA_GENERAL_CFG); + __entry->geni_se_dma_qsb_trans_cfg = readl(se->base + SE_DMA_QSB_TRANS_CFG); + __entry->geni_se_dma_dbg = readl(se->base + SE_DMA_DEBUG_REG0); + __entry->geni_se_m_irq_en = readl(se->base + SE_GENI_M_IRQ_EN); + __entry->geni_se_s_irq_en = readl(se->base + SE_GENI_S_IRQ_EN); + __entry->geni_se_gsi_event_en = readl(se->base + SE_GSI_EVENT_EN); + __entry->geni_se_irq_en = readl(se->base + SE_IRQ_EN); + __entry->geni_se_ser_m_clk_cfg = readl(se->base + GENI_SER_M_CLK_CFG); + __entry->geni_se_ser_s_clk_cfg = readl(se->base + GENI_SER_S_CLK_CFG); + __entry->geni_se_general_cfg = readl(se->base + GENI_GENERAL_CFG); + __entry->geni_se_output_ctrl = readl(se->base + GENI_OUTPUT_CTRL); + __entry->geni_se_clk_ctrl_ro = readl(se->base + GENI_CLK_CTRL_RO); + __entry->geni_se_fifo_if_disable = readl(se->base + GENI_IF_DISABLE_RO); + __entry->geni_se_fw_multilock_msa = readl(se->base + GENI_FW_MULTILOCK_MSA_RO); + __entry->geni_se_clk_sel = readl(se->base + SE_GENI_CLK_SEL); + ), + + TP_printk("%s: m_cmd0=0x%08x m_irq_status=0x%08x s_cmd0=0x%08x s_irq_status=0x%08x geni_status=0x%08x geni_ios=0x%08x m_cmd_ctrl=0x%08x m_cmd_err=0x%08x m_fw_err=0x%08x tx_fifo_sts=0x%08x rx_fifo_sts=0x%08x tx_watermark=0x%08x rx_watermark=0x%08x rx_watermark_rfr=0x%08x m_gp_length=0x%08x s_gp_length=0x%08x dma_tx_irq=0x%08x dma_rx_irq=0x%08x dma_tx_irq_en=0x%08x dma_rx_irq_en=0x%08x dma_rx_len=0x%08x dma_rx_len_in=0x%08x dma_tx_len=0x%08x dma_tx_len_in=0x%08x dma_tx_ptr_l=0x%08x dma_tx_ptr_h=0x%08x dma_rx_ptr_l=0x%08x dma_rx_ptr_h=0x%08x dma_tx_attr=0x%08x dma_tx_max_burst=0x%08x dma_rx_attr=0x%08x dma_rx_max_burst=0x%08x dma_if_en=0x%08x dma_if_en_ro=0x%08x dma_general_cfg=0x%08x dma_qsb_trans_cfg=0x%08x dma_dbg=0x%08x m_irq_en=0x%08x s_irq_en=0x%08x gsi_event_en=0x%08x se_irq_en=0x%08x ser_m_clk_cfg=0x%08x ser_s_clk_cfg=0x%08x general_cfg=0x%08x output_ctrl=0x%08x clk_ctrl_ro=0x%08x fifo_if_dis=0x%08x fw_multilock_msa=0x%08x clk_sel=0x%08x", + __get_str(geni_se_name), + __entry->geni_se_m_cmd0, __entry->geni_se_m_irq_status, + __entry->geni_se_s_cmd0, __entry->geni_se_s_irq_status, + __entry->geni_se_status, __entry->geni_se_ios, + __entry->geni_se_m_cmd_ctrl, + __entry->geni_se_m_cmd_err, __entry->geni_se_m_fw_err, + __entry->geni_se_tx_fifo_status, __entry->geni_se_rx_fifo_status, + __entry->geni_se_tx_watermark, __entry->geni_se_rx_watermark, + __entry->geni_se_rx_watermark_rfr, + __entry->geni_se_m_gp_length, __entry->geni_se_s_gp_length, + __entry->geni_se_dma_tx_irq, __entry->geni_se_dma_rx_irq, + __entry->geni_se_dma_tx_irq_en, __entry->geni_se_dma_rx_irq_en, + __entry->geni_se_dma_rx_len, __entry->geni_se_dma_rx_len_in, + __entry->geni_se_dma_tx_len, __entry->geni_se_dma_tx_len_in, + __entry->geni_se_dma_tx_ptr_l, __entry->geni_se_dma_tx_ptr_h, + __entry->geni_se_dma_rx_ptr_l, __entry->geni_se_dma_rx_ptr_h, + __entry->geni_se_dma_tx_attr, __entry->geni_se_dma_tx_max_burst, + __entry->geni_se_dma_rx_attr, __entry->geni_se_dma_rx_max_burst, + __entry->geni_se_dma_if_en, __entry->geni_se_dma_if_en_ro, + __entry->geni_se_dma_general_cfg, __entry->geni_se_dma_qsb_trans_cfg, + __entry->geni_se_dma_dbg, + __entry->geni_se_m_irq_en, __entry->geni_se_s_irq_en, + __entry->geni_se_gsi_event_en, __entry->geni_se_irq_en, + __entry->geni_se_ser_m_clk_cfg, __entry->geni_se_ser_s_clk_cfg, + __entry->geni_se_general_cfg, __entry->geni_se_output_ctrl, + __entry->geni_se_clk_ctrl_ro, __entry->geni_se_fifo_if_disable, + __entry->geni_se_fw_multilock_msa, __entry->geni_se_clk_sel) +); + +#endif /* _TRACE_QCOM_GENI_SE_H */ + +/* This part must be outside protection */ +#include