^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * IRQ chip definitions for INTC IRQs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2007, 2008 Magnus Damm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 - 2012 Paul Mundt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/cpumask.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/bsearch.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "internals.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) void _intc_enable(struct irq_data *data, unsigned long handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct intc_desc_int *d = get_intc_desc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) [_INTC_FN(handle)], irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) intc_balancing_enable(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void intc_enable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) _intc_enable(data, (unsigned long)irq_data_get_irq_chip_data(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void intc_disable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct intc_desc_int *d = get_intc_desc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned long handle = (unsigned long)irq_data_get_irq_chip_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) intc_balancing_disable(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) [_INTC_FN(handle)], irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * This is held with the irq desc lock held, so we don't require any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * additional locking here at the intc desc level. The affinity mask is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * later tested in the enable/disable paths.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static int intc_set_affinity(struct irq_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) const struct cpumask *cpumask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) bool force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!cpumask_intersects(cpumask, cpu_online_mask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) cpumask_copy(irq_data_get_affinity_mask(data), cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return IRQ_SET_MASK_OK_NOCOPY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static void intc_mask_ack(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct intc_desc_int *d = get_intc_desc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned long handle = intc_get_ack_handle(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) void __iomem *addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) intc_disable(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* read register and write zero only to the associated bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (handle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) unsigned int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) addr = (void __iomem *)INTC_REG(d, _INTC_ADDR_D(handle), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) value = intc_set_field_from_handle(0, 1, handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) switch (_INTC_FN(handle)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case REG_FN_MODIFY_BASE + 0: /* 8bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) __raw_readb(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) __raw_writeb(0xff ^ value, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case REG_FN_MODIFY_BASE + 1: /* 16bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) __raw_readw(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) __raw_writew(0xffff ^ value, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) case REG_FN_MODIFY_BASE + 3: /* 32bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) __raw_readl(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) __raw_writel(0xffffffff ^ value, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned int nr_hp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct intc_handle_int key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) key.irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) key.handle = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return bsearch(&key, hp, nr_hp, sizeof(*hp), intc_handle_int_cmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int intc_set_priority(unsigned int irq, unsigned int prio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct intc_desc_int *d = get_intc_desc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct irq_data *data = irq_get_irq_data(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct intc_handle_int *ihp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!intc_get_prio_level(irq) || prio <= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ihp = intc_find_irq(d->prio, d->nr_prio, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (ihp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (prio >= (1 << _INTC_WIDTH(ihp->handle)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) intc_set_prio_level(irq, prio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * only set secondary masking method directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * primary masking method is using intc_prio_level[irq]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * priority level will be set during next enable()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (_INTC_FN(ihp->handle) != REG_FN_ERR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) _intc_enable(data, ihp->handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #define SENSE_VALID_FLAG 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define VALID(x) (x | SENSE_VALID_FLAG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) [IRQ_TYPE_EDGE_FALLING] = VALID(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) [IRQ_TYPE_EDGE_RISING] = VALID(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) [IRQ_TYPE_LEVEL_LOW] = VALID(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* SH7706, SH7707 and SH7709 do not support high level triggered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #if !defined(CONFIG_CPU_SUBTYPE_SH7706) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) !defined(CONFIG_CPU_SUBTYPE_SH7707) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) !defined(CONFIG_CPU_SUBTYPE_SH7709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #if defined(CONFIG_ARM) /* all recent SH-Mobile / R-Mobile ARM support this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) [IRQ_TYPE_EDGE_BOTH] = VALID(4),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int intc_set_type(struct irq_data *data, unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct intc_desc_int *d = get_intc_desc(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct intc_handle_int *ihp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned long addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (!value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) value &= ~SENSE_VALID_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ihp = intc_find_irq(d->sense, d->nr_sense, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (ihp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* PINT has 2-bit sense registers, should fail on EDGE_BOTH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (value >= (1 << _INTC_WIDTH(ihp->handle)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct irq_chip intc_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .irq_mask = intc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .irq_unmask = intc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .irq_mask_ack = intc_mask_ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .irq_enable = intc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .irq_disable = intc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .irq_set_type = intc_set_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .irq_set_affinity = intc_set_affinity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .flags = IRQCHIP_SKIP_SET_WAKE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) };