3333#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248)
3434#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C)
3535#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300)
36- #define EXYNOS4_MCT_L_BASE (x ) (_EXYNOS4_MCT_L_BASE + (0x100 * x ))
36+ #define EXYNOS4_MCT_L_BASE (x ) (_EXYNOS4_MCT_L_BASE + (0x100 * (x) ))
3737#define EXYNOS4_MCT_L_MASK (0xffffff00)
3838
3939#define MCT_L_TCNTB_OFFSET (0x00)
6666#define MCT_L0_IRQ 4
6767/* Max number of IRQ as per DT binding document */
6868#define MCT_NR_IRQS 20
69+ /* Max number of local timers */
70+ #define MCT_NR_LOCAL (MCT_NR_IRQS - MCT_L0_IRQ)
6971
7072enum {
7173 MCT_INT_SPI ,
@@ -233,9 +235,16 @@ static cycles_t exynos4_read_current_timer(void)
233235}
234236#endif
235237
236- static int __init exynos4_clocksource_init (void )
238+ static int __init exynos4_clocksource_init (bool frc_shared )
237239{
238- exynos4_mct_frc_start ();
240+ /*
241+ * When the frc is shared, the main processer should have already
242+ * turned it on and we shouldn't be writing to TCON.
243+ */
244+ if (frc_shared )
245+ mct_frc .resume = NULL ;
246+ else
247+ exynos4_mct_frc_start ();
239248
240249#if defined(CONFIG_ARM )
241250 exynos4_delay_timer .read_current_timer = & exynos4_read_current_timer ;
@@ -449,7 +458,6 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
449458 per_cpu_ptr (& percpu_mct_tick , cpu );
450459 struct clock_event_device * evt = & mevt -> evt ;
451460
452- mevt -> base = EXYNOS4_MCT_L_BASE (cpu );
453461 snprintf (mevt -> name , sizeof (mevt -> name ), "mct_tick%d" , cpu );
454462
455463 evt -> name = mevt -> name ;
@@ -520,8 +528,17 @@ static int __init exynos4_timer_resources(struct device_node *np)
520528 return 0 ;
521529}
522530
531+ /**
532+ * exynos4_timer_interrupts - initialize MCT interrupts
533+ * @np: device node for MCT
534+ * @int_type: interrupt type, MCT_INT_PPI or MCT_INT_SPI
535+ * @local_idx: array mapping CPU numbers to local timer indices
536+ * @nr_local: size of @local_idx array
537+ */
523538static int __init exynos4_timer_interrupts (struct device_node * np ,
524- unsigned int int_type )
539+ unsigned int int_type ,
540+ const u32 * local_idx ,
541+ size_t nr_local )
525542{
526543 int nr_irqs , i , err , cpu ;
527544
@@ -554,13 +571,21 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
554571 } else {
555572 for_each_possible_cpu (cpu ) {
556573 int mct_irq ;
574+ unsigned int irq_idx ;
557575 struct mct_clock_event_device * pcpu_mevt =
558576 per_cpu_ptr (& percpu_mct_tick , cpu );
559577
578+ if (cpu >= nr_local ) {
579+ err = - EINVAL ;
580+ goto out_irq ;
581+ }
582+
583+ irq_idx = MCT_L0_IRQ + local_idx [cpu ];
584+
560585 pcpu_mevt -> evt .irq = -1 ;
561- if (MCT_L0_IRQ + cpu >= ARRAY_SIZE (mct_irqs ))
586+ if (irq_idx >= ARRAY_SIZE (mct_irqs ))
562587 break ;
563- mct_irq = mct_irqs [MCT_L0_IRQ + cpu ];
588+ mct_irq = mct_irqs [irq_idx ];
564589
565590 irq_set_status_flags (mct_irq , IRQ_NOAUTOEN );
566591 if (request_irq (mct_irq ,
@@ -576,6 +601,17 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
576601 }
577602 }
578603
604+ for_each_possible_cpu (cpu ) {
605+ struct mct_clock_event_device * mevt = per_cpu_ptr (& percpu_mct_tick , cpu );
606+
607+ if (cpu >= nr_local ) {
608+ err = - EINVAL ;
609+ goto out_irq ;
610+ }
611+
612+ mevt -> base = EXYNOS4_MCT_L_BASE (local_idx [cpu ]);
613+ }
614+
579615 /* Install hotplug callbacks which configure the timer on this CPU */
580616 err = cpuhp_setup_state (CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING ,
581617 "clockevents/exynos4/mct_timer:starting" ,
@@ -605,20 +641,49 @@ static int __init exynos4_timer_interrupts(struct device_node *np,
605641
606642static int __init mct_init_dt (struct device_node * np , unsigned int int_type )
607643{
644+ bool frc_shared = of_property_read_bool (np , "samsung,frc-shared" );
645+ u32 local_idx [MCT_NR_LOCAL ] = {0 };
646+ int nr_local ;
608647 int ret ;
609648
649+ nr_local = of_property_count_u32_elems (np , "samsung,local-timers" );
650+ if (nr_local == 0 )
651+ return - EINVAL ;
652+ if (nr_local > 0 ) {
653+ if (nr_local > ARRAY_SIZE (local_idx ))
654+ return - EINVAL ;
655+
656+ ret = of_property_read_u32_array (np , "samsung,local-timers" ,
657+ local_idx , nr_local );
658+ if (ret )
659+ return ret ;
660+ } else {
661+ int i ;
662+
663+ nr_local = ARRAY_SIZE (local_idx );
664+ for (i = 0 ; i < nr_local ; i ++ )
665+ local_idx [i ] = i ;
666+ }
667+
610668 ret = exynos4_timer_resources (np );
611669 if (ret )
612670 return ret ;
613671
614- ret = exynos4_timer_interrupts (np , int_type );
672+ ret = exynos4_timer_interrupts (np , int_type , local_idx , nr_local );
615673 if (ret )
616674 return ret ;
617675
618- ret = exynos4_clocksource_init ();
676+ ret = exynos4_clocksource_init (frc_shared );
619677 if (ret )
620678 return ret ;
621679
680+ /*
681+ * When the FRC is shared with a main processor, this secondary
682+ * processor cannot use the global comparator.
683+ */
684+ if (frc_shared )
685+ return ret ;
686+
622687 return exynos4_clockevent_init ();
623688}
624689
0 commit comments