Skip to content

Commit

Permalink
Patch to enable Xilinx AXI irq-xilinx-intc driver initialization on u…
Browse files Browse the repository at this point in the history
…sage of DTBO overlay. NOTE: dts(o) node must be mapped under "ampa_pl" and named "interrupt-controller@81800000"
  • Loading branch information
jeras committed Oct 10, 2017
1 parent 30b5bee commit 592b9c7
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 14 deletions.
88 changes: 75 additions & 13 deletions drivers/irqchip/irq-xilinx-intc.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* 2017/10/06, DM <dabvor.munda@kopica-sp.si>
* Change code to enable driver initialization on usage of DTBO overlay.
*/

#include <linux/irqdomain.h>
Expand Down Expand Up @@ -69,6 +72,14 @@ static unsigned int intc_read32_be(void __iomem *addr)
return ioread32be(addr);
}

/** Added by DM **/
int xilinx_intc_of_init_done = 0;
EXPORT_SYMBOL_GPL(xilinx_intc_of_init_done);

static struct device_node *node_bck;
int xilinx_intc_of_init(struct device_node *node, struct device_node *parent);


static void intc_enable_or_unmask(struct irq_data *d)
{
unsigned long mask = 1 << d->hwirq;
Expand All @@ -85,21 +96,35 @@ static void intc_enable_or_unmask(struct irq_data *d)
local_intc->write_fn(mask, local_intc->baseaddr + IAR);

local_intc->write_fn(mask, local_intc->baseaddr + SIE);

/** Added by DM to enable all IRQs **/
local_intc->write_fn(MER_HIE | MER_ME, local_intc->baseaddr + MER);
local_intc->write_fn(0xffffffff, local_intc->baseaddr + IAR); /* Acknowledge any pending interrupts just in case. */
}

/** Added by DM **/
static void xilinx_intc_of_cleanup(void);
static u32 irq;
static struct intc *intc = NULL;

static void intc_disable_or_mask(struct irq_data *d)
{
struct intc *local_intc = irq_data_get_irq_chip_data(d);

pr_debug("disable: %ld\n", d->hwirq);
local_intc->write_fn(1 << d->hwirq, local_intc->baseaddr + CIE);

/** Added by DM **/
if (d->hwirq == 0 && intc) {
xilinx_intc_of_cleanup();
}
}

static void intc_ack(struct irq_data *d)
{
struct intc *local_intc = irq_data_get_irq_chip_data(d);

pr_debug("ack: %ld\n", d->hwirq);
pr_debug("intc_ack: %ld\n", d->hwirq);
local_intc->write_fn(1 << d->hwirq, local_intc->baseaddr + IAR);
}

Expand All @@ -108,7 +133,7 @@ static void intc_mask_ack(struct irq_data *d)
unsigned long mask = 1 << d->hwirq;
struct intc *local_intc = irq_data_get_irq_chip_data(d);

pr_debug("disable_and_ack: %ld\n", d->hwirq);
pr_debug("intc_mask_ack: disable_and_ack: %ld\n", d->hwirq);
local_intc->write_fn(mask, local_intc->baseaddr + CIE);
local_intc->write_fn(mask, local_intc->baseaddr + IAR);
}
Expand All @@ -126,9 +151,15 @@ static unsigned int get_irq(struct intc *local_intc)
int hwirq, irq = -1;

hwirq = local_intc->read_fn(local_intc->baseaddr + IVR);
if (hwirq != -1U)
if (hwirq != -1)
irq = irq_find_mapping(local_intc->domain, hwirq);

/** Just in case by DM, because HW can generate randomly wrong interrupts ? **/
if (unlikely((!irq || irq == -1) && hwirq != -1)) {
ack_bad_irq(irq);
irq = -1;
}

pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);

return irq;
Expand Down Expand Up @@ -159,12 +190,14 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {

static void intc_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
/** Typecast by DM **/
struct irq_chip *chip = irq_desc_get_chip((struct irq_desc *)desc);
struct intc *local_intc =
irq_data_get_irq_handler_data(&desc->irq_data);
irq_data_get_irq_handler_data(&((struct irq_desc *)desc)->irq_data);
int irq;

pr_debug("intc_handler: input irq = %d\n", ((struct irq_desc *)desc)->irq_data.irq);

pr_debug("intc_handler: input irq = %d\n", desc->irq_data.irq);
chained_irq_enter(chip, desc);

/*
Expand All @@ -180,12 +213,28 @@ static void intc_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}

static int __init xilinx_intc_of_init(struct device_node *node,
struct device_node *parent)
/** Added by DM **/
extern unsigned int _irq_of_parse_and_map(struct device_node *, int);
static void xilinx_intc_of_cleanup(void) {

pr_debug("xilinx_intc_of_cleanup\n");

disable_irq(irq);
irq_domain_remove(intc->domain);
iounmap(intc->baseaddr);
kfree(intc);
intc = NULL;

xilinx_intc_of_init(node_bck, NULL);
xilinx_intc_of_init_done = 0;

return;
}

int xilinx_intc_of_init(struct device_node *node,
struct device_node *parent)
{
u32 irq;
int ret;
struct intc *intc;

intc = kzalloc(sizeof(struct intc), GFP_KERNEL);
if (!intc)
Expand Down Expand Up @@ -226,7 +275,7 @@ static int __init xilinx_intc_of_init(struct device_node *node,
* explicity requested.
*/
intc->write_fn(0, intc->baseaddr + IER);

/* Acknowledge any pending interrupts just in case. */
intc->write_fn(0xffffffff, intc->baseaddr + IAR);

Expand All @@ -249,7 +298,12 @@ static int __init xilinx_intc_of_init(struct device_node *node,
* Check if this interrupt controller is a chained interrupt controller
* and if so then set up the handler and enable it.
*/
irq = irq_of_parse_and_map(node, 0);
if (!xilinx_intc_of_init_done) { /** Added by DM **/
irq = _irq_of_parse_and_map(node, 0);
} else {
irq = irq_of_parse_and_map(node, 0);
}

if (irq > 0) {
pr_info("%s: chained intc connected to irq %d\n",
node->full_name, irq);
Expand All @@ -258,6 +312,10 @@ static int __init xilinx_intc_of_init(struct device_node *node,
enable_irq(irq);
};

/** Added by DM **/
node_bck = node;
xilinx_intc_of_init_done = 1;

return 0;

error2:
Expand All @@ -267,5 +325,9 @@ static int __init xilinx_intc_of_init(struct device_node *node,
kfree(intc);
return ret;
}
/** Added by DM **/
EXPORT_SYMBOL_GPL(xilinx_intc_of_init);


IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
/** Commented by DM **/
//IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
29 changes: 28 additions & 1 deletion drivers/of/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
* This file contains the code used to make IRQ descriptions in the
* device tree to actual irq numbers on an interrupt controller
* driver.
*
* 2017/10/06, DM <dabvor.munda@kopica-sp.si>
* Added code to enable Xilinx AXI irq-xilinx-intc driver initialization on usage of DTBO overlay.
*/

#define pr_fmt(fmt) "OF: " fmt
Expand All @@ -30,6 +33,22 @@
#include <linux/string.h>
#include <linux/slab.h>

/**
* Added by DM
**/
extern int xilinx_intc_of_init_done;
extern int xilinx_intc_of_init(struct device_node *, struct device_node *);
unsigned int _irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_phandle_args oirq;

if (of_irq_parse_one(dev, index, &oirq))
return 0;

return irq_create_of_mapping(&oirq);
}
EXPORT_SYMBOL_GPL(_irq_of_parse_and_map);

/**
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @dev: Device node of the device whose interrupt is to be mapped
Expand All @@ -41,7 +60,15 @@
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_phandle_args oirq;


/** Added by DM
NOTE: DTS(O) node must be mapped under "ampa_pl" and named "interrupt-controller@81800000" **/
if (!strcmp(dev->full_name, "/amba_pl/interrupt-controller@81800000\0")) {
if (!xilinx_intc_of_init_done) {
xilinx_intc_of_init(dev, NULL);
}
}

if (of_irq_parse_one(dev, index, &oirq))
return 0;

Expand Down

0 comments on commit 592b9c7

Please sign in to comment.