@@ -453,14 +453,16 @@ void VoodooGPIO::intel_pinctrl_pm_init() {
453
453
for (int i = 0 ; i < ncommunities; i++) {
454
454
intel_community *community = &communities[i];
455
455
456
- context.communities [i].intmask = IONew (UInt32 , community->ngpps );;
456
+ context.communities [i].intmask = IONew (UInt32 , community->ngpps );
457
+ context.communities [i].hostown = IONew (UInt32 , community->ngpps );
457
458
}
458
459
}
459
460
460
461
void VoodooGPIO::intel_pinctrl_pm_release () {
461
462
for (int i = 0 ; i < ncommunities; i++) {
462
463
intel_community *community = &communities[i];
463
464
IOSafeDeleteNULL (context.communities [i].intmask , UInt32 , community->ngpps );
465
+ IOSafeDeleteNULL (context.communities [i].hostown , UInt32 , community->ngpps );
464
466
}
465
467
466
468
IOSafeDeleteNULL (context.communities , intel_community_context, ncommunities);
@@ -500,11 +502,15 @@ void VoodooGPIO::intel_pinctrl_suspend() {
500
502
struct intel_community_context *communityContexts = context.communities ;
501
503
for (int i = 0 ; i < ncommunities; i++) {
502
504
struct intel_community *community = &communities[i];
503
-
504
- IOVirtualAddress base = community-> regs + community-> ie_offset ;
505
-
506
- for (unsigned gpp = 0 ; gpp < community->ngpps ; gpp++)
505
+ IOVirtualAddress base = 0 ;
506
+
507
+ base = community-> regs + community-> ie_offset ;
508
+ for (unsigned int gpp = 0 ; gpp < community->ngpps ; gpp++)
507
509
communityContexts[i].intmask [gpp] = readl (base + gpp * 4 );
510
+
511
+ base = community->regs + community->hostown_offset ;
512
+ for (unsigned int gpp = 0 ; gpp < community->ngpps ; gpp++)
513
+ communityContexts[i].hostown [gpp] = readl (base + gpp * 4 );
508
514
}
509
515
}
510
516
@@ -521,6 +527,37 @@ void VoodooGPIO::intel_gpio_irq_init() {
521
527
}
522
528
}
523
529
530
+ UInt32 VoodooGPIO::intel_gpio_is_requested (int base, unsigned int size) {
531
+ UInt32 requested = 0 ;
532
+
533
+ for (unsigned int pin_offset = 0 ; pin_offset < size; pin_offset++) {
534
+ UInt32 gpio_pin = base + pin_offset;
535
+ SInt32 hw_pin = intel_gpio_to_pin (gpio_pin, nullptr , nullptr );
536
+ if (hw_pin < 0 )
537
+ continue ;
538
+
539
+ for (unsigned int registered_idx = 0 ; registered_idx < registered_pin_list->getCount (); registered_idx++) {
540
+ OSNumber* registered_pin = OSDynamicCast (OSNumber, registered_pin_list->getObject (registered_idx));
541
+ if (registered_pin && registered_pin->unsigned32BitValue () == hw_pin) {
542
+ requested |= BIT (pin_offset);
543
+ break ;
544
+ }
545
+ }
546
+ }
547
+
548
+ return requested;
549
+ }
550
+
551
+ UInt32 VoodooGPIO::intel_gpio_update_pad_mode (IOVirtualAddress hostown, UInt32 mask, UInt32 value) {
552
+ UInt32 curr, updated;
553
+
554
+ curr = readl (hostown);
555
+ updated = (curr & ~mask) | (value & mask);
556
+ writel (updated, hostown);
557
+
558
+ return curr;
559
+ }
560
+
524
561
void VoodooGPIO::intel_pinctrl_resume () {
525
562
/* Mask all interrupts */
526
563
intel_gpio_irq_init ();
@@ -563,12 +600,28 @@ void VoodooGPIO::intel_pinctrl_resume() {
563
600
struct intel_community_context *communityContexts = context.communities ;
564
601
for (int i = 0 ; i < ncommunities; i++) {
565
602
struct intel_community *community = &communities[i];
603
+ IOVirtualAddress base = 0 ;
566
604
567
- IOVirtualAddress base = communities->regs + communities->ie_offset ;
568
-
569
- for (unsigned gpp = 0 ; gpp < community->ngpps ; gpp++) {
605
+ base = communities->regs + communities->ie_offset ;
606
+ for (unsigned int gpp = 0 ; gpp < community->ngpps ; gpp++) {
570
607
writel (communityContexts[i].intmask [gpp], base + gpp * 4 );
571
608
}
609
+
610
+ base = community->regs + community->hostown_offset ;
611
+ for (unsigned int gpp = 0 ; gpp < community->ngpps ; gpp++) {
612
+ const struct intel_padgroup *padgrp = &community->gpps [gpp];
613
+ UInt32 requested = 0 , value = 0 ;
614
+ UInt32 saved = communityContexts[i].hostown [gpp];
615
+
616
+ if (padgrp->gpio_base < 0 )
617
+ continue ;
618
+
619
+ requested = intel_gpio_is_requested (padgrp->gpio_base , padgrp->size );
620
+ value = intel_gpio_update_pad_mode (base + gpp * 4 , requested, saved);
621
+ if ((value ^ saved) & requested) {
622
+ IOLog (" %s::restore hostown %d/%u %#8x->%#8x\n " , getName (), i, gpp, value, saved);
623
+ }
624
+ }
572
625
}
573
626
}
574
627
@@ -746,37 +799,19 @@ void VoodooGPIO::stop(IOService *provider) {
746
799
}
747
800
748
801
IOReturn VoodooGPIO::setPowerState (unsigned long powerState, IOService *whatDevice) {
802
+ if (whatDevice != this )
803
+ return kIOPMAckImplied ;
804
+
749
805
if (powerState == 0 ) {
750
806
controllerIsAwake = false ;
751
807
752
- for (int i = 0 ; i < ncommunities; i++) {
753
- struct intel_community *community = &communities[i];
754
- for (int j = 0 ; j < community->npins ; j++) {
755
- OSObject *pinInterruptOwner = community->pinInterruptActionOwners [j];
756
- if (pinInterruptOwner) {
757
- int pin = community->pin_base + j;
758
- intel_gpio_irq_mask_unmask (pin, true );
759
- }
760
- }
761
- }
762
-
808
+ intel_pinctrl_suspend ();
763
809
IOLog (" %s::Going to Sleep!\n " , getName ());
764
810
} else {
765
811
if (!controllerIsAwake) {
766
812
controllerIsAwake = true ;
767
813
768
- for (int i = 0 ; i < ncommunities; i++) {
769
- struct intel_community *community = &communities[i];
770
- for (int j = 0 ; j < community->npins ; j++) {
771
- OSObject *pinInterruptOwner = community->pinInterruptActionOwners [j];
772
- if (pinInterruptOwner) {
773
- int pin = community->pin_base + j;
774
- intel_gpio_irq_set_type (pin, community->interruptTypes [j]);
775
- intel_gpio_irq_mask_unmask (pin, false );
776
- }
777
- }
778
- }
779
-
814
+ intel_pinctrl_resume ();
780
815
IOLog (" %s::Woke up from Sleep!\n " , getName ());
781
816
} else {
782
817
IOLog (" %s::GPIO Controller is already awake! Not reinitializing.\n " , getName ());
@@ -931,6 +966,8 @@ IOReturn VoodooGPIO::unregisterInterrupt(int pin) {
931
966
if (hw_pin < 0 )
932
967
return kIOReturnNoInterrupt ;
933
968
969
+ IOLog (" %s::Unregistering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n " , getName (), hw_pin, pin);
970
+
934
971
intel_gpio_irq_mask_unmask (hw_pin, true );
935
972
936
973
unsigned communityidx = hw_pin - community->pin_base ;
0 commit comments