Files
OpenCore-Legacy-Patcher/payloads/Kexts/Acidanthera/WhateverGreen-Navi-Backlight.patch
2023-03-11 10:55:22 -07:00

3320 lines
140 KiB
Diff

diff --git a/WhateverGreen/kern_rad.cpp b/WhateverGreen/kern_rad.cpp
index b4f271f..162dc82 100644
--- a/WhateverGreen/kern_rad.cpp
+++ b/WhateverGreen/kern_rad.cpp
@@ -8,6 +8,7 @@
#include <Headers/kern_api.hpp>
#include <Headers/kern_iokit.hpp>
#include <Headers/kern_devinfo.hpp>
+#include <Headers/kern_time.hpp>
#include <IOKit/IOService.h>
#include <Availability.h>
@@ -190,1015 +191,2399 @@ void RAD::processKernel(KernelPatcher &patcher, DeviceInfo *info) {
}
void RAD::updatePwmMaxBrightnessFromInternalDisplay() {
- OSDictionary * matching = IOService::serviceMatching("AppleBacklightDisplay");
- if (matching == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null AppleBacklightDisplay");
- return;
- }
-
- OSIterator *iter = IOService::getMatchingServices(matching);
- if (iter == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null matching");
- matching->release();
- return;
- }
-
- IORegistryEntry* display = OSDynamicCast(IORegistryEntry, iter->getNextObject());
- if (display == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null display");
- iter->release();
- matching->release();
- return;
- }
-
- OSDictionary* iodispparm = OSDynamicCast(OSDictionary, display->getProperty("IODisplayParameters"));
- if (iodispparm == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null IODisplayParameters");
- iter->release();
- matching->release();
- return;
- }
-
- OSDictionary* linearbri = OSDynamicCast(OSDictionary, iodispparm->getObject("linear-brightness"));
- if (linearbri == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null linear-brightness");
- iter->release();
- matching->release();
- return;
- }
-
- OSNumber* maxbri = OSDynamicCast(OSNumber, linearbri->getObject("max"));
- if (maxbri == nullptr) {
- DBGLOG("igfx", "isRadeonX6000WiredToInternalDisplay null max");
- iter->release();
- matching->release();
- return;
- }
+ OSDictionary * matching = IOService::serviceMatching("AppleBacklightDisplay");
+ if (matching == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null AppleBacklightDisplay");
+ return;
+ }
+
+ OSIterator *iter = IOService::getMatchingServices(matching);
+ if (iter == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null matching");
+ matching->release();
+ return;
+ }
+
+ IORegistryEntry* display = OSDynamicCast(IORegistryEntry, iter->getNextObject());
+ if (display == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null display");
+ iter->release();
+ matching->release();
+ return;
+ }
+
+ OSDictionary* iodispparm = OSDynamicCast(OSDictionary, display->getProperty("IODisplayParameters"));
+ if (iodispparm == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null IODisplayParameters");
+ iter->release();
+ matching->release();
+ return;
+ }
+
+ OSDictionary* linearbri = OSDynamicCast(OSDictionary, iodispparm->getObject("linear-brightness"));
+ if (linearbri == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null linear-brightness");
+ iter->release();
+ matching->release();
+ return;
+ }
+
+ OSNumber* maxbri = OSDynamicCast(OSNumber, linearbri->getObject("max"));
+ if (maxbri == nullptr) {
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay null max");
+ iter->release();
+ matching->release();
+ return;
+ }
+
+ callbackRAD->maxPwmBacklightLvl = maxbri->unsigned32BitValue();
+ DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay get max brightness: 0x%x", callbackRAD->maxPwmBacklightLvl);
+
+ iter->release();
+ matching->release();
+}
- callbackRAD->maxPwmBacklightLvl = maxbri->unsigned32BitValue();
- DBGLOG("igfx", "updatePwmMaxBrightnessFromInternalDisplay get max brightness: 0x%x", callbackRAD->maxPwmBacklightLvl);
+typedef int64_t __int64;
+typedef int64_t _QWORD;
+typedef int32_t _DWORD;
+typedef int8_t __int8;
- iter->release();
- matching->release();
-}
+struct dc_stream_state {
+ void *sink;
+ void *link;
+};
-uint32_t RAD::wrapDcePanelCntlHwInit(void *panel_cntl) {
- callbackRAD->panelCntlPtr = panel_cntl;
- callbackRAD->updatePwmMaxBrightnessFromInternalDisplay(); // read max brightness value from IOReg
- uint32_t ret = FunctionCast(wrapDcePanelCntlHwInit, callbackRAD->orgDcePanelCntlHwInit)(panel_cntl);
- return ret;
-}
+#define MAX_SINKS_PER_LINK 4
-IOReturn RAD::wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute(IOService *framebuffer, IOIndex connectIndex, IOSelect attribute, uintptr_t value) {
- IOReturn ret = FunctionCast(wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute, callbackRAD->orgAMDRadeonX6000AmdRadeonFramebufferSetAttribute)(framebuffer, connectIndex, attribute, value);
- if (attribute != (UInt32)'bklt') {
- return ret;
- }
-
- if (callbackRAD->maxPwmBacklightLvl == 0) {
- DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute zero maxPwmBacklightLvl");
- return 0;
- }
-
- if (callbackRAD->panelCntlPtr == nullptr) {
- DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute null panel cntl");
- return 0;
- }
-
- if (callbackRAD->orgDceDriverSetBacklight == nullptr) {
- DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute null orgDcLinkSetBacklightLevel");
- return 0;
- }
-
- // set the backlight of AMD navi10 driver
- callbackRAD->curPwmBacklightLvl = (uint32_t)value;
- uint32_t btlper = callbackRAD->curPwmBacklightLvl * 100 / callbackRAD->maxPwmBacklightLvl;
- uint32_t pwmval = 0;
- if (btlper >= 100) {
- // This is from the dmcu_set_backlight_level function of Linux source
- // ...
- // if (backlight_pwm_u16_16 & 0x10000)
- // backlight_8_bit = 0xFF;
- // else
- // backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
- // ...
- // The max brightness should have 0x10000 bit set
- pwmval = 0x1FF00;
- } else {
- pwmval = ((btlper * 0xFF) / 100) << 8U;
- }
+struct dc_link_settings {
+ uint32_t lane_count;
+ uint32_t link_rate;
+ uint32_t link_spread;
+ bool use_link_rate_set;
+ uint8_t link_rate_set;
+};
- callbackRAD->orgDceDriverSetBacklight(callbackRAD->panelCntlPtr, pwmval);
- return 0;
-}
+struct dc_lane_settings {
+ uint32_t VOLTAGE_SWING;
+ uint32_t PRE_EMPHASIS;
+ uint32_t POST_CURSOR2;
+};
-IOReturn RAD::wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute(IOService *framebuffer, IOIndex connectIndex, IOSelect attribute, uintptr_t * value) {
- IOReturn ret = FunctionCast(wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute, callbackRAD->orgAMDRadeonX6000AmdRadeonFramebufferGetAttribute)(framebuffer, connectIndex, attribute, value);
- if (attribute == (UInt32)'bklt') {
- // enable the backlight feature of AMD navi10 driver
- *value = callbackRAD->curPwmBacklightLvl;
- ret = 0;
- }
- return ret;
-}
+struct dc_link_training_overrides {
+ uint32_t *voltage_swing;
+ uint32_t *pre_emphasis;
+ uint32_t *post_cursor2;
+
+ uint16_t *cr_pattern_time;
+ uint16_t *eq_pattern_time;
+ uint32_t *pattern_for_cr;
+ uint32_t *pattern_for_eq;
+
+ uint32_t *downspread;
+ bool *alternate_scrambler_reset;
+ bool *enhanced_framing;
+ bool *mst_enable;
+ bool *fec_enable;
+};
-bool RAD::processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
- if (kextRadeonX6000Framebuffer.loadIndex == index) {
- KernelPatcher::RouteRequest requests[] = {
- {"_dce_panel_cntl_hw_init", wrapDcePanelCntlHwInit, orgDcePanelCntlHwInit},
- {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25setAttributeForConnectionEijm", wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferSetAttribute},
- {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25getAttributeForConnectionEijPm", wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferGetAttribute},
- };
+struct dp_audio_test_data_flags {
+ uint8_t test_requested :1;
+ uint8_t disable_video :1;
+};
- if (!patcher.routeMultiple(index, requests, address, size, true, true))
- SYSLOG("igfx", "Failed to route redeon x6000 gpu tracing.");
-
- orgDceDriverSetBacklight = reinterpret_cast<t_DceDriverSetBacklight>(patcher.solveSymbol(index, "_dce_driver_set_backlight"));
- if (patcher.getError() != KernelPatcher::Error::NoError) {
- SYSLOG("igfx", "failed to resolve _dce_driver_set_backlight");
- patcher.clearError();
- }
- }
-
- if (kextRadeonFramebuffer.loadIndex == index) {
- if (force24BppMode)
- process24BitOutput(patcher, kextRadeonFramebuffer, address, size);
- return true;
- }
+struct dp_audio_test_data {
- if (kextRadeonLegacyFramebuffer.loadIndex == index) {
- if (force24BppMode)
- process24BitOutput(patcher, kextRadeonLegacyFramebuffer, address, size);
- return true;
- }
+ struct dp_audio_test_data_flags flags;
+ uint8_t sampling_rate;
+ uint8_t channel_count;
+ uint8_t pattern_type;
+ uint8_t pattern_period[8];
+};
- if (kextRadeonSupport.loadIndex == index) {
- processConnectorOverrides(patcher, address, size, true);
+union compliance_test_state {
+ struct {
+ unsigned char STEREO_3D_RUNNING : 1;
+ unsigned char RESERVED : 7;
+ } bits;
+ unsigned char raw;
+};
- if (getKernelVersion() > KernelVersion::Mojave ||
- (getKernelVersion() == KernelVersion::Mojave && getKernelMinorVersion() >= 5)) {
- KernelPatcher::RouteRequest request("__ZN13ATIController8TestVRAME13PCI_REG_INDEXb", doNotTestVram);
- patcher.routeMultiple(index, &request, 1, address, size);
- }
+struct graphics_object_id {
+ uint32_t id:8;
+ uint32_t enum_id:4;
+ uint32_t type:4;
+ uint32_t reserved:16; /* for padding. total size should be u32 */
+};
- if (useCustomAgdpDecision) {
- KernelPatcher::RouteRequest request("__ZN16AtiDeviceControl16notifyLinkChangeE31kAGDCRegisterLinkControlEvent_tmj", wrapNotifyLinkChange, orgNotifyLinkChange);
- patcher.routeMultiple(index, &request, 1, address, size);
- }
+union ddi_channel_mapping {
+ struct mapping {
+ uint8_t lane0:2; /* Mapping for lane 0 */
+ uint8_t lane1:2; /* Mapping for lane 1 */
+ uint8_t lane2:2; /* Mapping for lane 2 */
+ uint8_t lane3:2; /* Mapping for lane 3 */
+ } mapping;
+ uint8_t raw;
+};
- return true;
- }
+struct device_id {
+ uint32_t device_type:16;
+ uint32_t enum_id:16; /* 1 based enum */
+ uint16_t raw_device_tag;
+};
- if (kextRadeonLegacySupport.loadIndex == index) {
- processConnectorOverrides(patcher, address, size, false);
- return true;
- }
+struct connector_device_tag_info {
+ uint32_t acpi_device;
+ struct device_id dev_id;
+};
- if (kextPolarisController.loadIndex == index) {
- KernelPatcher::RouteRequest request("__ZN17AMD9500Controller23findProjectByPartNumberEP20ControllerProperties", findProjectByPartNumber);
- patcher.routeMultiple(index, &request, 1, address, size);
- }
+union dpcd_rev {
+ struct {
+ uint8_t MINOR:4;
+ uint8_t MAJOR:4;
+ } bits;
+ uint8_t raw;
+};
- for (size_t i = 0; i < maxHardwareKexts; i++) {
- if (kextRadeonHardware[i].loadIndex == index) {
- processHardwareKext(patcher, i, address, size);
- return true;
- }
- }
+union max_lane_count {
+ struct {
+ uint8_t MAX_LANE_COUNT:5;
+ uint8_t POST_LT_ADJ_REQ_SUPPORTED:1;
+ uint8_t TPS3_SUPPORTED:1;
+ uint8_t ENHANCED_FRAME_CAP:1;
+ } bits;
+ uint8_t raw;
+};
- return false;
-}
+union max_down_spread {
+ struct {
+ uint8_t MAX_DOWN_SPREAD:1;
+ uint8_t RESERVED:5;
+ uint8_t NO_AUX_HANDSHAKE_LINK_TRAINING:1;
+ uint8_t TPS4_SUPPORTED:1;
+ } bits;
+ uint8_t raw;
+};
-void RAD::initHardwareKextMods() {
- // Decide on kext amount present for optimal performance.
- // 10.15+ has X4000, X5000, and X6000
- // 10.14+ has X4000 and X5000
- // 10.13.4+ has X3000, X4000, and X5000
- if (getKernelVersion() >= KernelVersion::Catalina)
- maxHardwareKexts = MaxRadeonHardwareCatalina;
- else if (getKernelVersion() >= KernelVersion::Mojave)
- maxHardwareKexts = MaxRadeonHardwareMojave;
- else if (getKernelVersion() == KernelVersion::HighSierra && getKernelMinorVersion() >= 5)
- maxHardwareKexts = MaxRadeonHardwareModernHighSierra;
-
- // 10.13.4 fixed black screen issues
- if (maxHardwareKexts != MaxRadeonHardware) {
- for (size_t i = 0; i < MaxGetFrameBufferProcs; i++)
- getFrameBufferProcNames[IndexRadeonHardwareX4000][i] = nullptr;
-
- // We have nothing to do for these kexts on recent systems
- if (!fixConfigName && !forceOpenGL && !forceCodecInfo) {
- // X4000 kext is not included in this list as we need to fix GVA properties for most of its GPUs
- kextRadeonHardware[IndexRadeonHardwareX5000].switchOff();
- kextRadeonHardware[IndexRadeonHardwareX6000].switchOff();
- }
- }
+union dprx_feature {
+ struct {
+ uint8_t GTC_CAP:1; // bit 0: DP 1.3+
+ uint8_t SST_SPLIT_SDP_CAP:1; // bit 1: DP 1.4
+ uint8_t AV_SYNC_CAP:1; // bit 2: DP 1.3+
+ uint8_t VSC_SDP_COLORIMETRY_SUPPORTED:1; // bit 3: DP 1.3+
+ uint8_t VSC_EXT_VESA_SDP_SUPPORTED:1; // bit 4: DP 1.4
+ uint8_t VSC_EXT_VESA_SDP_CHAINING_SUPPORTED:1; // bit 5: DP 1.4
+ uint8_t VSC_EXT_CEA_SDP_SUPPORTED:1; // bit 6: DP 1.4
+ uint8_t VSC_EXT_CEA_SDP_CHAINING_SUPPORTED:1; // bit 7: DP 1.4
+ } bits;
+ uint8_t raw;
+};
- if (getKernelVersion() < KernelVersion::Catalina) {
- kextRadeonHardware[IndexRadeonHardwareX6000].switchOff();
- }
+union sink_count {
+ struct {
+ uint8_t SINK_COUNT:6;
+ uint8_t CPREADY:1;
+ uint8_t RESERVED:1;
+ } bits;
+ uint8_t raw;
+};
- if (getKernelVersion() < KernelVersion::HighSierra) {
- // Versions before 10.13 do not support X4250 and X5000
- kextRadeonHardware[IndexRadeonHardwareX4250].switchOff();
- kextRadeonHardware[IndexRadeonHardwareX5000].switchOff();
+struct dc_dongle_caps {
+ /* dongle type (DP converter, CV smart dongle) */
+ uint32_t dongle_type;
+ bool extendedCapValid;
+ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
+ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
+ bool is_dp_hdmi_s3d_converter;
+ bool is_dp_hdmi_ycbcr422_pass_through;
+ bool is_dp_hdmi_ycbcr420_pass_through;
+ bool is_dp_hdmi_ycbcr422_converter;
+ bool is_dp_hdmi_ycbcr420_converter;
+ uint32_t dp_hdmi_max_bpc;
+ uint32_t dp_hdmi_max_pixel_clk_in_khz;
+};
- // Versions before 10.13 have legacy X3000 and X4000 IDs
- kextRadeonHardware[IndexRadeonHardwareX3000].id = idRadeonX3000Old;
- kextRadeonHardware[IndexRadeonHardwareX4000].id = idRadeonX4000Old;
+union dpcd_fec_capability {
+ struct {
+ uint8_t FEC_CAPABLE:1;
+ uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
+ uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
+ uint8_t BIT_ERROR_COUNT_CAPABLE:1;
+ uint8_t RESERVED:4;
+ } bits;
+ uint8_t raw;
+};
- bool preSierra = getKernelVersion() < KernelVersion::Sierra;
+union dpcd_dsc_branch_decoder_capabilities {
+ struct {
+ uint8_t BRANCH_OVERALL_THROUGHPUT_0;
+ uint8_t BRANCH_OVERALL_THROUGHPUT_1;
+ uint8_t BRANCH_MAX_LINE_WIDTH;
+ } fields;
+ uint8_t raw[3];
+};
- if (preSierra) {
- // Versions before 10.12 do not support X4100
- kextRadeonHardware[IndexRadeonHardwareX4100].switchOff();
- }
+struct dpcd_dsc_support {
+ uint8_t DSC_SUPPORT :1;
+ uint8_t DSC_PASSTHROUGH_SUPPORT :1;
+ uint8_t RESERVED :6;
+};
- if (preSierra || (getKernelVersion() == KernelVersion::Sierra && getKernelMinorVersion() < 7)) {
- // Versions before 10.12.6 do not support X4150, X4200
- kextRadeonHardware[IndexRadeonHardwareX4150].switchOff();
- kextRadeonHardware[IndexRadeonHardwareX4200].switchOff();
- }
- }
+struct dpcd_dsc_algorithm_revision {
+ uint8_t DSC_VERSION_MAJOR :4;
+ uint8_t DSC_VERSION_MINOR :4;
+};
- lilu.onKextLoadForce(kextRadeonHardware, maxHardwareKexts);
-}
+struct dpcd_dsc_rc_buffer_block_size {
+ uint8_t RC_BLOCK_BUFFER_SIZE :2;
+ uint8_t RESERVED :6;
+};
-void RAD::process24BitOutput(KernelPatcher &patcher, KernelPatcher::KextInfo &info, mach_vm_address_t address, size_t size) {
- auto bitsPerComponent = patcher.solveSymbol<int *>(info.loadIndex, "__ZL18BITS_PER_COMPONENT", address, size);
- if (bitsPerComponent) {
- while (bitsPerComponent && *bitsPerComponent) {
- if (*bitsPerComponent == 10) {
- auto ret = MachInfo::setKernelWriting(true, KernelPatcher::kernelWriteLock);
- if (ret == KERN_SUCCESS) {
- DBGLOG("rad", "fixing BITS_PER_COMPONENT");
- *bitsPerComponent = 8;
- MachInfo::setKernelWriting(false, KernelPatcher::kernelWriteLock);
- } else {
- SYSLOG("rad", "failed to disable write protection for BITS_PER_COMPONENT");
- }
- }
- bitsPerComponent++;
- }
- } else {
- SYSLOG("rad", "failed to find BITS_PER_COMPONENT");
- patcher.clearError();
- }
+struct dpcd_dsc_slice_capability1 {
+ uint8_t ONE_SLICE_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t TWO_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t RESERVED :1;
+ uint8_t FOUR_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t SIX_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t EIGHT_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t TEN_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+ uint8_t TWELVE_SLICES_PER_DP_DSC_SINK_DEVICE :1;
+};
- DBGLOG("rad", "fixing pixel types");
+struct dpcd_dsc_line_buffer_bit_depth {
+ uint8_t LINE_BUFFER_BIT_DEPTH :4;
+ uint8_t RESERVED :4;
+};
- KernelPatcher::LookupPatch pixelPatch {
- &info,
- reinterpret_cast<const uint8_t *>("--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB"),
- reinterpret_cast<const uint8_t *>("--------RRRRRRRRGGGGGGGGBBBBBBBB"),
- 32, 2
- };
+struct dpcd_dsc_block_prediction_support {
+ uint8_t BLOCK_PREDICTION_SUPPORT:1;
+ uint8_t RESERVED :7;
+};
- patcher.applyLookupPatch(&pixelPatch);
- if (patcher.getError() != KernelPatcher::Error::NoError) {
- SYSLOG("rad", "failed to patch RGB mask for 24-bit output");
- patcher.clearError();
- }
-}
+struct dpcd_maximum_bits_per_pixel_supported_by_the_decompressor {
+ uint8_t MAXIMUM_BITS_PER_PIXEL_SUPPORTED_BY_THE_DECOMPRESSOR_LOW :7;
+ uint8_t MAXIMUM_BITS_PER_PIXEL_SUPPORTED_BY_THE_DECOMPRESSOR_HIGH :7;
+ uint8_t RESERVED :2;
+};
-void RAD::processConnectorOverrides(KernelPatcher &patcher, mach_vm_address_t address, size_t size, bool modern) {
- if (modern) {
- if (getKernelVersion() >= KernelVersion::HighSierra) {
- KernelPatcher::RouteRequest requests[] {
- KernelPatcher::RouteRequest("__ZN14AtiBiosParser116getConnectorInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV1, orgGetConnectorsInfoV1),
- KernelPatcher::RouteRequest("__ZN14AtiBiosParser216getConnectorInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV2, orgGetConnectorsInfoV2),
- KernelPatcher::RouteRequest("__ZN14AtiBiosParser126translateAtomConnectorInfoERN30AtiObjectInfoTableInterface_V117AtomConnectorInfoER13ConnectorInfo",
- wrapTranslateAtomConnectorInfoV1, orgTranslateAtomConnectorInfoV1),
- KernelPatcher::RouteRequest("__ZN14AtiBiosParser226translateAtomConnectorInfoERN30AtiObjectInfoTableInterface_V217AtomConnectorInfoER13ConnectorInfo",
- wrapTranslateAtomConnectorInfoV2, orgTranslateAtomConnectorInfoV2),
- KernelPatcher::RouteRequest("__ZN13ATIController5startEP9IOService", wrapATIControllerStart, orgATIControllerStart)
- };
- patcher.routeMultiple(kextRadeonSupport.loadIndex, requests, address, size);
- } else {
- KernelPatcher::RouteRequest requests[] {
- KernelPatcher::RouteRequest("__ZN23AtiAtomBiosDceInterface17getConnectorsInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV1, orgGetConnectorsInfoV1),
- KernelPatcher::RouteRequest("__ZN13ATIController5startEP9IOService", wrapATIControllerStart, orgATIControllerStart),
- };
- patcher.routeMultiple(kextRadeonSupport.loadIndex, requests, address, size);
-
- orgGetAtomObjectTableForType = reinterpret_cast<t_getAtomObjectTableForType>(patcher.solveSymbol(kextRadeonSupport.loadIndex,
- "__ZN20AtiAtomBiosUtilities25getAtomObjectTableForTypeEhRh", address, size));
- if (!orgGetAtomObjectTableForType) {
- SYSLOG("rad", "failed to find AtiAtomBiosUtilities::getAtomObjectTableForType");
- patcher.clearError();
- }
- }
- } else {
- KernelPatcher::RouteRequest requests[] {
- KernelPatcher::RouteRequest("__ZN23AtiAtomBiosDceInterface17getConnectorsInfoEP13ConnectorInfoRh", wrapLegacyGetConnectorsInfo, orgLegacyGetConnectorsInfo),
- KernelPatcher::RouteRequest("__ZN19AMDLegacyController5startEP9IOService", wrapLegacyATIControllerStart, orgLegacyATIControllerStart),
- };
- patcher.routeMultiple(kextRadeonLegacySupport.loadIndex, requests, address, size);
+struct dpcd_dsc_decoder_color_format_capabilities {
+ uint8_t RGB_SUPPORT :1;
+ uint8_t Y_CB_CR_444_SUPPORT :1;
+ uint8_t Y_CB_CR_SIMPLE_422_SUPPORT :1;
+ uint8_t Y_CB_CR_NATIVE_422_SUPPORT :1;
+ uint8_t Y_CB_CR_NATIVE_420_SUPPORT :1;
+ uint8_t RESERVED :3;
+};
- orgLegacyGetAtomObjectTableForType = patcher.solveSymbol<t_getAtomObjectTableForType>(kextRadeonLegacySupport.loadIndex,
- "__ZN20AtiAtomBiosUtilities25getAtomObjectTableForTypeEhRh", address, size);
- if (!orgLegacyGetAtomObjectTableForType) {
- SYSLOG("rad", "failed to find AtiAtomBiosUtilities::getAtomObjectTableForType");
- patcher.clearError();
- }
- }
-}
+struct dpcd_dsc_decoder_color_depth_capabilities {
+ uint8_t RESERVED0 :1;
+ uint8_t EIGHT_BITS_PER_COLOR_SUPPORT :1;
+ uint8_t TEN_BITS_PER_COLOR_SUPPORT :1;
+ uint8_t TWELVE_BITS_PER_COLOR_SUPPORT :1;
+ uint8_t RESERVED1 :4;
+};
-void RAD::processHardwareKext(KernelPatcher &patcher, size_t hwIndex, mach_vm_address_t address, size_t size) {
- auto getFrame = getFrameBufferProcNames[hwIndex];
- auto &hardware = kextRadeonHardware[hwIndex];
-
- // Fix boot and wake to black screen
- for (size_t j = 0; j < MaxGetFrameBufferProcs && getFrame[j] != nullptr; j++) {
- auto getFB = patcher.solveSymbol(hardware.loadIndex, getFrame[j], address, size);
- if (getFB) {
- // Initially it was discovered that the only problematic register is PRIMARY_SURFACE_ADDRESS_HIGH (0x1A07).
- // This register must be nulled to solve most of the issues.
- // Depending on the amount of connected screens PRIMARY_SURFACE_ADDRESS (0x1A04) may not be null.
- // However, as of AMD Vega drivers in 10.13 DP1 both of these registers are now ignored.
- // Furthermore, there are no (extra) issues from just returning 0 in framebuffer base address.
-
- // xor rax, rax
- // ret
- uint8_t ret[] {0x48, 0x31, 0xC0, 0xC3};
- patcher.routeBlock(getFB, ret, sizeof(ret));
- if (patcher.getError() == KernelPatcher::Error::NoError) {
- DBGLOG("rad", "patched %s", getFrame[j]);
- } else {
- SYSLOG("rad", "failed to patch %s code %d", getFrame[j], patcher.getError());
- patcher.clearError();
- }
- } else {
- SYSLOG("rad", "failed to find %s code %d", getFrame[j], patcher.getError());
- patcher.clearError();
- }
- }
+struct dpcd_peak_dsc_throughput_dsc_sink {
+ uint8_t THROUGHPUT_MODE_0:4;
+ uint8_t THROUGHPUT_MODE_1:4;
+};
- // Fix reported Accelerator name to support WhateverName.app
- // Also fix GVA properties for X4000.
- if (fixConfigName || hwIndex == IndexRadeonHardwareX4000) {
- KernelPatcher::RouteRequest request(populateAccelConfigProcNames[hwIndex], wrapPopulateAccelConfig[hwIndex], orgPopulateAccelConfig[hwIndex]);
- patcher.routeMultiple(hardware.loadIndex, &request, 1, address, size);
- }
+struct dpcd_dsc_slice_capabilities_2 {
+ uint8_t SIXTEEN_SLICES_PER_DSC_SINK_DEVICE :1;
+ uint8_t TWENTY_SLICES_PER_DSC_SINK_DEVICE :1;
+ uint8_t TWENTYFOUR_SLICES_PER_DSC_SINK_DEVICE :1;
+ uint8_t RESERVED :5;
+};
- // Enforce OpenGL support if requested
- if (forceOpenGL) {
- DBGLOG("rad", "disabling Metal support");
- uint8_t find1[] {0x4D, 0x65, 0x74, 0x61, 0x6C, 0x53, 0x74, 0x61};
- uint8_t find2[] {0x4D, 0x65, 0x74, 0x61, 0x6C, 0x50, 0x6C, 0x75};
- uint8_t repl1[] {0x50, 0x65, 0x74, 0x61, 0x6C, 0x53, 0x74, 0x61};
- uint8_t repl2[] {0x50, 0x65, 0x74, 0x61, 0x6C, 0x50, 0x6C, 0x75};
-
- KernelPatcher::LookupPatch antimetal[] {
- {&hardware, find1, repl1, sizeof(find1), 2},
- {&hardware, find2, repl2, sizeof(find1), 2}
- };
+struct dpcd_bits_per_pixel_increment{
+ uint8_t INCREMENT_OF_BITS_PER_PIXEL_SUPPORTED :3;
+ uint8_t RESERVED :5;
+};
+union dpcd_dsc_basic_capabilities {
+ struct {
+ struct dpcd_dsc_support dsc_support;
+ struct dpcd_dsc_algorithm_revision dsc_algorithm_revision;
+ struct dpcd_dsc_rc_buffer_block_size dsc_rc_buffer_block_size;
+ uint8_t dsc_rc_buffer_size;
+ struct dpcd_dsc_slice_capability1 dsc_slice_capabilities_1;
+ struct dpcd_dsc_line_buffer_bit_depth dsc_line_buffer_bit_depth;
+ struct dpcd_dsc_block_prediction_support dsc_block_prediction_support;
+ struct dpcd_maximum_bits_per_pixel_supported_by_the_decompressor maximum_bits_per_pixel_supported_by_the_decompressor;
+ struct dpcd_dsc_decoder_color_format_capabilities dsc_decoder_color_format_capabilities;
+ struct dpcd_dsc_decoder_color_depth_capabilities dsc_decoder_color_depth_capabilities;
+ struct dpcd_peak_dsc_throughput_dsc_sink peak_dsc_throughput_dsc_sink;
+ uint8_t dsc_maximum_slice_width;
+ struct dpcd_dsc_slice_capabilities_2 dsc_slice_capabilities_2;
+ uint8_t reserved;
+ struct dpcd_bits_per_pixel_increment bits_per_pixel_increment;
+ } fields;
+ uint8_t raw[16];
+};
- for (auto &p : antimetal) {
- patcher.applyLookupPatch(&p);
- patcher.clearError();
- }
- }
+struct dpcd_dsc_capabilities {
+ union dpcd_dsc_basic_capabilities dsc_basic_caps;
+ union dpcd_dsc_branch_decoder_capabilities dsc_branch_decoder_caps;
+};
- // Patch AppleGVA support for non-supported models
- if (forceCodecInfo && getHWInfoProcNames[hwIndex] != nullptr) {
- KernelPatcher::RouteRequest request(getHWInfoProcNames[hwIndex], wrapGetHWInfo[hwIndex], orgGetHWInfo[hwIndex]);
- patcher.routeMultiple(hardware.loadIndex, &request, 1, address, size);
- }
-}
+#define MAX_REPEATER_CNT 8
-void RAD::mergeProperty(OSDictionary *props, const char *name, OSObject *value) {
- // The only type we could make from device properties is data.
- // To be able to override other types we do a conversion here.
- auto data = OSDynamicCast(OSData, value);
- if (data) {
- // It is hard to make a boolean even from ACPI, so we make a hack here:
- // 1-byte OSData with 0x01 / 0x00 values becomes boolean.
- auto val = static_cast<const uint8_t *>(data->getBytesNoCopy());
- auto len = data->getLength();
- if (val && len == sizeof(uint8_t)) {
- if (val[0] == 1) {
- props->setObject(name, kOSBooleanTrue);
- DBGLOG("rad", "prop %s was merged as kOSBooleanTrue", name);
- return;
- } else if (val[0] == 0) {
- props->setObject(name, kOSBooleanFalse);
- DBGLOG("rad", "prop %s was merged as kOSBooleanFalse", name);
- return;
- }
- }
+struct dc_lttpr_caps {
+ union dpcd_rev revision;
+ uint8_t mode;
+ uint8_t max_lane_count;
+ uint8_t max_link_rate;
+ uint8_t phy_repeater_cnt;
+ uint8_t max_ext_timeout;
+ uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
+};
- // Consult the original value to make a decision
- auto orgValue = props->getObject(name);
- if (val && orgValue) {
- DBGLOG("rad", "prop %s has original value", name);
- if (len == sizeof(uint32_t) && OSDynamicCast(OSNumber, orgValue)) {
- auto num = *reinterpret_cast<const uint32_t *>(val);
- auto osnum = OSNumber::withNumber(num, 32);
- if (osnum) {
- DBGLOG("rad", "prop %s was merged as number %u", name, num);
- props->setObject(name, osnum);
- osnum->release();
- }
- return;
- } else if (len > 0 && val[len-1] == '\0' && OSDynamicCast(OSString, orgValue)) {
- auto str = reinterpret_cast<const char *>(val);
- auto osstr = OSString::withCString(str);
- if (osstr) {
- DBGLOG("rad", "prop %s was merged as string %s", name, str);
- props->setObject(name, osstr);
- osstr->release();
- }
- return;
- }
- } else {
- DBGLOG("rad", "prop %s has no original value", name);
- }
- }
+struct psr_caps {
+ unsigned char psr_version;
+ unsigned int psr_rfb_setup_time;
+ bool psr_exit_link_training_required;
+};
- // Default merge as is
- props->setObject(name, value);
- DBGLOG("rad", "prop %s was merged", name);
-}
+struct dpcd_caps {
+ union dpcd_rev dpcd_rev;
+ union max_lane_count max_ln_count;
+ union max_down_spread max_down_spread;
+ union dprx_feature dprx_feature;
+
+ /* valid only for eDP v1.4 or higher*/
+ uint8_t edp_supported_link_rates_count;
+ uint32_t edp_supported_link_rates[8];
+
+ /* dongle type (DP converter, CV smart dongle) */
+ uint32_t dongle_type;
+ /* branch device or sink device */
+ bool is_branch_dev;
+ /* Dongle's downstream count. */
+ union sink_count sink_count;
+ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
+ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
+ struct dc_dongle_caps dongle_caps;
+
+ uint32_t sink_dev_id;
+ int8_t sink_dev_id_str[6];
+ int8_t sink_hw_revision;
+ int8_t sink_fw_revision[2];
+
+ uint32_t branch_dev_id;
+ int8_t branch_dev_name[6];
+ int8_t branch_hw_revision;
+ int8_t branch_fw_revision[2];
+
+ bool allow_invalid_MSA_timing_param;
+ bool panel_mode_edp;
+ bool dpcd_display_control_capable;
+ bool ext_receiver_cap_field_present;
+ bool dynamic_backlight_capable_edp;
+ union dpcd_fec_capability fec_cap;
+ struct dpcd_dsc_capabilities dsc_caps;
+ struct dc_lttpr_caps lttpr_caps;
+ struct psr_caps psr_caps;
-void RAD::mergeProperties(OSDictionary *props, const char *prefix, IOService *provider) {
- // Should be ok, but in case there are issues switch to dictionaryWithProperties();
- auto dict = provider->getPropertyTable();
- if (dict) {
- auto iterator = OSCollectionIterator::withCollection(dict);
- if (iterator) {
- OSSymbol *propname;
- size_t prefixlen = strlen(prefix);
- while ((propname = OSDynamicCast(OSSymbol, iterator->getNextObject())) != nullptr) {
- auto name = propname->getCStringNoCopy();
- if (name && propname->getLength() > prefixlen && !strncmp(name, prefix, prefixlen)) {
- auto prop = dict->getObject(propname);
- if (prop)
- mergeProperty(props, name + prefixlen, prop);
- else
- DBGLOG("rad", "prop %s was not merged due to no value", name);
- } else {
- //DBGLOG("rad", "prop %s does not match %s prefix", safeString(name), prefix);
- }
- }
+};
- iterator->release();
- } else {
- SYSLOG("rad", "prop merge failed to iterate over properties");
- }
- } else {
- SYSLOG("rad", "prop merge failed to get properties");
- }
+union dpcd_sink_ext_caps {
+ struct {
+ /* 0 - Sink supports backlight adjust via PWM during SDR/HDR mode
+ * 1 - Sink supports backlight adjust via AUX during SDR/HDR mode.
+ */
+ uint8_t sdr_aux_backlight_control : 1;
+ uint8_t hdr_aux_backlight_control : 1;
+ uint8_t reserved_1 : 2;
+ uint8_t oled : 1;
+ uint8_t reserved : 3;
+ } bits;
+ uint8_t raw;
+};
- if (!strcmp(prefix, "CAIL,")) {
- for (size_t i = 0; i < arrsize(powerGatingFlags); i++) {
- if (powerGatingFlags[i] && props->getObject(powerGatingFlags[i])) {
- DBGLOG("rad", "cail prop merge found %s, replacing", powerGatingFlags[i]);
- auto num = OSNumber::withNumber(1, 32);
- if (num) {
- props->setObject(powerGatingFlags[i], num);
- num->release();
- }
- }
- }
- }
-}
+struct dc;
+
+typedef struct {
+ void *remote_sinks[MAX_SINKS_PER_LINK];
+ unsigned int sink_count;
+ void *local_sink;
+ unsigned int link_index;
+ uint32_t type;
+ uint32_t connector_signal;
+ uint32_t irq_source_hpd;
+ uint32_t irq_source_hpd_rx;/* aka DP Short Pulse */
+ bool is_hpd_filter_disabled;
+ bool dp_ss_off;
+ bool link_state_valid;
+ bool aux_access_disabled;
+ bool sync_lt_in_progress;
+ uint32_t lttpr_mode;
+ bool is_internal_display;
+
+ /* TODO: Rename. Flag an endpoint as having a programmable mapping to a
+ * DIG encoder. */
+ bool is_dig_mapping_flexible;
+ bool hpd_status; /* HPD status of link without physical HPD pin. */
+
+ bool edp_sink_present;
+
+ /* caps is the same as reported_link_cap. link_traing use
+ * reported_link_cap. Will clean up. TODO
+ */
+ struct dc_link_settings reported_link_cap;
+ struct dc_link_settings verified_link_cap;
+ struct dc_link_settings cur_link_settings;
+ struct dc_lane_settings cur_lane_setting;
+ struct dc_link_settings preferred_link_setting;
+ struct dc_link_training_overrides preferred_training_settings;
+ struct dp_audio_test_data audio_test_data;
+
+ uint8_t ddc_hw_inst;
+
+ uint8_t hpd_src;
+
+ uint8_t link_enc_hw_inst;
+ /* DIG link encoder ID. Used as index in link encoder resource pool.
+ * For links with fixed mapping to DIG, this is not changed after dc_link
+ * object creation.
+ */
+ uint32_t eng_id;
+
+ bool test_pattern_enabled;
+ union compliance_test_state compliance_test_state;
+
+ void *priv;
+
+ void *ddc;
+
+ bool aux_mode;
+
+ /* Private to DC core */
+
+ struct dc *dc;
+
+ void *ctx;
+
+ void *panel_cntl;
+ void *link_enc;
+ struct graphics_object_id link_id;
+ /* Endpoint type distinguishes display endpoints which do not have entries
+ * in the BIOS connector table from those that do. Helps when tracking link
+ * encoder to display endpoint assignments.
+ */
+ uint32_t ep_type;
+ union ddi_channel_mapping ddi_channel_mapping;
+ struct connector_device_tag_info device_tag;
+ struct dpcd_caps dpcd_caps;
+ uint32_t dongle_max_pix_clk;
+ unsigned short chip_caps;
+ unsigned int dpcd_sink_count;
+//#if defined(CONFIG_DRM_AMD_DC_HDCP)
+// struct hdcp_caps hdcp_caps;
+//#endif
+ uint32_t edp_revision;
+ union dpcd_sink_ext_caps dpcd_sink_ext_caps;
+
+ /*
+ struct psr_settings psr_settings;
+
+ // MST record stream using this link
+ struct link_flags {
+ bool dp_keep_receiver_powered;
+ bool dp_skip_DID2;
+ bool dp_skip_reset_segment;
+ } wa_flags;
+ struct link_mst_stream_allocation_table mst_stream_alloc_table;
+
+ struct dc_link_status link_status;
+
+ struct link_trace link_trace;
+ struct gpio *hpd_gpio;
+ enum dc_link_fec_state fec_state;
+ */
+} my_dc_link_t;
+
+typedef struct {
+ void* plane_state;
+ struct dc_stream_state *stream;
+} my_pipe_ctx_t;
+
+struct panel_cntl_backlight_registers {
+ unsigned int BL_PWM_CNTL;
+ unsigned int BL_PWM_CNTL2;
+ unsigned int BL_PWM_PERIOD_CNTL;
+ unsigned int LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV;
+};
-void RAD::applyPropertyFixes(IOService *service, uint32_t connectorNum) {
- if (service && getKernelVersion() >= KernelVersion::HighSierra) {
- // Starting with 10.13.2 this is important to fix sleep issues due to enforced 6 screens
- if (!service->getProperty("CFG,CFG_FB_LIMIT")) {
- DBGLOG("rad", "setting fb limit to %u", connectorNum);
- service->setProperty("CFG_FB_LIMIT", connectorNum, 32);
- }
+struct hw_asic_id {
+ uint32_t chip_id;
+ uint32_t chip_family;
+ uint32_t pci_revision_id;
+ uint32_t hw_internal_rev;
+ uint32_t vram_type;
+ uint32_t vram_width;
+ uint32_t feature_flags;
+ uint32_t fake_paths_num;
+ void *atombios_base_address;
+};
- // In the past we set CFG_USE_AGDC to false, which caused visual glitches and broken multimonitor support.
- // A better workaround is to disable AGDP just like we do globally.
- }
-}
+struct dc_vram_info {
+ unsigned int num_chans;
+ unsigned int dram_channel_width_bytes;
+};
-void RAD::updateConnectorsInfo(void *atomutils, t_getAtomObjectTableForType gettable, IOService *ctrl, RADConnectors::Connector *connectors, uint8_t *sz) {
- if (atomutils) {
- DBGLOG("rad", "getConnectorsInfo found %u connectors", *sz);
- RADConnectors::print(connectors, *sz);
- }
+struct dc_golden_table {
+ uint16_t dc_golden_table_ver;
+ uint32_t aux_dphy_rx_control0_val;
+ uint32_t aux_dphy_tx_control_val;
+ uint32_t aux_dphy_rx_control1_val;
+ uint32_t dc_gpio_aux_ctrl_0_val;
+ uint32_t dc_gpio_aux_ctrl_1_val;
+ uint32_t dc_gpio_aux_ctrl_2_val;
+ uint32_t dc_gpio_aux_ctrl_3_val;
+ uint32_t dc_gpio_aux_ctrl_4_val;
+ uint32_t dc_gpio_aux_ctrl_5_val;
+};
- // Check if the user wants to override automatically detected connectors
- auto cons = ctrl->getProperty("connectors");
- if (cons) {
- auto consData = OSDynamicCast(OSData, cons);
- if (consData) {
- auto consPtr = consData->getBytesNoCopy();
- auto consSize = consData->getLength();
-
- uint32_t consCount;
- if (WIOKit::getOSDataValue(ctrl, "connector-count", consCount)) {
- *sz = consCount;
- DBGLOG("rad", "getConnectorsInfo got size override to %u", *sz);
- }
+struct dc_firmware_info {
+ struct pll_info {
+ uint32_t crystal_frequency; /* in KHz */
+ uint32_t min_input_pxl_clk_pll_frequency; /* in KHz */
+ uint32_t max_input_pxl_clk_pll_frequency; /* in KHz */
+ uint32_t min_output_pxl_clk_pll_frequency; /* in KHz */
+ uint32_t max_output_pxl_clk_pll_frequency; /* in KHz */
+ } pll_info;
+
+ struct firmware_feature {
+ uint32_t memory_clk_ss_percentage;
+ uint32_t engine_clk_ss_percentage;
+ } feature;
+
+ uint32_t default_display_engine_pll_frequency; /* in KHz */
+ uint32_t external_clock_source_frequency_for_dp; /* in KHz */
+ uint32_t smu_gpu_pll_output_freq; /* in KHz */
+ uint8_t min_allowed_bl_level;
+ uint8_t remote_display_config;
+ uint32_t default_memory_clk; /* in KHz */
+ uint32_t default_engine_clk; /* in KHz */
+ uint32_t dp_phy_ref_clk; /* in KHz - DCE12 only */
+ uint32_t i2c_engine_ref_clk; /* in KHz - DCE12 only */
+ bool oem_i2c_present;
+ uint8_t oem_i2c_obj_id;
- if (consPtr && consSize > 0 && *sz > 0 && RADConnectors::valid(consSize, *sz)) {
- RADConnectors::copy(connectors, *sz, static_cast<const RADConnectors::Connector *>(consPtr), consSize);
- DBGLOG("rad", "getConnectorsInfo installed %u connectors", *sz);
- applyPropertyFixes(ctrl, *sz);
- } else {
- DBGLOG("rad", "getConnectorsInfo conoverrides have invalid size %u for %u num", consSize, *sz);
- }
- } else {
- DBGLOG("rad", "getConnectorsInfo conoverrides have invalid type");
- }
- } else {
- if (atomutils) {
- DBGLOG("rad", "getConnectorsInfo attempting to autofix connectors");
- uint8_t sHeader = 0, displayPathNum = 0, connectorObjectNum = 0;
- auto baseAddr = static_cast<uint8_t *>(gettable(atomutils, AtomObjectTableType::Common, &sHeader)) - sizeof(uint32_t);
- auto displayPaths = static_cast<AtomDisplayObjectPath *>(gettable(atomutils, AtomObjectTableType::DisplayPath, &displayPathNum));
- auto connectorObjects = static_cast<AtomConnectorObject *>(gettable(atomutils, AtomObjectTableType::ConnectorObject, &connectorObjectNum));
- if (displayPathNum == connectorObjectNum)
- autocorrectConnectors(baseAddr, displayPaths, displayPathNum, connectorObjects, connectorObjectNum, connectors, *sz);
- else
- DBGLOG("rad", "getConnectorsInfo found different displaypaths %u and connectors %u", displayPathNum, connectorObjectNum);
- }
+};
- applyPropertyFixes(ctrl, *sz);
-
- // Prioritise connectors, since it may cause black screen on e.g. R9 370
- const uint8_t *senseList = nullptr;
- uint8_t senseNum = 0;
- auto priData = OSDynamicCast(OSData, ctrl->getProperty("connector-priority"));
- if (priData) {
- senseList = static_cast<const uint8_t *>(priData->getBytesNoCopy());
- senseNum = static_cast<uint8_t>(priData->getLength());
- DBGLOG("rad", "getConnectorInfo found %u senses in connector-priority", senseNum);
- reprioritiseConnectors(senseList, senseNum, connectors, *sz);
- } else {
- DBGLOG("rad", "getConnectorInfo leaving unchaged priority");
- }
- }
+#define NUMBER_OF_UCHAR_FOR_GUID 16
+#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7
+#define NUMBER_OF_CSR_M3_ARB 10
+#define NUMBER_OF_DISP_CLK_VOLTAGE 4
+#define NUMBER_OF_AVAILABLE_SCLK 5
- DBGLOG("rad", "getConnectorsInfo resulting %u connectors follow", *sz);
- RADConnectors::print(connectors, *sz);
-}
+struct i2c_reg_info {
+ unsigned char i2c_reg_index;
+ unsigned char i2c_reg_val;
+};
-void RAD::autocorrectConnectors(uint8_t *baseAddr, AtomDisplayObjectPath *displayPaths, uint8_t displayPathNum, AtomConnectorObject *connectorObjects,
- uint8_t connectorObjectNum, RADConnectors::Connector *connectors, uint8_t sz) {
- for (uint8_t i = 0; i < displayPathNum; i++) {
- if (!isEncoder(displayPaths[i].usGraphicObjIds)) {
- DBGLOG("rad", "autocorrectConnectors not encoder %X at %u", displayPaths[i].usGraphicObjIds, i);
- continue;
- }
+struct edp_info {
+ uint16_t edp_backlight_pwm_hz;
+ uint16_t edp_ss_percentage;
+ uint16_t edp_ss_rate_10hz;
+ uint8_t edp_pwr_on_off_delay;
+ uint8_t edp_pwr_on_vary_bl_to_blon;
+ uint8_t edp_pwr_down_bloff_to_vary_bloff;
+ uint8_t edp_panel_bpc;
+ uint8_t edp_bootup_bl_level;
+};
- uint8_t txmit = 0, enc = 0;
- if (!getTxEnc(displayPaths[i].usGraphicObjIds, txmit, enc))
- continue;
+struct integrated_info {
+ struct clock_voltage_caps {
+ /* The Voltage Index indicated by FUSE, same voltage index
+ shared with SCLK DPM fuse table */
+ uint32_t voltage_index;
+ /* Maximum clock supported with specified voltage index */
+ uint32_t max_supported_clk; /* in KHz */
+ } disp_clk_voltage[NUMBER_OF_DISP_CLK_VOLTAGE];
+
+ struct display_connection_info {
+ struct external_display_path {
+ /* A bit vector to show what devices are supported */
+ uint32_t device_tag;
+ /* 16bit device ACPI id. */
+ uint32_t device_acpi_enum;
+ /* A physical connector for displays to plug in,
+ using object connector definitions */
+ struct graphics_object_id device_connector_id;
+ /* An index into external AUX/DDC channel LUT */
+ uint8_t ext_aux_ddc_lut_index;
+ /* An index into external HPD pin LUT */
+ uint8_t ext_hpd_pin_lut_index;
+ /* external encoder object id */
+ struct graphics_object_id ext_encoder_obj_id;
+ /* XBAR mapping of the PHY channels */
+ union ddi_channel_mapping channel_mapping;
+
+ unsigned short caps;
+ } path[MAX_NUMBER_OF_EXT_DISPLAY_PATH];
+
+ uint8_t gu_id[NUMBER_OF_UCHAR_FOR_GUID];
+ uint8_t checksum;
+ } ext_disp_conn_info; /* exiting long long time */
+
+ struct available_s_clk_list {
+ /* Maximum clock supported with specified voltage index */
+ uint32_t supported_s_clk; /* in KHz */
+ /* The Voltage Index indicated by FUSE for specified SCLK */
+ uint32_t voltage_index;
+ /* The Voltage ID indicated by FUSE for specified SCLK */
+ uint32_t voltage_id;
+ } avail_s_clk[NUMBER_OF_AVAILABLE_SCLK];
+
+ uint8_t memory_type;
+ uint8_t ma_channel_number;
+ uint32_t boot_up_engine_clock; /* in KHz */
+ uint32_t dentist_vco_freq; /* in KHz */
+ uint32_t boot_up_uma_clock; /* in KHz */
+ uint32_t boot_up_req_display_vector;
+ uint32_t other_display_misc;
+ uint32_t gpu_cap_info;
+ uint32_t sb_mmio_base_addr;
+ uint32_t system_config;
+ uint32_t cpu_cap_info;
+ uint32_t max_nb_voltage;
+ uint32_t min_nb_voltage;
+ uint32_t boot_up_nb_voltage;
+ uint32_t ext_disp_conn_info_offset;
+ uint32_t csr_m3_arb_cntl_default[NUMBER_OF_CSR_M3_ARB];
+ uint32_t csr_m3_arb_cntl_uvd[NUMBER_OF_CSR_M3_ARB];
+ uint32_t csr_m3_arb_cntl_fs3d[NUMBER_OF_CSR_M3_ARB];
+ uint32_t gmc_restore_reset_time;
+ uint32_t minimum_n_clk;
+ uint32_t idle_n_clk;
+ uint32_t ddr_dll_power_up_time;
+ uint32_t ddr_pll_power_up_time;
+ /* start for V6 */
+ uint32_t pcie_clk_ss_type;
+ uint32_t lvds_ss_percentage;
+ uint32_t lvds_sspread_rate_in_10hz;
+ uint32_t hdmi_ss_percentage;
+ uint32_t hdmi_sspread_rate_in_10hz;
+ uint32_t dvi_ss_percentage;
+ uint32_t dvi_sspread_rate_in_10_hz;
+ uint32_t sclk_dpm_boost_margin;
+ uint32_t sclk_dpm_throttle_margin;
+ uint32_t sclk_dpm_tdp_limit_pg;
+ uint32_t sclk_dpm_tdp_limit_boost;
+ uint32_t boost_engine_clock;
+ uint32_t boost_vid_2bit;
+ uint32_t enable_boost;
+ uint32_t gnb_tdp_limit;
+ /* Start from V7 */
+ uint32_t max_lvds_pclk_freq_in_single_link;
+ uint32_t lvds_misc;
+ uint32_t lvds_pwr_on_seq_dig_on_to_de_in_4ms;
+ uint32_t lvds_pwr_on_seq_de_to_vary_bl_in_4ms;
+ uint32_t lvds_pwr_off_seq_vary_bl_to_de_in4ms;
+ uint32_t lvds_pwr_off_seq_de_to_dig_on_in4ms;
+ uint32_t lvds_off_to_on_delay_in_4ms;
+ uint32_t lvds_pwr_on_seq_vary_bl_to_blon_in_4ms;
+ uint32_t lvds_pwr_off_seq_blon_to_vary_bl_in_4ms;
+ uint32_t lvds_reserved1;
+ uint32_t lvds_bit_depth_control_val;
+ //Start from V9
+ unsigned char dp0_ext_hdmi_slv_addr;
+ unsigned char dp0_ext_hdmi_reg_num;
+ struct i2c_reg_info dp0_ext_hdmi_reg_settings[9];
+ unsigned char dp0_ext_hdmi_6g_reg_num;
+ struct i2c_reg_info dp0_ext_hdmi_6g_reg_settings[3];
+ unsigned char dp1_ext_hdmi_slv_addr;
+ unsigned char dp1_ext_hdmi_reg_num;
+ struct i2c_reg_info dp1_ext_hdmi_reg_settings[9];
+ unsigned char dp1_ext_hdmi_6g_reg_num;
+ struct i2c_reg_info dp1_ext_hdmi_6g_reg_settings[3];
+ unsigned char dp2_ext_hdmi_slv_addr;
+ unsigned char dp2_ext_hdmi_reg_num;
+ struct i2c_reg_info dp2_ext_hdmi_reg_settings[9];
+ unsigned char dp2_ext_hdmi_6g_reg_num;
+ struct i2c_reg_info dp2_ext_hdmi_6g_reg_settings[3];
+ unsigned char dp3_ext_hdmi_slv_addr;
+ unsigned char dp3_ext_hdmi_reg_num;
+ struct i2c_reg_info dp3_ext_hdmi_reg_settings[9];
+ unsigned char dp3_ext_hdmi_6g_reg_num;
+ struct i2c_reg_info dp3_ext_hdmi_6g_reg_settings[3];
+ /* V11 */
+ uint32_t dp_ss_control;
+ /* V2.1 */
+ struct edp_info edp1_info;
+ struct edp_info edp2_info;
+};
- uint8_t sense = getSenseID(baseAddr + connectorObjects[i].usRecordOffset);
- if (!sense) {
- DBGLOG("rad", "autocorrectConnectors failed to detect sense for %u connector", i);
- continue;
- }
+struct dc_bios {
+ void *funcs;
- DBGLOG("rad", "autocorrectConnectors found txmit %02X enc %02X sense %02X for %u connector", txmit, enc, sense, i);
+ uint8_t *bios;
+ uint32_t bios_size;
- autocorrectConnector(getConnectorID(displayPaths[i].usConnObjectId), sense, txmit, enc, connectors, sz);
- }
-}
+ uint8_t *bios_local_image;
-void RAD::autocorrectConnector(uint8_t connector, uint8_t sense, uint8_t txmit, uint8_t enc, RADConnectors::Connector *connectors, uint8_t sz) {
- // This function attempts to fix the following issues:
- //
- // 1. Incompatible DVI transmitter on 290X, 370 and probably some other models
- // In this case a correct transmitter is detected by AtiAtomBiosDce60::getPropertiesForEncoderObject, however, later
- // in AtiAtomBiosDce60::getPropertiesForConnectorObject for DVI DL and TITFP513 this value is conjuncted with 0xCF,
- // which makes it wrong: 0x10 -> 0, 0x11 -> 1. As a result one gets black screen when connecting multiple displays.
- // getPropertiesForEncoderObject takes usGraphicObjIds and getPropertiesForConnectorObject takes usConnObjectId
-
- if (callbackRAD->dviSingleLink) {
- if (connector != CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I &&
- connector != CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D &&
- connector != CONNECTOR_OBJECT_ID_LVDS) {
- DBGLOG("rad", "autocorrectConnector found unsupported connector type %02X", connector);
- return;
- }
+ void *ctx;
+ void *regs;
+ struct integrated_info *integrated_info;
+ struct dc_firmware_info fw_info;
+ bool fw_info_valid;
+ struct dc_vram_info vram_info;
+ struct dc_golden_table golden_table;
+};
- auto fixTransmit = [](auto &con, uint8_t idx, uint8_t sense, uint8_t txmit) {
- if (con.sense == sense) {
- if (con.transmitter != txmit && (con.transmitter & 0xCF) == con.transmitter) {
- DBGLOG("rad", "autocorrectConnector replacing txmit %02X with %02X for %u connector sense %02X",
- con.transmitter, txmit, idx, sense);
- con.transmitter = txmit;
- }
- return true;
- }
- return false;
- };
+struct dmcu_version {
+ unsigned int interface_version;
+ unsigned int abm_version;
+ unsigned int psr_version;
+ unsigned int build_version;
+};
- bool isModern = RADConnectors::modern();
- for (uint8_t j = 0; j < sz; j++) {
- if (isModern) {
- auto &con = (&connectors->modern)[j];
- if (fixTransmit(con, j, sense, txmit))
- break;
- } else {
- auto &con = (&connectors->legacy)[j];
- if (fixTransmit(con, j, sense, txmit))
- break;
- }
- }
- } else {
- DBGLOG("rad", "autocorrectConnector use -raddvi to enable dvi autocorrection");
- }
+struct dc_versions {
+ const char *dc_ver;
+ struct dmcu_version dmcu_version;
+};
+
+#define MAX_PLANES 6
+
+struct dc_plane_cap {
+ uint32_t type;
+ uint32_t blends_with_above : 1;
+ uint32_t blends_with_below : 1;
+ uint32_t per_pixel_alpha : 1;
+ struct {
+ uint32_t argb8888 : 1;
+ uint32_t nv12 : 1;
+ uint32_t fp16 : 1;
+ uint32_t p010 : 1;
+ uint32_t ayuv : 1;
+ } pixel_format_support;
+ // max upscaling factor x1000
+ // upscaling factors are always >= 1
+ // for example, 1080p -> 8K is 4.0, or 4000 raw value
+ struct {
+ uint32_t argb8888;
+ uint32_t nv12;
+ uint32_t fp16;
+ } max_upscale_factor;
+ // max downscale factor x1000
+ // downscale factors are always <= 1
+ // for example, 8K -> 1080p is 0.25, or 250 raw value
+ struct {
+ uint32_t argb8888;
+ uint32_t nv12;
+ uint32_t fp16;
+ } max_downscale_factor;
+ // minimal width/height
+ uint32_t min_width;
+ uint32_t min_height;
+};
+
+struct rom_curve_caps {
+ uint16_t srgb : 1;
+ uint16_t bt2020 : 1;
+ uint16_t gamma2_2 : 1;
+ uint16_t pq : 1;
+ uint16_t hlg : 1;
+};
+
+struct dpp_color_caps {
+ uint16_t dcn_arch : 1; // all DCE generations treated the same
+ // input lut is different than most LUTs, just plain 256-entry lookup
+ uint16_t input_lut_shared : 1; // shared with DGAM
+ uint16_t icsc : 1;
+ uint16_t dgam_ram : 1;
+ uint16_t post_csc : 1; // before gamut remap
+ uint16_t gamma_corr : 1;
+
+ // hdr_mult and gamut remap always available in DPP (in that order)
+ // 3d lut implies shaper LUT,
+ // it may be shared with MPC - check MPC:shared_3d_lut flag
+ uint16_t hw_3d_lut : 1;
+ uint16_t ogam_ram : 1; // blnd gam
+ uint16_t ocsc : 1;
+ uint16_t dgam_rom_for_yuv : 1;
+ struct rom_curve_caps dgam_rom_caps;
+ struct rom_curve_caps ogam_rom_caps;
+};
+
+struct mpc_color_caps {
+ uint16_t gamut_remap : 1;
+ uint16_t ogam_ram : 1;
+ uint16_t ocsc : 1;
+ uint16_t num_3dluts : 3; //3d lut always assumes a preceding shaper LUT
+ uint16_t shared_3d_lut:1; //can be in either DPP or MPC, but single instance
+
+ struct rom_curve_caps ogam_rom_caps;
+};
+
+struct dc_color_caps {
+ struct dpp_color_caps dpp;
+ struct mpc_color_caps mpc;
+};
+
+struct dc_caps {
+ uint32_t max_streams;
+ uint32_t max_links;
+ uint32_t max_audios;
+ uint32_t max_slave_planes;
+ uint32_t max_slave_yuv_planes;
+ uint32_t max_slave_rgb_planes;
+ uint32_t max_planes;
+ uint32_t max_downscale_ratio;
+ uint32_t i2c_speed_in_khz;
+ uint32_t i2c_speed_in_khz_hdcp;
+ uint32_t dmdata_alloc_size;
+ unsigned int max_cursor_size;
+ unsigned int max_video_width;
+ unsigned int min_horizontal_blanking_period;
+ int linear_pitch_alignment;
+ bool dcc_const_color;
+ bool dynamic_audio;
+ bool is_apu;
+ bool dual_link_dvi;
+ bool post_blend_color_processing;
+ bool force_dp_tps4_for_cp2520;
+ bool disable_dp_clk_share;
+ bool psp_setup_panel_mode;
+ bool extended_aux_timeout_support;
+ bool dmcub_support;
+ uint32_t num_of_internal_disp;
+ uint32_t max_dp_protocol_version;
+ unsigned int mall_size_per_mem_channel;
+ unsigned int mall_size_total;
+ unsigned int cursor_cache_size;
+ struct dc_plane_cap planes[MAX_PLANES];
+ struct dc_color_caps color;
+ bool vbios_lttpr_aware;
+ bool vbios_lttpr_enable;
+};
+
+struct dc_cap_funcs {
+ bool (*get_dcc_compression_cap)(const struct dc *dc,
+ const struct dc_dcc_surface_param *input,
+ struct dc_surface_dcc_cap *output);
+};
+
+struct dc_config {
+ bool gpu_vm_support;
+ bool disable_disp_pll_sharing;
+ bool fbc_support;
+ bool disable_fractional_pwm;
+ bool allow_seamless_boot_optimization;
+ bool power_down_display_on_boot;
+ bool edp_not_connected;
+ bool edp_no_power_sequencing;
+ bool force_enum_edp;
+ bool forced_clocks;
+ bool allow_lttpr_non_transparent_mode;
+ bool multi_mon_pp_mclk_switch;
+ bool disable_dmcu;
+ bool enable_4to1MPC;
+ bool allow_edp_hotplug_detection;
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// bool clamp_min_dcfclk;
+//#endif
+ uint64_t vblank_alignment_dto_params;
+ uint8_t vblank_alignment_max_frame_time_diff;
+ bool is_asymmetric_memory;
+ bool is_single_rank_dimm;
+};
+
+struct dc_bw_validation_profile {
+ bool enable;
+
+ unsigned long long total_ticks;
+ unsigned long long voltage_level_ticks;
+ unsigned long long watermark_ticks;
+ unsigned long long rq_dlg_ticks;
+
+ unsigned long long total_count;
+ unsigned long long skip_fast_count;
+ unsigned long long skip_pass_count;
+ unsigned long long skip_fail_count;
+};
+
+union mem_low_power_enable_options {
+ struct {
+ bool vga: 1;
+ bool i2c: 1;
+ bool dmcu: 1;
+ bool dscl: 1;
+ bool cm: 1;
+ bool mpc: 1;
+ bool optc: 1;
+ } bits;
+ uint32_t u32All;
+};
+
+struct dc_debug_options {
+ uint32_t visual_confirm;
+ bool sanity_checks;
+ bool max_disp_clk;
+ bool surface_trace;
+ bool timing_trace;
+ bool clock_trace;
+ bool validation_trace;
+ bool bandwidth_calcs_trace;
+ int max_downscale_src_width;
+
+ /* stutter efficiency related */
+ bool disable_stutter;
+ bool use_max_lb;
+ uint32_t disable_dcc;
+ uint32_t pipe_split_policy;
+ bool force_single_disp_pipe_split;
+ bool voltage_align_fclk;
+ bool disable_min_fclk;
+
+ bool disable_dfs_bypass;
+ bool disable_dpp_power_gate;
+ bool disable_hubp_power_gate;
+ bool disable_dsc_power_gate;
+ int dsc_min_slice_height_override;
+ int dsc_bpp_increment_div;
+ bool native422_support;
+ bool disable_pplib_wm_range;
+ uint32_t pplib_wm_report_mode;
+ unsigned int min_disp_clk_khz;
+ unsigned int min_dpp_clk_khz;
+ int sr_exit_time_dpm0_ns;
+ int sr_enter_plus_exit_time_dpm0_ns;
+ int sr_exit_time_ns;
+ int sr_enter_plus_exit_time_ns;
+ int urgent_latency_ns;
+ uint32_t underflow_assert_delay_us;
+ int percent_of_ideal_drambw;
+ int dram_clock_change_latency_ns;
+ bool optimized_watermark;
+ int always_scale;
+ bool disable_pplib_clock_request;
+ bool disable_clock_gate;
+ bool disable_mem_low_power;
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// bool pstate_enabled;
+//#endif
+ bool disable_dmcu;
+ bool disable_psr;
+ bool force_abm_enable;
+ bool disable_stereo_support;
+ bool vsr_support;
+ bool performance_trace;
+ bool az_endpoint_mute_only;
+ bool always_use_regamma;
+ bool recovery_enabled;
+ bool avoid_vbios_exec_table;
+ bool scl_reset_length10;
+ bool hdmi20_disable;
+ bool skip_detection_link_training;
+ uint32_t edid_read_retry_times;
+ bool remove_disconnect_edp;
+ unsigned int force_odm_combine; //bit vector based on otg inst
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// unsigned int force_odm_combine_4to1; //bit vector based on otg inst
+// bool disable_z9_mpc;
+//#endif
+ unsigned int force_fclk_khz;
+ bool enable_tri_buf;
+ bool dmub_offload_enabled;
+ bool dmcub_emulation;
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// bool disable_idle_power_optimizations;
+// unsigned int mall_size_override;
+// unsigned int mall_additional_timer_percent;
+// bool mall_error_as_fatal;
+//#endif
+ bool dmub_command_table; /* for testing only */
+ struct dc_bw_validation_profile bw_val_profile;
+ bool disable_fec;
+ bool disable_48mhz_pwrdwn;
+ /* This forces a hard min on the DCFCLK requested to SMU/PP
+ * watermarks are not affected.
+ */
+ unsigned int force_min_dcfclk_mhz;
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// int dwb_fi_phase;
+//#endif
+ bool disable_timing_sync;
+ bool cm_in_bypass;
+ int force_clock_mode;/*every mode change.*/
+
+ bool disable_dram_clock_change_vactive_support;
+ bool validate_dml_output;
+ bool enable_dmcub_surface_flip;
+ bool usbc_combo_phy_reset_wa;
+ bool disable_dsc;
+ bool enable_dram_clock_change_one_display_vactive;
+ union mem_low_power_enable_options enable_mem_low_power;
+ bool force_vblank_alignment;
+
+ /* Enable dmub aux for legacy ddc */
+ bool enable_dmub_aux_for_legacy_ddc;
+ bool optimize_edp_link_rate; /* eDP ILR */
+ /* force enable edp FEC */
+ bool force_enable_edp_fec;
+ /* FEC/PSR1 sequence enable delay in 100us */
+ uint8_t fec_enable_delay_in100us;
+//#if defined(CONFIG_DRM_AMD_DC_DCN)
+// bool disable_z10;
+// bool enable_sw_cntl_psr;
+//#endif
+};
+
+struct dc_bounding_box_overrides {
+ int sr_exit_time_ns;
+ int sr_enter_plus_exit_time_ns;
+ int urgent_latency_ns;
+ int percent_of_ideal_drambw;
+ int dram_clock_change_latency_ns;
+ int dummy_clock_change_latency_ns;
+ /* This forces a hard min on the DCFCLK we use
+ * for DML. Unlike the debug option for forcing
+ * DCFCLK, this override affects watermark calculations
+ */
+ int min_dcfclk_mhz;
+};
+
+struct dc_bug_wa {
+ bool no_connect_phy_config;
+ bool dedcn20_305_wa;
+ bool skip_clock_update;
+ bool lt_early_cr_pattern;
+};
+
+struct dc {
+ struct dc_versions versions;
+ struct dc_caps caps;
+ struct dc_cap_funcs cap_funcs;
+ struct dc_config config;
+ struct dc_debug_options debug;
+ struct dc_bounding_box_overrides bb_overrides;
+ struct dc_bug_wa work_arounds;
+ /*
+ struct dc_context *ctx;
+ struct dc_phy_addr_space_config vm_pa_config;
+
+ uint8_t link_count;
+ struct dc_link *links[MAX_PIPES * 2];
+
+ struct dc_state *current_state;
+ struct resource_pool *res_pool;
+
+ struct clk_mgr *clk_mgr;
+
+ // Display Engine Clock levels
+ struct dm_pp_clock_levels sclk_lvls;
+
+ // Inputs into BW and WM calculations.
+ struct bw_calcs_dceip *bw_dceip;
+ struct bw_calcs_vbios *bw_vbios;
+#ifdef CONFIG_DRM_AMD_DC_DCN
+ struct dcn_soc_bounding_box *dcn_soc;
+ struct dcn_ip_params *dcn_ip;
+ struct display_mode_lib dml;
+#endif
+
+ // HW functions
+ struct hw_sequencer_funcs hwss;
+ struct dce_hwseq *hwseq;
+
+ // Require to optimize clocks and bandwidth for added/removed planes
+ bool optimized_required;
+ bool wm_optimized_required;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ bool idle_optimizations_allowed;
+#endif
+
+ // Require to maintain clocks and bandwidth for UEFI enabled HW
+
+ // FBC compressor
+ struct compressor *fbc_compressor;
+
+ struct dc_debug_data debug_data;
+ struct dpcd_vendor_signature vendor_signature;
+
+ const char *build_id;
+ struct vm_helper *vm_helper;
+ */
+};
+
+struct dc_context {
+ struct dc *dc;
+
+ void *driver_context; /* e.g. amdgpu_device */
+ void *perf_trace;
+ void *cgs_device;
+
+ uint32_t dce_environment;
+ struct hw_asic_id asic_id;
+
+ /* todo: below should probably move to dc. to facilitate removal
+ * of AS we will store these here
+ */
+ uint32_t dce_version;
+ struct dc_bios *dc_bios;
+ bool created_bios;
+ void *gpio_service;
+ uint32_t dc_sink_id_count;
+ uint32_t dc_stream_id_count;
+ uint32_t dc_edp_id_count;
+ uint64_t fbc_gpu_addr;
+ void *dmub_srv;
+};
+
+struct panel_cntl_funcs {
+ void (*destroy)(struct panel_cntl **panel_cntl);
+ uint32_t (*hw_init)(struct panel_cntl *panel_cntl);
+ bool (*is_panel_backlight_on)(struct panel_cntl *panel_cntl);
+ bool (*is_panel_powered_on)(struct panel_cntl *panel_cntl);
+ void (*store_backlight_level)(struct panel_cntl *panel_cntl);
+ void (*driver_set_backlight)(struct panel_cntl *panel_cntl,
+ uint32_t backlight_pwm_u16_16);
+ uint32_t (*get_current_backlight)(struct panel_cntl *panel_cntl);
+};
+struct panel_cntl {
+ const struct panel_cntl_funcs *funcs;
+ struct dc_context *ctx;
+ uint32_t inst;
+ /* registers setting needs to be saved and restored at InitBacklight */
+ struct panel_cntl_backlight_registers stored_backlight_registers;
+};
+bool g_is_sleep = false;
+uint64_t g_last_sleep_time = 0;
+static my_dc_link_t* g_dc_link_ptr = NULL;
+static mach_vm_address_t orig_dce110_edp_backlight_control;
+
+static mach_vm_address_t orig_dce110_edp_power_control;
+static void wrap_dce110_edp_power_control(my_dc_link_t *dc_link, bool power_up) {
+ g_dc_link_ptr = dc_link;
+ if (orig_dce110_edp_power_control) {
+ FunctionCast(wrap_dce110_edp_power_control, orig_dce110_edp_power_control)(dc_link, power_up);
+ }
+ SYSLOG("igfx", "wrap_dce110_edp_power_control %d end - %p", power_up, g_dc_link_ptr);
}
-void RAD::reprioritiseConnectors(const uint8_t *senseList, uint8_t senseNum, RADConnectors::Connector *connectors, uint8_t sz) {
- static constexpr uint32_t typeList[] {
- RADConnectors::ConnectorLVDS,
- RADConnectors::ConnectorDigitalDVI,
- RADConnectors::ConnectorHDMI,
- RADConnectors::ConnectorDP,
- RADConnectors::ConnectorVGA
- };
- static constexpr uint8_t typeNum {static_cast<uint8_t>(arrsize(typeList))};
-
- bool isModern = RADConnectors::modern();
- uint16_t priCount = 1;
- // Automatically detected connectors have equal priority (0), which often results in black screen
- // This allows to change this firstly by user-defined list, then by type list.
- //TODO: priority is ignored for 5xxx and 6xxx GPUs, should we manually reorder items?
- for (uint8_t i = 0; i < senseNum + typeNum + 1; i++) {
- for (uint8_t j = 0; j < sz; j++) {
- auto reorder = [&](auto &con) {
- if (i == senseNum + typeNum) {
- if (con.priority == 0)
- con.priority = priCount++;
- } else if (i < senseNum) {
- if (con.sense == senseList[i]) {
- DBGLOG("rad", "reprioritiseConnectors setting priority of sense %02X to %u by sense", con.sense, priCount);
- con.priority = priCount++;
- return true;
- }
- } else {
- if (con.priority == 0 && con.type == typeList[i-senseNum]) {
- DBGLOG("rad", "reprioritiseConnectors setting priority of sense %02X to %u by type", con.sense, priCount);
- con.priority = priCount++;
- }
- }
- return false;
- };
-
- if ((isModern && reorder((&connectors->modern)[j])) ||
- (!isModern && reorder((&connectors->legacy)[j])))
- break;
- }
- }
+static char wrap_dce110_edp_backlight_control(my_dc_link_t *that, uint8_t a2) {
+ //SYSLOG("igfx", "wrap_dce110_edp_backlight_control start %p:%lu,%lu,%lu,%lu,%lu", that, on_or_off, a3, a4, a5, a6);
+ g_dc_link_ptr = that;
+ //if (g_dc_link_ptr && g_dc_link_ptr->dc) {
+ // SYSLOG("igfx", "dce110_edp_backlight_control disable_fractional_pwm: %u", g_dc_link_ptr->dc->config.disable_fractional_pwm);
+ //}
+ char ret = FunctionCast(wrap_dce110_edp_backlight_control, orig_dce110_edp_backlight_control)(that, a2);
+ SYSLOG("igfx", "wrap_dce110_edp_backlight_control end - %p, %d", g_dc_link_ptr, ret);
+
+ if (g_is_sleep) {
+ g_is_sleep = false;
+
+ if (g_dc_link_ptr) {
+ wrap_dce110_edp_backlight_control(g_dc_link_ptr, false);
+ wrap_dce110_edp_power_control(g_dc_link_ptr, false);
+ IOSleep(200);
+ wrap_dce110_edp_power_control(g_dc_link_ptr, true);
+ wrap_dce110_edp_backlight_control(g_dc_link_ptr, true);
+ }
+ }
+
+ return ret;
}
-void RAD::setGvaProperties(IOService *accelService) {
- auto codecStr = OSDynamicCast(OSString, accelService->getProperty("IOGVACodec"));
- if (codecStr == nullptr) {
- DBGLOG("rad", "updating X4000 accelerator IOGVACodec to VCE");
- accelService->setProperty("IOGVACodec", "VCE");
- } else {
- auto codec = codecStr->getCStringNoCopy();
- DBGLOG("rad", "X4000 accelerator IOGVACodec is already set to %s", safeString(codec));
- if (codec != nullptr && strncmp(codec, "AMD", strlen("AMD")) == 0) {
- bool needsDecode = accelService->getProperty("IOGVAHEVCDecode") == nullptr;
- bool needsEncode = accelService->getProperty("IOGVAHEVCEncode") == nullptr;
- if (needsDecode) {
- OSObject *VTMaxDecodeLevel = OSNumber::withNumber(153, 32);
- OSString *VTMaxDecodeLevelKey = OSString::withCString("VTMaxDecodeLevel");
- OSDictionary *VTPerProfileDetailsInner = OSDictionary::withCapacity(1);
- OSDictionary *VTPerProfileDetails = OSDictionary::withCapacity(3);
- OSString *VTPerProfileDetailsKey1 = OSString::withCString("1");
- OSString *VTPerProfileDetailsKey2 = OSString::withCString("2");
- OSString *VTPerProfileDetailsKey3 = OSString::withCString("3");
-
- OSArray *VTSupportedProfileArray = OSArray::withCapacity(3);
- OSNumber *VTSupportedProfileArray1 = OSNumber::withNumber(1, 32);
- OSNumber *VTSupportedProfileArray2 = OSNumber::withNumber(2, 32);
- OSNumber *VTSupportedProfileArray3 = OSNumber::withNumber(3, 32);
-
- OSDictionary *IOGVAHEVCDecodeCapabilities = OSDictionary::withCapacity(2);
- OSString *VTPerProfileDetailsKey = OSString::withCString("VTPerProfileDetails");
- OSString *VTSupportedProfileArrayKey = OSString::withCString("VTSupportedProfileArray");
-
- if (VTMaxDecodeLevel != nullptr && VTMaxDecodeLevelKey != nullptr && VTPerProfileDetailsInner != nullptr &&
- VTPerProfileDetails != nullptr && VTPerProfileDetailsKey1 != nullptr && VTPerProfileDetailsKey2 != nullptr &&
- VTPerProfileDetailsKey3 != nullptr && VTSupportedProfileArrayKey != nullptr && VTSupportedProfileArray1 != nullptr &&
- VTSupportedProfileArray2 != nullptr && VTSupportedProfileArray3 != nullptr && VTSupportedProfileArray != nullptr &&
- VTPerProfileDetailsKey != nullptr && IOGVAHEVCDecodeCapabilities != nullptr) {
- VTPerProfileDetailsInner->setObject(VTMaxDecodeLevelKey, VTMaxDecodeLevel);
- VTPerProfileDetails->setObject(VTPerProfileDetailsKey1, VTPerProfileDetailsInner);
- VTPerProfileDetails->setObject(VTPerProfileDetailsKey2, VTPerProfileDetailsInner);
- VTPerProfileDetails->setObject(VTPerProfileDetailsKey3, VTPerProfileDetailsInner);
-
- VTSupportedProfileArray->setObject(VTSupportedProfileArray1);
- VTSupportedProfileArray->setObject(VTSupportedProfileArray2);
- VTSupportedProfileArray->setObject(VTSupportedProfileArray3);
-
- IOGVAHEVCDecodeCapabilities->setObject(VTPerProfileDetailsKey, VTPerProfileDetails);
- IOGVAHEVCDecodeCapabilities->setObject(VTSupportedProfileArrayKey, VTSupportedProfileArray);
-
- accelService->setProperty("IOGVAHEVCDecode", "1");
- accelService->setProperty("IOGVAHEVCDecodeCapabilities", IOGVAHEVCDecodeCapabilities);
-
- DBGLOG("rad", "recovering IOGVAHEVCDecode");
- } else {
- SYSLOG("rad", "allocation failure in IOGVAHEVCDecode");
- }
-
- OSSafeReleaseNULL(VTMaxDecodeLevel);
- OSSafeReleaseNULL(VTMaxDecodeLevelKey);
- OSSafeReleaseNULL(VTPerProfileDetailsInner);
- OSSafeReleaseNULL(VTPerProfileDetails);
- OSSafeReleaseNULL(VTPerProfileDetailsKey1);
- OSSafeReleaseNULL(VTPerProfileDetailsKey2);
- OSSafeReleaseNULL(VTPerProfileDetailsKey3);
- OSSafeReleaseNULL(VTSupportedProfileArrayKey);
- OSSafeReleaseNULL(VTSupportedProfileArray1);
- OSSafeReleaseNULL(VTSupportedProfileArray2);
- OSSafeReleaseNULL(VTSupportedProfileArray3);
- OSSafeReleaseNULL(VTSupportedProfileArray);
- OSSafeReleaseNULL(VTPerProfileDetailsKey);
- OSSafeReleaseNULL(IOGVAHEVCDecodeCapabilities);
- }
+IOReturn RAD::wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute(IOService *framebuffer, IOIndex connectIndex, IOSelect attribute, uintptr_t value) {
+ IOReturn ret = FunctionCast(wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute, callbackRAD->orgAMDRadeonX6000AmdRadeonFramebufferSetAttribute)(framebuffer, connectIndex, attribute, value);
+ if (attribute != (UInt32)'bklt') {
+ return ret;
+ }
+
+ if (callbackRAD->maxPwmBacklightLvl == 0) {
+ DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute zero maxPwmBacklightLvl");
+ return 0;
+ }
+
+ if (callbackRAD->panelCntlPtr == nullptr) {
+ DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute null panel cntl");
+ return 0;
+ }
+
+ if (callbackRAD->orgDceDriverSetBacklight == nullptr) {
+ DBGLOG("igfx", "wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute null orgDcLinkSetBacklightLevel");
+ return 0;
+ }
+
+ // set the backlight of AMD navi10 driver
+ callbackRAD->curPwmBacklightLvl = (uint32_t)value;
+ uint32_t btlper = callbackRAD->curPwmBacklightLvl*100.0 / callbackRAD->maxPwmBacklightLvl;
+ if (btlper < 0) {
+ btlper = 0;
+ } else if (btlper > 100) {
+ btlper = 100;
+ }
+
+ int pwmval = (int)((btlper / 100.0) * 0xFF) << 8;
+ if (pwmval >= 0xFF00) {
+ // This is from the dmcu_set_backlight_level function of Linux source
+ // ...
+ // if (backlight_pwm_u16_16 & 0x10000)
+ // backlight_8_bit = 0xFF;
+ // else
+ // backlight_8_bit = (backlight_pwm_u16_16 >> 8) & 0xFF;
+ // ...
+ // The max brightness should have 0x10000 bit set
+ pwmval = 0x1FF00;
+ }
+
+ /*if (g_dc_link_ptr) {
+ __int64 v10 = 0;
+ __int64 v9 = *(_QWORD *)(*(_QWORD *)((__int64)g_dc_link_ptr + 304) + 944LL);
+ while ( true ) {
+ __int64 stream = *(_QWORD *)(v9 + v10 + 496);
+ if ( stream ) {
+ if (*(_QWORD *)(stream + 8) == (__int64)g_dc_link_ptr) {
+ __int64 pipe_ctx = (v9 + v10 + 488);
+ //SYSLOG("igfx", "my_set_backlight_lvl %p:%p, %d, %d", g_dc_link_ptr, pipe_ctx, backlight_pwm_u16_16, ramp);
+ _QWORD *a1 = (_QWORD *)pipe_ctx;
+ __int64 v5 = *(_QWORD *)(a1[1] + 8LL);
+ __int64 v6 = *(_QWORD *)(v5 + 320);
+ struct panel_cntl *panel_cntl = (struct panel_cntl *)v6;
+ SYSLOG("igfx", "panel_cntl: %p", panel_cntl);
+ break;
+ } else {
+ SYSLOG("igfx", "steam link %lu != %p", *(_QWORD *)(stream + 8), g_dc_link_ptr);
+ }
+ }
+ v10 += 1280LL;
+ if ( v10 >= 7680 )
+ break;
+ }
+ } else {
+ DBGLOG("igfx", "null g_dc_link_ptr");
+ }*/
+
+ struct panel_cntl* ppc = (struct panel_cntl*)callbackRAD->panelCntlPtr;
+ DBGLOG("igfx", "fb 0x%p, idx: %d, set brightness: 0x%p -> 0x%x, st: %d", framebuffer, connectIndex, callbackRAD->panelCntlPtr, pwmval, ppc->funcs->is_panel_powered_on(ppc));
+ callbackRAD->orgDceDriverSetBacklight(callbackRAD->panelCntlPtr, pwmval);
+ return 0;
+}
- if (needsEncode) {
- OSObject *VTMaxEncodeLevel = OSNumber::withNumber(153, 32);
- OSString *VTMaxEncodeLevelKey = OSString::withCString("VTMaxEncodeLevel");
-
- OSDictionary *VTPerProfileDetailsInner = OSDictionary::withCapacity(1);
- OSDictionary *VTPerProfileDetails = OSDictionary::withCapacity(1);
- OSString *VTPerProfileDetailsKey1 = OSString::withCString("1");
-
- OSArray *VTSupportedProfileArray = OSArray::withCapacity(1);
- OSNumber *VTSupportedProfileArray1 = OSNumber::withNumber(1, 32);
-
- OSDictionary *IOGVAHEVCEncodeCapabilities = OSDictionary::withCapacity(4);
- OSString *VTPerProfileDetailsKey = OSString::withCString("VTPerProfileDetails");
- OSString *VTQualityRatingKey = OSString::withCString("VTQualityRating");
- OSNumber *VTQualityRating = OSNumber::withNumber(50, 32);
- OSString *VTRatingKey = OSString::withCString("VTRating");
- OSNumber *VTRating = OSNumber::withNumber(350, 32);
- OSString *VTSupportedProfileArrayKey = OSString::withCString("VTSupportedProfileArray");
-
- if (VTMaxEncodeLevel != nullptr && VTMaxEncodeLevelKey != nullptr && VTPerProfileDetailsInner != nullptr &&
- VTPerProfileDetails != nullptr && VTPerProfileDetailsKey1 != nullptr && VTSupportedProfileArrayKey != nullptr &&
- VTSupportedProfileArray1 != nullptr && VTSupportedProfileArray != nullptr && VTPerProfileDetailsKey != nullptr &&
- VTQualityRatingKey != nullptr && VTQualityRating != nullptr && VTRatingKey != nullptr && VTRating != nullptr &&
- IOGVAHEVCEncodeCapabilities != nullptr) {
-
- VTPerProfileDetailsInner->setObject(VTMaxEncodeLevelKey, VTMaxEncodeLevel);
- VTPerProfileDetails->setObject(VTPerProfileDetailsKey1, VTPerProfileDetailsInner);
- VTSupportedProfileArray->setObject(VTSupportedProfileArray1);
-
- IOGVAHEVCEncodeCapabilities->setObject(VTPerProfileDetailsKey, VTPerProfileDetails);
- IOGVAHEVCEncodeCapabilities->setObject(VTQualityRatingKey, VTQualityRating);
- IOGVAHEVCEncodeCapabilities->setObject(VTRatingKey, VTRating);
- IOGVAHEVCEncodeCapabilities->setObject(VTSupportedProfileArrayKey, VTSupportedProfileArray);
-
- accelService->setProperty("IOGVAHEVCEncode", "1");
- accelService->setProperty("IOGVAHEVCEncodeCapabilities", IOGVAHEVCEncodeCapabilities);
-
- DBGLOG("rad", "recovering IOGVAHEVCEncode");
- } else {
- SYSLOG("rad", "allocation failure in IOGVAHEVCEncode");
- }
-
- OSSafeReleaseNULL(VTMaxEncodeLevel);
- OSSafeReleaseNULL(VTMaxEncodeLevelKey);
- OSSafeReleaseNULL(VTPerProfileDetailsInner);
- OSSafeReleaseNULL(VTPerProfileDetails);
- OSSafeReleaseNULL(VTPerProfileDetailsKey1);
- OSSafeReleaseNULL(VTSupportedProfileArrayKey);
- OSSafeReleaseNULL(VTSupportedProfileArray1);
- OSSafeReleaseNULL(VTSupportedProfileArray);
- OSSafeReleaseNULL(VTPerProfileDetailsKey);
- OSSafeReleaseNULL(VTQualityRatingKey);
- OSSafeReleaseNULL(VTQualityRating);
- OSSafeReleaseNULL(VTRatingKey);
- OSSafeReleaseNULL(VTRating);
- OSSafeReleaseNULL(IOGVAHEVCEncodeCapabilities);
- }
- }
- }
+uint32_t RAD::wrapDcePanelCntlHwInit(void *panel_cntl) {
+ callbackRAD->panelCntlPtr = panel_cntl;
+ callbackRAD->updatePwmMaxBrightnessFromInternalDisplay(); // read max brightness value from IOReg
+ struct panel_cntl* ppc = (struct panel_cntl*)callbackRAD->panelCntlPtr;
+ DBGLOG("igfx", "wrapDcePanelCntlHwInit: %p, bl: %d, pw: %d, bl: %d", panel_cntl, ppc->funcs->is_panel_backlight_on(ppc), ppc->funcs->is_panel_powered_on(ppc), ppc->funcs->get_current_backlight(ppc));
+ uint32_t ret = FunctionCast(wrapDcePanelCntlHwInit, callbackRAD->orgDcePanelCntlHwInit)(panel_cntl);
+ //if (ppc->funcs->is_panel_backlight_on(ppc) == 0 && ppc->funcs->is_panel_powered_on(ppc) == 1 && g_dc_link_ptr) {
+ //wrap_dce110_edp_backlight_control(g_dc_link_ptr, 0);
+ //wrap_dce110_edp_power_control(g_dc_link_ptr, false);
+ // g_is_sleep = true;
+ //}
+ DBGLOG("igfx", "wrapDcePanelCntlHwInit: %p - %u, st: %d", panel_cntl, ret, ppc->funcs->is_panel_powered_on(ppc));
+ return ret;
}
-void RAD::updateAccelConfig(size_t hwIndex, IOService *accelService, const char **accelConfig) {
- if (accelService && accelConfig) {
- if (fixConfigName) {
- auto gpuService = accelService->getParentEntry(gIOServicePlane);
-
- if (gpuService) {
- auto model = OSDynamicCast(OSData, gpuService->getProperty("model"));
- if (model) {
- auto modelStr = static_cast<const char *>(model->getBytesNoCopy());
- if (modelStr) {
- if (modelStr[0] == 'A' && ((modelStr[1] == 'M' && modelStr[2] == 'D') ||
- (modelStr[1] == 'T' && modelStr[2] == 'I')) && modelStr[3] == ' ') {
- modelStr += 4;
- }
-
- DBGLOG("rad", "updateAccelConfig found gpu model %s", modelStr);
- *accelConfig = modelStr;
- } else {
- DBGLOG("rad", "updateAccelConfig found null gpu model");
- }
- } else {
- DBGLOG("rad", "updateAccelConfig failed to find gpu model");
- }
-
- } else {
- DBGLOG("rad", "updateAccelConfig failed to find accelerator parent");
- }
- }
+IOReturn RAD::wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute(IOService *framebuffer, IOIndex connectIndex, IOSelect attribute, uintptr_t * value) {
+ IOReturn ret = FunctionCast(wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute, callbackRAD->orgAMDRadeonX6000AmdRadeonFramebufferGetAttribute)(framebuffer, connectIndex, attribute, value);
+ if (attribute == (UInt32)'bklt') {
+ // enable the backlight feature of AMD navi10 driver
+ *value = callbackRAD->curPwmBacklightLvl;
+ ret = 0;
+ }
+ return ret;
+}
- if (enableGvaSupport && hwIndex == IndexRadeonHardwareX4000) {
- setGvaProperties(accelService);
- }
- }
+static mach_vm_address_t Orig_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts;
+static int64_t Wrap_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts(__int64 a1, __int64 a2) {
+ SYSLOG("igfx", "Wrap_""AMDRadeonX6000_AmdInterruptManager_sleepInterrupts"" start " "%lu:%lu", a1, a2);
+ uint64_t currNs = getCurrentTimeNs();
+ if (currNs - g_last_sleep_time >= 1000000000) {
+ g_is_sleep = true;
+ g_last_sleep_time = getCurrentTimeNs();
+ }
+ int64_t ret = FunctionCast(Wrap_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts, Orig_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts)(a1, a2);
+ SYSLOG("igfx", "Wrap_""AMDRadeonX6000_AmdInterruptManager_sleepInterrupts"" end - " "%lu", ret);
+ return ret;
}
-bool RAD::wrapSetProperty(IORegistryEntry *that, const char *aKey, void *bytes, unsigned length) {
- if (length > 10 && aKey && reinterpret_cast<const uint32_t *>(aKey)[0] == 'edom' && reinterpret_cast<const uint16_t *>(aKey)[2] == 'l') {
- DBGLOG("rad", "SetProperty caught model %u (%.*s)", length, length, static_cast<char *>(bytes));
- if (*static_cast<uint32_t *>(bytes) == ' DMA' || *static_cast<uint32_t *>(bytes) == ' ITA' || *static_cast<uint32_t *>(bytes) == 'edaR') {
- if (FunctionCast(wrapGetProperty, callbackRAD->orgGetProperty)(that, aKey)) {
- DBGLOG("rad", "SetProperty ignored setting %s to %s", aKey, static_cast<char *>(bytes));
- return true;
- }
- DBGLOG("rad", "SetProperty missing %s, fallback to %s", aKey, static_cast<char *>(bytes));
- }
- }
+static mach_vm_address_t Orig_AMDRadeonX6000_AmdLogger_setDebugLevel;
+static int64_t Wrap_AMDRadeonX6000_AmdLogger_setDebugLevel(__int64 a1, int a2) {
+ SYSLOG("igfx", "Wrap_""AMDRadeonX6000_AmdLogger_setDebugLevel"" start " "%lu:%d", a1, a2);
+ a2 = 9999;
+ int64_t ret = FunctionCast(Wrap_AMDRadeonX6000_AmdLogger_setDebugLevel, Orig_AMDRadeonX6000_AmdLogger_setDebugLevel)(a1, a2);
+ SYSLOG("igfx", "Wrap_""AMDRadeonX6000_AmdLogger_setDebugLevel"" end - " "%lu", ret);
+ return ret;
+}
- return FunctionCast(wrapSetProperty, callbackRAD->orgSetProperty)(that, aKey, bytes, length);
+static mach_vm_address_t Orig_my_dm_logger_write;
+static char g_buffer[81920] = {0};
+static int64_t Wrap_my_dm_logger_write(int64_t a1, unsigned int a2, const char *a3, ...) {
+ va_list args;
+ va_start(args, a3);
+ vsnprintf(g_buffer, 8192, a3, args);
+ SYSLOG("igfx", "dm log, type: %d, msg: %s", a2, g_buffer);
+ va_end(args);
+ return 0;
}
-OSObject *RAD::wrapGetProperty(IORegistryEntry *that, const char *aKey) {
- auto obj = FunctionCast(wrapGetProperty, callbackRAD->orgGetProperty)(that, aKey);
- auto props = OSDynamicCast(OSDictionary, obj);
-
- if (props && aKey) {
- const char *prefix {nullptr};
- auto provider = OSDynamicCast(IOService, that->getParentEntry(gIOServicePlane));
- if (provider) {
- if (aKey[0] == 'a') {
- if (!strcmp(aKey, "aty_config"))
- prefix = "CFG,";
- else if (!strcmp(aKey, "aty_properties"))
- prefix = "PP,";
- } else if (aKey[0] == 'c' && !strcmp(aKey, "cail_properties")) {
- prefix = "CAIL,";
- }
+bool RAD::processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
+ if (kextRadeonX6000Framebuffer.loadIndex == index) {
+ SYSLOG("igfx", "RAD::processKext, index: %lu, address: %p, size: %lu", index, address, size);
+ if (getKernelVersion() >= KernelVersion::Monterey) {
+ KernelPatcher::RouteRequest requests[] = {
+ {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25setAttributeForConnectionEijm", wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferSetAttribute},
+ {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25getAttributeForConnectionEijPm", wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferGetAttribute},
+ //{"__ZN24AMDRadeonX6000_AmdLogger13setDebugLevelE11LogSeverity", Wrap_AMDRadeonX6000_AmdLogger_setDebugLevel, Orig_AMDRadeonX6000_AmdLogger_setDebugLevel},
+ //{"__ZN34AMDRadeonX6000_AmdInterruptManager15sleepInterruptsEv", Wrap_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts, Orig_AMDRadeonX6000_AmdInterruptManager_sleepInterrupts},
+ };
+
+ if (!patcher.routeMultiple(index, requests, address, size, true, true))
+ SYSLOG("igfx", "Failed to route redeon x6000 gpu tracing.");
+
+ SYSLOG("igfx", "route _dce_panel_cntl_hw_init");
+ mach_vm_address_t dpchi_cal = address + 0x12CB94; // For Monterey
+ if (getKernelVersion() >= KernelVersion::Ventura) {
+ dpchi_cal = address + 0x12EC5F; // For Ventura
+ }
+
+ // Verify the expect code of the destinate address, otherwise will not call to prevent kernel panic
+ const uint8_t dpchi_expect[] = { 0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x50, 0x49, 0x89, 0xFD, 0x4C, 0x8D, 0x45 };
+ unsigned char* dpchi_cal_charp = (unsigned char*)dpchi_cal;
+ bool expect_match = true;
+ for (int i = 0; i < 20; i++) {
+ //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ if (dpchi_cal_charp[i] != dpchi_expect[i]) {
+ SYSLOG("igfx", "_dce_panel_cntl_hw_init dismatch: %d => %x != %x", i, dpchi_cal_charp[i], dpchi_expect[i]);
+ expect_match = false;
+ break;
+ }
+ }
+
+ if (expect_match) {
+ orgDcePanelCntlHwInit = patcher.routeFunction(dpchi_cal, reinterpret_cast<mach_vm_address_t>(wrapDcePanelCntlHwInit), true);
+ if (patcher.getError() == KernelPatcher::Error::NoError) {
+ DBGLOG("igfx", "routed _dce_panel_cntl_hw_init");
+ } else {
+ SYSLOG("igfx", "failed to route _dce_panel_cntl_hw_init %d", patcher.getError());
+ patcher.clearError();
+ }
+
+ mach_vm_address_t ddsb_cal = address + 0x12CFC9;
+ if (getKernelVersion() >= KernelVersion::Ventura) {
+ ddsb_cal = address + 0x12F094;
+ }
+ SYSLOG("igfx", "got Monterey _dce_driver_set_backlight address: %p", ddsb_cal);
+ const uint8_t ddsb_expect[] = { 0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x50, 0x41, 0x89, 0xF7, 0x49, 0x89, 0xFE };
+ unsigned char* ddsb_cal_charp = (unsigned char*)ddsb_cal;
+ expect_match = true;
+ for (int i = 0; i < 20; i++) {
+ //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ if (ddsb_cal_charp[i] != ddsb_expect[i]) {
+ SYSLOG("igfx", "_dce_driver_set_backlight dismatch: %d => %x != %x", i, ddsb_cal_charp[i], ddsb_expect[i]);
+ expect_match = false;
+ break;
+ }
+ }
+
+ //for (int i = 0; i < 0x200000; i++) {
+ // ddsb_cal_charp = (unsigned char*)(address + i);
+ // int j = 0;
+ // for (j = 0; j < 20; j++) {
+ // //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ // if (ddsb_cal_charp[j] != ddsb_expect[j]) {
+ // //SYSLOG("igfx", "_dce_panel_cntl_hw_init dismatch: %d => %x != %x", i, dpchi_cal_charp[i], dpchi_expect[i]);
+ // //expect_match = false;
+ // break;
+ // }
+ // }
+ // if (j == 20) {
+ // SYSLOG("igfx", "found address %u", i);
+ // }
+ //}
+
+ if (expect_match) {
+ orgDceDriverSetBacklight = reinterpret_cast<t_DceDriverSetBacklight>(ddsb_cal);
+ }
+ }
+
+ /*SYSLOG("igfx", "route _dm_logger_write");
+ mach_vm_address_t dlw_cal = address + 0x169117;
+ const uint8_t dlw_expect[] = { 0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x81, 0xEC, 0x88, 0x04, 0x00, 0x00 };
+ unsigned char* dlw_cal_charp = (unsigned char*)dlw_cal;
+ expect_match = true;
+ for (int i = 0; i < 20; i++) {
+ //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ if (dlw_cal_charp[i] != dlw_expect[i]) {
+ SYSLOG("igfx", "_dm_logger_write dismatch: %d => %x != %x", i, dlw_cal_charp[i], dlw_expect[i]);
+ expect_match = false;
+ break;
+ }
+ }
+ if (expect_match) {
+ Orig_my_dm_logger_write = patcher.routeFunction(dlw_cal, reinterpret_cast<mach_vm_address_t>(Wrap_my_dm_logger_write), true);
+ if (patcher.getError() == KernelPatcher::Error::NoError) {
+ DBGLOG("igfx", "routed _dm_logger_write");
+ } else {
+ SYSLOG("igfx", "failed to route _dm_logger_write %d", patcher.getError());
+ patcher.clearError();
+ }
+ }*/
+
+ /*
+ SYSLOG("igfx", "route _dce110_edp_power_control");
+ mach_vm_address_t depc_cal = address + 0x1B04B9;
+ const uint8_t depc_expect[] = { 0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x83, 0xEC, 0x48, 0x4C, 0x8B, 0xB7 };
+ unsigned char* depc_cal_charp = (unsigned char*)depc_cal;
+ expect_match = true;
+ for (int i = 0; i < 20; i++) {
+ //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ if (depc_cal_charp[i] != depc_expect[i]) {
+ SYSLOG("igfx", "_dce110_edp_power_control dismatch: %d => %x != %x", i, depc_cal_charp[i], depc_expect[i]);
+ expect_match = false;
+ break;
+ }
+ }
+ if (expect_match) {
+ orig_dce110_edp_power_control = patcher.routeFunction(depc_cal, reinterpret_cast<mach_vm_address_t>(wrap_dce110_edp_power_control), true);
+ if (patcher.getError() == KernelPatcher::Error::NoError) {
+ DBGLOG("igfx", "routed _dce110_edp_power_control");
+ } else {
+ SYSLOG("igfx", "failed to route _dce110_edp_power_control %d", patcher.getError());
+ patcher.clearError();
+ }
+ }
+
+ SYSLOG("igfx", "route _dce110_edp_backlight_control");
+ mach_vm_address_t debc_cal = address + 0x1B0926;
+ const uint8_t debc_expect[] = { 0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x83, 0xEC, 0x48, 0x4C, 0x8B, 0xAF };
+ unsigned char* debc_cal_charp = (unsigned char*)debc_cal;
+ expect_match = true;
+ for (int i = 0; i < 20; i++) {
+ //SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ if (debc_cal_charp[i] != debc_expect[i]) {
+ SYSLOG("igfx", "_dce110_edp_backlight_control dismatch: %d => %x != %x", i, debc_cal_charp[i], debc_expect[i]);
+ expect_match = false;
+ break;
+ }
+ }
+ if (expect_match) {
+ orig_dce110_edp_backlight_control = patcher.routeFunction(debc_cal, reinterpret_cast<mach_vm_address_t>(wrap_dce110_edp_backlight_control), true);
+ if (patcher.getError() == KernelPatcher::Error::NoError) {
+ DBGLOG("igfx", "routed _dce110_edp_backlight_control");
+ } else {
+ SYSLOG("igfx", "failed to route _dce110_edp_backlight_control %d", patcher.getError());
+ patcher.clearError();
+ }
+ }*/
+ } else {
+ KernelPatcher::RouteRequest requests[] = {
+ {"_dce_panel_cntl_hw_init", wrapDcePanelCntlHwInit, orgDcePanelCntlHwInit},
+ {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25setAttributeForConnectionEijm", wrapAMDRadeonX6000AmdRadeonFramebufferSetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferSetAttribute},
+ {"__ZN35AMDRadeonX6000_AmdRadeonFramebuffer25getAttributeForConnectionEijPm", wrapAMDRadeonX6000AmdRadeonFramebufferGetAttribute, orgAMDRadeonX6000AmdRadeonFramebufferGetAttribute},
+ //{"_dc_link_bandwidth_kbps", wrapDcLinkBandwidthKbps, orgDcLinkBandwidthKbps},
+ };
+
+ mach_vm_address_t dpchi_cal = address + 0x124F56;
+ unsigned char* dpchi_cal_charp = (unsigned char*)dpchi_cal;
+ for (int i = 0; i < 20; i++) {
+ SYSLOG("igfx", "%d => %x", i, dpchi_cal_charp[i]);
+ }
+ mach_vm_address_t ddsb_cal = address + 0x124B21;
+ unsigned char* ddsb_cal_charp = (unsigned char*)ddsb_cal;
+ for (int i = 0; i < 20; i++) {
+ SYSLOG("igfx", "%d => %x", i, ddsb_cal_charp[i]);
+ }
+
+ if (!patcher.routeMultiple(index, requests, address, size, true, true))
+ SYSLOG("igfx", "Failed to route redeon x6000 gpu tracing.");
+
+ mach_vm_address_t ddsb = patcher.solveSymbol(index, "_dce_driver_set_backlight");
+ SYSLOG("igfx", "got Bigsur _dce_driver_set_backlight address: %p", ddsb);
+ orgDceDriverSetBacklight = reinterpret_cast<t_DceDriverSetBacklight>(ddsb);
+ }
+ //mach_vm_address_t ddsb_cal = address + 0x124F56;
+ //SYSLOG("igfx", "got _dce_driver_set_backlight address: %p, %p", ddsb, ddsb_cal);
+ //orgDceDriverSetBacklight = reinterpret_cast<t_DceDriverSetBacklight>(ddsb);
+ if (patcher.getError() != KernelPatcher::Error::NoError) {
+ SYSLOG("igfx", "failed to resolve _dce_driver_set_backlight");
+ patcher.clearError();
+ return false;
+ }
+ }
+
+ if (kextRadeonFramebuffer.loadIndex == index) {
+ if (force24BppMode)
+ process24BitOutput(patcher, kextRadeonFramebuffer, address, size);
+ return true;
+ }
+
+ if (kextRadeonLegacyFramebuffer.loadIndex == index) {
+ if (force24BppMode)
+ process24BitOutput(patcher, kextRadeonLegacyFramebuffer, address, size);
+ return true;
+ }
+
+ if (kextRadeonSupport.loadIndex == index) {
+ processConnectorOverrides(patcher, address, size, true);
+
+ if (getKernelVersion() > KernelVersion::Mojave ||
+ (getKernelVersion() == KernelVersion::Mojave && getKernelMinorVersion() >= 5)) {
+ KernelPatcher::RouteRequest request("__ZN13ATIController8TestVRAME13PCI_REG_INDEXb", doNotTestVram);
+ patcher.routeMultiple(index, &request, 1, address, size);
+ }
+
+ if (useCustomAgdpDecision) {
+ KernelPatcher::RouteRequest request("__ZN16AtiDeviceControl16notifyLinkChangeE31kAGDCRegisterLinkControlEvent_tmj", wrapNotifyLinkChange, orgNotifyLinkChange);
+ patcher.routeMultiple(index, &request, 1, address, size);
+ }
+
+ return true;
+ }
+
+ if (kextRadeonLegacySupport.loadIndex == index) {
+ processConnectorOverrides(patcher, address, size, false);
+ return true;
+ }
+
+ if (kextPolarisController.loadIndex == index) {
+ KernelPatcher::RouteRequest request("__ZN17AMD9500Controller23findProjectByPartNumberEP20ControllerProperties", findProjectByPartNumber);
+ patcher.routeMultiple(index, &request, 1, address, size);
+ }
+
+ for (size_t i = 0; i < maxHardwareKexts; i++) {
+ if (kextRadeonHardware[i].loadIndex == index) {
+ processHardwareKext(patcher, i, address, size);
+ return true;
+ }
+ }
+
+ return false;
+}
- if (prefix) {
- DBGLOG("rad", "GetProperty discovered property merge request for %s", aKey);
- auto rawProps = props->copyCollection();
- if (rawProps) {
- auto newProps = OSDynamicCast(OSDictionary, rawProps);
- if (newProps) {
- callbackRAD->mergeProperties(newProps, prefix, provider);
- that->setProperty(aKey, newProps);
- obj = newProps;
- }
- rawProps->release();
- }
+void RAD::initHardwareKextMods() {
+ // Decide on kext amount present for optimal performance.
+ // 10.15+ has X4000, X5000, and X6000
+ // 10.14+ has X4000 and X5000
+ // 10.13.4+ has X3000, X4000, and X5000
+ if (getKernelVersion() >= KernelVersion::Catalina)
+ maxHardwareKexts = MaxRadeonHardwareCatalina;
+ else if (getKernelVersion() >= KernelVersion::Mojave)
+ maxHardwareKexts = MaxRadeonHardwareMojave;
+ else if (getKernelVersion() == KernelVersion::HighSierra && getKernelMinorVersion() >= 5)
+ maxHardwareKexts = MaxRadeonHardwareModernHighSierra;
+
+ // 10.13.4 fixed black screen issues
+ if (maxHardwareKexts != MaxRadeonHardware) {
+ for (size_t i = 0; i < MaxGetFrameBufferProcs; i++)
+ getFrameBufferProcNames[IndexRadeonHardwareX4000][i] = nullptr;
+
+ // We have nothing to do for these kexts on recent systems
+ if (!fixConfigName && !forceOpenGL && !forceCodecInfo) {
+ // X4000 kext is not included in this list as we need to fix GVA properties for most of its GPUs
+ kextRadeonHardware[IndexRadeonHardwareX5000].switchOff();
+ kextRadeonHardware[IndexRadeonHardwareX6000].switchOff();
+ }
+ }
+
+ if (getKernelVersion() < KernelVersion::Catalina) {
+ kextRadeonHardware[IndexRadeonHardwareX6000].switchOff();
+ }
+
+ if (getKernelVersion() < KernelVersion::HighSierra) {
+ // Versions before 10.13 do not support X4250 and X5000
+ kextRadeonHardware[IndexRadeonHardwareX4250].switchOff();
+ kextRadeonHardware[IndexRadeonHardwareX5000].switchOff();
+
+ // Versions before 10.13 have legacy X3000 and X4000 IDs
+ kextRadeonHardware[IndexRadeonHardwareX3000].id = idRadeonX3000Old;
+ kextRadeonHardware[IndexRadeonHardwareX4000].id = idRadeonX4000Old;
+
+ bool preSierra = getKernelVersion() < KernelVersion::Sierra;
+
+ if (preSierra) {
+ // Versions before 10.12 do not support X4100
+ kextRadeonHardware[IndexRadeonHardwareX4100].switchOff();
+ }
+
+ if (preSierra || (getKernelVersion() == KernelVersion::Sierra && getKernelMinorVersion() < 7)) {
+ // Versions before 10.12.6 do not support X4150, X4200
+ kextRadeonHardware[IndexRadeonHardwareX4150].switchOff();
+ kextRadeonHardware[IndexRadeonHardwareX4200].switchOff();
+ }
+ }
+
+ lilu.onKextLoadForce(kextRadeonHardware, maxHardwareKexts);
+}
- }
- }
- }
+void RAD::process24BitOutput(KernelPatcher &patcher, KernelPatcher::KextInfo &info, mach_vm_address_t address, size_t size) {
+ auto bitsPerComponent = patcher.solveSymbol<int *>(info.loadIndex, "__ZL18BITS_PER_COMPONENT", address, size);
+ if (bitsPerComponent) {
+ while (bitsPerComponent && *bitsPerComponent) {
+ if (*bitsPerComponent == 10) {
+ auto ret = MachInfo::setKernelWriting(true, KernelPatcher::kernelWriteLock);
+ if (ret == KERN_SUCCESS) {
+ DBGLOG("rad", "fixing BITS_PER_COMPONENT");
+ *bitsPerComponent = 8;
+ MachInfo::setKernelWriting(false, KernelPatcher::kernelWriteLock);
+ } else {
+ SYSLOG("rad", "failed to disable write protection for BITS_PER_COMPONENT");
+ }
+ }
+ bitsPerComponent++;
+ }
+ } else {
+ SYSLOG("rad", "failed to find BITS_PER_COMPONENT");
+ patcher.clearError();
+ }
+
+ DBGLOG("rad", "fixing pixel types");
+
+ KernelPatcher::LookupPatch pixelPatch {
+ &info,
+ reinterpret_cast<const uint8_t *>("--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB"),
+ reinterpret_cast<const uint8_t *>("--------RRRRRRRRGGGGGGGGBBBBBBBB"),
+ 32, 2
+ };
+
+ patcher.applyLookupPatch(&pixelPatch);
+ if (patcher.getError() != KernelPatcher::Error::NoError) {
+ SYSLOG("rad", "failed to patch RGB mask for 24-bit output");
+ patcher.clearError();
+ }
+}
- return obj;
+void RAD::processConnectorOverrides(KernelPatcher &patcher, mach_vm_address_t address, size_t size, bool modern) {
+ if (modern) {
+ if (getKernelVersion() >= KernelVersion::HighSierra) {
+ KernelPatcher::RouteRequest requests[] {
+ KernelPatcher::RouteRequest("__ZN14AtiBiosParser116getConnectorInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV1, orgGetConnectorsInfoV1),
+ KernelPatcher::RouteRequest("__ZN14AtiBiosParser216getConnectorInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV2, orgGetConnectorsInfoV2),
+ KernelPatcher::RouteRequest("__ZN14AtiBiosParser126translateAtomConnectorInfoERN30AtiObjectInfoTableInterface_V117AtomConnectorInfoER13ConnectorInfo",
+ wrapTranslateAtomConnectorInfoV1, orgTranslateAtomConnectorInfoV1),
+ KernelPatcher::RouteRequest("__ZN14AtiBiosParser226translateAtomConnectorInfoERN30AtiObjectInfoTableInterface_V217AtomConnectorInfoER13ConnectorInfo",
+ wrapTranslateAtomConnectorInfoV2, orgTranslateAtomConnectorInfoV2),
+ KernelPatcher::RouteRequest("__ZN13ATIController5startEP9IOService", wrapATIControllerStart, orgATIControllerStart)
+ };
+ patcher.routeMultiple(kextRadeonSupport.loadIndex, requests, address, size);
+ } else {
+ KernelPatcher::RouteRequest requests[] {
+ KernelPatcher::RouteRequest("__ZN23AtiAtomBiosDceInterface17getConnectorsInfoEP13ConnectorInfoRh", wrapGetConnectorsInfoV1, orgGetConnectorsInfoV1),
+ KernelPatcher::RouteRequest("__ZN13ATIController5startEP9IOService", wrapATIControllerStart, orgATIControllerStart),
+ };
+ patcher.routeMultiple(kextRadeonSupport.loadIndex, requests, address, size);
+
+ orgGetAtomObjectTableForType = reinterpret_cast<t_getAtomObjectTableForType>(patcher.solveSymbol(kextRadeonSupport.loadIndex,
+ "__ZN20AtiAtomBiosUtilities25getAtomObjectTableForTypeEhRh", address, size));
+ if (!orgGetAtomObjectTableForType) {
+ SYSLOG("rad", "failed to find AtiAtomBiosUtilities::getAtomObjectTableForType");
+ patcher.clearError();
+ }
+ }
+ } else {
+ KernelPatcher::RouteRequest requests[] {
+ KernelPatcher::RouteRequest("__ZN23AtiAtomBiosDceInterface17getConnectorsInfoEP13ConnectorInfoRh", wrapLegacyGetConnectorsInfo, orgLegacyGetConnectorsInfo),
+ KernelPatcher::RouteRequest("__ZN19AMDLegacyController5startEP9IOService", wrapLegacyATIControllerStart, orgLegacyATIControllerStart),
+ };
+ patcher.routeMultiple(kextRadeonLegacySupport.loadIndex, requests, address, size);
+
+ orgLegacyGetAtomObjectTableForType = patcher.solveSymbol<t_getAtomObjectTableForType>(kextRadeonLegacySupport.loadIndex,
+ "__ZN20AtiAtomBiosUtilities25getAtomObjectTableForTypeEhRh", address, size);
+ if (!orgLegacyGetAtomObjectTableForType) {
+ SYSLOG("rad", "failed to find AtiAtomBiosUtilities::getAtomObjectTableForType");
+ patcher.clearError();
+ }
+ }
}
-uint32_t RAD::wrapGetConnectorsInfoV1(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
- uint32_t code = FunctionCast(wrapGetConnectorsInfoV1, callbackRAD->orgGetConnectorsInfoV1)(that, connectors, sz);
- auto props = callbackRAD->currentPropProvider.get();
-
- if (code == 0 && sz && props && *props) {
- if (getKernelVersion() >= KernelVersion::HighSierra)
- callbackRAD->updateConnectorsInfo(nullptr, nullptr, *props, connectors, sz);
- else
- callbackRAD->updateConnectorsInfo(static_cast<void **>(that)[1], callbackRAD->orgGetAtomObjectTableForType, *props, connectors, sz);
- } else {
- DBGLOG("rad", "getConnectorsInfoV1 failed %X or undefined %d", code, props == nullptr);
- }
+void RAD::processHardwareKext(KernelPatcher &patcher, size_t hwIndex, mach_vm_address_t address, size_t size) {
+ auto getFrame = getFrameBufferProcNames[hwIndex];
+ auto &hardware = kextRadeonHardware[hwIndex];
+
+ // Fix boot and wake to black screen
+ for (size_t j = 0; j < MaxGetFrameBufferProcs && getFrame[j] != nullptr; j++) {
+ auto getFB = patcher.solveSymbol(hardware.loadIndex, getFrame[j], address, size);
+ if (getFB) {
+ // Initially it was discovered that the only problematic register is PRIMARY_SURFACE_ADDRESS_HIGH (0x1A07).
+ // This register must be nulled to solve most of the issues.
+ // Depending on the amount of connected screens PRIMARY_SURFACE_ADDRESS (0x1A04) may not be null.
+ // However, as of AMD Vega drivers in 10.13 DP1 both of these registers are now ignored.
+ // Furthermore, there are no (extra) issues from just returning 0 in framebuffer base address.
+
+ // xor rax, rax
+ // ret
+ uint8_t ret[] {0x48, 0x31, 0xC0, 0xC3};
+ patcher.routeBlock(getFB, ret, sizeof(ret));
+ if (patcher.getError() == KernelPatcher::Error::NoError) {
+ DBGLOG("rad", "patched %s", getFrame[j]);
+ } else {
+ SYSLOG("rad", "failed to patch %s code %d", getFrame[j], patcher.getError());
+ patcher.clearError();
+ }
+ } else {
+ SYSLOG("rad", "failed to find %s code %d", getFrame[j], patcher.getError());
+ patcher.clearError();
+ }
+ }
+
+ // Fix reported Accelerator name to support WhateverName.app
+ // Also fix GVA properties for X4000.
+ if (fixConfigName || hwIndex == IndexRadeonHardwareX4000) {
+ KernelPatcher::RouteRequest request(populateAccelConfigProcNames[hwIndex], wrapPopulateAccelConfig[hwIndex], orgPopulateAccelConfig[hwIndex]);
+ patcher.routeMultiple(hardware.loadIndex, &request, 1, address, size);
+ }
+
+ // Enforce OpenGL support if requested
+ if (forceOpenGL) {
+ DBGLOG("rad", "disabling Metal support");
+ uint8_t find1[] {0x4D, 0x65, 0x74, 0x61, 0x6C, 0x53, 0x74, 0x61};
+ uint8_t find2[] {0x4D, 0x65, 0x74, 0x61, 0x6C, 0x50, 0x6C, 0x75};
+ uint8_t repl1[] {0x50, 0x65, 0x74, 0x61, 0x6C, 0x53, 0x74, 0x61};
+ uint8_t repl2[] {0x50, 0x65, 0x74, 0x61, 0x6C, 0x50, 0x6C, 0x75};
+
+ KernelPatcher::LookupPatch antimetal[] {
+ {&hardware, find1, repl1, sizeof(find1), 2},
+ {&hardware, find2, repl2, sizeof(find1), 2}
+ };
+
+ for (auto &p : antimetal) {
+ patcher.applyLookupPatch(&p);
+ patcher.clearError();
+ }
+ }
+
+ // Patch AppleGVA support for non-supported models
+ if (forceCodecInfo && getHWInfoProcNames[hwIndex] != nullptr) {
+ KernelPatcher::RouteRequest request(getHWInfoProcNames[hwIndex], wrapGetHWInfo[hwIndex], orgGetHWInfo[hwIndex]);
+ patcher.routeMultiple(hardware.loadIndex, &request, 1, address, size);
+ }
+}
- return code;
+void RAD::mergeProperty(OSDictionary *props, const char *name, OSObject *value) {
+ // The only type we could make from device properties is data.
+ // To be able to override other types we do a conversion here.
+ auto data = OSDynamicCast(OSData, value);
+ if (data) {
+ // It is hard to make a boolean even from ACPI, so we make a hack here:
+ // 1-byte OSData with 0x01 / 0x00 values becomes boolean.
+ auto val = static_cast<const uint8_t *>(data->getBytesNoCopy());
+ auto len = data->getLength();
+ if (val && len == sizeof(uint8_t)) {
+ if (val[0] == 1) {
+ props->setObject(name, kOSBooleanTrue);
+ DBGLOG("rad", "prop %s was merged as kOSBooleanTrue", name);
+ return;
+ } else if (val[0] == 0) {
+ props->setObject(name, kOSBooleanFalse);
+ DBGLOG("rad", "prop %s was merged as kOSBooleanFalse", name);
+ return;
+ }
+ }
+
+ // Consult the original value to make a decision
+ auto orgValue = props->getObject(name);
+ if (val && orgValue) {
+ DBGLOG("rad", "prop %s has original value", name);
+ if (len == sizeof(uint32_t) && OSDynamicCast(OSNumber, orgValue)) {
+ auto num = *reinterpret_cast<const uint32_t *>(val);
+ auto osnum = OSNumber::withNumber(num, 32);
+ if (osnum) {
+ DBGLOG("rad", "prop %s was merged as number %u", name, num);
+ props->setObject(name, osnum);
+ osnum->release();
+ }
+ return;
+ } else if (len > 0 && val[len-1] == '\0' && OSDynamicCast(OSString, orgValue)) {
+ auto str = reinterpret_cast<const char *>(val);
+ auto osstr = OSString::withCString(str);
+ if (osstr) {
+ DBGLOG("rad", "prop %s was merged as string %s", name, str);
+ props->setObject(name, osstr);
+ osstr->release();
+ }
+ return;
+ }
+ } else {
+ DBGLOG("rad", "prop %s has no original value", name);
+ }
+ }
+
+ // Default merge as is
+ props->setObject(name, value);
+ DBGLOG("rad", "prop %s was merged", name);
}
-uint32_t RAD::wrapGetConnectorsInfoV2(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
- uint32_t code = FunctionCast(wrapGetConnectorsInfoV2, callbackRAD->orgGetConnectorsInfoV2)(that, connectors, sz);
- auto props = callbackRAD->currentPropProvider.get();
+void RAD::mergeProperties(OSDictionary *props, const char *prefix, IOService *provider) {
+ // Should be ok, but in case there are issues switch to dictionaryWithProperties();
+ auto dict = provider->getPropertyTable();
+ if (dict) {
+ auto iterator = OSCollectionIterator::withCollection(dict);
+ if (iterator) {
+ OSSymbol *propname;
+ size_t prefixlen = strlen(prefix);
+ while ((propname = OSDynamicCast(OSSymbol, iterator->getNextObject())) != nullptr) {
+ auto name = propname->getCStringNoCopy();
+ if (name && propname->getLength() > prefixlen && !strncmp(name, prefix, prefixlen)) {
+ auto prop = dict->getObject(propname);
+ if (prop)
+ mergeProperty(props, name + prefixlen, prop);
+ else
+ DBGLOG("rad", "prop %s was not merged due to no value", name);
+ } else {
+ //DBGLOG("rad", "prop %s does not match %s prefix", safeString(name), prefix);
+ }
+ }
+
+ iterator->release();
+ } else {
+ SYSLOG("rad", "prop merge failed to iterate over properties");
+ }
+ } else {
+ SYSLOG("rad", "prop merge failed to get properties");
+ }
+
+ if (!strcmp(prefix, "CAIL,")) {
+ for (size_t i = 0; i < arrsize(powerGatingFlags); i++) {
+ if (powerGatingFlags[i] && props->getObject(powerGatingFlags[i])) {
+ DBGLOG("rad", "cail prop merge found %s, replacing", powerGatingFlags[i]);
+ auto num = OSNumber::withNumber(1, 32);
+ if (num) {
+ props->setObject(powerGatingFlags[i], num);
+ num->release();
+ }
+ }
+ }
+ }
+}
- if (code == 0 && sz && props && *props)
- callbackRAD->updateConnectorsInfo(nullptr, nullptr, *props, connectors, sz);
- else
- DBGLOG("rad", "getConnectorsInfoV2 failed %X or undefined %d", code, props == nullptr);
+void RAD::applyPropertyFixes(IOService *service, uint32_t connectorNum) {
+ if (service && getKernelVersion() >= KernelVersion::HighSierra) {
+ // Starting with 10.13.2 this is important to fix sleep issues due to enforced 6 screens
+ if (!service->getProperty("CFG,CFG_FB_LIMIT")) {
+ DBGLOG("rad", "setting fb limit to %u", connectorNum);
+ service->setProperty("CFG_FB_LIMIT", connectorNum, 32);
+ }
+
+ // In the past we set CFG_USE_AGDC to false, which caused visual glitches and broken multimonitor support.
+ // A better workaround is to disable AGDP just like we do globally.
+ }
+}
- return code;
+void RAD::updateConnectorsInfo(void *atomutils, t_getAtomObjectTableForType gettable, IOService *ctrl, RADConnectors::Connector *connectors, uint8_t *sz) {
+ if (atomutils) {
+ DBGLOG("rad", "getConnectorsInfo found %u connectors", *sz);
+ RADConnectors::print(connectors, *sz);
+ }
+
+ // Check if the user wants to override automatically detected connectors
+ auto cons = ctrl->getProperty("connectors");
+ if (cons) {
+ auto consData = OSDynamicCast(OSData, cons);
+ if (consData) {
+ auto consPtr = consData->getBytesNoCopy();
+ auto consSize = consData->getLength();
+
+ uint32_t consCount;
+ if (WIOKit::getOSDataValue(ctrl, "connector-count", consCount)) {
+ *sz = consCount;
+ DBGLOG("rad", "getConnectorsInfo got size override to %u", *sz);
+ }
+
+ if (consPtr && consSize > 0 && *sz > 0 && RADConnectors::valid(consSize, *sz)) {
+ RADConnectors::copy(connectors, *sz, static_cast<const RADConnectors::Connector *>(consPtr), consSize);
+ DBGLOG("rad", "getConnectorsInfo installed %u connectors", *sz);
+ applyPropertyFixes(ctrl, *sz);
+ } else {
+ DBGLOG("rad", "getConnectorsInfo conoverrides have invalid size %u for %u num", consSize, *sz);
+ }
+ } else {
+ DBGLOG("rad", "getConnectorsInfo conoverrides have invalid type");
+ }
+ } else {
+ if (atomutils) {
+ DBGLOG("rad", "getConnectorsInfo attempting to autofix connectors");
+ uint8_t sHeader = 0, displayPathNum = 0, connectorObjectNum = 0;
+ auto baseAddr = static_cast<uint8_t *>(gettable(atomutils, AtomObjectTableType::Common, &sHeader)) - sizeof(uint32_t);
+ auto displayPaths = static_cast<AtomDisplayObjectPath *>(gettable(atomutils, AtomObjectTableType::DisplayPath, &displayPathNum));
+ auto connectorObjects = static_cast<AtomConnectorObject *>(gettable(atomutils, AtomObjectTableType::ConnectorObject, &connectorObjectNum));
+ if (displayPathNum == connectorObjectNum)
+ autocorrectConnectors(baseAddr, displayPaths, displayPathNum, connectorObjects, connectorObjectNum, connectors, *sz);
+ else
+ DBGLOG("rad", "getConnectorsInfo found different displaypaths %u and connectors %u", displayPathNum, connectorObjectNum);
+ }
+
+ applyPropertyFixes(ctrl, *sz);
+
+ // Prioritise connectors, since it may cause black screen on e.g. R9 370
+ const uint8_t *senseList = nullptr;
+ uint8_t senseNum = 0;
+ auto priData = OSDynamicCast(OSData, ctrl->getProperty("connector-priority"));
+ if (priData) {
+ senseList = static_cast<const uint8_t *>(priData->getBytesNoCopy());
+ senseNum = static_cast<uint8_t>(priData->getLength());
+ DBGLOG("rad", "getConnectorInfo found %u senses in connector-priority", senseNum);
+ reprioritiseConnectors(senseList, senseNum, connectors, *sz);
+ } else {
+ DBGLOG("rad", "getConnectorInfo leaving unchaged priority");
+ }
+ }
+
+ DBGLOG("rad", "getConnectorsInfo resulting %u connectors follow", *sz);
+ RADConnectors::print(connectors, *sz);
}
-uint32_t RAD::wrapLegacyGetConnectorsInfo(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
- uint32_t code = FunctionCast(wrapLegacyGetConnectorsInfo, callbackRAD->orgLegacyGetConnectorsInfo)(that, connectors, sz);
- auto props = callbackRAD->currentLegacyPropProvider.get();
+void RAD::autocorrectConnectors(uint8_t *baseAddr, AtomDisplayObjectPath *displayPaths, uint8_t displayPathNum, AtomConnectorObject *connectorObjects,
+ uint8_t connectorObjectNum, RADConnectors::Connector *connectors, uint8_t sz) {
+ for (uint8_t i = 0; i < displayPathNum; i++) {
+ if (!isEncoder(displayPaths[i].usGraphicObjIds)) {
+ DBGLOG("rad", "autocorrectConnectors not encoder %X at %u", displayPaths[i].usGraphicObjIds, i);
+ continue;
+ }
+
+ uint8_t txmit = 0, enc = 0;
+ if (!getTxEnc(displayPaths[i].usGraphicObjIds, txmit, enc))
+ continue;
+
+ uint8_t sense = getSenseID(baseAddr + connectorObjects[i].usRecordOffset);
+ if (!sense) {
+ DBGLOG("rad", "autocorrectConnectors failed to detect sense for %u connector", i);
+ continue;
+ }
+
+ DBGLOG("rad", "autocorrectConnectors found txmit %02X enc %02X sense %02X for %u connector", txmit, enc, sense, i);
+
+ autocorrectConnector(getConnectorID(displayPaths[i].usConnObjectId), sense, txmit, enc, connectors, sz);
+ }
+}
- if (code == 0 && sz && props && *props)
- callbackRAD->updateConnectorsInfo(static_cast<void **>(that)[1], callbackRAD->orgLegacyGetAtomObjectTableForType, *props, connectors, sz);
- else
- DBGLOG("rad", "legacy getConnectorsInfo failed %X or undefined %d", code, props == nullptr);
+void RAD::autocorrectConnector(uint8_t connector, uint8_t sense, uint8_t txmit, uint8_t enc, RADConnectors::Connector *connectors, uint8_t sz) {
+ // This function attempts to fix the following issues:
+ //
+ // 1. Incompatible DVI transmitter on 290X, 370 and probably some other models
+ // In this case a correct transmitter is detected by AtiAtomBiosDce60::getPropertiesForEncoderObject, however, later
+ // in AtiAtomBiosDce60::getPropertiesForConnectorObject for DVI DL and TITFP513 this value is conjuncted with 0xCF,
+ // which makes it wrong: 0x10 -> 0, 0x11 -> 1. As a result one gets black screen when connecting multiple displays.
+ // getPropertiesForEncoderObject takes usGraphicObjIds and getPropertiesForConnectorObject takes usConnObjectId
+
+ if (callbackRAD->dviSingleLink) {
+ if (connector != CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I &&
+ connector != CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D &&
+ connector != CONNECTOR_OBJECT_ID_LVDS) {
+ DBGLOG("rad", "autocorrectConnector found unsupported connector type %02X", connector);
+ return;
+ }
+
+ auto fixTransmit = [](auto &con, uint8_t idx, uint8_t sense, uint8_t txmit) {
+ if (con.sense == sense) {
+ if (con.transmitter != txmit && (con.transmitter & 0xCF) == con.transmitter) {
+ DBGLOG("rad", "autocorrectConnector replacing txmit %02X with %02X for %u connector sense %02X",
+ con.transmitter, txmit, idx, sense);
+ con.transmitter = txmit;
+ }
+ return true;
+ }
+ return false;
+ };
+
+ bool isModern = RADConnectors::modern();
+ for (uint8_t j = 0; j < sz; j++) {
+ if (isModern) {
+ auto &con = (&connectors->modern)[j];
+ if (fixTransmit(con, j, sense, txmit))
+ break;
+ } else {
+ auto &con = (&connectors->legacy)[j];
+ if (fixTransmit(con, j, sense, txmit))
+ break;
+ }
+ }
+ } else {
+ DBGLOG("rad", "autocorrectConnector use -raddvi to enable dvi autocorrection");
+ }
+}
- return code;
+void RAD::reprioritiseConnectors(const uint8_t *senseList, uint8_t senseNum, RADConnectors::Connector *connectors, uint8_t sz) {
+ static constexpr uint32_t typeList[] {
+ RADConnectors::ConnectorLVDS,
+ RADConnectors::ConnectorDigitalDVI,
+ RADConnectors::ConnectorHDMI,
+ RADConnectors::ConnectorDP,
+ RADConnectors::ConnectorVGA
+ };
+ static constexpr uint8_t typeNum {static_cast<uint8_t>(arrsize(typeList))};
+
+ bool isModern = RADConnectors::modern();
+ uint16_t priCount = 1;
+ // Automatically detected connectors have equal priority (0), which often results in black screen
+ // This allows to change this firstly by user-defined list, then by type list.
+ //TODO: priority is ignored for 5xxx and 6xxx GPUs, should we manually reorder items?
+ for (uint8_t i = 0; i < senseNum + typeNum + 1; i++) {
+ for (uint8_t j = 0; j < sz; j++) {
+ auto reorder = [&](auto &con) {
+ if (i == senseNum + typeNum) {
+ if (con.priority == 0)
+ con.priority = priCount++;
+ } else if (i < senseNum) {
+ if (con.sense == senseList[i]) {
+ DBGLOG("rad", "reprioritiseConnectors setting priority of sense %02X to %u by sense", con.sense, priCount);
+ con.priority = priCount++;
+ return true;
+ }
+ } else {
+ if (con.priority == 0 && con.type == typeList[i-senseNum]) {
+ DBGLOG("rad", "reprioritiseConnectors setting priority of sense %02X to %u by type", con.sense, priCount);
+ con.priority = priCount++;
+ }
+ }
+ return false;
+ };
+
+ if ((isModern && reorder((&connectors->modern)[j])) ||
+ (!isModern && reorder((&connectors->legacy)[j])))
+ break;
+ }
+ }
}
-uint32_t RAD::wrapTranslateAtomConnectorInfoV1(void *that, RADConnectors::AtomConnectorInfo *info, RADConnectors::Connector *connector) {
- uint32_t code = FunctionCast(wrapTranslateAtomConnectorInfoV1, callbackRAD->orgTranslateAtomConnectorInfoV1)(that, info, connector);
-
- if (code == 0 && info && connector) {
- RADConnectors::print(connector, 1);
-
- uint8_t sense = getSenseID(info->i2cRecord);
- if (sense) {
- DBGLOG("rad", "translateAtomConnectorInfoV1 got sense id %02X", sense);
-
- // We need to extract usGraphicObjIds from info->hpdRecord, which is of type ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT:
- // struct ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT {
- // uint8_t ucNumberOfSrc;
- // uint16_t usSrcObjectID[ucNumberOfSrc];
- // uint8_t ucNumberOfDst;
- // uint16_t usDstObjectID[ucNumberOfDst];
- // };
- // The value we need is in usSrcObjectID. The structure is byte-packed.
-
- uint8_t ucNumberOfSrc = info->hpdRecord[0];
- for (uint8_t i = 0; i < ucNumberOfSrc; i++) {
- auto usSrcObjectID = *reinterpret_cast<uint16_t *>(info->hpdRecord + sizeof(uint8_t) + i * sizeof(uint16_t));
- DBGLOG("rad", "translateAtomConnectorInfoV1 checking %04X object id", usSrcObjectID);
- if (((usSrcObjectID & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT) == GRAPH_OBJECT_TYPE_ENCODER) {
- uint8_t txmit = 0, enc = 0;
- if (getTxEnc(usSrcObjectID, txmit, enc))
- callbackRAD->autocorrectConnector(getConnectorID(info->usConnObjectId), getSenseID(info->i2cRecord), txmit, enc, connector, 1);
- break;
- }
- }
+void RAD::setGvaProperties(IOService *accelService) {
+ auto codecStr = OSDynamicCast(OSString, accelService->getProperty("IOGVACodec"));
+ if (codecStr == nullptr) {
+ DBGLOG("rad", "updating X4000 accelerator IOGVACodec to VCE");
+ accelService->setProperty("IOGVACodec", "VCE");
+ } else {
+ auto codec = codecStr->getCStringNoCopy();
+ DBGLOG("rad", "X4000 accelerator IOGVACodec is already set to %s", safeString(codec));
+ if (codec != nullptr && strncmp(codec, "AMD", strlen("AMD")) == 0) {
+ bool needsDecode = accelService->getProperty("IOGVAHEVCDecode") == nullptr;
+ bool needsEncode = accelService->getProperty("IOGVAHEVCEncode") == nullptr;
+ if (needsDecode) {
+ OSObject *VTMaxDecodeLevel = OSNumber::withNumber(153, 32);
+ OSString *VTMaxDecodeLevelKey = OSString::withCString("VTMaxDecodeLevel");
+ OSDictionary *VTPerProfileDetailsInner = OSDictionary::withCapacity(1);
+ OSDictionary *VTPerProfileDetails = OSDictionary::withCapacity(3);
+ OSString *VTPerProfileDetailsKey1 = OSString::withCString("1");
+ OSString *VTPerProfileDetailsKey2 = OSString::withCString("2");
+ OSString *VTPerProfileDetailsKey3 = OSString::withCString("3");
+
+ OSArray *VTSupportedProfileArray = OSArray::withCapacity(3);
+ OSNumber *VTSupportedProfileArray1 = OSNumber::withNumber(1, 32);
+ OSNumber *VTSupportedProfileArray2 = OSNumber::withNumber(2, 32);
+ OSNumber *VTSupportedProfileArray3 = OSNumber::withNumber(3, 32);
+
+ OSDictionary *IOGVAHEVCDecodeCapabilities = OSDictionary::withCapacity(2);
+ OSString *VTPerProfileDetailsKey = OSString::withCString("VTPerProfileDetails");
+ OSString *VTSupportedProfileArrayKey = OSString::withCString("VTSupportedProfileArray");
+
+ if (VTMaxDecodeLevel != nullptr && VTMaxDecodeLevelKey != nullptr && VTPerProfileDetailsInner != nullptr &&
+ VTPerProfileDetails != nullptr && VTPerProfileDetailsKey1 != nullptr && VTPerProfileDetailsKey2 != nullptr &&
+ VTPerProfileDetailsKey3 != nullptr && VTSupportedProfileArrayKey != nullptr && VTSupportedProfileArray1 != nullptr &&
+ VTSupportedProfileArray2 != nullptr && VTSupportedProfileArray3 != nullptr && VTSupportedProfileArray != nullptr &&
+ VTPerProfileDetailsKey != nullptr && IOGVAHEVCDecodeCapabilities != nullptr) {
+ VTPerProfileDetailsInner->setObject(VTMaxDecodeLevelKey, VTMaxDecodeLevel);
+ VTPerProfileDetails->setObject(VTPerProfileDetailsKey1, VTPerProfileDetailsInner);
+ VTPerProfileDetails->setObject(VTPerProfileDetailsKey2, VTPerProfileDetailsInner);
+ VTPerProfileDetails->setObject(VTPerProfileDetailsKey3, VTPerProfileDetailsInner);
+
+ VTSupportedProfileArray->setObject(VTSupportedProfileArray1);
+ VTSupportedProfileArray->setObject(VTSupportedProfileArray2);
+ VTSupportedProfileArray->setObject(VTSupportedProfileArray3);
+
+ IOGVAHEVCDecodeCapabilities->setObject(VTPerProfileDetailsKey, VTPerProfileDetails);
+ IOGVAHEVCDecodeCapabilities->setObject(VTSupportedProfileArrayKey, VTSupportedProfileArray);
+
+ accelService->setProperty("IOGVAHEVCDecode", "1");
+ accelService->setProperty("IOGVAHEVCDecodeCapabilities", IOGVAHEVCDecodeCapabilities);
+
+ DBGLOG("rad", "recovering IOGVAHEVCDecode");
+ } else {
+ SYSLOG("rad", "allocation failure in IOGVAHEVCDecode");
+ }
+
+ OSSafeReleaseNULL(VTMaxDecodeLevel);
+ OSSafeReleaseNULL(VTMaxDecodeLevelKey);
+ OSSafeReleaseNULL(VTPerProfileDetailsInner);
+ OSSafeReleaseNULL(VTPerProfileDetails);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey1);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey2);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey3);
+ OSSafeReleaseNULL(VTSupportedProfileArrayKey);
+ OSSafeReleaseNULL(VTSupportedProfileArray1);
+ OSSafeReleaseNULL(VTSupportedProfileArray2);
+ OSSafeReleaseNULL(VTSupportedProfileArray3);
+ OSSafeReleaseNULL(VTSupportedProfileArray);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey);
+ OSSafeReleaseNULL(IOGVAHEVCDecodeCapabilities);
+ }
+
+ if (needsEncode) {
+ OSObject *VTMaxEncodeLevel = OSNumber::withNumber(153, 32);
+ OSString *VTMaxEncodeLevelKey = OSString::withCString("VTMaxEncodeLevel");
+
+ OSDictionary *VTPerProfileDetailsInner = OSDictionary::withCapacity(1);
+ OSDictionary *VTPerProfileDetails = OSDictionary::withCapacity(1);
+ OSString *VTPerProfileDetailsKey1 = OSString::withCString("1");
+
+ OSArray *VTSupportedProfileArray = OSArray::withCapacity(1);
+ OSNumber *VTSupportedProfileArray1 = OSNumber::withNumber(1, 32);
+
+ OSDictionary *IOGVAHEVCEncodeCapabilities = OSDictionary::withCapacity(4);
+ OSString *VTPerProfileDetailsKey = OSString::withCString("VTPerProfileDetails");
+ OSString *VTQualityRatingKey = OSString::withCString("VTQualityRating");
+ OSNumber *VTQualityRating = OSNumber::withNumber(50, 32);
+ OSString *VTRatingKey = OSString::withCString("VTRating");
+ OSNumber *VTRating = OSNumber::withNumber(350, 32);
+ OSString *VTSupportedProfileArrayKey = OSString::withCString("VTSupportedProfileArray");
+
+ if (VTMaxEncodeLevel != nullptr && VTMaxEncodeLevelKey != nullptr && VTPerProfileDetailsInner != nullptr &&
+ VTPerProfileDetails != nullptr && VTPerProfileDetailsKey1 != nullptr && VTSupportedProfileArrayKey != nullptr &&
+ VTSupportedProfileArray1 != nullptr && VTSupportedProfileArray != nullptr && VTPerProfileDetailsKey != nullptr &&
+ VTQualityRatingKey != nullptr && VTQualityRating != nullptr && VTRatingKey != nullptr && VTRating != nullptr &&
+ IOGVAHEVCEncodeCapabilities != nullptr) {
+
+ VTPerProfileDetailsInner->setObject(VTMaxEncodeLevelKey, VTMaxEncodeLevel);
+ VTPerProfileDetails->setObject(VTPerProfileDetailsKey1, VTPerProfileDetailsInner);
+ VTSupportedProfileArray->setObject(VTSupportedProfileArray1);
+
+ IOGVAHEVCEncodeCapabilities->setObject(VTPerProfileDetailsKey, VTPerProfileDetails);
+ IOGVAHEVCEncodeCapabilities->setObject(VTQualityRatingKey, VTQualityRating);
+ IOGVAHEVCEncodeCapabilities->setObject(VTRatingKey, VTRating);
+ IOGVAHEVCEncodeCapabilities->setObject(VTSupportedProfileArrayKey, VTSupportedProfileArray);
+
+ accelService->setProperty("IOGVAHEVCEncode", "1");
+ accelService->setProperty("IOGVAHEVCEncodeCapabilities", IOGVAHEVCEncodeCapabilities);
+
+ DBGLOG("rad", "recovering IOGVAHEVCEncode");
+ } else {
+ SYSLOG("rad", "allocation failure in IOGVAHEVCEncode");
+ }
+
+ OSSafeReleaseNULL(VTMaxEncodeLevel);
+ OSSafeReleaseNULL(VTMaxEncodeLevelKey);
+ OSSafeReleaseNULL(VTPerProfileDetailsInner);
+ OSSafeReleaseNULL(VTPerProfileDetails);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey1);
+ OSSafeReleaseNULL(VTSupportedProfileArrayKey);
+ OSSafeReleaseNULL(VTSupportedProfileArray1);
+ OSSafeReleaseNULL(VTSupportedProfileArray);
+ OSSafeReleaseNULL(VTPerProfileDetailsKey);
+ OSSafeReleaseNULL(VTQualityRatingKey);
+ OSSafeReleaseNULL(VTQualityRating);
+ OSSafeReleaseNULL(VTRatingKey);
+ OSSafeReleaseNULL(VTRating);
+ OSSafeReleaseNULL(IOGVAHEVCEncodeCapabilities);
+ }
+ }
+ }
+}
+void RAD::updateAccelConfig(size_t hwIndex, IOService *accelService, const char **accelConfig) {
+ if (accelService && accelConfig) {
+ if (fixConfigName) {
+ auto gpuService = accelService->getParentEntry(gIOServicePlane);
+
+ if (gpuService) {
+ auto model = OSDynamicCast(OSData, gpuService->getProperty("model"));
+ if (model) {
+ auto modelStr = static_cast<const char *>(model->getBytesNoCopy());
+ if (modelStr) {
+ if (modelStr[0] == 'A' && ((modelStr[1] == 'M' && modelStr[2] == 'D') ||
+ (modelStr[1] == 'T' && modelStr[2] == 'I')) && modelStr[3] == ' ') {
+ modelStr += 4;
+ }
+
+ DBGLOG("rad", "updateAccelConfig found gpu model %s", modelStr);
+ *accelConfig = modelStr;
+ } else {
+ DBGLOG("rad", "updateAccelConfig found null gpu model");
+ }
+ } else {
+ DBGLOG("rad", "updateAccelConfig failed to find gpu model");
+ }
+
+ } else {
+ DBGLOG("rad", "updateAccelConfig failed to find accelerator parent");
+ }
+ }
+
+ if (enableGvaSupport && hwIndex == IndexRadeonHardwareX4000) {
+ setGvaProperties(accelService);
+ }
+ }
+}
- } else {
- DBGLOG("rad", "translateAtomConnectorInfoV1 failed to detect sense for translated connector");
- }
- }
+bool RAD::wrapSetProperty(IORegistryEntry *that, const char *aKey, void *bytes, unsigned length) {
+ if (length > 10 && aKey && reinterpret_cast<const uint32_t *>(aKey)[0] == 'edom' && reinterpret_cast<const uint16_t *>(aKey)[2] == 'l') {
+ DBGLOG("rad", "SetProperty caught model %u (%.*s)", length, length, static_cast<char *>(bytes));
+ if (*static_cast<uint32_t *>(bytes) == ' DMA' || *static_cast<uint32_t *>(bytes) == ' ITA' || *static_cast<uint32_t *>(bytes) == 'edaR') {
+ if (FunctionCast(wrapGetProperty, callbackRAD->orgGetProperty)(that, aKey)) {
+ DBGLOG("rad", "SetProperty ignored setting %s to %s", aKey, static_cast<char *>(bytes));
+ return true;
+ }
+ DBGLOG("rad", "SetProperty missing %s, fallback to %s", aKey, static_cast<char *>(bytes));
+ }
+ }
+
+ return FunctionCast(wrapSetProperty, callbackRAD->orgSetProperty)(that, aKey, bytes, length);
+}
- return code;
+OSObject *RAD::wrapGetProperty(IORegistryEntry *that, const char *aKey) {
+ auto obj = FunctionCast(wrapGetProperty, callbackRAD->orgGetProperty)(that, aKey);
+ auto props = OSDynamicCast(OSDictionary, obj);
+
+ if (props && aKey) {
+ const char *prefix {nullptr};
+ auto provider = OSDynamicCast(IOService, that->getParentEntry(gIOServicePlane));
+ if (provider) {
+ if (aKey[0] == 'a') {
+ if (!strcmp(aKey, "aty_config"))
+ prefix = "CFG,";
+ else if (!strcmp(aKey, "aty_properties"))
+ prefix = "PP,";
+ } else if (aKey[0] == 'c' && !strcmp(aKey, "cail_properties")) {
+ prefix = "CAIL,";
+ }
+
+ if (prefix) {
+ DBGLOG("rad", "GetProperty discovered property merge request for %s", aKey);
+ auto rawProps = props->copyCollection();
+ if (rawProps) {
+ auto newProps = OSDynamicCast(OSDictionary, rawProps);
+ if (newProps) {
+ callbackRAD->mergeProperties(newProps, prefix, provider);
+ that->setProperty(aKey, newProps);
+ obj = newProps;
+ }
+ rawProps->release();
+ }
+
+ }
+ }
+ }
+
+ return obj;
}
-uint32_t RAD::wrapTranslateAtomConnectorInfoV2(void *that, RADConnectors::AtomConnectorInfo *info, RADConnectors::Connector *connector) {
- uint32_t code = FunctionCast(wrapTranslateAtomConnectorInfoV2, callbackRAD->orgTranslateAtomConnectorInfoV2)(that, info, connector);
+uint32_t RAD::wrapGetConnectorsInfoV1(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
+ uint32_t code = FunctionCast(wrapGetConnectorsInfoV1, callbackRAD->orgGetConnectorsInfoV1)(that, connectors, sz);
+ auto props = callbackRAD->currentPropProvider.get();
+
+ if (code == 0 && sz && props && *props) {
+ if (getKernelVersion() >= KernelVersion::HighSierra)
+ callbackRAD->updateConnectorsInfo(nullptr, nullptr, *props, connectors, sz);
+ else
+ callbackRAD->updateConnectorsInfo(static_cast<void **>(that)[1], callbackRAD->orgGetAtomObjectTableForType, *props, connectors, sz);
+ } else {
+ DBGLOG("rad", "getConnectorsInfoV1 failed %X or undefined %d", code, props == nullptr);
+ }
+
+ return code;
+}
- if (code == 0 && info && connector) {
- RADConnectors::print(connector, 1);
+uint32_t RAD::wrapGetConnectorsInfoV2(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
+ uint32_t code = FunctionCast(wrapGetConnectorsInfoV2, callbackRAD->orgGetConnectorsInfoV2)(that, connectors, sz);
+ auto props = callbackRAD->currentPropProvider.get();
- uint8_t sense = getSenseID(info->i2cRecord);
- if (sense) {
- DBGLOG("rad", "translateAtomConnectorInfoV2 got sense id %02X", sense);
- uint8_t txmit = 0, enc = 0;
- if (getTxEnc(info->usGraphicObjIds, txmit, enc))
- callbackRAD->autocorrectConnector(getConnectorID(info->usConnObjectId), getSenseID(info->i2cRecord), txmit, enc, connector, 1);
- } else {
- DBGLOG("rad", "translateAtomConnectorInfoV2 failed to detect sense for translated connector");
- }
- }
+ if (code == 0 && sz && props && *props)
+ callbackRAD->updateConnectorsInfo(nullptr, nullptr, *props, connectors, sz);
+ else
+ DBGLOG("rad", "getConnectorsInfoV2 failed %X or undefined %d", code, props == nullptr);
- return code;
+ return code;
}
-bool RAD::wrapATIControllerStart(IOService *ctrl, IOService *provider) {
- DBGLOG("rad", "starting controller " PRIKADDR, CASTKADDR(current_thread()));
- if (callbackRAD->forceVesaMode) {
- DBGLOG("rad", "disabling video acceleration on request");
- return false;
- }
+uint32_t RAD::wrapLegacyGetConnectorsInfo(void *that, RADConnectors::Connector *connectors, uint8_t *sz) {
+ uint32_t code = FunctionCast(wrapLegacyGetConnectorsInfo, callbackRAD->orgLegacyGetConnectorsInfo)(that, connectors, sz);
+ auto props = callbackRAD->currentLegacyPropProvider.get();
- callbackRAD->currentPropProvider.set(provider);
- bool r = FunctionCast(wrapATIControllerStart, callbackRAD->orgATIControllerStart)(ctrl, provider);
- DBGLOG("rad", "starting controller done %d " PRIKADDR, r, CASTKADDR(current_thread()));
- callbackRAD->currentPropProvider.erase();
+ if (code == 0 && sz && props && *props)
+ callbackRAD->updateConnectorsInfo(static_cast<void **>(that)[1], callbackRAD->orgLegacyGetAtomObjectTableForType, *props, connectors, sz);
+ else
+ DBGLOG("rad", "legacy getConnectorsInfo failed %X or undefined %d", code, props == nullptr);
- return r;
+ return code;
}
-bool RAD::wrapLegacyATIControllerStart(IOService *ctrl, IOService *provider) {
- DBGLOG("rad", "starting legacy controller " PRIKADDR, CASTKADDR(current_thread()));
- if (callbackRAD->forceVesaMode) {
- DBGLOG("rad", "disabling legacy video acceleration on request");
- return false;
- }
+uint32_t RAD::wrapTranslateAtomConnectorInfoV1(void *that, RADConnectors::AtomConnectorInfo *info, RADConnectors::Connector *connector) {
+ uint32_t code = FunctionCast(wrapTranslateAtomConnectorInfoV1, callbackRAD->orgTranslateAtomConnectorInfoV1)(that, info, connector);
+
+ if (code == 0 && info && connector) {
+ RADConnectors::print(connector, 1);
+
+ uint8_t sense = getSenseID(info->i2cRecord);
+ if (sense) {
+ DBGLOG("rad", "translateAtomConnectorInfoV1 got sense id %02X", sense);
+
+ // We need to extract usGraphicObjIds from info->hpdRecord, which is of type ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT:
+ // struct ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT {
+ // uint8_t ucNumberOfSrc;
+ // uint16_t usSrcObjectID[ucNumberOfSrc];
+ // uint8_t ucNumberOfDst;
+ // uint16_t usDstObjectID[ucNumberOfDst];
+ // };
+ // The value we need is in usSrcObjectID. The structure is byte-packed.
+
+ uint8_t ucNumberOfSrc = info->hpdRecord[0];
+ for (uint8_t i = 0; i < ucNumberOfSrc; i++) {
+ auto usSrcObjectID = *reinterpret_cast<uint16_t *>(info->hpdRecord + sizeof(uint8_t) + i * sizeof(uint16_t));
+ DBGLOG("rad", "translateAtomConnectorInfoV1 checking %04X object id", usSrcObjectID);
+ if (((usSrcObjectID & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT) == GRAPH_OBJECT_TYPE_ENCODER) {
+ uint8_t txmit = 0, enc = 0;
+ if (getTxEnc(usSrcObjectID, txmit, enc))
+ callbackRAD->autocorrectConnector(getConnectorID(info->usConnObjectId), getSenseID(info->i2cRecord), txmit, enc, connector, 1);
+ break;
+ }
+ }
+
+
+ } else {
+ DBGLOG("rad", "translateAtomConnectorInfoV1 failed to detect sense for translated connector");
+ }
+ }
+
+ return code;
+}
- callbackRAD->currentLegacyPropProvider.set(provider);
- bool r = FunctionCast(wrapLegacyATIControllerStart, callbackRAD->orgLegacyATIControllerStart)(ctrl, provider);
- DBGLOG("rad", "starting legacy legacy controller done %d " PRIKADDR, r, CASTKADDR(current_thread()));
- callbackRAD->currentLegacyPropProvider.erase();
+uint32_t RAD::wrapTranslateAtomConnectorInfoV2(void *that, RADConnectors::AtomConnectorInfo *info, RADConnectors::Connector *connector) {
+ uint32_t code = FunctionCast(wrapTranslateAtomConnectorInfoV2, callbackRAD->orgTranslateAtomConnectorInfoV2)(that, info, connector);
+
+ if (code == 0 && info && connector) {
+ RADConnectors::print(connector, 1);
+
+ uint8_t sense = getSenseID(info->i2cRecord);
+ if (sense) {
+ DBGLOG("rad", "translateAtomConnectorInfoV2 got sense id %02X", sense);
+ uint8_t txmit = 0, enc = 0;
+ if (getTxEnc(info->usGraphicObjIds, txmit, enc))
+ callbackRAD->autocorrectConnector(getConnectorID(info->usConnObjectId), getSenseID(info->i2cRecord), txmit, enc, connector, 1);
+ } else {
+ DBGLOG("rad", "translateAtomConnectorInfoV2 failed to detect sense for translated connector");
+ }
+ }
+
+ return code;
+}
- return r;
+bool RAD::wrapATIControllerStart(IOService *ctrl, IOService *provider) {
+ DBGLOG("rad", "starting controller " PRIKADDR, CASTKADDR(current_thread()));
+ if (callbackRAD->forceVesaMode) {
+ DBGLOG("rad", "disabling video acceleration on request");
+ return false;
+ }
+
+ callbackRAD->currentPropProvider.set(provider);
+ bool r = FunctionCast(wrapATIControllerStart, callbackRAD->orgATIControllerStart)(ctrl, provider);
+ DBGLOG("rad", "starting controller done %d " PRIKADDR, r, CASTKADDR(current_thread()));
+ callbackRAD->currentPropProvider.erase();
+
+ return r;
+}
+
+bool RAD::wrapLegacyATIControllerStart(IOService *ctrl, IOService *provider) {
+ DBGLOG("rad", "starting legacy controller " PRIKADDR, CASTKADDR(current_thread()));
+ if (callbackRAD->forceVesaMode) {
+ DBGLOG("rad", "disabling legacy video acceleration on request");
+ return false;
+ }
+
+ callbackRAD->currentLegacyPropProvider.set(provider);
+ bool r = FunctionCast(wrapLegacyATIControllerStart, callbackRAD->orgLegacyATIControllerStart)(ctrl, provider);
+ DBGLOG("rad", "starting legacy legacy controller done %d " PRIKADDR, r, CASTKADDR(current_thread()));
+ callbackRAD->currentLegacyPropProvider.erase();
+
+ return r;
}
IOReturn RAD::findProjectByPartNumber(IOService *ctrl, void *properties) {