diff --git a/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml index f2dd20370dbb..1d10cfbad86c 100644 --- a/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml +++ b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml @@ -9,9 +9,6 @@ title: Freescale Quad Serial Peripheral Interface (QuadSPI) maintainers: - Han Xu -allOf: - - $ref: spi-controller.yaml# - properties: compatible: oneOf: @@ -22,6 +19,7 @@ properties: - fsl,imx6ul-qspi - fsl,ls1021a-qspi - fsl,ls2080a-qspi + - spacemit,k1-qspi - items: - enum: - fsl,ls1043a-qspi @@ -54,6 +52,11 @@ properties: - const: qspi_en - const: qspi + resets: + items: + - description: SoC QSPI reset + - description: SoC QSPI bus reset + required: - compatible - reg @@ -62,6 +65,18 @@ required: - clocks - clock-names +allOf: + - $ref: spi-controller.yaml# + - if: + properties: + compatible: + not: + contains: + const: spacemit,k1-qspi + then: + properties: + resets: false + unevaluatedProperties: false examples: diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4d8f00c850c1..592d46c9998b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -435,7 +435,8 @@ config SPI_FSL_LPSPI config SPI_FSL_QUADSPI tristate "Freescale QSPI controller" - depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST + depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || \ + ARCH_SPACEMIT || COMPILE_TEST depends on HAS_IOMEM help This enables support for the Quad SPI controller in master mode. diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index c887abb028d7..a223b4bc6e63 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -196,11 +197,17 @@ */ #define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5) +/* + * Do not disable the "qspi" clock when changing its rate. + */ +#define QUADSPI_QUIRK_SKIP_CLK_DISABLE BIT(6) + struct fsl_qspi_devtype_data { unsigned int rxfifo; unsigned int txfifo; int invalid_mstrid; unsigned int ahb_buf_size; + unsigned int sfa_size; unsigned int quirks; bool little_endian; }; @@ -261,12 +268,23 @@ static const struct fsl_qspi_devtype_data ls2080a_data = { .little_endian = true, }; +static const struct fsl_qspi_devtype_data spacemit_k1_data = { + .rxfifo = SZ_128, + .txfifo = SZ_256, + .ahb_buf_size = SZ_512, + .sfa_size = SZ_1K, + .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID, + .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_SKIP_CLK_DISABLE, + .little_endian = true, +}; + struct fsl_qspi { void __iomem *iobase; void __iomem *ahb_addr; const struct fsl_qspi_devtype_data *devtype_data; struct mutex lock; struct completion c; + struct reset_control *resets; struct clk *clk, *clk_en; struct pm_qos_request pm_qos_req; struct device *dev; @@ -274,34 +292,39 @@ struct fsl_qspi { u32 memmap_phy; }; -static inline int needs_swap_endian(struct fsl_qspi *q) +static bool needs_swap_endian(struct fsl_qspi *q) { - return q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN; + return !!(q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN); } -static inline int needs_4x_clock(struct fsl_qspi *q) +static bool needs_4x_clock(struct fsl_qspi *q) { - return q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK; + return !!(q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK); } -static inline int needs_fill_txfifo(struct fsl_qspi *q) +static bool needs_fill_txfifo(struct fsl_qspi *q) { - return q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890; + return !!(q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890); } -static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) +static bool needs_wakeup_wait_mode(struct fsl_qspi *q) { - return q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618; + return !!(q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618); } -static inline int needs_amba_base_offset(struct fsl_qspi *q) +static bool needs_amba_base_offset(struct fsl_qspi *q) { return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL); } -static inline int needs_tdh_setting(struct fsl_qspi *q) +static bool needs_tdh_setting(struct fsl_qspi *q) { - return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING; + return !!(q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING); +} + +static bool needs_clk_disable(struct fsl_qspi *q) +{ + return !(q->devtype_data->quirks & QUADSPI_QUIRK_SKIP_CLK_DISABLE); } /* @@ -534,15 +557,18 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi, if (needs_4x_clock(q)) rate *= 4; - fsl_qspi_clk_disable_unprep(q); + if (needs_clk_disable(q)) + fsl_qspi_clk_disable_unprep(q); ret = clk_set_rate(q->clk, rate); if (ret) return; - ret = fsl_qspi_clk_prep_enable(q); - if (ret) - return; + if (needs_clk_disable(q)) { + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return; + } q->selected = spi_get_chipselect(spi, 0); @@ -722,6 +748,7 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q) { void __iomem *base = q->iobase; u32 reg, addr_offset = 0; + u32 sfa_size; int ret; /* disable and unprepare clock to avoid glitch pass to controller */ @@ -780,17 +807,17 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q) * In HW there can be a maximum of four chips on two buses with * two chip selects on each bus. We use four chip selects in SW * to differentiate between the four chips. - * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD, - * SFB2AD accordingly. + * + * By default we write the AHB buffer size to each chip, but + * a different size can be specified with devtype_data->sfa_size. + * The SFA1AD, SFA2AD, SFB1AD, and SFB2AD registers define the + * top (end) of these four regions. */ - qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset, - base + QUADSPI_SFA1AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset, - base + QUADSPI_SFA2AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset, - base + QUADSPI_SFB1AD); - qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset, - base + QUADSPI_SFB2AD); + sfa_size = q->devtype_data->sfa_size ? : q->devtype_data->ahb_buf_size; + qspi_writel(q, addr_offset + 1 * sfa_size, base + QUADSPI_SFA1AD); + qspi_writel(q, addr_offset + 2 * sfa_size, base + QUADSPI_SFA2AD); + qspi_writel(q, addr_offset + 3 * sfa_size, base + QUADSPI_SFB1AD); + qspi_writel(q, addr_offset + 4 * sfa_size, base + QUADSPI_SFB2AD); q->selected = -1; @@ -857,6 +884,8 @@ static void fsl_qspi_cleanup(void *data) { struct fsl_qspi *q = data; + reset_control_assert(q->resets); + fsl_qspi_clk_disable_unprep(q); mutex_destroy(&q->lock); @@ -902,6 +931,10 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (!q->ahb_addr) return -ENOMEM; + q->resets = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(q->resets)) + return PTR_ERR(q->resets); + /* find the clocks */ q->clk_en = devm_clk_get(dev, "qspi_en"); if (IS_ERR(q->clk_en)) @@ -923,6 +956,10 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (ret) return ret; + ret = reset_control_deassert(q->resets); + if (ret) + return ret; + /* find the irq */ ret = platform_get_irq(pdev, 0); if (ret < 0) @@ -976,6 +1013,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = { { .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, }, { .compatible = "fsl,ls1021a-qspi", .data = &ls1021a_data, }, { .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, }, + { .compatible = "spacemit,k1-qspi", .data = &spacemit_k1_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);