2222
2323#define IRQC_IRQ_START 1
2424#define IRQC_TINT_COUNT 32
25+ #define IRQC_SHARED_IRQ_COUNT 8
26+ #define IRQC_IRQ_SHARED_START (IRQC_IRQ_START + IRQC_SHARED_IRQ_COUNT)
2527
2628#define ISCR 0x10
2729#define IITSR 0x14
2830#define TSCR 0x20
2931#define TITSR (n ) (0x24 + (n) * 4)
3032#define TITSR0_MAX_INT 16
3133#define TITSEL_WIDTH 0x2
34+ #define INTTSEL 0x2c
3235#define TSSR (n ) (0x30 + ((n) * 4))
3336#define TIEN BIT(7)
3437#define TSSEL_SHIFT (n ) (8 * (n))
5255#define IITSR_IITSEL_EDGE_BOTH 3
5356#define IITSR_IITSEL_MASK (n ) IITSR_IITSEL((n), 3)
5457
58+ #define INTTSEL_TINTSEL (n ) BIT(n)
59+ #define INTTSEL_TINTSEL_START 24
60+
5561#define TINT_EXTRACT_HWIRQ (x ) FIELD_GET(GENMASK(15, 0), (x))
5662#define TINT_EXTRACT_GPIOINT (x ) FIELD_GET(GENMASK(31, 16), (x))
5763
5864/**
5965 * struct rzg2l_irqc_reg_cache - registers cache (necessary for suspend/resume)
6066 * @iitsr: IITSR register
67+ * @inttsel: INTTSEL register
6168 * @titsr: TITSR registers
6269 */
6370struct rzg2l_irqc_reg_cache {
6471 u32 iitsr ;
72+ u32 inttsel ;
6573 u32 titsr [2 ];
6674};
6775
@@ -71,12 +79,14 @@ struct rzg2l_irqc_reg_cache {
7179 * @irq_count: Number of IRQC interrupts
7280 * @tint_start: Start of TINT interrupts
7381 * @num_irq: Total Number of interrupts
82+ * @shared_irq_cnt: Number of shared interrupts
7483 */
7584struct rzg2l_hw_info {
7685 const u8 * tssel_lut ;
7786 unsigned int irq_count ;
7887 unsigned int tint_start ;
7988 unsigned int num_irq ;
89+ unsigned int shared_irq_cnt ;
8090};
8191
8292/**
@@ -88,6 +98,7 @@ struct rzg2l_hw_info {
8898 * @lock: Lock to serialize access to hardware registers
8999 * @info: Hardware specific data
90100 * @cache: Registers cache for suspend/resume
101+ * @used_irqs: Bitmap to manage the shared interrupts
91102 */
92103static struct rzg2l_irqc_priv {
93104 void __iomem * base ;
@@ -97,6 +108,7 @@ static struct rzg2l_irqc_priv {
97108 raw_spinlock_t lock ;
98109 struct rzg2l_hw_info info ;
99110 struct rzg2l_irqc_reg_cache cache ;
111+ DECLARE_BITMAP (used_irqs , IRQC_SHARED_IRQ_COUNT );
100112} * rzg2l_irqc_data ;
101113
102114static struct rzg2l_irqc_priv * irq_data_to_priv (struct irq_data * data )
@@ -462,6 +474,8 @@ static int rzg2l_irqc_irq_suspend(void *data)
462474 void __iomem * base = rzg2l_irqc_data -> base ;
463475
464476 cache -> iitsr = readl_relaxed (base + IITSR );
477+ if (rzg2l_irqc_data -> info .shared_irq_cnt )
478+ cache -> inttsel = readl_relaxed (base + INTTSEL );
465479 for (u8 i = 0 ; i < 2 ; i ++ )
466480 cache -> titsr [i ] = readl_relaxed (base + TITSR (i ));
467481
@@ -480,6 +494,8 @@ static void rzg2l_irqc_irq_resume(void *data)
480494 */
481495 for (u8 i = 0 ; i < 2 ; i ++ )
482496 writel_relaxed (cache -> titsr [i ], base + TITSR (i ));
497+ if (rzg2l_irqc_data -> info .shared_irq_cnt )
498+ writel_relaxed (cache -> inttsel , base + INTTSEL );
483499 writel_relaxed (cache -> iitsr , base + IITSR );
484500}
485501
@@ -560,6 +576,72 @@ static const struct irq_chip rzfive_irqc_tint_chip = {
560576 IRQCHIP_SKIP_SET_WAKE ,
561577};
562578
579+ static bool rzg2l_irqc_is_shared_irqc (const struct rzg2l_hw_info info , unsigned int hw_irq )
580+ {
581+ return ((hw_irq >= (info .tint_start - info .shared_irq_cnt )) && hw_irq < info .tint_start );
582+ }
583+
584+ static bool rzg2l_irqc_is_shared_tint (const struct rzg2l_hw_info info , unsigned int hw_irq )
585+ {
586+ return ((hw_irq >= (info .num_irq - info .shared_irq_cnt )) && hw_irq < info .num_irq );
587+ }
588+
589+ static bool rzg2l_irqc_is_shared_and_get_irq_num (struct rzg2l_irqc_priv * priv ,
590+ irq_hw_number_t hwirq , unsigned int * irq_num )
591+ {
592+ bool is_shared = false;
593+
594+ if (rzg2l_irqc_is_shared_irqc (priv -> info , hwirq )) {
595+ * irq_num = hwirq - IRQC_IRQ_SHARED_START ;
596+ is_shared = true;
597+ } else if (rzg2l_irqc_is_shared_tint (priv -> info , hwirq )) {
598+ * irq_num = hwirq - IRQC_TINT_COUNT - IRQC_IRQ_SHARED_START ;
599+ is_shared = true;
600+ }
601+
602+ return is_shared ;
603+ }
604+
605+ static void rzg2l_irqc_set_inttsel (struct rzg2l_irqc_priv * priv , unsigned int offset ,
606+ unsigned int select_irq )
607+ {
608+ u32 reg ;
609+
610+ guard (raw_spinlock_irqsave )(& priv -> lock );
611+ reg = readl_relaxed (priv -> base + INTTSEL );
612+ if (select_irq )
613+ reg |= INTTSEL_TINTSEL (offset );
614+ else
615+ reg &= ~INTTSEL_TINTSEL (offset );
616+ writel_relaxed (reg , priv -> base + INTTSEL );
617+ }
618+
619+ static int rzg2l_irqc_shared_irq_alloc (struct rzg2l_irqc_priv * priv , irq_hw_number_t hwirq )
620+ {
621+ unsigned int irq_num ;
622+
623+ if (rzg2l_irqc_is_shared_and_get_irq_num (priv , hwirq , & irq_num )) {
624+ if (test_and_set_bit (irq_num , priv -> used_irqs ))
625+ return - EBUSY ;
626+
627+ if (hwirq < priv -> info .tint_start )
628+ rzg2l_irqc_set_inttsel (priv , INTTSEL_TINTSEL_START + irq_num , 1 );
629+ else
630+ rzg2l_irqc_set_inttsel (priv , INTTSEL_TINTSEL_START + irq_num , 0 );
631+ }
632+
633+ return 0 ;
634+ }
635+
636+ static void rzg2l_irqc_shared_irq_free (struct rzg2l_irqc_priv * priv , irq_hw_number_t hwirq )
637+ {
638+ unsigned int irq_num ;
639+
640+ if (rzg2l_irqc_is_shared_and_get_irq_num (priv , hwirq , & irq_num ) &&
641+ test_and_clear_bit (irq_num , priv -> used_irqs ))
642+ rzg2l_irqc_set_inttsel (priv , INTTSEL_TINTSEL_START + irq_num , 0 );
643+ }
644+
563645static int rzg2l_irqc_alloc (struct irq_domain * domain , unsigned int virq ,
564646 unsigned int nr_irqs , void * arg )
565647{
@@ -592,16 +674,45 @@ static int rzg2l_irqc_alloc(struct irq_domain *domain, unsigned int virq,
592674 if (hwirq >= priv -> info .num_irq )
593675 return - EINVAL ;
594676
677+ if (priv -> info .shared_irq_cnt ) {
678+ ret = rzg2l_irqc_shared_irq_alloc (priv , hwirq );
679+ if (ret )
680+ return ret ;
681+ }
682+
595683 ret = irq_domain_set_hwirq_and_chip (domain , virq , hwirq , chip , (void * )(uintptr_t )tint );
596684 if (ret )
597- return ret ;
685+ goto shared_irq_free ;
686+
687+ ret = irq_domain_alloc_irqs_parent (domain , virq , nr_irqs , & priv -> fwspec [hwirq ]);
688+ if (ret )
689+ goto shared_irq_free ;
690+
691+ return 0 ;
692+
693+ shared_irq_free :
694+ if (priv -> info .shared_irq_cnt )
695+ rzg2l_irqc_shared_irq_free (priv , hwirq );
696+
697+ return ret ;
698+ }
598699
599- return irq_domain_alloc_irqs_parent (domain , virq , nr_irqs , & priv -> fwspec [hwirq ]);
700+ static void rzg2l_irqc_free (struct irq_domain * domain , unsigned int virq , unsigned int nr_irqs )
701+ {
702+ struct rzg2l_irqc_priv * priv = domain -> host_data ;
703+
704+ irq_domain_free_irqs_common (domain , virq , nr_irqs );
705+
706+ if (priv -> info .shared_irq_cnt ) {
707+ struct irq_data * d = irq_domain_get_irq_data (domain , virq );
708+
709+ rzg2l_irqc_shared_irq_free (priv , irqd_to_hwirq (d ));
710+ }
600711}
601712
602713static const struct irq_domain_ops rzg2l_irqc_domain_ops = {
603714 .alloc = rzg2l_irqc_alloc ,
604- .free = irq_domain_free_irqs_common ,
715+ .free = rzg2l_irqc_free ,
605716 .translate = irq_domain_translate_twocell ,
606717};
607718
@@ -716,6 +827,7 @@ static const struct rzg2l_hw_info rzg3l_hw_params = {
716827 .irq_count = 16 ,
717828 .tint_start = IRQC_IRQ_START + 16 ,
718829 .num_irq = IRQC_IRQ_START + 16 + IRQC_TINT_COUNT ,
830+ .shared_irq_cnt = IRQC_SHARED_IRQ_COUNT ,
719831};
720832
721833static const struct rzg2l_hw_info rzg2l_hw_params = {
0 commit comments