| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Platform driver for the Synopsys DesignWare DMA Controller |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Copyright (C) 2013 Intel Corporation |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Some parts of this driver are derived from the original dw_dmac. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 12 | | - * published by the Free Software Foundation. |
|---|
| 13 | 10 | */ |
|---|
| 14 | 11 | |
|---|
| 15 | 12 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 20 | 17 | #include <linux/dmaengine.h> |
|---|
| 21 | 18 | #include <linux/dma-mapping.h> |
|---|
| 22 | 19 | #include <linux/of.h> |
|---|
| 23 | | -#include <linux/of_dma.h> |
|---|
| 24 | 20 | #include <linux/acpi.h> |
|---|
| 25 | | -#include <linux/acpi_dma.h> |
|---|
| 26 | 21 | |
|---|
| 27 | 22 | #include "internal.h" |
|---|
| 28 | 23 | |
|---|
| 29 | 24 | #define DRV_NAME "dw_dmac" |
|---|
| 30 | 25 | |
|---|
| 31 | | -static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, |
|---|
| 32 | | - struct of_dma *ofdma) |
|---|
| 33 | | -{ |
|---|
| 34 | | - struct dw_dma *dw = ofdma->of_dma_data; |
|---|
| 35 | | - struct dw_dma_slave slave = { |
|---|
| 36 | | - .dma_dev = dw->dma.dev, |
|---|
| 37 | | - }; |
|---|
| 38 | | - dma_cap_mask_t cap; |
|---|
| 39 | | - |
|---|
| 40 | | - if (dma_spec->args_count != 3) |
|---|
| 41 | | - return NULL; |
|---|
| 42 | | - |
|---|
| 43 | | - slave.src_id = dma_spec->args[0]; |
|---|
| 44 | | - slave.dst_id = dma_spec->args[0]; |
|---|
| 45 | | - slave.m_master = dma_spec->args[1]; |
|---|
| 46 | | - slave.p_master = dma_spec->args[2]; |
|---|
| 47 | | - |
|---|
| 48 | | - if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || |
|---|
| 49 | | - slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || |
|---|
| 50 | | - slave.m_master >= dw->pdata->nr_masters || |
|---|
| 51 | | - slave.p_master >= dw->pdata->nr_masters)) |
|---|
| 52 | | - return NULL; |
|---|
| 53 | | - |
|---|
| 54 | | - dma_cap_zero(cap); |
|---|
| 55 | | - dma_cap_set(DMA_SLAVE, cap); |
|---|
| 56 | | - |
|---|
| 57 | | - /* TODO: there should be a simpler way to do this */ |
|---|
| 58 | | - return dma_request_channel(cap, dw_dma_filter, &slave); |
|---|
| 59 | | -} |
|---|
| 60 | | - |
|---|
| 61 | | -#ifdef CONFIG_ACPI |
|---|
| 62 | | -static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) |
|---|
| 63 | | -{ |
|---|
| 64 | | - struct acpi_dma_spec *dma_spec = param; |
|---|
| 65 | | - struct dw_dma_slave slave = { |
|---|
| 66 | | - .dma_dev = dma_spec->dev, |
|---|
| 67 | | - .src_id = dma_spec->slave_id, |
|---|
| 68 | | - .dst_id = dma_spec->slave_id, |
|---|
| 69 | | - .m_master = 0, |
|---|
| 70 | | - .p_master = 1, |
|---|
| 71 | | - }; |
|---|
| 72 | | - |
|---|
| 73 | | - return dw_dma_filter(chan, &slave); |
|---|
| 74 | | -} |
|---|
| 75 | | - |
|---|
| 76 | | -static void dw_dma_acpi_controller_register(struct dw_dma *dw) |
|---|
| 77 | | -{ |
|---|
| 78 | | - struct device *dev = dw->dma.dev; |
|---|
| 79 | | - struct acpi_dma_filter_info *info; |
|---|
| 80 | | - int ret; |
|---|
| 81 | | - |
|---|
| 82 | | - info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); |
|---|
| 83 | | - if (!info) |
|---|
| 84 | | - return; |
|---|
| 85 | | - |
|---|
| 86 | | - dma_cap_zero(info->dma_cap); |
|---|
| 87 | | - dma_cap_set(DMA_SLAVE, info->dma_cap); |
|---|
| 88 | | - info->filter_fn = dw_dma_acpi_filter; |
|---|
| 89 | | - |
|---|
| 90 | | - ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); |
|---|
| 91 | | - if (ret) |
|---|
| 92 | | - dev_err(dev, "could not register acpi_dma_controller\n"); |
|---|
| 93 | | -} |
|---|
| 94 | | - |
|---|
| 95 | | -static void dw_dma_acpi_controller_free(struct dw_dma *dw) |
|---|
| 96 | | -{ |
|---|
| 97 | | - struct device *dev = dw->dma.dev; |
|---|
| 98 | | - |
|---|
| 99 | | - acpi_dma_controller_free(dev); |
|---|
| 100 | | -} |
|---|
| 101 | | -#else /* !CONFIG_ACPI */ |
|---|
| 102 | | -static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} |
|---|
| 103 | | -static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} |
|---|
| 104 | | -#endif /* !CONFIG_ACPI */ |
|---|
| 105 | | - |
|---|
| 106 | | -#ifdef CONFIG_OF |
|---|
| 107 | | -static struct dw_dma_platform_data * |
|---|
| 108 | | -dw_dma_parse_dt(struct platform_device *pdev) |
|---|
| 109 | | -{ |
|---|
| 110 | | - struct device_node *np = pdev->dev.of_node; |
|---|
| 111 | | - struct dw_dma_platform_data *pdata; |
|---|
| 112 | | - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; |
|---|
| 113 | | - u32 nr_masters; |
|---|
| 114 | | - u32 nr_channels; |
|---|
| 115 | | - |
|---|
| 116 | | - if (!np) { |
|---|
| 117 | | - dev_err(&pdev->dev, "Missing DT data\n"); |
|---|
| 118 | | - return NULL; |
|---|
| 119 | | - } |
|---|
| 120 | | - |
|---|
| 121 | | - if (of_property_read_u32(np, "dma-masters", &nr_masters)) |
|---|
| 122 | | - return NULL; |
|---|
| 123 | | - if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) |
|---|
| 124 | | - return NULL; |
|---|
| 125 | | - |
|---|
| 126 | | - if (of_property_read_u32(np, "dma-channels", &nr_channels)) |
|---|
| 127 | | - return NULL; |
|---|
| 128 | | - if (nr_channels > DW_DMA_MAX_NR_CHANNELS) |
|---|
| 129 | | - return NULL; |
|---|
| 130 | | - |
|---|
| 131 | | - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
|---|
| 132 | | - if (!pdata) |
|---|
| 133 | | - return NULL; |
|---|
| 134 | | - |
|---|
| 135 | | - pdata->nr_masters = nr_masters; |
|---|
| 136 | | - pdata->nr_channels = nr_channels; |
|---|
| 137 | | - |
|---|
| 138 | | - if (of_property_read_bool(np, "is_private")) |
|---|
| 139 | | - pdata->is_private = true; |
|---|
| 140 | | - |
|---|
| 141 | | - /* |
|---|
| 142 | | - * All known devices, which use DT for configuration, support |
|---|
| 143 | | - * memory-to-memory transfers. So enable it by default. |
|---|
| 144 | | - */ |
|---|
| 145 | | - pdata->is_memcpy = true; |
|---|
| 146 | | - |
|---|
| 147 | | - if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) |
|---|
| 148 | | - pdata->chan_allocation_order = (unsigned char)tmp; |
|---|
| 149 | | - |
|---|
| 150 | | - if (!of_property_read_u32(np, "chan_priority", &tmp)) |
|---|
| 151 | | - pdata->chan_priority = tmp; |
|---|
| 152 | | - |
|---|
| 153 | | - if (!of_property_read_u32(np, "block_size", &tmp)) |
|---|
| 154 | | - pdata->block_size = tmp; |
|---|
| 155 | | - |
|---|
| 156 | | - if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { |
|---|
| 157 | | - for (tmp = 0; tmp < nr_masters; tmp++) |
|---|
| 158 | | - pdata->data_width[tmp] = arr[tmp]; |
|---|
| 159 | | - } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { |
|---|
| 160 | | - for (tmp = 0; tmp < nr_masters; tmp++) |
|---|
| 161 | | - pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); |
|---|
| 162 | | - } |
|---|
| 163 | | - |
|---|
| 164 | | - if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { |
|---|
| 165 | | - for (tmp = 0; tmp < nr_channels; tmp++) |
|---|
| 166 | | - pdata->multi_block[tmp] = mb[tmp]; |
|---|
| 167 | | - } else { |
|---|
| 168 | | - for (tmp = 0; tmp < nr_channels; tmp++) |
|---|
| 169 | | - pdata->multi_block[tmp] = 1; |
|---|
| 170 | | - } |
|---|
| 171 | | - |
|---|
| 172 | | - if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { |
|---|
| 173 | | - if (tmp > CHAN_PROTCTL_MASK) |
|---|
| 174 | | - return NULL; |
|---|
| 175 | | - pdata->protctl = tmp; |
|---|
| 176 | | - } |
|---|
| 177 | | - |
|---|
| 178 | | - return pdata; |
|---|
| 179 | | -} |
|---|
| 180 | | -#else |
|---|
| 181 | | -static inline struct dw_dma_platform_data * |
|---|
| 182 | | -dw_dma_parse_dt(struct platform_device *pdev) |
|---|
| 183 | | -{ |
|---|
| 184 | | - return NULL; |
|---|
| 185 | | -} |
|---|
| 186 | | -#endif |
|---|
| 187 | | - |
|---|
| 188 | 26 | static int dw_probe(struct platform_device *pdev) |
|---|
| 189 | 27 | { |
|---|
| 28 | + const struct dw_dma_chip_pdata *match; |
|---|
| 29 | + struct dw_dma_chip_pdata *data; |
|---|
| 190 | 30 | struct dw_dma_chip *chip; |
|---|
| 191 | 31 | struct device *dev = &pdev->dev; |
|---|
| 192 | | - struct resource *mem; |
|---|
| 193 | | - const struct dw_dma_platform_data *pdata; |
|---|
| 194 | 32 | int err; |
|---|
| 33 | + |
|---|
| 34 | + match = device_get_match_data(dev); |
|---|
| 35 | + if (!match) |
|---|
| 36 | + return -ENODEV; |
|---|
| 37 | + |
|---|
| 38 | + data = devm_kmemdup(&pdev->dev, match, sizeof(*match), GFP_KERNEL); |
|---|
| 39 | + if (!data) |
|---|
| 40 | + return -ENOMEM; |
|---|
| 195 | 41 | |
|---|
| 196 | 42 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); |
|---|
| 197 | 43 | if (!chip) |
|---|
| .. | .. |
|---|
| 201 | 47 | if (chip->irq < 0) |
|---|
| 202 | 48 | return chip->irq; |
|---|
| 203 | 49 | |
|---|
| 204 | | - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 205 | | - chip->regs = devm_ioremap_resource(dev, mem); |
|---|
| 50 | + chip->regs = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 206 | 51 | if (IS_ERR(chip->regs)) |
|---|
| 207 | 52 | return PTR_ERR(chip->regs); |
|---|
| 208 | 53 | |
|---|
| .. | .. |
|---|
| 210 | 55 | if (err) |
|---|
| 211 | 56 | return err; |
|---|
| 212 | 57 | |
|---|
| 213 | | - pdata = dev_get_platdata(dev); |
|---|
| 214 | | - if (!pdata) |
|---|
| 215 | | - pdata = dw_dma_parse_dt(pdev); |
|---|
| 58 | + if (!data->pdata) |
|---|
| 59 | + data->pdata = dev_get_platdata(dev); |
|---|
| 60 | + if (!data->pdata) |
|---|
| 61 | + data->pdata = dw_dma_parse_dt(pdev); |
|---|
| 216 | 62 | |
|---|
| 217 | 63 | chip->dev = dev; |
|---|
| 218 | 64 | chip->id = pdev->id; |
|---|
| 219 | | - chip->pdata = pdata; |
|---|
| 65 | + chip->pdata = data->pdata; |
|---|
| 220 | 66 | |
|---|
| 221 | | - chip->clk = devm_clk_get(chip->dev, "hclk"); |
|---|
| 67 | + data->chip = chip; |
|---|
| 68 | + |
|---|
| 69 | + chip->clk = devm_clk_get_optional(chip->dev, "hclk"); |
|---|
| 222 | 70 | if (IS_ERR(chip->clk)) |
|---|
| 223 | 71 | return PTR_ERR(chip->clk); |
|---|
| 224 | 72 | err = clk_prepare_enable(chip->clk); |
|---|
| .. | .. |
|---|
| 227 | 75 | |
|---|
| 228 | 76 | pm_runtime_enable(&pdev->dev); |
|---|
| 229 | 77 | |
|---|
| 230 | | - err = dw_dma_probe(chip); |
|---|
| 78 | + err = data->probe(chip); |
|---|
| 231 | 79 | if (err) |
|---|
| 232 | 80 | goto err_dw_dma_probe; |
|---|
| 233 | 81 | |
|---|
| 234 | | - platform_set_drvdata(pdev, chip); |
|---|
| 82 | + platform_set_drvdata(pdev, data); |
|---|
| 235 | 83 | |
|---|
| 236 | | - if (pdev->dev.of_node) { |
|---|
| 237 | | - err = of_dma_controller_register(pdev->dev.of_node, |
|---|
| 238 | | - dw_dma_of_xlate, chip->dw); |
|---|
| 239 | | - if (err) |
|---|
| 240 | | - dev_err(&pdev->dev, |
|---|
| 241 | | - "could not register of_dma_controller\n"); |
|---|
| 242 | | - } |
|---|
| 84 | + dw_dma_of_controller_register(chip->dw); |
|---|
| 243 | 85 | |
|---|
| 244 | | - if (ACPI_HANDLE(&pdev->dev)) |
|---|
| 245 | | - dw_dma_acpi_controller_register(chip->dw); |
|---|
| 86 | + dw_dma_acpi_controller_register(chip->dw); |
|---|
| 246 | 87 | |
|---|
| 247 | 88 | return 0; |
|---|
| 248 | 89 | |
|---|
| .. | .. |
|---|
| 254 | 95 | |
|---|
| 255 | 96 | static int dw_remove(struct platform_device *pdev) |
|---|
| 256 | 97 | { |
|---|
| 257 | | - struct dw_dma_chip *chip = platform_get_drvdata(pdev); |
|---|
| 98 | + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); |
|---|
| 99 | + struct dw_dma_chip *chip = data->chip; |
|---|
| 100 | + int ret; |
|---|
| 258 | 101 | |
|---|
| 259 | | - if (ACPI_HANDLE(&pdev->dev)) |
|---|
| 260 | | - dw_dma_acpi_controller_free(chip->dw); |
|---|
| 102 | + dw_dma_acpi_controller_free(chip->dw); |
|---|
| 261 | 103 | |
|---|
| 262 | | - if (pdev->dev.of_node) |
|---|
| 263 | | - of_dma_controller_free(pdev->dev.of_node); |
|---|
| 104 | + dw_dma_of_controller_free(chip->dw); |
|---|
| 264 | 105 | |
|---|
| 265 | | - dw_dma_remove(chip); |
|---|
| 106 | + ret = data->remove(chip); |
|---|
| 107 | + if (ret) |
|---|
| 108 | + dev_warn(chip->dev, "can't remove device properly: %d\n", ret); |
|---|
| 109 | + |
|---|
| 266 | 110 | pm_runtime_disable(&pdev->dev); |
|---|
| 267 | 111 | clk_disable_unprepare(chip->clk); |
|---|
| 268 | 112 | |
|---|
| .. | .. |
|---|
| 271 | 115 | |
|---|
| 272 | 116 | static void dw_shutdown(struct platform_device *pdev) |
|---|
| 273 | 117 | { |
|---|
| 274 | | - struct dw_dma_chip *chip = platform_get_drvdata(pdev); |
|---|
| 118 | + struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev); |
|---|
| 119 | + struct dw_dma_chip *chip = data->chip; |
|---|
| 275 | 120 | |
|---|
| 276 | 121 | /* |
|---|
| 277 | | - * We have to call dw_dma_disable() to stop any ongoing transfer. On |
|---|
| 122 | + * We have to call do_dw_dma_disable() to stop any ongoing transfer. On |
|---|
| 278 | 123 | * some platforms we can't do that since DMA device is powered off. |
|---|
| 279 | 124 | * Moreover we have no possibility to check if the platform is affected |
|---|
| 280 | 125 | * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put() |
|---|
| .. | .. |
|---|
| 283 | 128 | * used by the driver. |
|---|
| 284 | 129 | */ |
|---|
| 285 | 130 | pm_runtime_get_sync(chip->dev); |
|---|
| 286 | | - dw_dma_disable(chip); |
|---|
| 131 | + do_dw_dma_disable(chip); |
|---|
| 287 | 132 | pm_runtime_put_sync_suspend(chip->dev); |
|---|
| 288 | 133 | |
|---|
| 289 | 134 | clk_disable_unprepare(chip->clk); |
|---|
| .. | .. |
|---|
| 291 | 136 | |
|---|
| 292 | 137 | #ifdef CONFIG_OF |
|---|
| 293 | 138 | static const struct of_device_id dw_dma_of_id_table[] = { |
|---|
| 294 | | - { .compatible = "snps,dma-spear1340" }, |
|---|
| 139 | + { .compatible = "snps,dma-spear1340", .data = &dw_dma_chip_pdata }, |
|---|
| 295 | 140 | {} |
|---|
| 296 | 141 | }; |
|---|
| 297 | 142 | MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); |
|---|
| .. | .. |
|---|
| 299 | 144 | |
|---|
| 300 | 145 | #ifdef CONFIG_ACPI |
|---|
| 301 | 146 | static const struct acpi_device_id dw_dma_acpi_id_table[] = { |
|---|
| 302 | | - { "INTL9C60", 0 }, |
|---|
| 147 | + { "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata }, |
|---|
| 148 | + { "80862286", (kernel_ulong_t)&dw_dma_chip_pdata }, |
|---|
| 149 | + { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, |
|---|
| 150 | + |
|---|
| 151 | + /* Elkhart Lake iDMA 32-bit (PSE DMA) */ |
|---|
| 152 | + { "80864BB4", (kernel_ulong_t)&idma32_chip_pdata }, |
|---|
| 153 | + { "80864BB5", (kernel_ulong_t)&idma32_chip_pdata }, |
|---|
| 154 | + { "80864BB6", (kernel_ulong_t)&idma32_chip_pdata }, |
|---|
| 155 | + |
|---|
| 303 | 156 | { } |
|---|
| 304 | 157 | }; |
|---|
| 305 | 158 | MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); |
|---|
| .. | .. |
|---|
| 309 | 162 | |
|---|
| 310 | 163 | static int dw_suspend_late(struct device *dev) |
|---|
| 311 | 164 | { |
|---|
| 312 | | - struct dw_dma_chip *chip = dev_get_drvdata(dev); |
|---|
| 165 | + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); |
|---|
| 166 | + struct dw_dma_chip *chip = data->chip; |
|---|
| 313 | 167 | |
|---|
| 314 | | - dw_dma_disable(chip); |
|---|
| 168 | + do_dw_dma_disable(chip); |
|---|
| 315 | 169 | clk_disable_unprepare(chip->clk); |
|---|
| 316 | 170 | |
|---|
| 317 | 171 | return 0; |
|---|
| .. | .. |
|---|
| 319 | 173 | |
|---|
| 320 | 174 | static int dw_resume_early(struct device *dev) |
|---|
| 321 | 175 | { |
|---|
| 322 | | - struct dw_dma_chip *chip = dev_get_drvdata(dev); |
|---|
| 176 | + struct dw_dma_chip_pdata *data = dev_get_drvdata(dev); |
|---|
| 177 | + struct dw_dma_chip *chip = data->chip; |
|---|
| 323 | 178 | int ret; |
|---|
| 324 | 179 | |
|---|
| 325 | 180 | ret = clk_prepare_enable(chip->clk); |
|---|
| 326 | 181 | if (ret) |
|---|
| 327 | 182 | return ret; |
|---|
| 328 | 183 | |
|---|
| 329 | | - return dw_dma_enable(chip); |
|---|
| 184 | + return do_dw_dma_enable(chip); |
|---|
| 330 | 185 | } |
|---|
| 331 | 186 | |
|---|
| 332 | 187 | #endif /* CONFIG_PM_SLEEP */ |
|---|