From patchwork Fri May 10 02:18:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 16829 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-gh0-f197.google.com (mail-gh0-f197.google.com [209.85.160.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 86D6F238F7 for ; Fri, 10 May 2013 02:19:54 +0000 (UTC) Received: by mail-gh0-f197.google.com with SMTP id r20sf3743719ghr.8 for ; Thu, 09 May 2013 19:19:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:mime-version:x-beenthere:x-received:received-spf :x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe; bh=QZFCgIkxCt+GRNUxQ6Mx96eeNeCOVFHT6mbYbqA8oJY=; b=g1kBia8wmpIEYuk1Fiy/aJMZyvT21gNIYsdSvoxPoqybeadoXni+YJWb6XW9sH+0IM Ed9dAiClud6ntzpLVABIyXvwnD8D3KyEaVaeoLyZTbPjuCnRhviMZSEyUqgihP0L2hBR miaiycfy6E8VnjBsToDTSNmDoGmfNi3KiXpiz/B1Khvdl1/KEbdhnr2eXajjQ8acmeXu RMPC7gPtWe/naVTMxmh/NHgsOcu3NahjVJKN81KZb4h9IGDG+NKPEqnyYaS/OmfdOBgY H/mAQ+mMHt+3NfxqyAAzcWA+cu361rvM8sJLZZfMxcx7oMa7SLzx7SwbPtsQLhTMzodQ V6yA== X-Received: by 10.224.217.195 with SMTP id hn3mr11081200qab.5.1368152369868; Thu, 09 May 2013 19:19:29 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.134.99 with SMTP id pj3ls1832627qeb.93.gmail; Thu, 09 May 2013 19:19:29 -0700 (PDT) X-Received: by 10.220.156.75 with SMTP id v11mr9807891vcw.1.1368152369632; Thu, 09 May 2013 19:19:29 -0700 (PDT) Received: from mail-vb0-x233.google.com (mail-vb0-x233.google.com [2607:f8b0:400c:c02::233]) by mx.google.com with ESMTPS id gr7si319973vdc.142.2013.05.09.19.19.29 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 09 May 2013 19:19:29 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:400c:c02::233 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=2607:f8b0:400c:c02::233; Received: by mail-vb0-f51.google.com with SMTP id x16so3077594vbf.38 for ; Thu, 09 May 2013 19:19:29 -0700 (PDT) X-Received: by 10.58.144.170 with SMTP id sn10mr9678694veb.7.1368152369154; Thu, 09 May 2013 19:19:29 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.217.15 with SMTP id hk15csp36221vcb; Thu, 9 May 2013 19:19:28 -0700 (PDT) X-Received: by 10.194.59.106 with SMTP id y10mr21417697wjq.28.1368152367295; Thu, 09 May 2013 19:19:27 -0700 (PDT) Received: from mail-we0-x22d.google.com (mail-we0-x22d.google.com [2a00:1450:400c:c03::22d]) by mx.google.com with ESMTPS id n5si169324wjf.59.2013.05.09.19.19.26 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 09 May 2013 19:19:27 -0700 (PDT) Received-SPF: neutral (google.com: 2a00:1450:400c:c03::22d is neither permitted nor denied by best guess record for domain of julien.grall@linaro.org) client-ip=2a00:1450:400c:c03::22d; Received: by mail-we0-f173.google.com with SMTP id q54so3480189wes.32 for ; Thu, 09 May 2013 19:19:26 -0700 (PDT) X-Received: by 10.180.109.80 with SMTP id hq16mr681566wib.26.1368152366901; Thu, 09 May 2013 19:19:26 -0700 (PDT) Received: from belegaer.uk.xensource.com. (firewall.ctxuk.citrix.com. [46.33.159.2]) by mx.google.com with ESMTPSA id dj7sm597075wib.6.2013.05.09.19.19.25 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 09 May 2013 19:19:26 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xen.org Cc: Stefano.Stabellini@eu.citrix.com, ian.campbell@citrix.com, patches@linaro.org, Julien Grall Subject: [PATCH V3 17/41] xen/arm: Add helpers to retrieve an interrupt description from the device tree Date: Fri, 10 May 2013 03:18:03 +0100 Message-Id: <1368152307-598-18-git-send-email-julien.grall@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1368152307-598-1-git-send-email-julien.grall@linaro.org> References: <1368152307-598-1-git-send-email-julien.grall@linaro.org> X-Gm-Message-State: ALoCoQkTZXEArXPHD2jGKB9tf1cPiABtTtE66t3bR6/9oHQpA7pRjMy8p+Yn5nDfeU9vM78mN3rk X-Original-Sender: julien.grall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 2607:f8b0:400c:c02::233 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Signed-off-by: Julien Grall Acked-by: Ian Campbell Changes in v3: - Rename dt_irq_is_level_trigger to dt_irq_is_level_triggered - Remove hard tabs - Typoes Changes in v2: - Move interrupt type from xen/irq.h to xen/device_tree.h - Prefix all defines by DT_ --- xen/common/device_tree.c | 362 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 130 +++++++++++++++ 2 files changed, 492 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 27328c8..f0f60ce 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -27,8 +27,11 @@ struct dt_early_info __initdata early_info; void *device_tree_flattened; +dt_irq_xlate_func dt_irq_xlate; /* Host device tree */ struct dt_device_node *dt_host; +/* Interrupt controller node*/ +const struct dt_device_node *dt_interrupt_controller; /** * struct dt_alias_prop - Alias property in 'aliases' node @@ -1037,6 +1040,81 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, return 0; } +/** + * dt_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer. + */ +static const struct dt_device_node *dt_find_node_by_phandle(dt_phandle handle) +{ + const struct dt_device_node *np; + + for_each_device_node(dt_host, np) + if ( np->phandle == handle ) + break; + + return np; +} + +/** + * dt_irq_find_parent - Given a device node, find its interrupt parent node + * @child: pointer to device node + * + * Returns a pointer to the interrupt parent node, or NULL if the interrupt + * parent could not be determined. + */ +static const struct dt_device_node * +dt_irq_find_parent(const struct dt_device_node *child) +{ + const struct dt_device_node *p; + const __be32 *parp; + + do + { + parp = dt_get_property(child, "interrupt-parent", NULL); + if ( parp == NULL ) + p = dt_get_parent(child); + else + p = dt_find_node_by_phandle(be32_to_cpup(parp)); + child = p; + } while ( p && dt_get_property(p, "#interrupt-cells", NULL) == NULL ); + + return p; +} + +unsigned int dt_number_of_irq(const struct dt_device_node *device) +{ + const struct dt_device_node *p; + const __be32 *intspec, *tmp; + u32 intsize, intlen; + + dt_dprintk("dt_irq_number: dev=%s\n", device->full_name); + + /* Get the interrupts property */ + intspec = dt_get_property(device, "interrupts", &intlen); + if ( intspec == NULL ) + return 0; + intlen /= sizeof(*intspec); + + dt_dprintk(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); + + /* Look for the interrupt parent. */ + p = dt_irq_find_parent(device); + if ( p == NULL ) + return 0; + + /* Get size of interrupt specifier */ + tmp = dt_get_property(p, "#interrupt-cells", NULL); + if ( tmp == NULL ) + return 0; + intsize = be32_to_cpu(*tmp); + + dt_dprintk(" intsize=%d intlen=%d\n", intsize, intlen); + + return (intlen / intsize); +} + unsigned int dt_number_of_address(const struct dt_device_node *dev) { const __be32 *prop; @@ -1068,6 +1146,274 @@ unsigned int dt_number_of_address(const struct dt_device_node *dev) } /** + * dt_irq_map_raw - Low level interrupt tree parsing + * @parent: the device interrupt parent + * @intspec: interrupt specifier ("interrupts" property of the device) + * @ointsize: size of the passed in interrupt specifier + * @addr: address specifier (start of "reg" property of the device) + * @oirq: structure dt_raw_irq filled by this function + * + * Returns 0 on success and a negative number on error + * + * This function is a low-level interrupt tree walking function. It + * can be used to do a partial walk with synthesized reg and interrupts + * properties, for example when resolving PCI interrupts when no device + * node exist for the parent. + */ +static int dt_irq_map_raw(const struct dt_device_node *parent, + const __be32 *intspec, u32 ointsize, + const __be32 *addr, + struct dt_raw_irq *oirq) +{ + const struct dt_device_node *ipar, *tnode, *old = NULL, *newpar = NULL; + const __be32 *tmp, *imap, *imask; + u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; + u32 imaplen; + int match, i; + + dt_dprintk("dt_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", + parent->full_name, be32_to_cpup(intspec), + be32_to_cpup(intspec + 1), ointsize); + + ipar = parent; + + /* First get the #interrupt-cells property of the current cursor + * that tells us how to interpret the passed-in intspec. If there + * is none, we are nice and just walk up the tree + */ + do { + tmp = dt_get_property(ipar, "#interrupt-cells", NULL); + if ( tmp != NULL ) + { + intsize = be32_to_cpu(*tmp); + break; + } + tnode = ipar; + ipar = dt_irq_find_parent(ipar); + } while ( ipar ); + if ( ipar == NULL ) + { + dt_dprintk(" -> no parent found !\n"); + goto fail; + } + + dt_dprintk("dt_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + + if ( ointsize != intsize ) + return -EINVAL; + + /* Look for this #address-cells. We have to implement the old linux + * trick of looking for the parent here as some device-trees rely on it + */ + old = ipar; + do { + tmp = dt_get_property(old, "#address-cells", NULL); + tnode = dt_get_parent(old); + old = tnode; + } while ( old && tmp == NULL ); + + old = NULL; + addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp); + + dt_dprintk(" -> addrsize=%d\n", addrsize); + + /* Now start the actual "proper" walk of the interrupt tree */ + while ( ipar != NULL ) + { + /* Now check if cursor is an interrupt-controller and if it is + * then we are done + */ + if ( dt_get_property(ipar, "interrupt-controller", NULL) != NULL ) + { + dt_dprintk(" -> got it !\n"); + if ( intsize > DT_MAX_IRQ_SPEC ) + { + dt_dprintk(" -> intsize(%u) greater than DT_MAX_IRQ_SPEC(%u)\n", + intsize, DT_MAX_IRQ_SPEC); + goto fail; + } + for ( i = 0; i < intsize; i++ ) + oirq->specifier[i] = dt_read_number(intspec + i, 1); + oirq->size = intsize; + oirq->controller = ipar; + return 0; + } + + /* Now look for an interrupt-map */ + imap = dt_get_property(ipar, "interrupt-map", &imaplen); + /* No interrupt map, check for an interrupt parent */ + if ( imap == NULL ) + { + dt_dprintk(" -> no map, getting parent\n"); + newpar = dt_irq_find_parent(ipar); + goto skiplevel; + } + imaplen /= sizeof(u32); + + /* Look for a mask */ + imask = dt_get_property(ipar, "interrupt-map-mask", NULL); + + /* If we were passed no "reg" property and we attempt to parse + * an interrupt-map, then #address-cells must be 0. + * Fail if it's not. + */ + if ( addr == NULL && addrsize != 0 ) + { + dt_dprintk(" -> no reg passed in when needed !\n"); + goto fail; + } + + /* Parse interrupt-map */ + match = 0; + while ( imaplen > (addrsize + intsize + 1) && !match ) + { + /* Compare specifiers */ + match = 1; + for ( i = 0; i < addrsize && match; ++i ) + { + __be32 mask = imask ? imask[i] : cpu_to_be32(0xffffffffu); + match = ((addr[i] ^ imap[i]) & mask) == 0; + } + for ( ; i < (addrsize + intsize) && match; ++i ) + { + __be32 mask = imask ? imask[i] : cpu_to_be32(0xffffffffu); + match = ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; + } + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + + dt_dprintk(" -> match=%d (imaplen=%d)\n", match, imaplen); + + /* Get the interrupt parent */ + newpar = dt_find_node_by_phandle(be32_to_cpup(imap)); + imap++; + --imaplen; + + /* Check if not found */ + if ( newpar == NULL ) + { + dt_dprintk(" -> imap parent not found !\n"); + goto fail; + } + + /* Get #interrupt-cells and #address-cells of new + * parent + */ + tmp = dt_get_property(newpar, "#interrupt-cells", NULL); + if ( tmp == NULL ) + { + dt_dprintk(" -> parent lacks #interrupt-cells!\n"); + goto fail; + } + newintsize = be32_to_cpu(*tmp); + tmp = dt_get_property(newpar, "#address-cells", NULL); + newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp); + + dt_dprintk(" -> newintsize=%d, newaddrsize=%d\n", + newintsize, newaddrsize); + + /* Check for malformed properties */ + if ( imaplen < (newaddrsize + newintsize) ) + goto fail; + + imap += newaddrsize + newintsize; + imaplen -= newaddrsize + newintsize; + + dt_dprintk(" -> imaplen=%d\n", imaplen); + } + if ( !match ) + goto fail; + + old = newpar; + addrsize = newaddrsize; + intsize = newintsize; + intspec = imap - intsize; + addr = intspec - addrsize; + + skiplevel: + /* Iterate again with new parent */ + dt_dprintk(" -> new parent: %s\n", dt_node_full_name(newpar)); + ipar = newpar; + newpar = NULL; + } +fail: + return -EINVAL; +} + +int dt_device_get_raw_irq(const struct dt_device_node *device, int index, + struct dt_raw_irq *out_irq) +{ + const struct dt_device_node *p; + const __be32 *intspec, *tmp, *addr; + u32 intsize, intlen; + int res = -EINVAL; + + dt_dprintk("dt_device_get_raw_irq: dev=%s, index=%d\n", + device->full_name, index); + + /* Get the interrupts property */ + intspec = dt_get_property(device, "interrupts", &intlen); + if ( intspec == NULL ) + return -EINVAL; + intlen /= sizeof(*intspec); + + dt_dprintk(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); + + /* Get the reg property (if any) */ + addr = dt_get_property(device, "reg", NULL); + + /* Look for the interrupt parent. */ + p = dt_irq_find_parent(device); + if ( p == NULL ) + return -EINVAL; + + /* Get size of interrupt specifier */ + tmp = dt_get_property(p, "#interrupt-cells", NULL); + if ( tmp == NULL ) + goto out; + intsize = be32_to_cpu(*tmp); + + dt_dprintk(" intsize=%d intlen=%d\n", intsize, intlen); + + /* Check index */ + if ( (index + 1) * intsize > intlen ) + goto out; + + /* Get new specifier and map it */ + res = dt_irq_map_raw(p, intspec + index * intsize, intsize, + addr, out_irq); + if ( res ) + goto out; +out: + return res; +} + +int dt_irq_translate(const struct dt_raw_irq *raw, + struct dt_irq *out_irq) +{ + ASSERT(dt_irq_xlate != NULL); + + /* TODO: Retrieve the right irq_xlate. This is only work for the gic */ + + return dt_irq_xlate(raw->specifier, raw->size, + &out_irq->irq, &out_irq->type); +} + +int dt_device_get_irq(const struct dt_device_node *device, int index, + struct dt_irq *out_irq) +{ + struct dt_raw_irq raw; + int res; + + res = dt_device_get_raw_irq(device, index, &raw); + + if ( res ) + return res; + + return dt_irq_translate(&raw, out_irq); +} + +/** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @fdt: The parent device tree blob * @mem: Memory chunk to use for allocating device nodes and properties @@ -1409,6 +1755,22 @@ static void __init dt_alias_scan(void) } } +struct dt_device_node * __init dt_find_interrupt_controller(const char *compat) +{ + struct dt_device_node *np = NULL; + + while ( (np = dt_find_compatible_node(np, NULL, compat)) ) + { + if ( !dt_find_property(np, "interrupt-controller", NULL) ) + continue; + + if ( dt_get_parent(np) ) + break; + } + + return np; +} + void __init dt_unflatten_host_device_tree(void) { __unflatten_device_tree(device_tree_flattened, &dt_host); diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index cc3a070..a7cfa94 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -99,6 +99,67 @@ struct dt_device_node { }; +/** + * IRQ line type. + * + * DT_IRQ_TYPE_NONE - default, unspecified type + * DT_IRQ_TYPE_EDGE_RISING - rising edge triggered + * DT_IRQ_TYPE_EDGE_FALLING - falling edge triggered + * DT_IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered + * DT_IRQ_TYPE_LEVEL_HIGH - high level triggered + * DT_IRQ_TYPE_LEVEL_LOW - low level triggered + * DT_IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits + * DT_IRQ_TYPE_SENSE_MASK - Mask for all the above bits + */ +#define DT_IRQ_TYPE_NONE 0x00000000 +#define DT_IRQ_TYPE_EDGE_RISING 0x00000001 +#define DT_IRQ_TYPE_EDGE_FALLING 0x00000002 +#define DT_IRQ_TYPE_EDGE_BOTH \ + (DT_IRQ_TYPE_EDGE_FALLING | DT_IRQ_TYPE_EDGE_RISING) +#define DT_IRQ_TYPE_LEVEL_HIGH 0x00000004 +#define DT_IRQ_TYPE_LEVEL_LOW 0x00000008 +#define DT_IRQ_TYPE_LEVEL_MASK \ + (DT_IRQ_TYPE_LEVEL_LOW | DT_IRQ_TYPE_LEVEL_HIGH) +#define DT_IRQ_TYPE_SENSE_MASK 0x0000000f + +/** + * dt_irq - describe an IRQ in the device tree + * @irq: IRQ number + * @type: IRQ type (see DT_IRQ_TYPE_*) + * + * This structure is returned when an interrupt is mapped. + */ +struct dt_irq { + unsigned int irq; + unsigned int type; +}; + +/* If type == DT_IRQ_TYPE_NONE, assume we use level triggered */ +static inline bool_t dt_irq_is_level_triggered(const struct dt_irq *irq) +{ + unsigned int type = irq->type; + + return (type & DT_IRQ_TYPE_LEVEL_MASK) || (type == DT_IRQ_TYPE_NONE); +} + +/** + * dt_raw_irq - container for device_node/irq_specifier for an irq controller + * @controller: pointer to interrupt controller deivce tree node + * @size: size of interrupt specifier + * @specifier: array of cells @size long specifying the specific interrupt + * + * This structure is returned when an interrupt is mapped but not translated. + */ +#define DT_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ +struct dt_raw_irq { + const struct dt_device_node *controller; + u32 size; + u32 specifier[DT_MAX_IRQ_SPEC]; +}; + +#define dt_irq(irq) ((irq)->irq) +#define dt_irq_flags(irq) ((irq)->flags) + typedef int (*device_tree_node_func)(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, @@ -136,11 +197,40 @@ void __init device_tree_dump(const void *fdt); void __init dt_unflatten_host_device_tree(void); /** + * IRQ translation callback + * TODO: For the moment we assume that we only have ONE + * interrupt-controller. + */ +typedef int (*dt_irq_xlate_func)(const u32 *intspec, unsigned int intsize, + unsigned int *out_hwirq, + unsigned int *out_type); +extern dt_irq_xlate_func dt_irq_xlate; + +/** * Host device tree * DO NOT modify it! */ extern struct dt_device_node *dt_host; +/** + * Primary interrupt controller + * Exynos SOC has an interrupt combiner, interrupt has no physical + * meaning when it's not connected to the primary controller. + * We will only map interrupt whose parent controller is + * dt_interrupt_controller. It should always be a GIC. + * TODO: Handle multiple GIC + */ +extern const struct dt_device_node *dt_interrupt_controller; + +/** + * Find the interrupt controller + * For the moment we handle only one interrupt controller: the first + * one without parent which is compatible with the string "compat". + * + * If found, return the interrupt controller device node. + */ +struct dt_device_node * __init dt_find_interrupt_controller(const char *compat); + #define dt_node_cmp(s1, s2) strcmp((s1), (s2)) #define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l) @@ -285,6 +375,15 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, u64 *addr, u64 *size); /** + * dt_number_of_irq - Get the number of IRQ for a device + * @device: the device whose number of interrupt is to be retrieved + * + * Return the number of irq for this device or 0 if there is no + * interrupt or an error occurred. + */ +unsigned int dt_number_of_irq(const struct dt_device_node *device); + +/** * dt_number_of_address - Get the number of addresses for a device * @device: the device whose number of address is to be retrieved * @@ -294,6 +393,37 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, unsigned int dt_number_of_address(const struct dt_device_node *device); /** + * dt_device_get_irq - Resolve an interrupt for a device + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure dt_irq filled by this function + * + * This function resolves an interrupt, walking the tree, for a given + * device-tree node. It's the high level pendant to dt_device_get_raw_irq(). + */ +int dt_device_get_irq(const struct dt_device_node *device, int index, + struct dt_irq *irq); + +/** + * dt_device_get_raw_irq - Resolve an interrupt for a device without translation + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure dt_raw_irq filled by this function + * + * This function resolves an interrupt for a device, no translation is + * made. dt_irq_translate can be called after. + */ +int dt_device_get_raw_irq(const struct dt_device_node *device, int index, + struct dt_raw_irq *irq); + +/** + * dt_irq_translate - Translate an irq + * @raw: IRQ to translate (raw format) + * @out_irq: structure dt_irq filled by this function + */ +int dt_irq_translate(const struct dt_raw_irq *raw, struct dt_irq *out_irq); + +/** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value *