mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-28 09:39:00 +00:00
e2e2fc3cd0
Add updated patches for 6.6. DMA/cache-handling patches have been reworked / backported from upstream. Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
404 lines
11 KiB
Diff
404 lines
11 KiB
Diff
From 733e7bd23a1efad15a724fbdbce8d9f06aa6813a Mon Sep 17 00:00:00 2001
|
|
From: "ziv.xu" <ziv.xu@starfive.com>
|
|
Date: Wed, 23 Nov 2022 14:53:58 +0800
|
|
Subject: [PATCH 103/116] spi-pl022-starfive:fix the problem of spi overlay
|
|
reload
|
|
|
|
fix the problem of spi overlay reload
|
|
|
|
Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
|
Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
|
|
---
|
|
drivers/spi/spi-pl022.c | 270 ++++++++++++++++++++++++++++------------
|
|
1 file changed, 188 insertions(+), 82 deletions(-)
|
|
|
|
--- a/drivers/spi/spi-pl022.c
|
|
+++ b/drivers/spi/spi-pl022.c
|
|
@@ -2106,6 +2106,172 @@ pl022_platform_data_dt_get(struct device
|
|
return pd;
|
|
}
|
|
|
|
+static int pl022_platform_probe(struct platform_device *pdev, const struct amba_id *id)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct spi_controller *host;
|
|
+ struct pl022_ssp_controller *platform_info;
|
|
+ struct amba_device *adev;
|
|
+ struct pl022 *pl022 = NULL;
|
|
+ struct resource *res;
|
|
+ int status = 0;
|
|
+ int irq;
|
|
+
|
|
+ dev_info(dev,
|
|
+ "ARM PL022 driver for StarFive SoC platform, device ID: 0x%08x\n",
|
|
+ id->id);
|
|
+
|
|
+ adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL);
|
|
+ adev->dev = pdev->dev;
|
|
+ platform_info = pl022_platform_data_dt_get(dev);
|
|
+ if (!platform_info) {
|
|
+ dev_err(dev, "probe: no platform data defined\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ /* Allocate host with space for data */
|
|
+ host = spi_alloc_host(dev, sizeof(struct pl022));
|
|
+ if (host == NULL) {
|
|
+ dev_err(dev, "probe - cannot alloc SPI host\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ pl022 = spi_controller_get_devdata(host);
|
|
+ pl022->host = host;
|
|
+ pl022->host_info = platform_info;
|
|
+ pl022->adev = adev;
|
|
+ pl022->vendor = id->data;
|
|
+ pl022->host->dev.parent = &pdev->dev;
|
|
+ /*
|
|
+ * Bus Number Which has been Assigned to this SSP controller
|
|
+ * on this board
|
|
+ */
|
|
+ host->bus_num = platform_info->bus_id;
|
|
+ host->cleanup = pl022_cleanup;
|
|
+ host->setup = pl022_setup;
|
|
+ /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/
|
|
+ host->auto_runtime_pm = true;
|
|
+ host->transfer_one_message = pl022_transfer_one_message;
|
|
+ host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
|
|
+ host->rt = platform_info->rt;
|
|
+ host->dev.of_node = dev->of_node;
|
|
+ host->use_gpio_descriptors = true;
|
|
+
|
|
+ /*
|
|
+ * Supports mode 0-3, loopback, and active low CS. Transfers are
|
|
+ * always MS bit first on the original pl022.
|
|
+ */
|
|
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
|
+ if (pl022->vendor->extended_cr)
|
|
+ host->mode_bits |= SPI_LSB_FIRST;
|
|
+
|
|
+ dev_dbg(dev, "BUSNO: %d\n", host->bus_num);
|
|
+
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
+ pl022->phybase = res->start;
|
|
+ pl022->virtbase = devm_ioremap_resource(dev, res);
|
|
+ if (pl022->virtbase == NULL) {
|
|
+ status = -ENOMEM;
|
|
+ goto err_no_ioremap;
|
|
+ }
|
|
+ dev_info(dev, "mapped registers from %llx to %llx\n",
|
|
+ pdev->resource->start, pdev->resource->end);
|
|
+
|
|
+ pl022->clk = devm_clk_get(dev, NULL);
|
|
+ if (IS_ERR(pl022->clk)) {
|
|
+ status = PTR_ERR(pl022->clk);
|
|
+ dev_err(dev, "could not retrieve SSP/SPI bus clock\n");
|
|
+ goto err_no_clk;
|
|
+ }
|
|
+ status = clk_prepare_enable(pl022->clk);
|
|
+ if (status) {
|
|
+ dev_err(dev, "could not enable SSP/SPI bus clock\n");
|
|
+ goto err_no_clk_en;
|
|
+ }
|
|
+
|
|
+ pl022->rst = devm_reset_control_get_exclusive(dev, NULL);
|
|
+ if (!IS_ERR(pl022->rst)) {
|
|
+ status = reset_control_deassert(pl022->rst);
|
|
+ if (status) {
|
|
+ dev_err(dev, "could not deassert SSP/SPI bus reset\n");
|
|
+ goto err_no_rst_clr;
|
|
+ }
|
|
+ } else {
|
|
+ status = PTR_ERR(pl022->rst);
|
|
+ dev_err(dev, "could not retrieve SSP/SPI bus reset\n");
|
|
+ goto err_no_rst;
|
|
+ }
|
|
+
|
|
+ /* Initialize transfer pump */
|
|
+ tasklet_init(&pl022->pump_transfers, pump_transfers,
|
|
+ (unsigned long)pl022);
|
|
+
|
|
+ /* Disable SSP */
|
|
+ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
|
|
+ SSP_CR1(pl022->virtbase));
|
|
+ load_ssp_default_config(pl022);
|
|
+
|
|
+ /* Obtain IRQ line. */
|
|
+ irq = platform_get_irq(pdev, 0);
|
|
+ if (irq < 0) {
|
|
+ status = -ENXIO;
|
|
+ goto err_no_irq;
|
|
+ }
|
|
+ status = devm_request_irq(dev, irq, pl022_interrupt_handler,
|
|
+ 0, "pl022", pl022);
|
|
+ if (status < 0) {
|
|
+ dev_err(dev, "probe - cannot get IRQ (%d)\n", status);
|
|
+ goto err_no_irq;
|
|
+ }
|
|
+
|
|
+ /* Get DMA channels, try autoconfiguration first */
|
|
+ status = pl022_dma_autoprobe(pl022);
|
|
+ if (status == -EPROBE_DEFER) {
|
|
+ dev_dbg(dev, "deferring probe to get DMA channel\n");
|
|
+ goto err_no_irq;
|
|
+ }
|
|
+
|
|
+ /* dma is not used unless configured in the device tree */
|
|
+ platform_info->enable_dma = 0;
|
|
+
|
|
+ /* If that failed, use channels from platform_info */
|
|
+ if (status == 0)
|
|
+ platform_info->enable_dma = 1;
|
|
+ else if (platform_info->enable_dma) {
|
|
+ status = pl022_dma_probe(pl022);
|
|
+ if (status != 0)
|
|
+ platform_info->enable_dma = 0;
|
|
+ }
|
|
+
|
|
+ /* Register with the SPI framework */
|
|
+ dev_set_drvdata(dev, pl022);
|
|
+
|
|
+ status = devm_spi_register_controller(dev, host);
|
|
+ if (status != 0) {
|
|
+ dev_err(dev,
|
|
+ "probe - problem registering spi host\n");
|
|
+ goto err_spi_register;
|
|
+ }
|
|
+ dev_dbg(dev, "probe succeeded\n");
|
|
+
|
|
+ clk_disable_unprepare(pl022->clk);
|
|
+
|
|
+ return 0;
|
|
+ err_spi_register:
|
|
+ if (platform_info->enable_dma)
|
|
+ pl022_dma_remove(pl022);
|
|
+ err_no_irq:
|
|
+ reset_control_assert(pl022->rst);
|
|
+ err_no_rst_clr:
|
|
+ err_no_rst:
|
|
+ clk_disable_unprepare(pl022->clk);
|
|
+ err_no_clk_en:
|
|
+ err_no_clk:
|
|
+ err_no_ioremap:
|
|
+ release_mem_region(pdev->resource->start, resource_size(pdev->resource));
|
|
+ spi_controller_put(host);
|
|
+ return status;
|
|
+}
|
|
+
|
|
static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
|
{
|
|
struct device *dev = &adev->dev;
|
|
@@ -2114,14 +2280,6 @@ static int pl022_probe(struct amba_devic
|
|
struct spi_controller *host;
|
|
struct pl022 *pl022 = NULL; /*Data for this driver */
|
|
int status = 0;
|
|
- int platform_flag = 0;
|
|
-
|
|
- if (strncmp(dev->bus->name, "platform", strlen("platform")))
|
|
- platform_flag = 0;
|
|
- else
|
|
- platform_flag = 1;
|
|
- dev_dbg(&adev->dev, "bus name:%s platform flag:%d",
|
|
- dev->bus->name, platform_flag);
|
|
|
|
dev_info(&adev->dev,
|
|
"ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
|
|
@@ -2175,11 +2333,7 @@ static int pl022_probe(struct amba_devic
|
|
goto err_no_ioregion;
|
|
|
|
pl022->phybase = adev->res.start;
|
|
- if (platform_flag)
|
|
- pl022->virtbase = ioremap(adev->res.start,
|
|
- resource_size(&adev->res));
|
|
- else
|
|
- pl022->virtbase = devm_ioremap(dev, adev->res.start,
|
|
+ pl022->virtbase = devm_ioremap(dev, adev->res.start,
|
|
resource_size(&adev->res));
|
|
if (pl022->virtbase == NULL) {
|
|
status = -ENOMEM;
|
|
@@ -2188,10 +2342,7 @@ static int pl022_probe(struct amba_devic
|
|
dev_info(&adev->dev, "mapped registers from %pa to %p\n",
|
|
&adev->res.start, pl022->virtbase);
|
|
|
|
- if (platform_flag)
|
|
- pl022->clk = clk_get(&adev->dev, NULL);
|
|
- else
|
|
- pl022->clk = devm_clk_get(&adev->dev, NULL);
|
|
+ pl022->clk = devm_clk_get(&adev->dev, NULL);
|
|
if (IS_ERR(pl022->clk)) {
|
|
status = PTR_ERR(pl022->clk);
|
|
dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
|
|
@@ -2204,10 +2355,7 @@ static int pl022_probe(struct amba_devic
|
|
goto err_no_clk_en;
|
|
}
|
|
|
|
- if (platform_flag)
|
|
- pl022->rst = reset_control_get_exclusive(&adev->dev, NULL);
|
|
- else
|
|
- pl022->rst = devm_reset_control_get(&adev->dev, NULL);
|
|
+ pl022->rst = devm_reset_control_get(&adev->dev, NULL);
|
|
if (IS_ERR(pl022->rst)) {
|
|
status = PTR_ERR(pl022->rst);
|
|
dev_err(&adev->dev, "could not retrieve SSP/SPI bus reset\n");
|
|
@@ -2229,11 +2377,7 @@ static int pl022_probe(struct amba_devic
|
|
SSP_CR1(pl022->virtbase));
|
|
load_ssp_default_config(pl022);
|
|
|
|
- if (platform_flag)
|
|
- status = request_irq(adev->irq[0], pl022_interrupt_handler,
|
|
- 0, "pl022", pl022);
|
|
- else
|
|
- status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
|
|
+ status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler,
|
|
0, "pl022", pl022);
|
|
if (status < 0) {
|
|
dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
|
|
@@ -2258,18 +2402,16 @@ static int pl022_probe(struct amba_devic
|
|
|
|
/* Register with the SPI framework */
|
|
amba_set_drvdata(adev, pl022);
|
|
- if (platform_flag)
|
|
- status = spi_register_controller(host);
|
|
- else
|
|
- status = devm_spi_register_controller(&adev->dev, host);
|
|
+
|
|
+ status = devm_spi_register_controller(&adev->dev, host);
|
|
if (status != 0) {
|
|
dev_err_probe(&adev->dev, status,
|
|
"problem registering spi host\n");
|
|
goto err_spi_register;
|
|
}
|
|
dev_dbg(dev, "probe succeeded\n");
|
|
- if (!platform_flag)
|
|
- platform_info->autosuspend_delay = 100;
|
|
+
|
|
+ platform_info->autosuspend_delay = 100;
|
|
/* let runtime pm put suspend */
|
|
if (platform_info->autosuspend_delay > 0) {
|
|
dev_info(&adev->dev,
|
|
@@ -2279,10 +2421,8 @@ static int pl022_probe(struct amba_devic
|
|
platform_info->autosuspend_delay);
|
|
pm_runtime_use_autosuspend(dev);
|
|
}
|
|
- if (platform_flag)
|
|
- clk_disable_unprepare(pl022->clk);
|
|
- else
|
|
- pm_runtime_put(dev);
|
|
+
|
|
+ pm_runtime_put(dev);
|
|
|
|
return 0;
|
|
|
|
@@ -2290,26 +2430,17 @@ static int pl022_probe(struct amba_devic
|
|
if (platform_info->enable_dma)
|
|
pl022_dma_remove(pl022);
|
|
err_no_irq:
|
|
- if (platform_flag)
|
|
- free_irq(adev->irq[0], pl022);
|
|
reset_control_assert(pl022->rst);
|
|
err_no_rst_de:
|
|
- if (platform_flag)
|
|
- reset_control_put(pl022->rst);
|
|
err_no_rst:
|
|
clk_disable_unprepare(pl022->clk);
|
|
err_no_clk_en:
|
|
- if (platform_flag)
|
|
- clk_put(pl022->clk);
|
|
err_no_clk:
|
|
- if (platform_flag)
|
|
- iounmap(pl022->virtbase);
|
|
err_no_ioremap:
|
|
amba_release_regions(adev);
|
|
err_no_ioregion:
|
|
spi_controller_put(host);
|
|
- if (platform_flag)
|
|
- kfree(platform_info);
|
|
+
|
|
return status;
|
|
}
|
|
|
|
@@ -2523,23 +2654,8 @@ static int starfive_of_pl022_probe(struc
|
|
.mask = 0x000fffff,
|
|
.data = &vendor_arm
|
|
};
|
|
- struct amba_device *pcdev;
|
|
struct device *dev = &pdev->dev;
|
|
|
|
- pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
|
|
- if (!pcdev)
|
|
- return -ENOMEM;
|
|
-
|
|
- pcdev->dev = pdev->dev;
|
|
- pcdev->periphid = id.id;
|
|
- pcdev->res = *(pdev->resource);
|
|
-
|
|
- pcdev->irq[0] = platform_get_irq(pdev, 0);
|
|
- if (pcdev->irq[0] < 0) {
|
|
- dev_err(dev, "failed to get irq\n");
|
|
- ret = -EINVAL;
|
|
- }
|
|
-
|
|
ret = of_clk_set_defaults(dev->of_node, false);
|
|
if (ret < 0)
|
|
goto err_probe;
|
|
@@ -2548,16 +2664,11 @@ static int starfive_of_pl022_probe(struc
|
|
if (ret)
|
|
goto err_probe;
|
|
|
|
- ret = pl022_probe(pcdev, &id);
|
|
+ ret = pl022_platform_probe(pdev, &id);
|
|
|
|
- struct pl022 *pl022 = amba_get_drvdata(pcdev);
|
|
-
|
|
- pl022->host->dev.parent = &pdev->dev;
|
|
- platform_set_drvdata(pdev, pl022);
|
|
-
|
|
- pm_runtime_enable(&pdev->dev);
|
|
- pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
|
|
- pm_runtime_use_autosuspend(&pdev->dev);
|
|
+ pm_runtime_enable(dev);
|
|
+ pm_runtime_set_autosuspend_delay(dev, 100);
|
|
+ pm_runtime_use_autosuspend(dev);
|
|
|
|
if (ret) {
|
|
pm_runtime_disable(dev);
|
|
@@ -2572,32 +2683,27 @@ err_probe:
|
|
|
|
static int starfive_of_pl022_remove(struct platform_device *pdev)
|
|
{
|
|
- u32 size;
|
|
- int irq;
|
|
struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
|
|
|
|
if (!pl022)
|
|
return 0;
|
|
|
|
+ pm_runtime_get_sync(&pdev->dev);
|
|
pm_runtime_get_noresume(&pdev->dev);
|
|
|
|
load_ssp_default_config(pl022);
|
|
if (pl022->host_info->enable_dma)
|
|
pl022_dma_remove(pl022);
|
|
|
|
- irq = platform_get_irq(pdev, 0);
|
|
- free_irq(irq, pl022);
|
|
- reset_control_assert(pl022->rst);
|
|
- reset_control_put(pl022->rst);
|
|
clk_disable_unprepare(pl022->clk);
|
|
- clk_put(pl022->clk);
|
|
- iounmap(pl022->virtbase);
|
|
- kfree(pl022->host_info);
|
|
-
|
|
- size = resource_size(pdev->resource);
|
|
- release_mem_region(pdev->resource->start, size);
|
|
tasklet_disable(&pl022->pump_transfers);
|
|
+
|
|
+ pm_runtime_put_noidle(&pdev->dev);
|
|
pm_runtime_disable(&pdev->dev);
|
|
+ pm_runtime_set_suspended(&pdev->dev);
|
|
+ pm_runtime_put_noidle(&pdev->dev);
|
|
+ dev_pm_domain_detach(&pdev->dev, true);
|
|
+
|
|
return 0;
|
|
}
|
|
|