1 // SPDX-License-Identifier: GPL-2.0-only
3 * Freescale MU used as MSI controller
5 * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
7 * Frank Li <Frank.Li@nxp.com>
8 * Peng Fan <peng.fan@nxp.com>
10 * Based on drivers/mailbox/imx-mailbox.c
13 #include <linux/clk.h>
14 #include <linux/irq.h>
15 #include <linux/irqchip.h>
16 #include <linux/irqchip/chained_irq.h>
17 #include <linux/irqdomain.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/msi.h>
21 #include <linux/of_irq.h>
22 #include <linux/of_platform.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/pm_domain.h>
25 #include <linux/spinlock.h>
27 #include "irq-msi-lib.h"
29 #define IMX_MU_CHANS 4
51 /* Receive Interrupt Enable */
52 #define IMX_MU_xCR_RIEn(data, x) ((data->cfg->type) & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
53 #define IMX_MU_xSR_RFn(data, x) ((data->cfg->type) & IMX_MU_V2 ? BIT(x) : BIT(24 + (3 - (x))))
56 enum imx_mu_type type
;
57 u32 xTR
; /* Transmit Register0 */
58 u32 xRR
; /* Receive Register0 */
59 u32 xSR
[IMX_MU_xSR_MAX
]; /* Status Registers */
60 u32 xCR
[IMX_MU_xCR_MAX
]; /* Control Registers */
65 struct irq_domain
*msi_domain
;
67 phys_addr_t msiir_addr
;
68 const struct imx_mu_dcfg
*cfg
;
73 static void imx_mu_write(struct imx_mu_msi
*msi_data
, u32 val
, u32 offs
)
75 iowrite32(val
, msi_data
->regs
+ offs
);
78 static u32
imx_mu_read(struct imx_mu_msi
*msi_data
, u32 offs
)
80 return ioread32(msi_data
->regs
+ offs
);
83 static u32
imx_mu_xcr_rmw(struct imx_mu_msi
*msi_data
, enum imx_mu_xcr type
, u32 set
, u32 clr
)
88 raw_spin_lock_irqsave(&msi_data
->lock
, flags
);
89 val
= imx_mu_read(msi_data
, msi_data
->cfg
->xCR
[type
]);
92 imx_mu_write(msi_data
, val
, msi_data
->cfg
->xCR
[type
]);
93 raw_spin_unlock_irqrestore(&msi_data
->lock
, flags
);
98 static void imx_mu_msi_parent_mask_irq(struct irq_data
*data
)
100 struct imx_mu_msi
*msi_data
= irq_data_get_irq_chip_data(data
);
102 imx_mu_xcr_rmw(msi_data
, IMX_MU_RCR
, 0, IMX_MU_xCR_RIEn(msi_data
, data
->hwirq
));
105 static void imx_mu_msi_parent_unmask_irq(struct irq_data
*data
)
107 struct imx_mu_msi
*msi_data
= irq_data_get_irq_chip_data(data
);
109 imx_mu_xcr_rmw(msi_data
, IMX_MU_RCR
, IMX_MU_xCR_RIEn(msi_data
, data
->hwirq
), 0);
112 static void imx_mu_msi_parent_ack_irq(struct irq_data
*data
)
114 struct imx_mu_msi
*msi_data
= irq_data_get_irq_chip_data(data
);
116 imx_mu_read(msi_data
, msi_data
->cfg
->xRR
+ data
->hwirq
* 4);
119 static void imx_mu_msi_parent_compose_msg(struct irq_data
*data
,
122 struct imx_mu_msi
*msi_data
= irq_data_get_irq_chip_data(data
);
123 u64 addr
= msi_data
->msiir_addr
+ 4 * data
->hwirq
;
125 msg
->address_hi
= upper_32_bits(addr
);
126 msg
->address_lo
= lower_32_bits(addr
);
127 msg
->data
= data
->hwirq
;
130 static int imx_mu_msi_parent_set_affinity(struct irq_data
*irq_data
,
131 const struct cpumask
*mask
, bool force
)
136 static struct irq_chip imx_mu_msi_parent_chip
= {
138 .irq_mask
= imx_mu_msi_parent_mask_irq
,
139 .irq_unmask
= imx_mu_msi_parent_unmask_irq
,
140 .irq_ack
= imx_mu_msi_parent_ack_irq
,
141 .irq_compose_msi_msg
= imx_mu_msi_parent_compose_msg
,
142 .irq_set_affinity
= imx_mu_msi_parent_set_affinity
,
145 static int imx_mu_msi_domain_irq_alloc(struct irq_domain
*domain
,
147 unsigned int nr_irqs
,
150 struct imx_mu_msi
*msi_data
= domain
->host_data
;
154 WARN_ON(nr_irqs
!= 1);
156 raw_spin_lock_irqsave(&msi_data
->lock
, flags
);
157 pos
= find_first_zero_bit(&msi_data
->used
, IMX_MU_CHANS
);
158 if (pos
< IMX_MU_CHANS
)
159 __set_bit(pos
, &msi_data
->used
);
162 raw_spin_unlock_irqrestore(&msi_data
->lock
, flags
);
167 irq_domain_set_info(domain
, virq
, pos
,
168 &imx_mu_msi_parent_chip
, msi_data
,
169 handle_edge_irq
, NULL
, NULL
);
173 static void imx_mu_msi_domain_irq_free(struct irq_domain
*domain
,
174 unsigned int virq
, unsigned int nr_irqs
)
176 struct irq_data
*d
= irq_domain_get_irq_data(domain
, virq
);
177 struct imx_mu_msi
*msi_data
= irq_data_get_irq_chip_data(d
);
180 raw_spin_lock_irqsave(&msi_data
->lock
, flags
);
181 __clear_bit(d
->hwirq
, &msi_data
->used
);
182 raw_spin_unlock_irqrestore(&msi_data
->lock
, flags
);
185 static const struct irq_domain_ops imx_mu_msi_domain_ops
= {
186 .select
= msi_lib_irq_domain_select
,
187 .alloc
= imx_mu_msi_domain_irq_alloc
,
188 .free
= imx_mu_msi_domain_irq_free
,
191 static void imx_mu_msi_irq_handler(struct irq_desc
*desc
)
193 struct imx_mu_msi
*msi_data
= irq_desc_get_handler_data(desc
);
194 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
198 status
= imx_mu_read(msi_data
, msi_data
->cfg
->xSR
[IMX_MU_RSR
]);
200 chained_irq_enter(chip
, desc
);
201 for (i
= 0; i
< IMX_MU_CHANS
; i
++) {
202 if (status
& IMX_MU_xSR_RFn(msi_data
, i
))
203 generic_handle_domain_irq(msi_data
->msi_domain
, i
);
205 chained_irq_exit(chip
, desc
);
208 #define IMX_MU_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
209 MSI_FLAG_USE_DEF_CHIP_OPS | \
210 MSI_FLAG_PARENT_PM_DEV)
212 #define IMX_MU_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK)
214 static const struct msi_parent_ops imx_mu_msi_parent_ops
= {
215 .supported_flags
= IMX_MU_MSI_FLAGS_SUPPORTED
,
216 .required_flags
= IMX_MU_MSI_FLAGS_REQUIRED
,
217 .bus_select_token
= DOMAIN_BUS_NEXUS
,
218 .bus_select_mask
= MATCH_PLATFORM_MSI
,
220 .init_dev_msi_info
= msi_lib_init_dev_msi_info
,
223 static int imx_mu_msi_domains_init(struct imx_mu_msi
*msi_data
, struct device
*dev
)
225 struct fwnode_handle
*fwnodes
= dev_fwnode(dev
);
226 struct irq_domain
*parent
;
228 /* Initialize MSI domain parent */
229 parent
= irq_domain_create_linear(fwnodes
, IMX_MU_CHANS
,
230 &imx_mu_msi_domain_ops
, msi_data
);
232 dev_err(dev
, "failed to create IRQ domain\n");
236 irq_domain_update_bus_token(parent
, DOMAIN_BUS_NEXUS
);
237 parent
->dev
= parent
->pm_dev
= dev
;
238 parent
->flags
|= IRQ_DOMAIN_FLAG_MSI_PARENT
;
239 parent
->msi_parent_ops
= &imx_mu_msi_parent_ops
;
243 /* Register offset of different version MU IP */
244 static const struct imx_mu_dcfg imx_mu_cfg_imx6sx
= {
255 [IMX_MU_GIER
] = 0x24,
262 static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp
= {
273 [IMX_MU_GIER
] = 0x64,
280 static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp
= {
286 [IMX_MU_GSR
] = 0x118,
287 [IMX_MU_TSR
] = 0x124,
288 [IMX_MU_RSR
] = 0x12C,
291 [IMX_MU_GIER
] = 0x110,
292 [IMX_MU_GCR
] = 0x114,
293 [IMX_MU_TCR
] = 0x120,
298 static int __init
imx_mu_of_init(struct device_node
*dn
,
299 struct device_node
*parent
,
300 const struct imx_mu_dcfg
*cfg
)
302 struct platform_device
*pdev
= of_find_device_by_node(dn
);
303 struct device_link
*pd_link_a
;
304 struct device_link
*pd_link_b
;
305 struct imx_mu_msi
*msi_data
;
306 struct resource
*res
;
315 msi_data
= devm_kzalloc(&pdev
->dev
, sizeof(*msi_data
), GFP_KERNEL
);
321 msi_data
->regs
= devm_platform_ioremap_resource_byname(pdev
, "processor-a-side");
322 if (IS_ERR(msi_data
->regs
)) {
323 dev_err(&pdev
->dev
, "failed to initialize 'regs'\n");
324 return PTR_ERR(msi_data
->regs
);
327 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "processor-b-side");
331 msi_data
->msiir_addr
= res
->start
+ msi_data
->cfg
->xTR
;
333 irq
= platform_get_irq(pdev
, 0);
337 platform_set_drvdata(pdev
, msi_data
);
339 msi_data
->clk
= devm_clk_get(dev
, NULL
);
340 if (IS_ERR(msi_data
->clk
))
341 return PTR_ERR(msi_data
->clk
);
343 pd_a
= dev_pm_domain_attach_by_name(dev
, "processor-a-side");
345 return PTR_ERR(pd_a
);
347 pd_b
= dev_pm_domain_attach_by_name(dev
, "processor-b-side");
349 return PTR_ERR(pd_b
);
351 pd_link_a
= device_link_add(dev
, pd_a
,
357 dev_err(dev
, "Failed to add device_link to mu a.\n");
361 pd_link_b
= device_link_add(dev
, pd_b
,
368 dev_err(dev
, "Failed to add device_link to mu a.\n");
372 ret
= imx_mu_msi_domains_init(msi_data
, dev
);
376 pm_runtime_enable(dev
);
378 irq_set_chained_handler_and_data(irq
,
379 imx_mu_msi_irq_handler
,
385 device_link_remove(dev
, pd_b
);
387 device_link_remove(dev
, pd_a
);
392 static int __maybe_unused
imx_mu_runtime_suspend(struct device
*dev
)
394 struct imx_mu_msi
*priv
= dev_get_drvdata(dev
);
396 clk_disable_unprepare(priv
->clk
);
401 static int __maybe_unused
imx_mu_runtime_resume(struct device
*dev
)
403 struct imx_mu_msi
*priv
= dev_get_drvdata(dev
);
406 ret
= clk_prepare_enable(priv
->clk
);
408 dev_err(dev
, "failed to enable clock\n");
413 static const struct dev_pm_ops imx_mu_pm_ops
= {
414 SET_RUNTIME_PM_OPS(imx_mu_runtime_suspend
,
415 imx_mu_runtime_resume
, NULL
)
418 static int __init
imx_mu_imx7ulp_of_init(struct device_node
*dn
,
419 struct device_node
*parent
)
421 return imx_mu_of_init(dn
, parent
, &imx_mu_cfg_imx7ulp
);
424 static int __init
imx_mu_imx6sx_of_init(struct device_node
*dn
,
425 struct device_node
*parent
)
427 return imx_mu_of_init(dn
, parent
, &imx_mu_cfg_imx6sx
);
430 static int __init
imx_mu_imx8ulp_of_init(struct device_node
*dn
,
431 struct device_node
*parent
)
433 return imx_mu_of_init(dn
, parent
, &imx_mu_cfg_imx8ulp
);
436 IRQCHIP_PLATFORM_DRIVER_BEGIN(imx_mu_msi
)
437 IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_of_init
)
438 IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_of_init
)
439 IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_of_init
)
440 IRQCHIP_PLATFORM_DRIVER_END(imx_mu_msi
, .pm
= &imx_mu_pm_ops
)
443 MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>");
444 MODULE_DESCRIPTION("Freescale MU MSI controller driver");
445 MODULE_LICENSE("GPL");