From patchwork Thu Sep 20 14:43:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Porter X-Patchwork-Id: 1485871 Return-Path: X-Original-To: patchwork-davinci@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from devils.ext.ti.com (devils.ext.ti.com [198.47.26.153]) by patchwork1.kernel.org (Postfix) with ESMTP id 79B3B400EC for ; Thu, 20 Sep 2012 14:45:04 +0000 (UTC) Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id q8KEhXTw008326; Thu, 20 Sep 2012 09:43:33 -0500 Received: from DLEE74.ent.ti.com (dlee74.ent.ti.com [157.170.170.8]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8KEhW21014849; Thu, 20 Sep 2012 09:43:33 -0500 Received: from dlelxv24.itg.ti.com (172.17.1.199) by DLEE74.ent.ti.com (157.170.170.8) with Microsoft SMTP Server id 14.1.323.3; Thu, 20 Sep 2012 09:43:32 -0500 Received: from linux.omap.com (dlelxs01.itg.ti.com [157.170.227.31]) by dlelxv24.itg.ti.com (8.13.8/8.13.8) with ESMTP id q8KEhWlv007528; Thu, 20 Sep 2012 09:43:32 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id B5DF88062A; Thu, 20 Sep 2012 09:43:32 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp52.itg.ti.com (dflp52.itg.ti.com [128.247.22.96]) by linux.omap.com (Postfix) with ESMTP id 34E978062A for ; Thu, 20 Sep 2012 09:42:23 -0500 (CDT) Received: from white.ext.ti.com (white.ext.ti.com [192.94.93.38]) by dflp52.itg.ti.com (8.13.7/8.13.8) with ESMTP id q8KEgM48011921 for ; Thu, 20 Sep 2012 09:42:22 -0500 (CDT) Received: from psmtp.com (na3sys009amx171.postini.com [74.125.149.97]) by white.ext.ti.com (8.13.7/8.13.7) with SMTP id q8KEgKQS007384 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 20 Sep 2012 09:42:21 -0500 Received: from mail-ie0-f173.google.com ([209.85.223.173]) (using TLSv1) by na3sys009amx171.postini.com ([74.125.148.10]) with SMTP; Thu, 20 Sep 2012 14:42:21 GMT Received: by mail-ie0-f173.google.com with SMTP id c10so3339295ieb.4 for ; Thu, 20 Sep 2012 07:42:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=idGYXfvAvUC3Y3pmKGNhV0MfCOVceuQdQmxXaEr1KFo=; b=qsMvK5NLr/I/P1BA8lzccu/ZxJC5QH6JwT6iqc7RThT+h/w8hky53ohTwZWu08vWaI M/nCLse6CH+HVKJf/ukq3//SxsOSQF43uFnDiup9TbbItsJQNbZzwwDFIuYRpNm0In9U Gxk0YEplrGqVJjlUc27Sy/YOy/3v0TnUMGx442MYhe/+dKRNeN1864KGRar7mwbnaBsx ZztcDwvws/vhB+0hhdyFOfovA3DPf9ZhQd4iq7p/gNIv8QdG8/zvE9M02+LA6zgIqUQV LyWbiDFQsEtlnLCdybXNE3L3yQ26lTl/2MZunJ53xkB8Halu1CBo4pfCcT6rN1M8Y9Fr doIg== Received: by 10.43.106.147 with SMTP id du19mr1551128icc.56.1348152140551; Thu, 20 Sep 2012 07:42:20 -0700 (PDT) Received: from beef.ohporter.com (cpe-24-166-64-7.neo.res.rr.com. [24.166.64.7]) by mx.google.com with ESMTPS id p5sm15288242igm.13.2012.09.20.07.42.18 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 20 Sep 2012 07:42:19 -0700 (PDT) From: Matt Porter To: Tony Lindgren , Sekhar Nori , Grant Likely , Mark Brown , Benoit Cousson , Russell King , Vinod Koul , Rob Landley , Chris Ball Subject: [RFC PATCH 03/13] ARM: edma: add DT and runtime PM support for AM335x Date: Thu, 20 Sep 2012 10:43:36 -0400 Message-ID: <1348152226-13588-4-git-send-email-mporter@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1348152226-13588-1-git-send-email-mporter@ti.com> References: <1348152226-13588-1-git-send-email-mporter@ti.com> X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-dkim: 1 skipped:not-enabled X-pstn-settings: 2 (0.5000:0.0050) s cv GT3 gt2 gt1 r p m c X-pstn-addresses: from [82/3] CC: Linux DaVinci Kernel List , Arnd Bergmann , Linux Documentation List , Devicetree Discuss , Linux MMC List , Linux Kernel Mailing List , Rob Herring , Dan Williams , Linux SPI Devel List , Linux OMAP List , Linux ARM Kernel List X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com Adds support for parsing the TI EDMA DT data into the required EDMA private API platform data. Calls runtime PM API only in the DT case in order to unidle the associated hwmods on AM335x. Signed-off-by: Matt Porter --- arch/arm/common/edma.c | 252 ++++++++++++++++++++++++++++++++++++-- arch/arm/include/asm/mach/edma.h | 8 +- 2 files changed, 244 insertions(+), 16 deletions(-) diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index 001d268..f337f81 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -24,6 +24,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include @@ -1366,30 +1373,236 @@ void edma_clear_event(unsigned channel) EXPORT_SYMBOL(edma_clear_event); /*-----------------------------------------------------------------------*/ +static int edma_of_read_u32_to_s8_array(const struct device_node *np, + const char *propname, s8 *out_values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + const __be32 *val; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if ((sz * sizeof(u32)) > prop->length) + return -EOVERFLOW; + + val = prop->value; + + while (sz--) + *out_values++ = (s8)(be32_to_cpup(val++) & 0xff); + + /* Terminate it */ + *out_values++ = -1; + *out_values++ = -1; + + return 0; +} + +static int edma_of_read_u32_to_s16_array(const struct device_node *np, + const char *propname, s16 *out_values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + const __be32 *val; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if ((sz * sizeof(u32)) > prop->length) + return -EOVERFLOW; + + val = prop->value; + + while (sz--) + *out_values++ = (s16)(be32_to_cpup(val++) & 0xffff); + + /* Terminate it */ + *out_values++ = -1; + *out_values++ = -1; + + return 0; +} + +static int edma_of_parse_dt(struct device *dev, + struct device_node *node, + struct edma_soc_info *pdata) +{ + int ret = 0; + u32 value; + struct property *prop; + size_t sz; + struct edma_rsv_info *rsv_info; + s16 (*rsv_chans)[2], (*rsv_slots)[2]; + s8 (*queue_tc_map)[2], (*queue_priority_map)[2]; + + ret = of_property_read_u32(node, "dma-channels", &value); + if (ret < 0) + return ret; + pdata->n_channel = value; + + ret = of_property_read_u32(node, "ti,edma-regions", &value); + if (ret < 0) + return ret; + pdata->n_region = value; + + ret = of_property_read_u32(node, "ti,edma-slots", &value); + if (ret < 0) + return ret; + pdata->n_slot = value; + + pdata->n_cc = 1; + /* This is unused */ + pdata->n_tc = 3; + + rsv_info = + devm_kzalloc(dev, sizeof(struct edma_rsv_info), GFP_KERNEL); + if (!rsv_info) + return -ENOMEM; + pdata->rsv = rsv_info; + + /* Build the reserved channel/slots arrays */ + prop = of_find_property(node, "ti,edma-reserved-channels", &sz); + if (!prop) + return -EINVAL; + + rsv_chans = + devm_kzalloc(dev, sz/sizeof(s16) + 2*sizeof(s16), GFP_KERNEL); + if (!rsv_chans) + return -ENOMEM; + pdata->rsv->rsv_chans = rsv_chans; + + ret = edma_of_read_u32_to_s16_array(node, "ti,edma-reserved-channels", + (s16 *)rsv_chans, sz/sizeof(u32)); + if (ret < 0) + return ret; + + prop = of_find_property(node, "ti,edma-reserved-slots", &sz); + if (!prop) + return -EINVAL; + + rsv_slots = devm_kzalloc(dev, + sz/sizeof(s16) + 2*sizeof(s16), + GFP_KERNEL); + if (!rsv_slots) + return -ENOMEM; + pdata->rsv->rsv_slots = rsv_slots; + + ret = edma_of_read_u32_to_s16_array(node, + "ti,edma-reserved-slots", + (s16 *)rsv_slots, + sz/sizeof(u32)); + if (ret < 0) + return ret; + + prop = of_find_property(node, "ti,edma-queue-tc-map", &sz); + if (!prop) + return -EINVAL; + + queue_tc_map = devm_kzalloc(dev, + sz/sizeof(s8) + 2*sizeof(s8), + GFP_KERNEL); + if (!rsv_slots) + return -ENOMEM; + pdata->queue_tc_mapping = queue_tc_map; + + ret = edma_of_read_u32_to_s8_array(node, + "ti,edma-queue-tc-map", + (s8 *)queue_tc_map, + sz/sizeof(u32)); + if (ret < 0) + return ret; + + prop = of_find_property(node, "ti,edma-queue-priority-map", &sz); + if (!prop) + return -EINVAL; + + queue_priority_map = devm_kzalloc(dev, + sz/sizeof(s8) + 2*sizeof(s8), + GFP_KERNEL); + if (!rsv_slots) + return -ENOMEM; + pdata->queue_priority_mapping = queue_priority_map; + + ret = edma_of_read_u32_to_s8_array(node, + "ti,edma-queue-tc-map", + (s8 *)queue_priority_map, + sz/sizeof(u32)); + if (ret < 0) + return ret; + + ret = of_property_read_u32(node, "ti,edma-default-queue", &value); + if (ret < 0) + return ret; + pdata->default_queue = value; + + return ret; +} + +static struct of_dma_filter_info edma_filter_info = { + .filter_fn = edma_filter_fn, +}; static int __init edma_probe(struct platform_device *pdev) { struct edma_soc_info **info = pdev->dev.platform_data; - const s8 (*queue_priority_mapping)[2]; - const s8 (*queue_tc_mapping)[2]; + s8 (*queue_priority_mapping)[2]; + s8 (*queue_tc_mapping)[2]; int i, j, off, ln, found = 0; int status = -1; - const s16 (*rsv_chans)[2]; - const s16 (*rsv_slots)[2]; + s16 (*rsv_chans)[2]; + s16 (*rsv_slots)[2]; int irq[EDMA_MAX_CC] = {0, 0}; int err_irq[EDMA_MAX_CC] = {0, 0}; struct resource *r[EDMA_MAX_CC] = {NULL}; + struct resource res[EDMA_MAX_CC]; resource_size_t len[EDMA_MAX_CC]; char res_name[10]; char irq_name[10]; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct edma_soc_info *pdata; + + if (node) { + int ret; + pdata = devm_kzalloc(dev, + sizeof(struct edma_soc_info), + GFP_KERNEL); + edma_of_parse_dt(dev, node, pdata); + info = &pdata; + dma_cap_set(DMA_SLAVE, edma_filter_info.dma_cap); + of_dma_controller_register(dev->of_node, + of_dma_simple_xlate, + &edma_filter_info); + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (IS_ERR_VALUE(ret)) { + dev_err(dev, "pm_runtime_get_sync() failed\n"); + return ret; + } + } if (!info) return -ENODEV; for (j = 0; j < EDMA_MAX_CC; j++) { - sprintf(res_name, "edma_cc%d", j); - r[j] = platform_get_resource_byname(pdev, IORESOURCE_MEM, + if (node) { + int err; + err = of_address_to_resource(node, 0, &res[j]); + if (err) { + dev_err(dev, + "unable to find 'reg' property\n"); + return -EIO; + } + r[j] = &res[j]; + + } else { + sprintf(res_name, "edma_cc%d", j); + r[j] = platform_get_resource_byname(pdev, + IORESOURCE_MEM, res_name); + } if (!r[j] || !info[j]) { if (found) break; @@ -1465,8 +1678,12 @@ static int __init edma_probe(struct platform_device *pdev) } } - sprintf(irq_name, "edma%d", j); - irq[j] = platform_get_irq_byname(pdev, irq_name); + if (node) + irq[j] = irq_of_parse_and_map(node, 0); + else { + sprintf(irq_name, "edma%d", j); + irq[j] = platform_get_irq_byname(pdev, irq_name); + } edma_cc[j]->irq_res_start = irq[j]; status = request_irq(irq[j], dma_irq_handler, 0, "edma", &pdev->dev); @@ -1476,8 +1693,12 @@ static int __init edma_probe(struct platform_device *pdev) goto fail; } - sprintf(irq_name, "edma%d_err", j); - err_irq[j] = platform_get_irq_byname(pdev, irq_name); + if (node) + err_irq[j] = irq_of_parse_and_map(node, 2); + else { + sprintf(irq_name, "edma%d_err", j); + err_irq[j] = platform_get_irq_byname(pdev, irq_name); + } edma_cc[j]->irq_res_end = err_irq[j]; status = request_irq(err_irq[j], dma_ccerr_handler, 0, "edma_error", &pdev->dev); @@ -1538,9 +1759,17 @@ fail1: return status; } +static const struct of_device_id edma_of_ids[] = { + { .compatible = "ti,edma3", }, + {} +}; static struct platform_driver edma_driver = { - .driver.name = "edma", + .driver = { + .name = "edma", + .of_match_table = edma_of_ids, + }, + .probe = edma_probe, }; static int __init edma_init(void) @@ -1548,4 +1777,3 @@ static int __init edma_init(void) return platform_driver_probe(&edma_driver, edma_probe); } arch_initcall(edma_init); - diff --git a/arch/arm/include/asm/mach/edma.h b/arch/arm/include/asm/mach/edma.h index 7e84c90..ce5f6f8 100644 --- a/arch/arm/include/asm/mach/edma.h +++ b/arch/arm/include/asm/mach/edma.h @@ -237,8 +237,8 @@ void edma_resume(unsigned channel); struct edma_rsv_info { - const s16 (*rsv_chans)[2]; - const s16 (*rsv_slots)[2]; + s16 (*rsv_chans)[2]; + s16 (*rsv_slots)[2]; }; /* platform_data for EDMA driver */ @@ -260,8 +260,8 @@ struct edma_soc_info { /* Resource reservation for other cores */ struct edma_rsv_info *rsv; - const s8 (*queue_tc_mapping)[2]; - const s8 (*queue_priority_mapping)[2]; + s8 (*queue_tc_mapping)[2]; + s8 (*queue_priority_mapping)[2]; }; #endif