|
|
@@ -34,21 +34,23 @@
|
|
|
#define PRU_INTC_HIEISR 0x0034
|
|
|
#define PRU_INTC_HIDISR 0x0038
|
|
|
#define PRU_INTC_GPIR 0x0080
|
|
|
+#define PRU_INTC_SRSR(x) (0x0200 + (x) * 4)
|
|
|
#define PRU_INTC_SRSR0 0x0200
|
|
|
#define PRU_INTC_SRSR1 0x0204
|
|
|
+#define PRU_INTC_SECR(x) (0x0280 + (x) * 4)
|
|
|
#define PRU_INTC_SECR0 0x0280
|
|
|
#define PRU_INTC_SECR1 0x0284
|
|
|
+#define PRU_INTC_ESR(x) (0x0300 + (x) * 4)
|
|
|
#define PRU_INTC_ESR0 0x0300
|
|
|
#define PRU_INTC_ESR1 0x0304
|
|
|
+#define PRU_INTC_ECR(x) (0x0380 + (x) * 4)
|
|
|
#define PRU_INTC_ECR0 0x0380
|
|
|
#define PRU_INTC_ECR1 0x0384
|
|
|
#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
|
|
|
|
|
|
@@ -61,9 +63,13 @@ static const char * const irq_names[] = {
|
|
|
|
|
|
/**
|
|
|
* 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
|
|
|
* @no_host7_intr: flag denoting the absence of host7 interrupt into MPU
|
|
|
*/
|
|
|
struct pruss_intc_match_data {
|
|
|
+ u8 num_system_events;
|
|
|
+ u8 num_host_intrs;
|
|
|
bool no_host7_intr;
|
|
|
};
|
|
|
|
|
|
@@ -74,6 +80,7 @@ struct pruss_intc_match_data {
|
|
|
* @base: base virtual address of INTC register space
|
|
|
* @irqchip: irq chip for this interrupt controller
|
|
|
* @domain: irq domain for this interrupt controller
|
|
|
+ * @data: cached PRUSS INTC IP configuration data
|
|
|
* @config_map: stored INTC configuration mapping data
|
|
|
* @lock: mutex to serialize access to INTC
|
|
|
* @host_mask: indicate which HOST IRQs are enabled
|
|
|
@@ -84,6 +91,7 @@ struct pruss_intc {
|
|
|
void __iomem *base;
|
|
|
struct irq_chip *irqchip;
|
|
|
struct irq_domain *domain;
|
|
|
+ const struct pruss_intc_match_data *data;
|
|
|
struct pruss_intc_config config_map;
|
|
|
struct mutex lock; /* PRUSS INTC lock */
|
|
|
u32 host_mask;
|
|
|
@@ -106,7 +114,7 @@ static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
|
|
|
if (!intc)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (sysevent >= MAX_PRU_SYS_EVENTS)
|
|
|
+ if (sysevent >= intc->data->num_system_events)
|
|
|
return -EINVAL;
|
|
|
|
|
|
pruss_intc_write_reg(intc, reg, sysevent);
|
|
|
@@ -157,16 +165,24 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
{
|
|
|
struct device *dev = pruss->dev;
|
|
|
struct pruss_intc *intc = to_pruss_intc(pruss);
|
|
|
- int i, idx, ret;
|
|
|
+ int i, idx;
|
|
|
s8 ch, host;
|
|
|
- u64 sysevt_mask = 0;
|
|
|
+ u32 num_events = intc->data->num_system_events;
|
|
|
+ u32 num_intrs = intc->data->num_host_intrs;
|
|
|
+ u32 num_regs = DIV_ROUND_UP(num_events, 32);
|
|
|
+ u32 *sysevt_mask = NULL;
|
|
|
u32 ch_mask = 0;
|
|
|
u32 host_mask = 0;
|
|
|
+ int ret = 0;
|
|
|
u32 val;
|
|
|
|
|
|
if (!intc)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ sysevt_mask = kcalloc(num_regs, sizeof(*sysevt_mask), GFP_KERNEL);
|
|
|
+ if (!sysevt_mask)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
mutex_lock(&intc->lock);
|
|
|
|
|
|
/*
|
|
|
@@ -174,7 +190,7 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
* for 4 events, with each event occupying the lower nibble in
|
|
|
* a register byte address in little-endian fashion
|
|
|
*/
|
|
|
- for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
|
|
|
+ for (i = 0; i < num_events; i++) {
|
|
|
ch = intc_config->sysev_to_ch[i];
|
|
|
if (ch < 0)
|
|
|
continue;
|
|
|
@@ -193,7 +209,7 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
|
|
|
val |= ch << ((i & 3) * 8);
|
|
|
pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
|
|
|
- sysevt_mask |= BIT_ULL(i);
|
|
|
+ sysevt_mask[i / 32] |= BIT(i % 32);
|
|
|
ch_mask |= BIT(ch);
|
|
|
|
|
|
dev_dbg(dev, "SYSEV%d -> CH%d (CMR%d 0x%08x)\n", i, ch, idx,
|
|
|
@@ -205,7 +221,7 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
* 4 channels, with each channel occupying the lower nibble in
|
|
|
* a register byte address in little-endian fashion
|
|
|
*/
|
|
|
- for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
|
|
|
+ for (i = 0; i < num_intrs; i++) {
|
|
|
host = intc_config->ch_to_host[i];
|
|
|
if (host < 0)
|
|
|
continue;
|
|
|
@@ -241,17 +257,25 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
|
|
|
}
|
|
|
|
|
|
- dev_info(dev, "configured system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n",
|
|
|
- sysevt_mask, ch_mask, host_mask);
|
|
|
+ if (num_events == MAX_PRU_SYS_EVENTS) {
|
|
|
+ dev_info(dev, "configured system_events[63-0] = 0x%08x.%08x",
|
|
|
+ sysevt_mask[1], sysevt_mask[0]);
|
|
|
+ } else if (num_events == MAX_PRU_SYS_EVENTS_K3) {
|
|
|
+ dev_info(dev, "configured system_events[159-0] = 0x%08x.%08x.%08x.%08x.%08x",
|
|
|
+ sysevt_mask[4], sysevt_mask[3], sysevt_mask[2],
|
|
|
+ sysevt_mask[1], sysevt_mask[0]);
|
|
|
+ }
|
|
|
+ dev_info(dev, "configured intr_channels = 0x%08x host_intr = 0x%08x\n",
|
|
|
+ ch_mask, host_mask);
|
|
|
|
|
|
/* enable system events, writing 0 has no-effect */
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask));
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask));
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
|
|
|
+ for (i = 0; i < num_regs; i++) {
|
|
|
+ pruss_intc_write_reg(intc, PRU_INTC_ESR(i), sysevt_mask[i]);
|
|
|
+ pruss_intc_write_reg(intc, PRU_INTC_SECR(i), sysevt_mask[i]);
|
|
|
+ }
|
|
|
|
|
|
/* enable host interrupts */
|
|
|
- for (i = 0; i < MAX_PRU_HOST_INT; i++) {
|
|
|
+ for (i = 0; i < num_intrs; i++) {
|
|
|
if (host_mask & BIT(i))
|
|
|
pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i);
|
|
|
}
|
|
|
@@ -261,11 +285,9 @@ int pruss_intc_configure(struct pruss *pruss,
|
|
|
|
|
|
intc->host_mask |= host_mask;
|
|
|
|
|
|
- mutex_unlock(&intc->lock);
|
|
|
- return 0;
|
|
|
-
|
|
|
unlock:
|
|
|
mutex_unlock(&intc->lock);
|
|
|
+ kfree(sysevt_mask);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pruss_intc_configure);
|
|
|
@@ -286,25 +308,32 @@ int pruss_intc_unconfigure(struct pruss *pruss,
|
|
|
struct pruss_intc *intc = to_pruss_intc(pruss);
|
|
|
int i;
|
|
|
s8 ch, host;
|
|
|
- u64 sysevt_mask = 0;
|
|
|
+ u32 num_events = intc->data->num_system_events;
|
|
|
+ u32 num_intrs = intc->data->num_host_intrs;
|
|
|
+ u32 num_regs = DIV_ROUND_UP(num_events, 32);
|
|
|
+ u32 *sysevt_mask = NULL;
|
|
|
u32 host_mask = 0;
|
|
|
|
|
|
if (!intc)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ sysevt_mask = kcalloc(num_regs, sizeof(*sysevt_mask), GFP_KERNEL);
|
|
|
+ if (!sysevt_mask)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
mutex_lock(&intc->lock);
|
|
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
|
|
|
+ for (i = 0; i < num_events; i++) {
|
|
|
ch = intc_config->sysev_to_ch[i];
|
|
|
if (ch < 0)
|
|
|
continue;
|
|
|
|
|
|
/* mark sysevent free in global map */
|
|
|
intc->config_map.sysev_to_ch[i] = -1;
|
|
|
- sysevt_mask |= BIT_ULL(i);
|
|
|
+ sysevt_mask[i / 32] |= BIT(i % 32);
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
|
|
|
+ for (i = 0; i < num_intrs; i++) {
|
|
|
host = intc_config->ch_to_host[i];
|
|
|
if (host < 0)
|
|
|
continue;
|
|
|
@@ -314,15 +343,22 @@ int pruss_intc_unconfigure(struct pruss *pruss,
|
|
|
host_mask |= BIT(host);
|
|
|
}
|
|
|
|
|
|
- dev_info(dev, "unconfigured system_events = 0x%016llx host_intr = 0x%08x\n",
|
|
|
- sysevt_mask, host_mask);
|
|
|
+ if (num_events == MAX_PRU_SYS_EVENTS) {
|
|
|
+ dev_info(dev, "unconfigured system_events[63-0] = 0x%08x.%08x",
|
|
|
+ sysevt_mask[1], sysevt_mask[0]);
|
|
|
+ } else if (num_events == MAX_PRU_SYS_EVENTS_K3) {
|
|
|
+ dev_info(dev, "unconfigured system_events[159-0] = 0x%08x.%08x.%08x.%08x.%08x",
|
|
|
+ sysevt_mask[4], sysevt_mask[3], sysevt_mask[2],
|
|
|
+ sysevt_mask[1], sysevt_mask[0]);
|
|
|
+ }
|
|
|
+ dev_info(dev, "unconfigured host_intr = 0x%08x\n", host_mask);
|
|
|
|
|
|
- /* disable system events, writing 0 has no-effect */
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask));
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask));
|
|
|
- /* clear any pending status */
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
|
|
|
- pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
|
|
|
+ for (i = 0; i < num_regs; i++) {
|
|
|
+ /* disable system events, writing 0 has no-effect */
|
|
|
+ pruss_intc_write_reg(intc, PRU_INTC_ECR(i), sysevt_mask[i]);
|
|
|
+ /* clear any pending status */
|
|
|
+ pruss_intc_write_reg(intc, PRU_INTC_SECR(i), sysevt_mask[i]);
|
|
|
+ }
|
|
|
|
|
|
/* disable host interrupts */
|
|
|
for (i = 0; i < MAX_PRU_HOST_INT; i++) {
|
|
|
@@ -332,6 +368,7 @@ int pruss_intc_unconfigure(struct pruss *pruss,
|
|
|
|
|
|
intc->host_mask &= ~host_mask;
|
|
|
mutex_unlock(&intc->lock);
|
|
|
+ kfree(sysevt_mask);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -340,21 +377,26 @@ EXPORT_SYMBOL_GPL(pruss_intc_unconfigure);
|
|
|
static void pruss_intc_init(struct pruss_intc *intc)
|
|
|
{
|
|
|
int i;
|
|
|
+ int num_chnl_map_regs = DIV_ROUND_UP(intc->data->num_system_events, 4);
|
|
|
+ int num_host_intr_regs = DIV_ROUND_UP(intc->data->num_host_intrs, 4);
|
|
|
+ int num_event_type_regs =
|
|
|
+ DIV_ROUND_UP(intc->data->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);
|
|
|
}
|
|
|
|
|
|
@@ -509,13 +551,19 @@ static int pruss_intc_probe(struct platform_device *pdev)
|
|
|
int i, irq;
|
|
|
const struct pruss_intc_match_data *data;
|
|
|
bool skip_host7;
|
|
|
+ u8 max_system_events;
|
|
|
|
|
|
data = of_device_get_match_data(dev);
|
|
|
- skip_host7 = data ? data->no_host7_intr : false;
|
|
|
+ if (!data)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ skip_host7 = data->no_host7_intr;
|
|
|
+ max_system_events = data->num_system_events;
|
|
|
|
|
|
intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
|
|
|
if (!intc)
|
|
|
return -ENOMEM;
|
|
|
+ intc->data = data;
|
|
|
platform_set_drvdata(pdev, intc);
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
@@ -552,8 +600,7 @@ static int pruss_intc_probe(struct platform_device *pdev)
|
|
|
irqchip->name = dev_name(dev);
|
|
|
intc->irqchip = irqchip;
|
|
|
|
|
|
- /* 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;
|
|
|
@@ -584,10 +631,11 @@ fail_irq:
|
|
|
static int pruss_intc_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct pruss_intc *intc = platform_get_drvdata(pdev);
|
|
|
+ u8 max_system_events = intc->data->num_system_events;
|
|
|
unsigned int hwirq;
|
|
|
|
|
|
if (intc->domain) {
|
|
|
- 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);
|
|
|
@@ -596,30 +644,44 @@ static int pruss_intc_remove(struct platform_device *pdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct pruss_intc_match_data am437x_pruss_intc_data = {
|
|
|
- .no_host7_intr = true,
|
|
|
+static const struct pruss_intc_match_data am335x_am57xx_pruss_intc_data = {
|
|
|
+ .num_system_events = 64,
|
|
|
+ .num_host_intrs = 10,
|
|
|
+ .no_host7_intr = false,
|
|
|
};
|
|
|
|
|
|
-static const struct pruss_intc_match_data k2g_pruss_intc_data = {
|
|
|
+static const struct pruss_intc_match_data am437x_k2g_pruss_intc_data = {
|
|
|
+ .num_system_events = 64,
|
|
|
+ .num_host_intrs = 10,
|
|
|
.no_host7_intr = true,
|
|
|
};
|
|
|
|
|
|
+static const struct pruss_intc_match_data am65x_icssg_intc_data = {
|
|
|
+ .num_system_events = 160,
|
|
|
+ .num_host_intrs = 20,
|
|
|
+ .no_host7_intr = false,
|
|
|
+};
|
|
|
+
|
|
|
static const struct of_device_id pruss_intc_of_match[] = {
|
|
|
{
|
|
|
.compatible = "ti,am3356-pruss-intc",
|
|
|
- .data = NULL,
|
|
|
+ .data = &am335x_am57xx_pruss_intc_data,
|
|
|
},
|
|
|
{
|
|
|
.compatible = "ti,am4376-pruss-intc",
|
|
|
- .data = &am437x_pruss_intc_data,
|
|
|
+ .data = &am437x_k2g_pruss_intc_data,
|
|
|
},
|
|
|
{
|
|
|
.compatible = "ti,am5728-pruss-intc",
|
|
|
- .data = NULL,
|
|
|
+ .data = &am335x_am57xx_pruss_intc_data,
|
|
|
},
|
|
|
{
|
|
|
.compatible = "ti,k2g-pruss-intc",
|
|
|
- .data = &k2g_pruss_intc_data,
|
|
|
+ .data = &am437x_k2g_pruss_intc_data,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .compatible = "ti,am654-icssg-intc",
|
|
|
+ .data = &am65x_icssg_intc_data,
|
|
|
},
|
|
|
{ /* sentinel */ },
|
|
|
};
|