Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #define pr_fmt(fmt) "irq-ls-extirq: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <dt-bindings/interrupt-controller/arm-gic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #define MAXIRQ 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #define LS1021A_SCFGREVCR 0x200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) struct ls_extirq_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 	struct regmap		*syscon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	u32			intpcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	bool			bit_reverse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	u32			nirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	struct irq_fwspec	map[MAXIRQ];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) ls_extirq_set_type(struct irq_data *data, unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	struct ls_extirq_data *priv = data->chip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	irq_hw_number_t hwirq = data->hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	u32 value, mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	if (priv->bit_reverse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 		mask = 1U << (31 - hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 		mask = 1U << hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	case IRQ_TYPE_LEVEL_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 		type = IRQ_TYPE_LEVEL_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 		value = mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	case IRQ_TYPE_EDGE_FALLING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 		type = IRQ_TYPE_EDGE_RISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 		value = mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	case IRQ_TYPE_LEVEL_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	case IRQ_TYPE_EDGE_RISING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 		value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	regmap_update_bits(priv->syscon, priv->intpcr, mask, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	return irq_chip_set_type_parent(data, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) static struct irq_chip ls_extirq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	.name			= "ls-extirq",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	.irq_mask		= irq_chip_mask_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	.irq_unmask		= irq_chip_unmask_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	.irq_eoi		= irq_chip_eoi_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	.irq_set_type		= ls_extirq_set_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	.irq_retrigger		= irq_chip_retrigger_hierarchy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	.irq_set_affinity	= irq_chip_set_affinity_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	.flags                  = IRQCHIP_SET_TYPE_MASKED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) ls_extirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		       unsigned int nr_irqs, void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	struct ls_extirq_data *priv = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	struct irq_fwspec *fwspec = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	irq_hw_number_t hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	if (fwspec->param_count != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	hwirq = fwspec->param[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	if (hwirq >= priv->nirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &ls_extirq_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 				      priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	return irq_domain_alloc_irqs_parent(domain, virq, 1, &priv->map[hwirq]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) static const struct irq_domain_ops extirq_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	.xlate		= irq_domain_xlate_twocell,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	.alloc		= ls_extirq_domain_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	.free		= irq_domain_free_irqs_common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	const __be32 *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	u32 mapsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	map = of_get_property(node, "interrupt-map", &mapsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (!map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	if (mapsize % sizeof(*map))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	mapsize /= sizeof(*map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	while (mapsize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		struct device_node *ipar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		u32 hwirq, intsize, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		if (mapsize < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		hwirq = be32_to_cpup(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		if (hwirq >= MAXIRQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		priv->nirq = max(priv->nirq, hwirq + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		ipar = of_find_node_by_phandle(be32_to_cpup(map + 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		map += 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		mapsize -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		if (!ipar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		priv->map[hwirq].fwnode = &ipar->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		if (intsize > mapsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		priv->map[hwirq].param_count = intsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		for (j = 0; j < intsize; ++j)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			priv->map[hwirq].param[j] = be32_to_cpup(map++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		mapsize -= intsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ls_extirq_of_init(struct device_node *node, struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	struct irq_domain *domain, *parent_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct ls_extirq_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	parent_domain = irq_find_host(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	if (!parent_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		pr_err("Cannot find parent domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	priv->syscon = syscon_node_to_regmap(node->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (IS_ERR(priv->syscon)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		ret = PTR_ERR(priv->syscon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		pr_err("Failed to lookup parent regmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	ret = of_property_read_u32(node, "reg", &priv->intpcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		pr_err("Missing INTPCR offset value\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	ret = ls_extirq_parse_map(priv, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	if (of_device_is_compatible(node, "fsl,ls1021a-extirq")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		u32 revcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		ret = regmap_read(priv->syscon, LS1021A_SCFGREVCR, &revcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		priv->bit_reverse = (revcr != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 					  &extirq_domain_ops, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	if (!domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 		kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	return ret;
^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) IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init);