Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller
  4 * Copyright 2019 IBM Corporation
  5 *
  6 * Eddie James <eajames@linux.ibm.com>
  7 */
  8
  9#include <linux/bitops.h>
 10#include <linux/irq.h>
 11#include <linux/irqchip.h>
 12#include <linux/irqchip/chained_irq.h>
 13#include <linux/irqdomain.h>
 14#include <linux/mfd/syscon.h>
 15#include <linux/of_irq.h>
 16#include <linux/regmap.h>
 17
 18#define ASPEED_SCU_IC_REG		0x018
 19#define ASPEED_SCU_IC_SHIFT		0
 20#define ASPEED_SCU_IC_ENABLE		GENMASK(6, ASPEED_SCU_IC_SHIFT)
 21#define ASPEED_SCU_IC_NUM_IRQS		7
 22#define ASPEED_SCU_IC_STATUS_SHIFT	16
 23
 24#define ASPEED_AST2600_SCU_IC0_REG	0x560
 25#define ASPEED_AST2600_SCU_IC0_SHIFT	0
 26#define ASPEED_AST2600_SCU_IC0_ENABLE	\
 27	GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT)
 28#define ASPEED_AST2600_SCU_IC0_NUM_IRQS	6
 29
 30#define ASPEED_AST2600_SCU_IC1_REG	0x570
 31#define ASPEED_AST2600_SCU_IC1_SHIFT	4
 32#define ASPEED_AST2600_SCU_IC1_ENABLE	\
 33	GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT)
 34#define ASPEED_AST2600_SCU_IC1_NUM_IRQS	2
 35
 36struct aspeed_scu_ic {
 37	unsigned long irq_enable;
 38	unsigned long irq_shift;
 39	unsigned int num_irqs;
 40	unsigned int reg;
 41	struct regmap *scu;
 42	struct irq_domain *irq_domain;
 43};
 44
 45static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
 46{
 47	unsigned int irq;
 48	unsigned int sts;
 49	unsigned long bit;
 50	unsigned long enabled;
 51	unsigned long max;
 52	unsigned long status;
 53	struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
 54	struct irq_chip *chip = irq_desc_get_chip(desc);
 55	unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT;
 56
 57	chained_irq_enter(chip, desc);
 58
 59	/*
 60	 * The SCU IC has just one register to control its operation and read
 61	 * status. The interrupt enable bits occupy the lower 16 bits of the
 62	 * register, while the interrupt status bits occupy the upper 16 bits.
 63	 * The status bit for a given interrupt is always 16 bits shifted from
 64	 * the enable bit for the same interrupt.
 65	 * Therefore, perform the IRQ operations in the enable bit space by
 66	 * shifting the status down to get the mapping and then back up to
 67	 * clear the bit.
 68	 */
 69	regmap_read(scu_ic->scu, scu_ic->reg, &sts);
 70	enabled = sts & scu_ic->irq_enable;
 71	status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled;
 72
 73	bit = scu_ic->irq_shift;
 74	max = scu_ic->num_irqs + bit;
 75
 76	for_each_set_bit_from(bit, &status, max) {
 77		irq = irq_find_mapping(scu_ic->irq_domain,
 78				       bit - scu_ic->irq_shift);
 79		generic_handle_irq(irq);
 80
 81		regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
 82				   BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
 83	}
 84
 85	chained_irq_exit(chip, desc);
 86}
 87
 88static void aspeed_scu_ic_irq_mask(struct irq_data *data)
 89{
 90	struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
 91	unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) |
 92		(scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
 93
 94	/*
 95	 * Status bits are cleared by writing 1. In order to prevent the mask
 96	 * operation from clearing the status bits, they should be under the
 97	 * mask and written with 0.
 98	 */
 99	regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0);
100}
101
102static void aspeed_scu_ic_irq_unmask(struct irq_data *data)
103{
104	struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
105	unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
106	unsigned int mask = bit |
107		(scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
108
109	/*
110	 * Status bits are cleared by writing 1. In order to prevent the unmask
111	 * operation from clearing the status bits, they should be under the
112	 * mask and written with 0.
113	 */
114	regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit);
115}
116
117static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data,
118					  const struct cpumask *dest,
119					  bool force)
120{
121	return -EINVAL;
122}
123
124static struct irq_chip aspeed_scu_ic_chip = {
125	.name			= "aspeed-scu-ic",
126	.irq_mask		= aspeed_scu_ic_irq_mask,
127	.irq_unmask		= aspeed_scu_ic_irq_unmask,
128	.irq_set_affinity	= aspeed_scu_ic_irq_set_affinity,
129};
130
131static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq,
132			     irq_hw_number_t hwirq)
133{
134	irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq);
135	irq_set_chip_data(irq, domain->host_data);
136
137	return 0;
138}
139
140static const struct irq_domain_ops aspeed_scu_ic_domain_ops = {
141	.map = aspeed_scu_ic_map,
142};
143
144static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic,
145					struct device_node *node)
146{
147	int irq;
148	int rc = 0;
149
150	if (!node->parent) {
151		rc = -ENODEV;
152		goto err;
153	}
154
155	scu_ic->scu = syscon_node_to_regmap(node->parent);
156	if (IS_ERR(scu_ic->scu)) {
157		rc = PTR_ERR(scu_ic->scu);
158		goto err;
159	}
160
161	irq = irq_of_parse_and_map(node, 0);
162	if (irq < 0) {
163		rc = irq;
164		goto err;
165	}
166
167	scu_ic->irq_domain = irq_domain_add_linear(node, scu_ic->num_irqs,
168						   &aspeed_scu_ic_domain_ops,
169						   scu_ic);
170	if (!scu_ic->irq_domain) {
171		rc = -ENOMEM;
172		goto err;
173	}
174
175	irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler,
176					 scu_ic);
177
178	return 0;
179
180err:
181	kfree(scu_ic);
182
183	return rc;
184}
185
186static int __init aspeed_scu_ic_of_init(struct device_node *node,
187					struct device_node *parent)
188{
189	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
190
191	if (!scu_ic)
192		return -ENOMEM;
193
194	scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE;
195	scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT;
196	scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS;
197	scu_ic->reg = ASPEED_SCU_IC_REG;
198
199	return aspeed_scu_ic_of_init_common(scu_ic, node);
200}
201
202static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node,
203						 struct device_node *parent)
204{
205	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
206
207	if (!scu_ic)
208		return -ENOMEM;
209
210	scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE;
211	scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT;
212	scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS;
213	scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG;
214
215	return aspeed_scu_ic_of_init_common(scu_ic, node);
216}
217
218static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node,
219						 struct device_node *parent)
220{
221	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
222
223	if (!scu_ic)
224		return -ENOMEM;
225
226	scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE;
227	scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT;
228	scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS;
229	scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG;
230
231	return aspeed_scu_ic_of_init_common(scu_ic, node);
232}
233
234IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init);
235IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init);
236IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0",
237		aspeed_ast2600_scu_ic0_of_init);
238IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1",
239		aspeed_ast2600_scu_ic1_of_init);
v6.2
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller
  4 * Copyright 2019 IBM Corporation
  5 *
  6 * Eddie James <eajames@linux.ibm.com>
  7 */
  8
  9#include <linux/bitops.h>
 10#include <linux/irq.h>
 11#include <linux/irqchip.h>
 12#include <linux/irqchip/chained_irq.h>
 13#include <linux/irqdomain.h>
 14#include <linux/mfd/syscon.h>
 15#include <linux/of_irq.h>
 16#include <linux/regmap.h>
 17
 18#define ASPEED_SCU_IC_REG		0x018
 19#define ASPEED_SCU_IC_SHIFT		0
 20#define ASPEED_SCU_IC_ENABLE		GENMASK(6, ASPEED_SCU_IC_SHIFT)
 21#define ASPEED_SCU_IC_NUM_IRQS		7
 22#define ASPEED_SCU_IC_STATUS_SHIFT	16
 23
 24#define ASPEED_AST2600_SCU_IC0_REG	0x560
 25#define ASPEED_AST2600_SCU_IC0_SHIFT	0
 26#define ASPEED_AST2600_SCU_IC0_ENABLE	\
 27	GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT)
 28#define ASPEED_AST2600_SCU_IC0_NUM_IRQS	6
 29
 30#define ASPEED_AST2600_SCU_IC1_REG	0x570
 31#define ASPEED_AST2600_SCU_IC1_SHIFT	4
 32#define ASPEED_AST2600_SCU_IC1_ENABLE	\
 33	GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT)
 34#define ASPEED_AST2600_SCU_IC1_NUM_IRQS	2
 35
 36struct aspeed_scu_ic {
 37	unsigned long irq_enable;
 38	unsigned long irq_shift;
 39	unsigned int num_irqs;
 40	unsigned int reg;
 41	struct regmap *scu;
 42	struct irq_domain *irq_domain;
 43};
 44
 45static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
 46{
 
 47	unsigned int sts;
 48	unsigned long bit;
 49	unsigned long enabled;
 50	unsigned long max;
 51	unsigned long status;
 52	struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
 53	struct irq_chip *chip = irq_desc_get_chip(desc);
 54	unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT;
 55
 56	chained_irq_enter(chip, desc);
 57
 58	/*
 59	 * The SCU IC has just one register to control its operation and read
 60	 * status. The interrupt enable bits occupy the lower 16 bits of the
 61	 * register, while the interrupt status bits occupy the upper 16 bits.
 62	 * The status bit for a given interrupt is always 16 bits shifted from
 63	 * the enable bit for the same interrupt.
 64	 * Therefore, perform the IRQ operations in the enable bit space by
 65	 * shifting the status down to get the mapping and then back up to
 66	 * clear the bit.
 67	 */
 68	regmap_read(scu_ic->scu, scu_ic->reg, &sts);
 69	enabled = sts & scu_ic->irq_enable;
 70	status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled;
 71
 72	bit = scu_ic->irq_shift;
 73	max = scu_ic->num_irqs + bit;
 74
 75	for_each_set_bit_from(bit, &status, max) {
 76		generic_handle_domain_irq(scu_ic->irq_domain,
 77					  bit - scu_ic->irq_shift);
 
 78
 79		regmap_write_bits(scu_ic->scu, scu_ic->reg, mask,
 80				  BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
 81	}
 82
 83	chained_irq_exit(chip, desc);
 84}
 85
 86static void aspeed_scu_ic_irq_mask(struct irq_data *data)
 87{
 88	struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
 89	unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) |
 90		(scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
 91
 92	/*
 93	 * Status bits are cleared by writing 1. In order to prevent the mask
 94	 * operation from clearing the status bits, they should be under the
 95	 * mask and written with 0.
 96	 */
 97	regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0);
 98}
 99
100static void aspeed_scu_ic_irq_unmask(struct irq_data *data)
101{
102	struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
103	unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
104	unsigned int mask = bit |
105		(scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
106
107	/*
108	 * Status bits are cleared by writing 1. In order to prevent the unmask
109	 * operation from clearing the status bits, they should be under the
110	 * mask and written with 0.
111	 */
112	regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit);
113}
114
115static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data,
116					  const struct cpumask *dest,
117					  bool force)
118{
119	return -EINVAL;
120}
121
122static struct irq_chip aspeed_scu_ic_chip = {
123	.name			= "aspeed-scu-ic",
124	.irq_mask		= aspeed_scu_ic_irq_mask,
125	.irq_unmask		= aspeed_scu_ic_irq_unmask,
126	.irq_set_affinity	= aspeed_scu_ic_irq_set_affinity,
127};
128
129static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq,
130			     irq_hw_number_t hwirq)
131{
132	irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq);
133	irq_set_chip_data(irq, domain->host_data);
134
135	return 0;
136}
137
138static const struct irq_domain_ops aspeed_scu_ic_domain_ops = {
139	.map = aspeed_scu_ic_map,
140};
141
142static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic,
143					struct device_node *node)
144{
145	int irq;
146	int rc = 0;
147
148	if (!node->parent) {
149		rc = -ENODEV;
150		goto err;
151	}
152
153	scu_ic->scu = syscon_node_to_regmap(node->parent);
154	if (IS_ERR(scu_ic->scu)) {
155		rc = PTR_ERR(scu_ic->scu);
156		goto err;
157	}
158
159	irq = irq_of_parse_and_map(node, 0);
160	if (!irq) {
161		rc = -EINVAL;
162		goto err;
163	}
164
165	scu_ic->irq_domain = irq_domain_add_linear(node, scu_ic->num_irqs,
166						   &aspeed_scu_ic_domain_ops,
167						   scu_ic);
168	if (!scu_ic->irq_domain) {
169		rc = -ENOMEM;
170		goto err;
171	}
172
173	irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler,
174					 scu_ic);
175
176	return 0;
177
178err:
179	kfree(scu_ic);
180
181	return rc;
182}
183
184static int __init aspeed_scu_ic_of_init(struct device_node *node,
185					struct device_node *parent)
186{
187	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
188
189	if (!scu_ic)
190		return -ENOMEM;
191
192	scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE;
193	scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT;
194	scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS;
195	scu_ic->reg = ASPEED_SCU_IC_REG;
196
197	return aspeed_scu_ic_of_init_common(scu_ic, node);
198}
199
200static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node,
201						 struct device_node *parent)
202{
203	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
204
205	if (!scu_ic)
206		return -ENOMEM;
207
208	scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE;
209	scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT;
210	scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS;
211	scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG;
212
213	return aspeed_scu_ic_of_init_common(scu_ic, node);
214}
215
216static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node,
217						 struct device_node *parent)
218{
219	struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
220
221	if (!scu_ic)
222		return -ENOMEM;
223
224	scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE;
225	scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT;
226	scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS;
227	scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG;
228
229	return aspeed_scu_ic_of_init_common(scu_ic, node);
230}
231
232IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init);
233IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init);
234IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0",
235		aspeed_ast2600_scu_ic0_of_init);
236IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1",
237		aspeed_ast2600_scu_ic1_of_init);