aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSinan Kaya <okaya@codeaurora.org>2016-05-01 00:25:28 -0400
committerVinod Koul <vinod.koul@intel.com>2016-05-14 02:24:45 -0400
commit42d236f8a4479fefb69b20da3962a462e05a112d (patch)
tree9befbee1b156578123536c530376cef38f2beeba
parent570d0176296f0d17c4b5ab206ad4a4bc027b863b (diff)
dmaengine: qcom_hidma: add support for object hierarchy
In order to create a relationship model between the channels and the management object, we are adding support for object hierarchy to the drivers. This patch simplifies the userspace application development. We will not have to traverse different firmware paths based on device tree or ACPI based kernels. No matter what flavor of kernel is used, objects will be represented as platform devices. The new layout is as follows: hidmam_10: hidma-mgmt@0x5A000000 { compatible = "qcom,hidma-mgmt-1.0"; ... hidma_10: hidma@0x5a010000 { compatible = "qcom,hidma-1.0"; ... } } The hidma_mgmt_init detects each instance of the hidma-mgmt-1.0 objects in device tree and calls into the channel driver to create platform devices for each child of the management object. Signed-off-by: Sinan Kaya <okaya@codeaurora.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--Documentation/ABI/testing/sysfs-platform-hidma9
-rw-r--r--drivers/dma/qcom/hidma.c39
-rw-r--r--drivers/dma/qcom/hidma_mgmt.c113
3 files changed, 156 insertions, 5 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-hidma b/Documentation/ABI/testing/sysfs-platform-hidma
new file mode 100644
index 000000000000..d36441538660
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-hidma
@@ -0,0 +1,9 @@
1What: /sys/devices/platform/hidma-*/chid
2 /sys/devices/platform/QCOM8061:*/chid
3Date: Dec 2015
4KernelVersion: 4.4
5Contact: "Sinan Kaya <okaya@cudeaurora.org>"
6Description:
7 Contains the ID of the channel within the HIDMA instance.
8 It is used to associate a given HIDMA channel with the
9 priority and weight calls in the management interface.
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
index 1ad27c28d00c..41b5c6dee713 100644
--- a/drivers/dma/qcom/hidma.c
+++ b/drivers/dma/qcom/hidma.c
@@ -530,6 +530,43 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg)
530 return hidma_ll_inthandler(chirq, lldev); 530 return hidma_ll_inthandler(chirq, lldev);
531} 531}
532 532
533static ssize_t hidma_show_values(struct device *dev,
534 struct device_attribute *attr, char *buf)
535{
536 struct platform_device *pdev = to_platform_device(dev);
537 struct hidma_dev *mdev = platform_get_drvdata(pdev);
538
539 buf[0] = 0;
540
541 if (strcmp(attr->attr.name, "chid") == 0)
542 sprintf(buf, "%d\n", mdev->chidx);
543
544 return strlen(buf);
545}
546
547static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name,
548 int mode)
549{
550 struct device_attribute *attrs;
551 char *name_copy;
552
553 attrs = devm_kmalloc(dev->ddev.dev, sizeof(struct device_attribute),
554 GFP_KERNEL);
555 if (!attrs)
556 return -ENOMEM;
557
558 name_copy = devm_kstrdup(dev->ddev.dev, name, GFP_KERNEL);
559 if (!name_copy)
560 return -ENOMEM;
561
562 attrs->attr.name = name_copy;
563 attrs->attr.mode = mode;
564 attrs->show = hidma_show_values;
565 sysfs_attr_init(&attrs->attr);
566
567 return device_create_file(dev->ddev.dev, attrs);
568}
569
533static int hidma_probe(struct platform_device *pdev) 570static int hidma_probe(struct platform_device *pdev)
534{ 571{
535 struct hidma_dev *dmadev; 572 struct hidma_dev *dmadev;
@@ -645,6 +682,7 @@ static int hidma_probe(struct platform_device *pdev)
645 dmadev->irq = chirq; 682 dmadev->irq = chirq;
646 tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev); 683 tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev);
647 hidma_debug_init(dmadev); 684 hidma_debug_init(dmadev);
685 hidma_create_sysfs_entry(dmadev, "chid", S_IRUGO);
648 dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); 686 dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n");
649 platform_set_drvdata(pdev, dmadev); 687 platform_set_drvdata(pdev, dmadev);
650 pm_runtime_mark_last_busy(dmadev->ddev.dev); 688 pm_runtime_mark_last_busy(dmadev->ddev.dev);
@@ -692,7 +730,6 @@ static const struct of_device_id hidma_match[] = {
692 {.compatible = "qcom,hidma-1.0",}, 730 {.compatible = "qcom,hidma-1.0",},
693 {}, 731 {},
694}; 732};
695
696MODULE_DEVICE_TABLE(of, hidma_match); 733MODULE_DEVICE_TABLE(of, hidma_match);
697 734
698static struct platform_driver hidma_driver = { 735static struct platform_driver hidma_driver = {
diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c
index ef491b893f40..c0e365321310 100644
--- a/drivers/dma/qcom/hidma_mgmt.c
+++ b/drivers/dma/qcom/hidma_mgmt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Qualcomm Technologies HIDMA DMA engine Management interface 2 * Qualcomm Technologies HIDMA DMA engine Management interface
3 * 3 *
4 * Copyright (c) 2015, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and 7 * it under the terms of the GNU General Public License version 2 and
@@ -17,13 +17,14 @@
17#include <linux/acpi.h> 17#include <linux/acpi.h>
18#include <linux/of.h> 18#include <linux/of.h>
19#include <linux/property.h> 19#include <linux/property.h>
20#include <linux/interrupt.h> 20#include <linux/of_irq.h>
21#include <linux/platform_device.h> 21#include <linux/of_platform.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <linux/pm_runtime.h> 25#include <linux/pm_runtime.h>
26#include <linux/bitops.h> 26#include <linux/bitops.h>
27#include <linux/dma-mapping.h>
27 28
28#include "hidma_mgmt.h" 29#include "hidma_mgmt.h"
29 30
@@ -298,5 +299,109 @@ static struct platform_driver hidma_mgmt_driver = {
298 }, 299 },
299}; 300};
300 301
301module_platform_driver(hidma_mgmt_driver); 302#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
303static int object_counter;
304
305static int __init hidma_mgmt_of_populate_channels(struct device_node *np)
306{
307 struct platform_device *pdev_parent = of_find_device_by_node(np);
308 struct platform_device_info pdevinfo;
309 struct of_phandle_args out_irq;
310 struct device_node *child;
311 struct resource *res;
312 const __be32 *cell;
313 int ret = 0, size, i, num;
314 u64 addr, addr_size;
315
316 for_each_available_child_of_node(np, child) {
317 struct resource *res_iter;
318 struct platform_device *new_pdev;
319
320 cell = of_get_property(child, "reg", &size);
321 if (!cell) {
322 ret = -EINVAL;
323 goto out;
324 }
325
326 size /= sizeof(*cell);
327 num = size /
328 (of_n_addr_cells(child) + of_n_size_cells(child)) + 1;
329
330 /* allocate a resource array */
331 res = kcalloc(num, sizeof(*res), GFP_KERNEL);
332 if (!res) {
333 ret = -ENOMEM;
334 goto out;
335 }
336
337 /* read each reg value */
338 i = 0;
339 res_iter = res;
340 while (i < size) {
341 addr = of_read_number(&cell[i],
342 of_n_addr_cells(child));
343 i += of_n_addr_cells(child);
344
345 addr_size = of_read_number(&cell[i],
346 of_n_size_cells(child));
347 i += of_n_size_cells(child);
348
349 res_iter->start = addr;
350 res_iter->end = res_iter->start + addr_size - 1;
351 res_iter->flags = IORESOURCE_MEM;
352 res_iter++;
353 }
354
355 ret = of_irq_parse_one(child, 0, &out_irq);
356 if (ret)
357 goto out;
358
359 res_iter->start = irq_create_of_mapping(&out_irq);
360 res_iter->name = "hidma event irq";
361 res_iter->flags = IORESOURCE_IRQ;
362
363 memset(&pdevinfo, 0, sizeof(pdevinfo));
364 pdevinfo.fwnode = &child->fwnode;
365 pdevinfo.parent = pdev_parent ? &pdev_parent->dev : NULL;
366 pdevinfo.name = child->name;
367 pdevinfo.id = object_counter++;
368 pdevinfo.res = res;
369 pdevinfo.num_res = num;
370 pdevinfo.data = NULL;
371 pdevinfo.size_data = 0;
372 pdevinfo.dma_mask = DMA_BIT_MASK(64);
373 new_pdev = platform_device_register_full(&pdevinfo);
374 if (!new_pdev) {
375 ret = -ENODEV;
376 goto out;
377 }
378 of_dma_configure(&new_pdev->dev, child);
379
380 kfree(res);
381 res = NULL;
382 }
383out:
384 kfree(res);
385
386 return ret;
387}
388#endif
389
390static int __init hidma_mgmt_init(void)
391{
392#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
393 struct device_node *child;
394
395 for (child = of_find_matching_node(NULL, hidma_mgmt_match); child;
396 child = of_find_matching_node(child, hidma_mgmt_match)) {
397 /* device tree based firmware here */
398 hidma_mgmt_of_populate_channels(child);
399 of_node_put(child);
400 }
401#endif
402 platform_driver_register(&hidma_mgmt_driver);
403
404 return 0;
405}
406module_init(hidma_mgmt_init);
302MODULE_LICENSE("GPL v2"); 407MODULE_LICENSE("GPL v2");