@@ -495,7 +495,7 @@ config TI_SCI_INTA_IRQCHIP
config TI_PRUSS_INTC
tristate "TI PRU-ICSS Interrupt Controller"
- depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE
+ depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
select IRQ_DOMAIN
help
This enables support for the PRU-ICSS Local Interrupt Controller
@@ -7,6 +7,7 @@
* Suman Anna <s-anna@ti.com>
*/
+#include <linux/bitmap.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
@@ -25,9 +26,6 @@
/* minimum starting host interrupt number for MPU */
#define MIN_PRU_HOST_INT 2
-/* maximum number of system events */
-#define MAX_PRU_SYS_EVENTS 64
-
/* PRU_ICSS_INTC registers */
#define PRU_INTC_REVID 0x0000
#define PRU_INTC_CR 0x0004
@@ -41,30 +39,42 @@
#define PRU_INTC_HIDISR 0x0038
#define PRU_INTC_GPIR 0x0080
#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4)
-#define PRU_INTC_SECR0 0x0280
-#define PRU_INTC_SECR1 0x0284
-#define PRU_INTC_ESR0 0x0300
-#define PRU_INTC_ESR1 0x0304
-#define PRU_INTC_ECR0 0x0380
-#define PRU_INTC_ECR1 0x0384
+#define PRU_INTC_SECR(x) (0x0280 + (x) * 4)
+#define PRU_INTC_ESR(x) (0x0300 + (x) * 4)
+#define PRU_INTC_ECR(x) (0x0380 + (x) * 4)
#define PRU_INTC_CMR(x) (0x0400 + (x) * 4)
#define PRU_INTC_HMR(x) (0x0800 + (x) * 4)
#define PRU_INTC_HIPIR(x) (0x0900 + (x) * 4)
-#define PRU_INTC_SIPR0 0x0d00
-#define PRU_INTC_SIPR1 0x0d04
-#define PRU_INTC_SITR0 0x0d80
-#define PRU_INTC_SITR1 0x0d84
+#define PRU_INTC_SIPR(x) (0x0d00 + (x) * 4)
+#define PRU_INTC_SITR(x) (0x0d80 + (x) * 4)
#define PRU_INTC_HINLR(x) (0x1100 + (x) * 4)
#define PRU_INTC_HIER 0x1500
+/* CMR register bit-field macros */
+#define CMR_EVT_PER_REG 4
+
+/* HMR register bit-field macros */
+#define HMR_CH_PER_REG 4
+
/* HIPIR register bit-fields */
#define INTC_HIPIR_NONE_HINT 0x80000000
/**
+ * struct pruss_intc_match_data - match data to handle SoC variations
+ * @num_system_events: number of input system events handled by the PRUSS INTC
+ * @num_host_intrs: number of host interrupts supported by the PRUSS INTC
+ */
+struct pruss_intc_match_data {
+ u8 num_system_events;
+ u8 num_host_intrs;
+};
+
+/**
* struct pruss_intc - PRUSS interrupt controller structure
* @irqs: kernel irq numbers corresponding to PRUSS host interrupts
* @base: base virtual address of INTC register space
* @domain: irq domain for this interrupt controller
+ * @soc_config: cached PRUSS INTC IP configuration data
* @shared_intr: bit-map denoting if the MPU host interrupt is shared
* @invalid_intr: bit-map denoting if host interrupt is not connected to MPU
*/
@@ -72,6 +82,7 @@ struct pruss_intc {
unsigned int irqs[MAX_NUM_HOST_IRQS];
void __iomem *base;
struct irq_domain *domain;
+ const struct pruss_intc_match_data *soc_config;
u16 shared_intr;
u16 invalid_intr;
};
@@ -89,22 +100,30 @@ static inline void pruss_intc_write_reg(struct pruss_intc *intc,
static void pruss_intc_init(struct pruss_intc *intc)
{
+ const struct pruss_intc_match_data *soc_config = intc->soc_config;
int i;
+ int num_chnl_map_regs = DIV_ROUND_UP(soc_config->num_system_events,
+ CMR_EVT_PER_REG);
+ int num_host_intr_regs = DIV_ROUND_UP(soc_config->num_host_intrs,
+ HMR_CH_PER_REG);
+ int num_event_type_regs =
+ DIV_ROUND_UP(soc_config->num_system_events, 32);
- /* configure polarity to active high for all system interrupts */
- pruss_intc_write_reg(intc, PRU_INTC_SIPR0, 0xffffffff);
- pruss_intc_write_reg(intc, PRU_INTC_SIPR1, 0xffffffff);
-
- /* configure type to pulse interrupt for all system interrupts */
- pruss_intc_write_reg(intc, PRU_INTC_SITR0, 0);
- pruss_intc_write_reg(intc, PRU_INTC_SITR1, 0);
+ /*
+ * configure polarity (SIPR register) to active high and
+ * type (SITR register) to pulse interrupt for all system events
+ */
+ for (i = 0; i < num_event_type_regs; i++) {
+ pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff);
+ pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0);
+ }
- /* clear all 16 interrupt channel map registers */
- for (i = 0; i < 16; i++)
+ /* clear all interrupt channel map registers, 4 events per register */
+ for (i = 0; i < num_chnl_map_regs; i++)
pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
- /* clear all 3 host interrupt map registers */
- for (i = 0; i < 3; i++)
+ /* clear all host interrupt map registers, 4 channels per register */
+ for (i = 0; i < num_host_intr_regs; i++)
pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
}
@@ -266,11 +285,20 @@ static int pruss_intc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct pruss_intc *intc;
int i, irq, count;
+ const struct pruss_intc_match_data *data;
u8 temp_intr[MAX_NUM_HOST_IRQS] = { 0 };
+ u8 max_system_events;
+
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return -ENODEV;
+
+ max_system_events = data->num_system_events;
intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
if (!intc)
return -ENOMEM;
+ intc->soc_config = data;
platform_set_drvdata(pdev, intc);
intc->base = devm_platform_ioremap_resource(pdev, 0);
@@ -327,8 +355,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
pruss_intc_init(intc);
- /* always 64 events */
- intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS,
+ intc->domain = irq_domain_add_linear(dev->of_node, max_system_events,
&pruss_intc_irq_domain_ops, intc);
if (!intc->domain)
return -ENOMEM;
@@ -369,6 +396,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
static int pruss_intc_remove(struct platform_device *pdev)
{
struct pruss_intc *intc = platform_get_drvdata(pdev);
+ u8 max_system_events = intc->soc_config->num_system_events;
unsigned int hwirq;
int i;
@@ -378,7 +406,7 @@ static int pruss_intc_remove(struct platform_device *pdev)
NULL);
}
- for (hwirq = 0; hwirq < MAX_PRU_SYS_EVENTS; hwirq++)
+ for (hwirq = 0; hwirq < max_system_events; hwirq++)
irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq));
irq_domain_remove(intc->domain);
@@ -386,8 +414,25 @@ static int pruss_intc_remove(struct platform_device *pdev)
return 0;
}
+static const struct pruss_intc_match_data pruss_intc_data = {
+ .num_system_events = 64,
+ .num_host_intrs = 10,
+};
+
+static const struct pruss_intc_match_data icssg_intc_data = {
+ .num_system_events = 160,
+ .num_host_intrs = 20,
+};
+
static const struct of_device_id pruss_intc_of_match[] = {
- { .compatible = "ti,pruss-intc", },
+ {
+ .compatible = "ti,pruss-intc",
+ .data = &pruss_intc_data,
+ },
+ {
+ .compatible = "ti,icssg-intc",
+ .data = &icssg_intc_data,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, pruss_intc_of_match);