66#include "assert.h"
77#include "utils.h"
88
9- u64 aic_base ;
10-
119#define MASK_REG (x ) (4 * ((x) >> 5))
1210#define MASK_BIT (x ) BIT((x)&GENMASK(4, 0))
1311
14- static const struct aic_regs aic1_regs = {
15- .reg_size = AIC_REG_SIZE ,
16- .event = AIC_EVENT ,
17- .tgt_cpu = AIC_TARGET_CPU ,
18- .sw_set = AIC_SW_SET ,
19- .sw_clr = AIC_SW_CLR ,
20- .mask_set = AIC_MASK_SET ,
21- .mask_clr = AIC_MASK_CLR ,
12+ static struct aic aic1 = {
13+ .version = 1 ,
14+ .nr_die = 1 ,
15+ .max_die = 1 ,
16+ .regs =
17+ {
18+ .reg_size = AIC_REG_SIZE ,
19+ .event = AIC_EVENT ,
20+ .tgt_cpu = AIC_TARGET_CPU ,
21+ .sw_set = AIC_SW_SET ,
22+ .sw_clr = AIC_SW_CLR ,
23+ .mask_set = AIC_MASK_SET ,
24+ .mask_clr = AIC_MASK_CLR ,
25+ },
2226};
2327
24- static const struct aic_regs aic2_regs = {
25- .reg_size = AIC2_REG_SIZE ,
26- .event = AIC2_EVENT ,
27- .config = AIC2_IRQ_CFG ,
28- .sw_set = AIC2_SW_SET ,
29- .sw_clr = AIC2_SW_CLR ,
30- .mask_set = AIC2_MASK_SET ,
31- .mask_clr = AIC2_MASK_CLR ,
28+ static struct aic aic2 = {
29+ .version = 2 ,
30+ .regs =
31+ {
32+ .config = AIC2_IRQ_CFG ,
33+ },
3234};
3335
34- const struct aic_regs * aic_regs ;
36+ struct aic * aic ;
3537
36- static void aic2_init (int node )
38+ static int aic2_init (int node )
3739{
40+ int ret = ADT_GETPROP (adt , node , "aic-iack-offset" , & aic -> regs .event );
41+ if (ret < 0 ) {
42+ printf ("AIC: failed to get property aic-iack-offset\n" );
43+ return ret ;
44+ }
45+
46+ u32 info1 = read32 (aic -> base + AIC2_INFO1 );
47+ aic -> nr_die = FIELD_GET (AIC2_INFO1_LAST_DIE , info1 ) + 1 ;
48+ aic -> nr_irq = FIELD_GET (AIC2_INFO1_NR_IRQ , info1 );
49+
50+ u32 info3 = read32 (aic -> base + AIC2_INFO3 );
51+ aic -> max_die = FIELD_GET (AIC2_INFO3_MAX_DIE , info3 );
52+ aic -> max_irq = FIELD_GET (AIC2_INFO3_MAX_IRQ , info3 );
53+
54+ if (aic -> nr_die > AIC_MAX_DIES ) {
55+ printf ("AIC: more dies than supported: %u\n" , aic -> max_die );
56+ return -1 ;
57+ }
58+
59+ if (aic -> max_irq > AIC_MAX_HW_NUM ) {
60+ printf ("AIC: more IRQs than supported: %u\n" , aic -> max_irq );
61+ return -1 ;
62+ }
63+
64+ const u64 start_off = aic -> regs .config ;
65+ u64 off = start_off + sizeof (u32 ) * aic -> max_irq ; /* IRQ_CFG */
66+
67+ aic -> regs .sw_set = off ;
68+ off += sizeof (u32 ) * (aic -> max_irq >> 5 ); /* SW_SET */
69+ aic -> regs .sw_clr = off ;
70+ off += sizeof (u32 ) * (aic -> max_irq >> 5 ); /* SW_CLR */
71+ aic -> regs .mask_set = off ;
72+ off += sizeof (u32 ) * (aic -> max_irq >> 5 ); /* MASK_SET */
73+ aic -> regs .mask_clr = off ;
74+ off += sizeof (u32 ) * (aic -> max_irq >> 5 ); /* MASK_CLR */
75+ off += sizeof (u32 ) * (aic -> max_irq >> 5 ); /* HW_STATE */
76+
77+ aic -> die_stride = off - start_off ;
78+ aic -> regs .reg_size = aic -> regs .event + 4 ;
79+
80+ printf ("AIC: AIC2 with %u/%u dies, %u/%u IRQs, reg_size:%05lx die_stride:%05x\n" , aic -> nr_die ,
81+ aic -> max_die , aic -> nr_irq , aic -> max_irq , aic -> regs .reg_size , aic -> die_stride );
82+
3883 u32 ext_intr_config_len ;
3984 const u8 * ext_intr_config = adt_getprop (adt , node , "aic-ext-intr-cfg" , & ext_intr_config_len );
4085
4186 if (ext_intr_config ) {
4287 printf ("AIC: Configuring %d external interrupts\n" , ext_intr_config_len / 3 );
4388 for (u32 i = 0 ; i < ext_intr_config_len ; i += 3 ) {
44- u16 irq = ext_intr_config [i ] | (ext_intr_config [i + 1 ] << 8 );
89+ u8 die = ext_intr_config [i + 1 ] >> 4 ;
90+ u16 irq = ext_intr_config [i ] | ((ext_intr_config [i + 1 ] & 0xf ) << 8 );
4591 u8 target = ext_intr_config [i + 2 ];
46- assert (irq < 0x1000 ); // Will probably need updating for multi-die
47- mask32 (aic_base + aic_regs -> config + 4 * irq , AIC2_IRQ_CFG_TARGET ,
48- FIELD_PREP (AIC2_IRQ_CFG_TARGET , target ));
92+ assert (die < aic -> nr_die );
93+ assert (irq < aic -> nr_irq );
94+ mask32 (aic -> base + aic -> regs .config + die * aic -> die_stride + 4 * irq ,
95+ AIC2_IRQ_CFG_TARGET , FIELD_PREP (AIC2_IRQ_CFG_TARGET , target ));
4996 }
5097 }
51- return ;
98+
99+ return 0 ;
52100}
53101
54102void aic_init (void )
@@ -61,32 +109,45 @@ void aic_init(void)
61109 return ;
62110 }
63111
64- if (adt_get_reg (adt , path , "reg" , 0 , & aic_base , NULL )) {
112+ if (adt_is_compatible (adt , node , "aic,1" )) {
113+ aic = & aic1 ;
114+ } else if (adt_is_compatible (adt , node , "aic,2" )) {
115+ aic = & aic2 ;
116+ } else {
117+ printf ("AIC: Error: Unsupported version\n" );
118+ return ;
119+ }
120+
121+ if (adt_get_reg (adt , path , "reg" , 0 , & aic -> base , NULL )) {
65122 printf ("Failed to get AIC reg property!\n" );
66123 return ;
67124 }
68125
69- if (adt_is_compatible ( adt , node , "aic,1" ) ) {
70- printf ("AIC: Version 1 @ 0x%lx\n" , aic_base );
71- aic_regs = & aic1_regs ;
72- } else if ( adt_is_compatible ( adt , node , " aic,2" )) {
73- printf ( "AIC: Version 2 @ 0x%lx\n" , aic_base );
74- aic_regs = & aic2_regs ;
75- aic2_init (node );
76- } else {
77- printf ( "AIC: Error: Unsupported version @ 0x%lx\n" , aic_base ) ;
126+ if (aic -> version == 1 ) {
127+ printf ("AIC: Version 1 @ 0x%lx\n" , aic -> base );
128+ aic -> nr_irq = FIELD_GET ( AIC_INFO_NR_HW , read32 ( aic -> base + AIC_INFO )) ;
129+ aic -> max_irq = AIC1_MAX_IRQ ;
130+ } else if ( aic -> version == 2 ) {
131+ printf ( "AIC: Version 2 @ 0x%lx\n" , aic -> base ) ;
132+ int ret = aic2_init (node );
133+ if ( ret < 0 )
134+ aic = NULL ;
78135 }
79136}
80137
81138void aic_set_sw (int irq , bool active )
82139{
140+ u32 die = irq / aic -> max_irq ;
141+ irq = irq % aic -> max_irq ;
83142 if (active )
84- write32 (aic_base + aic_regs -> sw_set + MASK_REG (irq ), MASK_BIT (irq ));
143+ write32 (aic -> base + aic -> regs .sw_set + die * aic -> die_stride + MASK_REG (irq ),
144+ MASK_BIT (irq ));
85145 else
86- write32 (aic_base + aic_regs -> sw_clr + MASK_REG (irq ), MASK_BIT (irq ));
146+ write32 (aic -> base + aic -> regs .sw_clr + die * aic -> die_stride + MASK_REG (irq ),
147+ MASK_BIT (irq ));
87148}
88149
89150uint32_t aic_ack (void )
90151{
91- return read32 (aic_base + aic_regs -> event );
152+ return read32 (aic -> base + aic -> regs . event );
92153}
0 commit comments