1acf9e575SChristophe Leroy // SPDX-License-Identifier: GPL-2.0 2acf9e575SChristophe Leroy /* 3acf9e575SChristophe Leroy * Interrupt controller for the 4acf9e575SChristophe Leroy * Communication Processor Module. 5acf9e575SChristophe Leroy * Copyright (c) 1997 Dan error_act (dmalek@jlc.net) 6acf9e575SChristophe Leroy */ 7acf9e575SChristophe Leroy #include <linux/kernel.h> 8acf9e575SChristophe Leroy #include <linux/interrupt.h> 9acf9e575SChristophe Leroy #include <linux/irqdomain.h> 10acf9e575SChristophe Leroy #include <linux/of_irq.h> 11*22add2a2SChristophe Leroy #include <linux/platform_device.h> 12acf9e575SChristophe Leroy #include <asm/cpm1.h> 13acf9e575SChristophe Leroy 14acf9e575SChristophe Leroy static cpic8xx_t __iomem *cpic_reg; 15acf9e575SChristophe Leroy 16acf9e575SChristophe Leroy static struct irq_domain *cpm_pic_host; 17acf9e575SChristophe Leroy 18acf9e575SChristophe Leroy static void cpm_mask_irq(struct irq_data *d) 19acf9e575SChristophe Leroy { 20acf9e575SChristophe Leroy unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 21acf9e575SChristophe Leroy 22acf9e575SChristophe Leroy clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); 23acf9e575SChristophe Leroy } 24acf9e575SChristophe Leroy 25acf9e575SChristophe Leroy static void cpm_unmask_irq(struct irq_data *d) 26acf9e575SChristophe Leroy { 27acf9e575SChristophe Leroy unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 28acf9e575SChristophe Leroy 29acf9e575SChristophe Leroy setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec)); 30acf9e575SChristophe Leroy } 31acf9e575SChristophe Leroy 32acf9e575SChristophe Leroy static void cpm_end_irq(struct irq_data *d) 33acf9e575SChristophe Leroy { 34acf9e575SChristophe Leroy unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d); 35acf9e575SChristophe Leroy 36acf9e575SChristophe Leroy out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec)); 37acf9e575SChristophe Leroy } 38acf9e575SChristophe Leroy 39acf9e575SChristophe Leroy static struct irq_chip cpm_pic = { 40acf9e575SChristophe Leroy .name = "CPM PIC", 41acf9e575SChristophe Leroy .irq_mask = cpm_mask_irq, 42acf9e575SChristophe Leroy .irq_unmask = cpm_unmask_irq, 43acf9e575SChristophe Leroy .irq_eoi = cpm_end_irq, 44acf9e575SChristophe Leroy }; 45acf9e575SChristophe Leroy 46acf9e575SChristophe Leroy int cpm_get_irq(void) 47acf9e575SChristophe Leroy { 48acf9e575SChristophe Leroy int cpm_vec; 49acf9e575SChristophe Leroy 50acf9e575SChristophe Leroy /* 51acf9e575SChristophe Leroy * Get the vector by setting the ACK bit and then reading 52acf9e575SChristophe Leroy * the register. 53acf9e575SChristophe Leroy */ 54acf9e575SChristophe Leroy out_be16(&cpic_reg->cpic_civr, 1); 55acf9e575SChristophe Leroy cpm_vec = in_be16(&cpic_reg->cpic_civr); 56acf9e575SChristophe Leroy cpm_vec >>= 11; 57acf9e575SChristophe Leroy 58acf9e575SChristophe Leroy return irq_linear_revmap(cpm_pic_host, cpm_vec); 59acf9e575SChristophe Leroy } 60acf9e575SChristophe Leroy 61acf9e575SChristophe Leroy static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq, 62acf9e575SChristophe Leroy irq_hw_number_t hw) 63acf9e575SChristophe Leroy { 64acf9e575SChristophe Leroy pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); 65acf9e575SChristophe Leroy 66acf9e575SChristophe Leroy irq_set_status_flags(virq, IRQ_LEVEL); 67acf9e575SChristophe Leroy irq_set_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); 68acf9e575SChristophe Leroy return 0; 69acf9e575SChristophe Leroy } 70acf9e575SChristophe Leroy 71acf9e575SChristophe Leroy static const struct irq_domain_ops cpm_pic_host_ops = { 72acf9e575SChristophe Leroy .map = cpm_pic_host_map, 73acf9e575SChristophe Leroy }; 74acf9e575SChristophe Leroy 75acf9e575SChristophe Leroy unsigned int __init cpm_pic_init(void) 76acf9e575SChristophe Leroy { 77acf9e575SChristophe Leroy struct device_node *np = NULL; 78acf9e575SChristophe Leroy struct resource res; 79*22add2a2SChristophe Leroy unsigned int sirq = 0, hwirq; 80acf9e575SChristophe Leroy int ret; 81acf9e575SChristophe Leroy 82acf9e575SChristophe Leroy pr_debug("cpm_pic_init\n"); 83acf9e575SChristophe Leroy 84acf9e575SChristophe Leroy np = of_find_compatible_node(NULL, NULL, "fsl,cpm1-pic"); 85acf9e575SChristophe Leroy if (np == NULL) 86acf9e575SChristophe Leroy np = of_find_compatible_node(NULL, "cpm-pic", "CPM"); 87acf9e575SChristophe Leroy if (np == NULL) { 88acf9e575SChristophe Leroy printk(KERN_ERR "CPM PIC init: can not find cpm-pic node\n"); 89acf9e575SChristophe Leroy return sirq; 90acf9e575SChristophe Leroy } 91acf9e575SChristophe Leroy 92acf9e575SChristophe Leroy ret = of_address_to_resource(np, 0, &res); 93acf9e575SChristophe Leroy if (ret) 94acf9e575SChristophe Leroy goto end; 95acf9e575SChristophe Leroy 96acf9e575SChristophe Leroy cpic_reg = ioremap(res.start, resource_size(&res)); 97acf9e575SChristophe Leroy if (cpic_reg == NULL) 98acf9e575SChristophe Leroy goto end; 99acf9e575SChristophe Leroy 100acf9e575SChristophe Leroy sirq = irq_of_parse_and_map(np, 0); 101acf9e575SChristophe Leroy if (!sirq) 102acf9e575SChristophe Leroy goto end; 103acf9e575SChristophe Leroy 104acf9e575SChristophe Leroy /* Initialize the CPM interrupt controller. */ 105acf9e575SChristophe Leroy hwirq = (unsigned int)virq_to_hw(sirq); 106acf9e575SChristophe Leroy out_be32(&cpic_reg->cpic_cicr, 107acf9e575SChristophe Leroy (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | 108acf9e575SChristophe Leroy ((hwirq/2) << 13) | CICR_HP_MASK); 109acf9e575SChristophe Leroy 110acf9e575SChristophe Leroy out_be32(&cpic_reg->cpic_cimr, 0); 111acf9e575SChristophe Leroy 112acf9e575SChristophe Leroy cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); 113acf9e575SChristophe Leroy if (cpm_pic_host == NULL) { 114acf9e575SChristophe Leroy printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); 115acf9e575SChristophe Leroy sirq = 0; 116acf9e575SChristophe Leroy goto end; 117acf9e575SChristophe Leroy } 118acf9e575SChristophe Leroy 119acf9e575SChristophe Leroy setbits32(&cpic_reg->cpic_cicr, CICR_IEN); 120acf9e575SChristophe Leroy 121acf9e575SChristophe Leroy end: 122acf9e575SChristophe Leroy of_node_put(np); 123acf9e575SChristophe Leroy return sirq; 124acf9e575SChristophe Leroy } 125*22add2a2SChristophe Leroy 126*22add2a2SChristophe Leroy /* 127*22add2a2SChristophe Leroy * The CPM can generate the error interrupt when there is a race condition 128*22add2a2SChristophe Leroy * between generating and masking interrupts. All we have to do is ACK it 129*22add2a2SChristophe Leroy * and return. This is a no-op function so we don't need any special 130*22add2a2SChristophe Leroy * tests in the interrupt handler. 131*22add2a2SChristophe Leroy */ 132*22add2a2SChristophe Leroy static irqreturn_t cpm_error_interrupt(int irq, void *dev) 133*22add2a2SChristophe Leroy { 134*22add2a2SChristophe Leroy return IRQ_HANDLED; 135*22add2a2SChristophe Leroy } 136*22add2a2SChristophe Leroy 137*22add2a2SChristophe Leroy static int cpm_error_probe(struct platform_device *pdev) 138*22add2a2SChristophe Leroy { 139*22add2a2SChristophe Leroy int irq; 140*22add2a2SChristophe Leroy 141*22add2a2SChristophe Leroy irq = platform_get_irq(pdev, 0); 142*22add2a2SChristophe Leroy if (irq < 0) 143*22add2a2SChristophe Leroy return irq; 144*22add2a2SChristophe Leroy 145*22add2a2SChristophe Leroy return request_irq(irq, cpm_error_interrupt, IRQF_NO_THREAD, "error", NULL); 146*22add2a2SChristophe Leroy } 147*22add2a2SChristophe Leroy 148*22add2a2SChristophe Leroy static const struct of_device_id cpm_error_ids[] = { 149*22add2a2SChristophe Leroy { .compatible = "fsl,cpm1" }, 150*22add2a2SChristophe Leroy { .type = "cpm" }, 151*22add2a2SChristophe Leroy {}, 152*22add2a2SChristophe Leroy }; 153*22add2a2SChristophe Leroy 154*22add2a2SChristophe Leroy static struct platform_driver cpm_error_driver = { 155*22add2a2SChristophe Leroy .driver = { 156*22add2a2SChristophe Leroy .name = "cpm-error", 157*22add2a2SChristophe Leroy .of_match_table = cpm_error_ids, 158*22add2a2SChristophe Leroy }, 159*22add2a2SChristophe Leroy .probe = cpm_error_probe, 160*22add2a2SChristophe Leroy }; 161*22add2a2SChristophe Leroy 162*22add2a2SChristophe Leroy static int __init cpm_error_init(void) 163*22add2a2SChristophe Leroy { 164*22add2a2SChristophe Leroy return platform_driver_register(&cpm_error_driver); 165*22add2a2SChristophe Leroy } 166*22add2a2SChristophe Leroy subsys_initcall(cpm_error_init); 167