From e0ca3d2e08462ff940b97eaef3271c69d8da6db3 Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> Date: Sun, 25 Jun 2023 17:30:21 +0300 Subject: [PATCH] Add AMD support (#13) * Move Intel GPIO code to separate class Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * VoodooGPIO.h cleanup Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Move common fields to VoodooGPIO, fix inheritance bug Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * setInterruptTypeForPin should be virtual function Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Remote unused interruptOccurredGated function Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Move pinctrl_pin_desc to VoodooGPIO class Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add AMD GPIO pin definitions Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add VoodooGPIOAMD personality Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add VoodooGPIOAMD::start Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add VoodooGPIOAMD::stop Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add VoodooGPIOAMD logic Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Remove 2 unnecessary includes Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Add some missing logic Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Fix identation Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Remove bad logic in irq_set_types Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Cleanup Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Remove get_direction, direction_{input,output}, {get,set}_value Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * Use IONewZero instead of IONew Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> * do_amd_gpio_irq_handler should only be called once Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> * amd_gpio_irq_enable should be called before amd_gpio_irq_set_type Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> * Fix interrupt handler Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> * Move debounce logic to amd_gpio_irq_enable Closes #1 Co-authored-by: Huy Duong Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> --------- Signed-off-by: Visual <30368284+ChefKissInc@users.noreply.github.com> Signed-off-by: Visual Ehrmanntraut <30368284+ChefKissInc@users.noreply.github.com> Co-authored-by: Huy Duong --- VoodooGPIO.xcodeproj/project.pbxproj | 28 +- .../CannonLake-H/VoodooGPIOCannonLakeH.cpp | 4 +- .../CannonLake-H/VoodooGPIOCannonLakeH.hpp | 5 +- .../CannonLake-LP/VoodooGPIOCannonLakeLP.cpp | 4 +- .../CannonLake-LP/VoodooGPIOCannonLakeLP.hpp | 5 +- VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.cpp | 4 +- VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.hpp | 5 +- VoodooGPIO/Info.plist | 55 +- .../TigerLake-LP/VoodooGPIOTigerLakeLP.cpp | 2 +- .../TigerLake-LP/VoodooGPIOTigerLakeLP.hpp | 4 +- VoodooGPIO/VoodooGPIO.cpp | 1035 +--------- VoodooGPIO/VoodooGPIO.hpp | 246 +-- VoodooGPIO/VoodooGPIOAMD.cpp | 487 +++++ VoodooGPIO/VoodooGPIOAMD.hpp | 1674 +++++++++++++++++ VoodooGPIO/VoodooGPIOIntel.cpp | 1001 ++++++++++ VoodooGPIO/VoodooGPIOIntel.hpp | 229 +++ VoodooGPIO/VoodooGPIOSunrisePointH.cpp | 4 +- VoodooGPIO/VoodooGPIOSunrisePointH.hpp | 5 +- VoodooGPIO/VoodooGPIOSunrisePointLP.cpp | 4 +- VoodooGPIO/VoodooGPIOSunrisePointLP.hpp | 5 +- 20 files changed, 3505 insertions(+), 1301 deletions(-) create mode 100644 VoodooGPIO/VoodooGPIOAMD.cpp create mode 100644 VoodooGPIO/VoodooGPIOAMD.hpp create mode 100644 VoodooGPIO/VoodooGPIOIntel.cpp create mode 100644 VoodooGPIO/VoodooGPIOIntel.hpp diff --git a/VoodooGPIO.xcodeproj/project.pbxproj b/VoodooGPIO.xcodeproj/project.pbxproj index 0ee08fa..53b4788 100644 --- a/VoodooGPIO.xcodeproj/project.pbxproj +++ b/VoodooGPIO.xcodeproj/project.pbxproj @@ -8,6 +8,10 @@ /* Begin PBXBuildFile section */ 0FC03704258E6F890026BA14 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0FC03703258E6F890026BA14 /* libkmod.a */; }; + 406D56CB29B5050400427C54 /* VoodooGPIOIntel.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 406D56CA29B5050400427C54 /* VoodooGPIOIntel.hpp */; }; + 40AAD2D429B657EC001C60CD /* VoodooGPIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40AAD2D329B657EC001C60CD /* VoodooGPIO.cpp */; }; + 40AFB77629B6207E00223D0C /* VoodooGPIOAMD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 40AFB77429B6207E00223D0C /* VoodooGPIOAMD.cpp */; }; + 40AFB77729B6207E00223D0C /* VoodooGPIOAMD.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 40AFB77529B6207E00223D0C /* VoodooGPIOAMD.hpp */; }; ACD8275D219D034F0041DE1B /* VoodooGPIOCannonLakeLP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ACD8275B219D034F0041DE1B /* VoodooGPIOCannonLakeLP.cpp */; }; ACD8275E219D034F0041DE1B /* VoodooGPIOCannonLakeLP.hpp in Headers */ = {isa = PBXBuildFile; fileRef = ACD8275C219D034F0041DE1B /* VoodooGPIOCannonLakeLP.hpp */; }; ACD82762219D06C20041DE1B /* VoodooGPIOCannonLakeH.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ACD82760219D06C20041DE1B /* VoodooGPIOCannonLakeH.cpp */; }; @@ -17,13 +21,17 @@ F142D11B1F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F142D1191F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.cpp */; }; F142D11C1F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F142D11A1F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.hpp */; }; F1F172C91F42263A00AD98FA /* VoodooGPIO.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F1F172C81F42263A00AD98FA /* VoodooGPIO.hpp */; }; - F1F172CB1F42263A00AD98FA /* VoodooGPIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1F172CA1F42263A00AD98FA /* VoodooGPIO.cpp */; }; + F1F172CB1F42263A00AD98FA /* VoodooGPIOIntel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1F172CA1F42263A00AD98FA /* VoodooGPIOIntel.cpp */; }; FBE40CF824E2373400CDC4ED /* VoodooGPIOIceLakeLP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FBE40CF624E2373400CDC4ED /* VoodooGPIOIceLakeLP.cpp */; }; FBE40CF924E2373400CDC4ED /* VoodooGPIOIceLakeLP.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FBE40CF724E2373400CDC4ED /* VoodooGPIOIceLakeLP.hpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 0FC03703258E6F890026BA14 /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = ../../MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; + 406D56CA29B5050400427C54 /* VoodooGPIOIntel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooGPIOIntel.hpp; sourceTree = ""; }; + 40AAD2D329B657EC001C60CD /* VoodooGPIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIO.cpp; sourceTree = ""; }; + 40AFB77429B6207E00223D0C /* VoodooGPIOAMD.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIOAMD.cpp; sourceTree = ""; }; + 40AFB77529B6207E00223D0C /* VoodooGPIOAMD.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooGPIOAMD.hpp; sourceTree = ""; }; ACD8275B219D034F0041DE1B /* VoodooGPIOCannonLakeLP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIOCannonLakeLP.cpp; sourceTree = ""; }; ACD8275C219D034F0041DE1B /* VoodooGPIOCannonLakeLP.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooGPIOCannonLakeLP.hpp; sourceTree = ""; }; ACD82760219D06C20041DE1B /* VoodooGPIOCannonLakeH.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIOCannonLakeH.cpp; sourceTree = ""; }; @@ -35,7 +43,7 @@ F17C4C481F42AC33009DB44C /* linuxirq.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = linuxirq.h; sourceTree = ""; }; F1F172C51F42263A00AD98FA /* VoodooGPIO.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoodooGPIO.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F1F172C81F42263A00AD98FA /* VoodooGPIO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooGPIO.hpp; sourceTree = ""; }; - F1F172CA1F42263A00AD98FA /* VoodooGPIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIO.cpp; sourceTree = ""; }; + F1F172CA1F42263A00AD98FA /* VoodooGPIOIntel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIOIntel.cpp; sourceTree = ""; }; F1F172CC1F42263A00AD98FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; FBE40CF624E2373400CDC4ED /* VoodooGPIOIceLakeLP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VoodooGPIOIceLakeLP.cpp; sourceTree = ""; }; FBE40CF724E2373400CDC4ED /* VoodooGPIOIceLakeLP.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VoodooGPIOIceLakeLP.hpp; sourceTree = ""; }; @@ -117,13 +125,17 @@ F1F172C71F42263A00AD98FA /* VoodooGPIO */ = { isa = PBXGroup; children = ( - FBE40CF524E2366B00CDC4ED /* IceLake-LP */, ACD8275F219D06AF0041DE1B /* CannonLake-H */, ACD8275A219D03290041DE1B /* CannonLake-LP */, - F142D1181F42C244007AA5C6 /* SunrisePoint-LP */, + FBE40CF524E2366B00CDC4ED /* IceLake-LP */, F10447AB1F4278AB00BA5A85 /* SunrisePoint-H */, + F142D1181F42C244007AA5C6 /* SunrisePoint-LP */, + 40AAD2D329B657EC001C60CD /* VoodooGPIO.cpp */, F1F172C81F42263A00AD98FA /* VoodooGPIO.hpp */, - F1F172CA1F42263A00AD98FA /* VoodooGPIO.cpp */, + F1F172CA1F42263A00AD98FA /* VoodooGPIOIntel.cpp */, + 406D56CA29B5050400427C54 /* VoodooGPIOIntel.hpp */, + 40AFB77429B6207E00223D0C /* VoodooGPIOAMD.cpp */, + 40AFB77529B6207E00223D0C /* VoodooGPIOAMD.hpp */, F1F172CC1F42263A00AD98FA /* Info.plist */, F17C4C481F42AC33009DB44C /* linuxirq.h */, ); @@ -148,9 +160,11 @@ files = ( FBE40CF924E2373400CDC4ED /* VoodooGPIOIceLakeLP.hpp in Headers */, F1F172C91F42263A00AD98FA /* VoodooGPIO.hpp in Headers */, + 406D56CB29B5050400427C54 /* VoodooGPIOIntel.hpp in Headers */, F10447AF1F4278CD00BA5A85 /* VoodooGPIOSunrisePointH.hpp in Headers */, F142D11C1F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.hpp in Headers */, ACD82763219D06C20041DE1B /* VoodooGPIOCannonLakeH.hpp in Headers */, + 40AFB77729B6207E00223D0C /* VoodooGPIOAMD.hpp in Headers */, ACD8275E219D034F0041DE1B /* VoodooGPIOCannonLakeLP.hpp in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -227,9 +241,11 @@ F10447AE1F4278CD00BA5A85 /* VoodooGPIOSunrisePointH.cpp in Sources */, F142D11B1F42C255007AA5C6 /* VoodooGPIOSunrisePointLP.cpp in Sources */, ACD8275D219D034F0041DE1B /* VoodooGPIOCannonLakeLP.cpp in Sources */, + 40AFB77629B6207E00223D0C /* VoodooGPIOAMD.cpp in Sources */, + 40AAD2D429B657EC001C60CD /* VoodooGPIO.cpp in Sources */, FBE40CF824E2373400CDC4ED /* VoodooGPIOIceLakeLP.cpp in Sources */, ACD82762219D06C20041DE1B /* VoodooGPIOCannonLakeH.cpp in Sources */, - F1F172CB1F42263A00AD98FA /* VoodooGPIO.cpp in Sources */, + F1F172CB1F42263A00AD98FA /* VoodooGPIOIntel.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.cpp b/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.cpp index 9bde759..af56b48 100644 --- a/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.cpp +++ b/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOCannonLakeH.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOCannonLakeH, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOCannonLakeH, VoodooGPIOIntel); bool VoodooGPIOCannonLakeH::start(IOService *provider) { this->pins = cnlh_pins; @@ -22,5 +22,5 @@ bool VoodooGPIOCannonLakeH::start(IOService *provider) { IOLog("%s::Loading GPIO Data for CannonLake-H\n", getName()); - return VoodooGPIO::start(provider); + return VoodooGPIOIntel::start(provider); } diff --git a/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.hpp b/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.hpp index 0a7f96e..0850f5a 100644 --- a/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.hpp +++ b/VoodooGPIO/CannonLake-H/VoodooGPIOCannonLakeH.hpp @@ -6,10 +6,9 @@ // Copyright © 2018 Alexandre Daoud. All rights reserved. // -#include "../VoodooGPIO.hpp" - #ifndef VoodooGPIOCannonLakeH_h #define VoodooGPIOCannonLakeH_h +#include "../VoodooGPIOIntel.hpp" #define CNL_PAD_OWN 0x020 #define CNL_PADCFGLOCK 0x080 @@ -447,7 +446,7 @@ static struct intel_community cnlh_communities[] = { CNLH_COMMUNITY(3, 249, 298, cnlh_community4_gpps), }; -class VoodooGPIOCannonLakeH : public VoodooGPIO { +class VoodooGPIOCannonLakeH : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOCannonLakeH); bool start(IOService *provider) override; diff --git a/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.cpp b/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.cpp index e698df7..8d42ac5 100644 --- a/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.cpp +++ b/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOCannonLakeLP.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOCannonLakeLP, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOCannonLakeLP, VoodooGPIOIntel); bool VoodooGPIOCannonLakeLP::start(IOService *provider) { this->pins = cnllp_pins; @@ -22,5 +22,5 @@ bool VoodooGPIOCannonLakeLP::start(IOService *provider) { IOLog("%s::Loading GPIO Data for CannonLake-LP\n", getName()); - return VoodooGPIO::start(provider); + return VoodooGPIOIntel::start(provider); } diff --git a/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.hpp b/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.hpp index e235dbd..a51497a 100644 --- a/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.hpp +++ b/VoodooGPIO/CannonLake-LP/VoodooGPIOCannonLakeLP.hpp @@ -6,10 +6,9 @@ // Copyright © 2018 Alexandre Daoud. All rights reserved. // -#include "../VoodooGPIO.hpp" - #ifndef VoodooGPIOCannonLakeLP_h #define VoodooGPIOCannonLakeLP_h +#include "../VoodooGPIOIntel.hpp" #define CNL_PAD_OWN 0x020 #define CNL_PADCFGLOCK 0x080 @@ -391,7 +390,7 @@ static struct intel_community cnllp_communities[] = { CNLLP_COMMUNITY(2, 181, 243, cnllp_community4_gpps), }; -class VoodooGPIOCannonLakeLP : public VoodooGPIO { +class VoodooGPIOCannonLakeLP : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOCannonLakeLP); bool start(IOService *provider) override; diff --git a/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.cpp b/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.cpp index 0128165..72c1b0a 100644 --- a/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.cpp +++ b/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOIceLakeLP.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOIceLakeLP, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOIceLakeLP, VoodooGPIOIntel); bool VoodooGPIOIceLakeLP::start(IOService *provider) { this->pins = icllp_pins; @@ -22,5 +22,5 @@ bool VoodooGPIOIceLakeLP::start(IOService *provider) { IOLog("%s::Loading GPIO Data for IceLake-LP\n", getName()); - return VoodooGPIO::start(provider); + return VoodooGPIOIntel::start(provider); } diff --git a/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.hpp b/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.hpp index 55d9857..7d03131 100644 --- a/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.hpp +++ b/VoodooGPIO/IceLake-LP/VoodooGPIOIceLakeLP.hpp @@ -6,10 +6,9 @@ // Copyright © 2018 Alexandre Daoud. All rights reserved. // -#include "../VoodooGPIO.hpp" - #ifndef VoodooGPIOIceLakeLP_h #define VoodooGPIOIceLakeLP_h +#include "../VoodooGPIOIntel.hpp" #define ICL_PAD_OWN 0x020 #define ICL_PADCFGLOCK 0x080 @@ -387,7 +386,7 @@ static struct intel_community icllp_communities[] = { ICL_COMMUNITY(3, 216, 240, icllp_community5_gpps), }; -class VoodooGPIOIceLakeLP : public VoodooGPIO { +class VoodooGPIOIceLakeLP : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOIceLakeLP); bool start(IOService *provider) override; diff --git a/VoodooGPIO/Info.plist b/VoodooGPIO/Info.plist index b2b6f9b..3f8add8 100644 --- a/VoodooGPIO/Info.plist +++ b/VoodooGPIO/Info.plist @@ -18,84 +18,97 @@ 1.1 CFBundleVersion 1.1 - OSBundleCompatibleVersion - 1.1 IOKitPersonalities - VoodooGPIOTigerLakeLP + VoodooGPIOAMD CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOTigerLakeLP + VoodooGPIOAMD IONameMatch - INTC1055 + AMD0030 + AMDI0030 + AMDI0031 IOProviderClass IOService - VoodooGPIOSunrisePointLP + VoodooGPIOCannonLakeH CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOSunrisePointLP + VoodooGPIOCannonLakeH IONameMatch - INT344B + INT3450 IOProviderClass IOService - VoodooGPIOSunrisePointH + VoodooGPIOCannonLakeLP CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOSunrisePointH + VoodooGPIOCannonLakeLP IONameMatch - INT345D + INT34BB IOProviderClass IOService - VoodooGPIOCannonLakeLP + VoodooGPIOIceLakeLP CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOCannonLakeLP + VoodooGPIOIceLakeLP IONameMatch - INT34BB + INT3455 IOProviderClass IOService - VoodooGPIOIceLakeLP + VoodooGPIOSunrisePointH CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOIceLakeLP + VoodooGPIOSunrisePointH IONameMatch - INT3455 + INT345D IOProviderClass IOService - VoodooGPIOCannonLakeH + VoodooGPIOSunrisePointLP CFBundleIdentifier org.coolstar.VoodooGPIO IOClass - VoodooGPIOCannonLakeH + VoodooGPIOSunrisePointLP IONameMatch - INT3450 + INT344B + + IOProviderClass + IOService + + VoodooGPIOTigerLakeLP + + CFBundleIdentifier + org.coolstar.VoodooGPIO + IOClass + VoodooGPIOTigerLakeLP + IONameMatch + + INTC1055 IOProviderClass IOService @@ -103,6 +116,8 @@ NSHumanReadableCopyright Copyright © 2017 CoolStar. All rights reserved. + OSBundleCompatibleVersion + 1.1 OSBundleLibraries com.apple.iokit.IOACPIFamily diff --git a/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.cpp b/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.cpp index d49b70b..5eae359 100644 --- a/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.cpp +++ b/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOTigerLakeLP.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOTigerLakeLP, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOTigerLakeLP, VoodooGPIOIntel); bool VoodooGPIOTigerLakeLP::start(IOService *provider) { this->pins = tgllp_pins; diff --git a/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.hpp b/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.hpp index 1ecf8ba..97dcd8b 100644 --- a/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.hpp +++ b/VoodooGPIO/TigerLake-LP/VoodooGPIOTigerLakeLP.hpp @@ -6,7 +6,7 @@ // Copyright © 2023 CoolStar. All rights reserved. // -#include "../VoodooGPIO.hpp" +#include "../VoodooGPIOIntel.hpp" #ifndef VoodooGPIOTigerLakeLP_hpp #define VoodooGPIOTigerLakeLP_hpp @@ -436,7 +436,7 @@ static struct intel_community tgllp_communities[] = { TGL_LP_COMMUNITY(3, 260, 276, tgllp_community5_gpps), }; -class VoodooGPIOTigerLakeLP : public VoodooGPIO { +class VoodooGPIOTigerLakeLP : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOTigerLakeLP); bool start(IOService *provider) override; diff --git a/VoodooGPIO/VoodooGPIO.cpp b/VoodooGPIO/VoodooGPIO.cpp index 2cf1ef1..766b2df 100644 --- a/VoodooGPIO/VoodooGPIO.cpp +++ b/VoodooGPIO/VoodooGPIO.cpp @@ -2,93 +2,16 @@ // VoodooGPIO.cpp // VoodooGPIO // -// Created by CoolStar on 8/14/17. +// Created by Visual on 6/3/23. // Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. // #include "VoodooGPIO.hpp" OSDefineMetaClassAndStructors(VoodooGPIO, IOService); -#define kIOPMPowerOff 0 - -#if defined(__LP64__) && __LP64__ -#define BITS_PER_LONG 64 -#else -#define BITS_PER_LONG 32 -#endif - -#define BIT(x) 1UL << x -#define GENMASK(h, l) \ -(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) - -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -/* Offset from regs */ -#define REVID 0x000 -#define REVID_SHIFT 16 -#define REVID_MASK GENMASK(31, 16) - -#define PADBAR 0x00c -#define GPI_IS 0x100 - -#define PADOWN_BITS 4 -#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) -#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) -#define PADOWN_GPP(p) ((p) / 8) - -/* Offset from pad_regs */ -#define PADCFG0 0x000 -#define PADCFG0_RXEVCFG_SHIFT 25 -#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) -#define PADCFG0_RXEVCFG_LEVEL 0 -#define PADCFG0_RXEVCFG_EDGE 1 -#define PADCFG0_RXEVCFG_DISABLED 2 -#define PADCFG0_RXEVCFG_EDGE_BOTH 3 -#define PADCFG0_PREGFRXSEL BIT(24) -#define PADCFG0_RXINV BIT(23) -#define PADCFG0_GPIROUTIOXAPIC BIT(20) -#define PADCFG0_GPIROUTSCI BIT(19) -#define PADCFG0_GPIROUTSMI BIT(18) -#define PADCFG0_GPIROUTNMI BIT(17) -#define PADCFG0_PMODE_SHIFT 10 -#define PADCFG0_PMODE_MASK GENMASK(13, 10) -#define PADCFG0_GPIORXDIS BIT(9) -#define PADCFG0_GPIOTXDIS BIT(8) -#define PADCFG0_GPIORXSTATE BIT(1) -#define PADCFG0_GPIOTXSTATE BIT(0) - -#define PADCFG1 0x004 -#define PADCFG1_TERM_UP BIT(13) -#define PADCFG1_TERM_SHIFT 10 -#define PADCFG1_TERM_MASK GENMASK(12, 10) -#define PADCFG1_TERM_20K 4 -#define PADCFG1_TERM_2K 3 -#define PADCFG1_TERM_5K 2 -#define PADCFG1_TERM_1K 1 - -#define PADCFG2 0x008 -#define PADCFG2_DEBEN BIT(0) -#define PADCFG2_DEBOUNCE_SHIFT 1 -#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) - -#define DEBOUNCE_PERIOD 31250 /* ns */ - -#define pin_to_padno(c, p) ((p) - (c)->pin_base) -#define padgroup_offset(g, p) ((p) - (g)->base) - -// Log only if current thread is interruptible, otherwise we will get a panic. -#define TryLog(args...) do { if (ml_get_interrupts_enabled()) IOLog(args); } while (0) - -UInt32 VoodooGPIO::readl(IOVirtualAddress addr) { - return *(const volatile UInt32 *)addr; -} - -void VoodooGPIO::writel(UInt32 b, IOVirtualAddress addr) { - *(volatile UInt32 *)(addr) = b; -} - -IOWorkLoop* VoodooGPIO::getWorkLoop() { +IOWorkLoop *VoodooGPIO::getWorkLoop() { // Do we have a work loop already?, if so return it NOW. if ((vm_address_t) workLoop >> 1) return workLoop; @@ -108,956 +31,6 @@ IOWorkLoop* VoodooGPIO::getWorkLoop() { return workLoop; } -struct intel_community *VoodooGPIO::intel_get_community(unsigned pin) { - struct intel_community *community; - for (int i = 0; i < ncommunities; i++) { - community = &communities[i]; - if (pin >= community->pin_base && pin < community->pin_base + community->npins) - return community; - } - - TryLog("%s::Failed to find community for pin %u", getName(), pin); - return NULL; -} - -struct intel_padgroup *VoodooGPIO::intel_community_get_padgroup(struct intel_community *community, unsigned pin) { - for (int i = 0; i < community->ngpps; i++) { - struct intel_padgroup *padgrp = &community->gpps[i]; - if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) - return padgrp; - } - - TryLog("%s::Failed to find padgroup for pin %u", getName(), pin); - return NULL; -} - -IOVirtualAddress VoodooGPIO::intel_get_padcfg(unsigned pin, unsigned reg) { - struct intel_community *community; - unsigned padno; - size_t nregs; - - community = intel_get_community(pin); - if (!community) - return 0; - - padno = pin_to_padno(community, pin); - nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; - - if (reg >= nregs * 4) - return 0; - - return community->pad_regs + reg + padno * nregs * 4; -} - -bool VoodooGPIO::intel_pad_owned_by_host(unsigned pin) { - struct intel_community *community; - struct intel_padgroup *padgrp; - unsigned gpp, offset, gpp_offset; - IOVirtualAddress padown; - - community = intel_get_community(pin); - if (!community) - return false; - if (!community->padown_offset) - return true; - - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return false; - - gpp_offset = padgroup_offset(padgrp, pin); - gpp = PADOWN_GPP(gpp_offset); - - offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; - padown = community->regs + offset; - - return !(readl(padown) & PADOWN_MASK(gpp_offset)); -} - -bool VoodooGPIO::intel_pad_acpi_mode(unsigned pin) { - struct intel_community *community; - struct intel_padgroup *padgrp; - unsigned offset, gpp_offset; - IOVirtualAddress hostown; - - community = intel_get_community(pin); - if (!community) - return true; - if (!community->hostown_offset) - return false; - - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return true; - - gpp_offset = padgroup_offset(padgrp, pin); - offset = community->hostown_offset + padgrp->reg_num * 4; - hostown = community->regs + offset; - - return !(readl(hostown) & BIT(gpp_offset)); -} - -/** - * enum - Locking variants of the pad configuration. - * - * @PAD_UNLOCKED: Pad is fully controlled by the configuration registers - * @PAD_LOCKED: Pad configuration registers, except TX state, are locked - * @PAD_LOCKED_TX: Pad configuration TX state is locked - * @PAD_LOCKED_FULL: Pad configuration registers are locked completely - * - * Locking is considered as read-only mode for corresponding registers and - * their respective fields. That said, TX state bit is locked separately from - * the main locking scheme. - */ -enum { - PAD_UNLOCKED = 0, - PAD_LOCKED = 1, - PAD_LOCKED_TX = 2, - PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, -}; - -int VoodooGPIO::intel_pad_locked(unsigned int pin) { - struct intel_community *community; - struct intel_padgroup *padgrp; - unsigned offset, gpp_offset; - UInt32 value; - int ret = PAD_UNLOCKED; - - community = intel_get_community(pin); - if (!community) - return PAD_LOCKED_FULL; - if (!community->padcfglock_offset) - return PAD_UNLOCKED; - - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return PAD_LOCKED_FULL; - - gpp_offset = padgroup_offset(padgrp, pin); - - /* - * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, - * the pad is considered unlocked. Any other case means that it is - * either fully or partially locked. - */ - offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; - value = readl(community->regs + offset); - if (value & BIT(gpp_offset)) - ret |= PAD_LOCKED; - - offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; - value = readl(community->regs + offset); - if (value & BIT(gpp_offset)) - ret |= PAD_LOCKED_TX; - - return ret; -} - -bool VoodooGPIO::intel_pad_is_unlocked(unsigned int pin) { - return (intel_pad_locked(pin) & PAD_LOCKED) == PAD_UNLOCKED; -} - -/** - * Translate GPIO offset to hardware pin (They are not always the same). - * Putting appropriate community and padgroup in the variables. - * - * @param offset GPIO pin number. - * @param community Matching community for hardware pin number. - * @param padgrp Matching padgroup for hardware pin number. - * @return Hardware GPIO pin number. -1 if not found. - */ -SInt32 VoodooGPIO::intel_gpio_to_pin(UInt32 offset, - struct intel_community **community, - struct intel_padgroup **padgrp) { - int i; - for (i = 0; i < ncommunities; i++) { - struct intel_community *comm = &communities[i]; - int j; - for (j = 0; j < comm->ngpps; j++) { - struct intel_padgroup *pgrp = &comm->gpps[j]; - if (pgrp->gpio_base < 0) - continue; - - if (offset >= pgrp->gpio_base && - offset < pgrp->gpio_base + pgrp->size) { - int pin; - - pin = pgrp->base + offset - pgrp->gpio_base; - if (community) - *community = comm; - if (padgrp) - *padgrp = pgrp; - return pin; - } - } - } - - TryLog("%s::Failed getting hardware pin for GPIO pin %u", getName(), offset); - return -1; -} - -/** - * @param pin Hardware GPIO pin number to mask. - * @param mask Whether to mask or unmask. - */ -void VoodooGPIO::intel_gpio_irq_mask_unmask(unsigned pin, bool mask) { - struct intel_community *community = intel_get_community(pin); - if (community) { - struct intel_padgroup *padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - - unsigned gpp, gpp_offset; - IOVirtualAddress reg, is; - UInt32 value; - - gpp = padgrp->reg_num; - gpp_offset = padgroup_offset(padgrp, pin); - - reg = community->regs + community->ie_offset + gpp * 4; - is = community->regs + GPI_IS + gpp * 4; - - /* Clear interrupt status first to avoid unexpected interrupt */ - writel(static_cast(BIT(gpp_offset)), is); - - value = readl(reg); - if (mask) - value &= ~BIT(gpp_offset); - else - value |= BIT(gpp_offset); - writel(value, reg); - } -} - -/** - * @param pin Hardware GPIO pin number to set its type. - * @param type Type to set. - */ -bool VoodooGPIO::intel_gpio_irq_set_type(unsigned pin, unsigned type) { - IOVirtualAddress reg; - UInt32 value; - - reg = intel_get_padcfg(pin, PADCFG0); - if (!reg) - return false; - - /* - * If the pin is in ACPI mode it is still usable as a GPIO but it - * cannot be used as IRQ because GPI_IS status bit will not be - * updated by the host controller hardware. - */ - if (intel_pad_acpi_mode(pin)) { - TryLog("%s:: pin %u cannot be used as IRQ\n", getName(), pin); - return false; - } - - value = readl(reg); - - value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); - - if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { - value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; - } else if (type & IRQ_TYPE_EDGE_FALLING) { - value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; - value |= PADCFG0_RXINV; - } else if (type & IRQ_TYPE_EDGE_RISING) { - value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; - } else if (type & IRQ_TYPE_LEVEL_MASK) { - if (type & IRQ_TYPE_LEVEL_LOW) - value |= PADCFG0_RXINV; - } else { - value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; - } - - writel(value, reg); - return true; -} - -bool VoodooGPIO::intel_pinctrl_add_padgroups(intel_community *community) { - struct intel_padgroup *gpps; - unsigned padown_num = 0; - size_t ngpps; - - if (community->gpps) - ngpps = community->ngpps; - else - ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); - - gpps = IONew(intel_padgroup, ngpps); - - for (int i = 0; i < ngpps; i++) { - if (community->gpps) { - gpps[i] = community->gpps[i]; - } else { - unsigned gpp_size = community->gpp_size; - gpps[i].reg_num = i; - gpps[i].base = community->pin_base + i * gpp_size; - gpps[i].size = (UInt32)min(gpp_size, npins); - gpps[i].gpio_base = 0; - npins -= gpps[i].size; - } - - if (gpps[i].size > 32) { - IOLog("%s::Invalid GPP size for pad group %d\n", getName(), i); - return false; - } - - // Set gpio_base to base if not specified - if (!gpps[i].gpio_base) - gpps[i].gpio_base = gpps[i].base; - - gpps[i].padown_num = padown_num; - - /* - * In older hardware the number of padown registers per - * group is fixed regardless of the group size. - */ - if (community->gpp_num_padown_regs) - padown_num += community->gpp_num_padown_regs; - else - padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); - } - community->gpps = gpps; - community->ngpps = ngpps; - community->gpps_alloc = true; - return true; -} - -bool VoodooGPIO::intel_pinctrl_should_save(unsigned pin) { - if (!(intel_pad_owned_by_host(pin) && intel_pad_is_unlocked(pin))) - return false; - - struct intel_community *community = intel_get_community(pin); - - unsigned communityidx = pin - community->pin_base; - - /* - * Only restore the pin if it is actually in use by the kernel (or - * by userspace). It is possible that some pins are used by the - * BIOS during resume and those are not always locked down so leave - * them alone. - */ - if (community->pinInterruptActionOwners[communityidx]) - return true; - - return false; -} - -void VoodooGPIO::intel_pinctrl_pm_init() { - context.pads = IONew(intel_pad_context, npins); - memset(context.pads, 0, npins * sizeof(intel_pad_context)); - - context.communities = IONew(intel_community_context, ncommunities); - memset(context.communities, 0, ncommunities * sizeof(intel_community_context)); - - for (int i = 0; i < ncommunities; i++) { - intel_community *community = &communities[i]; - - context.communities[i].intmask = IONew(UInt32, community->ngpps); - context.communities[i].hostown = IONew(UInt32, community->ngpps); - } -} - -void VoodooGPIO::intel_pinctrl_pm_release() { - for (int i = 0; i < ncommunities; i++) { - intel_community *community = &communities[i]; - IOSafeDeleteNULL(context.communities[i].intmask, UInt32, community->ngpps); - IOSafeDeleteNULL(context.communities[i].hostown, UInt32, community->ngpps); - } - - IOSafeDeleteNULL(context.communities, intel_community_context, ncommunities); - - IOSafeDeleteNULL(context.pads, intel_pad_context, npins); -} - -void VoodooGPIO::intel_pinctrl_suspend() { - struct intel_pad_context *pads = context.pads; - for (int i = 0; i < npins; i++) { - struct pinctrl_pin_desc *desc = &pins[i]; - IOVirtualAddress padcfg; - uint32_t val; - - if (!intel_pinctrl_should_save(desc->number)) - continue; - - padcfg = intel_get_padcfg(desc->number, PADCFG0); - if (!padcfg) - continue; - - val = readl(padcfg); - pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; - - padcfg = intel_get_padcfg(desc->number, PADCFG1); - if (!padcfg) - continue; - - val = readl(padcfg); - pads[i].padcfg1 = val; - - padcfg = intel_get_padcfg(desc->number, PADCFG2); - if (padcfg) - pads[i].padcfg2 = readl(padcfg); - } - - struct intel_community_context *communityContexts = context.communities; - for (int i = 0; i < ncommunities; i++) { - struct intel_community *community = &communities[i]; - IOVirtualAddress base = 0; - - base = community->regs + community->ie_offset; - for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) - communityContexts[i].intmask[gpp] = readl(base + gpp * 4); - - base = community->regs + community->hostown_offset; - for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) - communityContexts[i].hostown[gpp] = readl(base + gpp * 4); - } -} - -void VoodooGPIO::intel_gpio_irq_init() { - for (size_t i = 0; i < ncommunities; i++) { - struct intel_community *community = &communities[i]; - IOVirtualAddress base = community->regs; - - for (unsigned gpp = 0; gpp < community->ngpps; gpp++) { - /* Mask and clear all interrupts */ - writel(0, base + community->ie_offset + gpp * 4); - writel(0xffff, base + GPI_IS + gpp * 4); - } - } -} - -UInt32 VoodooGPIO::intel_gpio_is_requested(int base, unsigned int size) { - UInt32 requested = 0; - - for (unsigned int pin_offset = 0; pin_offset < size; pin_offset++) { - UInt32 gpio_pin = base + pin_offset; - SInt32 hw_pin = intel_gpio_to_pin(gpio_pin, nullptr, nullptr); - if (hw_pin < 0) - continue; - - for (unsigned int registered_idx = 0; registered_idx < registered_pin_list->getCount(); registered_idx++) { - OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(registered_idx)); - if (registered_pin && registered_pin->unsigned32BitValue() == hw_pin) { - requested |= BIT(pin_offset); - break; - } - } - } - - return requested; -} - -UInt32 VoodooGPIO::intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value) { - UInt32 curr, updated; - - curr = readl(hostown); - updated = (curr & ~mask) | (value & mask); - writel(updated, hostown); - - return curr; -} - -void VoodooGPIO::intel_pinctrl_resume() { - /* Mask all interrupts */ - intel_gpio_irq_init(); - - struct intel_pad_context *pads = context.pads; - for (int i = 0; i < npins; i++) { - struct pinctrl_pin_desc *desc = &pins[i]; - IOVirtualAddress padcfg; - uint32_t val; - - if (!intel_pinctrl_should_save(desc->number)) - continue; - - padcfg = intel_get_padcfg(desc->number, PADCFG0); - if (!padcfg) - continue; - - val = readl(padcfg) & ~PADCFG0_GPIORXSTATE; - if (val != pads[i].padcfg0) - writel(pads[i].padcfg0, padcfg); - - padcfg = intel_get_padcfg(desc->number, PADCFG1); - if (!padcfg) - continue; - - val = readl(padcfg); - if (val != pads[i].padcfg1) { - writel(pads[i].padcfg1, padcfg); - } - - padcfg = intel_get_padcfg(desc->number, PADCFG2); - if (padcfg) { - val = readl(padcfg); - if (val != pads[i].padcfg2) { - writel(pads[i].padcfg2, padcfg); - } - } - } - - struct intel_community_context *communityContexts = context.communities; - for (int i = 0; i < ncommunities; i++) { - struct intel_community *community = &communities[i]; - IOVirtualAddress base = 0; - - base = communities->regs + communities->ie_offset; - for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) { - writel(communityContexts[i].intmask[gpp], base + gpp * 4); - } - - base = community->regs + community->hostown_offset; - for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) { - const struct intel_padgroup *padgrp = &community->gpps[gpp]; - UInt32 requested = 0, value = 0; - UInt32 saved = communityContexts[i].hostown[gpp]; - - if (padgrp->gpio_base < 0) - continue; - - requested = intel_gpio_is_requested(padgrp->gpio_base, padgrp->size); - value = intel_gpio_update_pad_mode(base + gpp * 4, requested, saved); - if ((value ^ saved) & requested) { - IOLog("%s::restore hostown %d/%u %#8x->%#8x\n", getName(), i, gpp, value, saved); - } - } - } -} - -bool VoodooGPIO::init(OSDictionary* properties) { - if (!IOService::init(properties)) - return false; - - memset(&(this->context), 0, sizeof(intel_pinctrl_context)); - - return true; -} - -bool VoodooGPIO::start(IOService *provider) { - if (!npins || !ngroups || !nfunctions || !ncommunities) { - IOLog("%s::Missing Platform Data! Aborting!\n", getName()); - return false; - } - - if (!IOService::start(provider)) - return false; - - isInterruptBusy = true; - - workLoop = getWorkLoop(); - if (!workLoop) { - IOLog("%s::Failed to get workloop!\n", getName()); - stop(provider); - return false; - } - workLoop->retain(); - - command_gate = IOCommandGate::commandGate(this); - if (!command_gate || (workLoop->addEventSource(command_gate) != kIOReturnSuccess)) { - IOLog("%s Could not open command gate\n", getName()); - stop(provider); - return false; - } - - IOLog("%s::VoodooGPIO Init!\n", getName()); - - for (int i = 0; i < ncommunities; i++) { - IOLog("%s::VoodooGPIO Initializing Community %d\n", getName(), i); - intel_community *community = &communities[i]; - - community->regs = 0; - community->pad_regs = 0; - - community->mmap = provider->mapDeviceMemoryWithIndex(i); - if (!community->mmap) { - IOLog("%s:VoodooGPIO error mapping community %d\n", getName(), i); - continue; - } - - IOVirtualAddress regs = community->mmap->getVirtualAddress(); - community->regs = regs; - - /* - * Determine community features based on the revision if - * not specified already. - */ - if (!community->features) { - UInt32 rev; - rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; - if (rev >= 0x94) { - community->features |= PINCTRL_FEATURE_DEBOUNCE; - community->features |= PINCTRL_FEATURE_1K_PD; - } - } - - /* Read offset of the pad configuration registers */ - UInt32 padbar = readl(regs + PADBAR); - - community->pad_regs = regs + padbar; - - if (!intel_pinctrl_add_padgroups(community)) { - IOLog("%s::Error adding padgroups to community %d\n", getName(), i); - } - } - - for (int i = 0; i < ncommunities; i++) { - size_t sz = sizeof(OSObject *) * communities[i].npins; - communities[i].pinInterruptActionOwners = (OSObject **)IOMalloc(sz); - memset(communities[i].pinInterruptActionOwners, 0, sz); - - sz = sizeof(IOInterruptAction) * communities[i].npins; - communities[i].pinInterruptAction = (IOInterruptAction *)IOMalloc(sz); - memset(communities[i].pinInterruptAction, 0, sz); - - sz = sizeof(unsigned) * communities[i].npins; - communities[i].interruptTypes = (unsigned *)IOMalloc(sz); - memset(communities[i].interruptTypes, 0, sz); - - sz = sizeof(void *) * communities[i].npins; - communities[i].pinInterruptRefcons = (void **)IOMalloc(sz); - memset(communities[i].pinInterruptRefcons, 0, sz); - - communities[i].isActiveCommunity = IONew(bool, 1); - *communities[i].isActiveCommunity = false; - } - nInactiveCommunities = (UInt32)ncommunities - 1; - - registered_pin_list = OSArray::withCapacity(2); - if (!registered_pin_list) { - return false; - } - - intel_pinctrl_pm_init(); - - isInterruptBusy = false; - controllerIsAwake = true; - - registerService(); - - // Declare an array of two IOPMPowerState structures (kMyNumberOfStates = 2). - -#define kMyNumberOfStates 2 - - static IOPMPowerState myPowerStates[kMyNumberOfStates]; - // Zero-fill the structures. - bzero (myPowerStates, sizeof(myPowerStates)); - // Fill in the information about your device's off state: - myPowerStates[0].version = 1; - myPowerStates[0].capabilityFlags = kIOPMPowerOff; - myPowerStates[0].outputPowerCharacter = kIOPMPowerOff; - myPowerStates[0].inputPowerRequirement = kIOPMPowerOff; - // Fill in the information about your device's on state: - myPowerStates[1].version = 1; - myPowerStates[1].capabilityFlags = kIOPMPowerOn; - myPowerStates[1].outputPowerCharacter = kIOPMPowerOn; - myPowerStates[1].inputPowerRequirement = kIOPMPowerOn; - - PMinit(); - provider->joinPMtree(this); - - registerPowerDriver(this, myPowerStates, kMyNumberOfStates); - - return true; -} - -void VoodooGPIO::stop(IOService *provider) { - IOLog("%s::VoodooGPIO stop!\n", getName()); - - if (command_gate) { - workLoop->removeEventSource(command_gate); - OSSafeReleaseNULL(command_gate); - } - - intel_pinctrl_pm_release(); - - for (int i = 0; i < ncommunities; i++) { - if (communities[i].gpps_alloc) { - IOSafeDeleteNULL(communities[i].gpps, intel_padgroup, communities[i].ngpps); - } - - IOSafeDeleteNULL(communities[i].pinInterruptActionOwners, OSObject*, communities[i].npins); - IOSafeDeleteNULL(communities[i].pinInterruptAction, IOInterruptAction, communities[i].npins); - IOSafeDeleteNULL(communities[i].interruptTypes, unsigned, communities[i].npins); - IOSafeDeleteNULL(communities[i].pinInterruptRefcons, void*, communities[i].npins); - IOSafeDeleteNULL(communities[i].isActiveCommunity, bool, 1); - } - - if (registered_pin_list) { - if (registered_pin_list->getCount() > 0) { - IOLog("%s::Interrupt has not been unregistered by client\n", getName()); - getProvider()->unregisterInterrupt(0); - } - OSSafeReleaseNULL(registered_pin_list); - } - - OSSafeReleaseNULL(workLoop); - - PMstop(); - - IOService::stop(provider); -} - -IOReturn VoodooGPIO::setPowerState(unsigned long powerState, IOService *whatDevice) { - if (whatDevice != this) - return kIOPMAckImplied; - - if (powerState == 0) { - controllerIsAwake = false; - - intel_pinctrl_suspend(); - IOLog("%s::Going to Sleep!\n", getName()); - } else { - if (!controllerIsAwake) { - controllerIsAwake = true; - - intel_pinctrl_resume(); - IOLog("%s::Woke up from Sleep!\n", getName()); - } else { - IOLog("%s::GPIO Controller is already awake! Not reinitializing.\n", getName()); - } - } - return kIOPMAckImplied; -} - -void VoodooGPIO::intel_gpio_community_irq_handler(struct intel_community *community, bool *firstdelay) { - for (int gpp = 0; gpp < community->ngpps; gpp++) { - const struct intel_padgroup *padgrp = &community->gpps[gpp]; - - unsigned padno = padgrp->base - community->pin_base; - if (padno >= community->npins) - break; - - unsigned long pending, enabled; - - pending = readl(community->regs + GPI_IS + padgrp->reg_num * 4); - enabled = readl(community->regs + community->ie_offset + - padgrp->reg_num * 4); - - /* Only interrupts that are enabled */ - pending &= enabled; - - if (!pending) - continue; - - for (int i = 0; i < 32; i++) { - bool isPin = (pending >> i) & 0x1; - if (isPin) { - unsigned pin = padno + i; - if (pin >= community->npins) - break; - - OSObject *owner = community->pinInterruptActionOwners[pin]; - if (owner) { - IOInterruptAction handler = community->pinInterruptAction[pin]; - void *refcon = community->pinInterruptRefcons[pin]; - handler(owner, refcon, this, pin - padgrp->base + padgrp->gpio_base); - if (*firstdelay) { - *firstdelay = false; - IODelay(25 * nInactiveCommunities); // Reduce CPU load. 25~30us per inactive community was reasonable. - } - } - - if (community->interruptTypes[pin] & IRQ_TYPE_LEVEL_MASK) - intel_gpio_irq_mask_unmask(community->pin_base + pin, false); // For Level interrupts, we need to clear the interrupt status or we get too many interrupts - } - } - } -} - -void VoodooGPIO::intel_gpio_pin_irq_handler(unsigned hw_pin) { - intel_community *community = intel_get_community(hw_pin); - intel_padgroup *pad_group = NULL; - if (!community || !(pad_group = intel_community_get_padgroup(community, hw_pin))) { - return; - } - - unsigned long pending, enabled; - IOVirtualAddress pending_address = community->regs + GPI_IS + pad_group->reg_num * 4; - pending = readl(pending_address); - enabled = readl(community->regs + community->ie_offset + pad_group->reg_num * 4); - - /* Only interrupts that are enabled */ - pending &= enabled; - - if (!pending) { - return; - } - - int pad_group_i = hw_pin - pad_group->base; - if (!((pending >> pad_group_i) & 0x1)) { - return; - } - - int community_i = hw_pin - community->pin_base; - OSObject *owner = community->pinInterruptActionOwners[community_i]; - if (owner) { - IOInterruptAction handler = community->pinInterruptAction[community_i]; - void *refcon = community->pinInterruptRefcons[community_i]; - handler(owner, refcon, this, pad_group_i + pad_group->gpio_base); - } - - if (community->interruptTypes[community_i] & IRQ_TYPE_LEVEL_MASK) { - /* For Level interrupts, we need to clear the interrupt status or we get too many interrupts */ - writel(static_cast(BIT(pad_group_i)), pending_address); - } -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt) - * @param interruptType variable to store interrupt type for specified GPIO pin. - */ -IOReturn VoodooGPIO::getInterruptType(int pin, int *interruptType) { - SInt32 hw_pin = intel_gpio_to_pin(pin, nullptr, nullptr); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - return getProvider()->getInterruptType(0, interruptType); -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt). - */ -IOReturn VoodooGPIO::registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) { - struct intel_community *community; - struct intel_padgroup *padgrp; - SInt32 hw_pin = intel_gpio_to_pin(pin, &community, &padgrp); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - IOLog("%s::Registering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); - - unsigned communityidx = hw_pin - community->pin_base; - - if (community->pinInterruptActionOwners[communityidx]) - return kIOReturnNoResources; - - if (OSNumber* registered_pin = OSNumber::withNumber(hw_pin, 32)) { - if (!registered_pin_list->setObject(registered_pin)) { - IOLog("%s::Unable to register pin into list\n", getName()); - registered_pin->release(); - return kIOReturnNoResources; - } - registered_pin->release(); - - community->pinInterruptActionOwners[communityidx] = target; - community->pinInterruptAction[communityidx] = handler; - community->pinInterruptRefcons[communityidx] = refcon; - *community->isActiveCommunity = true; - } else { - IOLog("%s::Unable to allocate interrupt pin", getName()); - return kIOReturnNoResources; - } - - IOLog("%s::Successfully registered hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); - - if (registered_pin_list->getCount() == 1) { - return getProvider()->registerInterrupt(0, this, OSMemberFunctionCast(IOInterruptAction, this, &VoodooGPIO::InterruptOccurred)); - } - return kIOReturnSuccess; -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt). - */ -IOReturn VoodooGPIO::unregisterInterrupt(int pin) { - struct intel_community *community; - SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - IOLog("%s::Unregistering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); - - intel_gpio_irq_mask_unmask(hw_pin, true); - - unsigned communityidx = hw_pin - community->pin_base; - community->pinInterruptActionOwners[communityidx] = NULL; - community->pinInterruptAction[communityidx] = NULL; - community->interruptTypes[communityidx] = 0; - community->pinInterruptRefcons[communityidx] = NULL; - - for (int i = registered_pin_list->getCount() - 1; i >= 0; i--) { - OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(i)); - if (registered_pin && registered_pin->unsigned32BitValue() == hw_pin) { - registered_pin_list->removeObject(i); - } - } - - if (registered_pin_list->getCount() == 0) { - return getProvider()->unregisterInterrupt(0); - } - return kIOReturnSuccess; -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt). - */ -IOReturn VoodooGPIO::enableInterrupt(int pin) { - struct intel_community *community; - SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - unsigned communityidx = hw_pin - community->pin_base; - if (community->pinInterruptActionOwners[communityidx]) { - intel_gpio_irq_set_type(hw_pin, community->interruptTypes[communityidx]); - intel_gpio_irq_mask_unmask(hw_pin, false); - return getProvider()->enableInterrupt(0); - } - return kIOReturnNoInterrupt; -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt). - */ -IOReturn VoodooGPIO::disableInterrupt(int pin) { - SInt32 hw_pin = intel_gpio_to_pin(pin, nullptr, nullptr); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - intel_gpio_irq_mask_unmask(hw_pin, true); - return getProvider()->disableInterrupt(0); -} - -/** - * @param pin 'Software' pin number (i.e. GpioInt). - * @param type Interrupt type to set for specified pin. - */ IOReturn VoodooGPIO::setInterruptTypeForPin(int pin, int type) { - struct intel_community *community; - SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); - if (hw_pin < 0) - return kIOReturnNoInterrupt; - - unsigned communityidx = hw_pin - community->pin_base; - community->interruptTypes[communityidx] = type; - if (type & IRQ_TYPE_LEVEL_MASK) - *community->isActiveCommunity = true; - return kIOReturnSuccess; -} - -void VoodooGPIO::InterruptOccurred(void *refCon, IOService *nub, int source) { - for (int i = 0; i < registered_pin_list->getCount(); i++) { - if (OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(i))) { - intel_gpio_pin_irq_handler(registered_pin->unsigned32BitValue()); - } - } -} - -IOReturn VoodooGPIO::interruptOccurredGated() { - UInt32 inactive = 0; - bool firstdelay = true; - - for (int i = 0; i < ncommunities; i++) { - struct intel_community *community = &communities[i]; - if (*community->isActiveCommunity) - intel_gpio_community_irq_handler(community, &firstdelay); - else - inactive++; - } - - nInactiveCommunities = (inactive < ncommunities)? inactive : ((UInt32)ncommunities - 1); - isInterruptBusy = false; - - return kIOReturnSuccess; + return kIOReturnNoInterrupt; } diff --git a/VoodooGPIO/VoodooGPIO.hpp b/VoodooGPIO/VoodooGPIO.hpp index 2fac5c3..59ccbb2 100644 --- a/VoodooGPIO/VoodooGPIO.hpp +++ b/VoodooGPIO/VoodooGPIO.hpp @@ -1,11 +1,14 @@ // -// VoodooGPIO.h +// VoodooGPIO.hpp // VoodooGPIO // // Created by CoolStar on 8/14/17. // Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. // +#ifndef VoodooGPIO_h +#define VoodooGPIO_h #include #include #include @@ -15,9 +18,6 @@ #include #include "linuxirq.h" -#ifndef VoodooGPIO_h -#define VoodooGPIO_h - // Exists in the macOS 10.15 SDK #ifndef IOSafeDeleteNULL #define IOSafeDeleteNULL(ptr, type, count) \ @@ -29,6 +29,14 @@ } while (0) #endif +inline UInt32 readl(IOVirtualAddress addr) { + return *(const volatile UInt32 *)addr; +} + +inline void writel(UInt32 b, IOVirtualAddress addr) { + *(volatile UInt32 *)(addr) = b; +} + struct pinctrl_pin_desc { unsigned number; char *name; @@ -38,236 +46,42 @@ struct pinctrl_pin_desc { #define PINCTRL_PIN(a, b) {.number = a, .name = b} #define PINCTRL_PIN_ANON(a) {.number = a} -/** - * struct intel_pingroup - Description about group of pins - * @name: Name of the groups - * @pins: All pins in this group - * @npins: Number of pins in this groups - * @mode: Native mode in which the group is muxed out @pins. Used if @modes - * is %NULL. - * @modes: If not %NULL this will hold mode for each pin in @pins - */ -struct intel_pingroup { - char *name; - unsigned *pins; - size_t npins; - unsigned short mode; - unsigned *modes; -}; - -/** - * struct intel_function - Description about a function - * @name: Name of the function - * @groups: An array of groups for this function - * @ngroups: Number of groups in @groups - */ -struct intel_function { - char *name; - char * const *groups; - size_t ngroups; -}; - -/** - * struct intel_padgroup - Hardware pad group information - * @reg_num: GPI_IS register number - * @base: Starting pin of this group - * @size: Size of this group (maximum is 32). - * @gpio_base: Starting GPIO base of this group (%0 if matches with @base, - * and %-1 if no GPIO mapping should be created) - * @padown_num: PAD_OWN register number (assigned by the core driver) - * - * If pad groups of a community are not the same size, use this structure - * to specify them. - */ -struct intel_padgroup { - UInt32 reg_num; - UInt32 base; - UInt32 size; - SInt32 gpio_base; - UInt32 padown_num; -}; - -/** - * struct intel_community - Intel pin community description - * @barno: MMIO BAR number where registers for this community reside - * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 - * then there is no support for owner. - * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then - * locking is not supported. - * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it - * is assumed that the host owns the pin (rather than - * ACPI). - * @ie_offset: Register offset of GPI_IE from @regs. - * @pin_base: Starting pin of pins in this community - * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, - * HOSTSW_OWN, GPI_IS, GPI_IE, etc. Used when @gpps is %NULL. - * @gpp_num_padown_regs: Number of pad registers each pad group consumes at - * minimum. Use %0 if the number of registers can be - * determined by the size of the group. - * @npins: Number of pins in this community - * @features: Additional features supported by the hardware - * @gpps: Pad groups if the controller has variable size pad groups - * @ngpps: Number of pad groups in this community - * @regs: Community specific common registers (reserved for core driver) - * @pad_regs: Community specific pad registers (reserved for core driver) - * - * Most Intel GPIO host controllers this driver supports each pad group is - * of equal size (except the last one). In that case the driver can just - * fill in @gpp_size field and let the core driver to handle the rest. If - * the controller has pad groups of variable size the client driver can - * pass custom @gpps and @ngpps instead. - */ -struct intel_community { - unsigned barno; - unsigned padown_offset; - unsigned padcfglock_offset; - unsigned hostown_offset; - unsigned ie_offset; - unsigned pin_base; - unsigned gpp_size; - unsigned gpp_num_padown_regs; - size_t npins; - unsigned features; - struct intel_padgroup *gpps; - size_t ngpps; - bool gpps_alloc; - bool *isActiveCommunity; - /* Reserved for the core driver */ - IOMemoryMap *mmap; - IOVirtualAddress regs; - IOVirtualAddress pad_regs; - - unsigned *interruptTypes; - OSObject **pinInterruptActionOwners; - IOInterruptAction *pinInterruptAction; - void **pinInterruptRefcons; -}; - -struct intel_pad_context { - uint32_t padcfg0; - uint32_t padcfg1; - uint32_t padcfg2; -}; +#define kIOPMPowerOff 0 -struct intel_community_context { - uint32_t *intmask; - uint32_t *hostown; -}; +#if defined(__LP64__) && __LP64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif -struct intel_pinctrl_context { - struct intel_pad_context *pads; - struct intel_community_context *communities; -}; +#define BIT(x) 1UL << x +#define GENMASK(h, l) \ +(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) -/* Additional features supported by the hardware */ -#define PINCTRL_FEATURE_DEBOUNCE 1 -#define PINCTRL_FEATURE_1K_PD 2 +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -/** - * PIN_GROUP - Declare a pin group - * @n: Name of the group - * @p: An array of pins this group consists - * @m: Mode which the pins are put when this group is active. Can be either - * a single integer or an array of integers in which case mode is per - * pin. - */ -#define PIN_GROUP(n, p, m) \ -{ \ - .name = (n), \ - .pins = (p), \ - .npins = ARRAY_SIZE((p)), \ - .mode = __builtin_choose_expr( \ - __builtin_constant_p((m)), (m), 0), \ - .modes = __builtin_choose_expr( \ - __builtin_constant_p((m)), NULL, (m)), \ -} - -#define FUNCTION(n, g) \ -{ \ - .name = (n), \ - .groups = (g), \ - .ngroups = ARRAY_SIZE((g)), \ -} +// Log only if current thread is interruptible, otherwise we will get a panic. +#define TryLog(args...) do { if (ml_get_interrupts_enabled()) IOLog(args); } while (0) class VoodooGPIO : public IOService { OSDeclareDefaultStructors(VoodooGPIO); - protected: - struct pinctrl_pin_desc *pins; - size_t npins; - struct intel_pingroup *groups; - size_t ngroups; - struct intel_function *functions; - size_t nfunctions; - struct intel_community *communities; - size_t ncommunities; - - private: - struct intel_pinctrl_context context; - - bool controllerIsAwake; +protected: + const struct pinctrl_pin_desc *pins = nullptr; + size_t npins { 0 }; + bool controllerIsAwake = false; IOWorkLoop *workLoop = nullptr; IOCommandGate* command_gate = nullptr; OSArray* registered_pin_list = nullptr; - bool isInterruptBusy; - UInt32 nInactiveCommunities; - - UInt32 readl(IOVirtualAddress addr); - void writel(UInt32 b, IOVirtualAddress addr); + bool isInterruptBusy = false; IOWorkLoop* getWorkLoop(); - struct intel_community *intel_get_community(unsigned pin); - struct intel_padgroup *intel_community_get_padgroup(struct intel_community *community, unsigned pin); - IOVirtualAddress intel_get_padcfg(unsigned pin, unsigned reg); - - bool intel_pad_owned_by_host(unsigned pin); - bool intel_pad_acpi_mode(unsigned pin); - int intel_pad_locked(unsigned pin); - bool intel_pad_is_unlocked(unsigned int pin); - - SInt32 intel_gpio_to_pin(UInt32 offset, - struct intel_community **community, - struct intel_padgroup **padgrp); - void intel_gpio_irq_mask_unmask(unsigned pin, bool mask); - bool intel_gpio_irq_set_type(unsigned pin, unsigned type); - - bool intel_pinctrl_add_padgroups(intel_community *community); - - bool intel_pinctrl_should_save(unsigned pin); - void intel_pinctrl_pm_init(); - void intel_pinctrl_pm_release(); - void intel_pinctrl_suspend(); - void intel_gpio_irq_init(); - UInt32 intel_gpio_is_requested(int base, unsigned int size); - UInt32 intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value); - void intel_pinctrl_resume(); - - void intel_gpio_community_irq_handler(struct intel_community *community, bool *firstdelay); - void intel_gpio_pin_irq_handler(unsigned hw_pin); - - void InterruptOccurred(void *refCon, IOService *nub, int source); - IOReturn interruptOccurredGated(); - public: - IOReturn getInterruptType(int pin, int *interruptType) override; - IOReturn registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) override; - IOReturn unregisterInterrupt(int pin) override; - - IOReturn enableInterrupt(int pin) override; - IOReturn disableInterrupt(int pin) override; - - IOReturn setInterruptTypeForPin(int pin, int type); - - bool init(OSDictionary* properties) override; - - bool start(IOService *provider) override; - void stop(IOService *provider) override; - - IOReturn setPowerState(unsigned long powerState, IOService *whatDevice) override; + virtual IOReturn setInterruptTypeForPin(int pin, int type); }; #endif /* VoodooGPIO_h */ diff --git a/VoodooGPIO/VoodooGPIOAMD.cpp b/VoodooGPIO/VoodooGPIOAMD.cpp new file mode 100644 index 0000000..735ac1c --- /dev/null +++ b/VoodooGPIO/VoodooGPIOAMD.cpp @@ -0,0 +1,487 @@ +// +// VoodooGPIOAMD.cpp +// VoodooGPIO +// +// Created by Visual on 6/3/23. +// Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. +// + +#include "VoodooGPIOAMD.hpp" + +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + +OSDefineMetaClassAndStructors(VoodooGPIOAMD, VoodooGPIO); + +void VoodooGPIOAMD::amd_gpio_irq_enable(unsigned pin) { + UInt32 pin_reg = readl(this->base + pin*4); + pin_reg |= BIT(INTERRUPT_ENABLE_OFF); + pin_reg |= BIT(INTERRUPT_MASK_OFF); + writel(pin_reg, this->base + pin*4); + + /* + * When debounce logic is enabled it takes ~900 us before interrupts + * can be enabled. During this "debounce warm up" period the + * "INTERRUPT_ENABLE" bit will read as 0. Poll the bit here until it + * reads back as 1, signaling that interrupts are now enabled. + */ + UInt32 mask = BIT(INTERRUPT_ENABLE_OFF) | BIT(INTERRUPT_MASK_OFF); + while ((readl(this->base + pin*4) & mask) != mask) + continue; +} + +void VoodooGPIOAMD::amd_gpio_irq_disable(unsigned pin) { + UInt32 pin_reg = readl(this->base + pin*4); + pin_reg &= ~BIT(INTERRUPT_ENABLE_OFF); + pin_reg &= ~BIT(INTERRUPT_MASK_OFF); + writel(pin_reg, this->base + pin*4); +} + +void VoodooGPIOAMD::amd_gpio_irq_mask(unsigned pin) { + UInt32 pin_reg = readl(this->base + pin*4); + pin_reg &= ~BIT(INTERRUPT_MASK_OFF); + writel(pin_reg, this->base + pin*4); +} + +void VoodooGPIOAMD::amd_gpio_irq_unmask(unsigned pin) { + UInt32 pin_reg = readl(this->base + pin*4); + pin_reg |= BIT(INTERRUPT_MASK_OFF); + writel(pin_reg, this->base + pin*4); +} + +int VoodooGPIOAMD::amd_gpio_irq_set_wake(unsigned pin, unsigned int on) { + UInt32 wake_mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3); + + UInt32 pin_reg = readl(this->base + pin*4); + + if (on) + pin_reg |= wake_mask; + else + pin_reg &= ~wake_mask; + + writel(pin_reg, this->base + pin*4); + + return 0; +} + +void VoodooGPIOAMD::amd_gpio_irq_eoi() { + UInt32 reg = readl(this->base + WAKE_INT_MASTER_REG); + reg |= EOI_MASK; + writel(reg, this->base + WAKE_INT_MASTER_REG); +} + +int VoodooGPIOAMD::amd_gpio_irq_set_type(unsigned pin, unsigned int type) { + int ret = 0; + + UInt32 pin_reg = readl(this->base + pin*4); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + pin_reg &= ~BIT(LEVEL_TRIG_OFF); + pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); + pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; + break; + case IRQ_TYPE_EDGE_FALLING: + pin_reg &= ~BIT(LEVEL_TRIG_OFF); + pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); + pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; + break; + case IRQ_TYPE_EDGE_BOTH: + pin_reg &= ~BIT(LEVEL_TRIG_OFF); + pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); + pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; + break; + case IRQ_TYPE_LEVEL_HIGH: + pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF; + pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); + pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; + break; + case IRQ_TYPE_LEVEL_LOW: + pin_reg |= LEVEL_TRIGGER << LEVEL_TRIG_OFF; + pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); + pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; + break; + case IRQ_TYPE_NONE: + break; + default: + TryLog("%s::VoodooGPIO Invalid type value\n", this->getName()); + ret = -1; + } + + pin_reg |= CLR_INTR_STAT << INTERRUPT_STS_OFF; + writel(pin_reg, this->base + pin*4); + + return ret; +} + +#define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) + +bool VoodooGPIOAMD::do_amd_gpio_irq_handler(int irq) { + UInt32 i, irqnr; + bool ret = false; + UInt32 regval; + UInt64 status, mask; + + /* Read the wake status */ + status = readl(this->base + WAKE_INT_STATUS_REG1); + status <<= 32; + status |= readl(this->base + WAKE_INT_STATUS_REG0); + + /* Bit 0-45 contain the relevant status bits */ + status &= (1ULL << 46) - 1; + UInt32* regs = (UInt32*)this->base; + for (mask = 1, irqnr = 0; status; mask <<= 1, regs += 4, irqnr += 4) { + if (!(status & mask)) + continue; + + status &= ~mask; + + /* Each status bit covers four pins */ + for (i = 0; i < 4; i++) { + regval = readl((IOVirtualAddress)(regs + i)); + + /* caused wake on resume context for shared IRQ */ + if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) { + TryLog("%s::VoodooGPIO Waking due to GPIO %d: 0x%x\n", this->getName(), irqnr + i, regval); + return true; + } + + if (!(regval & PIN_IRQ_PENDING) || + !(regval & BIT(INTERRUPT_MASK_OFF))) + continue; + + UInt32 pin = irqnr + i; + if (pin >= this->npins) + break; + + if (OSObject *owner = this->pinInterruptActionOwners[pin]) + this->pinInterruptAction[pin](owner, this->pinInterruptRefcons[pin], this, pin); + + // For Level interrupts, we need to clear the interrupt status or we get too many interrupts + if (this->interruptTypes[pin] & IRQ_TYPE_LEVEL_MASK) + this->amd_gpio_irq_unmask(pin); + + /* Clear interrupt. + * We must read the pin register again, in case the + * value was changed while executing + * generic_handle_domain_irq() above. + * If we didn't find a mapping for the interrupt, + * disable it in order to avoid a system hang caused + * by an interrupt storm. + */ + regval = readl((IOVirtualAddress)(regs + i)); + if (irq == 0) { + regval &= ~BIT(INTERRUPT_ENABLE_OFF); + TryLog("%s::VoodooGPIO: Disabling spurious GPIO IRQ %d\n", this->getName(), irqnr + i); + } + writel(regval, (IOVirtualAddress)(regs + i)); + + ret = true; + } + } + /* did not cause wake on resume context for shared IRQ */ + if (irq < 0) + return false; + + this->amd_gpio_irq_eoi(); + + return ret; +} + +void VoodooGPIOAMD::amd_gpio_irq_init() { + UInt32 pin_reg, mask; + int i; + + mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) | + BIT(INTERRUPT_MASK_OFF) | BIT(INTERRUPT_ENABLE_OFF) | + BIT(WAKE_CNTRL_OFF_S4); + + for (i = 0; i < this->npins; i++) { + pin_reg = readl(this->base + i * 4); + pin_reg &= ~mask; + writel(pin_reg, this->base + i * 4); + } +} + +int VoodooGPIOAMD::amd_gpio_suspend() { + for (size_t i = 0; i < this->npins; i++) { + int pin = this->pins[i].number; + + this->saved_regs[i] = readl(this->base + pin * 4) & ~PIN_IRQ_PENDING; + } + + return 0; +} + +int VoodooGPIOAMD::amd_gpio_resume() { + for (size_t i = 0; i < this->npins; i++) { + int pin = this->pins[i].number; + + this->saved_regs[i] |= readl(this->base + pin * 4) & PIN_IRQ_PENDING; + writel(this->saved_regs[i], this->base + pin * 4); + } + + return 0; +} + +void VoodooGPIOAMD::InterruptOccurred(void *refCon, IOService *nub, int source) { + this->do_amd_gpio_irq_handler(source); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt) + * @param interruptType variable to store interrupt type for specified GPIO pin. + */ +IOReturn VoodooGPIOAMD::getInterruptType(int pin, int *interruptType) { + if (pin < 0 || pin >= this->npins) + return kIOReturnNoInterrupt; + + return this->getProvider()->getInterruptType(0, interruptType); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOAMD::registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) { + if (pin < 0 || pin >= this->npins) + return kIOReturnNoInterrupt; + + IOLog("%s::Registering GPIO IRQ pin 0x%02X\n", this->getName(), pin); + + if (this->pinInterruptActionOwners[pin]) + return kIOReturnNoResources; + + if (OSNumber* registered_pin = OSNumber::withNumber(pin, 32)) { + if (!this->registered_pin_list->setObject(registered_pin)) { + IOLog("%s::Unable to register pin into list\n", this->getName()); + registered_pin->release(); + return kIOReturnNoResources; + } + registered_pin->release(); + + this->pinInterruptActionOwners[pin] = target; + this->pinInterruptAction[pin] = handler; + this->pinInterruptRefcons[pin] = refcon; + } else { + IOLog("%s::Unable to allocate interrupt pin", this->getName()); + return kIOReturnNoResources; + } + + IOLog("%s::Successfully registered GPIO IRQ pin 0x%02X\n", this->getName(), pin); + + if (this->registered_pin_list->getCount() == 1) + return this->getProvider()->registerInterrupt(0, this, OSMemberFunctionCast(IOInterruptAction, this, &VoodooGPIOAMD::InterruptOccurred)); + + return kIOReturnSuccess; +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOAMD::unregisterInterrupt(int pin) { + if (pin < 0 || pin >= this->npins) + return kIOReturnNoInterrupt; + + IOLog("%s::Unregistering GPIO IRQ pin 0x%02X\n", this->getName(), pin); + + this->amd_gpio_irq_mask(pin); + + this->pinInterruptActionOwners[pin] = NULL; + this->pinInterruptAction[pin] = NULL; + this->interruptTypes[pin] = 0; + this->pinInterruptRefcons[pin] = NULL; + + for (int i = this->registered_pin_list->getCount() - 1; i >= 0; i--) { + OSNumber* registered_pin = OSDynamicCast(OSNumber, this->registered_pin_list->getObject(i)); + if (registered_pin && registered_pin->unsigned32BitValue() == pin) { + this->registered_pin_list->removeObject(i); + } + } + + if (this->registered_pin_list->getCount() == 0) + return getProvider()->unregisterInterrupt(0); + + return kIOReturnSuccess; +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOAMD::enableInterrupt(int pin) { + if (pin < 0 || pin >= this->npins || !this->pinInterruptActionOwners[pin]) + return kIOReturnNoInterrupt; + + this->amd_gpio_irq_enable(pin); + this->amd_gpio_irq_set_type(pin, this->interruptTypes[pin]); + this->amd_gpio_irq_unmask(pin); + return this->getProvider()->enableInterrupt(0); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOAMD::disableInterrupt(int pin) { + if (pin < 0 || pin >= this->npins) + return kIOReturnNoInterrupt; + + this->amd_gpio_irq_disable(pin); + this->amd_gpio_irq_mask(pin); + return this->getProvider()->disableInterrupt(0); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + * @param type Interrupt type to set for specified pin. + */ +IOReturn VoodooGPIOAMD::setInterruptTypeForPin(int pin, int type) { + if (pin < 0 || pin >= this->npins) + return kIOReturnNoInterrupt; + + this->interruptTypes[pin] = type; + return kIOReturnSuccess; +} + +bool VoodooGPIOAMD::start(IOService *provider) { + this->pins = kerncz_pins; + this->npins = ARRAY_SIZE(kerncz_pins); + this->groups = kerncz_groups; + this->ngroups = ARRAY_SIZE(kerncz_groups); + this->functions = pmx_functions; + this->nfunctions = ARRAY_SIZE(pmx_functions); + + IOLog("%s::Loading GPIO Data for AMD\n", this->getName()); + + if (!IOService::start(provider)) + return false; + + this->isInterruptBusy = true; + + this->workLoop = getWorkLoop(); + if (!this->workLoop) { + IOLog("%s::Failed to get workloop!\n", this->getName()); + stop(provider); + return false; + } + workLoop->retain(); + + this->command_gate = IOCommandGate::commandGate(this); + if (!this->command_gate || (this->workLoop->addEventSource(this->command_gate) != kIOReturnSuccess)) { + IOLog("%s Could not open command gate\n", this->getName()); + stop(provider); + return false; + } + + IOLog("%s::VoodooGPIO Init!\n", this->getName()); + + this->saved_regs = IONewZero(UInt32, this->npins); + if (!this->saved_regs) { + IOLog("%s::Failed to allocate saved_regs!\n", this->getName()); + stop(provider); + return false; + } + + this->mmap = provider->mapDeviceMemoryWithIndex(0); + if (!this->mmap) { + IOLog("%s:VoodooGPIO error mapping base 0\n", this->getName()); + return false; + } + this->base = this->mmap->getVirtualAddress(); + + this->registered_pin_list = OSArray::withCapacity(2); + if (!this->registered_pin_list) { + IOLog("%s::Failed to allocate registered_pin_list!\n", this->getName()); + return false; + } + + this->isInterruptBusy = false; + this->controllerIsAwake = true; + + this->pinInterruptActionOwners = IONewZero(OSObject*, this->npins); + this->pinInterruptAction = IONewZero(IOInterruptAction, this->npins); + this->interruptTypes = IONewZero(unsigned, this->npins); + this->pinInterruptRefcons = IONewZero(void *, this->npins); + + this->amd_gpio_irq_init(); + + this->registerService(); + + // Declare an array of two IOPMPowerState structures (kMyNumberOfStates = 2). + +#define kMyNumberOfStates 2 + + static IOPMPowerState myPowerStates[kMyNumberOfStates]; + // Zero-fill the structures. + bzero (myPowerStates, sizeof(myPowerStates)); + // Fill in the information about your device's off state: + myPowerStates[0].version = 1; + myPowerStates[0].capabilityFlags = kIOPMPowerOff; + myPowerStates[0].outputPowerCharacter = kIOPMPowerOff; + myPowerStates[0].inputPowerRequirement = kIOPMPowerOff; + // Fill in the information about your device's on state: + myPowerStates[1].version = 1; + myPowerStates[1].capabilityFlags = kIOPMPowerOn; + myPowerStates[1].outputPowerCharacter = kIOPMPowerOn; + myPowerStates[1].inputPowerRequirement = kIOPMPowerOn; + + this->PMinit(); + provider->joinPMtree(this); + + this->registerPowerDriver(this, myPowerStates, kMyNumberOfStates); + + return true; +} + +void VoodooGPIOAMD::stop(IOService *provider) { + IOLog("%s::VoodooGPIO stop!\n", this->getName()); + + if (this->command_gate) { + this->workLoop->removeEventSource(this->command_gate); + OSSafeReleaseNULL(this->command_gate); + } + + if (this->mmap) { + OSSafeReleaseNULL(mmap); + } + + if (this->registered_pin_list) { + if (this->registered_pin_list->getCount() > 0) { + IOLog("%s::Interrupt has not been unregistered by client\n", this->getName()); + this->getProvider()->unregisterInterrupt(0); + } + OSSafeReleaseNULL(this->registered_pin_list); + } + + IOSafeDeleteNULL(this->pinInterruptActionOwners, OSObject*, this->npins); + IOSafeDeleteNULL(this->pinInterruptAction, IOInterruptAction, this->npins); + IOSafeDeleteNULL(this->interruptTypes, unsigned, this->npins); + IOSafeDeleteNULL(this->pinInterruptRefcons, void*, this->npins); + + OSSafeReleaseNULL(this->workLoop); + + this->PMstop(); + + IOService::stop(provider); +} + +IOReturn VoodooGPIOAMD::setPowerState(unsigned long powerState, IOService *whatDevice) { + if (whatDevice != this) + return kIOPMAckImplied; + + if (powerState == 0) { + this->controllerIsAwake = false; + + this->amd_gpio_suspend(); + IOLog("%s::Going to Sleep!\n", this->getName()); + } else { + if (!this->controllerIsAwake) { + this->controllerIsAwake = true; + + this->amd_gpio_resume(); + IOLog("%s::Woke up from Sleep!\n", this->getName()); + } else { + IOLog("%s::GPIO Controller is already awake! Not reinitializing.\n", this->getName()); + } + } + return kIOPMAckImplied; +} diff --git a/VoodooGPIO/VoodooGPIOAMD.hpp b/VoodooGPIO/VoodooGPIOAMD.hpp new file mode 100644 index 0000000..301835a --- /dev/null +++ b/VoodooGPIO/VoodooGPIOAMD.hpp @@ -0,0 +1,1674 @@ +// +// VoodooGPIOAMD.hpp +// VoodooGPIO +// +// Created by Visual on 6/3/23. +// Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. +// + +#ifndef VoodooGPIOAMD_hpp +#define VoodooGPIOAMD_hpp +#include "VoodooGPIO.hpp" + +/** + * struct pingroup - provides information on pingroup + * @name: a name for pingroup + * @pins: an array of pins in the pingroup + * @npins: number of pins in the pingroup + */ +struct pingroup { + const char *name; + const unsigned int *pins; + size_t npins; +}; + +/* Convenience macro to define a single named or anonymous pingroup */ +#define PINCTRL_PINGROUP(_name, _pins, _npins) \ +(struct pingroup) { \ + .name = _name, \ + .pins = _pins, \ + .npins = _npins, \ +} + +#define AMD_GPIO_PINS_PER_BANK 64 + +#define AMD_GPIO_PINS_BANK0 63 +#define AMD_GPIO_PINS_BANK1 64 +#define AMD_GPIO_PINS_BANK2 56 +#define AMD_GPIO_PINS_BANK3 32 + +#define WAKE_INT_MASTER_REG 0xfc +#define EOI_MASK (1 << 29) + +#define WAKE_INT_STATUS_REG0 0x2f8 +#define WAKE_INT_STATUS_REG1 0x2fc + +#define DB_TMR_OUT_OFF 0 +#define DB_TMR_OUT_UNIT_OFF 4 +#define DB_CNTRL_OFF 5 +#define DB_TMR_LARGE_OFF 7 +#define LEVEL_TRIG_OFF 8 +#define ACTIVE_LEVEL_OFF 9 +#define INTERRUPT_ENABLE_OFF 11 +#define INTERRUPT_MASK_OFF 12 +#define WAKE_CNTRL_OFF_S0I3 13 +#define WAKE_CNTRL_OFF_S3 14 +#define WAKE_CNTRL_OFF_S4 15 +#define PIN_STS_OFF 16 +#define DRV_STRENGTH_SEL_OFF 17 +#define PULL_UP_SEL_OFF 19 +#define PULL_UP_ENABLE_OFF 20 +#define PULL_DOWN_ENABLE_OFF 21 +#define OUTPUT_VALUE_OFF 22 +#define OUTPUT_ENABLE_OFF 23 +#define SW_CNTRL_IN_OFF 24 +#define SW_CNTRL_EN_OFF 25 +#define WAKECNTRL_Z_OFF 27 +#define INTERRUPT_STS_OFF 28 +#define WAKE_STS_OFF 29 + +#define DB_TMR_OUT_MASK 0xFUL +#define DB_CNTRl_MASK 0x3UL +#define ACTIVE_LEVEL_MASK 0x3UL +#define DRV_STRENGTH_SEL_MASK 0x3UL + +#define ACTIVE_LEVEL_HIGH 0x0UL +#define ACTIVE_LEVEL_LOW 0x1UL +#define ACTIVE_LEVEL_BOTH 0x2UL + +#define DB_TYPE_NO_DEBOUNCE 0x0UL +#define DB_TYPE_PRESERVE_LOW_GLITCH 0x1UL +#define DB_TYPE_PRESERVE_HIGH_GLITCH 0x2UL +#define DB_TYPE_REMOVE_GLITCH 0x3UL + +#define EDGE_TRAGGER 0x0UL +#define LEVEL_TRIGGER 0x1UL + +#define ACTIVE_HIGH 0x0UL +#define ACTIVE_LOW 0x1UL +#define BOTH_EADGE 0x2UL + +#define ENABLE_INTERRUPT 0x1UL +#define DISABLE_INTERRUPT 0x0UL + +#define ENABLE_INTERRUPT_MASK 0x0UL +#define DISABLE_INTERRUPT_MASK 0x1UL + +#define CLR_INTR_STAT 0x1UL + +#define NSELECTS 0x4 + +#define FUNCTION_MASK GENMASK(1, 0) +#define FUNCTION_INVALID GENMASK(7, 0) + +struct amd_function { + const char *name; + const char * const groups[NSELECTS]; + unsigned ngroups; + int index; +}; + +/* KERNCZ configuration*/ +static const struct pinctrl_pin_desc kerncz_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "GPIO_156"), + PINCTRL_PIN(157, "GPIO_157"), + PINCTRL_PIN(158, "GPIO_158"), + PINCTRL_PIN(159, "GPIO_159"), + PINCTRL_PIN(160, "GPIO_160"), + PINCTRL_PIN(161, "GPIO_161"), + PINCTRL_PIN(162, "GPIO_162"), + PINCTRL_PIN(163, "GPIO_163"), + PINCTRL_PIN(164, "GPIO_164"), + PINCTRL_PIN(165, "GPIO_165"), + PINCTRL_PIN(166, "GPIO_166"), + PINCTRL_PIN(167, "GPIO_167"), + PINCTRL_PIN(168, "GPIO_168"), + PINCTRL_PIN(169, "GPIO_169"), + PINCTRL_PIN(170, "GPIO_170"), + PINCTRL_PIN(171, "GPIO_171"), + PINCTRL_PIN(172, "GPIO_172"), + PINCTRL_PIN(173, "GPIO_173"), + PINCTRL_PIN(174, "GPIO_174"), + PINCTRL_PIN(175, "GPIO_175"), + PINCTRL_PIN(176, "GPIO_176"), + PINCTRL_PIN(177, "GPIO_177"), + PINCTRL_PIN(178, "GPIO_178"), + PINCTRL_PIN(179, "GPIO_179"), + PINCTRL_PIN(180, "GPIO_180"), + PINCTRL_PIN(181, "GPIO_181"), + PINCTRL_PIN(182, "GPIO_182"), + PINCTRL_PIN(183, "GPIO_183"), +}; + +#define AMD_PINS(...) (const unsigned int []){__VA_ARGS__} + +enum amd_functions { + IMX_F0_GPIO0, + IMX_F1_GPIO0, + IMX_F2_GPIO0, + IMX_F3_GPIO0, + IMX_F0_GPIO1, + IMX_F1_GPIO1, + IMX_F2_GPIO1, + IMX_F3_GPIO1, + IMX_F0_GPIO2, + IMX_F1_GPIO2, + IMX_F2_GPIO2, + IMX_F3_GPIO2, + IMX_F0_GPIO3, + IMX_F1_GPIO3, + IMX_F2_GPIO3, + IMX_F3_GPIO3, + IMX_F0_GPIO4, + IMX_F1_GPIO4, + IMX_F2_GPIO4, + IMX_F3_GPIO4, + IMX_F0_GPIO5, + IMX_F1_GPIO5, + IMX_F2_GPIO5, + IMX_F3_GPIO5, + IMX_F0_GPIO6, + IMX_F1_GPIO6, + IMX_F2_GPIO6, + IMX_F3_GPIO6, + IMX_F0_GPIO7, + IMX_F1_GPIO7, + IMX_F2_GPIO7, + IMX_F3_GPIO7, + IMX_F0_GPIO8, + IMX_F1_GPIO8, + IMX_F2_GPIO8, + IMX_F3_GPIO8, + IMX_F0_GPIO9, + IMX_F1_GPIO9, + IMX_F2_GPIO9, + IMX_F3_GPIO9, + IMX_F0_GPIO10, + IMX_F1_GPIO10, + IMX_F2_GPIO10, + IMX_F3_GPIO10, + IMX_F0_GPIO11, + IMX_F1_GPIO11, + IMX_F2_GPIO11, + IMX_F3_GPIO11, + IMX_F0_GPIO12, + IMX_F1_GPIO12, + IMX_F2_GPIO12, + IMX_F3_GPIO12, + IMX_F0_GPIO13, + IMX_F1_GPIO13, + IMX_F2_GPIO13, + IMX_F3_GPIO13, + IMX_F0_GPIO14, + IMX_F1_GPIO14, + IMX_F2_GPIO14, + IMX_F3_GPIO14, + IMX_F0_GPIO15, + IMX_F1_GPIO15, + IMX_F2_GPIO15, + IMX_F3_GPIO15, + IMX_F0_GPIO16, + IMX_F1_GPIO16, + IMX_F2_GPIO16, + IMX_F3_GPIO16, + IMX_F0_GPIO17, + IMX_F1_GPIO17, + IMX_F2_GPIO17, + IMX_F3_GPIO17, + IMX_F0_GPIO18, + IMX_F1_GPIO18, + IMX_F2_GPIO18, + IMX_F3_GPIO18, + IMX_F0_GPIO19, + IMX_F1_GPIO19, + IMX_F2_GPIO19, + IMX_F3_GPIO19, + IMX_F0_GPIO20, + IMX_F1_GPIO20, + IMX_F2_GPIO20, + IMX_F3_GPIO20, + IMX_F0_GPIO21, + IMX_F1_GPIO21, + IMX_F2_GPIO21, + IMX_F3_GPIO21, + IMX_F0_GPIO22, + IMX_F1_GPIO22, + IMX_F2_GPIO22, + IMX_F3_GPIO22, + IMX_F0_GPIO23, + IMX_F1_GPIO23, + IMX_F2_GPIO23, + IMX_F3_GPIO23, + IMX_F0_GPIO24, + IMX_F1_GPIO24, + IMX_F2_GPIO24, + IMX_F3_GPIO24, + IMX_F0_GPIO25, + IMX_F1_GPIO25, + IMX_F2_GPIO25, + IMX_F3_GPIO25, + IMX_F0_GPIO26, + IMX_F1_GPIO26, + IMX_F2_GPIO26, + IMX_F3_GPIO26, + IMX_F0_GPIO27, + IMX_F1_GPIO27, + IMX_F2_GPIO27, + IMX_F3_GPIO27, + IMX_F0_GPIO28, + IMX_F1_GPIO28, + IMX_F2_GPIO28, + IMX_F3_GPIO28, + IMX_F0_GPIO29, + IMX_F1_GPIO29, + IMX_F2_GPIO29, + IMX_F3_GPIO29, + IMX_F0_GPIO30, + IMX_F1_GPIO30, + IMX_F2_GPIO30, + IMX_F3_GPIO30, + IMX_F0_GPIO31, + IMX_F1_GPIO31, + IMX_F2_GPIO31, + IMX_F3_GPIO31, + IMX_F0_GPIO32, + IMX_F1_GPIO32, + IMX_F2_GPIO32, + IMX_F3_GPIO32, + IMX_F0_GPIO33, + IMX_F1_GPIO33, + IMX_F2_GPIO33, + IMX_F3_GPIO33, + IMX_F0_GPIO34, + IMX_F1_GPIO34, + IMX_F2_GPIO34, + IMX_F3_GPIO34, + IMX_F0_GPIO35, + IMX_F1_GPIO35, + IMX_F2_GPIO35, + IMX_F3_GPIO35, + IMX_F0_GPIO36, + IMX_F1_GPIO36, + IMX_F2_GPIO36, + IMX_F3_GPIO36, + IMX_F0_GPIO37, + IMX_F1_GPIO37, + IMX_F2_GPIO37, + IMX_F3_GPIO37, + IMX_F0_GPIO38, + IMX_F1_GPIO38, + IMX_F2_GPIO38, + IMX_F3_GPIO38, + IMX_F0_GPIO39, + IMX_F1_GPIO39, + IMX_F2_GPIO39, + IMX_F3_GPIO39, + IMX_F0_GPIO40, + IMX_F1_GPIO40, + IMX_F2_GPIO40, + IMX_F3_GPIO40, + IMX_F0_GPIO41, + IMX_F1_GPIO41, + IMX_F2_GPIO41, + IMX_F3_GPIO41, + IMX_F0_GPIO42, + IMX_F1_GPIO42, + IMX_F2_GPIO42, + IMX_F3_GPIO42, + IMX_F0_GPIO43, + IMX_F1_GPIO43, + IMX_F2_GPIO43, + IMX_F3_GPIO43, + IMX_F0_GPIO44, + IMX_F1_GPIO44, + IMX_F2_GPIO44, + IMX_F3_GPIO44, + IMX_F0_GPIO45, + IMX_F1_GPIO45, + IMX_F2_GPIO45, + IMX_F3_GPIO45, + IMX_F0_GPIO46, + IMX_F1_GPIO46, + IMX_F2_GPIO46, + IMX_F3_GPIO46, + IMX_F0_GPIO47, + IMX_F1_GPIO47, + IMX_F2_GPIO47, + IMX_F3_GPIO47, + IMX_F0_GPIO48, + IMX_F1_GPIO48, + IMX_F2_GPIO48, + IMX_F3_GPIO48, + IMX_F0_GPIO49, + IMX_F1_GPIO49, + IMX_F2_GPIO49, + IMX_F3_GPIO49, + IMX_F0_GPIO50, + IMX_F1_GPIO50, + IMX_F2_GPIO50, + IMX_F3_GPIO50, + IMX_F0_GPIO51, + IMX_F1_GPIO51, + IMX_F2_GPIO51, + IMX_F3_GPIO51, + IMX_F0_GPIO52, + IMX_F1_GPIO52, + IMX_F2_GPIO52, + IMX_F3_GPIO52, + IMX_F0_GPIO53, + IMX_F1_GPIO53, + IMX_F2_GPIO53, + IMX_F3_GPIO53, + IMX_F0_GPIO54, + IMX_F1_GPIO54, + IMX_F2_GPIO54, + IMX_F3_GPIO54, + IMX_F0_GPIO55, + IMX_F1_GPIO55, + IMX_F2_GPIO55, + IMX_F3_GPIO55, + IMX_F0_GPIO56, + IMX_F1_GPIO56, + IMX_F2_GPIO56, + IMX_F3_GPIO56, + IMX_F0_GPIO57, + IMX_F1_GPIO57, + IMX_F2_GPIO57, + IMX_F3_GPIO57, + IMX_F0_GPIO58, + IMX_F1_GPIO58, + IMX_F2_GPIO58, + IMX_F3_GPIO58, + IMX_F0_GPIO59, + IMX_F1_GPIO59, + IMX_F2_GPIO59, + IMX_F3_GPIO59, + IMX_F0_GPIO60, + IMX_F1_GPIO60, + IMX_F2_GPIO60, + IMX_F3_GPIO60, + IMX_F0_GPIO61, + IMX_F1_GPIO61, + IMX_F2_GPIO61, + IMX_F3_GPIO61, + IMX_F0_GPIO62, + IMX_F1_GPIO62, + IMX_F2_GPIO62, + IMX_F3_GPIO62, + IMX_F0_GPIO64, + IMX_F1_GPIO64, + IMX_F2_GPIO64, + IMX_F3_GPIO64, + IMX_F0_GPIO65, + IMX_F1_GPIO65, + IMX_F2_GPIO65, + IMX_F3_GPIO65, + IMX_F0_GPIO66, + IMX_F1_GPIO66, + IMX_F2_GPIO66, + IMX_F3_GPIO66, + IMX_F0_GPIO67, + IMX_F1_GPIO67, + IMX_F2_GPIO67, + IMX_F3_GPIO67, + IMX_F0_GPIO68, + IMX_F1_GPIO68, + IMX_F2_GPIO68, + IMX_F3_GPIO68, + IMX_F0_GPIO69, + IMX_F1_GPIO69, + IMX_F2_GPIO69, + IMX_F3_GPIO69, + IMX_F0_GPIO70, + IMX_F1_GPIO70, + IMX_F2_GPIO70, + IMX_F3_GPIO70, + IMX_F0_GPIO71, + IMX_F1_GPIO71, + IMX_F2_GPIO71, + IMX_F3_GPIO71, + IMX_F0_GPIO72, + IMX_F1_GPIO72, + IMX_F2_GPIO72, + IMX_F3_GPIO72, + IMX_F0_GPIO73, + IMX_F1_GPIO73, + IMX_F2_GPIO73, + IMX_F3_GPIO73, + IMX_F0_GPIO74, + IMX_F1_GPIO74, + IMX_F2_GPIO74, + IMX_F3_GPIO74, + IMX_F0_GPIO75, + IMX_F1_GPIO75, + IMX_F2_GPIO75, + IMX_F3_GPIO75, + IMX_F0_GPIO76, + IMX_F1_GPIO76, + IMX_F2_GPIO76, + IMX_F3_GPIO76, + IMX_F0_GPIO77, + IMX_F1_GPIO77, + IMX_F2_GPIO77, + IMX_F3_GPIO77, + IMX_F0_GPIO78, + IMX_F1_GPIO78, + IMX_F2_GPIO78, + IMX_F3_GPIO78, + IMX_F0_GPIO79, + IMX_F1_GPIO79, + IMX_F2_GPIO79, + IMX_F3_GPIO79, + IMX_F0_GPIO80, + IMX_F1_GPIO80, + IMX_F2_GPIO80, + IMX_F3_GPIO80, + IMX_F0_GPIO81, + IMX_F1_GPIO81, + IMX_F2_GPIO81, + IMX_F3_GPIO81, + IMX_F0_GPIO82, + IMX_F1_GPIO82, + IMX_F2_GPIO82, + IMX_F3_GPIO82, + IMX_F0_GPIO83, + IMX_F1_GPIO83, + IMX_F2_GPIO83, + IMX_F3_GPIO83, + IMX_F0_GPIO84, + IMX_F1_GPIO84, + IMX_F2_GPIO84, + IMX_F3_GPIO84, + IMX_F0_GPIO85, + IMX_F1_GPIO85, + IMX_F2_GPIO85, + IMX_F3_GPIO85, + IMX_F0_GPIO86, + IMX_F1_GPIO86, + IMX_F2_GPIO86, + IMX_F3_GPIO86, + IMX_F0_GPIO87, + IMX_F1_GPIO87, + IMX_F2_GPIO87, + IMX_F3_GPIO87, + IMX_F0_GPIO88, + IMX_F1_GPIO88, + IMX_F2_GPIO88, + IMX_F3_GPIO88, + IMX_F0_GPIO89, + IMX_F1_GPIO89, + IMX_F2_GPIO89, + IMX_F3_GPIO89, + IMX_F0_GPIO90, + IMX_F1_GPIO90, + IMX_F2_GPIO90, + IMX_F3_GPIO90, + IMX_F0_GPIO91, + IMX_F1_GPIO91, + IMX_F2_GPIO91, + IMX_F3_GPIO91, + IMX_F0_GPIO92, + IMX_F1_GPIO92, + IMX_F2_GPIO92, + IMX_F3_GPIO92, + IMX_F0_GPIO93, + IMX_F1_GPIO93, + IMX_F2_GPIO93, + IMX_F3_GPIO93, + IMX_F0_GPIO94, + IMX_F1_GPIO94, + IMX_F2_GPIO94, + IMX_F3_GPIO94, + IMX_F0_GPIO95, + IMX_F1_GPIO95, + IMX_F2_GPIO95, + IMX_F3_GPIO95, + IMX_F0_GPIO96, + IMX_F1_GPIO96, + IMX_F2_GPIO96, + IMX_F3_GPIO96, + IMX_F0_GPIO97, + IMX_F1_GPIO97, + IMX_F2_GPIO97, + IMX_F3_GPIO97, + IMX_F0_GPIO98, + IMX_F1_GPIO98, + IMX_F2_GPIO98, + IMX_F3_GPIO98, + IMX_F0_GPIO99, + IMX_F1_GPIO99, + IMX_F2_GPIO99, + IMX_F3_GPIO99, + IMX_F0_GPIO100, + IMX_F1_GPIO100, + IMX_F2_GPIO100, + IMX_F3_GPIO100, + IMX_F0_GPIO101, + IMX_F1_GPIO101, + IMX_F2_GPIO101, + IMX_F3_GPIO101, + IMX_F0_GPIO102, + IMX_F1_GPIO102, + IMX_F2_GPIO102, + IMX_F3_GPIO102, + IMX_F0_GPIO103, + IMX_F1_GPIO103, + IMX_F2_GPIO103, + IMX_F3_GPIO103, + IMX_F0_GPIO104, + IMX_F1_GPIO104, + IMX_F2_GPIO104, + IMX_F3_GPIO104, + IMX_F0_GPIO105, + IMX_F1_GPIO105, + IMX_F2_GPIO105, + IMX_F3_GPIO105, + IMX_F0_GPIO106, + IMX_F1_GPIO106, + IMX_F2_GPIO106, + IMX_F3_GPIO106, + IMX_F0_GPIO107, + IMX_F1_GPIO107, + IMX_F2_GPIO107, + IMX_F3_GPIO107, + IMX_F0_GPIO108, + IMX_F1_GPIO108, + IMX_F2_GPIO108, + IMX_F3_GPIO108, + IMX_F0_GPIO109, + IMX_F1_GPIO109, + IMX_F2_GPIO109, + IMX_F3_GPIO109, + IMX_F0_GPIO110, + IMX_F1_GPIO110, + IMX_F2_GPIO110, + IMX_F3_GPIO110, + IMX_F0_GPIO111, + IMX_F1_GPIO111, + IMX_F2_GPIO111, + IMX_F3_GPIO111, + IMX_F0_GPIO112, + IMX_F1_GPIO112, + IMX_F2_GPIO112, + IMX_F3_GPIO112, + IMX_F0_GPIO113, + IMX_F1_GPIO113, + IMX_F2_GPIO113, + IMX_F3_GPIO113, + IMX_F0_GPIO114, + IMX_F1_GPIO114, + IMX_F2_GPIO114, + IMX_F3_GPIO114, + IMX_F0_GPIO115, + IMX_F1_GPIO115, + IMX_F2_GPIO115, + IMX_F3_GPIO115, + IMX_F0_GPIO116, + IMX_F1_GPIO116, + IMX_F2_GPIO116, + IMX_F3_GPIO116, + IMX_F0_GPIO117, + IMX_F1_GPIO117, + IMX_F2_GPIO117, + IMX_F3_GPIO117, + IMX_F0_GPIO118, + IMX_F1_GPIO118, + IMX_F2_GPIO118, + IMX_F3_GPIO118, + IMX_F0_GPIO119, + IMX_F1_GPIO119, + IMX_F2_GPIO119, + IMX_F3_GPIO119, + IMX_F0_GPIO120, + IMX_F1_GPIO120, + IMX_F2_GPIO120, + IMX_F3_GPIO120, + IMX_F0_GPIO121, + IMX_F1_GPIO121, + IMX_F2_GPIO121, + IMX_F3_GPIO121, + IMX_F0_GPIO122, + IMX_F1_GPIO122, + IMX_F2_GPIO122, + IMX_F3_GPIO122, + IMX_F0_GPIO123, + IMX_F1_GPIO123, + IMX_F2_GPIO123, + IMX_F3_GPIO123, + IMX_F0_GPIO124, + IMX_F1_GPIO124, + IMX_F2_GPIO124, + IMX_F3_GPIO124, + IMX_F0_GPIO125, + IMX_F1_GPIO125, + IMX_F2_GPIO125, + IMX_F3_GPIO125, + IMX_F0_GPIO126, + IMX_F1_GPIO126, + IMX_F2_GPIO126, + IMX_F3_GPIO126, + IMX_F0_GPIO127, + IMX_F1_GPIO127, + IMX_F2_GPIO127, + IMX_F3_GPIO127, + IMX_F0_GPIO128, + IMX_F1_GPIO128, + IMX_F2_GPIO128, + IMX_F3_GPIO128, + IMX_F0_GPIO129, + IMX_F1_GPIO129, + IMX_F2_GPIO129, + IMX_F3_GPIO129, + IMX_F0_GPIO130, + IMX_F1_GPIO130, + IMX_F2_GPIO130, + IMX_F3_GPIO130, + IMX_F0_GPIO131, + IMX_F1_GPIO131, + IMX_F2_GPIO131, + IMX_F3_GPIO131, + IMX_F0_GPIO132, + IMX_F1_GPIO132, + IMX_F2_GPIO132, + IMX_F3_GPIO132, + IMX_F0_GPIO133, + IMX_F1_GPIO133, + IMX_F2_GPIO133, + IMX_F3_GPIO133, + IMX_F0_GPIO134, + IMX_F1_GPIO134, + IMX_F2_GPIO134, + IMX_F3_GPIO134, + IMX_F0_GPIO135, + IMX_F1_GPIO135, + IMX_F2_GPIO135, + IMX_F3_GPIO135, + IMX_F0_GPIO136, + IMX_F1_GPIO136, + IMX_F2_GPIO136, + IMX_F3_GPIO136, + IMX_F0_GPIO137, + IMX_F1_GPIO137, + IMX_F2_GPIO137, + IMX_F3_GPIO137, + IMX_F0_GPIO138, + IMX_F1_GPIO138, + IMX_F2_GPIO138, + IMX_F3_GPIO138, + IMX_F0_GPIO139, + IMX_F1_GPIO139, + IMX_F2_GPIO139, + IMX_F3_GPIO139, + IMX_F0_GPIO140, + IMX_F1_GPIO140, + IMX_F2_GPIO140, + IMX_F3_GPIO140, + IMX_F0_GPIO141, + IMX_F1_GPIO141, + IMX_F2_GPIO141, + IMX_F3_GPIO141, + IMX_F0_GPIO142, + IMX_F1_GPIO142, + IMX_F2_GPIO142, + IMX_F3_GPIO142, + IMX_F0_GPIO143, + IMX_F1_GPIO143, + IMX_F2_GPIO143, + IMX_F3_GPIO143, + IMX_F0_GPIO144, + IMX_F1_GPIO144, + IMX_F2_GPIO144, + IMX_F3_GPIO144, +}; + +#define AMD_PINCTRL_FUNC_GRP(_number, _func) \ + [IMX_F##_func##_GPIO##_number] = \ + PINCTRL_PINGROUP("IMX_F"#_func "_GPIO"#_number, AMD_PINS(_number), 1) + +static const struct pingroup kerncz_groups[] = { + AMD_PINCTRL_FUNC_GRP(0, 0), + AMD_PINCTRL_FUNC_GRP(0, 1), + AMD_PINCTRL_FUNC_GRP(0, 2), + AMD_PINCTRL_FUNC_GRP(0, 3), + AMD_PINCTRL_FUNC_GRP(1, 0), + AMD_PINCTRL_FUNC_GRP(1, 1), + AMD_PINCTRL_FUNC_GRP(1, 2), + AMD_PINCTRL_FUNC_GRP(1, 3), + AMD_PINCTRL_FUNC_GRP(2, 0), + AMD_PINCTRL_FUNC_GRP(2, 1), + AMD_PINCTRL_FUNC_GRP(2, 2), + AMD_PINCTRL_FUNC_GRP(2, 3), + AMD_PINCTRL_FUNC_GRP(3, 0), + AMD_PINCTRL_FUNC_GRP(3, 1), + AMD_PINCTRL_FUNC_GRP(3, 2), + AMD_PINCTRL_FUNC_GRP(3, 3), + AMD_PINCTRL_FUNC_GRP(4, 0), + AMD_PINCTRL_FUNC_GRP(4, 1), + AMD_PINCTRL_FUNC_GRP(4, 2), + AMD_PINCTRL_FUNC_GRP(4, 3), + AMD_PINCTRL_FUNC_GRP(5, 0), + AMD_PINCTRL_FUNC_GRP(5, 1), + AMD_PINCTRL_FUNC_GRP(5, 2), + AMD_PINCTRL_FUNC_GRP(5, 3), + AMD_PINCTRL_FUNC_GRP(6, 0), + AMD_PINCTRL_FUNC_GRP(6, 1), + AMD_PINCTRL_FUNC_GRP(6, 2), + AMD_PINCTRL_FUNC_GRP(6, 3), + AMD_PINCTRL_FUNC_GRP(7, 0), + AMD_PINCTRL_FUNC_GRP(7, 1), + AMD_PINCTRL_FUNC_GRP(7, 2), + AMD_PINCTRL_FUNC_GRP(7, 3), + AMD_PINCTRL_FUNC_GRP(8, 0), + AMD_PINCTRL_FUNC_GRP(8, 1), + AMD_PINCTRL_FUNC_GRP(8, 2), + AMD_PINCTRL_FUNC_GRP(8, 3), + AMD_PINCTRL_FUNC_GRP(9, 0), + AMD_PINCTRL_FUNC_GRP(9, 1), + AMD_PINCTRL_FUNC_GRP(9, 2), + AMD_PINCTRL_FUNC_GRP(9, 3), + AMD_PINCTRL_FUNC_GRP(10, 0), + AMD_PINCTRL_FUNC_GRP(10, 1), + AMD_PINCTRL_FUNC_GRP(10, 2), + AMD_PINCTRL_FUNC_GRP(10, 3), + AMD_PINCTRL_FUNC_GRP(11, 0), + AMD_PINCTRL_FUNC_GRP(11, 1), + AMD_PINCTRL_FUNC_GRP(11, 2), + AMD_PINCTRL_FUNC_GRP(11, 3), + AMD_PINCTRL_FUNC_GRP(12, 0), + AMD_PINCTRL_FUNC_GRP(12, 1), + AMD_PINCTRL_FUNC_GRP(12, 2), + AMD_PINCTRL_FUNC_GRP(12, 3), + AMD_PINCTRL_FUNC_GRP(13, 0), + AMD_PINCTRL_FUNC_GRP(13, 1), + AMD_PINCTRL_FUNC_GRP(13, 2), + AMD_PINCTRL_FUNC_GRP(13, 3), + AMD_PINCTRL_FUNC_GRP(14, 0), + AMD_PINCTRL_FUNC_GRP(14, 1), + AMD_PINCTRL_FUNC_GRP(14, 2), + AMD_PINCTRL_FUNC_GRP(14, 3), + AMD_PINCTRL_FUNC_GRP(15, 0), + AMD_PINCTRL_FUNC_GRP(15, 1), + AMD_PINCTRL_FUNC_GRP(15, 2), + AMD_PINCTRL_FUNC_GRP(15, 3), + AMD_PINCTRL_FUNC_GRP(16, 0), + AMD_PINCTRL_FUNC_GRP(16, 1), + AMD_PINCTRL_FUNC_GRP(16, 2), + AMD_PINCTRL_FUNC_GRP(16, 3), + AMD_PINCTRL_FUNC_GRP(17, 0), + AMD_PINCTRL_FUNC_GRP(17, 1), + AMD_PINCTRL_FUNC_GRP(17, 2), + AMD_PINCTRL_FUNC_GRP(17, 3), + AMD_PINCTRL_FUNC_GRP(18, 0), + AMD_PINCTRL_FUNC_GRP(18, 1), + AMD_PINCTRL_FUNC_GRP(18, 2), + AMD_PINCTRL_FUNC_GRP(18, 3), + AMD_PINCTRL_FUNC_GRP(19, 0), + AMD_PINCTRL_FUNC_GRP(19, 1), + AMD_PINCTRL_FUNC_GRP(19, 2), + AMD_PINCTRL_FUNC_GRP(19, 3), + AMD_PINCTRL_FUNC_GRP(20, 0), + AMD_PINCTRL_FUNC_GRP(20, 1), + AMD_PINCTRL_FUNC_GRP(20, 2), + AMD_PINCTRL_FUNC_GRP(20, 3), + AMD_PINCTRL_FUNC_GRP(21, 0), + AMD_PINCTRL_FUNC_GRP(21, 1), + AMD_PINCTRL_FUNC_GRP(21, 2), + AMD_PINCTRL_FUNC_GRP(21, 3), + AMD_PINCTRL_FUNC_GRP(22, 0), + AMD_PINCTRL_FUNC_GRP(22, 1), + AMD_PINCTRL_FUNC_GRP(22, 2), + AMD_PINCTRL_FUNC_GRP(22, 3), + AMD_PINCTRL_FUNC_GRP(23, 0), + AMD_PINCTRL_FUNC_GRP(23, 1), + AMD_PINCTRL_FUNC_GRP(23, 2), + AMD_PINCTRL_FUNC_GRP(23, 3), + AMD_PINCTRL_FUNC_GRP(24, 0), + AMD_PINCTRL_FUNC_GRP(24, 1), + AMD_PINCTRL_FUNC_GRP(24, 2), + AMD_PINCTRL_FUNC_GRP(24, 3), + AMD_PINCTRL_FUNC_GRP(25, 0), + AMD_PINCTRL_FUNC_GRP(25, 1), + AMD_PINCTRL_FUNC_GRP(25, 2), + AMD_PINCTRL_FUNC_GRP(25, 3), + AMD_PINCTRL_FUNC_GRP(26, 0), + AMD_PINCTRL_FUNC_GRP(26, 1), + AMD_PINCTRL_FUNC_GRP(26, 2), + AMD_PINCTRL_FUNC_GRP(26, 3), + AMD_PINCTRL_FUNC_GRP(27, 0), + AMD_PINCTRL_FUNC_GRP(27, 1), + AMD_PINCTRL_FUNC_GRP(27, 2), + AMD_PINCTRL_FUNC_GRP(27, 3), + AMD_PINCTRL_FUNC_GRP(28, 0), + AMD_PINCTRL_FUNC_GRP(28, 1), + AMD_PINCTRL_FUNC_GRP(28, 2), + AMD_PINCTRL_FUNC_GRP(28, 3), + AMD_PINCTRL_FUNC_GRP(29, 0), + AMD_PINCTRL_FUNC_GRP(29, 1), + AMD_PINCTRL_FUNC_GRP(29, 2), + AMD_PINCTRL_FUNC_GRP(29, 3), + AMD_PINCTRL_FUNC_GRP(30, 0), + AMD_PINCTRL_FUNC_GRP(30, 1), + AMD_PINCTRL_FUNC_GRP(30, 2), + AMD_PINCTRL_FUNC_GRP(30, 3), + AMD_PINCTRL_FUNC_GRP(31, 0), + AMD_PINCTRL_FUNC_GRP(31, 1), + AMD_PINCTRL_FUNC_GRP(31, 2), + AMD_PINCTRL_FUNC_GRP(31, 3), + AMD_PINCTRL_FUNC_GRP(32, 0), + AMD_PINCTRL_FUNC_GRP(32, 1), + AMD_PINCTRL_FUNC_GRP(32, 2), + AMD_PINCTRL_FUNC_GRP(32, 3), + AMD_PINCTRL_FUNC_GRP(33, 0), + AMD_PINCTRL_FUNC_GRP(33, 1), + AMD_PINCTRL_FUNC_GRP(33, 2), + AMD_PINCTRL_FUNC_GRP(33, 3), + AMD_PINCTRL_FUNC_GRP(34, 0), + AMD_PINCTRL_FUNC_GRP(34, 1), + AMD_PINCTRL_FUNC_GRP(34, 2), + AMD_PINCTRL_FUNC_GRP(34, 3), + AMD_PINCTRL_FUNC_GRP(35, 0), + AMD_PINCTRL_FUNC_GRP(35, 1), + AMD_PINCTRL_FUNC_GRP(35, 2), + AMD_PINCTRL_FUNC_GRP(35, 3), + AMD_PINCTRL_FUNC_GRP(36, 0), + AMD_PINCTRL_FUNC_GRP(36, 1), + AMD_PINCTRL_FUNC_GRP(36, 2), + AMD_PINCTRL_FUNC_GRP(36, 3), + AMD_PINCTRL_FUNC_GRP(37, 0), + AMD_PINCTRL_FUNC_GRP(37, 1), + AMD_PINCTRL_FUNC_GRP(37, 2), + AMD_PINCTRL_FUNC_GRP(37, 3), + AMD_PINCTRL_FUNC_GRP(38, 0), + AMD_PINCTRL_FUNC_GRP(38, 1), + AMD_PINCTRL_FUNC_GRP(38, 2), + AMD_PINCTRL_FUNC_GRP(38, 3), + AMD_PINCTRL_FUNC_GRP(39, 0), + AMD_PINCTRL_FUNC_GRP(39, 1), + AMD_PINCTRL_FUNC_GRP(39, 2), + AMD_PINCTRL_FUNC_GRP(39, 3), + AMD_PINCTRL_FUNC_GRP(40, 0), + AMD_PINCTRL_FUNC_GRP(40, 1), + AMD_PINCTRL_FUNC_GRP(40, 2), + AMD_PINCTRL_FUNC_GRP(40, 3), + AMD_PINCTRL_FUNC_GRP(41, 0), + AMD_PINCTRL_FUNC_GRP(41, 1), + AMD_PINCTRL_FUNC_GRP(41, 2), + AMD_PINCTRL_FUNC_GRP(41, 3), + AMD_PINCTRL_FUNC_GRP(42, 0), + AMD_PINCTRL_FUNC_GRP(42, 1), + AMD_PINCTRL_FUNC_GRP(42, 2), + AMD_PINCTRL_FUNC_GRP(42, 3), + AMD_PINCTRL_FUNC_GRP(43, 0), + AMD_PINCTRL_FUNC_GRP(43, 1), + AMD_PINCTRL_FUNC_GRP(43, 2), + AMD_PINCTRL_FUNC_GRP(43, 3), + AMD_PINCTRL_FUNC_GRP(44, 0), + AMD_PINCTRL_FUNC_GRP(44, 1), + AMD_PINCTRL_FUNC_GRP(44, 2), + AMD_PINCTRL_FUNC_GRP(44, 3), + AMD_PINCTRL_FUNC_GRP(45, 0), + AMD_PINCTRL_FUNC_GRP(45, 1), + AMD_PINCTRL_FUNC_GRP(45, 2), + AMD_PINCTRL_FUNC_GRP(45, 3), + AMD_PINCTRL_FUNC_GRP(46, 0), + AMD_PINCTRL_FUNC_GRP(46, 1), + AMD_PINCTRL_FUNC_GRP(46, 2), + AMD_PINCTRL_FUNC_GRP(46, 3), + AMD_PINCTRL_FUNC_GRP(47, 0), + AMD_PINCTRL_FUNC_GRP(47, 1), + AMD_PINCTRL_FUNC_GRP(47, 2), + AMD_PINCTRL_FUNC_GRP(47, 3), + AMD_PINCTRL_FUNC_GRP(48, 0), + AMD_PINCTRL_FUNC_GRP(48, 1), + AMD_PINCTRL_FUNC_GRP(48, 2), + AMD_PINCTRL_FUNC_GRP(48, 3), + AMD_PINCTRL_FUNC_GRP(49, 0), + AMD_PINCTRL_FUNC_GRP(49, 1), + AMD_PINCTRL_FUNC_GRP(49, 2), + AMD_PINCTRL_FUNC_GRP(49, 3), + AMD_PINCTRL_FUNC_GRP(50, 0), + AMD_PINCTRL_FUNC_GRP(50, 1), + AMD_PINCTRL_FUNC_GRP(50, 2), + AMD_PINCTRL_FUNC_GRP(50, 3), + AMD_PINCTRL_FUNC_GRP(51, 0), + AMD_PINCTRL_FUNC_GRP(51, 1), + AMD_PINCTRL_FUNC_GRP(51, 2), + AMD_PINCTRL_FUNC_GRP(51, 3), + AMD_PINCTRL_FUNC_GRP(52, 0), + AMD_PINCTRL_FUNC_GRP(52, 1), + AMD_PINCTRL_FUNC_GRP(52, 2), + AMD_PINCTRL_FUNC_GRP(52, 3), + AMD_PINCTRL_FUNC_GRP(53, 0), + AMD_PINCTRL_FUNC_GRP(53, 1), + AMD_PINCTRL_FUNC_GRP(53, 2), + AMD_PINCTRL_FUNC_GRP(53, 3), + AMD_PINCTRL_FUNC_GRP(54, 0), + AMD_PINCTRL_FUNC_GRP(54, 1), + AMD_PINCTRL_FUNC_GRP(54, 2), + AMD_PINCTRL_FUNC_GRP(54, 3), + AMD_PINCTRL_FUNC_GRP(55, 0), + AMD_PINCTRL_FUNC_GRP(55, 1), + AMD_PINCTRL_FUNC_GRP(55, 2), + AMD_PINCTRL_FUNC_GRP(55, 3), + AMD_PINCTRL_FUNC_GRP(56, 0), + AMD_PINCTRL_FUNC_GRP(56, 1), + AMD_PINCTRL_FUNC_GRP(56, 2), + AMD_PINCTRL_FUNC_GRP(56, 3), + AMD_PINCTRL_FUNC_GRP(57, 0), + AMD_PINCTRL_FUNC_GRP(57, 1), + AMD_PINCTRL_FUNC_GRP(57, 2), + AMD_PINCTRL_FUNC_GRP(57, 3), + AMD_PINCTRL_FUNC_GRP(58, 0), + AMD_PINCTRL_FUNC_GRP(58, 1), + AMD_PINCTRL_FUNC_GRP(58, 2), + AMD_PINCTRL_FUNC_GRP(58, 3), + AMD_PINCTRL_FUNC_GRP(59, 0), + AMD_PINCTRL_FUNC_GRP(59, 1), + AMD_PINCTRL_FUNC_GRP(59, 2), + AMD_PINCTRL_FUNC_GRP(59, 3), + AMD_PINCTRL_FUNC_GRP(60, 0), + AMD_PINCTRL_FUNC_GRP(60, 1), + AMD_PINCTRL_FUNC_GRP(60, 2), + AMD_PINCTRL_FUNC_GRP(60, 3), + AMD_PINCTRL_FUNC_GRP(61, 0), + AMD_PINCTRL_FUNC_GRP(61, 1), + AMD_PINCTRL_FUNC_GRP(61, 2), + AMD_PINCTRL_FUNC_GRP(61, 3), + AMD_PINCTRL_FUNC_GRP(62, 0), + AMD_PINCTRL_FUNC_GRP(62, 1), + AMD_PINCTRL_FUNC_GRP(62, 2), + AMD_PINCTRL_FUNC_GRP(62, 3), + AMD_PINCTRL_FUNC_GRP(64, 0), + AMD_PINCTRL_FUNC_GRP(64, 1), + AMD_PINCTRL_FUNC_GRP(64, 2), + AMD_PINCTRL_FUNC_GRP(64, 3), + AMD_PINCTRL_FUNC_GRP(65, 0), + AMD_PINCTRL_FUNC_GRP(65, 1), + AMD_PINCTRL_FUNC_GRP(65, 2), + AMD_PINCTRL_FUNC_GRP(65, 3), + AMD_PINCTRL_FUNC_GRP(66, 0), + AMD_PINCTRL_FUNC_GRP(66, 1), + AMD_PINCTRL_FUNC_GRP(66, 2), + AMD_PINCTRL_FUNC_GRP(66, 3), + AMD_PINCTRL_FUNC_GRP(67, 0), + AMD_PINCTRL_FUNC_GRP(67, 1), + AMD_PINCTRL_FUNC_GRP(67, 2), + AMD_PINCTRL_FUNC_GRP(67, 3), + AMD_PINCTRL_FUNC_GRP(68, 0), + AMD_PINCTRL_FUNC_GRP(68, 1), + AMD_PINCTRL_FUNC_GRP(68, 2), + AMD_PINCTRL_FUNC_GRP(68, 3), + AMD_PINCTRL_FUNC_GRP(69, 0), + AMD_PINCTRL_FUNC_GRP(69, 1), + AMD_PINCTRL_FUNC_GRP(69, 2), + AMD_PINCTRL_FUNC_GRP(69, 3), + AMD_PINCTRL_FUNC_GRP(70, 0), + AMD_PINCTRL_FUNC_GRP(70, 1), + AMD_PINCTRL_FUNC_GRP(70, 2), + AMD_PINCTRL_FUNC_GRP(70, 3), + AMD_PINCTRL_FUNC_GRP(71, 0), + AMD_PINCTRL_FUNC_GRP(71, 1), + AMD_PINCTRL_FUNC_GRP(71, 2), + AMD_PINCTRL_FUNC_GRP(71, 3), + AMD_PINCTRL_FUNC_GRP(72, 0), + AMD_PINCTRL_FUNC_GRP(72, 1), + AMD_PINCTRL_FUNC_GRP(72, 2), + AMD_PINCTRL_FUNC_GRP(72, 3), + AMD_PINCTRL_FUNC_GRP(73, 0), + AMD_PINCTRL_FUNC_GRP(73, 1), + AMD_PINCTRL_FUNC_GRP(73, 2), + AMD_PINCTRL_FUNC_GRP(73, 3), + AMD_PINCTRL_FUNC_GRP(74, 0), + AMD_PINCTRL_FUNC_GRP(74, 1), + AMD_PINCTRL_FUNC_GRP(74, 2), + AMD_PINCTRL_FUNC_GRP(74, 3), + AMD_PINCTRL_FUNC_GRP(75, 0), + AMD_PINCTRL_FUNC_GRP(75, 1), + AMD_PINCTRL_FUNC_GRP(75, 2), + AMD_PINCTRL_FUNC_GRP(75, 3), + AMD_PINCTRL_FUNC_GRP(76, 0), + AMD_PINCTRL_FUNC_GRP(76, 1), + AMD_PINCTRL_FUNC_GRP(76, 2), + AMD_PINCTRL_FUNC_GRP(76, 3), + AMD_PINCTRL_FUNC_GRP(77, 0), + AMD_PINCTRL_FUNC_GRP(77, 1), + AMD_PINCTRL_FUNC_GRP(77, 2), + AMD_PINCTRL_FUNC_GRP(77, 3), + AMD_PINCTRL_FUNC_GRP(78, 0), + AMD_PINCTRL_FUNC_GRP(78, 1), + AMD_PINCTRL_FUNC_GRP(78, 2), + AMD_PINCTRL_FUNC_GRP(78, 3), + AMD_PINCTRL_FUNC_GRP(79, 0), + AMD_PINCTRL_FUNC_GRP(79, 1), + AMD_PINCTRL_FUNC_GRP(79, 2), + AMD_PINCTRL_FUNC_GRP(79, 3), + AMD_PINCTRL_FUNC_GRP(80, 0), + AMD_PINCTRL_FUNC_GRP(80, 1), + AMD_PINCTRL_FUNC_GRP(80, 2), + AMD_PINCTRL_FUNC_GRP(80, 3), + AMD_PINCTRL_FUNC_GRP(81, 0), + AMD_PINCTRL_FUNC_GRP(81, 1), + AMD_PINCTRL_FUNC_GRP(81, 2), + AMD_PINCTRL_FUNC_GRP(81, 3), + AMD_PINCTRL_FUNC_GRP(82, 0), + AMD_PINCTRL_FUNC_GRP(82, 1), + AMD_PINCTRL_FUNC_GRP(82, 2), + AMD_PINCTRL_FUNC_GRP(82, 3), + AMD_PINCTRL_FUNC_GRP(83, 0), + AMD_PINCTRL_FUNC_GRP(83, 1), + AMD_PINCTRL_FUNC_GRP(83, 2), + AMD_PINCTRL_FUNC_GRP(83, 3), + AMD_PINCTRL_FUNC_GRP(84, 0), + AMD_PINCTRL_FUNC_GRP(84, 1), + AMD_PINCTRL_FUNC_GRP(84, 2), + AMD_PINCTRL_FUNC_GRP(84, 3), + AMD_PINCTRL_FUNC_GRP(85, 0), + AMD_PINCTRL_FUNC_GRP(85, 1), + AMD_PINCTRL_FUNC_GRP(85, 2), + AMD_PINCTRL_FUNC_GRP(85, 3), + AMD_PINCTRL_FUNC_GRP(86, 0), + AMD_PINCTRL_FUNC_GRP(86, 1), + AMD_PINCTRL_FUNC_GRP(86, 2), + AMD_PINCTRL_FUNC_GRP(86, 3), + AMD_PINCTRL_FUNC_GRP(87, 0), + AMD_PINCTRL_FUNC_GRP(87, 1), + AMD_PINCTRL_FUNC_GRP(87, 2), + AMD_PINCTRL_FUNC_GRP(87, 3), + AMD_PINCTRL_FUNC_GRP(88, 0), + AMD_PINCTRL_FUNC_GRP(88, 1), + AMD_PINCTRL_FUNC_GRP(88, 2), + AMD_PINCTRL_FUNC_GRP(88, 3), + AMD_PINCTRL_FUNC_GRP(89, 0), + AMD_PINCTRL_FUNC_GRP(89, 1), + AMD_PINCTRL_FUNC_GRP(89, 2), + AMD_PINCTRL_FUNC_GRP(89, 3), + AMD_PINCTRL_FUNC_GRP(90, 0), + AMD_PINCTRL_FUNC_GRP(90, 1), + AMD_PINCTRL_FUNC_GRP(90, 2), + AMD_PINCTRL_FUNC_GRP(90, 3), + AMD_PINCTRL_FUNC_GRP(91, 0), + AMD_PINCTRL_FUNC_GRP(91, 1), + AMD_PINCTRL_FUNC_GRP(91, 2), + AMD_PINCTRL_FUNC_GRP(91, 3), + AMD_PINCTRL_FUNC_GRP(92, 0), + AMD_PINCTRL_FUNC_GRP(92, 1), + AMD_PINCTRL_FUNC_GRP(92, 2), + AMD_PINCTRL_FUNC_GRP(92, 3), + AMD_PINCTRL_FUNC_GRP(93, 0), + AMD_PINCTRL_FUNC_GRP(93, 1), + AMD_PINCTRL_FUNC_GRP(93, 2), + AMD_PINCTRL_FUNC_GRP(93, 3), + AMD_PINCTRL_FUNC_GRP(94, 0), + AMD_PINCTRL_FUNC_GRP(94, 1), + AMD_PINCTRL_FUNC_GRP(94, 2), + AMD_PINCTRL_FUNC_GRP(94, 3), + AMD_PINCTRL_FUNC_GRP(95, 0), + AMD_PINCTRL_FUNC_GRP(95, 1), + AMD_PINCTRL_FUNC_GRP(95, 2), + AMD_PINCTRL_FUNC_GRP(95, 3), + AMD_PINCTRL_FUNC_GRP(96, 0), + AMD_PINCTRL_FUNC_GRP(96, 1), + AMD_PINCTRL_FUNC_GRP(96, 2), + AMD_PINCTRL_FUNC_GRP(96, 3), + AMD_PINCTRL_FUNC_GRP(97, 0), + AMD_PINCTRL_FUNC_GRP(97, 1), + AMD_PINCTRL_FUNC_GRP(97, 2), + AMD_PINCTRL_FUNC_GRP(97, 3), + AMD_PINCTRL_FUNC_GRP(98, 0), + AMD_PINCTRL_FUNC_GRP(98, 1), + AMD_PINCTRL_FUNC_GRP(98, 2), + AMD_PINCTRL_FUNC_GRP(98, 3), + AMD_PINCTRL_FUNC_GRP(99, 0), + AMD_PINCTRL_FUNC_GRP(99, 1), + AMD_PINCTRL_FUNC_GRP(99, 2), + AMD_PINCTRL_FUNC_GRP(99, 3), + AMD_PINCTRL_FUNC_GRP(100, 0), + AMD_PINCTRL_FUNC_GRP(100, 1), + AMD_PINCTRL_FUNC_GRP(100, 2), + AMD_PINCTRL_FUNC_GRP(100, 3), + AMD_PINCTRL_FUNC_GRP(101, 0), + AMD_PINCTRL_FUNC_GRP(101, 1), + AMD_PINCTRL_FUNC_GRP(101, 2), + AMD_PINCTRL_FUNC_GRP(101, 3), + AMD_PINCTRL_FUNC_GRP(102, 0), + AMD_PINCTRL_FUNC_GRP(102, 1), + AMD_PINCTRL_FUNC_GRP(102, 2), + AMD_PINCTRL_FUNC_GRP(102, 3), + AMD_PINCTRL_FUNC_GRP(103, 0), + AMD_PINCTRL_FUNC_GRP(103, 1), + AMD_PINCTRL_FUNC_GRP(103, 2), + AMD_PINCTRL_FUNC_GRP(103, 3), + AMD_PINCTRL_FUNC_GRP(104, 0), + AMD_PINCTRL_FUNC_GRP(104, 1), + AMD_PINCTRL_FUNC_GRP(104, 2), + AMD_PINCTRL_FUNC_GRP(104, 3), + AMD_PINCTRL_FUNC_GRP(105, 0), + AMD_PINCTRL_FUNC_GRP(105, 1), + AMD_PINCTRL_FUNC_GRP(105, 2), + AMD_PINCTRL_FUNC_GRP(105, 3), + AMD_PINCTRL_FUNC_GRP(106, 0), + AMD_PINCTRL_FUNC_GRP(106, 1), + AMD_PINCTRL_FUNC_GRP(106, 2), + AMD_PINCTRL_FUNC_GRP(106, 3), + AMD_PINCTRL_FUNC_GRP(107, 0), + AMD_PINCTRL_FUNC_GRP(107, 1), + AMD_PINCTRL_FUNC_GRP(107, 2), + AMD_PINCTRL_FUNC_GRP(107, 3), + AMD_PINCTRL_FUNC_GRP(108, 0), + AMD_PINCTRL_FUNC_GRP(108, 1), + AMD_PINCTRL_FUNC_GRP(108, 2), + AMD_PINCTRL_FUNC_GRP(108, 3), + AMD_PINCTRL_FUNC_GRP(109, 0), + AMD_PINCTRL_FUNC_GRP(109, 1), + AMD_PINCTRL_FUNC_GRP(109, 2), + AMD_PINCTRL_FUNC_GRP(109, 3), + AMD_PINCTRL_FUNC_GRP(110, 0), + AMD_PINCTRL_FUNC_GRP(110, 1), + AMD_PINCTRL_FUNC_GRP(110, 2), + AMD_PINCTRL_FUNC_GRP(110, 3), + AMD_PINCTRL_FUNC_GRP(111, 0), + AMD_PINCTRL_FUNC_GRP(111, 1), + AMD_PINCTRL_FUNC_GRP(111, 2), + AMD_PINCTRL_FUNC_GRP(111, 3), + AMD_PINCTRL_FUNC_GRP(112, 0), + AMD_PINCTRL_FUNC_GRP(112, 1), + AMD_PINCTRL_FUNC_GRP(112, 2), + AMD_PINCTRL_FUNC_GRP(112, 3), + AMD_PINCTRL_FUNC_GRP(113, 0), + AMD_PINCTRL_FUNC_GRP(113, 1), + AMD_PINCTRL_FUNC_GRP(113, 2), + AMD_PINCTRL_FUNC_GRP(113, 3), + AMD_PINCTRL_FUNC_GRP(114, 0), + AMD_PINCTRL_FUNC_GRP(114, 1), + AMD_PINCTRL_FUNC_GRP(114, 2), + AMD_PINCTRL_FUNC_GRP(114, 3), + AMD_PINCTRL_FUNC_GRP(115, 0), + AMD_PINCTRL_FUNC_GRP(115, 1), + AMD_PINCTRL_FUNC_GRP(115, 2), + AMD_PINCTRL_FUNC_GRP(115, 3), + AMD_PINCTRL_FUNC_GRP(116, 0), + AMD_PINCTRL_FUNC_GRP(116, 1), + AMD_PINCTRL_FUNC_GRP(116, 2), + AMD_PINCTRL_FUNC_GRP(116, 3), + AMD_PINCTRL_FUNC_GRP(117, 0), + AMD_PINCTRL_FUNC_GRP(117, 1), + AMD_PINCTRL_FUNC_GRP(117, 2), + AMD_PINCTRL_FUNC_GRP(117, 3), + AMD_PINCTRL_FUNC_GRP(118, 0), + AMD_PINCTRL_FUNC_GRP(118, 1), + AMD_PINCTRL_FUNC_GRP(118, 2), + AMD_PINCTRL_FUNC_GRP(118, 3), + AMD_PINCTRL_FUNC_GRP(119, 0), + AMD_PINCTRL_FUNC_GRP(119, 1), + AMD_PINCTRL_FUNC_GRP(119, 2), + AMD_PINCTRL_FUNC_GRP(119, 3), + AMD_PINCTRL_FUNC_GRP(120, 0), + AMD_PINCTRL_FUNC_GRP(120, 1), + AMD_PINCTRL_FUNC_GRP(120, 2), + AMD_PINCTRL_FUNC_GRP(120, 3), + AMD_PINCTRL_FUNC_GRP(121, 0), + AMD_PINCTRL_FUNC_GRP(121, 1), + AMD_PINCTRL_FUNC_GRP(121, 2), + AMD_PINCTRL_FUNC_GRP(121, 3), + AMD_PINCTRL_FUNC_GRP(122, 0), + AMD_PINCTRL_FUNC_GRP(122, 1), + AMD_PINCTRL_FUNC_GRP(122, 2), + AMD_PINCTRL_FUNC_GRP(122, 3), + AMD_PINCTRL_FUNC_GRP(123, 0), + AMD_PINCTRL_FUNC_GRP(123, 1), + AMD_PINCTRL_FUNC_GRP(123, 2), + AMD_PINCTRL_FUNC_GRP(123, 3), + AMD_PINCTRL_FUNC_GRP(124, 0), + AMD_PINCTRL_FUNC_GRP(124, 1), + AMD_PINCTRL_FUNC_GRP(124, 2), + AMD_PINCTRL_FUNC_GRP(124, 3), + AMD_PINCTRL_FUNC_GRP(125, 0), + AMD_PINCTRL_FUNC_GRP(125, 1), + AMD_PINCTRL_FUNC_GRP(125, 2), + AMD_PINCTRL_FUNC_GRP(125, 3), + AMD_PINCTRL_FUNC_GRP(126, 0), + AMD_PINCTRL_FUNC_GRP(126, 1), + AMD_PINCTRL_FUNC_GRP(126, 2), + AMD_PINCTRL_FUNC_GRP(126, 3), + AMD_PINCTRL_FUNC_GRP(127, 0), + AMD_PINCTRL_FUNC_GRP(127, 1), + AMD_PINCTRL_FUNC_GRP(127, 2), + AMD_PINCTRL_FUNC_GRP(127, 3), + AMD_PINCTRL_FUNC_GRP(128, 0), + AMD_PINCTRL_FUNC_GRP(128, 1), + AMD_PINCTRL_FUNC_GRP(128, 2), + AMD_PINCTRL_FUNC_GRP(128, 3), + AMD_PINCTRL_FUNC_GRP(129, 0), + AMD_PINCTRL_FUNC_GRP(129, 1), + AMD_PINCTRL_FUNC_GRP(129, 2), + AMD_PINCTRL_FUNC_GRP(129, 3), + AMD_PINCTRL_FUNC_GRP(130, 0), + AMD_PINCTRL_FUNC_GRP(130, 1), + AMD_PINCTRL_FUNC_GRP(130, 2), + AMD_PINCTRL_FUNC_GRP(130, 3), + AMD_PINCTRL_FUNC_GRP(131, 0), + AMD_PINCTRL_FUNC_GRP(131, 1), + AMD_PINCTRL_FUNC_GRP(131, 2), + AMD_PINCTRL_FUNC_GRP(131, 3), + AMD_PINCTRL_FUNC_GRP(132, 0), + AMD_PINCTRL_FUNC_GRP(132, 1), + AMD_PINCTRL_FUNC_GRP(132, 2), + AMD_PINCTRL_FUNC_GRP(132, 3), + AMD_PINCTRL_FUNC_GRP(133, 0), + AMD_PINCTRL_FUNC_GRP(133, 1), + AMD_PINCTRL_FUNC_GRP(133, 2), + AMD_PINCTRL_FUNC_GRP(133, 3), + AMD_PINCTRL_FUNC_GRP(134, 0), + AMD_PINCTRL_FUNC_GRP(134, 1), + AMD_PINCTRL_FUNC_GRP(134, 2), + AMD_PINCTRL_FUNC_GRP(134, 3), + AMD_PINCTRL_FUNC_GRP(135, 0), + AMD_PINCTRL_FUNC_GRP(135, 1), + AMD_PINCTRL_FUNC_GRP(135, 2), + AMD_PINCTRL_FUNC_GRP(135, 3), + AMD_PINCTRL_FUNC_GRP(136, 0), + AMD_PINCTRL_FUNC_GRP(136, 1), + AMD_PINCTRL_FUNC_GRP(136, 2), + AMD_PINCTRL_FUNC_GRP(136, 3), + AMD_PINCTRL_FUNC_GRP(137, 0), + AMD_PINCTRL_FUNC_GRP(137, 1), + AMD_PINCTRL_FUNC_GRP(137, 2), + AMD_PINCTRL_FUNC_GRP(137, 3), + AMD_PINCTRL_FUNC_GRP(138, 0), + AMD_PINCTRL_FUNC_GRP(138, 1), + AMD_PINCTRL_FUNC_GRP(138, 2), + AMD_PINCTRL_FUNC_GRP(138, 3), + AMD_PINCTRL_FUNC_GRP(139, 0), + AMD_PINCTRL_FUNC_GRP(139, 1), + AMD_PINCTRL_FUNC_GRP(139, 2), + AMD_PINCTRL_FUNC_GRP(139, 3), + AMD_PINCTRL_FUNC_GRP(140, 0), + AMD_PINCTRL_FUNC_GRP(140, 1), + AMD_PINCTRL_FUNC_GRP(140, 2), + AMD_PINCTRL_FUNC_GRP(140, 3), + AMD_PINCTRL_FUNC_GRP(141, 0), + AMD_PINCTRL_FUNC_GRP(141, 1), + AMD_PINCTRL_FUNC_GRP(141, 2), + AMD_PINCTRL_FUNC_GRP(141, 3), + AMD_PINCTRL_FUNC_GRP(142, 0), + AMD_PINCTRL_FUNC_GRP(142, 1), + AMD_PINCTRL_FUNC_GRP(142, 2), + AMD_PINCTRL_FUNC_GRP(142, 3), + AMD_PINCTRL_FUNC_GRP(143, 0), + AMD_PINCTRL_FUNC_GRP(143, 1), + AMD_PINCTRL_FUNC_GRP(143, 2), + AMD_PINCTRL_FUNC_GRP(143, 3), + AMD_PINCTRL_FUNC_GRP(144, 0), + AMD_PINCTRL_FUNC_GRP(144, 1), + AMD_PINCTRL_FUNC_GRP(144, 2), + AMD_PINCTRL_FUNC_GRP(144, 3), + + PINCTRL_PINGROUP("i2c0", AMD_PINS(145, 146), 2), + PINCTRL_PINGROUP("i2c1", AMD_PINS(147, 148), 2), + PINCTRL_PINGROUP("i2c2", AMD_PINS(113, 114), 2), + PINCTRL_PINGROUP("i2c3", AMD_PINS(19, 20), 2), + PINCTRL_PINGROUP("uart0", AMD_PINS(135, 136, 137, 138, 139), 5), + PINCTRL_PINGROUP("uart1", AMD_PINS(140, 141, 142, 143, 144), 5), +}; + +#define AMD_PMUX_FUNC(_number) { \ + .name = "iomux_gpio_"#_number, \ + .groups = { \ + "IMX_F0_GPIO"#_number, "IMX_F1_GPIO"#_number, \ + "IMX_F2_GPIO"#_number, "IMX_F3_GPIO"#_number, \ + }, \ + .index = _number, \ + .ngroups = NSELECTS, \ +} + +static const struct amd_function pmx_functions[] = { + AMD_PMUX_FUNC(0), + AMD_PMUX_FUNC(1), + AMD_PMUX_FUNC(2), + AMD_PMUX_FUNC(3), + AMD_PMUX_FUNC(4), + AMD_PMUX_FUNC(5), + AMD_PMUX_FUNC(6), + AMD_PMUX_FUNC(7), + AMD_PMUX_FUNC(8), + AMD_PMUX_FUNC(9), + AMD_PMUX_FUNC(10), + AMD_PMUX_FUNC(11), + AMD_PMUX_FUNC(12), + AMD_PMUX_FUNC(13), + AMD_PMUX_FUNC(14), + AMD_PMUX_FUNC(15), + AMD_PMUX_FUNC(16), + AMD_PMUX_FUNC(17), + AMD_PMUX_FUNC(18), + AMD_PMUX_FUNC(19), + AMD_PMUX_FUNC(20), + AMD_PMUX_FUNC(21), + AMD_PMUX_FUNC(22), + AMD_PMUX_FUNC(23), + AMD_PMUX_FUNC(24), + AMD_PMUX_FUNC(25), + AMD_PMUX_FUNC(26), + AMD_PMUX_FUNC(27), + AMD_PMUX_FUNC(28), + AMD_PMUX_FUNC(29), + AMD_PMUX_FUNC(30), + AMD_PMUX_FUNC(31), + AMD_PMUX_FUNC(32), + AMD_PMUX_FUNC(33), + AMD_PMUX_FUNC(34), + AMD_PMUX_FUNC(35), + AMD_PMUX_FUNC(36), + AMD_PMUX_FUNC(37), + AMD_PMUX_FUNC(38), + AMD_PMUX_FUNC(39), + AMD_PMUX_FUNC(40), + AMD_PMUX_FUNC(41), + AMD_PMUX_FUNC(42), + AMD_PMUX_FUNC(43), + AMD_PMUX_FUNC(44), + AMD_PMUX_FUNC(45), + AMD_PMUX_FUNC(46), + AMD_PMUX_FUNC(47), + AMD_PMUX_FUNC(48), + AMD_PMUX_FUNC(49), + AMD_PMUX_FUNC(50), + AMD_PMUX_FUNC(51), + AMD_PMUX_FUNC(52), + AMD_PMUX_FUNC(53), + AMD_PMUX_FUNC(54), + AMD_PMUX_FUNC(55), + AMD_PMUX_FUNC(56), + AMD_PMUX_FUNC(57), + AMD_PMUX_FUNC(58), + AMD_PMUX_FUNC(59), + AMD_PMUX_FUNC(60), + AMD_PMUX_FUNC(61), + AMD_PMUX_FUNC(62), + AMD_PMUX_FUNC(64), + AMD_PMUX_FUNC(65), + AMD_PMUX_FUNC(66), + AMD_PMUX_FUNC(67), + AMD_PMUX_FUNC(68), + AMD_PMUX_FUNC(69), + AMD_PMUX_FUNC(70), + AMD_PMUX_FUNC(71), + AMD_PMUX_FUNC(72), + AMD_PMUX_FUNC(73), + AMD_PMUX_FUNC(74), + AMD_PMUX_FUNC(75), + AMD_PMUX_FUNC(76), + AMD_PMUX_FUNC(77), + AMD_PMUX_FUNC(78), + AMD_PMUX_FUNC(79), + AMD_PMUX_FUNC(80), + AMD_PMUX_FUNC(81), + AMD_PMUX_FUNC(82), + AMD_PMUX_FUNC(83), + AMD_PMUX_FUNC(84), + AMD_PMUX_FUNC(85), + AMD_PMUX_FUNC(86), + AMD_PMUX_FUNC(87), + AMD_PMUX_FUNC(88), + AMD_PMUX_FUNC(89), + AMD_PMUX_FUNC(90), + AMD_PMUX_FUNC(91), + AMD_PMUX_FUNC(92), + AMD_PMUX_FUNC(93), + AMD_PMUX_FUNC(94), + AMD_PMUX_FUNC(95), + AMD_PMUX_FUNC(96), + AMD_PMUX_FUNC(97), + AMD_PMUX_FUNC(98), + AMD_PMUX_FUNC(99), + AMD_PMUX_FUNC(100), + AMD_PMUX_FUNC(101), + AMD_PMUX_FUNC(102), + AMD_PMUX_FUNC(103), + AMD_PMUX_FUNC(104), + AMD_PMUX_FUNC(105), + AMD_PMUX_FUNC(106), + AMD_PMUX_FUNC(107), + AMD_PMUX_FUNC(108), + AMD_PMUX_FUNC(109), + AMD_PMUX_FUNC(110), + AMD_PMUX_FUNC(111), + AMD_PMUX_FUNC(112), + AMD_PMUX_FUNC(113), + AMD_PMUX_FUNC(114), + AMD_PMUX_FUNC(115), + AMD_PMUX_FUNC(116), + AMD_PMUX_FUNC(117), + AMD_PMUX_FUNC(118), + AMD_PMUX_FUNC(119), + AMD_PMUX_FUNC(120), + AMD_PMUX_FUNC(121), + AMD_PMUX_FUNC(122), + AMD_PMUX_FUNC(123), + AMD_PMUX_FUNC(124), + AMD_PMUX_FUNC(125), + AMD_PMUX_FUNC(126), + AMD_PMUX_FUNC(127), + AMD_PMUX_FUNC(128), + AMD_PMUX_FUNC(129), + AMD_PMUX_FUNC(130), + AMD_PMUX_FUNC(131), + AMD_PMUX_FUNC(132), + AMD_PMUX_FUNC(133), + AMD_PMUX_FUNC(134), + AMD_PMUX_FUNC(135), + AMD_PMUX_FUNC(136), + AMD_PMUX_FUNC(137), + AMD_PMUX_FUNC(138), + AMD_PMUX_FUNC(139), + AMD_PMUX_FUNC(140), + AMD_PMUX_FUNC(141), + AMD_PMUX_FUNC(142), + AMD_PMUX_FUNC(143), + AMD_PMUX_FUNC(144), +}; + +class VoodooGPIOAMD : public VoodooGPIO { + OSDeclareDefaultStructors(VoodooGPIOAMD); + +private: + const struct pingroup *groups = nullptr; + size_t ngroups { 0 }; + const struct amd_function *functions = nullptr; + size_t nfunctions { 0 }; + UInt32 *saved_regs = nullptr; + int irq { -1 }; + IOMemoryMap *mmap = nullptr; + IOVirtualAddress base {}; + unsigned *interruptTypes; + OSObject **pinInterruptActionOwners; + IOInterruptAction *pinInterruptAction; + void **pinInterruptRefcons; + + void amd_gpio_irq_enable(unsigned pin); + void amd_gpio_irq_disable(unsigned pin); + void amd_gpio_irq_mask(unsigned pin); + void amd_gpio_irq_unmask(unsigned pin); + int amd_gpio_irq_set_wake(unsigned pin, unsigned int on); + void amd_gpio_irq_eoi(); + int amd_gpio_irq_set_type(unsigned pin, unsigned int type); + bool do_amd_gpio_irq_handler(int irq); + void amd_gpio_irq_init(); + int amd_gpio_suspend(); + int amd_gpio_resume(); + + void InterruptOccurred(void *refCon, IOService *nub, int source); + + public: + IOReturn getInterruptType(int pin, int *interruptType) override; + IOReturn registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) override; + IOReturn unregisterInterrupt(int pin) override; + + IOReturn enableInterrupt(int pin) override; + IOReturn disableInterrupt(int pin) override; + + IOReturn setInterruptTypeForPin(int pin, int type) override; + + bool start(IOService *provider) override; + void stop(IOService *provider) override; + + IOReturn setPowerState(unsigned long powerState, IOService *whatDevice) override; +}; + +#endif /* VoodooGPIOAMD_hpp */ diff --git a/VoodooGPIO/VoodooGPIOIntel.cpp b/VoodooGPIO/VoodooGPIOIntel.cpp new file mode 100644 index 0000000..536c6a5 --- /dev/null +++ b/VoodooGPIO/VoodooGPIOIntel.cpp @@ -0,0 +1,1001 @@ +// +// VoodooGPIOIntel.cpp +// VoodooGPIO +// +// Created by CoolStar on 8/14/17. +// Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. +// + +#include "VoodooGPIOIntel.hpp" + +/* Offset from regs */ +#define REVID 0x000 +#define REVID_SHIFT 16 +#define REVID_MASK GENMASK(31, 16) + +#define PADBAR 0x00c +#define GPI_IS 0x100 + +#define PADOWN_BITS 4 +#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) +#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) +#define PADOWN_GPP(p) ((p) / 8) + +/* Offset from pad_regs */ +#define PADCFG0 0x000 +#define PADCFG0_RXEVCFG_SHIFT 25 +#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) +#define PADCFG0_RXEVCFG_LEVEL 0 +#define PADCFG0_RXEVCFG_EDGE 1 +#define PADCFG0_RXEVCFG_DISABLED 2 +#define PADCFG0_RXEVCFG_EDGE_BOTH 3 +#define PADCFG0_PREGFRXSEL BIT(24) +#define PADCFG0_RXINV BIT(23) +#define PADCFG0_GPIROUTIOXAPIC BIT(20) +#define PADCFG0_GPIROUTSCI BIT(19) +#define PADCFG0_GPIROUTSMI BIT(18) +#define PADCFG0_GPIROUTNMI BIT(17) +#define PADCFG0_PMODE_SHIFT 10 +#define PADCFG0_PMODE_MASK GENMASK(13, 10) +#define PADCFG0_GPIORXDIS BIT(9) +#define PADCFG0_GPIOTXDIS BIT(8) +#define PADCFG0_GPIORXSTATE BIT(1) +#define PADCFG0_GPIOTXSTATE BIT(0) + +#define PADCFG1 0x004 +#define PADCFG1_TERM_UP BIT(13) +#define PADCFG1_TERM_SHIFT 10 +#define PADCFG1_TERM_MASK GENMASK(12, 10) +#define PADCFG1_TERM_20K 4 +#define PADCFG1_TERM_2K 3 +#define PADCFG1_TERM_5K 2 +#define PADCFG1_TERM_1K 1 + +#define PADCFG2 0x008 +#define PADCFG2_DEBEN BIT(0) +#define PADCFG2_DEBOUNCE_SHIFT 1 +#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1) + +#define DEBOUNCE_PERIOD 31250 /* ns */ + +#define pin_to_padno(c, p) ((p) - (c)->pin_base) +#define padgroup_offset(g, p) ((p) - (g)->base) + +OSDefineMetaClassAndStructors(VoodooGPIOIntel, VoodooGPIO); + +struct intel_community *VoodooGPIOIntel::intel_get_community(unsigned pin) { + struct intel_community *community; + for (int i = 0; i < ncommunities; i++) { + community = &communities[i]; + if (pin >= community->pin_base && pin < community->pin_base + community->npins) + return community; + } + + TryLog("%s::Failed to find community for pin %u", getName(), pin); + return NULL; +} + +struct intel_padgroup *VoodooGPIOIntel::intel_community_get_padgroup(struct intel_community *community, unsigned pin) { + for (int i = 0; i < community->ngpps; i++) { + struct intel_padgroup *padgrp = &community->gpps[i]; + if (pin >= padgrp->base && pin < padgrp->base + padgrp->size) + return padgrp; + } + + TryLog("%s::Failed to find padgroup for pin %u", getName(), pin); + return NULL; +} + +IOVirtualAddress VoodooGPIOIntel::intel_get_padcfg(unsigned pin, unsigned reg) { + struct intel_community *community; + unsigned padno; + size_t nregs; + + community = intel_get_community(pin); + if (!community) + return 0; + + padno = pin_to_padno(community, pin); + nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2; + + if (reg >= nregs * 4) + return 0; + + return community->pad_regs + reg + padno * nregs * 4; +} + +bool VoodooGPIOIntel::intel_pad_owned_by_host(unsigned pin) { + struct intel_community *community; + struct intel_padgroup *padgrp; + unsigned gpp, offset, gpp_offset; + IOVirtualAddress padown; + + community = intel_get_community(pin); + if (!community) + return false; + if (!community->padown_offset) + return true; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return false; + + gpp_offset = padgroup_offset(padgrp, pin); + gpp = PADOWN_GPP(gpp_offset); + + offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4; + padown = community->regs + offset; + + return !(readl(padown) & PADOWN_MASK(gpp_offset)); +} + +bool VoodooGPIOIntel::intel_pad_acpi_mode(unsigned pin) { + struct intel_community *community; + struct intel_padgroup *padgrp; + unsigned offset, gpp_offset; + IOVirtualAddress hostown; + + community = intel_get_community(pin); + if (!community) + return true; + if (!community->hostown_offset) + return false; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return true; + + gpp_offset = padgroup_offset(padgrp, pin); + offset = community->hostown_offset + padgrp->reg_num * 4; + hostown = community->regs + offset; + + return !(readl(hostown) & BIT(gpp_offset)); +} + +/** + * enum - Locking variants of the pad configuration. + * + * @PAD_UNLOCKED: Pad is fully controlled by the configuration registers + * @PAD_LOCKED: Pad configuration registers, except TX state, are locked + * @PAD_LOCKED_TX: Pad configuration TX state is locked + * @PAD_LOCKED_FULL: Pad configuration registers are locked completely + * + * Locking is considered as read-only mode for corresponding registers and + * their respective fields. That said, TX state bit is locked separately from + * the main locking scheme. + */ +enum { + PAD_UNLOCKED = 0, + PAD_LOCKED = 1, + PAD_LOCKED_TX = 2, + PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX, +}; + +int VoodooGPIOIntel::intel_pad_locked(unsigned int pin) { + struct intel_community *community; + struct intel_padgroup *padgrp; + unsigned offset, gpp_offset; + UInt32 value; + int ret = PAD_UNLOCKED; + + community = intel_get_community(pin); + if (!community) + return PAD_LOCKED_FULL; + if (!community->padcfglock_offset) + return PAD_UNLOCKED; + + padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return PAD_LOCKED_FULL; + + gpp_offset = padgroup_offset(padgrp, pin); + + /* + * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad, + * the pad is considered unlocked. Any other case means that it is + * either fully or partially locked. + */ + offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED; + + offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8; + value = readl(community->regs + offset); + if (value & BIT(gpp_offset)) + ret |= PAD_LOCKED_TX; + + return ret; +} + +bool VoodooGPIOIntel::intel_pad_is_unlocked(unsigned int pin) { + return (intel_pad_locked(pin) & PAD_LOCKED) == PAD_UNLOCKED; +} + +/** + * Translate GPIO offset to hardware pin (They are not always the same). + * Putting appropriate community and padgroup in the variables. + * + * @param offset GPIO pin number. + * @param community Matching community for hardware pin number. + * @param padgrp Matching padgroup for hardware pin number. + * @return Hardware GPIO pin number. -1 if not found. + */ +SInt32 VoodooGPIOIntel::intel_gpio_to_pin(UInt32 offset, + struct intel_community **community, + struct intel_padgroup **padgrp) { + int i; + for (i = 0; i < ncommunities; i++) { + struct intel_community *comm = &communities[i]; + int j; + for (j = 0; j < comm->ngpps; j++) { + struct intel_padgroup *pgrp = &comm->gpps[j]; + if (pgrp->gpio_base < 0) + continue; + + if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { + int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; + if (community) + *community = comm; + if (padgrp) + *padgrp = pgrp; + return pin; + } + } + } + + TryLog("%s::Failed getting hardware pin for GPIO pin %u", getName(), offset); + return -1; +} + +/** + * @param pin Hardware GPIO pin number to mask. + * @param mask Whether to mask or unmask. + */ +void VoodooGPIOIntel::intel_gpio_irq_mask_unmask(unsigned pin, bool mask) { + struct intel_community *community = intel_get_community(pin); + if (community) { + struct intel_padgroup *padgrp = intel_community_get_padgroup(community, pin); + if (!padgrp) + return; + + unsigned gpp, gpp_offset; + IOVirtualAddress reg, is; + UInt32 value; + + gpp = padgrp->reg_num; + gpp_offset = padgroup_offset(padgrp, pin); + + reg = community->regs + community->ie_offset + gpp * 4; + is = community->regs + GPI_IS + gpp * 4; + + /* Clear interrupt status first to avoid unexpected interrupt */ + writel(static_cast(BIT(gpp_offset)), is); + + value = readl(reg); + if (mask) + value &= ~BIT(gpp_offset); + else + value |= BIT(gpp_offset); + writel(value, reg); + } +} + +/** + * @param pin Hardware GPIO pin number to set its type. + * @param type Type to set. + */ +bool VoodooGPIOIntel::intel_gpio_irq_set_type(unsigned pin, unsigned type) { + IOVirtualAddress reg; + UInt32 value; + + reg = intel_get_padcfg(pin, PADCFG0); + if (!reg) + return false; + + /* + * If the pin is in ACPI mode it is still usable as a GPIO but it + * cannot be used as IRQ because GPI_IS status bit will not be + * updated by the host controller hardware. + */ + if (intel_pad_acpi_mode(pin)) { + TryLog("%s:: pin %u cannot be used as IRQ\n", getName(), pin); + return false; + } + + value = readl(reg); + + value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); + + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + value |= PADCFG0_RXEVCFG_EDGE_BOTH << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_EDGE_FALLING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + value |= PADCFG0_RXINV; + } else if (type & IRQ_TYPE_EDGE_RISING) { + value |= PADCFG0_RXEVCFG_EDGE << PADCFG0_RXEVCFG_SHIFT; + } else if (type & IRQ_TYPE_LEVEL_MASK) { + if (type & IRQ_TYPE_LEVEL_LOW) + value |= PADCFG0_RXINV; + } else { + value |= PADCFG0_RXEVCFG_DISABLED << PADCFG0_RXEVCFG_SHIFT; + } + + writel(value, reg); + return true; +} + +bool VoodooGPIOIntel::intel_pinctrl_add_padgroups(intel_community *community) { + struct intel_padgroup *gpps; + unsigned padown_num = 0; + size_t ngpps; + + if (community->gpps) + ngpps = community->ngpps; + else + ngpps = DIV_ROUND_UP(community->npins, community->gpp_size); + + gpps = IONew(intel_padgroup, ngpps); + + for (int i = 0; i < ngpps; i++) { + if (community->gpps) { + gpps[i] = community->gpps[i]; + } else { + unsigned gpp_size = community->gpp_size; + gpps[i].reg_num = i; + gpps[i].base = community->pin_base + i * gpp_size; + gpps[i].size = (UInt32)min(gpp_size, npins); + gpps[i].gpio_base = 0; + npins -= gpps[i].size; + } + + if (gpps[i].size > 32) { + IOLog("%s::Invalid GPP size for pad group %d\n", getName(), i); + return false; + } + + // Set gpio_base to base if not specified + if (!gpps[i].gpio_base) + gpps[i].gpio_base = gpps[i].base; + + gpps[i].padown_num = padown_num; + + /* + * In older hardware the number of padown registers per + * group is fixed regardless of the group size. + */ + if (community->gpp_num_padown_regs) + padown_num += community->gpp_num_padown_regs; + else + padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32); + } + community->gpps = gpps; + community->ngpps = ngpps; + community->gpps_alloc = true; + return true; +} + +bool VoodooGPIOIntel::intel_pinctrl_should_save(unsigned pin) { + if (!(intel_pad_owned_by_host(pin) && intel_pad_is_unlocked(pin))) + return false; + + struct intel_community *community = intel_get_community(pin); + + unsigned communityidx = pin - community->pin_base; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). It is possible that some pins are used by the + * BIOS during resume and those are not always locked down so leave + * them alone. + */ + if (community->pinInterruptActionOwners[communityidx]) + return true; + + return false; +} + +void VoodooGPIOIntel::intel_pinctrl_pm_init() { + context.pads = IONew(intel_pad_context, npins); + memset(context.pads, 0, npins * sizeof(intel_pad_context)); + + context.communities = IONew(intel_community_context, ncommunities); + memset(context.communities, 0, ncommunities * sizeof(intel_community_context)); + + for (int i = 0; i < ncommunities; i++) { + intel_community *community = &communities[i]; + + context.communities[i].intmask = IONew(UInt32, community->ngpps); + context.communities[i].hostown = IONew(UInt32, community->ngpps); + } +} + +void VoodooGPIOIntel::intel_pinctrl_pm_release() { + for (int i = 0; i < ncommunities; i++) { + intel_community *community = &communities[i]; + IOSafeDeleteNULL(context.communities[i].intmask, UInt32, community->ngpps); + IOSafeDeleteNULL(context.communities[i].hostown, UInt32, community->ngpps); + } + + IOSafeDeleteNULL(context.communities, intel_community_context, ncommunities); + + IOSafeDeleteNULL(context.pads, intel_pad_context, npins); +} + +void VoodooGPIOIntel::intel_pinctrl_suspend() { + struct intel_pad_context *pads = context.pads; + for (int i = 0; i < npins; i++) { + const struct pinctrl_pin_desc *desc = &pins[i]; + IOVirtualAddress padcfg; + uint32_t val; + + if (!intel_pinctrl_should_save(desc->number)) + continue; + + padcfg = intel_get_padcfg(desc->number, PADCFG0); + if (!padcfg) + continue; + + val = readl(padcfg); + pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE; + + padcfg = intel_get_padcfg(desc->number, PADCFG1); + if (!padcfg) + continue; + + val = readl(padcfg); + pads[i].padcfg1 = val; + + padcfg = intel_get_padcfg(desc->number, PADCFG2); + if (padcfg) + pads[i].padcfg2 = readl(padcfg); + } + + struct intel_community_context *communityContexts = context.communities; + for (int i = 0; i < ncommunities; i++) { + struct intel_community *community = &communities[i]; + IOVirtualAddress base = 0; + + base = community->regs + community->ie_offset; + for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) + communityContexts[i].intmask[gpp] = readl(base + gpp * 4); + + base = community->regs + community->hostown_offset; + for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) + communityContexts[i].hostown[gpp] = readl(base + gpp * 4); + } +} + +void VoodooGPIOIntel::intel_gpio_irq_init() { + for (size_t i = 0; i < ncommunities; i++) { + struct intel_community *community = &communities[i]; + IOVirtualAddress base = community->regs; + + for (unsigned gpp = 0; gpp < community->ngpps; gpp++) { + /* Mask and clear all interrupts */ + writel(0, base + community->ie_offset + gpp * 4); + writel(0xffff, base + GPI_IS + gpp * 4); + } + } +} + +UInt32 VoodooGPIOIntel::intel_gpio_is_requested(int base, unsigned int size) { + UInt32 requested = 0; + + for (unsigned int pin_offset = 0; pin_offset < size; pin_offset++) { + UInt32 gpio_pin = base + pin_offset; + SInt32 hw_pin = intel_gpio_to_pin(gpio_pin, nullptr, nullptr); + if (hw_pin < 0) + continue; + + for (unsigned int registered_idx = 0; registered_idx < registered_pin_list->getCount(); registered_idx++) { + OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(registered_idx)); + if (registered_pin && registered_pin->unsigned32BitValue() == hw_pin) { + requested |= BIT(pin_offset); + break; + } + } + } + + return requested; +} + +UInt32 VoodooGPIOIntel::intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value) { + UInt32 curr, updated; + + curr = readl(hostown); + updated = (curr & ~mask) | (value & mask); + writel(updated, hostown); + + return curr; +} + +void VoodooGPIOIntel::intel_pinctrl_resume() { + /* Mask all interrupts */ + intel_gpio_irq_init(); + + struct intel_pad_context *pads = context.pads; + for (int i = 0; i < npins; i++) { + const struct pinctrl_pin_desc *desc = &pins[i]; + IOVirtualAddress padcfg; + uint32_t val; + + if (!intel_pinctrl_should_save(desc->number)) + continue; + + padcfg = intel_get_padcfg(desc->number, PADCFG0); + if (!padcfg) + continue; + + val = readl(padcfg) & ~PADCFG0_GPIORXSTATE; + if (val != pads[i].padcfg0) + writel(pads[i].padcfg0, padcfg); + + padcfg = intel_get_padcfg(desc->number, PADCFG1); + if (!padcfg) + continue; + + val = readl(padcfg); + if (val != pads[i].padcfg1) { + writel(pads[i].padcfg1, padcfg); + } + + padcfg = intel_get_padcfg(desc->number, PADCFG2); + if (padcfg) { + val = readl(padcfg); + if (val != pads[i].padcfg2) { + writel(pads[i].padcfg2, padcfg); + } + } + } + + struct intel_community_context *communityContexts = context.communities; + for (int i = 0; i < ncommunities; i++) { + struct intel_community *community = &communities[i]; + IOVirtualAddress base = 0; + + base = communities->regs + communities->ie_offset; + for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) { + writel(communityContexts[i].intmask[gpp], base + gpp * 4); + } + + base = community->regs + community->hostown_offset; + for (unsigned int gpp = 0; gpp < community->ngpps; gpp++) { + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + UInt32 requested = 0, value = 0; + UInt32 saved = communityContexts[i].hostown[gpp]; + + if (padgrp->gpio_base < 0) + continue; + + requested = intel_gpio_is_requested(padgrp->gpio_base, padgrp->size); + value = intel_gpio_update_pad_mode(base + gpp * 4, requested, saved); + if ((value ^ saved) & requested) { + IOLog("%s::restore hostown %d/%u %#8x->%#8x\n", getName(), i, gpp, value, saved); + } + } + } +} + +bool VoodooGPIOIntel::init(OSDictionary* properties) { + if (!IOService::init(properties)) + return false; + + memset(&(this->context), 0, sizeof(intel_pinctrl_context)); + + return true; +} + +bool VoodooGPIOIntel::start(IOService *provider) { + if (!npins || !ngroups || !nfunctions || !ncommunities) { + IOLog("%s::Missing Platform Data! Aborting!\n", getName()); + return false; + } + + if (!IOService::start(provider)) + return false; + + isInterruptBusy = true; + + workLoop = getWorkLoop(); + if (!workLoop) { + IOLog("%s::Failed to get workloop!\n", getName()); + stop(provider); + return false; + } + workLoop->retain(); + + command_gate = IOCommandGate::commandGate(this); + if (!command_gate || (workLoop->addEventSource(command_gate) != kIOReturnSuccess)) { + IOLog("%s Could not open command gate\n", getName()); + stop(provider); + return false; + } + + IOLog("%s::VoodooGPIO Init!\n", getName()); + + for (int i = 0; i < ncommunities; i++) { + IOLog("%s::VoodooGPIO Initializing Community %d\n", getName(), i); + intel_community *community = &communities[i]; + + community->regs = 0; + community->pad_regs = 0; + + community->mmap = provider->mapDeviceMemoryWithIndex(i); + if (!community->mmap) { + IOLog("%s:VoodooGPIO error mapping community %d\n", getName(), i); + continue; + } + + IOVirtualAddress regs = community->mmap->getVirtualAddress(); + community->regs = regs; + + /* + * Determine community features based on the revision if + * not specified already. + */ + if (!community->features) { + UInt32 rev; + rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT; + if (rev >= 0x94) { + community->features |= PINCTRL_FEATURE_DEBOUNCE; + community->features |= PINCTRL_FEATURE_1K_PD; + } + } + + /* Read offset of the pad configuration registers */ + UInt32 padbar = readl(regs + PADBAR); + + community->pad_regs = regs + padbar; + + if (!intel_pinctrl_add_padgroups(community)) { + IOLog("%s::Error adding padgroups to community %d\n", getName(), i); + } + } + + for (int i = 0; i < ncommunities; i++) { + size_t sz = sizeof(OSObject *) * communities[i].npins; + communities[i].pinInterruptActionOwners = (OSObject **)IOMalloc(sz); + memset(communities[i].pinInterruptActionOwners, 0, sz); + + sz = sizeof(IOInterruptAction) * communities[i].npins; + communities[i].pinInterruptAction = (IOInterruptAction *)IOMalloc(sz); + memset(communities[i].pinInterruptAction, 0, sz); + + sz = sizeof(unsigned) * communities[i].npins; + communities[i].interruptTypes = (unsigned *)IOMalloc(sz); + memset(communities[i].interruptTypes, 0, sz); + + sz = sizeof(void *) * communities[i].npins; + communities[i].pinInterruptRefcons = (void **)IOMalloc(sz); + memset(communities[i].pinInterruptRefcons, 0, sz); + + communities[i].isActiveCommunity = IONew(bool, 1); + *communities[i].isActiveCommunity = false; + } + nInactiveCommunities = (UInt32)ncommunities - 1; + + registered_pin_list = OSArray::withCapacity(2); + if (!registered_pin_list) { + return false; + } + + intel_pinctrl_pm_init(); + + isInterruptBusy = false; + controllerIsAwake = true; + + registerService(); + + // Declare an array of two IOPMPowerState structures (kMyNumberOfStates = 2). + +#define kMyNumberOfStates 2 + + static IOPMPowerState myPowerStates[kMyNumberOfStates]; + // Zero-fill the structures. + bzero (myPowerStates, sizeof(myPowerStates)); + // Fill in the information about your device's off state: + myPowerStates[0].version = 1; + myPowerStates[0].capabilityFlags = kIOPMPowerOff; + myPowerStates[0].outputPowerCharacter = kIOPMPowerOff; + myPowerStates[0].inputPowerRequirement = kIOPMPowerOff; + // Fill in the information about your device's on state: + myPowerStates[1].version = 1; + myPowerStates[1].capabilityFlags = kIOPMPowerOn; + myPowerStates[1].outputPowerCharacter = kIOPMPowerOn; + myPowerStates[1].inputPowerRequirement = kIOPMPowerOn; + + PMinit(); + provider->joinPMtree(this); + + registerPowerDriver(this, myPowerStates, kMyNumberOfStates); + + return true; +} + +void VoodooGPIOIntel::stop(IOService *provider) { + IOLog("%s::VoodooGPIO stop!\n", getName()); + + if (command_gate) { + workLoop->removeEventSource(command_gate); + OSSafeReleaseNULL(command_gate); + } + + intel_pinctrl_pm_release(); + + for (int i = 0; i < ncommunities; i++) { + if (communities[i].gpps_alloc) { + IOSafeDeleteNULL(communities[i].gpps, intel_padgroup, communities[i].ngpps); + } + + IOSafeDeleteNULL(communities[i].pinInterruptActionOwners, OSObject*, communities[i].npins); + IOSafeDeleteNULL(communities[i].pinInterruptAction, IOInterruptAction, communities[i].npins); + IOSafeDeleteNULL(communities[i].interruptTypes, unsigned, communities[i].npins); + IOSafeDeleteNULL(communities[i].pinInterruptRefcons, void*, communities[i].npins); + IOSafeDeleteNULL(communities[i].isActiveCommunity, bool, 1); + } + + if (registered_pin_list) { + if (registered_pin_list->getCount() > 0) { + IOLog("%s::Interrupt has not been unregistered by client\n", getName()); + getProvider()->unregisterInterrupt(0); + } + OSSafeReleaseNULL(registered_pin_list); + } + + OSSafeReleaseNULL(workLoop); + + PMstop(); + + IOService::stop(provider); +} + +IOReturn VoodooGPIOIntel::setPowerState(unsigned long powerState, IOService *whatDevice) { + if (whatDevice != this) + return kIOPMAckImplied; + + if (powerState == 0) { + controllerIsAwake = false; + + intel_pinctrl_suspend(); + IOLog("%s::Going to Sleep!\n", getName()); + } else { + if (!controllerIsAwake) { + controllerIsAwake = true; + + intel_pinctrl_resume(); + IOLog("%s::Woke up from Sleep!\n", getName()); + } else { + IOLog("%s::GPIO Controller is already awake! Not reinitializing.\n", getName()); + } + } + return kIOPMAckImplied; +} + +void VoodooGPIOIntel::intel_gpio_community_irq_handler(struct intel_community *community, bool *firstdelay) { + for (int gpp = 0; gpp < community->ngpps; gpp++) { + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + + unsigned padno = padgrp->base - community->pin_base; + if (padno >= community->npins) + break; + + unsigned long pending, enabled; + + pending = readl(community->regs + GPI_IS + padgrp->reg_num * 4); + enabled = readl(community->regs + community->ie_offset + + padgrp->reg_num * 4); + + /* Only interrupts that are enabled */ + pending &= enabled; + + if (!pending) + continue; + + for (int i = 0; i < 32; i++) { + bool isPin = (pending >> i) & 0x1; + if (isPin) { + unsigned pin = padno + i; + if (pin >= community->npins) + break; + + OSObject *owner = community->pinInterruptActionOwners[pin]; + if (owner) { + IOInterruptAction handler = community->pinInterruptAction[pin]; + void *refcon = community->pinInterruptRefcons[pin]; + handler(owner, refcon, this, pin - padgrp->base + padgrp->gpio_base); + if (*firstdelay) { + *firstdelay = false; + IODelay(25 * nInactiveCommunities); // Reduce CPU load. 25~30us per inactive community was reasonable. + } + } + + if (community->interruptTypes[pin] & IRQ_TYPE_LEVEL_MASK) + intel_gpio_irq_mask_unmask(community->pin_base + pin, false); // For Level interrupts, we need to clear the interrupt status or we get too many interrupts + } + } + } +} + +void VoodooGPIOIntel::intel_gpio_pin_irq_handler(unsigned hw_pin) { + intel_community *community = intel_get_community(hw_pin); + intel_padgroup *pad_group = NULL; + if (!community || !(pad_group = intel_community_get_padgroup(community, hw_pin))) { + return; + } + + unsigned long pending, enabled; + IOVirtualAddress pending_address = community->regs + GPI_IS + pad_group->reg_num * 4; + pending = readl(pending_address); + enabled = readl(community->regs + community->ie_offset + pad_group->reg_num * 4); + + /* Only interrupts that are enabled */ + pending &= enabled; + + if (!pending) { + return; + } + + int pad_group_i = hw_pin - pad_group->base; + if (!((pending >> pad_group_i) & 0x1)) { + return; + } + + int community_i = hw_pin - community->pin_base; + OSObject *owner = community->pinInterruptActionOwners[community_i]; + if (owner) { + IOInterruptAction handler = community->pinInterruptAction[community_i]; + void *refcon = community->pinInterruptRefcons[community_i]; + handler(owner, refcon, this, pad_group_i + pad_group->gpio_base); + } + + if (community->interruptTypes[community_i] & IRQ_TYPE_LEVEL_MASK) { + /* For Level interrupts, we need to clear the interrupt status or we get too many interrupts */ + writel(static_cast(BIT(pad_group_i)), pending_address); + } +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt) + * @param interruptType variable to store interrupt type for specified GPIO pin. + */ +IOReturn VoodooGPIOIntel::getInterruptType(int pin, int *interruptType) { + SInt32 hw_pin = intel_gpio_to_pin(pin, nullptr, nullptr); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + return getProvider()->getInterruptType(0, interruptType); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOIntel::registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) { + struct intel_community *community; + struct intel_padgroup *padgrp; + SInt32 hw_pin = intel_gpio_to_pin(pin, &community, &padgrp); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + IOLog("%s::Registering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); + + unsigned communityidx = hw_pin - community->pin_base; + + if (community->pinInterruptActionOwners[communityidx]) + return kIOReturnNoResources; + + if (OSNumber* registered_pin = OSNumber::withNumber(hw_pin, 32)) { + if (!registered_pin_list->setObject(registered_pin)) { + IOLog("%s::Unable to register pin into list\n", getName()); + registered_pin->release(); + return kIOReturnNoResources; + } + registered_pin->release(); + + community->pinInterruptActionOwners[communityidx] = target; + community->pinInterruptAction[communityidx] = handler; + community->pinInterruptRefcons[communityidx] = refcon; + *community->isActiveCommunity = true; + } else { + IOLog("%s::Unable to allocate interrupt pin", getName()); + return kIOReturnNoResources; + } + + IOLog("%s::Successfully registered hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); + + if (registered_pin_list->getCount() == 1) { + return getProvider()->registerInterrupt(0, this, OSMemberFunctionCast(IOInterruptAction, this, &VoodooGPIOIntel::InterruptOccurred)); + } + return kIOReturnSuccess; +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOIntel::unregisterInterrupt(int pin) { + struct intel_community *community; + SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + IOLog("%s::Unregistering hardware pin 0x%02X for GPIO IRQ pin 0x%02X\n", getName(), hw_pin, pin); + + intel_gpio_irq_mask_unmask(hw_pin, true); + + unsigned communityidx = hw_pin - community->pin_base; + community->pinInterruptActionOwners[communityidx] = NULL; + community->pinInterruptAction[communityidx] = NULL; + community->interruptTypes[communityidx] = 0; + community->pinInterruptRefcons[communityidx] = NULL; + + for (int i = registered_pin_list->getCount() - 1; i >= 0; i--) { + OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(i)); + if (registered_pin && registered_pin->unsigned32BitValue() == hw_pin) { + registered_pin_list->removeObject(i); + } + } + + if (registered_pin_list->getCount() == 0) { + return getProvider()->unregisterInterrupt(0); + } + return kIOReturnSuccess; +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOIntel::enableInterrupt(int pin) { + struct intel_community *community; + SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + unsigned communityidx = hw_pin - community->pin_base; + if (community->pinInterruptActionOwners[communityidx]) { + intel_gpio_irq_set_type(hw_pin, community->interruptTypes[communityidx]); + intel_gpio_irq_mask_unmask(hw_pin, false); + return getProvider()->enableInterrupt(0); + } + return kIOReturnNoInterrupt; +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + */ +IOReturn VoodooGPIOIntel::disableInterrupt(int pin) { + SInt32 hw_pin = intel_gpio_to_pin(pin, nullptr, nullptr); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + intel_gpio_irq_mask_unmask(hw_pin, true); + return getProvider()->disableInterrupt(0); +} + +/** + * @param pin 'Software' pin number (i.e. GpioInt). + * @param type Interrupt type to set for specified pin. + */ +IOReturn VoodooGPIOIntel::setInterruptTypeForPin(int pin, int type) { + struct intel_community *community; + SInt32 hw_pin = intel_gpio_to_pin(pin, &community, nullptr); + if (hw_pin < 0) + return kIOReturnNoInterrupt; + + unsigned communityidx = hw_pin - community->pin_base; + community->interruptTypes[communityidx] = type; + if (type & IRQ_TYPE_LEVEL_MASK) + *community->isActiveCommunity = true; + return kIOReturnSuccess; +} + +void VoodooGPIOIntel::InterruptOccurred(void *refCon, IOService *nub, int source) { + for (int i = 0; i < registered_pin_list->getCount(); i++) { + if (OSNumber* registered_pin = OSDynamicCast(OSNumber, registered_pin_list->getObject(i))) { + intel_gpio_pin_irq_handler(registered_pin->unsigned32BitValue()); + } + } +} diff --git a/VoodooGPIO/VoodooGPIOIntel.hpp b/VoodooGPIO/VoodooGPIOIntel.hpp new file mode 100644 index 0000000..d1fa751 --- /dev/null +++ b/VoodooGPIO/VoodooGPIOIntel.hpp @@ -0,0 +1,229 @@ +// +// VoodooGPIOIntel.hpp +// VoodooGPIO +// +// Created by Visual on 5/3/23. +// Copyright © 2017 CoolStar. All rights reserved. +// Copyright © 2023 Visual/Noot Inc/ChefKiss Inc. All rights reserved. +// + +#ifndef VoodooGPIOIntel_h +#define VoodooGPIOIntel_h +#include "VoodooGPIO.hpp" + +/** + * struct intel_pingroup - Description about group of pins + * @name: Name of the groups + * @pins: All pins in this group + * @npins: Number of pins in this groups + * @mode: Native mode in which the group is muxed out @pins. Used if @modes + * is %NULL. + * @modes: If not %NULL this will hold mode for each pin in @pins + */ +struct intel_pingroup { + char *name; + unsigned *pins; + size_t npins; + unsigned short mode; + unsigned *modes; +}; + +/** + * struct intel_function - Description about a function + * @name: Name of the function + * @groups: An array of groups for this function + * @ngroups: Number of groups in @groups + */ +struct intel_function { + char *name; + char * const *groups; + size_t ngroups; +}; + +/** + * struct intel_padgroup - Hardware pad group information + * @reg_num: GPI_IS register number + * @base: Starting pin of this group + * @size: Size of this group (maximum is 32). + * @gpio_base: Starting GPIO base of this group (%0 if matches with @base, + * and %-1 if no GPIO mapping should be created) + * @padown_num: PAD_OWN register number (assigned by the core driver) + * + * If pad groups of a community are not the same size, use this structure + * to specify them. + */ +struct intel_padgroup { + UInt32 reg_num; + UInt32 base; + UInt32 size; + SInt32 gpio_base; + UInt32 padown_num; +}; + +/** + * struct intel_community - Intel pin community description + * @barno: MMIO BAR number where registers for this community reside + * @padown_offset: Register offset of PAD_OWN register from @regs. If %0 + * then there is no support for owner. + * @padcfglock_offset: Register offset of PADCFGLOCK from @regs. If %0 then + * locking is not supported. + * @hostown_offset: Register offset of HOSTSW_OWN from @regs. If %0 then it + * is assumed that the host owns the pin (rather than + * ACPI). + * @ie_offset: Register offset of GPI_IE from @regs. + * @pin_base: Starting pin of pins in this community + * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK, + * HOSTSW_OWN, GPI_IS, GPI_IE, etc. Used when @gpps is %NULL. + * @gpp_num_padown_regs: Number of pad registers each pad group consumes at + * minimum. Use %0 if the number of registers can be + * determined by the size of the group. + * @npins: Number of pins in this community + * @features: Additional features supported by the hardware + * @gpps: Pad groups if the controller has variable size pad groups + * @ngpps: Number of pad groups in this community + * @regs: Community specific common registers (reserved for core driver) + * @pad_regs: Community specific pad registers (reserved for core driver) + * + * Most Intel GPIO host controllers this driver supports each pad group is + * of equal size (except the last one). In that case the driver can just + * fill in @gpp_size field and let the core driver to handle the rest. If + * the controller has pad groups of variable size the client driver can + * pass custom @gpps and @ngpps instead. + */ +struct intel_community { + unsigned barno; + unsigned padown_offset; + unsigned padcfglock_offset; + unsigned hostown_offset; + unsigned ie_offset; + unsigned pin_base; + unsigned gpp_size; + unsigned gpp_num_padown_regs; + size_t npins; + unsigned features; + struct intel_padgroup *gpps; + size_t ngpps; + bool gpps_alloc; + bool *isActiveCommunity; + /* Reserved for the core driver */ + IOMemoryMap *mmap; + IOVirtualAddress regs; + IOVirtualAddress pad_regs; + + unsigned *interruptTypes; + OSObject **pinInterruptActionOwners; + IOInterruptAction *pinInterruptAction; + void **pinInterruptRefcons; +}; + +struct intel_pad_context { + uint32_t padcfg0; + uint32_t padcfg1; + uint32_t padcfg2; +}; + +struct intel_community_context { + uint32_t *intmask; + uint32_t *hostown; +}; + +struct intel_pinctrl_context { + struct intel_pad_context *pads; + struct intel_community_context *communities; +}; + +/* Additional features supported by the hardware */ +#define PINCTRL_FEATURE_DEBOUNCE 1 +#define PINCTRL_FEATURE_1K_PD 2 + +/** + * PIN_GROUP - Declare a pin group + * @n: Name of the group + * @p: An array of pins this group consists + * @m: Mode which the pins are put when this group is active. Can be either + * a single integer or an array of integers in which case mode is per + * pin. + */ +#define PIN_GROUP(n, p, m) \ +{ \ + .name = (n), \ + .pins = (p), \ + .npins = ARRAY_SIZE((p)), \ + .mode = __builtin_choose_expr( \ + __builtin_constant_p((m)), (m), 0), \ + .modes = __builtin_choose_expr( \ + __builtin_constant_p((m)), NULL, (m)), \ +} + +#define FUNCTION(n, g) \ +{ \ + .name = (n), \ + .groups = (g), \ + .ngroups = ARRAY_SIZE((g)), \ +} + +class VoodooGPIOIntel : public VoodooGPIO { + OSDeclareDefaultStructors(VoodooGPIOIntel); + +protected: + struct intel_pingroup *groups; + size_t ngroups; + struct intel_function *functions; + size_t nfunctions; + struct intel_community *communities; + size_t ncommunities; + + private: + struct intel_pinctrl_context context; + UInt32 nInactiveCommunities; + + struct intel_community *intel_get_community(unsigned pin); + struct intel_padgroup *intel_community_get_padgroup(struct intel_community *community, unsigned pin); + IOVirtualAddress intel_get_padcfg(unsigned pin, unsigned reg); + + bool intel_pad_owned_by_host(unsigned pin); + bool intel_pad_acpi_mode(unsigned pin); + int intel_pad_locked(unsigned pin); + bool intel_pad_is_unlocked(unsigned int pin); + + SInt32 intel_gpio_to_pin(UInt32 offset, + struct intel_community **community, + struct intel_padgroup **padgrp); + void intel_gpio_irq_mask_unmask(unsigned pin, bool mask); + bool intel_gpio_irq_set_type(unsigned pin, unsigned type); + + bool intel_pinctrl_add_padgroups(intel_community *community); + + bool intel_pinctrl_should_save(unsigned pin); + void intel_pinctrl_pm_init(); + void intel_pinctrl_pm_release(); + void intel_pinctrl_suspend(); + void intel_gpio_irq_init(); + UInt32 intel_gpio_is_requested(int base, unsigned int size); + UInt32 intel_gpio_update_pad_mode(IOVirtualAddress hostown, UInt32 mask, UInt32 value); + void intel_pinctrl_resume(); + + void intel_gpio_community_irq_handler(struct intel_community *community, bool *firstdelay); + void intel_gpio_pin_irq_handler(unsigned hw_pin); + + void InterruptOccurred(void *refCon, IOService *nub, int source); + + public: + IOReturn getInterruptType(int pin, int *interruptType) override; + IOReturn registerInterrupt(int pin, OSObject *target, IOInterruptAction handler, void *refcon) override; + IOReturn unregisterInterrupt(int pin) override; + + IOReturn enableInterrupt(int pin) override; + IOReturn disableInterrupt(int pin) override; + + IOReturn setInterruptTypeForPin(int pin, int type) override; + + bool init(OSDictionary* properties) override; + + bool start(IOService *provider) override; + void stop(IOService *provider) override; + + IOReturn setPowerState(unsigned long powerState, IOService *whatDevice) override; +}; + +#endif /* VoodooGPIOIntel_h */ diff --git a/VoodooGPIO/VoodooGPIOSunrisePointH.cpp b/VoodooGPIO/VoodooGPIOSunrisePointH.cpp index e9c7929..4563b52 100644 --- a/VoodooGPIO/VoodooGPIOSunrisePointH.cpp +++ b/VoodooGPIO/VoodooGPIOSunrisePointH.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOSunrisePointH.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOSunrisePointH, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOSunrisePointH, VoodooGPIOIntel); bool VoodooGPIOSunrisePointH::start(IOService *provider) { this->pins = spth_pins; @@ -22,5 +22,5 @@ bool VoodooGPIOSunrisePointH::start(IOService *provider) { IOLog("%s::Loading GPIO Data for SunrisePoint-H\n", getName()); - return VoodooGPIO::start(provider); + return VoodooGPIOIntel::start(provider); } diff --git a/VoodooGPIO/VoodooGPIOSunrisePointH.hpp b/VoodooGPIO/VoodooGPIOSunrisePointH.hpp index fb511e1..bb2ffd3 100644 --- a/VoodooGPIO/VoodooGPIOSunrisePointH.hpp +++ b/VoodooGPIO/VoodooGPIOSunrisePointH.hpp @@ -6,10 +6,9 @@ // Copyright © 2017 CoolStar. All rights reserved. // -#include "VoodooGPIO.hpp" - #ifndef VoodooGPIOSunrisePointH_h #define VoodooGPIOSunrisePointH_h +#include "VoodooGPIOIntel.hpp" #define SPT_PAD_OWN 0x020 #define SPT_PADCFGLOCK 0x0a0 @@ -279,7 +278,7 @@ static struct intel_community spth_communities[] = { SPT_COMMUNITY(2, 181, 191), }; -class VoodooGPIOSunrisePointH : public VoodooGPIO { +class VoodooGPIOSunrisePointH : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOSunrisePointH); bool start(IOService *provider) override; diff --git a/VoodooGPIO/VoodooGPIOSunrisePointLP.cpp b/VoodooGPIO/VoodooGPIOSunrisePointLP.cpp index 4cd30f4..5d1f33f 100644 --- a/VoodooGPIO/VoodooGPIOSunrisePointLP.cpp +++ b/VoodooGPIO/VoodooGPIOSunrisePointLP.cpp @@ -8,7 +8,7 @@ #include "VoodooGPIOSunrisePointLP.hpp" -OSDefineMetaClassAndStructors(VoodooGPIOSunrisePointLP, VoodooGPIO); +OSDefineMetaClassAndStructors(VoodooGPIOSunrisePointLP, VoodooGPIOIntel); bool VoodooGPIOSunrisePointLP::start(IOService *provider) { this->pins = sptlp_pins; @@ -22,5 +22,5 @@ bool VoodooGPIOSunrisePointLP::start(IOService *provider) { IOLog("%s::Loading GPIO Data for SunrisePoint-LP\n", getName()); - return VoodooGPIO::start(provider); + return VoodooGPIOIntel::start(provider); } diff --git a/VoodooGPIO/VoodooGPIOSunrisePointLP.hpp b/VoodooGPIO/VoodooGPIOSunrisePointLP.hpp index 80b6741..4aef303 100644 --- a/VoodooGPIO/VoodooGPIOSunrisePointLP.hpp +++ b/VoodooGPIO/VoodooGPIOSunrisePointLP.hpp @@ -6,10 +6,9 @@ // Copyright © 2017 CoolStar. All rights reserved. // -#include "VoodooGPIO.hpp" - #ifndef VoodooGPIOSunrisePointLP_h #define VoodooGPIOSunrisePointLP_h +#include "VoodooGPIOIntel.hpp" #define SPT_PAD_OWN 0x020 #define SPT_PADCFGLOCK 0x0a0 @@ -267,7 +266,7 @@ static struct intel_community sptlp_communities[] = { SPT_COMMUNITY(2, 120, 151), }; -class VoodooGPIOSunrisePointLP : public VoodooGPIO { +class VoodooGPIOSunrisePointLP : public VoodooGPIOIntel { OSDeclareDefaultStructors(VoodooGPIOSunrisePointLP); bool start(IOService *provider) override;