Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1ad9a576
Commit
1ad9a576
authored
Feb 21, 2016
by
Jason Cooper
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'irqchip/mvebu' into irqchip/core
parents
7cf03c9f
0407dace
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
284 additions
and
14 deletions
+284
-14
Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt
...bindings/interrupt-controller/marvell,odmi-controller.txt
+41
-0
drivers/irqchip/Kconfig
drivers/irqchip/Kconfig
+4
-0
drivers/irqchip/Makefile
drivers/irqchip/Makefile
+1
-0
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic-v2m.c
+1
-13
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-gic.c
+1
-1
drivers/irqchip/irq-mvebu-odmi.c
drivers/irqchip/irq-mvebu-odmi.c
+236
-0
No files found.
Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt
0 → 100644
View file @
1ad9a576
* Marvell ODMI for MSI support
Some Marvell SoCs have an On-Die Message Interrupt (ODMI) controller
which can be used by on-board peripheral for MSI interrupts.
Required properties:
- compatible : The value here should contain "marvell,odmi-controller".
- interrupt,controller : Identifies the node as an interrupt controller.
- msi-controller : Identifies the node as an MSI controller.
- marvell,odmi-frames : Number of ODMI frames available. Each frame
provides a number of events.
- reg : List of register definitions, one for each
ODMI frame.
- marvell,spi-base : List of GIC base SPI interrupts, one for each
ODMI frame. Those SPI interrupts are 0-based,
i.e marvell,spi-base = <128> will use SPI #96.
See Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
for details about the GIC Device Tree binding.
- interrupt-parent : Reference to the parent interrupt controller.
Example:
odmi: odmi@300000 {
compatible = "marvell,odmi-controller";
interrupt-controller;
msi-controller;
marvell,odmi-frames = <4>;
reg = <0x300000 0x4000>,
<0x304000 0x4000>,
<0x308000 0x4000>,
<0x30C000 0x4000>;
marvell,spi-base = <128>, <136>, <144>, <152>;
};
drivers/irqchip/Kconfig
View file @
1ad9a576
...
@@ -229,3 +229,7 @@ config IRQ_MXS
...
@@ -229,3 +229,7 @@ config IRQ_MXS
def_bool y if MACH_ASM9260 || ARCH_MXS
def_bool y if MACH_ASM9260 || ARCH_MXS
select IRQ_DOMAIN
select IRQ_DOMAIN
select STMP_DEVICE
select STMP_DEVICE
config MVEBU_ODMI
bool
select GENERIC_MSI_IRQ_DOMAIN
drivers/irqchip/Makefile
View file @
1ad9a576
...
@@ -62,3 +62,4 @@ obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
...
@@ -62,3 +62,4 @@ obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
obj-$(CONFIG_INGENIC_IRQ)
+=
irq-ingenic.o
obj-$(CONFIG_INGENIC_IRQ)
+=
irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2)
+=
irq-imx-gpcv2.o
obj-$(CONFIG_IMX_GPCV2)
+=
irq-imx-gpcv2.o
obj-$(CONFIG_PIC32_EVIC)
+=
irq-pic32-evic.o
obj-$(CONFIG_PIC32_EVIC)
+=
irq-pic32-evic.o
obj-$(CONFIG_MVEBU_ODMI)
+=
irq-mvebu-odmi.o
drivers/irqchip/irq-gic-v2m.c
View file @
1ad9a576
...
@@ -92,18 +92,6 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
...
@@ -92,18 +92,6 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
.
chip
=
&
gicv2m_msi_irq_chip
,
.
chip
=
&
gicv2m_msi_irq_chip
,
};
};
static
int
gicv2m_set_affinity
(
struct
irq_data
*
irq_data
,
const
struct
cpumask
*
mask
,
bool
force
)
{
int
ret
;
ret
=
irq_chip_set_affinity_parent
(
irq_data
,
mask
,
force
);
if
(
ret
==
IRQ_SET_MASK_OK
)
ret
=
IRQ_SET_MASK_OK_DONE
;
return
ret
;
}
static
void
gicv2m_compose_msi_msg
(
struct
irq_data
*
data
,
struct
msi_msg
*
msg
)
static
void
gicv2m_compose_msi_msg
(
struct
irq_data
*
data
,
struct
msi_msg
*
msg
)
{
{
struct
v2m_data
*
v2m
=
irq_data_get_irq_chip_data
(
data
);
struct
v2m_data
*
v2m
=
irq_data_get_irq_chip_data
(
data
);
...
@@ -122,7 +110,7 @@ static struct irq_chip gicv2m_irq_chip = {
...
@@ -122,7 +110,7 @@ static struct irq_chip gicv2m_irq_chip = {
.
irq_mask
=
irq_chip_mask_parent
,
.
irq_mask
=
irq_chip_mask_parent
,
.
irq_unmask
=
irq_chip_unmask_parent
,
.
irq_unmask
=
irq_chip_unmask_parent
,
.
irq_eoi
=
irq_chip_eoi_parent
,
.
irq_eoi
=
irq_chip_eoi_parent
,
.
irq_set_affinity
=
gicv2m_set_affinity
,
.
irq_set_affinity
=
irq_chip_set_affinity_parent
,
.
irq_compose_msi_msg
=
gicv2m_compose_msi_msg
,
.
irq_compose_msi_msg
=
gicv2m_compose_msi_msg
,
};
};
...
...
drivers/irqchip/irq-gic.c
View file @
1ad9a576
...
@@ -319,7 +319,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
...
@@ -319,7 +319,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
writel_relaxed
(
val
|
bit
,
reg
);
writel_relaxed
(
val
|
bit
,
reg
);
raw_spin_unlock_irqrestore
(
&
irq_controller_lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
irq_controller_lock
,
flags
);
return
IRQ_SET_MASK_OK
;
return
IRQ_SET_MASK_OK
_DONE
;
}
}
#endif
#endif
...
...
drivers/irqchip/irq-mvebu-odmi.c
0 → 100644
View file @
1ad9a576
/*
* Copyright (C) 2016 Marvell
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#define pr_fmt(fmt) "GIC-ODMI: " fmt
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#define GICP_ODMIN_SET 0x40
#define GICP_ODMI_INT_NUM_SHIFT 12
#define GICP_ODMIN_GM_EP_R0 0x110
#define GICP_ODMIN_GM_EP_R1 0x114
#define GICP_ODMIN_GM_EA_R0 0x108
#define GICP_ODMIN_GM_EA_R1 0x118
/*
* We don't support the group events, so we simply have 8 interrupts
* per frame.
*/
#define NODMIS_SHIFT 3
#define NODMIS_PER_FRAME (1 << NODMIS_SHIFT)
#define NODMIS_MASK (NODMIS_PER_FRAME - 1)
struct
odmi_data
{
struct
resource
res
;
void
__iomem
*
base
;
unsigned
int
spi_base
;
};
static
struct
odmi_data
*
odmis
;
static
unsigned
long
*
odmis_bm
;
static
unsigned
int
odmis_count
;
/* Protects odmis_bm */
static
DEFINE_SPINLOCK
(
odmis_bm_lock
);
static
void
odmi_compose_msi_msg
(
struct
irq_data
*
d
,
struct
msi_msg
*
msg
)
{
struct
odmi_data
*
odmi
;
phys_addr_t
addr
;
unsigned
int
odmin
;
if
(
WARN_ON
(
d
->
hwirq
>=
odmis_count
*
NODMIS_PER_FRAME
))
return
;
odmi
=
&
odmis
[
d
->
hwirq
>>
NODMIS_SHIFT
];
odmin
=
d
->
hwirq
&
NODMIS_MASK
;
addr
=
odmi
->
res
.
start
+
GICP_ODMIN_SET
;
msg
->
address_hi
=
upper_32_bits
(
addr
);
msg
->
address_lo
=
lower_32_bits
(
addr
);
msg
->
data
=
odmin
<<
GICP_ODMI_INT_NUM_SHIFT
;
}
static
struct
irq_chip
odmi_irq_chip
=
{
.
name
=
"ODMI"
,
.
irq_mask
=
irq_chip_mask_parent
,
.
irq_unmask
=
irq_chip_unmask_parent
,
.
irq_eoi
=
irq_chip_eoi_parent
,
.
irq_set_affinity
=
irq_chip_set_affinity_parent
,
.
irq_compose_msi_msg
=
odmi_compose_msi_msg
,
};
static
int
odmi_irq_domain_alloc
(
struct
irq_domain
*
domain
,
unsigned
int
virq
,
unsigned
int
nr_irqs
,
void
*
args
)
{
struct
odmi_data
*
odmi
=
NULL
;
struct
irq_fwspec
fwspec
;
struct
irq_data
*
d
;
unsigned
int
hwirq
,
odmin
;
int
ret
;
spin_lock
(
&
odmis_bm_lock
);
hwirq
=
find_first_zero_bit
(
odmis_bm
,
NODMIS_PER_FRAME
*
odmis_count
);
if
(
hwirq
>=
NODMIS_PER_FRAME
*
odmis_count
)
{
spin_unlock
(
&
odmis_bm_lock
);
return
-
ENOSPC
;
}
__set_bit
(
hwirq
,
odmis_bm
);
spin_unlock
(
&
odmis_bm_lock
);
odmi
=
&
odmis
[
hwirq
>>
NODMIS_SHIFT
];
odmin
=
hwirq
&
NODMIS_MASK
;
fwspec
.
fwnode
=
domain
->
parent
->
fwnode
;
fwspec
.
param_count
=
3
;
fwspec
.
param
[
0
]
=
GIC_SPI
;
fwspec
.
param
[
1
]
=
odmi
->
spi_base
-
32
+
odmin
;
fwspec
.
param
[
2
]
=
IRQ_TYPE_EDGE_RISING
;
ret
=
irq_domain_alloc_irqs_parent
(
domain
,
virq
,
1
,
&
fwspec
);
if
(
ret
)
{
pr_err
(
"Cannot allocate parent IRQ
\n
"
);
spin_lock
(
&
odmis_bm_lock
);
__clear_bit
(
odmin
,
odmis_bm
);
spin_unlock
(
&
odmis_bm_lock
);
return
ret
;
}
/* Configure the interrupt line to be edge */
d
=
irq_domain_get_irq_data
(
domain
->
parent
,
virq
);
d
->
chip
->
irq_set_type
(
d
,
IRQ_TYPE_EDGE_RISING
);
irq_domain_set_hwirq_and_chip
(
domain
,
virq
,
hwirq
,
&
odmi_irq_chip
,
NULL
);
return
0
;
}
static
void
odmi_irq_domain_free
(
struct
irq_domain
*
domain
,
unsigned
int
virq
,
unsigned
int
nr_irqs
)
{
struct
irq_data
*
d
=
irq_domain_get_irq_data
(
domain
,
virq
);
if
(
d
->
hwirq
>=
odmis_count
*
NODMIS_PER_FRAME
)
{
pr_err
(
"Failed to teardown msi. Invalid hwirq %lu
\n
"
,
d
->
hwirq
);
return
;
}
irq_domain_free_irqs_parent
(
domain
,
virq
,
nr_irqs
);
/* Actually free the MSI */
spin_lock
(
&
odmis_bm_lock
);
__clear_bit
(
d
->
hwirq
,
odmis_bm
);
spin_unlock
(
&
odmis_bm_lock
);
}
static
const
struct
irq_domain_ops
odmi_domain_ops
=
{
.
alloc
=
odmi_irq_domain_alloc
,
.
free
=
odmi_irq_domain_free
,
};
static
struct
irq_chip
odmi_msi_irq_chip
=
{
.
name
=
"ODMI"
,
};
static
struct
msi_domain_ops
odmi_msi_ops
=
{
};
static
struct
msi_domain_info
odmi_msi_domain_info
=
{
.
flags
=
(
MSI_FLAG_USE_DEF_DOM_OPS
|
MSI_FLAG_USE_DEF_CHIP_OPS
),
.
ops
=
&
odmi_msi_ops
,
.
chip
=
&
odmi_msi_irq_chip
,
};
static
int
__init
mvebu_odmi_init
(
struct
device_node
*
node
,
struct
device_node
*
parent
)
{
struct
irq_domain
*
inner_domain
,
*
plat_domain
;
int
ret
,
i
;
if
(
of_property_read_u32
(
node
,
"marvell,odmi-frames"
,
&
odmis_count
))
return
-
EINVAL
;
odmis
=
kcalloc
(
odmis_count
,
sizeof
(
struct
odmi_data
),
GFP_KERNEL
);
if
(
!
odmis
)
return
-
ENOMEM
;
odmis_bm
=
kcalloc
(
BITS_TO_LONGS
(
odmis_count
*
NODMIS_PER_FRAME
),
sizeof
(
long
),
GFP_KERNEL
);
if
(
!
odmis_bm
)
{
ret
=
-
ENOMEM
;
goto
err_alloc
;
}
for
(
i
=
0
;
i
<
odmis_count
;
i
++
)
{
struct
odmi_data
*
odmi
=
&
odmis
[
i
];
ret
=
of_address_to_resource
(
node
,
i
,
&
odmi
->
res
);
if
(
ret
)
goto
err_unmap
;
odmi
->
base
=
of_io_request_and_map
(
node
,
i
,
"odmi"
);
if
(
IS_ERR
(
odmi
->
base
))
{
ret
=
PTR_ERR
(
odmi
->
base
);
goto
err_unmap
;
}
if
(
of_property_read_u32_index
(
node
,
"marvell,spi-base"
,
i
,
&
odmi
->
spi_base
))
{
ret
=
-
EINVAL
;
goto
err_unmap
;
}
}
inner_domain
=
irq_domain_create_linear
(
of_node_to_fwnode
(
node
),
odmis_count
*
NODMIS_PER_FRAME
,
&
odmi_domain_ops
,
NULL
);
if
(
!
inner_domain
)
{
ret
=
-
ENOMEM
;
goto
err_unmap
;
}
inner_domain
->
parent
=
irq_find_host
(
parent
);
plat_domain
=
platform_msi_create_irq_domain
(
of_node_to_fwnode
(
node
),
&
odmi_msi_domain_info
,
inner_domain
);
if
(
!
plat_domain
)
{
ret
=
-
ENOMEM
;
goto
err_remove_inner
;
}
return
0
;
err_remove_inner:
irq_domain_remove
(
inner_domain
);
err_unmap:
for
(
i
=
0
;
i
<
odmis_count
;
i
++
)
{
struct
odmi_data
*
odmi
=
&
odmis
[
i
];
if
(
odmi
->
base
&&
!
IS_ERR
(
odmi
->
base
))
iounmap
(
odmis
[
i
].
base
);
}
kfree
(
odmis_bm
);
err_alloc:
kfree
(
odmis
);
return
ret
;
}
IRQCHIP_DECLARE
(
mvebu_odmi
,
"marvell,odmi-controller"
,
mvebu_odmi_init
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment