From d4d925fd799bdc0eb4826bb67f4211354868452c Mon Sep 17 00:00:00 2001 From: hornet Date: Sat, 30 Nov 2024 08:11:08 +0500 Subject: [PATCH] finished project outline, added two walkthrough sections, included local copies of some sources --- README.md | 173 +- .../.github/workflows/build.yml | 106 + .../.github/workflows/nightly.yml | 41 + .../.github/workflows/release.yml | 28 + local/UEFI/edk2-rk3588-master/.gitignore | 13 + local/UEFI/edk2-rk3588-master/.gitmodules | 16 + local/UEFI/edk2-rk3588-master/README.md | 376 ++ local/UEFI/edk2-rk3588-master/build.sh | 252 + .../edk2-rk3588-master/configs/RK3588.conf | 3 + .../edk2-rk3588-master/configs/aio-3588q.conf | 3 + .../edk2-rk3588-master/configs/blade3.conf | 3 + .../edk2-rk3588-master/configs/edge2.conf | 3 + .../configs/fydetab-duo.conf | 3 + .../UEFI/edk2-rk3588-master/configs/h88k.conf | 3 + .../configs/indiedroid-nova.conf | 3 + .../edk2-rk3588-master/configs/itx-3588j.conf | 3 + .../edk2-rk3588-master/configs/nanopc-t6.conf | 3 + .../configs/nanopi-r6c.conf | 3 + .../configs/nanopi-r6s.conf | 3 + .../configs/orangepi-5.conf | 3 + .../configs/orangepi-5plus.conf | 3 + .../edk2-rk3588-master/configs/r58-mini.conf | 3 + .../UEFI/edk2-rk3588-master/configs/r58x.conf | 3 + .../configs/roc-rk3588s-pc.conf | 3 + .../configs/rock-5-itx.conf | 3 + .../edk2-rk3588-master/configs/rock-5a.conf | 3 + .../edk2-rk3588-master/configs/rock-5b.conf | 3 + .../configs/rock-5bplus.conf | 3 + .../configs/station-m3.conf | 3 + .../Platform/Rockchip/DeviceTree/README.md | 20 + .../Rockchip/DeviceTree/itx-3588j.dtb | Bin 0 -> 168063 bytes .../DeviceTree/rk3588-blade3-v101-linux.dtb | Bin 0 -> 269831 bytes .../rk3588-blueberry-edge-v12-linux.dtb | Bin 0 -> 271643 bytes .../rk3588-blueberry-minipc-linux.dtb | Bin 0 -> 269283 bytes .../DeviceTree/rk3588-firefly-aio-3588q.dtb | Bin 0 -> 182117 bytes .../DeviceTree/rk3588-hinlink-h88k.dtb | Bin 0 -> 268895 bytes .../Rockchip/DeviceTree/rk3588-nanopc-t6.dtb | Bin 0 -> 273254 bytes .../DeviceTree/rk3588-orangepi-5-plus.dtb | Bin 0 -> 281743 bytes .../Rockchip/DeviceTree/rk3588-rock-5-itx.dtb | Bin 0 -> 272046 bytes .../DeviceTree/rk3588-rock-5b-plus.dtb | Bin 0 -> 176048 bytes .../Rockchip/DeviceTree/rk3588-rock-5b.dtb | Bin 0 -> 272520 bytes .../DeviceTree/rk3588s-9tripod-linux.dtb | Bin 0 -> 241209 bytes .../DeviceTree/rk3588s-fydetab-duo.dtb | Bin 0 -> 251158 bytes .../DeviceTree/rk3588s-khadas-edge2.dtb | Bin 0 -> 261417 bytes .../DeviceTree/rk3588s-nanopi-r6c.dtb | Bin 0 -> 234781 bytes .../DeviceTree/rk3588s-nanopi-r6s.dtb | Bin 0 -> 235007 bytes .../DeviceTree/rk3588s-orangepi-5.dtb | Bin 0 -> 252880 bytes .../Rockchip/DeviceTree/rk3588s-rock-5a.dtb | Bin 0 -> 235315 bytes .../Rockchip/DeviceTree/roc-rk3588s-pc.dtb | Bin 0 -> 147959 bytes .../Ameridroid/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 193390 bytes .../Ameridroid/Drivers/LogoDxe/Logo.c | 144 + .../Ameridroid/Drivers/LogoDxe/Logo.idf | 10 + .../Ameridroid/Drivers/LogoDxe/LogoDxe.inf | 48 + .../IndiedroidNova/AcpiTables/AcpiTables.inf | 58 + .../IndiedroidNova/AcpiTables/Dsdt.asl | 53 + .../IndiedroidNova.Modules.fdf.inc | 18 + .../IndiedroidNova/IndiedroidNova.dsc | 116 + .../RockchipPlatformLib/RockchipPlatformLib.c | 296 + .../RockchipPlatformLib.inf | 35 + .../AIO-3588Q/AIO-3588Q.Modules.fdf.inc | 18 + .../Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc | 31 + .../Firefly/AIO-3588Q/AIO-3588Q.dsc.inc | 134 + .../AIO-3588Q/AcpiTables/AcpiTables.inf | 58 + .../Firefly/AIO-3588Q/AcpiTables/Dsdt.asl | 55 + .../RockchipPlatformLib/RockchipPlatformLib.c | 460 ++ .../RockchipPlatformLib.inf | 38 + .../RockchipPlatformLibPcaDepex.inf | 42 + .../Platform/Firefly/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 106806 bytes .../Platform/Firefly/Drivers/LogoDxe/Logo.c | 144 + .../Platform/Firefly/Drivers/LogoDxe/Logo.idf | 10 + .../Firefly/Drivers/LogoDxe/LogoDxe.inf | 48 + .../ITX-3588J/AcpiTables/AcpiTables.inf | 58 + .../Firefly/ITX-3588J/AcpiTables/Dsdt.asl | 41 + .../ITX-3588J/ITX-3588J.Modules.fdf.inc | 19 + .../Platform/Firefly/ITX-3588J/ITX-3588J.dsc | 34 + .../Firefly/ITX-3588J/ITX-3588J.dsc.inc | 120 + .../RockchipPlatformLib/RockchipPlatformLib.c | 511 ++ .../RockchipPlatformLib.inf | 38 + .../ROC-RK3588S-PC/AcpiTables/AcpiTables.inf | 58 + .../ROC-RK3588S-PC/AcpiTables/Dsdt.asl | 53 + .../RockchipPlatformLib/RockchipPlatformLib.c | 368 ++ .../RockchipPlatformLib.inf | 35 + .../ROC-RK3588S-PC.Modules.fdf.inc | 18 + .../Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc | 45 + .../ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc | 107 + .../FriendlyElec/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 148634 bytes .../FriendlyElec/Drivers/LogoDxe/Logo.c | 144 + .../FriendlyElec/Drivers/LogoDxe/Logo.idf | 10 + .../FriendlyElec/Drivers/LogoDxe/LogoDxe.inf | 48 + .../NanoPC-T6/AcpiTables/AcpiTables.inf | 58 + .../NanoPC-T6/AcpiTables/Dsdt.asl | 44 + .../RockchipPlatformLib/RockchipPlatformLib.c | 354 ++ .../RockchipPlatformLib.inf | 34 + .../NanoPC-T6/NanoPC-T6.Modules.fdf.inc | 18 + .../FriendlyElec/NanoPC-T6/NanoPC-T6.dsc | 116 + .../NanoPi-R6C/AcpiTables/AcpiTables.inf | 58 + .../NanoPi-R6C/AcpiTables/Dsdt.asl | 39 + .../RockchipPlatformLib/RockchipPlatformLib.c | 342 + .../RockchipPlatformLib.inf | 34 + .../NanoPi-R6C/NanoPi-R6C.Modules.fdf.inc | 19 + .../FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc | 114 + .../NanoPi-R6S/AcpiTables/AcpiTables.inf | 58 + .../NanoPi-R6S/AcpiTables/Dsdt.asl | 39 + .../RockchipPlatformLib/RockchipPlatformLib.c | 329 + .../RockchipPlatformLib.inf | 34 + .../NanoPi-R6S/NanoPi-R6S.Modules.fdf.inc | 18 + .../FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc | 112 + .../FydetabDuo/AcpiTables/AcpiTables.inf | 58 + .../FydetabDuo/AcpiTables/Dsdt.asl | 60 + .../FydetabDuo/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 119030 bytes .../FydetabDuo/Drivers/LogoDxe/Logo.c | 144 + .../FydetabDuo/Drivers/LogoDxe/Logo.idf | 10 + .../FydetabDuo/Drivers/LogoDxe/LogoDxe.inf | 48 + .../FydetabDuo/FydetabDuo.Modules.fdf.inc | 18 + .../FydeInnovations/FydetabDuo/FydetabDuo.dsc | 113 + .../RockchipPlatformLib/CsotDsiPanel.c | 171 + .../RockchipPlatformLib/RockchipPlatformLib.c | 306 + .../RockchipPlatformLib.inf | 41 + .../Platform/Hinlink/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 504138 bytes .../Platform/Hinlink/Drivers/LogoDxe/Logo.c | 144 + .../Platform/Hinlink/Drivers/LogoDxe/Logo.idf | 10 + .../Hinlink/Drivers/LogoDxe/LogoDxe.inf | 48 + .../Hinlink/H88K/AcpiTables/AcpiTables.inf | 58 + .../Platform/Hinlink/H88K/AcpiTables/Dsdt.asl | 54 + .../Hinlink/H88K/H88K.Modules.fdf.inc | 18 + .../Platform/Hinlink/H88K/H88K.dsc | 121 + .../RockchipPlatformLib/RockchipPlatformLib.c | 386 ++ .../RockchipPlatformLib.inf | 35 + .../Drivers/KhadasMcuDxe/KhadasMcuDxe.c | 341 + .../Drivers/KhadasMcuDxe/KhadasMcuDxe.h | 64 + .../Drivers/KhadasMcuDxe/KhadasMcuDxe.inf | 48 + .../Platform/Khadas/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 330318 bytes .../Platform/Khadas/Drivers/LogoDxe/Logo.c | 144 + .../Platform/Khadas/Drivers/LogoDxe/Logo.idf | 10 + .../Khadas/Drivers/LogoDxe/LogoDxe.inf | 48 + .../Khadas/Edge2/AcpiTables/AcpiTables.inf | 58 + .../Platform/Khadas/Edge2/AcpiTables/Dsdt.asl | 53 + .../Khadas/Edge2/Edge2.Modules.fdf.inc | 21 + .../Platform/Khadas/Edge2/Edge2.dsc | 120 + .../RockchipPlatformLib/RockchipPlatformLib.c | 383 ++ .../RockchipPlatformLib.inf | 40 + .../Khadas/Include/Protocol/KhadasMcu.h | 30 + .../Platform/Khadas/KhadasPkg.dec | 26 + .../Mekotronics/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 224526 bytes .../Mekotronics/Drivers/LogoDxe/Logo.c | 144 + .../Mekotronics/Drivers/LogoDxe/Logo.idf | 10 + .../Mekotronics/Drivers/LogoDxe/LogoDxe.inf | 48 + .../R58-Mini/AcpiTables/AcpiTables.inf | 58 + .../Mekotronics/R58-Mini/AcpiTables/Dsdt.asl | 40 + .../RockchipPlatformLib/RockchipPlatformLib.c | 341 + .../RockchipPlatformLib.inf | 34 + .../R58-Mini/R58-Mini.Modules.fdf.inc | 18 + .../Mekotronics/R58-Mini/R58-Mini.dsc | 124 + .../R58X/AcpiTables/AcpiTables.inf | 58 + .../Mekotronics/R58X/AcpiTables/Dsdt.asl | 55 + .../RockchipPlatformLib/RockchipPlatformLib.c | 384 ++ .../RockchipPlatformLib.inf | 34 + .../Mekotronics/R58X/R58X.Modules.fdf.inc | 18 + .../Platform/Mekotronics/R58X/R58X.dsc | 126 + .../Mixtile/Blade3/AcpiTables/AcpiTables.inf | 58 + .../Mixtile/Blade3/AcpiTables/Dsdt.asl | 40 + .../Mixtile/Blade3/Blade3.Modules.fdf.inc | 18 + .../Platform/Mixtile/Blade3/Blade3.dsc | 109 + .../RockchipPlatformLib/RockchipPlatformLib.c | 345 ++ .../RockchipPlatformLib.inf | 35 + .../Platform/Mixtile/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 172854 bytes .../Platform/Mixtile/Drivers/LogoDxe/Logo.c | 144 + .../Platform/Mixtile/Drivers/LogoDxe/Logo.idf | 10 + .../Mixtile/Drivers/LogoDxe/LogoDxe.inf | 48 + .../OrangePi/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 116534 bytes .../Platform/OrangePi/Drivers/LogoDxe/Logo.c | 144 + .../OrangePi/Drivers/LogoDxe/Logo.idf | 10 + .../OrangePi/Drivers/LogoDxe/LogoDxe.inf | 48 + .../OrangePi5/AcpiTables/AcpiTables.inf | 58 + .../OrangePi/OrangePi5/AcpiTables/Dsdt.asl | 53 + .../RockchipPlatformLib/RockchipPlatformLib.c | 332 + .../RockchipPlatformLib.inf | 35 + .../OrangePi5/OrangePi5.Modules.fdf.inc | 18 + .../Platform/OrangePi/OrangePi5/OrangePi5.dsc | 122 + .../OrangePi5Plus/AcpiTables/AcpiTables.inf | 58 + .../OrangePi5Plus/AcpiTables/Dsdt.asl | 53 + .../RockchipPlatformLib/RockchipPlatformLib.c | 385 ++ .../RockchipPlatformLib.inf | 35 + .../OrangePi5Plus.Modules.fdf.inc | 18 + .../OrangePi/OrangePi5Plus/OrangePi5Plus.dsc | 119 + .../Platform/Radxa/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 218470 bytes .../Platform/Radxa/Drivers/LogoDxe/Logo.c | 144 + .../Platform/Radxa/Drivers/LogoDxe/Logo.idf | 10 + .../Radxa/Drivers/LogoDxe/LogoDxe.inf | 48 + .../Radxa/ROCK5A/AcpiTables/AcpiTables.inf | 58 + .../Platform/Radxa/ROCK5A/AcpiTables/Dsdt.asl | 53 + .../RockchipPlatformLib/RockchipPlatformLib.c | 330 + .../RockchipPlatformLib.inf | 35 + .../Radxa/ROCK5A/ROCK5A.Modules.fdf.inc | 18 + .../Platform/Radxa/ROCK5A/ROCK5A.dsc | 115 + .../Radxa/ROCK5B/AcpiTables/AcpiTables.inf | 58 + .../Platform/Radxa/ROCK5B/AcpiTables/Dsdt.asl | 54 + .../RockchipPlatformLib/RockchipPlatformLib.c | 384 ++ .../RockchipPlatformLib.inf | 35 + .../Radxa/ROCK5B/ROCK5B.Modules.fdf.inc | 18 + .../Platform/Radxa/ROCK5B/ROCK5B.dsc | 120 + .../ROCK5BPlus/AcpiTables/AcpiTables.inf | 58 + .../Radxa/ROCK5BPlus/AcpiTables/Dsdt.asl | 54 + .../RockchipPlatformLib/RockchipPlatformLib.c | 395 ++ .../RockchipPlatformLib.inf | 35 + .../ROCK5BPlus/ROCK5BPlus.Modules.fdf.inc | 18 + .../Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc | 122 + .../Radxa/ROCK5ITX/AcpiTables/AcpiTables.inf | 58 + .../Radxa/ROCK5ITX/AcpiTables/Dsdt.asl | 54 + .../RockchipPlatformLib/RockchipPlatformLib.c | 388 ++ .../RockchipPlatformLib.inf | 35 + .../Radxa/ROCK5ITX/ROCK5ITX.Modules.fdf.inc | 18 + .../Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc | 126 + .../StationPC/Drivers/LogoDxe/Logo.bmp | Bin 0 -> 106738 bytes .../Platform/StationPC/Drivers/LogoDxe/Logo.c | 144 + .../StationPC/Drivers/LogoDxe/Logo.idf | 10 + .../StationPC/Drivers/LogoDxe/LogoDxe.inf | 48 + .../StationPC/StationM3/StationM3.dsc | 52 + .../Applications/I2cDemoTest/I2cDemoTest.c | 356 ++ .../Applications/I2cDemoTest/I2cDemoTest.inf | 45 + .../Applications/I2cDemoTest/I2cDemoTest.uni | 49 + .../Applications/SpiTool/SpiFlashCmd.c | 417 ++ .../Applications/SpiTool/SpiFlashCmd.inf | 46 + .../Applications/SpiTool/SpiFlashCmd.uni | 50 + .../Drivers/DwcSdhciDxe/DwcSdhciDxe.c | 276 + .../Drivers/DwcSdhciDxe/DwcSdhciDxe.h | 97 + .../Drivers/DwcSdhciDxe/DwcSdhciDxe.inf | 50 + .../Drivers/I2c/I2cDemoDxe/I2cDemoDxe.c | 306 + .../Drivers/I2c/I2cDemoDxe/I2cDemoDxe.h | 76 + .../Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf | 43 + .../Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c | 1036 ++++ .../Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h | 327 + .../Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf | 61 + .../Rk860xRegulatorDxe/Rk860xRegulatorDxe.c | 546 ++ .../Rk860xRegulatorDxe/Rk860xRegulatorDxe.h | 120 + .../Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf | 52 + .../LcdGraphicsOutputBlt.c | 938 +++ .../LcdGraphicsOutputDxe.c | 738 +++ .../LcdGraphicsOutputDxe.h | 122 + .../LcdGraphicsOutputDxe.inf | 62 + .../Drivers/NorFlashDxe/NorFlashDxe.c | 1214 ++++ .../Drivers/NorFlashDxe/NorFlashDxe.inf | 61 + .../Rockchip/Drivers/OhciDxe/ComponentName.c | 219 + .../Rockchip/Drivers/OhciDxe/ComponentName.h | 141 + .../Rockchip/Drivers/OhciDxe/Descriptor.h | 132 + .../Silicon/Rockchip/Drivers/OhciDxe/Ohci.c | 2416 ++++++++ .../Silicon/Rockchip/Drivers/OhciDxe/Ohci.h | 668 ++ .../Rockchip/Drivers/OhciDxe/OhciDebug.c | 85 + .../Rockchip/Drivers/OhciDxe/OhciDebug.h | 46 + .../Rockchip/Drivers/OhciDxe/OhciDxe.inf | 77 + .../Rockchip/Drivers/OhciDxe/OhciReg.c | 1383 +++++ .../Rockchip/Drivers/OhciDxe/OhciReg.h | 920 +++ .../Rockchip/Drivers/OhciDxe/OhciSched.c | 531 ++ .../Rockchip/Drivers/OhciDxe/OhciSched.h | 225 + .../Rockchip/Drivers/OhciDxe/OhciUrb.c | 889 +++ .../Rockchip/Drivers/OhciDxe/OhciUrb.h | 387 ++ .../Rockchip/Drivers/OhciDxe/UsbHcMem.c | 546 ++ .../Rockchip/Drivers/OhciDxe/UsbHcMem.h | 150 + .../Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.c | 869 +++ .../Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.h | 76 + .../Drivers/Pca9555Dxe/Pca9555Dxe.inf | 48 + .../Drivers/PlatformSmbiosDxe/Crc32Table.h | 266 + .../PlatformSmbiosDxe/PlatformSmbiosDxe.c | 1168 ++++ .../PlatformSmbiosDxe/PlatformSmbiosDxe.inf | 73 + .../Rockchip/Drivers/RkFvbDxe/RkFvbDxe.c | 1458 +++++ .../Rockchip/Drivers/RkFvbDxe/RkFvbDxe.h | 126 + .../Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf | 82 + .../Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.c | 169 + .../Drivers/RkSdmmcDxe/RkSdmmcDxe.inf | 49 + .../Rtc8563PlatformDxe/Rtc8563PlatformDxe.c | 98 + .../Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf | 42 + .../Drivers/StatusLedDxe/StatusLedDxe.c | 278 + .../Drivers/StatusLedDxe/StatusLedDxe.inf | 41 + .../Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.c | 419 ++ .../Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.h | 157 + .../Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf | 53 + .../Rockchip/Drivers/Vop2Dxe/Vop2Dxe.c | 2574 ++++++++ .../Rockchip/Drivers/Vop2Dxe/Vop2Dxe.h | 230 + .../Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf | 44 + .../Silicon/Rockchip/FvCompactModules.fdf.inc | 9 + .../Silicon/Rockchip/FvMainAprioriDxe.fdf.inc | 13 + .../Silicon/Rockchip/FvMainModules.fdf.inc | 229 + .../Silicon/Rockchip/FvRules.fdf.inc | 139 + .../Rockchip/Include/Library/AcpiNextLib.h | 98 + .../Rockchip/Include/Library/AnalogixDpLib.h | 1032 +++ .../Include/Library/BaseVariableLib.h | 90 + .../Silicon/Rockchip/Include/Library/CruLib.h | 304 + .../Rockchip/Include/Library/DrmModes.h | 161 + .../Rockchip/Include/Library/DwHdmiQpLib.h | 1000 +++ .../Include/Library/DwcSdhciPlatformLib.h | 21 + .../Silicon/Rockchip/Include/Library/Fspi.h | 98 + .../Silicon/Rockchip/Include/Library/HalDef.h | 142 + .../Rockchip/Include/Library/MediaBusFormat.h | 163 + .../Silicon/Rockchip/Include/Library/OtpLib.h | 35 + .../Silicon/Rockchip/Include/Library/PWMLib.h | 423 ++ .../Silicon/Rockchip/Include/Library/RK806.h | 175 + .../Rockchip/Include/Library/RkAtagsLib.h | 208 + .../Include/Library/RkSdmmcPlatformLib.h | 33 + .../Include/Library/RockchipDisplayLib.h | 285 + .../Include/Library/RockchipPlatformLib.h | 155 + .../Rockchip/Include/Library/SdramLib.h | 17 + .../Silicon/Rockchip/Include/Library/Snor.h | 106 + .../Silicon/Rockchip/Include/Library/SpiLib.h | 133 + .../Silicon/Rockchip/Include/Library/SpiMem.h | 152 + .../Rockchip/Include/Library/Vop2Regs.h | 701 +++ .../Rockchip/Include/Library/drm_dp_helper.h | 1227 ++++ .../Rockchip/Include/Library/drm_dsc.h | 613 ++ .../Rockchip/Include/Library/drm_mipi_dsi.h | 256 + .../Silicon/Rockchip/Include/Library/errno.h | 168 + .../Rockchip/Include/Library/mipi_display.h | 143 + .../Rockchip/Include/Library/uboot-env.h | 222 + .../Silicon/Rockchip/Include/Protocol/DpPhy.h | 64 + .../Silicon/Rockchip/Include/Protocol/I2c.h | 32 + .../Rockchip/Include/Protocol/I2cDemo.h | 32 + .../Include/Protocol/NorFlashProtocol.h | 69 + .../Include/Protocol/OhciDeviceProtocol.h | 23 + .../Rockchip/Include/Protocol/Pca9555.h | 28 + .../Include/Protocol/Rk860xRegulator.h | 74 + .../Protocol/RockchipConnectorProtocol.h | 107 + .../Include/Protocol/RockchipCrtcProtocol.h | 105 + .../Include/Protocol/RockchipDsiPanel.h | 50 + .../Protocol/RockchipI2cMasterProtocol.h | 23 + .../Library/BaseVariableLib/BaseVariableLib.c | 1460 +++++ .../BaseVariableLib/BaseVariableLib.inf | 51 + .../Library/BaseVariableLib/Variable.h | 45 + .../Silicon/Rockchip/Library/CruLib/CruLib.c | 1048 ++++ .../Rockchip/Library/CruLib/CruLib.inf | 39 + .../Library/DisplayLib/AnalogixDpLib.c | 1311 ++++ .../Library/DisplayLib/AnalogixDpLib.inf | 63 + .../Library/DisplayLib/AnalogixDpReg.c | 1233 ++++ .../Rockchip/Library/DisplayLib/DwDpLib.c | 1706 +++++ .../Rockchip/Library/DisplayLib/DwDpLib.inf | 50 + .../Rockchip/Library/DisplayLib/DwHdmiQpLib.c | 768 +++ .../Library/DisplayLib/DwHdmiQpLib.inf | 63 + .../Library/DisplayLib/DwMipiDsi2Lib.c | 1623 +++++ .../Library/DisplayLib/DwMipiDsi2Lib.inf | 53 + .../DisplayLib/PhyRockchipSamsungHdptx.c | 897 +++ .../DisplayLib/PhyRockchipSamsungHdptxHdmi.c | 1190 ++++ .../Library/DisplayLib/RockchipDisplayLib.c | 107 + .../Library/DisplayLib/RockchipDisplayLib.inf | 35 + .../Library/DisplayLib/drm_dp_helper.c | 320 + .../Rockchip/Library/DisplayLib/drm_dsc.c | 374 ++ .../Library/DisplayLib/drm_mipi_dsi.c | 791 +++ .../Library/DisplayLib/rockchip_phy.c | 86 + .../Library/DisplayLib/rockchip_phy.h | 44 + .../Library/DisplayLib/samsung_mipi_dcphy.c | 1830 ++++++ .../DebugDw8250SerialPortLib.c | 40 + .../DebugDw8250SerialPortLib.inf | 35 + .../Dw8250SerialPortLib/Dw8250SerialPortLib.c | 50 + .../Dw8250SerialPortLib/Dw8250SerialPortLib.h | 110 + .../Dw8250SerialPortLib.inf | 37 + .../Dw8250SerialPortLibCommon.c | 260 + .../DwcSdhciPlatformLibNull.c | 30 + .../DwcSdhciPlatformLibNull.inf | 24 + .../Rockchip/Library/FspiLib/FspiLib.c | 497 ++ .../Rockchip/Library/FspiLib/FspiLib.inf | 39 + .../Silicon/Rockchip/Library/PWMLib/PWMLib.c | 139 + .../Rockchip/Library/PWMLib/PWMLib.inf | 35 + .../PlatformBootDescriptionLib.c | 416 ++ .../PlatformBootDescriptionLib.inf | 42 + .../PlatformBootManagerLib/PlatformBm.c | 1331 ++++ .../PlatformBootManagerLib/PlatformBm.h | 53 + .../PlatformBootManagerLib.inf | 100 + .../PlatformFlashAccessLibDxe.c | 172 + .../PlatformFlashAccessLibDxe.inf | 45 + .../Library/ResetSystemLib/ResetSystemLib.c | 164 + .../Library/ResetSystemLib/ResetSystemLib.inf | 35 + .../Rockchip/Library/RkAtagsLib/RkAtagsLib.c | 213 + .../Library/RkAtagsLib/RkAtagsLib.inf | 28 + .../Rockchip/Library/RkMtlLib/RkMtlLib.c | 197 + .../Rockchip/Library/RkMtlLib/RkMtlLib.inf | 35 + .../Library/RkMtlLib/RkMtlPrivateLib.h | 33 + .../Rockchip/Library/RkMtlLib/source.txt | 1 + .../RkSdmmcPlatformLibNull.c | 39 + .../RkSdmmcPlatformLibNull.inf | 24 + .../Rockchip/Library/SdramLib/SdramLib.c | 144 + .../Rockchip/Library/SdramLib/SdramLib.inf | 36 + .../Silicon/Rockchip/Library/SpiLib/RK806.c | 611 ++ .../Silicon/Rockchip/Library/SpiLib/RK806.inf | 41 + .../Silicon/Rockchip/Library/SpiLib/SpiLib.c | 491 ++ .../Rockchip/Library/SpiLib/SpiLib.inf | 39 + .../Rockchip/RK3588/AcpiTables/Cpu.asl | 134 + .../Rockchip/RK3588/AcpiTables/Dbg2.aslc | 69 + .../Rockchip/RK3588/AcpiTables/Dma.asl | 104 + .../Rockchip/RK3588/AcpiTables/DsdtCommon.asl | 13 + .../Rockchip/RK3588/AcpiTables/Emmc.asl | 133 + .../Rockchip/RK3588/AcpiTables/Es8388.asl | 28 + .../Rockchip/RK3588/AcpiTables/Fadt.aslc | 86 + .../Rockchip/RK3588/AcpiTables/Gmac0.asl | 96 + .../Rockchip/RK3588/AcpiTables/Gmac1.asl | 96 + .../Rockchip/RK3588/AcpiTables/Gpio.asl | 166 + .../Rockchip/RK3588/AcpiTables/Gtdt.aslc | 71 + .../Rockchip/RK3588/AcpiTables/I2c.asl | 200 + .../Rockchip/RK3588/AcpiTables/I2s.asl | 240 + .../Rockchip/RK3588/AcpiTables/Madt.aslc | 123 + .../Rockchip/RK3588/AcpiTables/Mcfg.aslc | 102 + .../Rockchip/RK3588/AcpiTables/Pcie.asl | 120 + .../Rockchip/RK3588/AcpiTables/Pptt.aslc | 267 + .../RK3588/AcpiTables/RK3588PcieIort.aslc | 121 + .../Rockchip/RK3588/AcpiTables/Sata.asl | 77 + .../Rockchip/RK3588/AcpiTables/Scmi.asl | 264 + .../Rockchip/RK3588/AcpiTables/Sdhc.asl | 72 + .../Rockchip/RK3588/AcpiTables/Spcr.aslc | 50 + .../Rockchip/RK3588/AcpiTables/Spi.asl | 145 + .../Rockchip/RK3588/AcpiTables/Uart.asl | 36 + .../Rockchip/RK3588/AcpiTables/Usb2Host.asl | 198 + .../Rockchip/RK3588/AcpiTables/Usb3Host0.asl | 23 + .../Rockchip/RK3588/AcpiTables/Usb3Host1.asl | 23 + .../Rockchip/RK3588/AcpiTables/Usb3Host2.asl | 26 + .../Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c | 581 ++ .../AcpiPlatformDxe/AcpiPlatformDxe.inf | 63 + .../Drivers/FdtPlatformDxe/FdtPlatformDxe.c | 717 +++ .../Drivers/FdtPlatformDxe/FdtPlatformDxe.inf | 62 + .../Drivers/GmacPlatformDxe/EthernetPhy.h | 50 + .../Drivers/GmacPlatformDxe/GmacPlatformDxe.c | 309 + .../GmacPlatformDxe/GmacPlatformDxe.inf | 51 + .../Drivers/GmacPlatformDxe/MotorcommPhy.c | 97 + .../Drivers/GmacPlatformDxe/RealtekPhy.c | 54 + .../RK3588/Drivers/RK3588Dxe/ComboPhy.c | 216 + .../RK3588/Drivers/RK3588Dxe/ComboPhy.h | 29 + .../RK3588/Drivers/RK3588Dxe/ConfigTable.c | 63 + .../RK3588/Drivers/RK3588Dxe/ConfigTable.h | 29 + .../RK3588/Drivers/RK3588Dxe/CpuPerformance.c | 498 ++ .../RK3588/Drivers/RK3588Dxe/CpuPerformance.h | 40 + .../Drivers/RK3588Dxe/DebugSerialPort.c | 50 + .../Drivers/RK3588Dxe/DebugSerialPort.h | 33 + .../RK3588/Drivers/RK3588Dxe/FanControl.c | 58 + .../RK3588/Drivers/RK3588Dxe/FanControl.h | 34 + .../RK3588/Drivers/RK3588Dxe/PciExpress30.c | 56 + .../RK3588/Drivers/RK3588Dxe/PciExpress30.h | 29 + .../RK3588/Drivers/RK3588Dxe/RK3588Dxe.c | 520 ++ .../RK3588/Drivers/RK3588Dxe/RK3588Dxe.h | 12 + .../RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf | 119 + .../Drivers/RK3588Dxe/RK3588DxeFormSetGuid.h | 17 + .../RK3588/Drivers/RK3588Dxe/RK3588DxeHii.uni | 183 + .../RK3588/Drivers/RK3588Dxe/RK3588DxeHii.vfr | 576 ++ .../RK3588/Drivers/RK3588Dxe/UsbDpPhy.c | 52 + .../RK3588/Drivers/RK3588Dxe/UsbDpPhy.h | 29 + .../RK3588/Drivers/UsbDpPhyDxe/UsbDpPhy.h | 79 + .../RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.c | 1253 ++++ .../Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf | 48 + .../RK3588/Drivers/UsbDpPhyDxe/errno.h | 168 + .../RK3588/Drivers/UsbDpPhyDxe/uboot-env.h | 85 + .../Rockchip/RK3588/Include/AcpiTables.h | 126 + .../Rockchip/RK3588/Include/Library/GpioLib.h | 143 + .../RK3588/Include/Library/Pcie30PhyLib.h | 17 + .../RK3588/Include/Library/Rk3588Mem.h | 28 + .../RK3588/Include/Library/Rk3588Pcie.h | 67 + .../Silicon/Rockchip/RK3588/Include/RK3588.h | 5519 +++++++++++++++++ .../Rockchip/RK3588/Include/RK3588RegsPeri.h | 13 + .../Rockchip/RK3588/Include/ScmiDefinitions.h | 55 + .../Silicon/Rockchip/RK3588/Include/Soc.h | 86 + .../Rockchip/RK3588/Include/VarStoreData.h | 97 + .../DwcSdhciPlatformLib/DwcSdhciPlatformLib.c | 63 + .../DwcSdhciPlatformLib.inf | 28 + .../Rockchip/RK3588/Library/GpioLib/GpioLib.c | 339 + .../RK3588/Library/GpioLib/GpioLib.inf | 35 + .../MemoryInitPeiLib/MemoryInitPeiLib.c | 164 + .../MemoryInitPeiLib/MemoryInitPeiLib.inf | 45 + .../Rockchip/RK3588/Library/OtpLib/OtpLib.c | 98 + .../Rockchip/RK3588/Library/OtpLib/OtpLib.inf | 35 + .../Library/Pcie30PhyLib/Pcie30PhyLib.c | 117 + .../Library/Pcie30PhyLib/Pcie30PhyLib.inf | 41 + .../Library/PlatformLib/PlatformLib.inf | 73 + .../RK3588/Library/PlatformLib/Rk3588.c | 120 + .../RK3588/Library/PlatformLib/Rk3588Helper.S | 45 + .../RK3588/Library/PlatformLib/Rk3588Mem.c | 192 + .../PciHostBridgeInit.c | 655 ++ .../PciHostBridgeInit.h | 18 + .../Rk3588PciHostBridgeLib/PciHostBridgeLib.c | 295 + .../Rk3588PciHostBridgeLib.inf | 56 + .../Rk3588PciSegmentLib/PciSegmentLib.c | 1415 +++++ .../Rk3588PciSegmentLib.inf | 41 + .../Rk3588PciSegmentLib.uni | 16 + .../RkSdmmcPlatformLib/RkSdmmcPlatformLib.c | 66 + .../RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf | 33 + .../RockchipPlatformLibCommon/RK3588CruLib.c | 480 ++ .../Silicon/Rockchip/RK3588/RK3588.dec | 98 + .../Silicon/Rockchip/RK3588/RK3588.fdf | 178 + .../Rockchip/RK3588/RK3588Base.dsc.inc | 374 ++ .../Rockchip/RK3588/RK3588Platform.dsc.inc | 29 + .../Rockchip/RK3588/RK3588SPlatform.dsc.inc | 29 + .../Silicon/Rockchip/Rockchip.dsc.inc | 795 +++ .../Silicon/Rockchip/RockchipPkg.dec | 96 + .../Synopsys/DesignWare/DesignWarePkg.dec | 25 + .../Drivers/DwMmcHcDxe/ComponentName.c | 207 + .../Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1294 ++++ .../Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 810 +++ .../Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 67 + .../DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.c | 1647 +++++ .../DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.h | 988 +++ .../Drivers/DwMmcHcDxe/EmmcDevice.c | 1035 ++++ .../DesignWare/Drivers/DwMmcHcDxe/SdDevice.c | 1110 ++++ .../Include/Protocol/PlatformDwMmc.h | 73 + .../edk2-rk3588-master/misc/extractbl31.py | 30 + local/UEFI/edk2-rk3588-master/misc/repack.sh | 34 + .../misc/rk3588_spi_nor_gpt.img | Bin 0 -> 17408 bytes .../misc/rk3588_spi_nor_gpt.txt | 11 + .../edk2-rk3588-master/misc/rk3588_spl.dtb | Bin 0 -> 7829 bytes .../misc/rk3588_spl_v1.12.bin | Bin 0 -> 228826 bytes .../misc/tools/aarch64/mkimage | Bin 0 -> 237712 bytes .../misc/tools/x86_64/mkimage | Bin 0 -> 211864 bytes .../edk2-rk3588-master/misc/uefi_rk3588.its | 111 + .../orangepi-5plus_UEFI_Release_v0.11.2.img | Bin 0 -> 6915584 bytes local/freebsd/bsdinstall.html | 530 ++ .../bsdinstall_files/FreeBSD-colors.svg | 92 + .../FreeBSD-monochromatic.svg | 82 + .../bsdinstall_files/bsdinstall-adduser1.png | Bin 0 -> 6678 bytes .../bsdinstall_files/bsdinstall-adduser2.png | Bin 0 -> 10337 bytes .../bsdinstall_files/bsdinstall-adduser3.png | Bin 0 -> 14716 bytes .../bsdinstall-boot-options-menu.png | Bin 0 -> 118629 bytes .../bsdinstall-choose-mode.png | Bin 0 -> 6969 bytes .../bsdinstall-config-components.png | Bin 0 -> 10826 bytes .../bsdinstall-config-hostname.png | Bin 0 -> 7844 bytes .../bsdinstall-config-services.png | Bin 0 -> 11743 bytes ...-configure-network-interface-ipv4-dhcp.png | Bin 0 -> 6529 bytes ...onfigure-network-interface-ipv4-static.png | Bin 0 -> 8016 bytes ...stall-configure-network-interface-ipv4.png | Bin 0 -> 6490 bytes ...onfigure-network-interface-ipv6-static.png | Bin 0 -> 8459 bytes ...stall-configure-network-interface-ipv6.png | Bin 0 -> 6488 bytes ...tall-configure-network-interface-slaac.png | Bin 0 -> 6727 bytes ...bsdinstall-configure-network-interface.png | Bin 0 -> 7318 bytes .../bsdinstall-configure-network-ipv4-dns.png | Bin 0 -> 9069 bytes ...nstall-configure-wireless-accesspoints.png | Bin 0 -> 11462 bytes .../bsdinstall-configure-wireless-scan.png | Bin 0 -> 6612 bytes ...sdinstall-configure-wireless-wpa2setup.png | Bin 0 -> 6309 bytes .../bsdinstall-distfile-extracting.png | Bin 0 -> 9506 bytes .../bsdinstall-distfile-fetching.png | Bin 0 -> 8628 bytes .../bsdinstall-distfile-verifying.png | Bin 0 -> 9099 bytes .../bsdinstall-final-confirmation.png | Bin 0 -> 10844 bytes .../bsdinstall-final-modification-shell.png | Bin 0 -> 8105 bytes .../bsdinstall-finalconfiguration.png | Bin 0 -> 14367 bytes .../bsdinstall_files/bsdinstall-hardening.png | Bin 0 -> 15265 bytes .../bsdinstall_files/bsdinstall-keymap-10.png | Bin 0 -> 17396 bytes .../bsdinstall-keymap-loading.png | Bin 0 -> 5213 bytes .../bsdinstall-keymap-testing.png | Bin 0 -> 7789 bytes .../bsdinstall_files/bsdinstall-mainexit.png | Bin 0 -> 7156 bytes .../bsdinstall-netinstall-files.png | Bin 0 -> 7932 bytes .../bsdinstall-netinstall-mirrorselect.png | Bin 0 -> 22826 bytes .../bsdinstall-newboot-loader-menu.png | Bin 0 -> 120071 bytes .../bsdinstall-part-entire-part.png | Bin 0 -> 8252 bytes .../bsdinstall-part-guided-disk.png | Bin 0 -> 7721 bytes .../bsdinstall-part-manual-addpart.png | Bin 0 -> 10676 bytes .../bsdinstall-part-manual-create.png | Bin 0 -> 8041 bytes .../bsdinstall-part-manual-partscheme.png | Bin 0 -> 9845 bytes .../bsdinstall-part-review.png | Bin 0 -> 9695 bytes .../bsdinstall-post-root-passwd.png | Bin 0 -> 5446 bytes .../bsdinstall-timezone-confirm.png | Bin 0 -> 5699 bytes .../bsdinstall-timezone-country.png | Bin 0 -> 11452 bytes .../bsdinstall-timezone-date.png | Bin 0 -> 6128 bytes .../bsdinstall-timezone-region.png | Bin 0 -> 8694 bytes .../bsdinstall-timezone-time.png | Bin 0 -> 5907 bytes .../bsdinstall-timezone-zone.png | Bin 0 -> 7310 bytes .../bsdinstall-ufs-warning.png | Bin 0 -> 7715 bytes .../bsdinstall-zfs-disk_info.png | Bin 0 -> 15786 bytes .../bsdinstall-zfs-disk_select.png | Bin 0 -> 7142 bytes .../bsdinstall-zfs-geli_password.png | Bin 0 -> 8343 bytes .../bsdinstall-zfs-init-encription.png | Bin 0 -> 6456 bytes .../bsdinstall_files/bsdinstall-zfs-menu.png | Bin 0 -> 13254 bytes .../bsdinstall-zfs-partmenu.png | Bin 0 -> 10367 bytes .../bsdinstall-zfs-pool-name.png | Bin 0 -> 6541 bytes .../bsdinstall-zfs-rescan-devices.png | Bin 0 -> 5600 bytes .../bsdinstall-zfs-swap-amount.png | Bin 0 -> 7462 bytes .../bsdinstall-zfs-vdev_invalid.png | Bin 0 -> 7370 bytes .../bsdinstall-zfs-vdev_type.png | Bin 0 -> 11919 bytes .../bsdinstall-zfs-warning.png | Bin 0 -> 7816 bytes .../bsdinstall_files/copy-clipboard.min.js | 1 + .../bsdinstall_files/font-awesome-min.css | 5 + local/freebsd/bsdinstall_files/language.png | Bin 0 -> 4772 bytes local/freebsd/bsdinstall_files/main.min.css | 1 + local/freebsd/bsdinstall_files/search.min.js | 1 + .../bsdinstall_files/theme-chooser.min.js | 1 + 572 files changed, 100413 insertions(+), 1 deletion(-) create mode 100644 local/UEFI/edk2-rk3588-master/.github/workflows/build.yml create mode 100644 local/UEFI/edk2-rk3588-master/.github/workflows/nightly.yml create mode 100644 local/UEFI/edk2-rk3588-master/.github/workflows/release.yml create mode 100644 local/UEFI/edk2-rk3588-master/.gitignore create mode 100644 local/UEFI/edk2-rk3588-master/.gitmodules create mode 100644 local/UEFI/edk2-rk3588-master/README.md create mode 100755 local/UEFI/edk2-rk3588-master/build.sh create mode 100644 local/UEFI/edk2-rk3588-master/configs/RK3588.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/aio-3588q.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/blade3.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/edge2.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/fydetab-duo.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/h88k.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/indiedroid-nova.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/itx-3588j.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/nanopc-t6.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/nanopi-r6c.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/nanopi-r6s.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/orangepi-5.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/orangepi-5plus.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/r58-mini.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/r58x.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/roc-rk3588s-pc.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/rock-5-itx.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/rock-5a.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/rock-5b.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/rock-5bplus.conf create mode 100644 local/UEFI/edk2-rk3588-master/configs/station-m3.conf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/README.md create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/itx-3588j.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blade3-v101-linux.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-edge-v12-linux.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-minipc-linux.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-firefly-aio-3588q.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-hinlink-h88k.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-nanopc-t6.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-orangepi-5-plus.dtb create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5-itx.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5b-plus.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5b.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-9tripod-linux.dtb create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-fydetab-duo.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-khadas-edge2.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6c.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6s.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-orangepi-5.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-rock-5a.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/roc-rk3588s-pc.dtb create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLibPcaDepex.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/CsotDsiPanel.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Include/Protocol/KhadasMcu.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/KhadasPkg.dec create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/AcpiTables.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/AcpiTables.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/Dsdt.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.Modules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.bmp create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.idf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/LogoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/StationM3/StationM3.dsc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.uni create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.uni create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputBlt.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Descriptor.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/Crc32Table.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvCompactModules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainAprioriDxe.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainModules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvRules.fdf.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AcpiNextLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AnalogixDpLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/BaseVariableLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/CruLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DrmModes.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwHdmiQpLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwcSdhciPlatformLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Fspi.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/HalDef.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/MediaBusFormat.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/OtpLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/PWMLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RK806.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkAtagsLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkSdmmcPlatformLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipDisplayLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipPlatformLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SdramLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Snor.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiMem.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Vop2Regs.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dp_helper.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dsc.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_mipi_dsi.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/errno.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/mipi_display.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/uboot-env.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/DpPhy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2c.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2cDemo.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/NorFlashProtocol.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/OhciDeviceProtocol.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Pca9555.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Rk860xRegulator.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipConnectorProtocol.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipCrtcProtocol.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipDsiPanel.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipI2cMasterProtocol.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/Variable.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpReg.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptx.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptxHdmi.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dp_helper.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dsc.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_mipi_dsi.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/samsung_mipi_dcphy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLibCommon.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlPrivateLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/source.txt create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Cpu.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dbg2.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dma.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/DsdtCommon.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Emmc.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Es8388.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Fadt.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac0.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac1.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gpio.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gtdt.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2c.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2s.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Madt.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Mcfg.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pcie.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pptt.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/RK3588PcieIort.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sata.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Scmi.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sdhc.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spcr.aslc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spi.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Uart.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb2Host.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host0.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host1.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host2.asl create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/EthernetPhy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/MotorcommPhy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/RealtekPhy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeFormSetGuid.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.uni create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.vfr create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhy.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/errno.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/uboot-env.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/AcpiTables.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/GpioLib.h create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Pcie30PhyLib.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Mem.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Pcie.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588RegsPeri.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/ScmiDefinitions.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Soc.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/VarStoreData.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.c create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/PlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Helper.S create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Mem.c create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.c create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.h create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeLib.c create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/Rk3588PciHostBridgeLib.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/PciSegmentLib.c create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.inf create mode 100755 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.uni create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon/RK3588CruLib.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.dec create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Rockchip.dsc.inc create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RockchipPkg.dec create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/ComponentName.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.h create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/EmmcDevice.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/SdDevice.c create mode 100644 local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/PlatformDwMmc.h create mode 100755 local/UEFI/edk2-rk3588-master/misc/extractbl31.py create mode 100755 local/UEFI/edk2-rk3588-master/misc/repack.sh create mode 100644 local/UEFI/edk2-rk3588-master/misc/rk3588_spi_nor_gpt.img create mode 100644 local/UEFI/edk2-rk3588-master/misc/rk3588_spi_nor_gpt.txt create mode 100755 local/UEFI/edk2-rk3588-master/misc/rk3588_spl.dtb create mode 100644 local/UEFI/edk2-rk3588-master/misc/rk3588_spl_v1.12.bin create mode 100755 local/UEFI/edk2-rk3588-master/misc/tools/aarch64/mkimage create mode 100755 local/UEFI/edk2-rk3588-master/misc/tools/x86_64/mkimage create mode 100644 local/UEFI/edk2-rk3588-master/misc/uefi_rk3588.its create mode 100644 local/UEFI/orangepi-5plus_UEFI_Release_v0.11.2.img create mode 100644 local/freebsd/bsdinstall.html create mode 100644 local/freebsd/bsdinstall_files/FreeBSD-colors.svg create mode 100644 local/freebsd/bsdinstall_files/FreeBSD-monochromatic.svg create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-adduser1.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-adduser2.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-adduser3.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-boot-options-menu.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-choose-mode.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-config-components.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-config-hostname.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-config-services.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-ipv4-dhcp.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-ipv4-static.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-ipv4.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-ipv6-static.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-ipv6.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface-slaac.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-interface.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-network-ipv4-dns.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-wireless-accesspoints.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-wireless-scan.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-configure-wireless-wpa2setup.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-distfile-extracting.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-distfile-fetching.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-distfile-verifying.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-final-confirmation.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-final-modification-shell.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-finalconfiguration.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-hardening.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-keymap-10.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-keymap-loading.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-keymap-testing.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-mainexit.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-netinstall-files.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-netinstall-mirrorselect.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-newboot-loader-menu.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-entire-part.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-guided-disk.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-manual-addpart.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-manual-create.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-manual-partscheme.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-part-review.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-post-root-passwd.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-confirm.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-country.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-date.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-region.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-time.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-timezone-zone.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-ufs-warning.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-disk_info.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-disk_select.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-geli_password.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-init-encription.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-menu.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-partmenu.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-pool-name.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-rescan-devices.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-swap-amount.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-vdev_invalid.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-vdev_type.png create mode 100644 local/freebsd/bsdinstall_files/bsdinstall-zfs-warning.png create mode 100644 local/freebsd/bsdinstall_files/copy-clipboard.min.js create mode 100644 local/freebsd/bsdinstall_files/font-awesome-min.css create mode 100644 local/freebsd/bsdinstall_files/language.png create mode 100644 local/freebsd/bsdinstall_files/main.min.css create mode 100644 local/freebsd/bsdinstall_files/search.min.js create mode 100644 local/freebsd/bsdinstall_files/theme-chooser.min.js diff --git a/README.md b/README.md index 163e3d5..0fda7de 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,174 @@ # wirecat -fuck your phone - PDA based on OrangePi 5 Plus \ No newline at end of file +fuck your phone - PDA based on OrangePi 5 Plus + +## quick FAQ & overview + +>what the fuck is this? + +wirecat is a project i thought about for a long time - building your own portable device with all the functionality you need, tailored to your specific needs, and of course - the one that looks cool. + +> why wirecat? + +just a cool name. also, the amount of interface ports on opi5+ is sure impressive for a SBC, so it's kinda fitting. + +> why FreeBSD? + +the only OS i could find that would satisfy my needs of running properly on this piece of hardware and not being a piece of dead shit. none of the linux distros would do, since unfortunately as of 11/2024 there is not a single systemd-free distro that works properly. trust me, i've tried several(void, alpine, artix, gentoo, etc.) + +> what kind of functionality does it have? + +it is a fully capable ARM computer running a UNIX-compliant system - the only limit is your schizo level. but in short - it can do everything what a smartphone/laptop can do, taking desktop functionality as granted - connect and utilize cellular network, work with RFID/NFC devices, even used as an electronic recon system(if you have an SDR)! sounds cool, doesn't it? + +> SDR? what is that? + +software-defined radio. an auxillary device that can be used to discover the electromagnetic(radio) spectrum around it, receive or transmit on certain radio frequency with certain types of modulation, depending on your SDR specs. for my own i used RTL-SDRv3, since it's cheap and i've had it for years. a reasonable choice for beginners in RF field, though better alternatives exist as of now, but those have a higher price tag(HackRF One, for example). + +> specs? + +OrangePi 5 Plus: +- CPU: octa-core Rockchip RK3588 64-bit ARM processor(aarch64, 4x Cortex-A55 + 4x Cortex-A72, upo to 2.4GHz) +- RAM: dual-channel 16GB LPDDR4X* +- GPU: Mali-610 ARM +- storage: 1x NVME M.2 MSI Spectrum Z390 SSD 240GB(system), 1x eMMC 256GB(secondary storage) +- wireless: 1x RTL8862BE(PCIE+USB) wireless network adapter(Wi-Fi 6/BT 5 capable), 1x Sierra Wireless AIrprime EM7455 M.2 key cellular/GPS module with USB adapter +- ethernet: 2x Realtek 2.5Gbps Ethernet adapters +battery: +- cells: 6x Samsung INR18650-35E 18650 batteries, 3500mAh +- BMS: chinkshit 22,5W BMS, QuickCharge 3.0/4.0, 2x USB, 1x microUSB, 1x USB-C, 1x USB-C(charge only) +auxillary: +- cellular: Sierra Wireless Airprime EM7455, GSM/LTE/GPS, 1x SIM card slot, 3x U.FL male antenna connector +- RFID/NFC: RFID-RC522 module +- display: 5" FHD HDMI touchscreen display(many options, acquisition in progress) +- keyboard: mini-keyboard, wireless capable(many options, acquisition in progress) +software: +- operating system: FreeBSD 14.1-RELEASE aarch64 +- video drivers: Panfrost/drm-510 + +## walkthrough(WIP) + +walkthrough on how to assemble your own variation of wirecat is divided into following sections: +1. hardware assembly +2. OS installation +3. software installation(WIP) +4. chassis assembly(WIP) + +full list of parts and tools needed for building will be in the end of this document + +### hardware assembly + +BATTERY ASSEMBLY + +hardware required: +- 6x battery cells +- BMS board +- wiring(i recommend 16AWG) +- 18650 battery slots(any kind, just make sure they are connected in parallel) +tools required: +- soldering iron +- wire stripper/knife +- multimeter +- isolation tape +- two-side duct tape(optional) + +step-by-step: + +0. prepare the wiring, measure the length and strip the ends for soldering +1. connect the 18650 battery slots in parallel so you have a single 6-piece battery block +2. solder the positive and negative terminals according to their respective locations on the BMS board(marked by B+ and B- accordingly) +3. check connections with multimeter, then properly isolate the terminals with isolation nape or in any other suitable way(thermal glue, epoxy, etc.) +4. OPTIONAL: use two-way duct tape to secure the BMS board on the top/side of the battery block +5. this BMS plate has a thermal resistor, place it right on one of the battery cells and secure with tape +6. insert the battery cells +7. put the battery assembly to charge + +congrats! the battery block is ready! + +ORANGEPI 5 PLUS + +hardware required: +- OrangePi 5 Plus +- eMMC chip +- cooler/radiator kit +- M.2 SSD +tools required: +- screwdriver + +>>note: i know 99% of people can manage this without any instructions, but anyway +step-by-step: + +0. prepare all your stuff, watch out for small components getting lost! +1. unpack the M.2 SSD, install it just like any other one in the back M.2 2280 slot +2. unpack the eMMC, install into the designated slot +3. unpack the coller/radiator kit, remove the back cover to expose the thermal sticky pads, install to their respective places + +probably the easiest part, nonetheless - way to go! + +RFID/NFC MODULE WIRING(WIP) + +### OS installation + +depending on your OS, instructions may not be suitable for your system of choice. only FreeBSd installation will be covered here. known other operating systems with some level of Orange Pi 5 Plus support: +- Orange Pi OS(full, vendor-provided) +- Armbian(partial) +- BredOS(full) +- Armtix(barely) + +tools required: +- flashing/burning software(dd/Rufus/balenaEtcher/etc.) +- SD card + +PART 1 - UEFI INSTALLATION VIA JUMPER OS + +0. prepare your tools +1. pick any OS image you want, vendor-provided ones are a good option +2. flash the image onto an SD card +3. insert the SD card and boot up Orange Pi 5 Plus +4. once logged in, follow [guide in this repo](https://github.com/edk2-porting/edk2-rk3588) to install UEFI firmware [local copy of guide and UEFI image](./local/UEFI) + +now you should have a working UEFI installed, after rebooting the I/O status light will blink blue instead of green + +PART 2 - FREEBSD INSTALLATION + +tools required: +- flashing/burning software(dd/Rufus/balenaEtcher/etc.) +- SD card or USB flash drive + +0. prepare your tools, download the OS image from [here](https://download.freebsd.org/releases/ISO-IMAGES/14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-memstick.img) +1. flash the image onto the storage device +2. insert the storage device into the SD card slot/USB port +3. power on the OrangePi 5 Plus, enter the BIOS +4. select the storage medium and boot +5. FreeBSD installation here is not really any different from any other platform, pretty intuitive as well, nonetheless i will leave [this guide](https://docs.freebsd.org/en/books/handbook/bsdinstall/) here [(local copy)](./local/freebsd/bsdinstall.html) + +NOTE: as of 11/2024, the current version of FreeBSD 14.1-RELEASE does not come with the drivers for wireless card, so for network connectivity you will need to use either an Ethernet cable or USB tethering via your smartphone until then + +congratulations, now you should have a working FreeBSD installation running! + +### software installation(WIP) + +### chassis assembly(WIP) + +## list of parts and tools(WIP) + +PARTS + +- OrangePi 5 Plus 16GB kit(32GB version is available for purchase as of 11/2024) - i recommend the option with the cooling/radiator kit, wireless card and 265GB eMMC card +- M.2 2280 SSD +- RFID-RC522 module +- Sierra Wireless Airprime EM7455 module with USB adapter +- RTL-SDRv3 software-defined radio +- 5" FHD HDMI touchscreen display +- 6x 18650 batteries - you can alter the battery assembly design to your needs, i just went full blast on this one +- 3x 2-piece parallel 18650 battery slots - you can get whatever combination you want, according to your battery aseembly configuration +- 16AWG wiring - you will probably need like 20cm of it at most, suit yourself :3 +- signal wires - can find those almost anywhere +- HDMI cable +- USB-C cable + +TOOLS +- soldering iron and soldering neccessities(flux, solder, cleaning kit, etc.) +- screwdriver +- wire stripper +- isolation tape +- two-way duct tape(optional) \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/.github/workflows/build.yml b/local/UEFI/edk2-rk3588-master/.github/workflows/build.yml new file mode 100644 index 0000000..65a5fa2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/.github/workflows/build.yml @@ -0,0 +1,106 @@ +name: Build +on: + push: + paths-ignore: + - '**.md' + branches: + - master + pull_request: + paths-ignore: + - '**.md' + branches: + - master + workflow_call: + inputs: + build-configs: + type: string + required: true + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + PLATFORM: + - rock-5b + - rock-5a + - rock-5-itx + - orangepi-5 + - orangepi-5plus + - indiedroid-nova + - fydetab-duo + - roc-rk3588s-pc + - itx-3588j + - aio-3588q + - station-m3 + - r58x + - r58-mini + - edge2 + - nanopi-r6c + - nanopi-r6s + - nanopc-t6 + - blade3 + - h88k + CONFIGURATION: ${{ fromJSON(format('[{0}]', inputs.build-configs || '"Debug"')) }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install dependencies + shell: bash + run: | + sudo apt-get update && \ + sudo apt-get install -y \ + acpica-tools \ + binutils-aarch64-linux-gnu \ + build-essential \ + device-tree-compiler \ + gettext \ + git \ + gcc-aarch64-linux-gnu \ + libc6-dev-arm64-cross \ + python3 \ + python3-pyelftools + + - name: Get version tag + id: get_version_tag + shell: bash + run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT + + - name: Set up Secure Boot default keys + run: | + mkdir keys + # We don't really need a usable PK, so just generate a public key for it and discard the private key + openssl req -new -x509 -newkey rsa:2048 -subj "/CN=Rockchip Platform Key/" -keyout /dev/null -outform DER -out keys/pk.cer -days 7300 -nodes -sha256 + curl -L https://go.microsoft.com/fwlink/?LinkId=321185 -o keys/ms_kek.cer + curl -L https://go.microsoft.com/fwlink/?linkid=321192 -o keys/ms_db1.cer + curl -L https://go.microsoft.com/fwlink/?linkid=321194 -o keys/ms_db2.cer + curl -L https://uefi.org/sites/default/files/resources/dbxupdate_arm64.bin -o keys/arm64_dbx.bin + + - name: Build platform + shell: bash + run: | + export EDK2_SECUREBOOT_FLAGS=" \ + -D DEFAULT_KEYS=TRUE \ + -D PK_DEFAULT_FILE=keys/pk.cer \ + -D KEK_DEFAULT_FILE1=keys/ms_kek.cer \ + -D DB_DEFAULT_FILE1=keys/ms_db1.cer \ + -D DB_DEFAULT_FILE2=keys/ms_db2.cer \ + -D DBX_DEFAULT_FILE1=keys/arm64_dbx.bin \ + -D SECURE_BOOT_ENABLE=TRUE" + + export EDK2_BUILD_FLAGS=" \ + ${EDK2_SECUREBOOT_FLAGS}" + + ./build.sh --device ${{matrix.PLATFORM}} --release ${{matrix.CONFIGURATION}} --edk2-flags "${EDK2_BUILD_FLAGS}" + mv RK3588_NOR_FLASH.img ${{matrix.PLATFORM}}_UEFI_${{matrix.CONFIGURATION}}_${{steps.get_version_tag.outputs.version}}.img + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{matrix.PLATFORM}} UEFI ${{matrix.CONFIGURATION}} image + path: ./*.img + if-no-files-found: error diff --git a/local/UEFI/edk2-rk3588-master/.github/workflows/nightly.yml b/local/UEFI/edk2-rk3588-master/.github/workflows/nightly.yml new file mode 100644 index 0000000..ec78c82 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/.github/workflows/nightly.yml @@ -0,0 +1,41 @@ +name: Nightly +run-name: Nightly build +on: + schedule: + - cron: "0 0 * * *" + +jobs: + prepare: + runs-on: ubuntu-latest + permissions: + actions: write + steps: + - name: Delete previous cancelled runs + uses: Mattraks/delete-workflow-runs@v2 + with: + retain_days: 0 + keep_minimum_runs: 0 + delete_workflow_pattern: ${{ github.workflow }} + delete_run_by_conclusion_pattern: cancelled + + - name: Check for new commits + id: check-new-commits + uses: adriangl/check-new-commits-action@v1 + with: + seconds: 86400 # One day in seconds + branch: 'master' + + - name: Cancel action if no new commits + if: ${{ steps.check-new-commits.outputs.has-new-commits != 'true' }} + uses: andymckay/cancel-action@0.3 + + - name: Wait for cancellation + if: ${{ steps.check-new-commits.outputs.has-new-commits != 'true' }} + shell: bash + run: while true; do echo "Waiting for job to be cancelled"; sleep 5; done + + build_for_nightly: + needs: prepare + uses: ./.github/workflows/build.yml + with: + build-configs: '"Debug", "Release"' diff --git a/local/UEFI/edk2-rk3588-master/.github/workflows/release.yml b/local/UEFI/edk2-rk3588-master/.github/workflows/release.yml new file mode 100644 index 0000000..a37dbc4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Release +on: + push: + tags: + - '*' + +jobs: + build_for_release: + uses: ./.github/workflows/build.yml + with: + build-configs: '"Debug", "Release"' + + release: + runs-on: ubuntu-latest + needs: build_for_release + permissions: + contents: write + steps: + - name: Download all workflow run artifacts + uses: actions/download-artifact@v4 + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + draft: true + prerelease: false + files: "*/*Release*.img" + fail_on_unmatched_files: true diff --git a/local/UEFI/edk2-rk3588-master/.gitignore b/local/UEFI/edk2-rk3588-master/.gitignore new file mode 100644 index 0000000..d805189 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/.gitignore @@ -0,0 +1,13 @@ +boot-*.img +uefi-*.img +uefi-*.img.gz +workspace +*.dll +ramdisk +.cache +.vscode +*.dts +*.swp +*.rej +*.orig +*_FLASH.img diff --git a/local/UEFI/edk2-rk3588-master/.gitmodules b/local/UEFI/edk2-rk3588-master/.gitmodules new file mode 100644 index 0000000..be3edcc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/.gitmodules @@ -0,0 +1,16 @@ +[submodule "edk2"] + path = edk2 + url = https://github.com/tianocore/edk2.git +[submodule "edk2-non-osi"] + path = edk2-non-osi + url = https://github.com/tianocore/edk2-non-osi.git +[submodule "edk2-platforms"] + path = edk2-platforms + url = https://github.com/tianocore/edk2-platforms.git +[submodule "misc/rkbin"] + path = misc/rkbin + url = https://github.com/rockchip-linux/rkbin.git +[submodule "arm-trusted-firmware"] + path = arm-trusted-firmware + url = https://github.com/worproject/arm-trusted-firmware + branch = rk3588 diff --git a/local/UEFI/edk2-rk3588-master/README.md b/local/UEFI/edk2-rk3588-master/README.md new file mode 100644 index 0000000..49edc63 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/README.md @@ -0,0 +1,376 @@ +# EDK2 UEFI firmware for Rockchip RK3588 platforms +This repository contains an UEFI firmware implementation based on EDK2 for various RK3588 boards. + +# Supported platforms +- [Radxa ROCK 5B](https://radxa.com/products/rock5/5b/) +- [Radxa ROCK 5A](https://radxa.com/products/rock5/5a/) +- [Radxa ROCK 5 ITX](https://radxa.com/products/rock5/5itx/) +- [Orange Pi 5](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5.html) +- [Orange Pi 5 Plus](http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5-plus.html) +- [ameriDroid Indiedroid Nova](https://indiedroid.us) +- [Fydetab Duo](https://fydetabduo.com/) +- [Firefly AIO-3588Q](https://en.t-firefly.com/product/industry/aio3588q) +- [Firefly ITX-3588J](https://en.t-firefly.com/product/industry/itx3588j) +- [Firefly ROC-RK3588S-PC](https://en.t-firefly.com/product/industry/rocrk3588spc) +- [StationPC Station M3](https://www.stationpc.com/product/stationm3) +- [Mekotronics R58X](https://www.mekotronics.com/h-pd-75.html) +- [Mekotronics R58 Mini](https://www.mekotronics.com/h-pd-76.html) +- [Khadas Edge2](https://www.khadas.com/edge2) +- [Mixtile Blade 3](https://www.mixtile.com/blade-3) +- [FriendlyELEC NanoPC T6](https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T6) +- [FriendlyELEC NanoPi R6C](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R6C) +- [FriendlyELEC NanoPi R6S](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R6S) +- [Hinlink H88K](http://www.hinlink.com) + +# Supported OSes +## In ACPI mode +| OS | Version | Tested/supported hardware | Notes | +| --- | --- | --- | --- | +| Windows | 11 | [Status](https://github.com/worproject/Rockchip-Windows-Drivers#hardware-support-status) || +| NetBSD | 10 | Display, UART, USB, PCIe (incl. NVME), SATA, eMMC, GMAC Ethernet || +| VMware ESXi Arm Fling | >= 1.12 | Display, USB | * PCIe devices will hang at boot, need to disable in settings or leave the ports empty.
* GMAC Ethernet gets detected but does not work. | +| Linux | tested Ubuntu 22.04, kernel 5.15.0-75-generic | Display, UART, USB, PCIe (incl. NVME & Ethernet), SATA | For full hardware functionality, use a kernel with RK3588 support and switch to Device Tree mode. | + +> [!NOTE] +> ACPI support is only being developed and tested against Windows. There are no plans to further improve functionality for other OSes. Consider using Device Tree instead (where applicable, for instance Linux). + +## In Device Tree mode +| OS | Version | Tested/supported hardware | Notes | +| --- | --- | --- | --- | +| Rockchip SDK Linux | 5.10 legacy, tested with [Armbian rk3588-live-iso](https://github.com/amazingfate/rk3588-live-iso) | Platform-dependent, most peripherals work. | If using a different kernel, see [Device Tree configuration](#device-tree-configuration). | + +# Supported peripherals in UEFI + +> [!NOTE] +> Applicable to all platforms unless otherwise noted. +> +> Only devices relevant to the firmware itself (not OS) are listed below. + +| Device | Status | Notes | +| --- | --- | --- | +| USB 3 / 2.0 / 1.1 | 🟢 Working | Host-mode only, USB 3 devices connected to a Type-C port only work in one orientation. | +| PCIe 3.0 (RK3588) | 🟢 Working | No bifurcation support | +| PCIe 2.1 | 🟢 Working | | +| SATA | 🟢 Working | | +| SD/eMMC | 🟢 Working | | +| HDMI output | 🟡 Partial | Single display with mode limited at 1080p 60 Hz | +| DisplayPort output (USB-C) | 🟡 Partial | Mode fixed at 1080p 60 Hz, only works in one orientation of the Type-C port. Some displays may not work regardless. | +| eDP output | 🟡 Partial | Disabled, requires manual configuration depending on the platform and panel. | +| DSI output | 🟢 Working | Only enabled on Fydetab Duo. Requires manual configuration depending on the platform and panel. | +| GMAC Ethernet | 🔴 Not working | Only brought-up for OS usage | +| Realtek PCIe Ethernet | 🟢 Working | Some platforms don't have MAC addresses set, networking may not work in that case. | +| UART | 🟢 Working | UART2 console available at 1500000 baud rate | +| GPIO | 🟡 Partial | Only read, write and alt function supported | +| I2C | 🟢 Working | | +| SPI | 🟢 Working | | +| PWM | 🟢 Working | | +| SPI NOR Flash | 🟢 Working | | +| HYM8563 real-time clock | 🟢 Working | | +| RNG | 🟢 Working | | +| Cooling fan | 🟢 Working | Supported on most platforms. Fan connector where present, otherwise available at the GPIO header for 3-pin PWM fans (do *not* connect 2-pin fans there!):
* Orange Pi 5: `GPIO4_B2`
* Indiedroid Nova: `GPIO4_B4` | +| Status LED | 🟢 Working | | +| Voltage regulators (RK806, RK860) | 🟢 Working | | +| FUSB302 USB Type-C Controller | 🔴 Not working | Required for PD negotiation and connector orientation switching | + +# Getting started +## 1. Requirements +* One of the [supported devices](#supported-platforms). +* Storage for the firmware: SPI NOR flash (included with some devices), SD card or eMMC. +* Quality power supply that can provide at least 15 W. Depending on the peripherals you use, more may be needed. + + Note: on Mixtile Blade 3, a fixed voltage *higher than* 5V must be supplied. The board cannot power any external peripherals if the input voltage is just 5V. USB-PD negotiation is not supported by firmware. +* HDMI or DisplayPort (USB-C) screen capable of at least 1080p 60Hz. +* Optionally, if display is not available or for debugging purposes, an UART adapter capable of 1500000 baud rate (e.g. USB CH340, CP2104). + +## 2. Download the firmware image +The latest version can be obtained from . + +If your platform is not yet supported, using an image meant for another device is **not** recommended. Although they are generally similar, voltage setup can happen to be different and you may risk damaging the board. External peripherals are unlikely to work either. + +## 3. Flash the firmware +UEFI can be flashed to either a SPI NOR flash, SD card or eMMC module: +* For removable SD or eMMC (easiest), you can simply use balenaEtcher, RPi Imager or dd. +* For SPI NOR or soldered eMMC, instructions can be found at: . + + In short, you can flash the image from Linux booted on the device or by using RKDevTool on another computer. The latter requires entering Maskrom mode on the device. The way to do this slightly varies across platforms, refer to your vendor documentation. + +**Warning:** these operations will erase data on the storage device. Make a backup first! + +If you wish to have both UEFI and an OS on the same SD or eMMC device: flash UEFI first, then create any additional partitions without touching the first, reserved one. Steps for updating the firmware in this case can be found [here](#updating-the-firmware). + +Note: Using SPI NOR (if present) is recommeded, as it leaves the other storage options free for other purposes. Additionally, SD/eMMC will limit the firmware's ability to access its own storage (variable store) when an OS is running. This feature is mostly used by OS installers to create the boot menu options, it is not mandatory. + +## 4. Connect peripherals and power on the device +If the flashing process has been done correctly, you should see the status LED blinking (if present), and shortly after, the platform's boot logo with a progress bar at the bottom on the connected display. + +At this stage, you can press Esc to enter the firmware setup, F1 to launch the UEFI Shell, or, provided you also have an UEFI bootloader/app on a storage device, you can let the system automatically run that, which is the default behavior if no action is taken. + +Check the [Supported OSes](#supported-oses) and [Supported peripherals in UEFI](#supported-peripherals-in-uefi) sections to see what's currently possible with this firmware. + +Also check the configuration options described below, some of which may need to be changed depending on the OS used. + +If you experience any issues, please see the [Troubleshooting](#troubleshooting) section. + +# Configuration settings +The UEFI provides a few configuration options, like CPU frequency, PCIe/SATA selection for an M.2 port, fan control, etc. These can be viewed and changed using the UI configuration menu (under `Device Manager` -> `Rockchip Platform Configuration`). + +Configuration through the user interface is fairly straightforward and help/navigation information is provided around the menus. + +## Tips +* CPU clocks are set to 816 MHz (boot default) on platforms without a cooling fan included. If you have adequate cooling, go to the configuration menu -> `CPU Performance` and set all Cluster Presets to `Maximum`. + +## Device Tree configuration +For rich Linux support, it is recommended to enable Device Tree mode. You can do so by going to the configuration menu -> `ACPI / Device Tree` and setting `Config Table Mode` to `Device Tree`. + +By default, the firmware installs a [DTB compatible with (most) Rockchip SDK Linux 5.10 legacy kernel variants](https://github.com/edk2-porting/edk2-rk3588/tree/master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree). + +### Custom Device Tree Blob (DTB) override and overlays +It is also possible to provide a custom DTB and overlays. To enable this, go to the configuration menu -> `ACPI / Device Tree` and set `Support DTB override & overlays` to `Enabled`. + +The firmware will now look for overrides in the partition of a selected boot option / OS loader. In most cases this will be the first FAT32 EFI System Partition. + +* The base DTB must be located at `\dtb\base\.dtb`. + +* The overlays can be placed in: + * `\dtb\overlays` - will be applied first, regardless of the platform. + * `\dtb\overlays\` - will be applied only to the specified platform. + + and must have the `.dtbo` extension. + +The paths above are relative to the root of the file system. That is, the `dtb` directory must not be placed in a sub-directory. + +`` can be: +| Name | Platform | +| --------------------------------------- | ----------------------------- | +| `rk3588-rock-5b` | ROCK 5B | +| `rk3588s-rock-5a` | ROCK 5A | +| `rk3588-rock-5-itx` | ROCK 5 ITX | +| `rk3588s-orangepi-5` | Orange Pi 5 | +| `rk3588-orangepi-5-plus` | Orange Pi 5 Plus | +| `rk3588s-9tripod-linux` | Indiedroid Nova | +| `rk3588s-fydetab-duo` | Fydetab Duo | +| `rk3588-firefly-aio-3588q` | Firefly AIO-3588Q | +| `itx-3588j` | Firefly ITX-3588J | +| `roc-rk3588s-pc` | ROC-RK3588S-PC / Station M3 | +| `rk3588-blueberry-edge-v12-linux` | R58X (v1.2) | +| `rk3588-blueberry-minipc-linux` | R58 Mini | +| `rk3588s-khadas-edge2` | Edge2 | +| `rk3588-blade3-v101-linux` | Blade 3 | +| `rk3588-nanopc-t6` | NanoPC T6 | +| `rk3588s-nanopi-r6c` | NanoPi R6C | +| `rk3588s-nanopi-r6s` | NanoPi R6S | +| `rk3588-hinlink-h88k` | H88K | + +In the absence of a custom base DTB override, the overlays are applied on top of the firmware-provided DTB. + +The firmware applies some fix-ups to its own DTB depending on the user settings (e.g. PCIe/SATA/USB selection, making SATA overlays redundant). These fix-ups are not applied to a custom base DTB - overlays must be used instead. + +If the application of an overlay fails (e.g. due to it being invalid in regard to the base DTB), all overlays are discarded, including those that got applied up to that point. + +If the custom base DTB is invalid, the firmware-provided one will be passed to the OS instead. + +This entire process is logged to the [serial console](#advanced-troubleshooting). There's currently no other way to see potential errors. + +# Updating the firmware +If the storage is only used for UEFI and nothing else, simply download the latest image and flash it as described in the [Getting started](#getting-started) section. + +If it is also used by an OS and has additional partitions, only part of the image needs to be applied. This can be done with the `dd` tool: +```bash +dd if=FIRMWARE.img of=DESTINATION bs=512 skip=64 seek=64 conv=notrunc +``` + +`FIRMWARE.img` is the firmware image for your platform. E.g. `edge2_UEFI_Release_v0.8.img`. + +`DESTINATION` is the destination storage that you wish to update the firmware on. E.g. `/dev/sdb`. + +Here we skip the GPT and copy the firmware starting at offset 0x8000 (`64` blocks * `512` bytes block size) until its end. See [Flash layout](#flash-layout) for more details. + +# Troubleshooting + +> [!IMPORTANT] +> First of all, make sure your device can only possibly load the UEFI firmware and nothing else. +> +> **U-Boot must not present on either SPI NOR, SD or eMMC, otherwise it could take precedence and cause hidden issues.** + +Below you can find some basic debugging information. If none of this helps, please see the [Advanced troubleshooting](#advanced-troubleshooting) section. + +## Meaning of the Status LED +If your device has an activity LED, the firmware will blink it in different patterns to indicate the current system status. + +1. Immediately after power on, the LED should start pulsing quickly. This indicates that the firmware is initializing. + +2. After initialization (usually takes less than 5 seconds), the LED will switch to a short pulsing every 2 seconds or so. This indicates that the firmware is ready and waiting for user action or the countdown to boot automatically. The display output should also be enabled at this point. + +3. When the firmware boots an OS and is about to exit, the LED will stop blinking. + +If the LED: +* does not light up after power on, this means the firmware has not managed to load up at all. +* gets stuck in either on or off state after blinking a few times and never recovers, something went wrong and the firmware has crashed or frozen. + + Note that it is only expected to stop as described at point 3) above. + +## Common issues +### Nothing shows up on the screen +Make sure you've flashed the firmware correctly and that it is the version designed for your device. In most cases this is the culprit. + +Assuming the firmware loads fine: +* The display must support a resolution of at least 1080p at 60 Hz. +* If you're using HDMI and the system has two ports, only one will work. Try both. +* If you're using USB-C to DisplayPort, only one orientation of the USB-C connector will work. Check both. + +If you are not able to get any display output, the only way to interact with UEFI is via the [serial console](#advanced-troubleshooting). + +### Configuration settings do not get saved +This has been observed in cases where U-Boot was still present on another boot device (SD, eMMC or SPI NOR). This is not a supported scenario. The solution is to unplug or erase devices that may have other firmware on them. + +What's happening: +1. Board loads U-Boot from a storage device that has higher priority (let's say eMMC). +2. That U-Boot image in turn loads UEFI and its settings from another device with lower priority (let's say SD). +3. UEFI cannot accurately determine to which device it belongs. The parameter used to verify this points to eMMC (U-Boot), while UEFI actually got loaded from SD. +4. Consequently, UEFI mistakenly saves the user settings to eMMC. On reboot, U-Boot loads UEFI and the original/unchanged settings from SD and the cycle repeats. + +### USB 3 devices do not work +* Try a different port. +* If you're using USB-C, 3.0 devices will only work in one orientation of the connector. Check both. +* Make sure the power supply and cable are good. + +### Networking does not work +* Only Realtek PCIe and USB controllers are supported. Native Gigabit provided by RK3588 isn't. + +* Some boards with Realtek NICs do not have a MAC address set at factory and will show-up as being all zeros in UEFI, possibly preventing the adapter from obtaining an IP address. + + You can easily fix this by writing the MAC address manually: + + 1. Boot into Linux and open up a terminal. The commands below apply to Armbian with legacy kernel. + + 2. Install the headers for your kernel version: + ```bash + sudo apt install -y linux-headers-legacy-rk35xx + ``` + + 3. Clone Realtek PGTool and build the driver: + ```bash + git clone https://github.com/redchenjs/rtnicpg + cd rtnicpg + make + ``` + + 4. Unload all Realtek modules and load the driver built above: + ```bash + sudo rmmod pgdrv + sudo ./pgload.sh + ``` + Note: make sure there aren't any remaining Realtek modules loaded after this, except for the new `pgdrv`.
If you have `r8125` built-in, you might have to reboot with `initcall_blacklist=rtl8125_init_module` as a kernel parameter (in Grub). + + 5. Burn a MAC address into the eFuses: + + For only one NIC: + ```bash + sudo ./rtnicpg-aarch64-linux-gnu /efuse /nodeid 00E04C001234 + ``` + For two or more: + ```bash + sudo ./rtnicpg-aarch64-linux-gnu /efuse /# 1 /nodeid 00E04C001234 + sudo ./rtnicpg-aarch64-linux-gnu /efuse /# 2 /nodeid 00E04C001235 + ``` + `00E04C001234` is an example address. You can generate random and unique ones using: + + **Note:** the number of eFuses is limited, thus MAC addresses can only be changed a few times. + +## Advanced troubleshooting +The firmware will log detailed information to the serial console when using a debug version. See the [release notes](https://github.com/edk2-porting/edk2-rk3588/releases) for details on how to obtain this version. + +1. The debug image needs to be flashed in place of the existing one. + +2. Connect the **UART2** RX, TX and GND pins on your device (check vendor documentation) to the UART adapter on your other computer. + +3. Open up a serial terminal (`PuTTY` on Windows, `stty` on Linux) set to 1500000 baud rate and 8n1 (default). + +4. Power on the device. + +You should be able to see many debug messages being printed to the console. If that's not the case, double check the connections (swap RX/TX), make sure the adapter is functional and configured correctly. + +The logs should give an insight of what's going on. If you need help analyzing them, feel free to open an issue ticket. + +# Reporting issues +You can open issues related to UEFI at . + +Please include as many details as possible: expected behavior, what actually happens, steps to reproduce, [serial logs](#advanced-troubleshooting), etc. + +Also check the existing issues in case yours might be already reported. + +# Building +The firmware can only be built on Linux currently. For Windows use WSL. + +1. Install required packages: + + For Ubuntu/Debian: + ```bash + sudo apt install git gcc g++ build-essential gcc-aarch64-linux-gnu acpica-tools python3-pyelftools uuid-dev python-is-python3 device-tree-compiler + ``` + For Arch Linux: + ```bash + sudo pacman -Syu + sudo pacman -S git base-devel gcc dtc aarch64-linux-gnu-binutils aarch64-linux-gnu-gcc aarch64-linux-gnu-glibc python python-pyelftools iasl --needed + ``` + +2. Clone the repository: + ```bash + git clone https://github.com/edk2-porting/edk2-rk3588.git --recursive + cd edk2-rk3588 + ``` + +3. Build UEFI (ROCK 5B for example, check [list of platform configs](https://github.com/edk2-porting/edk2-rk3588/tree/master/configs)): + ```bash + ./build.sh --device rock-5b --release Release # (or Debug) + ``` + +If you get build errors, it is very likely that you're still missing some dependencies. The list of packages above is not complete and depending on the distro you may need to install additional ones. In most cases, looking up the error messages on the internet will point you at the right packages. + +# Notes + +## Flash layout +| Address | Size | Desc | File | +| ---------- | ---------- | --------------------- | ---------------------- | +| 0x00000000 | 0x00004400 | GPT Table | rk3588_spi_nor_gpt.img | +| 0x00008000 | | IDBlock | idblock.bin | +| 0x00100000 | 0x00500000 | BL33_AP_UEFI FV | ${DEVICE}_EFI.itb | +| 0x007C0000 | 0x00010000 | NV_VARIABLE_STORE | | +| 0x007D0000 | 0x00010000 | NV_FTW_WORKING | | +| 0x007E0000 | 0x00010000 | NV_FTW_SPARE | | + +The variable store is not included in the flash image, in order to prevent overwriting it and to maintain the user settings across updates. + +The firmware expects these exact offsets, do not change them. + +## Memory Map +| Address | Size | Desc | File | +| ---------- | --------- | --------------------- | ------------------- | +| 0x00040000 | | ATF | bl31_0x00040000.bin | +| 0x000f0000 | | ATF | bl31_0x000f0000.bin | +| 0x00200000 | 0x00500000 | UEFI FV | BL33_AP_UEFI.Fv | +| 0x007C0000 | 0x00010000 | NV_VARIABLE_STORE | | +| 0x007D0000 | 0x00010000 | NV_FTW_WORKING | | +| 0x007E0000 | 0x00010000 | NV_FTW_SPARE | | +| 0x08400000 | | OP-TEE | bl32.bin | +| 0xff100000 | | ATF (PMU_MEM) | bl31_0xff100000.bin | + +## Licenses +Most of the UEFI code is licensed under the default EDK2 license, which is [BSD-2-Clause-Patent](https://github.com/tianocore/edk2/blob/master/License.txt). + +Some non-critical components have been ported from Rockchip's U-Boot fork and are licensed as **GPL-2.0-or-later**: +* UsbDpPhy +* DwDpLib + +The files in `edk2-rockchip-non-osi` are licensed as **GPL-2.0-only**. + +The license for some of the blobs in the `misc/rkbin/` directory can be found at: . Note that it also contains binaries built from open-source projects such as U-Boot (SPL), Arm Trusted Firmware and OP-TEE, having a different license. + +## Community +* Hack w/ Rockchip Telegram: +* Windows on R Discord: + +## Credits & alternatives +This firmware is based on Rockchip's initial efforts at . + +For RK356x, check out the Quartz64-UEFI project at https://github.com/jaredmcneill/quartz64_uefi, from which we also reused some code. diff --git a/local/UEFI/edk2-rk3588-master/build.sh b/local/UEFI/edk2-rk3588-master/build.sh new file mode 100755 index 0000000..e472005 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/build.sh @@ -0,0 +1,252 @@ +#!/bin/bash + +function _help(){ + echo + echo "Build EDK2 for Rockchip RK3588 platforms." + echo + echo "Usage: build.sh [options]" + echo + echo "Options:" + echo " -d, --device DEV Build for DEV, or 'all'." + echo " -r, --release MODE Release mode for building, default is 'DEBUG', 'RELEASE' alternatively." + echo " -t, --toolchain TOOLCHAIN Set toolchain, default is 'GCC'." + echo " --open-tfa ENABLE Use open-source TF-A submodule. Default: ${OPEN_TFA}" + echo " -C, --clean Clean workspace and output." + echo " -D, --distclean Clean up all files that are not in repo." + echo " --tfa-flags \"FLAGS\" Flags appended to open TF-A build process." + echo " --edk2-flags \"FLAGS\" Flags appended to the EDK2 build process." + echo " -h, --help Show this help." + echo + exit "${1}" +} + +function _error() { echo "${@}" >&2; exit 1; } + +function _build_idblock() { + echo " => Building idblock.bin" + pushd ${WORKSPACE} + + FLASHFILES="FlashHead.bin FlashData.bin FlashBoot.bin" + rm -f rk35*_spl_loader_*.bin idblock.bin rk35*_ddr_*.bin rk35*_usbplug*.bin UsbHead.bin ${FLASHFILES} + + DDRBIN_RKBIN=$(grep '^FlashData' ${ROOTDIR}/misc/rkbin/RKBOOT/${MINIALL_INI} | cut -d = -f 2-) + SPL_RKBIN=$(grep '^FlashBoot' ${ROOTDIR}/misc/rkbin/RKBOOT/${MINIALL_INI} | cut -d = -f 2-) + + DDRBIN="${ROOTDIR}/misc/rkbin/${DDRBIN_RKBIN}" + + # + # SPL v1.13 has broken SD card support! + # Use v1.12 instead. + # + # SPL="${ROOTDIR}/misc/rkbin/${SPL_RKBIN}" + SPL="${ROOTDIR}/misc/rk3588_spl_v1.12.bin" + + # Create idblock.bin + ${ROOTDIR}/misc/tools/${MACHINE_TYPE}/mkimage -n rk3588 -T rksd -d ${DDRBIN}:${SPL} idblock.bin + + popd + echo " => idblock.bin build done" +} + +function _build_fit() { + echo " => Building FIT" + pushd ${WORKSPACE} + + BL31_RKBIN=$(grep '^PATH=.*_bl31_' ${ROOTDIR}/misc/rkbin/RKTRUST/${TRUST_INI} | cut -d = -f 2-) + BL32_RKBIN=$(grep '^PATH=.*_bl32_' ${ROOTDIR}/misc/rkbin/RKTRUST/${TRUST_INI} | cut -d = -f 2-) + + BL31="${ROOTDIR}/misc/rkbin/${BL31_RKBIN}" + BL32="${ROOTDIR}/misc/rkbin/${BL32_RKBIN}" + + if [ ${OPEN_TFA} == 1 ]; then + BL31="${ROOTDIR}/arm-trusted-firmware/build/${TFA_PLAT}/${RELEASE_TYPE,,}/bl31/bl31.elf" + fi + + rm -f bl31_0x*.bin ${WORKSPACE}/BL33_AP_UEFI.Fv ${SOC_L}_${DEVICE}_EFI.its + + ${ROOTDIR}/misc/extractbl31.py ${BL31} + if [ ! -f bl31_0x000f0000.bin ]; then + # Not used but FIT expects it. + touch bl31_0x000f0000.bin + fi + + cp ${BL32} ${WORKSPACE}/bl32.bin + cp ${ROOTDIR}/misc/${SOC_L}_spl.dtb ${WORKSPACE}/${DEVICE}.dtb + cp ${WORKSPACE}/Build/${PLATFORM_NAME}/${RELEASE_TYPE}_${TOOLCHAIN}/FV/BL33_AP_UEFI.Fv ${WORKSPACE}/ + cat ${ROOTDIR}/misc/uefi_${SOC_L}.its | sed "s,@DEVICE@,${DEVICE},g" > ${SOC_L}_${DEVICE}_EFI.its + ${ROOTDIR}/misc/tools/${MACHINE_TYPE}/mkimage -f ${SOC_L}_${DEVICE}_EFI.its -E ${DEVICE}_EFI.itb + + popd + echo " => FIT build done" +} + +function _pack_image() { + _build_idblock + _build_fit + + echo " => Building 8MB NOR FLASH IMAGE" + cp ${WORKSPACE}/Build/${PLATFORM_NAME}/${RELEASE_TYPE}_${TOOLCHAIN}/FV/NOR_FLASH_IMAGE.fd ${WORKSPACE}/RK3588_NOR_FLASH.img + + # GPT at 0x0, size:0x4400 + dd if=${ROOTDIR}/misc/rk3588_spi_nor_gpt.img of=${WORKSPACE}/RK3588_NOR_FLASH.img + # idblock at 0x8000 + dd if=${WORKSPACE}/idblock.bin of=${WORKSPACE}/RK3588_NOR_FLASH.img bs=1K seek=32 + # FIT Image at 0x100000 + dd if=${WORKSPACE}/${DEVICE}_EFI.itb of=${WORKSPACE}/RK3588_NOR_FLASH.img bs=1K seek=1024 + cp ${WORKSPACE}/RK3588_NOR_FLASH.img ${ROOTDIR}/ +} + +function _build(){ + local DEVICE="${1}"; shift + + # + # Grab platform parameters + # + if [ -f "configs/${DEVICE}.conf" ] + then source "configs/${DEVICE}.conf" + else _error "Device configuration not found" + fi + if [ -f "configs/${SOC}.conf" ] + then source "configs/${SOC}.conf" + else _error "SoC configuration not found" + fi + typeset -l SOC_L="$SOC" + + rm -f "${OUTDIR}/RK35*_NOR_FLASH.img" + + # + # Build TF-A + # + if [ ${OPEN_TFA} == 1 ]; then + pushd arm-trusted-firmware + + if [ ${RELEASE_TYPE} == "DEBUG" ]; then + DEBUG=1 + else + DEBUG=0 + fi + + make PLAT=${TFA_PLAT} DEBUG=${DEBUG} all ${TFA_FLAGS} + + popd + fi + + # + # Build EDK2 + # + [ -d "${WORKSPACE}/Conf" ] || mkdir -p "${WORKSPACE}/Conf" + + export GCC_AARCH64_PREFIX="${CROSS_COMPILE}" + export CLANG38_AARCH64_PREFIX="${CROSS_COMPILE}" + export PACKAGES_PATH="${ROOTDIR}/edk2:${ROOTDIR}/edk2-platforms:${ROOTDIR}/edk2-rockchip:${ROOTDIR}/edk2-rockchip-non-osi:${ROOTDIR}/edk2-non-osi:${ROOTDIR}" + + make -C "${ROOTDIR}/edk2/BaseTools" + source "${ROOTDIR}/edk2/edksetup.sh" + + build \ + -s \ + -n 0 \ + -a AARCH64 \ + -t "${TOOLCHAIN}" \ + -p "${ROOTDIR}/${DSC_FILE}" \ + -b "${RELEASE_TYPE}" \ + -D FIRMWARE_VER="${GIT_COMMIT}" \ + ${EDK2_FLAGS} + + # + # Compile final image + # + _pack_image + + echo "Build done: RK3588_NOR_FLASH.img" +} + +function _clean() { rm --one-file-system --recursive --force "${OUTDIR}"/workspace "${OUTDIR}"/RK3588_*.img; } +function _distclean() { if [ -d .git ]; then git clean -xdf; else _clean; fi; } + +# +# Default variables +# +typeset -l DEVICE +typeset -u RELEASE_TYPE +DEVICE="" +RELEASE_TYPE=DEBUG +TOOLCHAIN=GCC +OPEN_TFA=1 +TFA_FLAGS="" +EDK2_FLAGS="" +CLEAN=false +DISTCLEAN=false +OUTDIR="${PWD}" + +# +# Get options +# +OPTS=$(getopt -o "d:r:t:CDh" -l "device:,release:,toolchain:,open-tfa:,tfa-flags:,edk2-flags:,clean,distclean,help" -n build.sh -- "${@}") || _help $? +eval set -- "${OPTS}" +while true; do + case "${1}" in + -d|--device) DEVICE="${2}"; shift 2 ;; + -r|--release) RELEASE_TYPE="${2}"; shift 2 ;; + -t|--toolchain) TOOLCHAIN="${2}"; shift 2 ;; + --open-tfa) OPEN_TFA="${2}"; shift 2 ;; + --tfa-flags) TFA_FLAGS="${2}"; shift 2 ;; + --edk2-flags) EDK2_FLAGS="${2}"; shift 2 ;; + -C|--clean) CLEAN=true; shift ;; + -D|--distclean) DISTCLEAN=true; shift ;; + -h|--help) _help 0; shift ;; + --) shift; break ;; + *) break ;; + esac +done +if [[ -n "${@}" ]]; then + echo "Invalid additional arguments '${@}'" + _help 1 +fi + +if "${DISTCLEAN}"; then _distclean; exit "$?"; fi +if "${CLEAN}"; then _clean; exit "$?"; fi + +[ -z "${DEVICE}" ] && _help 1 +[ -f "configs/${DEVICE}.conf" ] || [ "${DEVICE}" == "all" ] || _error "Device configuration not found" + +# +# Get machine architecture +# +MACHINE_TYPE=$(uname -m) + +# Fix-up possible differences in reported arch +if [ ${MACHINE_TYPE} == 'arm64' ]; then + MACHINE_TYPE='aarch64' +elif [ ${MACHINE_TYPE} == 'amd64' ]; then + MACHINE_TYPE='x86_64' +fi + +if [ ${MACHINE_TYPE} != 'aarch64' ]; then + export CROSS_COMPILE="${CROSS_COMPILE:-aarch64-linux-gnu-}" +fi + +GIT_COMMIT="$(git describe --tags --always)" || GIT_COMMIT="unknown" + +export WORKSPACE="${OUTDIR}/workspace" +[ -d "${WORKSPACE}" ] || mkdir "${WORKSPACE}" + +ROOTDIR="$(realpath "$(dirname "$0")")" +cd "${ROOTDIR}" || exit 1 + +# Exit on first error +set -e + +if [ "${DEVICE}" == "all" ] +then + for i in configs/*.conf; do + DEV="$(basename "$i" .conf)" + if [ "${DEV}" != "RK3588" ] + then + echo "Building ${DEV}" + _build "${DEV}" + fi + done +else + _build "${DEVICE}" +fi diff --git a/local/UEFI/edk2-rk3588-master/configs/RK3588.conf b/local/UEFI/edk2-rk3588-master/configs/RK3588.conf new file mode 100644 index 0000000..9af38af --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/RK3588.conf @@ -0,0 +1,3 @@ +MINIALL_INI=RK3588MINIALL.ini +TRUST_INI=RK3588TRUST.ini +TFA_PLAT=rk3588_reference_pmic diff --git a/local/UEFI/edk2-rk3588-master/configs/aio-3588q.conf b/local/UEFI/edk2-rk3588-master/configs/aio-3588q.conf new file mode 100644 index 0000000..f394772 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/aio-3588q.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc +PLATFORM_NAME=AIO-3588Q +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/blade3.conf b/local/UEFI/edk2-rk3588-master/configs/blade3.conf new file mode 100644 index 0000000..aec306d --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/blade3.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc +PLATFORM_NAME=Blade3 +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/edge2.conf b/local/UEFI/edk2-rk3588-master/configs/edge2.conf new file mode 100644 index 0000000..46efa16 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/edge2.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc +PLATFORM_NAME=Edge2 +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/fydetab-duo.conf b/local/UEFI/edk2-rk3588-master/configs/fydetab-duo.conf new file mode 100644 index 0000000..07d32af --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/fydetab-duo.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc +PLATFORM_NAME=FydetabDuo +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/h88k.conf b/local/UEFI/edk2-rk3588-master/configs/h88k.conf new file mode 100644 index 0000000..cb71fdc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/h88k.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Hinlink/H88K/H88K.dsc +PLATFORM_NAME=H88K +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/indiedroid-nova.conf b/local/UEFI/edk2-rk3588-master/configs/indiedroid-nova.conf new file mode 100644 index 0000000..e625278 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/indiedroid-nova.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc +PLATFORM_NAME=IndiedroidNova +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/itx-3588j.conf b/local/UEFI/edk2-rk3588-master/configs/itx-3588j.conf new file mode 100644 index 0000000..f7c6aa9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/itx-3588j.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc +PLATFORM_NAME=ITX-3588J +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/nanopc-t6.conf b/local/UEFI/edk2-rk3588-master/configs/nanopc-t6.conf new file mode 100644 index 0000000..4661e0c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/nanopc-t6.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc +PLATFORM_NAME=NanoPC-T6 +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/nanopi-r6c.conf b/local/UEFI/edk2-rk3588-master/configs/nanopi-r6c.conf new file mode 100644 index 0000000..9901a4a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/nanopi-r6c.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc +PLATFORM_NAME=NanoPi-R6C +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/nanopi-r6s.conf b/local/UEFI/edk2-rk3588-master/configs/nanopi-r6s.conf new file mode 100644 index 0000000..428af0e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/nanopi-r6s.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc +PLATFORM_NAME=NanoPi-R6S +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/orangepi-5.conf b/local/UEFI/edk2-rk3588-master/configs/orangepi-5.conf new file mode 100644 index 0000000..d33b89b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/orangepi-5.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.dsc +PLATFORM_NAME=OrangePi5 +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/orangepi-5plus.conf b/local/UEFI/edk2-rk3588-master/configs/orangepi-5plus.conf new file mode 100644 index 0000000..10eaf0a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/orangepi-5plus.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc +PLATFORM_NAME=OrangePi5Plus +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/r58-mini.conf b/local/UEFI/edk2-rk3588-master/configs/r58-mini.conf new file mode 100644 index 0000000..d62060e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/r58-mini.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.dsc +PLATFORM_NAME=R58-Mini +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/r58x.conf b/local/UEFI/edk2-rk3588-master/configs/r58x.conf new file mode 100644 index 0000000..06fe1bb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/r58x.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Mekotronics/R58X/R58X.dsc +PLATFORM_NAME=R58X +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/roc-rk3588s-pc.conf b/local/UEFI/edk2-rk3588-master/configs/roc-rk3588s-pc.conf new file mode 100644 index 0000000..52ee539 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/roc-rk3588s-pc.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc +PLATFORM_NAME=ROC-RK3588S-PC +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/rock-5-itx.conf b/local/UEFI/edk2-rk3588-master/configs/rock-5-itx.conf new file mode 100644 index 0000000..56dbf4e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/rock-5-itx.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc +PLATFORM_NAME=ROCK5ITX +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/rock-5a.conf b/local/UEFI/edk2-rk3588-master/configs/rock-5a.conf new file mode 100644 index 0000000..60aed61 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/rock-5a.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.dsc +PLATFORM_NAME=ROCK5A +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/rock-5b.conf b/local/UEFI/edk2-rk3588-master/configs/rock-5b.conf new file mode 100644 index 0000000..cef4eb6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/rock-5b.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc +PLATFORM_NAME=ROCK5B +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/rock-5bplus.conf b/local/UEFI/edk2-rk3588-master/configs/rock-5bplus.conf new file mode 100644 index 0000000..4bdd94a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/rock-5bplus.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc +PLATFORM_NAME=ROCK5BPlus +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/configs/station-m3.conf b/local/UEFI/edk2-rk3588-master/configs/station-m3.conf new file mode 100644 index 0000000..232df39 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/configs/station-m3.conf @@ -0,0 +1,3 @@ +DSC_FILE=edk2-rockchip/Platform/StationPC/StationM3/StationM3.dsc +PLATFORM_NAME=StationM3 +SOC=RK3588 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/README.md b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/README.md new file mode 100644 index 0000000..716d477 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/README.md @@ -0,0 +1,20 @@ +# Rockchip Platform Device Trees +## Sources +* + * Updated to `rk-6.1-rkr1` branch, currently called `vendor` branch in armbian/build + +* roc-rk3588s-pc: + +* itx-3588j: + (note: in the dtb given here, the builtin bootargs in the source above were commented out + before building. Not sure if that was a necessary step - SS) + +* rk3588-firefly-aio-3588q: + +* rk3588-rock-5b-plus: + +* rk3588s-fydetab-duo: + (note: dtb taken from the `noble` branch which is based on the rockchip 6.1 rkr3 bsp kernel) + +## License +SPDX-License-Identifier: GPL-2.0-only diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/itx-3588j.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/itx-3588j.dtb new file mode 100644 index 0000000000000000000000000000000000000000..7b2e01690bf6c1a91833b6aa1d15e39753443293 GIT binary patch literal 168063 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%0DqS=z( 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blade3-v101-linux.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blade3-v101-linux.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c3e920acc6c034c67b35297fc24499edf1d5949a GIT binary patch literal 269831 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-edge-v12-linux.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-edge-v12-linux.dtb new file mode 100644 index 0000000000000000000000000000000000000000..0122b39377c9ee13e3480f5d6946cf42e5f0038f GIT binary patch literal 271643 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5b-plus.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..1a79c295a94e698ceb22ef920bad3195511e4d63 GIT binary patch literal 176048 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 z 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-9tripod-linux.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-9tripod-linux.dtb new file mode 100644 index 0000000000000000000000000000000000000000..cddc6e76b906f288ca6793b93a585d5ea840f24d GIT binary patch literal 241209 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

    (d&mBUV@Pb> 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 OUJ;dSC!aN)Z1#U%8_CuH literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-fydetab-duo.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-fydetab-duo.dtb new file mode 100755 index 0000000000000000000000000000000000000000..213d3a0ad83a7cbb2766afed28deffdf7da81f16 GIT binary patch literal 251158 zcmeEv37i~NoqttNjv+TWARtN;qJpH!%p@U+$67#CRM3dB9;*&L-JML6IhvWtBq-{D z7dPm7;IS?)=yHj83tmysmBST0R&ZGbb-i_QK?G&O|NH&D->Z6c^fi-!?w|MhRKM%@ ze)l`8y6U$1yMO0(e1AXB^EP-LXZ{lLVYv3iwFno&iASRRT9c0b`kL!N+{5(9aA{kq zzgk;0vTe<}4I4%aW5vFK%2=Vhr&JiI4sG9=gfIx$eg>|&xQNr{4?;TUFt8QMstjmcKqKUqceM{H;;> zTDSbdsC=C*Ux38>R+mSs!IpBRrwf5K1{do-Wb4+%>z1JI($$r*{>sQuWh~fI=`Mu; zp5@u~0=6J$XhC)1j3H=ez%aSma zxQ>?r=GCiDsa3XCEIWOU%7h=nl#(!XJK@;yOqf%WFcHfko>P-B^alqI?BnlTJz5#5 z76<5_j%fu4>nFncN?+vth7Z=C<AJt#v)E^b8BgB8PQ@=i={t~C&am%p%y8AY&#~@1wk{f) zLYzOab9Rb}Y%PvexU3R|P^XK)dVtuQJiYU`j1f>K`lfz2Szs-LJ#w3o zhP=75mXWuYBkioiQg(w)Jm52WDhluA+VIM4=V5L_ki9{7tUMe-9H-e?dYAb!n^qWW2<+ns~z5ZE$`y* z)zMnF(_fD=jzfHTTvPFzezrqs(Qo{F0NV!t{`G*5bpP1%e|MYwe<8-dSr>OXCMb3R z0AV^dxI{3tZi9BmOu|Qf_pd{SFRRX4oV)xlSsA1c8yVcLP?R0^^z3liUbX{ePTJwI zmZ4oce8tKjcHq9O7dyq_a%IHn6n_Kjh+Q!`%s$n%MQIQ8Ytmq7b!`1QVA~m6zY6%6 zKVh%^Sj%u@n=*XO${_y4{gykrnpNF&#@2S%blexUV}lz~{JRz~yMpQP-|n8E)F%J5 zm-tYPdxGM)!~MqY>Gy$s==%(<_JMZCBla2LU;O8>=fB;#`5TshS>KJ8tHaSay0M4W zoYtJS&nm&tSpS@ZH!B_bD)X)E#r_Sjk?)KTclB-^*|Hb*W8f$3ljPIpv-Zd2J$Yuq zRr1yZuiXx>dvfn?c_Sa>m3waLv>jf#CKtU9qEA+b3e}#`E))r#c}%o=Rzp|>(nq`8 zlZmL;AhqS>6Z-MLiGl>pZVNMAn%#A1-jt>pyRR}GIeY5Ryg5x%PQO)0)6(slIy7%_ zX%2566N93ktlLmp)9vj2aklF0;b8j$fLVq>{uaSR0b+0R6*nwrj9~o@J}>@88*ao! zc-q$O3rmoXd;qw6$A){WavM(IiGv4Ivv57d!EqYW48)0$I}bk=KYeF_g}8jWmdeL- zvArZ;?i~*OEcuMTrRAeOD2uP{5v63gm4$>!$->Y z9?X&^(m&;)yM50`h9!y;XJ#peBW02M8;B0PxwO~Tns*73xma)Ne^ttjr9?AS=8ZP zp5wpl3zq|sd>A^Ymk~dtBlWarSnu3NwC(qC>t!U3x1Xc+28ZEE$<*a(u8T8+C(cL2 z=i*e>>f+?H0HGWiIB{<##A)Da+k=F@u7-XACU(O;AkQm~46cG+$0|Du#dYgg68cFX zIg{ty|M}Wzsp^zbe^~qF7Hb>!h0RC{UM(Zcok%Zo^1nlRUnf85c@xN5x*gPa;N%ZN zdcw&co`B~~kHD!v4(SOee-hG`NAT0J1$pX6`$Gp6Qg-qeB8_<_tbczz&$Wi*bI>vF z^P$MX=i1aUyMeU*Ti5YYM+ekV)bF4p-0!qW4ElM^>RBj#1)w3OEW)$>J5E&Jafhi8PE1t z7}_a4o=KOsbhE~@u+O7?$KkS?3uW%e7|&wx9M6_V^s~k@f0a|u@$3L6&+*L3iyubw z6?BXTIsjt%Z`@bYI)?k1whjF7Z$ifhIy#^q+BsYN5D&FjIq3rp$NaR8xZItRAF_Yz zyd{441SkJk_#x+J<)J*L?}PvT`Pky-AmAp#V_6plQf4qYr8Jan`*Ic^RCsET{h>%=~*?+mOJbZsq{4GmwV7 zGtb2JUZl}(=Eb-^hBWZayav||NMk)U^G45mD#vdZ|3%0nu)V}@Mw)Xg@qYl5Y2v>H*H4fp{-5IdGt$J5@jHf}AXl0;gq^{A=Vd4VJ(L~q=CPy0r2_vAFj$0oj2_A7Ymq+G$y0|bHJ?ZQ>E8Ug zcOVa%S09Hs=gm3(^HM+ieCU(>i%p2@9f|yv-ooO9Q~!;G9RGC=>lyF=wRrTM(KotL2bCT!P0*M|iG}`4s)k`dS2YOA9b}HGyG2O8IH`+L+Tc z)#b~!$S@uCjk*8w7LOO@bJG#;Z1R0t|HN*xXG=c%aLMFs?4C3xrv}!%x`%q1CqfMeiLeh$PbMyazXXyeO-ij$q#I z&HK001e&3n(~atVx+j$p3v=2gBYm%upb2nyV3}Ty(U~Xvv<}PpE zj8$?89w%+^xO$CrshZRQys3|Fd;WLgx+JZvE8_j_-hvk$WG=!w=?LaxZ^09fGZ$f; zbOdvSH~+U|a*>{!j$p3$=6~T5xdg^ZM=-Z|^Ut|eE`f2<5zJlQ{8v6Gm%un_1Cy!C zQwoEP=0mJ|T9^;ne{COj(@p3$m=iPUrshPKmYZ%ux52!aNjEhwy0qMM6S@uN#!R}Y zxzVNNrkl~NKR;&DP0f!kEjQheZgrUo@BtGxe693mf(e!++!Pk1*iBsf?H}Tb40%e&RULV2;X^ zH#J8!AEVyhWQ?M`7kl#$Un!T2V@^7Gl90?e4FGWA)xh}%ME&Ufb>Hyy!Xo^s|LHyy!1pH1f=%u~+1nL0=LK<+hUW|*Ial#JbItOW-7tA^r*X2mV ze`Z~wX9xDVkdpzfXA`rY0T_f?&%^~>LJRv_>|G5lJXb(mLJOOrSvd0$S|3OH+enkv zZMg15nza6qphfWHIR*Nz=#n}}pHsy4$IuRtiMLfq?uZyO@-#P z_xif$rakRmJn|F)3C+K{}v>4^8}tVCdRoyc?q z6P=X^jII;oFwt3w!00+L4ilY~2#lVU#9^=w)w2(Qancb#I1kf(0Abv82m^h)zT>71 zOs2kjy4pMQ+j;osp(dFF**E*cH7NPAYtXoSSoiB1l;v(Z!h?0Hu0aLHNk=ePr|KG1 zV4QRWgLSH|K?TN1M=)5Y>KasFoOA?(b-(U02;-(h80g#XD+DIxN7?%BY40rX%^%>h z&C&P5eFr?bz?YkjV6ZQ^8|PEF$d{XrU{L?@8|4xhCmq3D5uTF?49~f6F&)8N-vXXn zTEKHx%y%;V2>Nz?$4wi4>gao&dlJF5jXj6J+!{W6$}+j%^R^vWzDDx(i@cOMc{QTB zrtaR4G*>GAkmlJh3sB_R_?R@kNblKlu34w62%-{PuAIj?Wg_Q!T~}K;(~pz#*?c28 zb%&d=$EBPTNtzeV2dQbw`S_V-%(j_l38{6kT|3A*nR71Hz_xNGRR4ZnCf(Fpc&c>k zuZJ_~rq;t#rCWbZoJn^|XMT2G7F#&yc4=E=?!)%TS)E;PkOwy%^-Zido1Qyjz3K4p zrXxI9Z#w?wrX!eJT7bd&rx_lue;UGMj+>&-`fJWiyQl6c*)<3C>82wYu?A{*?!_?} zYtE+Unpkr-J=esVv+21e)|?H`HOUXwK+e5AHyz5wHIQ@P&P^Mbx;k&L?#$GAdfln( z5$fE%Lf&w8?v}gh2nOpQ=l-6Xj$p73YI@F!b!XFaR;)Xlp0nb7wAnc;*Fg=>S(7@K z^AtTp?b$B_JgBKk56hskNhf z2Ii&>uH;xFdVc&2HTzk@^m@@be|!84b$ZW8+4U#)t!_G+#~(jKt@Dg)YCUV$q12_D zj&%9>8LD${tif6~^ZreGEvxHG>f5e0nRfMU*Ox4J(-F+$XQ*}jdkSZ$So1eMLw)@0 zGvi)Z&*NvGkDq;F;7Z;9pW@j}gJ%FT&k0iN*D2C%u!hZ~`}o;s!?QP@C*gU`hUbOu zUgGhy&uCtM{Or^G_v-PpPx~J<_bk&*M?UlT*{4~b%h@O1yHuzRZpW-7=O2rh;JcV` zjc;Jhc=*3wJZm`nL{#JXOnL7R?x9MXJhHEG%J?oBK6^M97uv|TqwMpF7{~bRo{wiJ z&GU13mx}z|6?u+p`{Ih;z3x{>~y5NaCK`Lk!eSSa1rwk2$b$0)c6rXFU&c8Z7e~{u6w-o;h`MksOiLt9TP&}qrLp{UI`hpVdw0V!%9I;jm84ZAN+_F58x6n?R!%uariyZ71(-dq$M+ zJOt?joIKaoq-c!d0k$2+8**rUPwd%&pdHz@nF zajj7N(9ItCUmRwG&OzX$tOw&_$m3dti)FL{{fjct#=CJ*C%mA8nHZy+ybp$Fd?7q_ z;?d@EFM3^%ds|U(!dCU)_j2&g%g|KdmIE$&-wU6)vG-{CEK~%8_k-wvNeE;A^ALx@ z`$1e7{eMav2LFX|VKi-E#J+rgO?TH(u0YgLLwTNkdCBFqKa@e_(f^3V`H0?kBJ$|} zcH%Gzd9E@41&PBXHA!!U&ejT>L_k&_*`o;HSoJknI0X#%al9rcUC?lH~m3;VoP;oa7S@Ow?Oy?ZE3K| zj*q}THJ=Hd;jz3hY8D?_$9eM{qyr~^(V1rcW?R(PeJ8%w%e?v%!1=Y2;j!V;@IcVb zZI94K`&@vuT{ke#)d1%*wnsni`~YIEPZ$_eCdRDig*mtLD&DKImzERP2Bd8phd#Fi zG5Y&O`OaNPTl$K_Crx|#qvcAr{!m`%KGKZ75&o~JN?m>YRPkY69jmBeSicCDhwsi7 zM}}8PRblLPEV6C0aQzJRA#eJ*?$UO)GVS=k=V%Q%juX!~5OLR8Gl~ALK|S&N@=$$in2ltbW`1mWJ3fBl@_|>&T0tqpqp6Qyx_sajnU578zjFCl``GdEYnP98 zj~ySs3HiV}b#!DLS@G{>OoV-9kd>8@@oGtj5IatEehXmSG|`{X2RrHac1&y3*RKGa z^bhA<%)}AS5iD;o#!1_eZFm!Dp*&tgLj<;8!bHe-96))LzWqFf2hZrro_Cz)oAhhh z`^IS(@Ikk+EyO|malIM(A%Mb=CeG>v7uz(U>Hiim4ow-c2FA;yC>EOB8z*Is0Vy2l zPD}O|08bVlkp|k=0dcmXgWolzT^O&9L}ym**q~MVzi&$4Od#$0K&$lsrz!pDp2yyh z|K2+Ejn*GsKYU?5UK~ek*AB$liXZ-=G40S1_ZI#CZBAbtac|MTuQ`2j#JxrT{yOw^ z`Sz%ehsW3BWg31+oUQob9~;x2vLCie|AFT8r{ssN(*IL)`cv}5R_Q-jhrStwAKmfr zgnGP8!w-qG6+e8aG3_b)VXO52+?@WD{IFH}e`!vCN`BZX{f8s^xC!1xeao=`ZMOuM zyDkI(>sczcwd=tbX};MybP{m7{vD_8CJRWw&ykgCx)MZ2n@L`>fSGq))`f;L1H0d4FuAS{s!r zlQy5GDafQ1!S8du=dXM)%Fp~2&Mt1#Jazl2T5)u=I$j|rmj?8q@`8@ymO(FqBX0NG zBdy~0UTSeuPofif!=W9CdjMCw7{TcJvAHi_-8gj^?-W zJHM(boQW6hqhz+-KHmU5c_MxK!7YeqKcYd)>6bq=w@(ai;7RHu3(wpZ@W=q~(8Sjn&1g_*H_&tpFws%kmKNPrzH#esO3#;votA-(y*dfT}?+0o)O0UY%6ZprN1fFaO`*c z3)d^IJvf)g`U~+}0V3FG*@E{QV=@d)Plj0$Ut$N&zcCqze-F#RvwK$trv0(%p#7K{ zb;`c#{P!iSWgX_t@V_sZLl)APICf#Y3e%W(!!+i3Nei9Pk>Vge&b>t+d?7xr1H8e( z>M(8w6$hCyb_EZ)0BLY@uSAB7wRz^fc{_%(tt^b9_LB95J|sXOZH|4;^8x*X6~h4Q zIOhk55u`24AS>?OY*6A-MIBidFxv0V#G@O9JDwo#i!Lj<;mzQX4joW9w4 z)!g5F&4CHms9ZO(9d&vq;*+9$#}=f)o2}>f;OBlc%FFYaPjd1Fr0GY*2imD;$w6bE zU!d;q6$W{EM$*ZPU0;TJ(xpucwc^lN|L{nbZJ!31Xy2g!l@h)2VG}XzAY< z{&&i7ANuij54s~P%OR84_T`#qpW24>EL_(9&GuJ(We%fOfOJSU%_10r04BmOE=;UmPc{}0~M5)S+1Ul*Yh zd_3`6BBAQEJ|A`7vtJ}a=RfrgWx=+0k1>z-v*Ig zQ^yIo=v3f`<4eaIkp`ZQH|h5}FkXf@FG8Bx)f&S^JB~$~I5*+qSU{W@2RJ4R&T&K+ zAWfVXCUCO&N(0Aw`Bo{0pfBG6d6l-!BR{?GfXq5@LU9rIf428L`mFT#Nuy^xfltP=lYqa`SjMsH zp{(y_IpZ7VjKsKNpC^y{L!+^-E)8e=Yneu!v9K-;XMAj#MxC*;E)8e=Y?(%#v9vA? zXM9x}&iEQWV=ZGG`vzg~EWLd;9_4P@^cTWJ&(hPDal2YP(YHhE!$jW>O~arM86T`O z_Sco!nGcN2?tI{;BYE&lzWwh32Nk=fyi~WBB_2Q%>nCSZ-OK`` z?_FU!f{EVEEHL(2?HCN+&0N<`p}*9bqwDI$nYUFhlr`guc#YmSCvf`ThPXV@H#-DI z-+>&5!L#T3-eZAr(h;rbn;ilZTbJ0r7JairU>ut{{=)xG)LENSH&`pD-@lm}&)xpx zrW17PtY7QWNsZ|)Za1Bv(_mcBlqWT=ySUwSf=+|6J(EsqY(ky<9jBZ)cEe= zcGEFB8?4%3c3Bf~Z$aB&{!jZr&lL|&D4g~W$G@`2gy=s`^vCQm0po@<4!G&a_oM%t z2%gL_p~Z2-X1&CGE@Km zAB@}LH`_=1$|L19yMq5p>GIG3Un`2By;_``^a zdl8B^ja0UH_V#k$cG&{54&#HIhmtRwKLTl+XA*ljsl$FR>wJv+iyZIq`;aTxQZn0V zp1Vxp za5gk&0r*){7#`b-G6t1z&VgE__-3Dux_`j+YK6i5nb~KcZBK!(FA^lN_ZUH*IV-l0 z4OV-1;J!Z^X*)!7s5|0Cm~$+CY?}COn##B7cRA_LIO!ia=?9|p++~{1vIVN<94uZVMOQ~-uS<(&I`q)(3W;yXpn z!{;2oL7|ps`D~W`z_-{8Jc$mi?qumD*bE<;x*K+NCmCr$z9ZeeMX^vr2A8Y5J5aV4 zb+r1t|+U5MWI7xlf11lIHN60=QLG{^a;BG0~u;B$VkX`GRU>0wQ?Eyjq>Tm_H4 zjh%`Sb7TZhV%0{fr+THq@~MT<(}u_|17U${?n@Ed@t*$E;QydG&Z{w5%`HllhPG@X z>$L(~Pu4e}*2?!LCw-=qe!Zsmwyb&3v3-DZfL)Z4?o`)guxq#`q4Dc9 z-lFjth)ENDGQC!l`KZ=k^J>+av)-T%Ilq&CwX@9QHqR<+^G5T{Apq35rYws$tS1gd-XE#-4G)jukxa8< zW&IKY8q|eEwQWD+TL78BrTFH)?!;qmus#JF%smJBxla9ikcU1(_{$RT*CLPVu>On4 z6Su{GGx8iuZT`E+b8T<)KSCaU6y|@6JfC;7^?yO0&n#$O$Grx}C+3^^_>%!6`wVs{1jUj0tPSf0w(%aLe%o-5 zf+tT9lvXZ4nmX6K>`}N+X@P(5PHk)b#Kum4l^Gvkf{#9x(rNgdrPF5>KJuAYvLyq% zk>!hZ>T!e=(}OO+O`5zWSa`pP_UAf#y050f;x-ykscb|@1`-?7gt#>EtPN6vsv z5mGdXGfC4O3%UMC(JYT{cl!oG$e%-Rf@KIPdba;Nwq(~2Wz3|oumAH{{at{c8q2*M^z&#)oT7=mknI&zQQN0kP<(H{nXk$K!Mq3mo?q zDf^8NC&?x3_o|cG3?a`SOK&sMJioDd(*GH*Bz@O^rbvGRXc=PmB>jF|F8!O4PtteC z_Dp@_C?Tl;;#>q&0b+0RRl67=1pIO7Rgq87lNGsz%cO_pVqq$q<=e$(2r>VGzxt=6FhQ^6>T_!JULBAaLW&;uS4nzq|Hzz2;GgAMTFkhQ zzIuWL5d!`=KI(Jfkf14h2@7{56Uli5GsnxDrpf#U}A4fcNi zcGUYg569n+l4r#8)}oG~9u8E^d$!iwxq+h!WC<^4&Mmt>xQF~<0;CuM{;2G&_(Sd~ zfRFsaa%OO};S&?2o8=R4M|qY{JRjxI&x~^rlixk*6J|9W>Ouay2NHGdXKnUc!1&y2 zJ5HdwZ0Z9RM-e#c+1(vm_mJIpfgD4?pLXp2RKQ1ex11RqZP1NrTeLc(WFF-l% zelFrYZTB_6$)I{@+3tO4GhMrvfuoMyEAAS5B^gYPv;F1T*v`ZR05Hk{-R1(s-Xy(K zLTa8HK{07NV@$>NWa5agi_AKulqQ#?H-V-M0e`GcH-OAe9Uta2%^dutv8}nXq5)=XXFBosK!Qy2L>wm z6GM4Dg%qj=U*>s2X@paW#VOCnavd3`&y^6v%w7Ct9mfyOUCw;nxy#94j3M#^$dk8y zG{$@;dA4IY=1Yn1(D;WM-)UlhfyO)+0=y4>FwVVC%W?+~p+`#B3p&sj4O_d&QEp9$|@Q?>@{og8)Lk8Im;R98>1Rwqo=M@)wV0BC53 z0O@0*{JfVVJ)n7usRiujj)0e{;W!@;rn zlN#kkn9uWH*j6s1lQqFwolNTJL~2<_IsxKiacO=^I_Z8Cb;5mCJ366me7s7sS{z`v zi=F>*{TSGAnC;X$Q3uO#@LLYg-v}g6f`}BLuKWtxh{A10Y z)Q80dTZ#gg_NY9TGC9%KTds`qBEBKnRqZYnIs9#W|q?Jn?cJ zVdr!boZ`Ah#&6tHqi)K>gT?Aluz}o!{0B&5Ot<;EbmBNRqD9yy7a)x>t|<=cA`jU% zBZkfV)f#teOh05f?L=6NQ}bVncoY}U5#>xOCW{#+2}_*?i09y99zNWVj$CYvr;%?ZaI8g>m_E4gp&l_mg}S~FdD`&H8h=sai!{Cfv8(&jO*!xTIzHOH4#gHO z7a+Y*^LdBXyHJ)z>)i?q*+f6#xp$lfmpm~V(5KDU?FZx?aG|_6B2ON^u5GQ)a^L(W zTobqwvaLsvrIQPg#(GWic?a)JC?j4MKl3*$tfg}X@@L|Dvw>$Dx#Bc?Qog(laB7E! zvchhmtk$MqGBkW^+plQ;N{z43_-c(mrm?P5{f}$@T8%%U@h3I@l*XUd_%j-RPGjtU ztiHs)Z$bX8xZZ|~`_i*;osH`pTwDz%bdl-{`vZo$aQe0PLgcB-=bKpkS@k6}&(r!i z?)0}hY#+%xdTi83TpI264Tpa}t8citv-?C(YCPHxa32K zHU6E6g$Gxk=qDmKeI`LaHO?Fe7`Aoj=Z-Y(bE`EjXiPl;XO2F~_y~>5h>63>{tl$y zY3h>n*Q40#Iu{^~LnWJU*!R0YZ!=)2mwPn+iN-(H_(vN5x5ht1to|Z4`A6jGi|@wu z9$X3CKm{Q$xd7>dG@o~9AA&OSfU*=Xt`6Rd`il)rl8!7`2n%1$1&F!lXWpH={sVc^ z`M$}!w@__(pZQ$ucsl7z_d>I=Nz`&Bf0BLWM9w5Qz zuliZtzHew7q6(V}*bsqv;@ylGyym`PV)-Iqz-}&U8fuv-TKcxZ~fo&Se)Lp12 z(?_H|e%g>px{sAV7ii<8Oy5K~dFGhgvP|;7VKmS-9A8p)vd_mwB8B=42tWBz{xY;7 zlT6t$naF!mrkhd5ay$07WT)`1lEHTX+NWgV^J#VE;Yv?J8}i7|5|f9rB;@gR9`p~_ zx-5CLjr|Xx|0BRc2mW2!W)ANmjEs$XBfQ0pLImoFm+gOj@;`dkG|&N`39PGwPnpJT z*;Izam<}*TNgngP?R!4P+7L$ioaWI#t;{pJPzHHsa9u%tG?W>(yMtPI1rY?|h=I)D#%=0Lrx zw>omFheWqc^hknji8oMPEkt@2F6hD6b(OzD^Pnx|y8iMH)ja17!gItRF2v?tc9gn^ z0j^7ayXCjX>z5M#c1ya)9sk%Kb_?HSM_yP4d1CLfgAT3T{GX$q^sm);m&U);*zT3S zhCFex?SfG_a&NKAGjX@ZJtpqg@_sGv57+vfv$p{U`9eRE7=9x0T*Sl=9nOChbuRkm zPkh|rTIpXD7IG1dcd6!Q@_s<#TkL?D&#CG%g+X54pXcOxwr1DGo)3!Cd5;!ni;v=3 zq4eMfd-Oe8)~3e+?Ag>D_J@JP$~gaZ-oj&oD8EMLjxEL$t z9VHKCy^ACD{uoymZaR|ZZ&EMz#Vr`v8EE5%dP%+S#?^(J{u|dzgZJ}f`b+BlJgzR> z^xwE%8oW;^Q!lCa3Aws((~({c3?WPlS8jQ=CbW-E8i`z{n=Na?%kD-nrQH9d{U`>c009 z`xfq9@C>eb{|8P__&gv=42{K1gwNm#5WY0ULQ@~0IWC@?T*L^$9F$C6b&2G{{MCv4 z$6|Tvcjc7NQTUQ|Y|grSHPIsp(kEU>6P`I?-zUcfrXrFxYvO!YN&Qc9i=j>OntuleWkCI?jgr zizAhCuY8fLx9G*P{Qy*0MDs6o(qGdw=*gMRv6k^ z0;gqHnvi}Gj+f}Ln7XKD(Q~u$(y=LA%7g$BZRGaVapY-imd}U#nZ62}h9g^ZyW;HA z^j9-L0h4Ky<;$Se@|eXwBswULkCqFyf$gI>b?;lp_hN=L_>4d_Zvar>3hLwn7W!qt z?Br*l8VSanjdD|3CS79s9L4o?)D5_>4R68;FfZwian!=k}o3Z7KC0t_uLP zMm~%q4q$B&5N7hT{ACdPCha1Nj+}g0k02O#wkGw}j9NpxjrIW1rfu@U&lw}Cbs1{ApGR#v{kl` z@P0(LkC+>0Y)pKvkDP-%edBD6&sCU1QSA7Lx!YwNqg%ebCI$0qvYw7&l&NXw#Mf@OhKh@t1+( z3m#W5XJ`faonzM#LZ8qPuFXhO51-cfGg?QTnf}sj&40sl(L{pkCS3CqC(FPf*8B#J zdB_m1`M-la=;ywxu&i5P7yBmeN0s0~6t3}YU%XoDkk6b4Ij|~UZLQ8x^@img`Aq+%{;5OMFW@s! z*J!@oG3Y3?6I+J?P~NydN9zpNpJ`j_&&R&nQY=5r5#!A|8Z}~HI zo#oG5YoSW~u}y!TU^|3Ne}1D@r2W~fj*|WQTENqvKY^Had%~ZIleilB^S`4WbaUTU z*hSMApB;L8)t@&Qo?UC_`tyWVr2Uz@H=}n~51&LC_3$aJ+Y|mwoX!0CHbXaeyTXE} zDX%wdUxY&Tsy}ZuJiGo}nxa2{6R0Ev_@%B~e|{74+5Wty?s_9>$Gzpx)HVDCI;hmR z&`3U?3_Ch&X8`FPHp)o93lMvgJmr#rj0R#HE?`ixW+Ga8RSRVc5lkC0y z^2-Aatw$8@_n7{gmV>9%Uap=$<6gDpPuAPEzco6$c{*`vtHnA@h9C zwHjzo(V_iMJg)U-yyexe+kl)k(!S@Q`gAAo`;}^aF6SPSmXC{vS0@%4n zDUDc)ifaLEidvs1w6SmxXtI`s*m9Z{Mi#HxLu&At2|5 zN5~anUjxBxT*L+V1&1M~Lo)CB1Z1=@@{RJ(Xug4u zpbf@V1nR;aX*+I946v8;0>&xlw1$2A`a|Kiao2A{oGoM-(79^Jx;L^#z#CaJ!8WLtR@`ifB>;Kc>{kLsB)|41s6E5&`UU9T%a(Rkadlr zfLhM6$*vhJEc#099tdE<_3@e7Zcel=2oaJ`1a}><;9?YzQPz>KZHPI(Ezq(?KK=#3 z#Pnwl^-F8$3#eltUf8p)4p~K*JWvH5!sHESFhbyv!2E>7jy@sVf(!8e#!+veIz)yM zh{K(KdXcwdio5oM^@KIT9|oG65km(5B8@N9_#ZWXhsN(j%r;ohx3CtJMPae8Sdv?Q z{gv@jZ%MMiVDO;-&p%)Lg~$6@yqs^m<{i6R-s?0qw5O{qx{NULKK5(k3oXK-)NyB-(oV3*7}kN%|f3$BD$TE7Im ztT!R2t(WyEky?1}1iq+w`0;{U9=R7ewlFZ8QTAU*L&lR?2HAHpKHu|CW_+IJ&-HS< zn18G0-zKgp@6_S2&-dx9VSIu9#nICLA5pEL1^VsuqujHAPx_I)pMoBQ=O9Q%i-i4R4niNyg;W?IR~658X;RG!?GV*hlK^8!rMpc=g#&h>vru+3(A9tSB+% zh?>r^fLX|~Ms-+st=r02MBfq}+Ob^6A|B)$O&U7wjYT&m#-bZ1K!$;?DSWpw78L<& z^_&=sx-Fi=!2V`rsM~jI{4R|-Mzj1q8ow7Yb@o_{MV7aEJkgI@8H;o*%W+(VY&pf3 zQyFts#tnOEEaG^fe%HcSloQ`l_?E^Z?v4m=#-h8Cf@Tm{20K3{V-eScq~Bmp&;1?h zr5}Z3(b_4FMK>nKq8l5IMSY-a`v`r=?!Pe>g*V5@JL)p~3F{t>v8V+ddh{*PVR5{h zkLZ+~huX;JGF;J`570KI*hYxCj4}v4?-WfF9_wFY3(6vAAO;tqJ`G#JlAMMgSG7X;(4*(bWMBE#QZ$DhoI61N{@Hno-}deju+L z6@Fa1zZvk>?r(L{Sl_p0_rt()J9eiW&vor-9w>*hWA=+>)R^%yF#wPu5T~pECuo_~ z|5r8NME~B402k@s^vMFwy2TRf?NjK6Uh8|1Tiyh;45mX)-Wto3cl59D4E`<1Tf3a4 zX~KY>^g*)`q02^t80+&5?0`DyZ|rA;J<#f3|7>SpTcrQI14LSOc$2sCfzv|3wsg&IH1lP#6e|{e@^soQW_y^h!{uZqZ zYT-l@&LoDbh=#761rO__cb*T4*>}N{UF5#NS(Z`hii#kmDmpzUmy*B-80!qc$U%)ed&IMHD^hn6?kl?iD!TbIz@ z0pQR-FJy#}>0i9JV)bYJD>-Jl{#8$hkEVZ7hw5LY>J|=P(VczjCcdxK^)nz*CH9JR z^Y1KTfa{n#=m7Vus#|*HJ_}1txjUwDe2M7{@CDq*91&;(e;8QYj6D7AXBz*v#y{1V zBPZ+01^LD{L&rHX%NI)aGQm$dNutUGzsZU9oK5Q1MA{!0-Sg;R9|P_V*iK@uF_>Sg z@j8u<(s;eb8#LaCm^?uy^L!a~Qk195m@?0qF;$Mrgfl*cCJ@MV$Le}wxizue+E|Xv zA&@@%v>nf>Heha=Fu0oa<>vtox_9P^N?Xsu<X0CP z8F`TjC7FHuR8&|$r5=R36t>k+J60W*`g^B2LWi*-03LjNAEvKuA)IQmMs zKjWZD-7#E*%jywh3-mZzmHv*i0!{T0j`*SHP^aJ4vIQvH#0j^Typl4ZLwI|3*RfK| zFwyDzTrH!u5Wc~An|CyzLS1&dy6o8ly8MptFcn?C11+sC->GTpsvTY426(n@WF>GFGM$daRhQ2}`%stbTwO+Q?3lVPxr=3JUzhJgE33=* zYr0)svRAaD%fl6Zs=CD4kJ07$Fb@>U(ZBNz9~kS?^EY5wOg{5y9(V|o+*L_9Mt&#n z+^qRUj0p=K^*N}m#lgX1@4)sk0b!lHPX8eC)FaD*#Lmk(5{2D!!y2 z#zPu&J;nMFjYkm^H#QdbJ|6^`5kS5o2x-J%ZSO!@;ui|&56{gGC4?G`b;JriFTOB889(s}TmuP$DGZ2+w! zwAwZh=n#J4rO3lhw*A6SAPxS*{MV6YaA@a_LEf(nmE~dDIQ?9JItGQG%YEIgQC@ie zIr5|#;pj##Y?BL+<|yXk;NI2Y!MhjvI1b~i7ADYo7l+;Vs{Z->o!}5Wv_lZ%qp2N8 z!{JkONqS0CbUDY#Q^O+Bg?A|p$Zq);JD@Jie*)qLPM&s{73IYa zn~-nE4&RBl_kMwVTwl#~{@nx)Jri;Gi0LaAC=Iof*zJ1>9KTnXNR~Ay33ZVRH0|Qx zDvbF?KD7?@arx+FalDQVgg358l#ck+Pmw1M!6W@G##>ANKzxc*?99R3=3(dDgp;S8 zXGeLl^K+1obQ2ppa{=lY6rafOgD5XDSbvLfG`I5|2^>cuAJ=7bJ9CwydMSFJ8> z>|QmlS*~$9EU5IoW)( zB36!XP}uj#$I6}WPDr`fgMS}cA2LJqRv(5JXI=5A@Uo!+FFjX0IHCL*Uc&!w#N>4T zyAdnL`{?ceHDcv>2YswO^euZ|puBNCPQR%d(amBe63udT~y|YC4aO|uQpbPKA58EIt7{d?KjmE)mqF#Juv{uF` z{Mb%zKAeZE*nSnRNGEzfK;Yx0M{OvWQh>AFqEJ`=Nem1qGIg+Vcvg4=%IsJR-ON80 zdEQ&Ha~g0h+J9^(N=#d>a#}%^^ z+NE@fvhci?x?(%%bIyXXodr>VmLXciS%mdT{lm76?k(q@i#B2d*QcXfT!M4@KK&z5 zk&tPd8&PF#1DQjgw)1yVSFQN;%YlWAUwA=LS+_BmY`U`bs?P6_3zoxvzkE^a< zTYaKk=-0p0cJ=)F`C5-?(W{;G6#d=jGa@nD*q7BP?lx_+3(XiZZSy5mWZC8zl!J$y zjqTd2UE4exc&KyNHqO`_jyd})oY)4#7=yM8$D9n?%vhpuVw;iln8PzI;%T>k9EUby z12g7~a2}Prl-fy%Q%Z`~FhliCiv;C>y~ACW;ww_O{sUx^LM zqgARux@%|nqd&y-yl%sWg4_c|1G8ljIU-&Ege?%v5|2E&>z02-K1ffHwkwLU^AOz6|>%Pa%T?9&l`F+5M--PE@&G*1unUPMDwTQ?4HgOC7^qE{PKpnj+ zlnH4DSBC$J^1|;=kheGu-r`VYz#Lq%U6!o-qTCy;4%P-Lg&M&N@OhRYD6L$;41(qt zU5qqWIX3?5JEJs-M1^h4#-<~(ST-j3GKESPr#WRoN#XV7e z(d|gH&saKlC-V2k^ZQa?4*b3g6ZsWR9?5-qDx}Y%n{kMjpLrV;H!rut z`{8nL(cK;M^4_eubJr|5=xH0C`?9`jZO3V^f5RL7obT-u?DORV9zNjD2RwM-h68sV z_}QmDaKzdp#-1^@ZET}A>$*2DKJX+QOmw`Y6Ti8auH5K7@e>Da+xFC7cu!cI&ld^@ zujvlH^~ixUmtE|g_0S`ae0!s}_>Exh2atJk)>EMEi4o^dNV$I;e{O_`^8zgjo$2CYu9e_I`05KH+fH* z_=u09Tf8M3yt%-fyA=?*+h=d|4*#yVtFyCn#*7(DbF*j9?q0HZ@#2n-j-EyPdi(Y) z>hO@l557|cNxHv(zyZsb=W-n#GiJ=3IcwHztj~OZ`SKvh=a(Y{!Sdy+S9f>wTE6^f z1hn}Nmd>0xV@5|uF6YB4vuDqmwS4&j2h?v9+%rw%Z1m>+V%E~72Ohe?JM=Xe=}Ijo$oU9+`>uDrU+jly&0YJ7A;+V(7}g3^@!DL)<5If z$3E|cC%&q$dg^Isoc)fAKYYa}uKViE-}&KBe|`Uh5B+8Gk^L^)wBJR)c<9ti?mIXj z3TP!lkzaXOp?lrNXC3{V=bv!WYbt}=-|*J+-}S-EuKx5FZ@l$;cm3?Q_dodOhj%|R z>&l1!;gLr!d+2Qsog^rr9io^$cj1!#p8zgab*dgl%(O}NN?WkiMR{K}*^@xevj1oFT75k2JA z4nqA3N}he&>|LE5`y$(MEl(M9zd|?7T@Mzd+TVAh=N}I9ag0IO_bU9@@#ZT?f7Ho; z6a571sj&V#NWaR-b6?XL(-ML9ynWGw{~lrJ+W@xhwIjIb(AkkDg!TrqwgH&_&sH3 z#oN+a^+lu`t|`07R>)T%xiBwl)t_p86L~z|hobL9xT(z$S1v%BmRDW{H}BCf-wgL1 zfJymfKQ$T}n0c>={6m8elb9z;wpC6ue`p;W!2l;ulS)e49R}aU z8iO=C-lXvxH0C~w`^w>V0~nZ|0X0uz#rDRw)ime))v&~X5>NB|G9~C zw`%?`ny20fPncgLCccA^-NZd?ar;gW=i8p_@6BnmbrHfrC*gSm@v;oKILZlGgb75H&+Q|ZAP<{KIjm^=NRH={;33EU&3L)S+#@r8 zn8t@ACQkOR>5f<5G&noHq4C!>zER_w5tG(*#w)Ht)W$MiS)5J$GWQb0gXi~`2jx&s z-uH(>1mdH9(qq<+0>N2Dm^^e8cnFifX>U3jWU{P5v$yu1y0_}z>TD(z0rStQeMCI-Tz zEF3$nol%xLy8&J~yP?)O&i@A2Z*dU^^f{kv4C+<$$!881bA4(325>TdTb*zWI>Q=0 z!V$agx=-VEo_`+NJz8V9$|z&diKH8jyIshII>-ggASk?y>D&V_-$Wko-vI;LIk=mT z>0B?hg8TLq?&jk<*IupQ{+{9{@AmR5X2FuYAI^PXs{aF)#iRwF%LRzNNqU+D6q&kt zPG7$iW!Cq&_SlR(Xy^9Tn2nfUjF^3qxUpW!Z2~D-DLU&DR9V_#Ke`8HXy0+S)?v*v zX93#kF}=WBpXOSX_;KM(zJ`>^XZ16*k$&Rzi`bf_iI2#=;77~n+wt*xRpuuAd*1>a zeI&x&+{gdWBJSH#xSRX<`WA72S8)sPQ(U{e%)voCg6q^_J~y&u4OjLkW1uf_jm_If zCH$e1fn|%(BtYy<-nW?%Lmn6F;8z@*yq&n>cyU(@WehFg<P72(D-R`J|_rpoNd@iPSym!~b`%fvnZTZfz0zlL#ZMlWi}%gQ$MAyPHvEC;B;@hy;yoSt7+&7= z5J&^p*nc0epecU!%r^1|4#2JB4HPtmmwU??ziq7_9yqxk-nXRiw&f3f_3*wmg|{t# zDA&XLwiMoW#@`3F)WiGs6yA2m-v|2Z;XNyb7w=G2VESVdKRcx!-m_D9v9oO*??64g z=cMr3eFV99%#?XQuY6dcm_k2{u`o;RT{CA`d-rPwEyv|W> z3;h1cqD|>xJc+lhas5w=EaE&8u6}vO=jwrKXkEX5B033q{JMBYk&okTN56ksAxQC) z$K~Q3Lq3kTo$=vME74p+9=|SLJ^KvDU+1`2;2QV02MtpECh=Z`GMC>CZQ1R?x^{a< z3U535eX#C){LUoaw*28iiZ3CLUst~uARp61Ph0%f^@j^B-trb4(^tBZ>poc^xX&o_ z*;&A%neYb%=K`d?-FAuXGiP~U%yI31HP5r&bBDJTd4|B?%J+2SMZQ|8iWfasx*Z21 zoCuKQgRtJ{P;GQoc}GDqL~HTNy?VA)I^GdTlLqrxxG&}&o_+P%T86YeKlERMGQj$O zukrC3zgpv>iF02^Onip}+`O}V5U(kcHzhCf@xaVh-m zoPEv$Hudn`v1+X!MWKGzBF#k-;i#WR&*88S`NseF`Y*WP_SzV}E{He(4G#=d#36|X zVaapx!!&Jq5H1GI$9$Fbb8%U_f!DC#uus@>z{z>2^*hLidqq0NI4@fvjTN|3_asFA z>5VY~(7qTKY0##d5rYr^M2%mr@d+BgM&mw>&qU0&hojk^9%Ckfm%3zl7?(}+84sKO zvy*;E)8yyT8e?eBWPtuWYiGBPe6gJMZlEkIXFV_EWsG6D&HoZF*qj2N={n>2oo z#+<}hKB)1rh}otK#hXUQ@LH@ANXn-akdy~A@<$k_oy_OdiO|Gf2T$Ez*A!gU1TlDMRwXW%mWD2^4;r+T<&HKc?uuCLraRVenCs@4c4lOu@QCl@fY zo8BTpOvbvy!1iXupyi*cF%N>6AJe#`G0)-I26~2{gD-3hiUZa0iZ`-zc(~7#Cy+*~ z1Q$4GJ>_%Ew))39yEDgEu?nPtg?(hr%=ygfN9HrqNvxTHXX()ixJGNoR{=JrOXneZ z$}=@x9*UL{GIcqMD(bMN@wmpiC-5hbC+(@|lKYZYbV*u!T9=#?jV^24>-RXX`w)5N zqdxM>(Jg9Xse__&0jj;->;)16{!$N)ugJ4YRz9}bjC$(wSsMSHwt-LOHt|&yBqNWs z#pw|TXE>_^<}GE?Y% zL#LSFjorf!bST`Ov3mj7Bn12=e{LVR6?rRv9_-jY@II7-H~;-6&h66ptB8qX+IFA& z8@iI<%Cb9n;&Yt*hoprGZT(~|Yu2w`3piK5&g)eK=W5i)`j4C!?kL6kRoN62M$4S} z7$|?#ua1;5HLujU`u!Gat$vqdKKcOi)ax@eex}AxN36E#yo$QNEE8cc4-JC#bfqh#FH5eb7ce z&HBa3fD?V-Uq+$~o?o*u0`WptM<4uy(0DhCv@RDgvwQsnBLt$7I!6!k&2g&-@E+=c z@)HmC9Jx(0mqvd;V!10Pd14vXaeN+pv|>b*vO2ya_NLZEK6$@YWo>9|#fN_A$k*ik zR=b}^Xa-RW`Elg*K8?JU6L>{V(q4m$F};Pcl?C>0`hF`Avf~857b5M~Atr6qh3^BR z&l9)xebmXjXSiQvU~I=v=uqAdq^~{^T(rwJz@Sd{&WhiT1>O#n6aVXQu}=1h@(!%{ zJ5W%yjH96HX4&&WmTCGn1JnCLZQ*+ss%5MT;_ny%?=s#)mpg@EiDte<|=#E?@n_xqTzJ+VhX&fJp*G2z3yi8+-<38UB$w59Qz? zcag?tY1URibqV`|fR-qQe+g9jHBz8#xlToJt?5?ZiBWK%6WOzjA~ zKE@{>eZ`-TYXL5dTRwQ<9?i$uk&iJ?@IXH?+cg`%`q0j`pK~-W_`pME|Bj9ET}K^N z;D7!Qs5kJH3lMv|;k_oH$ke(0{j(^u_GFvQ$di|+YPyf+wrY#$m(MD`oD-U8Fu{OC!hYzLu zAz)cddh9;|VsG~g`O6U6i*=h(0Q|Xs*7!q+*-q>NJkqxqr~6hoK3Y4YUF^MI&H4f8 zOFwuL^n-I7KacAW&{jQ3e^{Y;tII_aE?{Q&3H)UUZ2=ni zetiT>ooogG=;ba!Og_N3SsNqGz%q9Zx*2)ku{=MFIqj8PGovi!!{AqZ*v<>cx25;3;31`V=Y^(w zM(-~M6$zPo{~D^2dgt6V9lbvf?J3tLT$I7p`*WhQY3uz6#nqWycQg_hHs1$X`hd^iF!n=xRAA%<_I7mv;z`$T;Q`5!qaNR)EW9L{u9c3 zd+|L~9p4Q1b8pf1SaYQI)6i4wJ|#exeM;dQ`8WGMd1_P7xqh?}J@@YztyPD3E=47W z%Ru6ckFyaVs)QzW6d>*GeieTixHPu>EW1?;ls`EesG>~hWA$&kp578BRtqgNOi`s38V%3BhT{ zL_)v^!oCUJQ#NVo58`Wu(c?;#i2p7SiO3iBV6Hrcs(uKEbqLGYzm@-Gze3vb9O=4D zI0Q--!V3NSwKRi=@KMb@!vkj}h7=FEQ?!&detEDM*F`bByGcH{cM;px2G*?UGN}=q zjg~3{1FRxUB=?6|#1QaD+lTx7zegGDAOU9;p>5bFHzQAecH&|?>A!f?tvAts(S8|q zXmyU{vPZOywJ{gZbz}?gHnuO@rNAm7;BQj4SD?(w_DW3?#+B_fZ8sg+=zAhtsW=43 zEru@+QruXxJ7X?@3Oz@PV{3h6E4$(`ork>IzJsKH5`HKT%h|@-r-nS~4{M$5Gy3qZ z3l6gx_CnimY`sp~eqP&x9?oWqLmt`GKj5p*>aG>I|0E1}+mCx~>j%uQL>}X|^`C~% zFmiq3>M`tm+P-x?eiSVvKvYB9)uZ+Kq#pT@Bv}cji)#HHj z;;TO<&yic#XC<3)Nwm{DI3m`oW9+^qkz?y!m=jps{u2+FXt~qmOeeVe`Aaf^|>7lsFNKU zk0T~+%!zvMMS6NTDzgq_obBV`Sr^L|l;wuR5I|b$lLRDfoH_Fzf3d|g%lQ5MH5)hL z%(7%@(pLgzc3;6?hEN}_ADxd1(tay0$|Pen@r06^a<^}DUj(}gJmjrAW_2kH=vh5^ z*P@K{XeFz|1*GSUgT#%qCwGkVxL#sV9vhBv9HU)*h6_h+e;5(PcAt1Qf;_lob@h2A zTQfi`!w(XnA6z(vr+ku@p8F$ zsJ6X#v@0xU`?qkV;>!!;H3r4mN z6vu`~3ZrAiu}WdE!l6m{MKpg2eyC@A*}j@Q*PNbjT?GmfM7^r#(6=r`73sen7wcN_ ztpIS)kH9zTt2Ca{3;XIPQAT?7c-Eo)oOb(aBi}j|IQ@a@Xis@Z(7h2E1k%A+gNbcy zm8t4Z`PBgmN4eljaz9b|lQlQbvB9h5x$gMH9b3|#$+Okz+4E{pkdSH5i%>=SXW=6M zt=RKuz_nt}wTcsjLwkM-Wu!+h+Z*;A0bakqI#}G5!fM+7$P1I z%CNj;$|W96IdnN<7tZb2!u*ZMPNFP~rEqWf&c)JOQG*;X$Jyn^hG(OU^*`CrRufAX zffxFVz3^jhKbbN-I+kuj8S7(&|2<-f>)K*>rdyh+_3%xr-PIWs;9y;`coL_8f1Q%C z{IGGTiVVgIk!PDd1?LTwe?>aaxvzK~%4j1~Q67xq>dbF&QaS^^QWG2XPPMiS|10#oep8C*-);;Fw4nuH|FT<7E0Lbe8)F z>(L&JS5Bdnht5aXv7Y%se&w}}#JKUR+XypwtM@BcqjE(3%KiPl@#||KNB!7Gjqg_F zS1Lij9&F_H)UW5jr-;wuc}9Lu{c5izZM^a;^rOJyK|5COSFXh5i29ZD4hbKUjXCzQO9oYwA#~9f)$vBDdjO1A9W(? zo!+*zU_w*l7OUV9-4u3ru7lE~{tR|SNP?lUO|iz7-*XGGp>M)Sb1Codtj{O;KyR+@e%yKv66#rign)~x*>wyH&$}6W3h5$1iNpn~(I> z>~$V>7OH-h$L07}crenQ>`^-1Ri6aJKG7ZPs6_WVbf0VWg1uVN_t3r7SG8S#eeZGo ztzfXezqydkzXxBd$oP7$y*;KY)}wppTNA9*0mt6@_NYtx=zgH}^>U-RP`BDUyJc>? z36<|vY?ux)SpPMD*or#5uhaRcuN#d;tF4ifxZt(aYIHR+M@<)!y4XLZkJ>(&EZs#X zkfOd{V|+I@Ey_q_DP4x1I9QjX?7AaWHy717h=n6scQPIvf8z=mOr2|PF8KUGwq3`T zN2fb;jrMdm)KAvItMOIFHykibz4+*(-`K-$F?`hb=7P^B<5RspJ-$3{RI_%l9g8o7 z+yLFgcfK7H?2NA5w7}8Nm$n_RPug+R@kjzFW3eZM^EaB5Y%?Thfo~bzB&C8xg-feQ*7?in)M(x~UNA=JU9A zUbBhk(dG4%*?D7#doTmqIM6kz%f+MB zb=Cbky&kyP%-QTaZmq~ExHC5wSrf?j90%wt)Z+?%(m5l|~le1Me|#5By*x zejZ}v_H-}&61aqWvc|u1-==8t;hrUV^jcw_#aj~|0oj)yY>yUr!p8XWu!+hiQ`na!S2y$12VXcihJRJgBy{ z$HmR%D6?@xnXSlEAFJ1!jSSiw@3hH(?iUybt~0X6?$qzf0o&d8qYvki(BDL#96!qa zf=dk#c>CTXeIEFde&&4W9+jp(cg~0J27(+>A6@}c%!eODIdysq5_Q;@KEyp{@gded z1AWM`f%Oma;q$>0_|QEjedm3MtL5Z~`tVB7Vm|yR%Bj;^k@mF@(XYjanEM9$@V5$QYcL-tBJqCUI|q?ivsiE`>>$DMr@haCUm519uTkF>8}U%sE=8RSD= zV+TG=Jr{lF`ttjLE=Sad9RFfI{4C0;)7z2uWgOCn?8E$IJPz{V<%VaF4_^enz=!Vf zYSwY*eE5DK$PxA7{XvTP@CzuXPPZcMYag-?(}(vo*!|*=<2CCalJ~k1vSi!7}iO zZ5#t^J+M>sXM4~N#x`k)H$49cor3SJ3>w>BZgB9ti1mlr6;5!^06k?puQ~R>AM^u{ zed!NtGcetC%D(akpIr>%V{B9`*f;(dFN#~p^*D~`Q|mi*1l0+O^`b8+&IhKljMlS z%A-Kq8-H*;6Z(T?w8Q#pZ^x3?8XP;8z#sc?Ecs~Pv1D)k!8z*h<&W28{jm?nl8^Qs zOZL_u>~nkTk3MVo;w@QU?89;7qkYE_>kFt*oW{Ss={FpI_SP?h*7L8ozUg&q4St(m zt`J92n$&p&PtYt^L=8sz-u`f=exB< z(?IU)MwC4gDbqd)FDZhLF?^_s^THkU1`k@8&~*De17)COlx9;!fhodV{<60vN{diqody+$u=LYa+$^VRtU>bz>s zjX#_pFGo4c4g~gQUWZRBB@7MNN3#yw4uksh8^9a-#ob6SnES>r+}V~R>X$7bS-)JO z&hMknFE!_(U#>v;zV-{p7V!(-TftayHwH{yXW%mx6CCGO{f>*zQJM$BCefYovlZv8 z^Eu}8DTanN#& zQmIZfk#jcVJLkQq}V9QVy8N2^W+qhr%HzZ@D^r^#;zpF3HwR^_!0O#n- zpibT7`;4W9>QzB5Jw$B8>-@yN3prk=(O?TyEOeC z8$oJ-Zuv1*6*zyhJ!~rCopKA!I^LauLLB6kz=2Ckb-rcIQ%SoEY`psF2VPXVnA{0J z>^%D6jiuULQY08GYevdC_-fw{#Rof%eysZL9_E0fpS@r4+3WTj`pUZf?o$1ese^nk zWx3DGp6HvAFV^OI^LVXeH;tR`OT%y6<@{4k%O8#P$lp|39Q~HR;Q){G-M((Wbp6tP zjA+$<#pSU6DrO|bQ^h%Tb}@l-9tJ}&xB0xxUptYvHtEme?C$vulT+i>NnZ!=O%-Nq z?cGc343z~Af2fM{`>QHT~;?=d8PUW2@i9UC|90RzK(=i=s{sTPlD+&m8i*8eml z+P|8(*#bV;Y}-9|zF9ClI&R*JGSgCtp?vbYg=~@8kqXHCQbFh-1nq>ft);? z-!SglYsKPyL9jmHXWqJ#HUfY#C3a&?B%iOsr=<;gPs)FQ_dq0mVoVY_jQe}^o|HD? zwS#oMk%!KE^q!P=K#uKJ#C8a;x!l7C1~21RUUPvLWM^lUnLED7|2*h6q2>9{t{q2| z|6TwY>hXN@`9kx_=XB^#^y8t;s5g13Vr_Az(3#zhavr1~<;Sq%S;zycc&7PWYk1)6 zyWcZ~0fM1HSD9bliF^^?0mTZx(X5U+I{N-l6*=n2#5#?P{I(Fwik(`0M{RqvlsxNO zT3DK&!K*T6Tia)=lc4jUoW;TzO&f)%9e+q4hifdGw={4BJa| zVmn~C??R($rH<0HtnQoEMr)t8ah<}O87<8fd zUV}1`#d|BA>{w#4wwJbrvahwW$qxZoe~*d5plNyb(NO-qPQJ4=S88`UrPji>c6Gdg zavoZq`)-VNmf7|?5$B>i;%8>G;t?j21%j5pI3jMBe5*OPK4qR@+s zz$5;dZOpfFd~^cAbnLTFI3M9`zC{kHZ(sW9P^fk)Z-*G&raP@&&ACxm7i=HGob2+L zIqWs&e$PND?CR@Z(s}K|&!^*){yK^NX3J-NzSze1Fbi{a{+DB4`2QzBLj73RCGi>F zkBG)6_J9MsiqZMrf5bUk&E$`{JLo;1KZLX&nmpD(_8Mf! zT)PiF7BuKR1is>u;e)P2jCH=Zv4uC&F5*{ylIKd7dL~4qKFsH~on&8w_Me&Hncvb( z_TEvx-{TE7uFJ7Ukm>`SdUu+w)S0izCpZ&(_Giquchq)ENm7Q>V@3=eag*9#UIQ9t zZP^nuBBCeDFEr&vLooi5bv*lekqrS$Nj9`p|BLCuxJ9fMeuPBZi%a8sjqwPJVUGr47_bi60kmX_IWxsma=Vi}UMBuJ$}sjHYIQ*tz~qO@o^VQEw34?iyS+kgTypxcf+~de=Tsp zP7aojxOiPtxEOirZP&fYnr4mr?XANYr}NWx1lhj0t;9iN7!X!^ji=)Vr;*QUg98EzR!a zEbn(1SSRoNq<^gXHn}!0^xFDI1%Njn!iNx)ref}7(58rR{s5djlK}N=vv%!=0OU3$y(+jAH zo_pz+6#>Zc3)ZEp^2^cSqmD-z{?IR#v|rpcg7wQk7&+uu?U%Bt)AT1<`X}Bn}*p985`I-2bb30JwkWR%oflkuLS-?DOv~e@^VdP$w2(sXPyMd)OFW4@BjPn0YY%le@*NS$vz3{+K($%@=D(`hR6dq$|!?%=mhw# zGyL@Jwb1n+O}<~u{V#YV=HMjsz-IW)-o5kf_kk+Ms(kxVu+q0rG@pCxTjC7zE%%h@ z+iw}(z4h%s8F{qZF_>$`PX3b;4w75^K%qiYB1L^=fIclXGj$fsmE2FaX?_q^imYjvqv-|y!*T7@Wv zuoeC{b;{WFA>_p#ExXjQ}%#PDE|>7FBs-MwU!6{Fgp(fJa&9}3|Ng`;tS&0 zyxluw9*6r4LdeSc=CLTmzD%oK-PYKk7B%F@HI34NOn6hjc`Ac+`nHPC!e5`l|2!lV zNW+|Cub<_2#8IE>zr6d@ zX-{okfy{`P8)U0o--@lB`nK&Q?0e6ZmO7Bo#gPUel~ z+{!#2`9Nl&Z8oiJJ?{%-R^l?H#^N$=4J4g9y%QTip(l8;AO)xO2Y4ZusHB_A)0myZs>OQIzoFN~Lu4ZusHB_A)0 zmyZv?OQIzoFNl}old^am$5e}?#}_rGMdRfY1M$-1ONbZ5%g`qW;-$xz5HE8Twon5B;}0-$OYM z`Ui)bFM0ko{A0Nt^FELBn9nSV#jv`>F#b7(FV`VV*jylV%P8JWg zq~bq$@-xzBCYjVj#Zl zKQaCPWg!0KKz!SuBKXA{2IAxA!c5PwJ_zH-_OA&3(7&ee@%(dVsV7e~p`3@s{HZy& z{p-uf`?ynbIcr-h4>8woE!J21V`bL78q4-yi}i2)vDi1jk+lm&dL6~}_s~~Sn6VL0 zV`=%{8!THt<1Z$o-C})eWg(LB$=CbhIG4Eg(O98RzR?%Uxg?6EVo7}R%@mfoj!`pt z^2?{*zv0@??%f-I+5JL%mu0EZ=q8(F=DdXMp)RTuy{gHhnsUzZ3i8DjL!-ZSp8nN& zoQHY2zFLQJ%1V39^eXrg1abgQ&UO98gG~Lz!X6l9q<-dk=sfk)dE)Cl_0xG`=sd>* zooD~md9(lN>gPVArr#sT)90Gb`vf|F&me!VAP?J9{0FPN@iqNf*p`%&7tdJM+;2t6 z`TVH%XJN$n6Rffc3Z2Cs=2^eZEBs;!?d7p8m7=%+r554;>`F&PKVz?xQc;4{hYylkI2oTHk*+cox%M$57v~KKdR8Ij!H} zLEh@??$HQd+`kZ&Jz41N+Kc|Sd95$+2vgTY-xk9IanagV;vE(odZdKL+eaG@UV3-kMmSsa8R^@a?&ZU`HhUD z?;p@PK52fAPc~01$jjXEUpQx7iQaQN#>XTK5EF8ar$9l(K^Yqt%CUC?_wItJe&4KA*1#+uq{xoNcf3YnK$LWDbg3Qt*(=HsN zEH3@Qxj^SR7wA0aGMm?W{0QY^~(xx*`Aaxnun`BzMzC*95s zk2CysZm@YfH`u(L8*H8vVG(~ePao_2@j?Csm8ULyQbo}=GL-=TiYb4{f2kWJCi#;H7bQ+b0a{^7Z8 zzu)1UyorCuN-=xL&#^$)Z{>e)A1joRFA)+TkMtLwdamBPH$Ip5hYo9uAgG^e?vL-NOUo4WPb0-t&q}KV0Ha*1?RNa z=)zNv<-WOqdU=lV6Tx5C-|x46g1oG=5I3%UEhgJhbn_Uqoknscp?ysZ_Q4p2v(ICo z)xnHIV=&LL7=0w82l)a$x{VqovKSoSV;Iy?WAt{7I)`XI$j8`=*ivxoCu0jS;1F=9 z^`PG%AH{HMD1~7i66(RYqaHUHeCWo$Td?aW+qTrhIwZtkA0Wn!0ft*QIX&+NEC$CFjgc4AU=x2}ekrct zoVHmE&PgFgEDo$c@R`BjJQiYDhfvOrH8_=P6ZX#=a88=lgL7X7!*ucxgY80$8v_iE zL1~PN3y=_l?Gp0``&@{T=MURIS0JNpVV?^zV*a2E_p})6Hv||QgEANqe-MLfG-8DQ z;9ARLjOES&9Ix_h;rcAVi1rs^b)8)`R64jGT7iwFfc6c42uMBOa%$m%fYH!tpJ{ zuui3%wT1pbAB)<;K9IqP*g_0q#%wXyOG&$w8qJxd?W17Lv@6G5q~eO9K_|{-!|cmW zheTekBtjeX9u;X;p4Z`lysYp;d5*WS`pxyC)_)wV8T~od#^lZQo|d18$#a~I$&a8s z(0?)}&oMS8e_~dCDkjgenEXjbUUa}a8>R73#`o@U!)({KWKm0hj+i+eryPH&x6I+p zo4MJ|>9&1NPWTMoSS}vp8Fe^3#-`1)Zi83YVeqWJ5-cdAzT6bc)0guLV!+{Ztg?B9 zU!?sG8~2s+@XQ*(;hFh7WB(~BynOrF53D{ob@$nxfODna@Ttgq{l=sEk*@KWXFsv{ z8t=3e-b56S{h#e&<(X%{w|R|sI?7p})zMsTOZ)IXTAn{S|5!Yna{O|6g&O*7>pD`|j z6UyW~$DhRG`oZEcpX1NrwV+vj$8+MH`snsyJ_oPJ_V#%3_Ca5kImznBJmwasueN_( z3NP+Y%5zTDcpOh`UgMPvp4CwXYn0KS6FL5*JjXYUm#6R920y`z+YgphJTadaPi4@Y zuJifvNgb_zY;Vfgyt2PYdp%yBK>c=7loKXuab$fokv-q4@x$%upgT%Y4lV(WNhK4&~B+Vx0+7w_-XSI?i!=gptg z&)UDfk3YE{wf57WT#wnj^5-zt*n(#> zZLo*(v^OR{pOVKFWlsInKPJz4(bwN?v^YWF2 zbSRH%>Bmrh_#&eZ`zPgXM2GUQB_?0wxaw@7you;go^j9mSCUWHo^Ef{)^8#@lxN(> z$}?_a@?3WW^3tNAJm=$>Jl82{`6Qx4d5q;zd5+V8yo5w3&vuU0e{fbl zYCqd4CVxm)K59SPDJFktN**t;G$XRsA1tz-V}E!;f@9l%_~Jl57Qd8dJICZV2lBD_ zr99g?Cch<=kHjzK?R>I=bJ}Lcqv1<%?%NOFcZtL=SmgSE^{?Pu%ijn2Kt9ucV3GA| zO#afWe5U;hV_5&&6${&J#H=rP&UnJ%+LQ6A^LD=Cb)mxsUaWsuJbZ@zqsVzs%g6c$ zjfwso@duvg?)l21E+70o)$=-+K5t&^2!8?*jU-mDW78?Niswu6sH zk>^+s*he)eKVsU4x=?O^gU3AE!RE2OZiWB!UakvJL;XERW z6ZbQ5xE7D$JTi(C_cL+0CXeAfDvA^LGjSM)F`Q|QQ|dKGk>^1f8^=691PSq)@$a=s zdD0&sFAF1-h4P2y$k&X#^aZ>t9oa&W?@YIYD)JhObhF;b=rRKuaRjSVZ{bC4yR1HV z_eGLdgA8$DFNXrDgX<9OBaW{+&+%91aW4DGb(E*-R0EH$1N?H0U@@3KSYa{`pGWIx zpgdJaX$()9_ImiO0X{SjYT8f4;(7z089y~qp7PW9sD1q(zenF{O5V2sZ5T0r;#kD> zj>Tm@^b=^}mu;X0^`zTl9PJad$F*vHqA#%K6a8^2*C#qpJ#?PyJDulPr}LcOY@Rk* zJvpB{--=Ft;vnC(Mknw~oLJkL-yccmS*G*Irt+*u)9F8(*E-FjJgrlD9=}$#2ko{P z#Dk5gyp99Xd1!t;R*{~k6X(8^PNmU-F_<^*T$jPB48-F4+v=@-wZmX(-P|=!63@HB z?{C_E4^fF<8yC!TK+t)v<7{5nJBRXAoqhVfo>yQ)YFuYtw}Gx>K2t|J4y+xNp`O}5 zv_t2)9@BZ8OF!l4k+#EsL5sMy4#oxNYm31=`F(Ezk6XFt7vbo!L|NY zUoHx$Z=!Q!9`Ptgv4eB8bKY8){(v9C`LB2~${kiBFUth_>>xF+(!VkJQv&(e{t11< z`f*78%o7hsMxT>VsP&2MFH@fWiRok3;)wmkAF=&8%5$EM$(uE}mY3l(^asb6nEVLJ z1N~(SBb4X(6O%tNB_Cg#gGJUxs3-K_@N!l@)1H*4|6}qy1Nm5cQXa9vL+a;APJ0gT z0?qqF_DdyXwLd7&aVDnE?yP*&9*$cv`A28vGwlf$ndf5i|B#i>v?t~Bt^xni$Xg$X z@+f0`a=jPpujuO%-w}O^XBa#spYaFfIp4+P&kW>a?Q81?tF*7hvw5~1$~b-&PY>{7 z{gv{J_lQ2j|CE)F+Qa@9lYdNBKGVLepZz^1|Jba2rhO@&7hfwW`FMZjc*8j`R{!I& z@)`Rn&vk1=zIbXNA8SurKUk$bEuPJ*_8fkEfEQ~|%5#kt(P#LEtbEiS&ZRN=8?*A6 z_GJB>Yh&_H$jWEhlk%LqBl5-5j67)Qqw}pgK6%KwTSdv(UFewkk#zb4NAafQlh|&r zi$(M?>J|Spe{hgLB*-5cfN&#Uq{9CK0^i15i#Zi#LgL9>n9bq_OrQ zo$VFzZ}EXBcUU>?O?j@>Bl-+K)5u$lDKg`rK71B4Pam%BB6!6Iq1<8R=)<{}V`W5s z_*q8YVys7=2lZLsM<34R5xnBnD0f(W^kMu)lXU z81patXHGm89}Jqq>SIriKZc*1l8@WN`t#(UXXLF88nftQGkQ?RP+RiGWx~#ah~&t=v2H0sF-evmh> zyfBU74GS=cmxu8pgW+^Blcm_EH>M+)91~-=-Y1GH;w2qe6zuDwwVc4Y||4e z_(GrO&GE0$dQJ4VEoYrkd_)?fuWekn$85XBU^v^%kBHBYd_GhY~L8h>kWqUgB|CoSD$g7dT|VjVZOm&ie8ocK1IEl zVi<2U7)~!czEZC~<16*zdN+poCW9$@=?ff`hyLOi6vKG4!ASIKw0KR+qlk@>wlbA? z*P6KD`Tj_d(QPRCn@~r}LE2c@t+vBS#u_axalf&T*rmn+%$iuNwX6 zGp^YnEAK>Ro@*YR=QX*`bKPL`#4`04?!dXP+ihp2{7ZcHlbHOU19|%bH`Za-Pn2iB zi^=~bE#GMNP=G_rGfxc4TYp>q|B7;@e`n`nbAkM!e55_4pTEV(Cm47e(6*$b7rSzf zRc>!rhzC7n-b5WbK4d@jEQ4p|D-n6x!u3)tUf*iuy*^0?Pw?2m0y-Z6^`4uj*#C20ZHyJ=saSJ z_nn1KSrZS%jW~C8!CQ6njVAKgc*LpnmzX@SLDTYy|3i8DJ0`y&CGV$jZ6E!`I;=eN zJanEhX7kFv;agGe^}~L3#6IG2?GuxKM@BwtALSVjG5L3<|hp51z{ZD!JAB(U3a~sOj@>%;R&$%!r|L&B$U;1eKc+T-u%X9qId5*t2 z51-0-^B$CY{qU?@#6IG4yo|}eHzS|5kMbO^WAg7a@>YjL8XXD!QBVD$y$1()VgJkP z59gWsEPkH7T<=HpEuNE+kK4;Nbxi);lze`?>h@xMaDKIT%!lo3+w=Vae#}0~hw)%ZhFo|2EpD_BH- z_*s6xjCqc?I#2s;UbSEGe3bk4i;u5hk?}evzbPZ1wU6>_zli+sCycz+!EAR(yy~qA z9k2A49$%Q(<2Uo%$B4vR@jfVbbz!}q*Ph{c225GcU6PT{+ROS6j@Li@$&`G4d+PB4 zBB}9*c|AU<_8k5cXx_g3_RO14KAn-z+Q<6y#-Goml>b@ea$8|6E2sYaitg&yoMUk+(ihuEr4Cm@oAf7BR3=p_>`^@{GB)k9i$m%;&^Q z@p{l)U46#ay!o!3kaOi$o`=O_KF_`{f#&Ut_eaX++4nC-UNCyyTBD8v97Q?D z0M?z2zEhq<Ic|!~LtFB^VxoIv_43W^pPuMdXXqS@}|XaXUp)>vHCeZ!$W388o9` zp}16AOn!X>{Bn*!w=dE%m?KIr#wyy=J)6P4YV)S8Wo`Wxl(P0fq+GV+ZmOthuL zz^Tl45zGQN6BMR@AqvVhCgY6>*EOOi&q=p=t>?d?++&vNy)J9X`jTr->a=2LI2Sv= zioB9v%#-IB8U~^f8QYq%m^a4{S2WT3eW>|7~9D^-Yv3z0k?ywh@E#UQDlV zg%~-u5rcDM4CCJohSS9?{w4mo_|IuaV(NBdp6jWIt;Khu+~eoR2IF1(i+OANO*mKn zD_)ky%xx3OK&O;m+((G$IsEMurf(5q*fEah+&75%@;}n@t~Ek=uCrtE-!byeS7u== zZNd9^Ic>rChkni`<_}hR)^Gd$f8yNZ=eGrAbo(-&*S_~nW9GI6+mqK6*7wZsuku>Y z|3bOfGu{@olWUlmFTb0XkG2Kn56O|g-N-u~%%V-&f{V63ZNYW8wUKpj-EH&Q#_yRr z3})__Ntv)8=zgLwi}y=o=C%d(f=*5^=51UCeQo&rDa`z~$QxsRke1JF3(m>0w)~-y zcWp6=0vzHu{X#vI(HA3Tj%IvuVPbvHJg-4)UioeKM=1CBXy2Uim>9M_S8%Q|{yW5Q zmZs+#V%Qi7F@BuJ=o=H(U$(ut#);TgygbCrv5odK#oFK}Ax4gEl&4Q(7(Y#8{bwOYj{m3w>x%jB z=V^>w{}Drv56p+-2Vzjxfxj@A&c5|1z#+a|pYK1~8O||!4$}U+61*Ni-+z?J8_$0k zV&wRb7|69-&fGWrD}(9m+kgTb;y?W|L6lLq5j8gHbqL1hU1)r;Q2vS$HG9{*%U<=}k@Axk=7FBK3Ke z8W%VY0JHcMeA;%z4lUlR`?LVJola=#)yeE#sbG=9D>I@ z$7~!S{_tN==9y3IDfM=D>~EhHk+0)Ly-C!jF$tFE%Nc`N?9MDzO35y>wuv!nj!>WBzk(n(L3S)h zmVU;Ok-Y9*sd^&TTj{7;i$M#n@Tf(NrOj(u2Y|{jd1u5M#EDj@(+joHK>VVs{Go7h0ZJ!pu@^#G0x<||Ps?XZ3KBBQ%BCwwX2F~;)bIjCEm1c$#1 zhu7V|o_K#B zMQr|boUfSty+FTkv0dL$pKW#4NyVTzUYU>ohI}zo$2$8uI){4=*q#bru_40WZX_dt z)r0&`GyEch---5CCpzp;yW2ZzG8h}Z?upMrN@o@%{D;DxnM*fcaanou){^BZjXFC0 zv6QIj^v1PU@##h$bLX+oMgAGcv(2b0j$>bie@1Wm1TfZ4K6{A=4eh{W`10CI=K8tT z!qTpF^3-Oj(Q zj~?%pp@TY7ubT_${6mZ$hAw(NN9)zy-8EH-o&EfT>##((K&HQbo6t-yW}#m?PyMKm z(yzcF()n$2dDP1H(+zzy(M|C~u8-gH+YfTb-iCkFX$>B!cmQ;y5!8tX%URz6jpnx6 z(wy$2YcK~EF-BN>)vk2qob){0sm4 zJc=`RlJ8(79)s+Bp5Z~<$+$;;*KSz%&&=7VPq6yghP7ERh=?Pk*C*-CnH|^#6>v_=UZa4TzKTYQmCldFjour>` zL7Di|TxTFVP(SGhj%#_{IoY>-+q|C z6Z`NYQ8ly=v{A+($V~g`!0HvXQ`>?5DaW4J@d8MwcG=JDRbWpBU9hx<3ckxw&&#GM{1&Ltma&*T#T!abwy<##K|N)ZH(h zUS#xxpQL}h#ONsPz&!%wc@VE(AI4aov_T*Pu~0vWeay*n5I0A^V?PTT=}c@##F^|p z*gV^T`kK7x|1#vAf4M(_JP-1$QvZ|;#G?9}eGS3g6aBgGq4lS}O8@xLGK7u~U!Q|~R#m6p2Zm+ld4m9e@W zQ`twRu{P5E5w^+p0q_I|ADQb{u4SYSH%8l0z_qVn&{t+`Ew12P`MAjOQ~OwkZSis( zivyHt+YA=lPh;8kvPh=QoKD8i865gjaOAs+CUn(UrF~<@+R!)q*)^ezKk>Dk=s|nT znku6Q*HF~MrXrq{EbVCS?xKtb?GYOyTHbp=Y;~v>a!EZXKl*BvFU>bcmO4^w+x$50iL-K3_i<+w z3RjLGFa9Q0qrG#%p(T9qvBM)7>`tC|iz*WoYi*xZ`FnlsGu9>(`#&o1fN8yv{Xp^{~$HWUVCN@43 z^=CTXq!aMTG-A?;_+&cCq?7TQZi8O_@9%%#8Mx=9)&P6&8X%o`GNRL9A zM!FWMhBSjzM`|E7k+vaiN18=yAzg>G18EM43m67Y8;K!#Jrd)FvDiaeLRv=JiL?ue z(fnwne?a<2q<=zs4ANtfR*)Wt^mwEjkZweJ0@6)LPeghW(vy*%g7j3Rry)HZ=^04R zM0ys|vyq;I^jxIpAw3`I1xPPMdJ)o#kzRuIQlyt5y&UOgq*ox_g7iwHS0TL`=`~2N zMS305>yh4o^hTsNA-x&tEl6)gdK=Q)k#0qL2hux{-i34<(z}t~gY;gc_aVI>=>td~ zMEVfYhmk&l^iiabA$=U_6G)##`V`Wqkv@a;S)|V)eIDtbk-mWRMWinw{R`5+B7GU@ zD@gx_^i`yOM@avT z^kbx-ApI2S{~`Sh>E}qlK>8)p{~-Me>DNfVLHaGy?~s0v^uI{|hx7-eKO+4J>CZ@i zLHaAw9Y}ve8b;a=-S(mQq^&l;n9g$@Cpr(|vp8Fun=8p?F>;B_K|Jy0rER+#O-s8g z)(Lrg2yA=SxdubdwfLk?#~`uH>heUK7fpWuK4bVjz$5zA+w(JRyjH%%h41L{hDi`` z5Kr{<*958ku|uH7PAfZ|m4$ffn&YOznm=qcxbPvaVbb}BK`ZjLZs&BX zJzZ}v^cLH5D8xbiV)osW#2kL$9mjrmI}&8&AP&oK!RPHr_ORvbH@73vr#x&q`^N1^ zutg4*<6QJU5a)?+<(_e=w$Pfd^;+$PgjFz(;JMvzUbi%Z8$_k#wsOK`@Q!2u;bHTP zb=$tE?|7UaNGwA?{v_ltHTlp#qEoZGVSK{|y=^YCAusXnjpTKl$F5dO_GG)kJp;ta zu`|||Qc?j$i2>gpzX>YyobhCJN1VHL3TaG;$zy-WH4ScjH|sr=IJ>Y`IpCEeKA&2v zu#U?BeK*j9c0K;VraWk;<7a|<97~C6){n>Dg#4?0eX_^@8k0vG9KU#}yI+6#RaZZ# zQtsa`r z_&St}?(R;DlN0*u4V^rRjZ5?MyGxEc&(6ca@5hZsS_mYgL-gL2trPccqxa7#dnobU zZS@kOsn@`pcvxz&hql7LH<&zPZfJ9JS8uvLhZ~o|CVU(>o{a46NF3|z*mN+4EjI__ zS*>aRh>6G{CS~8?jSzVg(wmXq0(oQC;hf9fYVxe(ML6eNeJm0W^0A!$XSvJ;s{CE1 zT>NOtWASABo9iRaXZ}7q>ykN|x6>MoRgShQRWEHo)gejPcnNC4;uZ;-1fRc>=Lw;}OfKV08f!mq>K{4 zwaxK=z`1Q_`0w~T+S|5SI@*MLsS*#=hX?CA43}nWx-;FUj1-?S0@Hsg54_pf zR3Tw{pWbSU7>>iR$wwJgsoV53WTS`O&8icmO_e6gl^xe@J<3d_g~v@#UR{r{8$S zaZhZUZ!NSi1zIPtPU*YOt~7(S0sXD`E>jQcJ%RJgZ6=St9euXP_T!^$-F#4NaT$XQ zZsfF+=MxRS%th4C=GPh-=6Ong73=fjN|qhO(k`xNfYzADTM66Am6+i_;R7J^9DW;y zUvR9*e@p))a^jE1;(TeYy}fN#Dx|0VVHreRFj4nVHOZ#_Q`Xol`&kaZzBJRqQ>sh7 zq!RMUJmh@NIvkT=l4lk5>~}Qyq@Kmve7oK0Rx1^bR}O>mQ!q51rg818A~Uk}{Rv+; z&NB9#@B_%{c>Rq;rE9Ab{w9(xKZ1CW!^n>uUMN;sVDhqVAPvW=>to-bsMI+<-QA5{ zjk)ghG(m`kYx0pZ%CZ3Lmb)E0T?h^Hz(~o`cC{A9$C5=Nk^BpXk@>b}Gu2sibn& zP2MM2Uct=gJqf%oNbxT2SjIDeqYAoaf`{1Tf4$`wJqGi?&+>~d3BOjoHsSq2{Lfo{ zg`dZNI{3eB`33*FPILP-EWnd&i^>Sq)~w@KDH-V0T&U|h>S>!#ELwi6Qy=~j+(tOW z@{3Nhje19W)IT3h-V-ytS`+^~=JDViwY(k1bPW%`xNzQR-#^ZFBJU>4D>~%!B3@3s zujLi{_%c%kJeCBk#l6PziVn-|(dq4r+ai61Iy3{`isIG%^)T=*THblshR6A_T_ml* zdP#pwmM$xKOMgn1J_b?gkCb|U6UK?;}zAn$@}&QFUO%6 z?}u`EYi?k+zWqXkcPt0@TM^#z2rq{D6Mt03W<;0&{QQg=@x-6|a!ji9M&d8he(Pyt zA?;6|HXhJULSM0UVXd6PJn62UhHIBJ?OvWX71ECIwDp>X>-&?AOKAM5qmn#CBX*X$ zbIoSQ+Jp7ZNv9`#b9liGS0p)_?YDFYyW12Pb`{T<^B{r4QT=G0h?VAniXD&A38n zi06}jYG_uBcCh?+zTAxsEdQG?7q1!qlke`!-B8VX7ay;$La|u{HK8bK7;tX$*XT^2l*c`nBVz> z{Er;K-!uwY{Mo_$4*yi(cL(tMZ!sh`(?^dTAhWoA#`y@>J10N6+?cORNrHhGKl$k_ zONXHNl(d(Yx3w1Mcj9`g+^x^I92V~9oqS80R_-jed+mCAu3C}i7Yy>fF_&-3;jymU z6knt1>pBRu_j_8q(@P#5qo3~q+DFS=zcfqr`jW%L*l_aa%k!;HE9oaC+1?eh=tcV1 z`_LJ;-xE6DU))N?|IekI?@ddW|DTleePgNeQ--9R@0m@PA1LMcjrE}XC@G&zm18_O z<>c}_hMDf-a$<(q0sBu`TVC8z$Cou4%N=L`!6={f<#^1q)sqcGaL{k0Z!vW7(%f=t zKNHuXr(7M<6$&vhkDRh2&Qn@$ExOny-%a^^&bQ=yWj>!9YtVMZyM=sGTVfmb6;An3 zhVGT8?#F@Wt2sPQdE+bc{!brXF~IYldXGN5W_qzPSiE=0Yrv=@>^SxG3_WAVspseL zMC>^AVSRW*JC^(KhIZH(bg^U@tR2q@vH0Y%2}#o)r@k?VCuYZ|`|yT#e6J6$wgdC$ zsec78CZ$o<8O*JxG3G4IgqyS@1SK_CgC^ZxWP*4|Bq4?=JUdn~U?cxzeNY zo%61%1M|vhpG?!r-FCfXxE8cB(9)w)DN@lX}=o4YYcP{wl>O-K>m)n zJbt1eQ`hPD8o-;b3-hC~jCEoE;Pm4H`MFlFH-}A!#ip(;u?-8w(<=k{O^pB&6k8$c zW1YC>JpKFtquyM=f<0Rwn*H=E`tq8(41leQ^&l2ce`p}Py|a|6gnWpJ)0_ExrUFV@ z^u!M0F9dQ6Irxvx=QH?}OylEP<@6iMUF-%|E2G?KP0pn!P;ZP4r$3_%y{g-0xGk!$ zC2{ZL^yiR$hucUB_Ib>F!QvB7Zp6-A@SVWqTEq@RXp>t{9IrWLN%IM}33p`H{9F)}5{5)>n`!zjM|Hm~wTmOlV)O73$1^9 z230??v&c?#wAI6X=FLAr5q z%|3Z1{_fkKw=8d^i0JTOEf@HgI_SRMAl>WWxUCM?g;;6cTpgB`oIFku_~}MXcb2<8 zcBYO&+<6IO=*(9s`S9K$=F>A@m+S-MAu)Macdm(vi#Nn9679n{Uid<}HC6{{19dQg zN*d;zGvAb=VIjO>YILkRA;XR3`M@f8{w2aQUY(GoyT$ph0X&SY-;{A1y;Yl|y5YD6 zTh9DLxwDh^(>AD1YwSGpuZpJci9qhGAw?TgJ|OJ?MH^Q%`1oGWz(~x8jpl0$we8J$ zth`ux!?h;sUWcy;y(XW}P<$&v#LlBhWZ3mmhBFsDS zmQEjDg!!#T3diaMR_Y|~6&`nrYcnl(jg`ahekfP>a_d961uGZCH0$fiURs0NxDaAH zk+$1oZXBK1;B>*9U3`SygTrc`!r{C|`5U}^P5X%Q^-w+-*D3!DC6DS;^miGMW>)K>%<8+-%Qbb3W1d|5IN8rm_R&kTJ0XuJ98D`zo;=SKo@7tm@Nnhp zVx2rM7oKE)-SD`Ov^Z}To@B4x@Ngta;k;jXl6`l>BhQ3F74ZY>`mFFId+>(Gjn1qK zeSYoN%XqORt#Kn|B9AeD?Z2mJa!DeaSCqxvxb}Myx^N{+Owr>s@ck&C&tKrE{z92w zuSTXqYZHAbbH{3A%!QP(VcnWsnFO4Cz+QJyK3|><>yBNGOxlKZXRbyjuwi|!Ou}ew zI5(d!*M|G7MkcV~L93BbHqgH_tC2Aq!PcJkYGfuPL?jjwvu8XuS0(|s*#DT%m+Px1 zuSO>D)eBZ5qkM(=V%@7Klb-JE*thOhH-dmkRgOJ0b^4(}%m+KjPa z-6ya<=ju+bmsEeG>=#n9Zs?SHDf@LR%gI^ElE!tv;L3)UZx7=B*x)YiLd7!bCc;Li z!i&p|Zi^&0k|zBfZMp8(DOxf5Hb0bzzt@$1RpIV;Lj#ztjxu7vL)n6E|%KdwVc>vQ;V6`$Euvbvy+3O8FhHyb%W zmo}$pxqdEPp3mp(*Y=^`m#$fjjPf($zxdx}K3B(}aMPmLkNZ?7UtDeo#Z88=jj@Ei zj#5L@Qf6e-b29B!$QbpU%%fK!W4g4+u$`ZfCzB2x;inIN?tGA5GlF*VZqVkX({OR* z`xEwsN>5MIQeLp}fM+X9FX+P;dW-(0%&S)=lX%O@+`1|mKaU|+Pp+5olnR^QtvKBp zp!DGsEoEM)w)m1U`1#eys2HTo*H#%+!d-^-OrH!^(#J4^qse0`ha=C*Oa!Dwl} z_cV-*Y`Me-kUP8JY4#FdY$fd;o)$i9clHsE<~LkTeP^HOXm+>3*LRkqabF~@%Y>tG z&PdZP@U)B#_w}@l4G;CSj19Av=7$Dn`;w<+>U+GWW$JsTr=cOzHoVN!GP=Cc(=vW} zkE7Y06z|VZdK!r7`o3&wY@&enJx|Nn_Zv?O?JEyET1J=hVV)LZmQVGx4Ca)hK`gCj z`65T-WRtS5e5IqY0n@YxJ6a|_%a8K3jGj9@Eu-gdPYc_x{6tR++pqk5Ps4S2TF+N| z8b+uz?N(1St25W`8Y)n)WhN6Y9kdYq?)^^Kn4Xc;|6$2~10cYe9C4bxzAH0UdsBS$YPcj_%{ znlvk3QI2(MLAyLnE6+8z*Xp}Vc(S6oxVY58%Ol)|yEGEzi1~0Q=P#x$W;0D&6(+{( z(O!9})ux)kT!*#u=wr%FKH;#?#GbTfV4b-BAH6Y4FVEu%e=1ELtcgaS65;9g=I3km zQf*g@mTqfprvMJhU>+NNWkhCiSLynt=28>yt8gNg|F#H!FNdFg{A{_4ub9K8F~&*K z5r{?FmmJM6R7s<+zKUxJw)dF7w6U>w_Sxn6dE5hOjs<>%++l4?QyWnh^P86DFL?y> zVAO}_loxk*dTgF?)%9$hqdzP!F5s)9ATq|FBo2%FljNGHIiUnC?bnv(L(|Fq$kaUl?d`1|Z}~K3)h?bQ5B6^>=agr6qE#38HUTmy)5LDv z>#JN?j&)6NOTYK=vmU%#`tz3OyAt$#`HkF9Yff<z*o+DY)0V}5voubHN)FFuRc=nv=&#W! zyj*nykx)FNt}(q`OseBbmux$1_yD@ z1rGO`IF8SVjs5J<`gC?KHWnNX_4&?T;n+8cdjI@vFL1^p{=qXJdu-R(bjCkpci$_V zjDND6gMwqW)K}Qhw{@o3D!W zpK&}(w<`Zz`5^wsYkMdk#P9h09?FODhv#VbNdGYY@SNTr$%pax^i|4VndAQ#@1cC? z|2OQReCYpo@1cC?|J9D4)_(1Ou7$s8>sJ>x>>CFow*T2Z57?aXS7OPUfpm<$=6ON$ zQmmwF$=F8vHxyl6{x~|;h)!Nz0y+Bk6+OKEA^uMkU0nh>d5p~tUtI<{`tKB7UBWo} zpA=nP#t0q0nlo7ZS2R6lkal-P3!aCZxR;{o=OHO~n5DTZo}?{EJ6h4g z`i@t$u)b3iEv)Y>OY@gd&UReX@LAC23}|6}Q;HVWcb=l@`fyD*aZy=*#1yFFZMniS zu{d!l_MR5;&QucBrJ3k+2xPA+&(~UWGi}_;Zq`+>QJ(Z`G+hN7>F{6Sr{=no&*kZB zyQ3jnOVP@+c$#~>QmIbp?=4iow>^)q|E(~w;bh1!<;r7UZvk(LHQ#Qd&X~t0{%J6O zyk^MrusBcKGo17dGlN4vy)?i{evP#{3E#-U`tV(liC3rjI<4_WXIEuxbbY-#X)dcp zH)7(sNZE%-+NHds*BGlzR;uIL_t?*xcyF4oTi>u@!&G(3?HRCrK9a+OucDaWgXxy} zQ)u|92=xnUu8$RdY30>mLz`It7gMxy@^WCjG>e9lhcRaNHtK3HGPI(-UJjolWZ(WO zz6^kSuFbj{geXVHl z1ggmlL453MO#FE@a(Kg2)lAHk!?O^Rho|N64Ng4y*Q(3wq0_Y{l9W3Xa+S1Pt5Ho> zjHDxWCO4$%w0F6=*u_hytCc!a{D`73FD`h(9IC*a!>=h-&-uQacHcwcxY&7#Nh{w&RFUtW>$8b@2+Kcso> z!(YNXWd=6myQ%#HUi)Bl!tCP>^U>6ydOix~bM)(}W3zkD{-IanQ;ZE$CzbiNqHWDa zcFvnxC(n1p>6AU!$_8^Do{yTkBt^pmGV04nw3j>&O7kp@2RvxQshKoSAc9?~)mn=W?6=i95^l5zkYxJaiEwjy$aYi>3}~ zIx}fm+P5q%*eAw4w5cB@-;LcS%O-Vi17q9NFVZw@u*%c(^2J&`FQP9^VQtFq+gh9y zue#+W`r_Rm>+wCC($C?hUg%@6Yh~3ku8g z(F~8js<1qt&hYq~D&#@jt;ZTUu?6>ax8YlI*bK){^ni$iJZR_j$3}ScZ|jg}ZG>mR z{4zapaKCl^IXOI~#^N$Y++{oo=;DI>R}bcQYXb6j2J_2QZuNQUV1Bv8wEV9d%rBRe zmjB~}`DHY<{NEYOFDnD`p9FjVFT#(XR|>qDv?KU895jeujSJ*Ia}d8-7#V#w;8}!7 zEGd1=1-s?Pa|ZqS%>}yU?+xNta})J{`XGMsX5t^j&xTn0$}9f^k5V7<$J#gG*YUX_ z*1iG1j?WFT_6_)Td~Q4>VsF5&<8xzaFu#t^jh7DQckzku)i%cD&K!wYHV{W;eXsm5#$fA0w8|eMg1|Z+{E;@I8-nKOE)5CP^ikh=@nu zeIbv}T#Q;iKmI@`ynq^Cqvr=M>Zo0!AKUi(9xug*&g#}%M}Y5_p0Bec+aESc5-iNA z=lb!h(OAUgPahR5?;`l>SAmym8Opf#w|@z4R-2&d>08O)Zb_SHKV)ubt)b<7uMMhUnV?6T> zR~Pn5&bv9n!ynzjOKun2Gs&)_^~2jeZ*La6qWI@pk38rX=lMB$8*X%!`7hJA(I3zA z*FBoA-Zjfx>9@rDva8ecdC$83eV$*pX}&Dpj~(82Ja<|t%m31Rt2Hlfk$Q1$e%^1Q zeDH9~HJ9+>I(Abr%8RE|(P(D*?RfpQoUR{Fs0O@fn@z{XakoQTH*(SMwV>Zlm)z=3#bI zZFK&9qI}UdI{(4BylMZS?ay!K@@CrTe1Dy#ZK4iFS>HzI-;jfgw*rJQb^dd5d9(Vy zGM6{2@2&Z~shDC6`28?%+gP@rp8ur?rtn2#;6L+tgBbW(E?+tZ{ut#G|0f;a`~QNw z=JTd(M+{tWWDakntu8n%mp9}83nueWE zQ+rP2o6X}>drjnv#D1cm+G8Rg_RYqPis`u(Hk!^<+q>XT9Zo)qDW`R{oVzL*`i zMEGKMyhZcj#Xw{Asi=N_ZAF%ZFQ(t8B6zWSzZ~I<`R_ZLZ$0Z>AJy+C5x$sTeiz}3 z=yzd3^KD?g8)EfdxF*6EsrSO8B7CuWPl@n_e!+V1!coQ7<#^g1E%Ap_>{v=3f1iou zglBFs`4v}=x8&Iz!Qs#9Xq+n}JeVa@Ji33`y6`e}x39vwaNpL|j`O&C0K{2|^0ZU>JSEPP(nt38nEx((gRYD7P?z(SZ4Ed7 zU3goR&$fu?`&g9Ewu!k1ws?Me8Dbc!4VVtSLu+Zx5Q zJ<9VvB9AZd%WNKB;Fn$=U*MNi|MGS;!ghOF4qiLZ??rihfqt*a;|uh=Rr7IO)g7C! zxDnF(??X|(Z2NvL%9m~5uSNON?Tfv+i*AqeHIiSLN%SM1zow!I){bsNzVvO@%^2@4 z`d^L5by|1aS!>44iwhARYpLbAdxXbYX?aq8%+zHqBoFpZFFrnkgXrb7B5Qr}oF3&# zEF%ua&5Qj!cU`Zxz07|YH`Dvse~C_OCx;YUMH@jFMg2YME0Gud0jXZY4^!9hnY!0P{wI6P3_q@S zGyE^>!;iNYX88R+bXFg{$uPtJi9Yyvt6_%!>k)qFoonw;`tZl>_4gmW{uV!C@8)~< z!H?Lx`NTf_p}mOp%@bMvQm>h83NQx9e9T@`s*1y59TCVhhZ{@zQL-$!b~k9T};Zs+5d#<0oW>$Ml;rVDiDLETx; zO)0tYQQS5Y#pKNOEYJV^fZy0Lo@d8v`|yW$P@i}A;Sa|I+WqN#{?cfU-IV)IAGu17 z9QFHcC^u%@wQDTaj$8a5G20PtQv4D7w;b9BKeQkEY&p3Pe|V1(?+@EDp3k4L+Qi5f zKRz29&~XxDcwL`~^)3Fo!?Jn)n9Z}HP6|I}^R7PpF`J*1&mXlJbNrTOCOrIu zt?4lnbKI6UWr^~<&>U)C>+d3-^={+^=NFY6b7 zogVN7etAKp-blP$;_tn9yjZ-vHHw$@i@zVQ@v?qV^M`8>iL1abUy0V6^^3nR6V$8x zf@_0Ie(Le&TlI1W|J+Dw))klhR`D!>1;3q?x(AGYcFA8n&rXg5_?H=z!FQj#M)<<9 zn0$vt_`)%md?T6>V1Uf z!{oSgemsh&<|wcvd@;OU1TSXCN`x<*yXa?stq#>NFXCTRzZYq|N%C<|JKG-qTAeHj zU(AkMHQvT3zevBa`<{~#F;(hQTIw*ouc2`x;OwWr(<;tDk{AT7iH--pN zj@4DwU3I7a{pwUzPhS*Y#HXMHf<}}eBEH0j_~O54h$I9h5JJd9AR>w)VniPdMikM{ zcdh;JoI3rB4_&?X+H0@z94`e(m@4(Dmi}2Ycwc z`Lag-8bc(Wd1by`D&t`(5hPng_s4qaa?X*i&{qY&oO7i6p%y=%=+c0(r6XNy9t|Vi zdA`S9e&_k-Gh?c0yh%Y|)wE7?u(yIO1d^bbj+(fH?U`T zl#d_$vT^37wZyBxncHrrgPe_iSwS_$IR(}Tul`;yU3={$x}WT)3nw)_U(x;3Ub@*l ze5zr-49=Op`ng^@?s%H}A-6b2^Bl6f6X{@Gp{O1{e2l&kje~!k`58f^#dK-aSIst?#~v zE=!=CZ(cj)`s#(5ZaZf`ahtB2?~j)GYE&(UXY*3+{I`4Q&h!0=N9elwW}T%hJ>R}| z&i>_+?mXXouB}bi&G%Q!@*&oC%TlW4cK#2&bm#g0w@2u@`TnmSx}Nd;`rCTx&hmYo zb(^Z-_0YKQl=kMX)^{=WVzJ^Xs+@9V$u2wgYdzgyB> zDc{mkOXK- z4-WPjjgQ~jdR<7vi7m*-qbmrr3uy6@}dmro_dy1eP58%z&PaZX=#{?om5JU~;> z(T1PmS_(2j**gZlQbB^`+3y;vnoFiTK50?41>#Oqp^CW5b7kcU1^-zCg-KFw{d{Zra42tgG_wgIVS~#8B<-fM* z##RrlFT3^l-@SBa^?38`y>w^wc=NmZ=+5i$=6ieT&g$_duglafS5^;6!A?EiT(|f| zy7PKuTe0MKUXQQ$@$0F_pY5ePug9WA_sr_?tfwA%ZKm>Ny3TlhlXX&?F6JD@{hPct zE9uVLCHpPfblrTj-=a;|%{SYCC0)Cn8K-Z4w$(1rtzDj<%a=F5^ax$Id|B5h-^{OD zzU;Rs>CVgdo2`6bSovO@m+$SjK0?S^@#bN_uD`2<#(pH-sb(KHor1o&XBy# zw%BRAv$qG&{4Z~RE#-N0c>e4;pTYCn@zXqk*MCfOy6b0fd)!Rjb{eFx+#I%^SDpVy zqMt4%`@8x6BK)tn={zxg_wKhPy2X4l+by`Z;9|j@F3}MqnZ-9h@3O90_|X)LY1vwI8XL&(?ff=pVK%cwYR0({m&Bdj(bhs{k6pJez~8oc+FyPvpUWX+wEcDlh^9n#5Uv3!FPY>i_+X2 z_=2{Xcl(&LJMVt-w@7zC`7ke<-r93Ox_|!vlWwtPTrKyXTPt|ms;s|wp7wq<*<9Rn z+u^{{Sgt9d+D~QucVCpwp1r3#)9Cd4G*13|O4rOc&31pWUW~4;Rj^F0JeV7weM^`2 z?qRPkAJ`YW&Xac=Kl_q>BFq<++vBGEp7uM5`-<)fC}PC>cY^^% ziz2Se^Gn44QM+X`U$H5k-wys0o9B6cEC2U~YaVz@11c}`cYyyP!*f%oVRK!k7m`65 zAMBhLaVj%!*18sY9JvSdVmRWcfhwZxYMQn# z{NukL`lJuK^r;C#g~(rJU~awt?T_VgR`hn-KSbKE{1$0rwPH%;$yv7d$#&|N(>Er( zwTikSr`{)@bT^HLMQ2DUANu9}Cl_2uJoqqwFzMxWW=wqf#~3Tq4=e5y%KbsVzyJP= z#e}QsY{tUE+K7I9U-K5z`ew@!%Yi!o@^tMVZYm$f()-UZzHwhKw{>{>Oi3**WBUDH z3|Gw-Q`F+Vjkq7?4#_wP#EZH9{zoom$MyQbE{UBQC+GD&#Qhjjt1F{pUMj~=t+dtt|wOON|d>@|h|03gukr#9Q{V!lkY!P7*_hoRu%)N`8X5kXT;iay+E#rQb z_mFOmJm^E5ZVilaYJ-2nIRD(gWMwue#_Oa$`gM+HZ88gU&gHC*hxnwfwfXl})z`oCjGk*6x7%IAUBDDO zm78}=zy954w6Uz*ST$dN-|#l3@cJmt?|nRtlK92hmP=KA3w6-ncjzH0Zr;7&le7F< z*KWf8*P(hc;Sw6D<>`F2YN{vA@|*JjuenHgRdJyHX@HvLh{t~y50}+6fKQHui zUF|<``BAL{+V$!*Lkf2g!!BafMT|k{5>6%6f2BBaud9XmKdip7o8NIZ-2R2o$V21G zZ&$ty|A*oKDEyD{S0Vf?{C^()zX<=Y!~d5RZdRDF_o5%z;IP&Y40g+Bl^$lkwBKRH z2JEGN45C&O^aPzd)l+VvcOAan&v`p=GkvH$941@l@>zlx}L^ai(?52z5?&;0)fJ1e8d+4Ch(}yjO&@~ecPKH`Fo1d1`d3|`;&8zuF zXeQ`kv7J@Z3Aa`+4-W&R+O9#2ezV%{_~hb%5=3z^vYWw)5w|=YrLN#BF_;WZH7jXjAk#*S(Qf7+v83z!qfgO4uBCyVXO*oQ)tc`-fOp`e|ZsjFYrEYZ;}+Y3U-2M3KF`oJ9iNpxm&Wo6oAvN!k0n&+x$eICY&$$_wTQ%Ef)| zz077XYmOPeI~~?7LPMOkD?SF&b>piqjO_3s?T&}eQc;Z8_V$+c?;xAWddEo7n{b^N z4e$<1rRkt_DbHb!l4$28)L^%#{X2M`{#?^R-_#9#De7*2n*+4UKnP_f6+Q;G(43@cNbGnd9|w+F__33 zD@HE0E9C6!brIt(;;M^y z)^^VTNxIP?;Aq27M?& z`Vgj-gc8$KGpf<-$MRrg+;M+>I~2%ekUTxAyBRZpAN1tx%3&$x$~`i*MLNQtil~kQ z8zdpWTu7hYNLh`k0pbg>S@E!L9BY-Xdt_zDZ68D}C##CZ7vsmo>9KK%S51zHZRfD5 zrVvU_xkyV*9B!Dm5f&zY)hwv93A2VHLd#h-X`1ET2H_HPN;^D2x=U{{q|p>EsS^Lg zr1@a)-XdI&h}9Hf)OY(W_qKWr=a$wqdLqCo$bn`xpUYW=b*Y6!B67Ui6fX7>Z;H~A z-k7)1dJs5Cg&mKWN*Q26O&*Ze)bli_-wSNTFg>6;P05*>s3Hqr+&7gbu2kG{Kd-oD zY*$4c<7$#13Sh}+TsD9vE9nPQEUBy-x}j~YU1$bt%rFl2wT&7EsH@y&vumEBk6HWO ztawguU4MRD?mtu!Kfo2_N~en-J&I?X%ys4t-PE9?I|*r^f#yfhlZ(490hhrocXyNB zK#CYmjs;V&Ko5SfP6|fEVA0CqEE-GKQ`_&L`LIO7lf7ncC0`b=&!VXA`I2-&Q?0iM zV)U)q7c@79^hRy{#Ku$@lCg2>{YRXh^>VWthi0>qX(Fz+lNoChA5P{?b@+DD9Bg`9 zOi8ubYA`v~p0{9m<^p>`!|}LAbO=ycrVhpzPd!B4=8dLhh+J-{Srt6&LA1nBAr$2l zJnUDdx1Oj`x-$-=Y&y^rDdyZgp+4epi!Z1!S7;(%YoupYEJs<9N3_9qZ+a&wf)bB{ z>BD2`XofP8is>2bAgP)lUHpZdoQ(-U`YK~4tNY1AGic$kC+PfWSBW@UszA8O@0YW~ zqTLWsDQY4)6*|VIm@A-m{A6~TY^L%YXcBfP*ru`hlaida!!`mJM-^N0p3<$E z+ST;9$D2z@H`0nJ@eV&rw;gu-C1xZ7Q*j*yib#;!E_7YY$rXlV=m+)P5kpz8V0%YA zF*ogCHes=3Zh*1?5AtR)XIQQzbTN_Q2-n?XWY1hlRE!{Lu1;F3l3K0GZZe-oandCJ zepFU*bm1mL2hcu7;i?s37@|{{SF_a)LH9ynvoA#-H)jO7m87jnAu&cS4ZW=EU*)8D zdb^t3u|^am*?cfiwP~tm#iBKgGlv&*^Z$j%i5SY?;PtK);?~rCh4@DIS=kz2g<~KX z&Q@^=XTx`}URTaj(0+>@DLr(vn^ud-^dRHn6#g%6_m~AJ)IBO}(L8K$RbkmItREeV z^_NLbiR4s}c*4lqNJ4-?AE4dx<9wwl6T+$IPuupGXA;z{5Yi>)oj{`|L)yn+ z4zE%ECJS1qim`nB_>^yng8;60#%i#<(Ii6NG#1>pgQw;EUbc6owT#ULR?`e9Jv~n@ zmc)BBRb{u_v1`OiE@vJbu{=_r$GXYwW;$X1+KO8fEb)lmt&G_%c2<8g9o97Cj05vH zwB67;G+PHIADNMEeLCe~Wfw$tP?$(1)&0KSHv4+TmHd`!KWm3^s%%2cN35awao)%c z!!AI`zKgZx%3!HA_8Rd*gWWD~@!QNy2SKaKlA6S`9ar?}|4&ijNXEM$YsQF+FoRmBW4gJ%iYB2qLuFMejJ|W+0 zix$){Syp)3qBxW!v>}x+++vS8(d?(0h}sNT!ST3Xu>fr=LYW-FDQ6K+7Wah{Pvf>2 zjZZA>j$BE1pGXt=j#lF_UtRGY=57&28kH(~k!xa$&;k|1)G}ejl4Cz>Do4>p=pF4J z6v(vu=rm~u9x+Up_`tOTM zdC{t)pRzH&D9YDTQb;f&~;ozbbCT2YB*2!a@Vkyi?cAWKFJ>#8t(~PbGkZPyCb&r3Ha6IhFNQO z!)wVHmI4OKC+ilC1+fU(zW(4#8y0Gecm;Pe77!R-dn^ZsPndouu8Ru(1&^x^%cokG zhO;+80!sI94|i^YhNA-V{vPONr3j}|1bV^&7N%|ZfYFR%kxGk&nIy7|>`;dE1*xYk z$XW7mlMY8Q)et9#f;>tgqc?qf~oNNi9B+)5v$EuO75VTEl?8)RtY&*`Jn5+U<_@jvt=mi&>m}!oe706WQAndk7V?qA7 zVd;&u(%beM=>k2`1_OGvnIIV zn*YTCb3b@NSqsc>CrAAI-57)cM=nftZ$fcNZ@d4&QeJOwmaBPf+65<#1x#erx2<3d z+}Cj&q?R+caGnOaN!hg9Zl;MljE?uRwjx|PFEe1{X$Nv<@01gxjDkQncp!qafSJ`~+c&rk1&(X>1j&y?$&T-vdAr>aao#@8?I~8V#cq zn=TaH%A*4d=oU6M&DW)nn^bg6V}4Au&?B`BuP9TR9Dh3u2*k>P;rgl0BhvVVEt(4U*P%9G)|6U)%;l0xEnR> z&nKXJGb-ZFaw_7^vKsYg70|s|6>(=-6>(=-jr+3-=-#Y~xU;N^IAz6iG z4r{(zXDqZ%nzCxQ{nbip7z^dMeznx!V5Me3#)__Y)G5pzWWU!huMxb9udwp?F~+Xupg_9$=QB3t}g>r z&+exR`M+Ar%sT8@LR!l(;`r`jx)gl~Zp+}X9gEymEE_w#BVKF4lHkQoJj5|%Z&p{x zA7Sj;&(EZU&E)klczf?|*bJ>tyK(L#t-?b8I8khCMQ~`wbg7z0VKtxrv#DbLRT+gP z?@Y|MLe5YA+FB~W;$mnN)7z@gbWoR!eo$LYFnRLo1A(*uf#bS~SBt(8$of ztXP294-QK1L(`9@D~)Omo5q~uYC4|{3L<6Y*^i+nCtRufy9w$;lgz?mW$1}^8jia&$hXbaid(MwNhlBKMHPG?3@1DH|(dkRcA zj+^ik_#*M@BccX3y-7d+=O{0R#HLk9@f*tyy zK?=Ewjv?35G31ImhFn+2kgIEjm=iWHFh8mjrQxpzHcKVKW|hQ%8zU#m$zMV0a3J+S zBppGD{gt>n97sKoNS#c^QA(qOy-fZxCIxbg3?ohO+?xuiq3sis`tVWbe4DHKn(eHJ z8VmKzPyjEBxcx^vQhbTz(FUFVBY{Q*JQi$)a;LOW6(FYwS*$X1%`RrD@0*zFk(b2u2@=EG!emm^@5V5bY93 zMjoMOEbHSE&w)K?S*=+#2e@tyYsIp;S#z%MxO0+veOPgV>I`*=DBV`Z`FGuIRyDWN zs+q}VneHEU2M&GUUealOCFQfk3l2o%@N^e2TXg@>`_Sz4ElNh zK}VJM)&1-cHxKLmhwIDdXd!;<*{K=Uo1+dt=P<|d${-h*%{bhY7ymLFyE zQQb*CsyoRkLdnfseu?|I!<`jJ$$i}AK5la#tAd$3CX^hCGIk`qf=y#`tZnjOE5=xJ za1bnvBHUjwmYK@RBQWwnLC6;`Ar3Es;Ia1h>Jgv3?fCjHhWUEWz}f6`CquPCHauMm zJxTB-Fhw7pXk#a_lm_A{YGy)<@$1#xN5;Cpk&Gq>Dn!PX1!ZKFeZ_lOy zX8@5Ldk!o!G}kwH0&N$BBWyiU+7w~+iIIlp(Z**xskqm;b@fk~gkw9(@aD1(=b9}v zEJLdl&`6AA8paWp1cs)L zwjv7dJzF|q=(@AdmP!h72Fzl1c1TMwvW!nqa3A;yLH}S2ZrPZz`qi! z@J>`&^iEV+cxu&f@G3XH(Y8@GEP7ByojXiA1Br!yE00bzis*}?QEOimef7oBD55V) zjgpJetVlRy5CpLXV}WQ-z_SQ7nz!Lul}VOZd~U@hTC1)k^50v;1o`v7v3%ky5soTM8* zPcek9*+==nRvjuLLR8duc`SD<3#8+85egQAA+H!jda9@~i0Nj*U8)f4%ve5wk$#tI z#(qa87)F9QC+uYPZ75V_0V}gXs+R*?>T7_`(XcMqZ*TbQ^RNhIyyYxVY^MP0T0;Xv zIRY%SEj0MtcexHA*>KR7>^+9H1x4U{Vp;B(`ekT;M>=coKx<*h1NDxNFDbM~641tR z3}Gd3UZ_ZX_=ssQ9c@i1MM@>eUC)r`kiXuY!(>pz>Ur}J$7|bVQU&!$c@bMARctHm zFcS|cgeMb}d0MC_j)fCX55?lB;fmsTFcrsxMbcJr6pQ04wt@#+X_0HO6+AXoh4o2M zVha@|ws1=7p;+RPmAHs(l}WKhnLOAc)*g}f1#3IL5_4yb!|tnbSXLDKct$fW;Hv`G zSK5)rzEsyNvpc;w0I9hZVNI?K4-2@Y85j7g1WUBUw4;LOXr1Xt>rBu6fr*|QUkf z&vij_-J(f6@gvyVG3HUQcNY!P_Pu)<7$FhTTSFF$2Tj)!kQT^%mIj%tQV`b~gjhTw z5lVDhqf@`f`~=4w1;;!M4!H){_yyQF1~~DIxjWwT4{$*r%fPZmuclH)N%mX@o1O_z zEv-hPiFFTf;A!|!2EpC}P7}*u_=4WcAe9(w;8x%`@far# z>@kGC!wkxhrv=6NOMki2rMJOB9T^<-j<&6$gtw<8om^m`*4l<%<8mCm3u)@1g+l5u zhFU200lFwQ1G*@71R@F^UG@=Gu#c#MeMA-PBPz4!STu`#ssS*xJtI?S=IOJC{k+a8 z94a2e^#~2C2L{ayz(mtScUUAjl|K*I2^U-}J~X%|M^<0-UPv$H>u{@XrXBz3x zNH6`F;mn_##S=b{A6#-pTIt4^Ryr`l882NI@!VHhz&S7Jx=3?f&`9q^{L6xd`!frC zrqKgIDS|+zB2bXE+OE}jW$O)xMHA?aoy@vyOud$qW6I_vrpUBxL|(cn%9f`e-CDLU zfr3odM{EsZLihOdFdm_uh76^~ux*IQNr6;<4}?4vNVW7pjA1JzrPo_2$OGO=v3)n2 zVF6-o?CsBT!aoh(lCTVaNyyf@knFSC=w5$6OY^;k_L%KYL7Ie;UPFsIB2<~ zac&f;972a&(%?4=FNZnrA+h`MEzkvV+WO&a4Gmj5*Z~sK6oIf9u$bEJ(RI+StQDw^ zOZ3)@x~x6M6l4V_>(xxg$}I-eg^8Pbs|XYfsA5Wy6Q?DOa#uH{#Oje8$cfpZihR`I zi9~H%1d7DiNhw86oEAIES%E~PK*}SngPe^1i@X$5kQEuGwUE*%kkTlS(mXF~C>@cC zuRuzpKuVLAO=6waN->bqC?=(mYDugWD98%d*O^F)CZ$jyrBEO-epyyPfr2ay5bbQ3 z@V2{-9rTf{oy6Kc*9#v^>9S%zwv`MGn@!rFww*k#_~o7xrLF|xtn!UW+lLdzwk355 zaGgT>unGpc8`Hj9a~iJGVq;)ttn4b@6tb-`%Tb>cabTCv9gjM^?0a*ToKH*mEJEM3 zJ2yi4ONbb-BNypQ2n(f8AME3Z)~644$)rAVPYw1SH0>4i9>1k+X@)B z!b7CKdJDU6+ViBf^pE|P0O=Oia78BGH~UUf?RBHGGhxS+&FrwT8rl!nD1KCZ{9zQf zVQTxNVy(ueeFds30>DXV|7y_Fu_j@^J7Cmx7FL>Yb!o~$yv|Y<$e38Dpl0o>lu(4S zYHWYjcHyVKo*_lap$R5MaW(l4PqJnY+ zZ^fTR@j?(#1WzymDk>`8`1|=2@WvAn2p+)y`+fDQyZV@GcLV4@^_lK^RrTtETsd@TQ|GERYaHCkfM?-geb!}qKO7k+eTb8u199l2tm(tCCr3lMDCF-}>#DU!0;fKS#kTa9&?e|nfNRc!vo zFu#MOZ2p;Hey5xNsxW`0oBxI|f0fOj3*eF!#cH{0L$TD+hQJcTgJo~GWu4Kog(!Q^ ziqddzX=tD{+_j<9UI-8<-<~)wUr{L!6o!ZTR&1=42f<)XK7n&Z45w5Gg|Kw4N#KOS zSe)wyS6~SS9zp|p-QJ|=6f+Ep3%f4pHO8K?PvTxb4u!%vvJ8W4`vfhtu zS*X6C-v8LLVzS;{T2@Gr^H;VkMb3L|Sxioj!9TAU+EgfS$n}>ih!JczR{j_lQCGjZ0(aYB&; zIve9Svp&dfUaCs&SYdJ3lR zePgsxC-ZdF`(NOQ>|4qMogJHy8UruS8@2VOkynhC<@GZlSzaA0`&p&+cKHK`*?N|j zOUv^5KOhOO-a_A|?vcTEn8)fu+nQ2=wGH1af!I>WXg0SoKU~W7l?Oy2)aiVX6UL9c zdioz(4*_{1KlQuLB5U4sQ!VHyMJQ! zPIXb9X2&eOd#LwvwbJg4*TanAkX{zYSjKBF>mf90^Zq@+Z9#tjZs3Qyf8yn*Jgvyj z_J;DCb#a^11^G50AdIIEwh4vi`=C{y`3ukwZRp9-hMQDpO^yTqm$nTuhD{sXp^%p= z?D6%(hj(&6{K~dL)(%gOHniFgzqW0Ve&BUkH?9;1i=`oFQ2ZOLBYqQU2l@insjfX0 zCSY7|2M>m3ed||&+lp`cE$}1b`bp4+TU%_y?`#{yo_M|GdRMcm8;@^obxp_XqE`Cg z-h}+F6`8Ao@yOrmH9?_8`G0Tauke~6KjKKgwtf6#U&YdhGRz{KluPJG#JeY3gTI^5271_mhMh4ruHx6ys z3D;wgCy}7~87d7GLXA?08%5XC{thTe$0u0tB|bg?`z_It zKdm*P{@FKEm98DPe?vOnhK`-rA99~q?IE>4%($!FAC$G0Z9S0Emd>5n7Ve4GYl|7r zwcCPy;+k!FP}?GXQ>f@JeZWudeOue4tsH`b!3S=xKVLC$-{$IYX-G{GWw;;b*d=XX zD-dZDh7ZcySu@}x<&-lhckTt+`moWkT)bhl{tPWQG>lBjrlw3YU79H}%}SxEqSd6y zc_?T{3e7nVO@mk2+!fQ;+o4~eNx$Jfj_2iv`VWO(hf7;>`Bkf!V{O9tT1|8Q-d3p= z%7PK%T#fwQ6vvMBxiOrtAWdFsYndMbp6{f8?Rld}2IcfiU153>?PJtQFNoq#Isj!| zPC1)A>ZG3q79YXaHi7q~bE9dl7aW^|j&ZLJS(aX=MICb( zNZo&T9b--kbU+=2;|@B)Jxkk8=(JTGvAg~wbhNv+gF2v&Lf-=&;ohxn=NNP((+W@j z?sl{&rX%ZrIX86SR&>)kS}k`L1Diw&YHeso0gmg>9Dk9aKifm;u%D9tOonv8H^rX? zV;=P;7)8^HL9q#Ag(+-`q*kQQFfgR$}5}*X_ZBfUZe*PnLyuYIZ+M!+N`Q;*>fT<4S znTo2@)=3vR>oi$USNlq(3Neg6f^}b5KPV&0dliqq>B^XIx*26fr~C(iw>arvqR#Ka zwDjqGr0G9-_9OnQ=d#9X><6VGJ zZ_2xId=fC|O}QG!Er79Bm~yM0gH9(|}3;Ivn2wO#0u# z@e9DD|4SVI08IM-jL|2`TTLBl+s6PGo%EMbew>s3vA5{5E+>7jH|xx6o%Fu|+jSMJ zati$<`^o96DTh=C3pqZ~-=Bwi0=-T-8t@V)eKO#sn$Ch&(VH{tPNaQr)>X$K&UiDA z`<#?dy9oNE{I-v#oE=NQ)ti?eb;_@fwuAa#c)nBqGw6xN3tfs1{~T@S)ESw>N@E%PG#(Wl+5Y?H^7&1%QgLEWiqQ2uv3?oQh!9p)X2*xT!c?_|Why^wdJ zw3BU}``Y^=aL6C~*6-^AKJ38oln1M$&luO`x%3vQe|$XGv@2Iq3fok(oo$yNYVpS0 zPVCLN%C&l|$@7`Jqie_6&USe~J5X*zp3i;bg)yFYt@LK%kp6VwP_995=GE)v5F7^% zaYmcKxzwBanhWI+Iu0Dt`B22BXlK^eLY(WGz`3;n4#wxygq^mpj2KNrU7oT*+;liL zW_{>9j|bc5!lCSgGIr^w1P8H&L!41>R@cwu5F7^%aW3^{&7UrZ;5cxI^Pwhipi8IE zT{xrzUDm~MbxBdk)V$K?}L+*I&g?H>doE%7;_NEfkT{2y*YmzmV^9U zIK=soH|LAnMc1J)*Tl{{`&rpIFP?#8!=xt-Nw}UiGHBY9F^MM#2nSwM-4XcQEcz1 zH|OAGa)=*u;IL0IM>U)eF-JLbpbLj|Fh@CapbLjMn4_FI(1i_7ZTnf>CjaD1nWs|q zS=!3WLTAo*=N%UgaWGFg^NtILIM8RqISBKVGw--?NC)$jGw--?h=X~`nRi?`#KAn} z^r;IQoVY$^-q*c}_6gdXSOz^m1;<41O+fa@e#CmDbw6UN9d~Tse&CJ$f~nZ&nTo{| z*NIbczijFWfPpvl1vq#yPTYPRZw8G0f~jx8@o~VgpQ%^q-T^n>Nqarew;)EC`V5Vq z2^h45*NK380h1S=DH$9;gw>#s3hM33)NVC;$<)WMf< z9OtBe9K9Z&+{8YGKNn)-5Sp_gQjL9zsrM@mbpYP7Z*h?3Ws#o1eTr$by~UpbY1>Zh z743Ugmy^C_-1`<0`m%4qd!G}#Z!zzPuHf2`aL}IMdXTzAh+f0gS+Aw;nggFTU}&EAUOIIyux(!rjHlkdVI4zA;MKSk&`aEKG`i3pDFtq=}yrX3s^ z8?Igr4t;WR-(Sr;c=m*c&@w`)Vn?!uw$;a-X0=sJ;bh!gIW2#&53qd4JSiQwou zF^UuJl?aaRl|*r{4%NL6!ExYFo?C!H7IdhIK;s^Ro9?`*f)~UJ%6&wc+aj;I+HK^b?aEOC- zs;)r=$ALo}to!vEgE%f6;6UH@xDZeKhd9?YfrIr=BRX9F)WxZ7 z=e5_Isr{a~r)1Y0)TaxFZNwU=?!Fh-Qdn~~+}FgKv*Erb)|?IZHL>QbyRS)kum*DO z?YVH!F0O%``*tpDaBAwj&bl*I=gD=au1BbI_XuRe-npCa!XXaULC*a>7Y=c-4r;j1 zigjnheO9bH8}74Wf3(p)E7w7F_gUjQm;DsoL+zNLJ=CXS9$$`Q*B+`j^*?bB^AQ1?MwcI}};2?+LDN3RQ#_hA!jM|Tg*g$=E^uMs`(+Cxo$mN2CeeT-(#6mN1|9^~oGj*N;NZlt$tY62- zx6T?imG7>-&$@eW+)u*unsxUJ-D`_+`WdDQzC6sqDA%A2IOGY|v8J;zqwhjqApDFLu!M#hVlST34)R{X7-DO*sARo0F@QS<#40;p!I-GL$%W*i!-#z^Bvt%L=Wqz{s`@@js$=L54 z^v(AB>5jgoE%ohcLi&BB%BSPUJHe5`_PzGI{j8j{=gHFVybgLY_B(EBHr?;<8!BS7rlSxjzgCQoT zECn9-anwkk|4PV7@9^Z)=OYO@Ioh6laz1M1gbi2v@@MC&n|rEf;|-|&BChoRz667B zYo#Nq%};v=P*>xy>B|7G(KP$^iXzsaeS;eZk;mYU6~1%AAHus|Wff=PT(M%727+75 zKA3+a={~)uzao?k?fJ;RjrrZ1__fYHTTH(A&(O3V7D@wn-K*5Fc|VWkasBZZV64UA z$jf1E#*E0E!-qtTpu|aA|2-Zuu8YZN*KkI!lri*^PoysS-z-;`fj>98EZI&c&J!so z{yP?tlk$i^59EBp^~r0j3~bbutGC#1jPZ%I#b?EIhcV&GIJB_`83<2wAODxipzF&F zuWhY8N?#ZI3s%nE2?V}SuOXdsT(in`GtrL4!G5vr+ff+g_am))vvxI||6P2x;^Epe zb2Q+&IBZ?!tpks4y#5{8ww}C;u`5hZ-vjX8PI?Jo%1i$1@whi^4n zIB&2G^v#@asS_S(bF1%olK(<>p{_h%vZ}*A)=?MpePX9*Xl0Cq74K zpS$4mjUf)+`J?|2BaZzaQxs=3ilhHIi{jw_Z7v;!4UY6L|L54=c9`2B>Zopep8fHH zE9;3t8>Bt@zptnq;X90^J^Ej~C{CBK@NMWqe;H*A94m7O@EZxt&sELhL(4E{On)8Vqnz{`&W(KA zpyr+%X`{Z(tMEhElNuTv9xM#@b+xZVQh2kR`!06ffV6ybgmamW%HWd6Se<)rWTmn-F*+}=)PxLsI-P$Uf9Q5Vmbf4q+ zm<*>nG6b@)PuicDzN3G7GWOjGF}=~L1^RlN`tAiW8BTL#2xMX3;g#feKyj=*UgM5_ z`pMXLC&u)~2_ewe!LGSD=HTO}-;9`Zkxl7H)^5zNv-Xg>L!0o{?_6=Df{F;NzmPy6cN9TolzI0g#b+BH1bnil8`uxu z4Q}KPNat|-YIp;(Q}kw#0tCe&Pu_Jlf~0uh zTet1?`s+oYA%2g%5PbXGfk}!Sq|e12=UdgathYEHQ+|8+MlFGep$1#mA>|^kI@Z-@Dj+;tSxcv;*JBZZR*)lyE714?MKShXdLjmsae@y8k0TW zob16s7_0n^>;TtIsdlKkBYznPJBvSUENvV({AD2QEdE^QrtvqU|M43KFNYk>+7j1+ z)Q9z{Tqo8W2OZ-W2b7Dv>dgoHqP$tz`Mj1ZdjaVtWFPZ5u<|z=2m7fU@wrrWH|BBB zEdTu*^B>bVXqNv0HTauZXky1fgTC-yQA?I_*fD9+?i%pU@Sa(kKj@4tOh~JhbwRWI zvyJ(W$sae%e{o~}W3t0$`7a6i;{l*Hj=MHwN#89b;9QFUf#uA#K1J5!-I}iFvz7wK z^;zss_|uwu)xr9_{&UZ=USAJ7N>A3jTm#2^oNb#dw}?BDZCeIn0Qa3nUJ{34StIrC`->w%p2PgYX+Sal? z+O{?7v*pUu^qKH#**==(b#Rhb%l6SMFa8&Vx-{)_92W98PPjI5eOBkHHEVKWx9PsC zsP!7@lm9<)_=bk5^;_jzYLf4vA>WbGKq0u1#I|w`<+gPs2MqiNW(eP;vxvm2GY-6O zpj_KEGQ4>JPe_ue(Iu~0L;54-VreiJ$7!Uu97q`YgN03n-ZJ*#Hsfn|1JpYM<%{}| zNMBkbeev2YYoGYcm#4@uniS{&L1MO|eaLZjkvQCXYPrn(H4NC=U)lheN&C%jgGgz(bu%H>`;IAFe-8ptSkoN)bgIy1^Bj)1z7}H+xQQG3*LcAHE?S7-KS=!!4OPhKs43&qGW^iQw z3N1#{5xTIG%w?>D4=k#ATRf4Q&Wdu2?1jNW-0t0&>(5(NVUIg+A3?VDW_%I&l!^Rk z2ip-(eN2Pqv%kJ;mN|wt=*0DrMrURdbi|oEeA4L5Zi0?D>IQUr8_)@K*HhkD7#u3K zxgSz=XxFo4*LLmxJM<_0L;H@{Zonrrgo&_&Rp4XWBDSD>+Q-=*(o*@PJ%`n34{qlM zhCLDOSsiarUwL@Auf#5jw8-*mwttB4wuj>`(m&uMOv2_^e2)JykJGjB_L%4N$JG{R zzL36I7jKL5uuZYL8c#c(5pTyvJOYyZ_Gn$-?~WJDk5<3Z2F!cW{vdtZfDm_FeZgnD zBV%P?d~KK-$|Y_1uXr0se}dca>{uIQ%nz6Q?MHXn*Yj~W|B((#S%!Ht_>VO1`^}>* z(Rbk`b(>QKJFtG#W5K1@k^d~V3=?=KJHMrOXB3Dd8TLH`ds|2~r| zY;2#WUPD_Sin{&|t%TOFK8vv4ApbTgA@6yF!e`EU`}Ge%EaRL{pM@ZGnWw&4oJyDppF@M zO=V&3xe+El=Hh8Po_pe{-totu>OJoTM<7e`v*2+wU_SrA@dBBBy(i@By%~RZs zM88bhOa%N!a9j+SG%tzKWcFJP9?K_x4DfzV`b)^8oYWP|e=N^`hv|mjjKW&&Y#vGj zwl(Dt_F-&(fsM|12sn^EuzT>6??w%1-7M1M`)<_KeMXfQY2PyL??Q#o4}+fADaVTZ z7oyX+9qV|gKeVy-e<2p!b2(5%&wBwc{GK(RKezu?AS^nv?@d)EtZC}j<+0~a&a-$; z^RQ3Y8`muI)#b7Ow`t0)wPV7*VO2+0t6S`kgFnwLIkz2G>;Ep;9}XPij0WF25;^RD zFr?4e|I~T-KaHfU7AO4HbZwmQThmD#@sskMt`^(8;u>^q*dF|U#XeJxHn?zzga3Qj z|FsaufkPZTdvE^}K^zATaiACb-xuJxaEKFrZ%W#n+6T~!lkdXLxLMnxURHhh-l$$U z?&W~2E*#2=|BdMT*D0$Dhd9uSzRRCDE*#>7@A4NMeNPwR5GQ<>zu-817UJMt{!ZVx zu%j2eTTKI-+jy)$P@brH(ghQOs;63?*qwma*;^2P``ks8j zao~_n_>CvQar!L83BU0qI8L8Adg1?a>iBb9D^kZP(tSes|2b)|;~zqsh2L=efD4B>;eVNudJE?nx1BB=(h0u-lB5&N zGyS>9hdM~#>IFDSy|ggTI6NX=yCIMN44>`z@@W4!dWm^$(|2|C|NnvC7X56l_7sPT zo!!pb^=TZq&NBpZKdyLIp)-=%xpr+%GKp>1fO5SKy8h+JWBehFKd3nKk-cuHw868t zlzKMH-3{6*{DWLqQ7)Ud_wblTkbM!tHLjCoAF7LpXjj*Uf|;t3W?;RU1gZm->Y-8D zDVOY*{EG+-U2p`*$uqQsN0d_>+Xa|v9mld&+adjt4g4*WR>{vQYadkD|MdPeG|^#zJ%9jfJMr}WF=Nbjus_h&|V z`KKaHJ8}=T3FC)R#y~wRArQCsQg5N`Z7dCxhRTJUB#0&Wp{dujyfm9l>p$CPN1z^Lwc}}xEWJn!p{DKzUEN6{zz=nIp5)ci-JK}i ziMrbvx{|(dbtQ(Tt*oi5rtIwey1L@{Ow-i|kPmtMZHPI}$75$_p}uQpTQogUc6KD_ zxw;e2jXZ{$x@*eLE;K|$Lxz?+M*kP3J5hIHXA`U|k9{G!Di8MeWB0ybR(;Y=>I&`C z`vNG=h3|(A$KF=Kb@%Ms!a2^TFQrZpeA!d`;#`EiSV_}<>b#3D^Bmws+G=i9AUEjC25r4oaBH>o zH7K=h!d`L!pXpLlIAHLD9$(S-IX$tcCEF z>9*X)AuQUZl2{L{ z)hf#u;!x7LSh1}?`Ffy?;!t|C`cFFI7VASmf7WY|#(mqM`~sxWA3^$EG5pJsMsZMn z4br4->EDPn{iscU4e4o4`g=&jhJy0Dke=(L|BUoJC;g9Tx#;6ql&AGa-sz7laMJpt z-R%#cP)?^0wjs%oo<49A{m;49;-&f-bi2zg*8Oqb+er(7tX$sScaZk=4RVx; z_ihtybIPIL*|UnJ4f)M|T;^I@v-bu}pG6vt=8xwAN3Jt^cO|EG50Zghw*^{pQSJ$e59zqGu8{NA5|XKlodo$)KPzvZ`#K>S)Jc=pN}!$6}h zLYsLBYcgGgOM5M$!iZHQ|_e%;_bB0 zFh!dgZ)X>)A|!Y&L1vt%>l=BEpWs=nZg$58QDS->WgbF;AKMV)$DtpzF_jyumS z$QC@TXOjIlG8ktU>%W(-XElT@PnI9oDO?xYH2C{eK%Bp8KV#%S3bG6l{gVHyaX9?F zyO56acYS-RzOmMdD}XfTgOr)iU%DMhhAy65eq1}p_{r+r;-&J#(y=~2eIg`f{&-yq zKi8h3`jx->7qM9uXD4k4+xN0A%8P)kNc;ScBOPxa?`>GTG4eZ+^$`;Mu0Up-pWA=9 z_HgW%>u)YJ6U~daZ#%0YMC^z5`Uzyl_!V4zj*Z{TyT}Y7!S70B#`(G9BXu5ueHJUp zW=3uF<)dVX(8ZHuqjvw0^MG;o6(DvHs1h1D?LpR`TW`Z(qo@a!p%*H_F<8$DnPL_s}`%*-Me2 z-(Y#2YZbYF;A3wbe@PgU#h=zeduFcz%utI4ie?|F<#ul1eg)bR9L`#%=-S`}*~2JU zF?8`nIoS{U;c)t2u8*CxToXK>IDtJ_$qbDaY+@8-#KDlaYZGrmI?X1IMLzU1`OSz~ zXCiIFtcC+UL~Npt4anZO&+Bf-2vnC1ZGd*dndG(F9%~2OAFpKxuCJXSJJ=3(3|&06 zVh6_oKePiYS<7~?oqW@L1IK=v9q@XIcJLO&6Kw~bpvj7)@|H<@)zA;~Vz zZxmG-x_D9@3%`#d9p`5)Y8?EwlMg}{PcFZYAsyq#N9JW}Al|;L5Z7sWuwb{BSWLW7 zm)*=l5LHHaU4>lXRp`T?6?53q8Xg+#>njamXKOVZDO?S`)cuCS5M6?$DbLb!of+lN zl{Uka?L4y#V@K@Q@!!)qPuldm;X=0}P1$B>3|}W{_*RLzpTzPzHRgUE(?2z_KUZV! zBO%}J-DKWl(wX;~Sgu1@?~jVdb|RfoJ{hGGytl#L%Yl!XzU}a>S9(vs8xPRqIh>=v zd!~2rPp%y0^HO}4>Cn&YIXdORdpxEY^I7;kUOH?0^!vUyD$m7#7F~&B%5UDk-EYr< zt<{ZOk5MKbez~K7?vQ;(?GC|P&I$=T=qN<;_?Q9e6E)f=^k5QTCSjRfvv8iH4&JC` z=!48U(y7?hi>Wgk%bIm005PA1ll6(vUCq6xQQ)a8!J29b@-mod7i$^n&s;!$&YFs} z)7AjU7J7B&!p!l&!T+b%9M;y+wNfWkl_8=-B3OFhC%)(irH}ON4S>(lH1lP54)%yQZtlzDpS?N!U1Jy<&E}6S#6y^4bWMF*opg4s)XAlW zPNdZG;dSkiI5a&bowPrWIuV;`K_{XYygIR*@8htG><=D`6_~F_W_7K#uWASR_L8i<#T894?W!ClNHy1e+!LBE0D6>dXXxWZ(2dzg zM;r1OCPE)sp)|4jc%#a;GxYI7(2nV&)78hGY)?4Pm-+{XONHS+J3NAZGW(5h@oZhl zDrJ}xf;rlb4;1+?!Kv0*spki{HW;gIOrh^cej|2HkJ2Pvj@t@iJLfUY>re(Q=UkVe z5A(}I_{!PY?M~U8x8iwVo9;zjj^97v;64b~c=RBgLpftVf};<|UvZRi{2Ip@I3C8q zdE;X^hHzXCR_7rGEr}lh%v)lQ;&?xf&*HcW2m8_V<=|O(DM^2RAiuHHk4HP`2!ovx z(~g6H>-4L<07Sl3oPL`)(7Ea7i$+-;0qTk9#k(76+=nCoa6L~X1nO@wfzY0mZ*6=q zFzY9+Plht5I_X0IGmw6bK9=I7W6CI2HUggntY-(){=y+Bl84& zvQ5{dL0PkCoBDfy1=8p{pT@+P~6 zgLV069idPAbZkiV)b852(4I90+7~Kq(of;hfo!Wc;ej?M2Wo(EFa;!K+{>LZQnp1+vd_|`kRVt`MeY9cj0)q!IyRdFUGSYVatnv)2RPh zj(!W;YWws?!^^jQ`(;gkLgOnmzDnayYJ9cE*JymL#-Gyo(;8o=@nfi>% zlr5|F&;14NEnJ4pML*oZE{+q^s*7#2*78zW9e#GRbwf!&@MfmTdX@|evf6A;dbTT=OsVBCT zHp-auKI0-{^0#gOC}6IgP!@0hYGg(Db3apMudDkukh633J*WfP{x3AXOXHtw{A-PW zg_yKqFVZI;2TXrJ-*6?4Sl>Vefh^KDT<5TU*5SPvY4S#%#I7u^4(M;x*TnhAf<@ab zeD((})9&2$W2OHijen}~of@<4EC!T*bDd}6@+EBapd?N2nTDqKERCaf zzOoJ3q95=Q`-9!tw2YG*v>x%DYJE&OnmywQ=`s5^a({+>%=3Hnrz!wTT{A zLJMt@;bYq`x?yFt{h&>^A&)ZC=d!G+HpzdYfsDX9^e>5ivd{a4O$vCMe)=eDF|^Po znX-kBwJpjXZ__uC$9(Jin`%>V7tGM(yqRbdpSP>o9(qR!Ewo2mOQbz)ORPP<&V&BJ zT9(!xtz(~?_w8KuGp#d|_dJG%tKJZA*^8W_BkIYHzaDu2l)x$9te&qTh!$ z0hv|FG<0M;elF4fgsz*BKR55BIe{3V(OZ^?hU#!EHkyg__=4AMeu-q*!e=i%Vm zZD_iBEx=Jy6`eb`a(zhI0b*_VTzNIXmF&%=7|ChA=D%~RCx zd#HD#Jl_CWM6N8-<9k=wv=4%YZR4Dud-IOy3e!8~-C-OP6ZGz|tJlkW zkoeAy=sS?uXBfj%@!fIf{ZuY&+Dx3$$a}}4?;x{u9@qC-$@(_B#)Yq}{Z6&SyK!7y zxNz9!e@ngCm(swoGq7*!>Lu|mA6FMH{BN$8I`1C(d)j+x67L>zb>YJQ=6b2~uB24G zB;J+e>cWLXy}&Ot^e_KT@3|ZG+;^tAu-j($-F7Y<;-Jk9-*dO?9d^-o9oe~N*E{Ue z-!-`F9diF}_jl!1ldBsek6gJen!YNQ{$wOgUdzV3kAnBEn0*ulI=TrkkS^Zfvf5N&?McsAD{gU#Ae4*6lNz`tl$bN#nbH(znv40@<%(%xO`X4FD=2cH@ZyDD- zj{Zk*0UCb4$kLx5^uhJaV!)-RX*;f4?Xz6o7A;`Auun2=2ezNO$(P6o%qOj*5kn?_ zyT;rbVHspGy67I^CzJ}ZQ)FSq!5V+gUzcwD+$hovtcN`NY`)NB9t51eP4Sek-8;(M zhH~)Fd_(Kwo&olTdhDQv|S6nF?f~249S144!OGPZziH@!7r9Y9K+OKD6 z0qcbQ3cg4)SX#UKRTMa`emxcXlzz4T5(5@fSD@!c{?Zw%7#1dUAz~l7V|4^+b~f|p z1Y;F_8hEzG{ffO$GhU5@0wq%ij1#sDUQPQfjv>)OexzE=Rr)qpvFqNmitqdkc<>p4 zaNYo-;N{fF1ud{kGk;tU)kq-egg#Pjocv9lfY$#HHeRFuTJmS~6ZPH$_9Ez2`gmw# zp1teb9u!^gPQ3@~0w8tD$3MgXtiLh+dV}^5r

    D4k6FlIriwM?FdOl?uBsfv3=`4 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

    dW9VJk(S6l5Jn%SqF#N$@lg&I@;$Xh=-$tem(b@ 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 P&%J=_7?}JI%$R@t literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6s.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6s.dtb new file mode 100644 index 0000000000000000000000000000000000000000..e83e1fa13d3b137073fde901f2e6051c57c60968 GIT binary patch literal 235007 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 z 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�&I5lL0i3^Hs_FadV^IKh&F^Z?)>Pl7U4N3m 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 G1%a)yCPi4XnVV;$Qq1g$?hG)WT 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

    enPAksNph=?|-B(G- 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 edai7THLrDGr literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-rock-5a.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588s-rock-5a.dtb new file mode 100644 index 0000000000000000000000000000000000000000..1adc6ef9a1d5d9fe67cad44ff7680ade598a0676 GIT binary patch literal 235315 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

    %_kD%%UI$JtnxK(}sXgHKK6ntQI@JJPIdx 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 + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..48b6d03 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI4" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PA7 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.Modules.fdf.inc new file mode 100644 index 0000000..edfaed1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-9tripod-linux.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc new file mode 100644 index 0000000..6d55c3a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/IndiedroidNova.dsc @@ -0,0 +1,116 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = IndiedroidNova + PLATFORM_VENDOR = Ameridroid + PLATFORM_GUID = 247fa541-ba0c-478e-ba76-4e00450f7f11 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # No status LED on this platform. + DEFINE RK_STATUS_LED_ENABLE = FALSE + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Indiedroid Nova" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"ameriDroid" + gRockchipTokenSpaceGuid.PcdFamilyName|"Indiedroid" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://indiedroid.us" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-9tripod-linux" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..0cef780 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,296 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + // RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + break; + case 4: + GpioPinSetFunction(1, GPIO_PIN_PA3, 9); //i2c4_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PA2, 9); //i2c4_sda_m3 + break; + case 5: + GpioPinSetFunction(3, GPIO_PIN_PC7, 9); //i2c5_scl_m0 + GpioPinSetFunction(3, GPIO_PIN_PD0, 9); //i2c5_sda_m0 + break; + case 6: + GpioPinSetFunction(4, GPIO_PIN_PB1, 9); //i2c6_scl_m3 + GpioPinSetFunction(4, GPIO_PIN_PB0, 9); //i2c6_sda_m3 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Set GPIO4 PA5 output high to enable USB-C VBUS */ + GpioPinWrite (4, GPIO_PIN_PA5, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L2) { // RTL8111 + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* nothing to power on */ +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER2, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM2_CH3 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (4, GPIO_PIN_PB4, 0xB); // PWM11_IR_M1 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + // No controllable LEDs on this platform +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + // No controllable LEDs on this platform +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + GpioPinSetFunction(4, GPIO_PIN_PA7, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Ameridroid/IndiedroidNova/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.Modules.fdf.inc new file mode 100644 index 0000000..656ef89 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-firefly-aio-3588q.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc new file mode 100644 index 0000000..a09f125 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc @@ -0,0 +1,31 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = AIO-3588Q + PLATFORM_VENDOR = Firefly + PLATFORM_GUID = 400f8259-7664-47df-b375-8ba262e4867e + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + + # + # Platform based on AIO-3588Q board + # +!include Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc.inc diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc.inc new file mode 100644 index 0000000..e14a3e8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AIO-3588Q.dsc.inc @@ -0,0 +1,134 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = Platform/Firefly/AIO-3588Q/AIO-3588Q.Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # PCA9555 GPIO extender support + # I2C location configured by PCDs below. + # + DEFINE RK_PCA9555_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"AIO-3588Q" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Firefly" + gRockchipTokenSpaceGuid.PcdFamilyName|"AIO" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://en.t-firefly.com/product/core/icore3588q" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"aio-3588q" + + # I2C + # i2c0: pc9202@3c, rk8602@42, rk8603@43 + # i2c1: rk8602@42 (npu) + # i2c3: es8388@11, XC7160b@1b, gc2053b@37, gc2093b@7e + # i2c6: pca9555@20, pca9555@21, fusb302@22, hym8563@51 + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x42, 0x11, 0x51, 0x20, 0x21, 0x22 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x1, 0x3, 0x6, 0x6, 0x6, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + gRockchipTokenSpaceGuid.PcdPca9555Address|0x21 + gRockchipTokenSpaceGuid.PcdPca9555Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac0Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0x47 + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x4f + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf + + # Hack to enable use of PCA9555 during PCIe initialization. + MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { + + RockchipPlatformLib|Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLibPcaDepex.inf + } diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..21b5dea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/AcpiTables/Dsdt.asl @@ -0,0 +1,55 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C3" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PC4 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac0.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C3) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..8c130ad --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,460 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + // RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +EFI_STATUS +EFIAPI +GetPca9555Protocol ( + IN OUT PCA95XX_PROTOCOL **Pca95xxProtocl + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN HandleCount; + + /* Locate Handles of all PCA95XX_PROTOCOL producers */ + Status = gBS->LocateHandleBuffer (ByProtocol, + &gPca95xxProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Unable to locate handles\n", __FUNCTION__)); + return Status; + } + + DEBUG ((DEBUG_INFO, + "%a: got %d PCA95XX_PROTOCOLs\n", + __FUNCTION__, + HandleCount)); + + /* + * Open Pca95xxProtocl. With EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute + * the consumer is not obliged to call CloseProtocol. + */ + Status = gBS->OpenProtocol (HandleBuffer[0], + &gPca95xxProtocolGuid, + (VOID **)Pca95xxProtocl, + HandleBuffer[0], + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + return Status; +} + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 0: + /* gmac0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; // GMAC0_RXD2, GMAC0_RXD3 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; // GMAC0_RXCLK, GMAC0_TXD2, GMAC0_TXD3, GMAC0_TXCLK + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; // GMAC0_TXD0, GMAC0_TXD1 + BUS_IOC->GPIO2C_IOMUX_SEL_L = (0x0FFFUL << 16) | 0x0111; // GMAC0_TXEN, GMAC0_RXD0, GMAC0_RXD1 + BUS_IOC->GPIO4C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; // GMAC0_RXDV_CRS, GMAC0_MCLKINOUT + BUS_IOC->GPIO4C_IOMUX_SEL_H = (0x00FFUL << 16) | 0x0011; // GMAC0_MDC, GMAC0_MDIO + + /* phy0 reset */ + GpioPinSetDirection (3, GPIO_PIN_PC7, GPIO_PIN_OUTPUT); + break; + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; /* GMAC1_MCLKINOUT, GMAC1_TXEN, GMAC1_TXD1 */ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; /* GMAC1_RXD3, GMAC1_RXD2, GMAC1_TXD3, GMAC1_TXD2 */ + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; /* GMAC1_TXD0, GMAC1_RXDV_CRS, GMAC1_RXD1 */ + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; /* GMAC1_RXD0, GMAC1_RXCLK, GMAC1_TXCLK */ + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; /* GMAC1_MDIO, GMAC1_MDC */ + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 0: + /* phy0 reset */ + GpioPinWrite (3, GPIO_PIN_PC7, !Enable); + break; + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB7, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); // I2C0_SCL_M2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); // I2C0_SDA_M2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); // I2C1_SCL_M2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); // I2C1_SDA_M2 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); // I2C3_SCL_M0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); // I2C3_SDA_M0 + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); // I2C6_SCL_M0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); // I2C6_SDA_M0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + /* On Firefly AIO-3588Q this is controlled via the PCA9555. */ + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "UsbPortPowerEnable failed to get PCA9555! (%d)\n", Status)); + } else { + /* USB-C */ + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 12, /* vbus5v0_typec_pwr_en */ + GPIO_MODE_OUTPUT_0 + ); + + gBS->Stall(1200000); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 12, /* vbus5v0_typec_pwr_en */ + GPIO_MODE_OUTPUT_1 + ); + + /* other USB stuff */ + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 5, /* vcc5v0_host */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 4, /* vcc_hub_reset */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 6, /* vcc_hub3_reset */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 7, /* vcc5v0_host3 */ + GPIO_MODE_OUTPUT_1 + ); + } +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + switch (Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); // PCIE30X4_PERSTN_M1 + GpioPinSetDirection (4, GPIO_PIN_PC6, GPIO_PIN_OUTPUT); // vcc3v3_pcie30 + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinSetDirection (1, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch (Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PC6, Enable); // vcc3v3_pcie30 + break; + case PCIE_SEGMENT_PCIE20L0: + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + switch (Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); // PCIE30X4_PERSTN_M1 + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PB4, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "PciePeReset(L2) failed to get PCA9555! (%d)\n", Status)); + } else { + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 14, /* PCA_IO1_6 */ + Enable ? GPIO_MODE_OUTPUT_0 : GPIO_MODE_OUTPUT_1 + ); + } + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER3, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 50000, + .DutyNs = 50000, + .Polarity = FALSE, +}; // PWM15 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (1, GPIO_PIN_PC6, 0xB); // PWM15_IR_M2 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + GpioPinWrite (3, GPIO_PIN_PB2, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PB2, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); // headphone enable + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetFunction (1, GPIO_PIN_PC4, 0); // headphone detect +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..8becb63 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,38 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Protocols] + gPca95xxProtocolGuid + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLibPcaDepex.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLibPcaDepex.inf new file mode 100644 index 0000000..6c686c3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/AIO-3588Q/Library/RockchipPlatformLib/RockchipPlatformLibPcaDepex.inf @@ -0,0 +1,42 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Protocols] + gPca95xxProtocolGuid + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c + +# Hack to enable use of PCA9555 during PCIe initialization. +[Depex] + gPca95xxProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ba8587141a8b2fc87d118bba84c3d5f0d90f0b43 GIT binary patch literal 106806 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 XqJ0=k(i+=Xb>U0-anQV;#P9zfxq76C literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.c new file mode 100644 index 0000000..2255b11 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.c @@ -0,0 +1,144 @@ +/** @file + Logo DXE Driver, install Edkii Platform Logo protocol. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..1a55cb5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..0fa03f6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/AcpiTables/Dsdt.asl @@ -0,0 +1,41 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac0.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.Modules.fdf.inc new file mode 100644 index 0000000..1af29d9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.Modules.fdf.inc @@ -0,0 +1,19 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Shimrra Shai +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/itx-3588j.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc new file mode 100644 index 0000000..272e886 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc @@ -0,0 +1,34 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Shimrra Shai +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ITX-3588J + PLATFORM_VENDOR = Firefly + PLATFORM_GUID = db88a604-ec99-4d39-84d4-af4fa5b5e757 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + + # + # Platform based on ITX-3588J board + # +!include Platform/Firefly/ITX-3588J/ITX-3588J.dsc.inc + + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc.inc new file mode 100644 index 0000000..2cb3d96 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/ITX-3588J.dsc.inc @@ -0,0 +1,120 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Shimrra Shai +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = Platform/Firefly/ITX-3588J/ITX-3588J.Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # PCA9555 GPIO extender support + # I2C location configured by PCDs below. + # + DEFINE RK_PCA9555_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ITX-3588J" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Firefly" + gRockchipTokenSpaceGuid.PcdFamilyName|"ITX" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://en.t-firefly.com/product/industry/itx3588j" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"itx-3588j" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x21, 0x22 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x6, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + gRockchipTokenSpaceGuid.PcdPca9555Address|0x21 + gRockchipTokenSpaceGuid.PcdPca9555Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_SATA) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac0Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0x45 + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + Platform/Firefly/ITX-3588J/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..cea6bd3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,511 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + // RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +EFI_STATUS +EFIAPI +GetPca9555Protocol ( + IN OUT PCA95XX_PROTOCOL **Pca95xxProtocl + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN HandleCount; + UINTN Index; + + /* Locate Handles of all PCA95XX_PROTOCOL producers */ + Status = gBS->LocateHandleBuffer (ByProtocol, + &gPca95xxProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Unable to locate handles\n", __FUNCTION__)); + return Status; + } + + DEBUG ((DEBUG_INFO, + "%a: got %d PCA95XX_PROTOCOLs\n", + __FUNCTION__, + HandleCount)); + + /* + * Open Pca95xxProtocl. With EFI_OPEN_PROTOCOL_GET_PROTOCOL attribute + * the consumer is not obliged to call CloseProtocol. + */ + Status = gBS->OpenProtocol (HandleBuffer[0], + &gPca95xxProtocolGuid, + (VOID **)Pca95xxProtocl, + HandleBuffer[0], + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + return Status; +} + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 0: + /* gmac0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2C_IOMUX_SEL_L = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO4C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO4C_IOMUX_SEL_H = (0x00FFUL << 16) | 0x0011; + + /* phy0 reset */ + GpioPinSetDirection (3, GPIO_PIN_PC7, GPIO_PIN_OUTPUT); + break; + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; /* GMAC1_MCLKINOUT, GMAC1_TXEN, GMAC1_TXD1 */ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; /* GMAC1_RXD3, GMAC1_RXD2, GMAC1_TXD3, GMAC1_TXD2 */ + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; /* GMAC1_TXD0, GMAC1_RXDV_CRS, GMAC1_RXD1 */ + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; /* GMAC1_RXD0, GMAC1_RXCLK, GMAC1_TXCLK */ + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; /* GMAC1_MDIO, GMAC1_MDC */ + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 0: + /* phy0 reset */ + GpioPinWrite (3, GPIO_PIN_PC7, !Enable); + break; + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB7, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + /* io mux M2 */ + PMU2_IOC->GPIO0D_IOMUX_SEL_L = (0x0F00UL << 16) | 0x0300; + PMU2_IOC->GPIO0D_IOMUX_SEL_L = (0x00F0UL << 16) | 0x0030; + break; + case 1: + /* io mux */ + //BUS_IOC->GPIO0B_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0990; + //PMU2_IOC->GPIO0B_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0880; + break; + case 2: + /* io mux */ + BUS_IOC->GPIO0B_IOMUX_SEL_H = (0xF000UL << 16) | 0x9000; + BUS_IOC->GPIO0C_IOMUX_SEL_L = (0x000FUL << 16) | 0x0009; + PMU2_IOC->GPIO0B_IOMUX_SEL_H = (0xF000UL << 16) | 0x8000; + PMU2_IOC->GPIO0C_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + /* io mux M0 */ + BUS_IOC->GPIO0C_IOMUX_SEL_H = (0xF000UL << 16) | 0x9000; + BUS_IOC->GPIO0D_IOMUX_SEL_L = (0x000FUL << 16) | 0x0009; + PMU2_IOC->GPIO0C_IOMUX_SEL_H = (0xF000UL << 16) | 0x8000; + PMU2_IOC->GPIO0D_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + /* On Firefly ITX-3588J this is controlled via the PCA9555. */ + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get PCA9555! (%d)\n", Status)); + } else { + /* USB-C */ + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 12, /* vbus5v0_typec_pwr_en */ + GPIO_MODE_OUTPUT_0 + ); + + gBS->Stall(1200000); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 12, /* vbus5v0_typec_pwr_en */ + GPIO_MODE_OUTPUT_1 + ); + + /* other USB stuff */ + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 5, /* vcc5v0_host */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 4, /* vcc_hub_reset */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 6, /* vcc_hub3_reset */ + GPIO_MODE_OUTPUT_1 + ); + + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 7, /* vcc5v0_host3 */ + GPIO_MODE_OUTPUT_1 + ); + } +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE30X4) { + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie30 */ + GpioPinSetDirection (2, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE30X4) { + /* vcc3v3_pcie30 */ + GpioPinWrite (2, GPIO_PIN_PC5, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE30X4) { + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER2, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 50000, + .DutyNs = 50000, + .Polarity = TRUE, +}; // PWM2_CH3 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get PCA9555! (%d)\n", Status)); + } else { + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 11, /* vcc_fan_pwr_en */ + GPIO_MODE_OUTPUT_1 + ); + } +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get PCA9555! (%d)\n", Status)); + } else { + /* (SS) NB: (TBA?) It doesn't *appear* we can regulate the fan speed, + * only power up/down, but I could be wrong + */ + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 11, /* vcc_fan_pwr_en */ + (Percentage > 0) ? GPIO_MODE_OUTPUT_1 : GPIO_MODE_OUTPUT_0 + ); + } +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Activate power LED only */ + GpioPinWrite (1, GPIO_PIN_PB3, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + +#if 0 + /* Red off, Green for status, Blue for power */ + GpioPinWrite (3, GPIO_PIN_PB2, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); + GpioPinWrite (3, GPIO_PIN_PC0, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PC0, GPIO_PIN_OUTPUT); + GpioPinWrite (1, GPIO_PIN_PD5, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); +#endif +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + /* (SS) does not seem to work and causes errors on I2C complaining + * about something being too high + */ +#if 0 + EFI_STATUS Status = EFI_SUCCESS; + PCA95XX_PROTOCOL *Pca95xxProtocol; + + /* On Firefly ITX-3588J this is controlled via the PCA9555. */ + Status = GetPca9555Protocol(&Pca95xxProtocol); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get PCA9555! (%d)\n", Status)); + } else { + Pca95xxProtocol->GpioProtocol.Set( + &Pca95xxProtocol->GpioProtocol, + 3, /* user_led */ + Enable ? GPIO_MODE_OUTPUT_1 : GPIO_MODE_OUTPUT_0 + ); + } +#endif +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..8becb63 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ITX-3588J/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,38 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Protocols] + gPca95xxProtocolGuid + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..2815d7f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C3" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PA6 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C3) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..5a66f79 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,368 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + // RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (0, GPIO_PIN_PD3, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 1: + /* phy1 reset */ + GpioPinWrite (0, GPIO_PIN_PD3, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + GpioPinSetFunction(1, GPIO_PIN_PA3, 9); //i2c4_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PA2, 9); //i2c4_sda_m3 + break; + case 5: + break; + case 6: + GpioPinSetFunction(4, GPIO_PIN_PB1, 9); //i2c6_scl_m3 + GpioPinSetFunction(4, GPIO_PIN_PB0, 9); //i2c6_sda_m3 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Enable USB-C VBUS */ + GpioPinWrite (1, GPIO_PIN_PB1, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PB1, GPIO_PIN_OUTPUT); + + // + // Power cycle vcc5v0_host as some USB 3.0 devices won't enumerate + // during boot otherwise. + // + GpioPinSetDirection (1, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinWrite (1, GPIO_PIN_PB6, FALSE); + gBS->Stall (1200000); + GpioPinWrite (1, GPIO_PIN_PB6, TRUE); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L2) { // M.2 M Key + /* reset */ + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie20 */ + GpioPinSetDirection (1, GPIO_PIN_PD7, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + /* vcc3v3_pcie20 */ + GpioPinWrite (1, GPIO_PIN_PD7, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER2, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 50000, + .DutyNs = 50000, + .Polarity = TRUE, +}; // PWM2_CH3 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (3, GPIO_PIN_PD5, 0xB); // PWM11_IR_M3 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Red off, Green for status, Blue for power */ + GpioPinWrite (3, GPIO_PIN_PB2, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); + GpioPinWrite (3, GPIO_PIN_PC0, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PC0, GPIO_PIN_OUTPUT); + GpioPinWrite (1, GPIO_PIN_PD5, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PC0, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + GpioPinSetFunction(1, GPIO_PIN_PA6, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.Modules.fdf.inc new file mode 100644 index 0000000..783d147 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/roc-rk3588s-pc.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc new file mode 100644 index 0000000..555b9d2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc @@ -0,0 +1,45 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ROC-RK3588S-PC + PLATFORM_VENDOR = Firefly + PLATFORM_GUID = d6741299-c347-4115-9f1a-1207fdf16ab0 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + + # + # Platform based on ROC-RK3588S-PC board + # +!include Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ROC-RK3588S-PC" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Firefly" + gRockchipTokenSpaceGuid.PcdFamilyName|"ROC" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://en.t-firefly.com/product/industry/rocrk3588spc" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"roc-rk3588s-pc" diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc new file mode 100644 index 0000000..b3dc9a9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc @@ -0,0 +1,107 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|Platform/Firefly/ROC-RK3588S-PC/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdBoardName|"ROC-RK3588S-PC" + gRockchipTokenSpaceGuid.PcdBoardVendorName|"Firefly" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x2, 0x3 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x2 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x43 + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + Platform/Firefly/ROC-RK3588S-PC/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bd5021dd0b29323c80d7645879353e7be82a9f73 GIT binary patch literal 148634 zcmeI52e{P4+JNc3cj>+N-h1!eMp3YV0*9)opj^F*UKB;)Dn(HNvHdDuIp@#>lrB|3 ziqcd-iqb(8{og|*hLqWCHk;i&ne#-MOeRyl%)C40n{Qfnnb|s3ilo1~{8yg;{x4;U z6r=e!Wr_m)U->IlHARY~|8D&CUGlKJ!XbgeP0QVovHVv`KuRF`B@hk_$T*RJWMTAI ze)~C0lQCW90@-tv%9pF$Ejh~;$XOjWJvo@yl%LNkUUqpyJ_?1 zZ|n5V13f++*(YI~T3dQ98r9|9p)IH0Sz~DHf(^^0%a+lNG-VtSlz{qerNdnbgo%a4 z+g5ffpLB8TRJ?{0y1SBMkB{Th=g6c>v3MKTij%Ea9$n;)Z?hK3RrTKH9pAd&e!;se ze6aS&_PNU25~<^i$rr;Z0sCKDh73vqVPaviR+WOvh9EFwJv%k4{-a$5k=TFK?So-P z78Yw&(S8hqkiFx_W-FT8PI1Ix7zo!I(T+Z!XX5uooe^DWFX8{?YruO8hiY&|SNF9nq??tuY7u9}Dc!ARx~v&=k=wk5SnXyFRzH28 z#BsHTw}pSmhhnyRxu4aLnO8t2D=Q`1R|WH|HCGzYSQ{8RQX-q#kijA?0ksN*&(UYe zIIiAYiDP@2T}h9whv}1ylpQ@_As}fq>89RHP#@937&&*vLT&$hcTlOQfdh__nF`f) z&eV79IGl}y?7;xRu3z!w`uY6HgQtGj zef+x}$M>u`u<7%?D;IwAzgITRd-AJShpu?K?~+H_$H%o=JgjZ}a9GiCc#q{c!2-KCX=VzmuKGUaM z@4CzmGMdhiD+|MCCJ6J_D$WdOiz#=oxU7AJA$GYw*LQy1Rv&-*izq2Zx|PfH?MOiT z83Vd|CXVft5J#sCCf&AV{J2#w%=mi2XM2`!`eDbx(?9%j@yw;GSFZhe?ax2|{43-? zBH{1qAHScweBtQX6W{*)-Kql{0Oa%QXFvGGGu;!$DB0+mFp8mfz?^#@z+)EDF)G=q zI_;GbT}t&@$lq2Xm;kM|D8{+B!z$q+Ysf4XIxv{tD6bRQmx< z-H?W^7~tuU5O?2-f4#8b%|+iX-*I%$&*x5EzIp{*g-pHRB7n5#uUt6%%TMc%Y+d-x zXHTw~-f!t+45-`04@=@=)btm3ESr$jmyM4Y6eSDo)bEI}kWZsldz5h)Qi9nWp2QPne_SO%!{*#OT@K^Xggd2rJcYo@nPh+~N* zd;@36LOU(SYZj(V(fZYa3jCPZW2=g4R-xrf{p@5|hDp8>u)~k!7lu`qZ;tJKY2#a6 z6GyXF6b>SK&%!K)a)zUxMrIuuotoTPTrUnw#%zjHScrjIG^o{1A$y8lPfkV{QxZsi zoU>mdW)r_Vb$G_+1>LSI5V=c4uUQyBwp`zOB#MOto0m;v1`%N)y4GcS)GpGryv?#; zroxWuIOb*)_+dc-E;f0(w{nY}S@z?_RKt~-bzK7X$&p+`Ld5S+AAyLS6Gky=RyztI zIy`2fgWQI=2d_go^$Q&o$Ic!+v|W^#$$W;KnN`cxt)}&Ny=BP=V@(3dm2kn93nK10 zao|52-e7wn`&S&aMcpgW&qAlR8UEgn991l|X`2DvLFF?wpK?1LL3O-bcWkFvYq&DM zu1g?TW;hNHZ1^+2uK1fiG6oK}56jJ4e%kfOms3$mMD1LMx1eslVWIanyRhe{$RQjo z47bfL)=QMkH=Nj=Lrqk(3M?+W-m+wbu_gg`=>pQw&AD{-GIko+GQ98PfsKc@tvt9P zasTQMzghgw)=%ba`)KyI54G3atslR;ebHyTm#sLk?yCcvb{zfo!08{3ojq~x%7x#4 zzZwxnVqqe2|Ca-nPG}cD+_6bT4_L^-Nt`c-wUqLG>jih+TEG0Q^)uwkY^Sz*HeZM_ z1`hXgRvhL^?VLo1Dz(DGy5l;t-9%kPu6SodJED+blC=avWFf4=Lc{U1CwCs(xBR=c z^R|ETpY?OF+;!Koi8r?MC0Q|~n}wb;XkpP-cj3vfwDsboFpBA!PVpmeUosv=z=>Z? zo4#rON4pZ&9NNqx$1fMpvims14BLPG__z6Fp!ds=};((!Q}q zAJnB7s?U_))@p%wENoNRadGJI*+F~FVSo1v8$HnjQx?mwvk(?p`DDZ~k#7>gYf^*y4D>!bsS)j_ENnhqWlbU~I$7 zm^UjH`jy*yk94uqSY()FEdiBq0UcMa{>HGE&fm06Z_{b(lrR$bVapZrd0;6EK*Cq{ zi-23ui2cIRE1!R3>j&!&Z#jPMK)PRhPaODgSN!VPG35P%Ni)}y0i%>zIKcw zddxzUN{Y6u$f3Qt$``bG*)#<0*?gha#y_ko+@xI2G6igwg>$Uz7*k|ite)spsBu{g zcBwT}8rn*}kh57b9T?~UoxXVHiv#N?t(n1qlzB3`Uy-c7y^;`|czGLOXp;O4N zMRoZEtJKo^swyR4I#f15LC!3hzx~s@mpuVa0AY0Y0>uPUo|5yV>CE_HLsmRZ*Y?LV z$0(gz($F3IP97YwaxyF6g3Nf<T69P7AKozmf9Qlymtw*Gc_|tjpVpL54}D5&#Sg zhdHh8rHyZ2x9~SSL>*(bW<`TTwa)n3=6Cm=JmBKMncnk@8|U()VfBk4S!k!lSj`tE z?H3M@jsNT=@~T#>OLeKi@lt9$s$3|Pg7(SVg&-6G;( zLJ_4#dWvkZgZgeAS-?8Ydpj4inqoSAC|PKyxp>b)a;5eK*^i7x2h~CYm6O#JJK2_D zlA{Dz7s390L=fe1qIBR`0jIprub;E$#P_a@nu&y6HC+=%8`W(j3+*(Qh_H~|Eo$9k z$4QogIXMJb^+6HcPR>okaGo9q&Q}`H*z~FNjBW|2Rlp|>)`1`*eMDA-QI`yT?vNO^ zAN`h7RdlwpB@69T{D`oSjHz8i7OWXHmuOc-TmS1l+?hk|?Brh?hVgaNXZtGgunoxO zGQBni>5ixbv{k@AZu*FfnmOeKtN(1B4xNZt{Tj0TDbCMQW#~N%>EDE-Dn&%6CTSfx z47OZV`EZ0g6jVM|(g{!*)3FUt{dPE5R^|+4HGDt^=caUe`vGkX1slo}0|JUIssd=g zp5NTeBce3K9-6NXZw`H@^U*Uuk6rx&h*iYsH4Ed%V$}c@Ll#2=UKn-YvSZAEx*8D{ z0xHfdwqG1{6Ybb?)iyoErB-;R3{#~^Rbyyt)dvUq+mt2~~ffB|da;c~O_Hyp2i;=)R;X>aj+Ds zhuEhN#|NjKso#jnHn|^Jk%moMuDUP6DF^ICR^^Go2Il;7S1iP+S@qO8dVM}dRnOKv z;ub~jtVMF8v#tFBVeFhXb9!CU@;3S;VEmrG^+7eJ<>H4}Wj=cLL?|6ZaQNif8JQb} zWpJcpp}M2i!B>mIej%o`927)(#X-N2=9n>0*0!(zL%uExALL|EI*4Vu*XlHHi2clP zwlek?i7*MJn$BX^_a3roKRo)_;I|yv|JptYNe6M@vWe@DYz;-}=JcgA4ca#iM_tmg zuxN{l7$oKYMVgg&a7EkMPs|QFFHY0)j*ofA@L`J=@6=Xreqk60vk=UlXz&crv`UXfhCu@Ahm{Uh0?Z(yLA_wdqKm&> zcHBYi)2B}uK357Y3tPW3pw5_%4lcIha&Zuxog8Y1dvtojXTPxZtIms4XLN@QxtyON zid_e^VAKkLgN2jE|LRq+e(AJX(z7Z9r1`Ze+p7+`gY4of+p{*N9q5VjBAv**Rf}LK zo0&pw42_@aEqAflsbEnPM*H=oTa^GxH|(#&K*h0h4#&$Luu#pdGe@+Ik)4%7eaqPx zS=$hq;??QJ5ILPfpjhFK28^AN82v>q4CrvW0t+q7*BXb?-9H+^5L+9wbjN}O)T$&M zMhP%pzGwNQUB~x3=pBZOg{}WtJ27TBC?A{iScZOKe6gBydL zJ`5KNHS5T_tOk1pA* z)|Z(+{CM}0po}_%iG_4rU>G)AL%WEffX!`YOeLQ zb|JO}{p%@Hu=0Vu*Lvf-pkmnN-Jx{*Py**-YLLETyVnP?`W0^o4QrUf<^mn92hwMoc)`&0swb3sXf#pRbaymjHXO96X_l7&8PQL@;vDuJL# zAOj--j=`F|e)fgmE{bs|Ss1HLLgw425|DUvAOWn~Ox-Z|qOf-;S?JRiC5s)a5^z8Q z`3e$Xu>8u#cdlHuTuPBFjMXL~^X*d!NU%AU063hp^+PMehmwUpZBeq=u_^(_B#R-1&(w@)P?krs*s&^v4sKYZEuYmMtDl7&8PQL@;vDuGZ)Am2p- zy%WcFiXXY{=x!YjB@1J|KUXKs1_+Mj;lmOPfdMA!MaQX;1l>I_qw<}rr*pq;ZB#==dfzAmd zIU@Pe)ytBFvDX-6j(sfw2{6|s&@O(&tZnai?%vhc6-yRgN+8B0;5rFpgh-%k!l;5x z%Enk#klB?I@U;Xay22!Z!cEKhx?;(~O9{l71j0lD8LebtjI{)rUB62}LMu!XkSz3j z(~{+nF$uU%f}ZTpO^9n3KfHbX2&T=jUf_BXZbjH<$-~_fM{@`=x$PJq$5uMGVkRER z!We4_GP{14fQzlaXW|%)w%otssi~XZn!Ej@+1uWqxb{`h2y9$T#jU7NeqrO>xG!IP zee1%vwtqBz^Zenfo?{8PTf%5pk_ZzE3+BntvSyxU)%92N>UkPh$(25BDz_?hu>zT_ z5^7Z0ZbEg+=OAOo+$uh;YUV9*OD1iGE0@UHqJ~L$Jb9!Isdd*Vlil7f-mb-Sj9Hk0o&Y3lB z%9O_JIP@u!FQaL-(WP$l79lsRoC|@Q=B9L^%%*AaR^19YgD;dT?VdM&-i7wpU)VW4eCFuPt?ze8i0d6q9YoGMp1fi9o|E5S(VX#l@#^I*M|VB^&-*!n->ZJ^X$<(`)a%){xS));RDS*|(HwDtPXGyH$Z)=>x`Dt85Od7*u~Srj6&V zM{BB&bdI^>YidJk-HV>7uM6zf?TFr`vI9p zR&lESGsjfdy{O(M{HLKB%)Wy}zn)v&6?A3ar9oRH(E5A`f*Oq8a%X=Zb)IEVK#dBqrs&S$~I+Ex*2 z{b!7-rh8Gn{oiC4eh@(8|2yZ2M5{xtike((hL$t((y$VPq%? zC1VzDf1^dfw!--9(0gsIsw)0#XEbGWrq*l45i2a*__~`cyrXqtfuOXHW{eCk3)Qsv z#1jXWE1WmzpH|mdNVhe1SP0?P9NBCN6|Lu$Kdw$#^9rjep#UbtcbU8#ykgSnOJ}qh zGj;Djb*O9N=uj4Ze9pqz<1Bl4N`vd&yr2$*-1?A(%r?;VQ6VIDc*a5{8#~@?$(Yw_ zy3Y9d@bNJV=@dS=@)^dJrbN+st~#_4!&V{kER@$-FP^{iGhMDsZ?FA%ZSsa$p>z%X z%))@3!i7)NF>OgcWZ{bsRT1+~`_y9=DoKC%ue$c<5q-?UjtOxywk$BkiP7`OnWNnj z$Ar?^3I&9`3yHrzy3?33Q=dh9mvbz<;}reOLUE_?`*+*umP}MG`i+GwgKAM1&>ayL zlB=z=Td?k|ekOs#$1FsNW}&^F7QFfS!s*+WJ{G|RWyq}<)G~#i&U5wQO|2G77MiSC zi{}e#mk+Rf%<`XAWAYUXGi6ARFT?rM39B#5Tz{?D|Metck5#oGNbnF`dQ4b=|Ez7yXWKq6b&7ZIzxXEyVENV zZ7|K7(R1E6in!}_-}O*JCRYxwdKGh;>L{U86Z$%G zm6F-)C=}`#>41f#GNfCHUd;;jZBa~L$j-`)=h;1LTP~0he{((w@daXS20}B~r(nAsePw*(LEL1)L8;S$&<5@nn z5#Tian*L@Xhyoiu635b)Vgs^{E8HGGe-aReGWX^R1=UCxDUV(~<-5~|jakKK^U+;* zEq?<0HEMWg4!^Nb+$p3_U^@4vYfpY);Y-5;C=?!CXt`g<0~Yc{7&W6)C_plgdNwst zmFHdGvk+P^amZZYQ|n$^dt}RxXOGkIVprb2QwQ1kJ7C#_Xy_4Yk;e9yo=e8PvHhc+ zKkxhb!YOjg5FQFn`}&=Z2_r+9CR9`L8w&*(qv^24Rfj#(TR|kw_9I8z7@5TbF=K!b zmJ+POc*8tJY)iVZdxSo`U>Y(k$Uk1#<9voUJuN0oB07|dS5>&*e$NO0w=3T=+P$S)@_qw5n*Aj zYPKK!k#Ll0m=lkvjq?6iymc9w7+Er(Uu! zeY#XDge%LY!(_?An^|Z@9bfr-&%!Zq5Eeffh}pba*Urn{DpL!v0v2Mw5X%Zm zLfFkjS?z%J6xWLnR@PEe>~@`nZ$ynw4GM+(7lP*80Jj{uvg{+WPY-b!VHxjQX`1)4Cn#)L>)zy(jDFgrmDf9a>2xdRWLV6I~{?x9>bw zODh(|?IjDbKda4;*1h4iW~=}ivnTZN5)ZygD^^&DiROG}o8nwyAv%S`k5wAzlGTQu zt?Mk*wvV9Pn2)h)Hx5`hpj`lk!g-JX!0uxhDn41}!m zhJWw|#(l*nFAFPKsH>-6zS5*q{rpydQT(Hah0j@QLk7!2)?`sB(n&*m%QiV|{Hv0Q z9u{UypL+GQCfclO-F#32sM%H=-mnk`3#6oE5~;#VUG{{xUgE)5X-O7p+l}gG8?2x{ zCQBAh8(vi{zNv#X6|GDJt=!}JLN)@^`7_Nko@~lC_VvACq0LiOkfhaKX05<)xP8SZ zFAFPKXw`-Wce2zqOnxkEQ#*h{At!U_h!Q<4Wb^o9YZjW$$$7xS@49Jm_ecH;5h3t5F? z`dM3@#BQhwJ54K_!P8fK^0Kh8!a|e~0X^o-BwVIk_O zg00h^Ki9xG0u46{*}x?Iz2l~zPp_}zjwx(m%e7IUpGDh|{7!LB2t zC%5#4Mu}4z>Mm4s88?Zw=#;9;mRr-VVRB+2XTS3;j7?MZL7U0+9Fgc@A+`q9+!`Hk zKl;zwx7x=FD+>|V&bh6OISJ@vZwsie_~d0_y=NiE7IWxQ=|Y*y7RjPqWeR7mTp}xn ziwG{5WV%64pi}eJt4*;_Pxa^LR(mm|;`l}qgM7V;y&#F^bwyew=)Sg6}3tkzHmjsPsQXvf-wz>i?OY&!GqIt#tGYt6!C?riDMFc-8- z9q{W=-2 z5Cdf>4Ox{Mf4Yo?^Ja)<7M8drQ^4uo;k`}Im;7YZ7p@+jb%W@P(?*eyaCKwJuzBCK%kIt!V& z6QZFAFPK$cnaL{)Pn@WieV?F_S^RP}~qXqttY0sTD$` zSV(tp^8J-qc^4Ofr;qh7tIe?1?K%sm$5j*O=U;;=XfuFYFd88$$ZD}L<|Q6{m6rD` zWCqT-4?tH}|RLMx?iW7770#PfxMB7+$_7R+2{p{f3; zQeMD}>4;7Z^0U)fJVB_IYt8hgIkVnm$yX~ncUjn_VF5K=QwI|cMzFDnBG&ADHLj{Q z&o|t@;**z!^`3={T(E)HwobnGb%VG%)XUGX$k!`xzx4K4B;_b%)5@!Q zVu;iDvg<5lZv;DngA#}m7?V1t>!jq_F$)Dci&{~*%R-j&Ck`z4P|uRg@F^F1jU)S( z!V>FiqpPz7vg<9;8j1S7R0kDIn_HdRMHZr#wf?^WM(dPImjUHga9pTTkj@PY7+&-e z557vvdlss-HCP9VSscZos~Q3p0$rLlV-vJ()r(t9SYwBeeuJG1m>T|forQLCVio4! z_n50&J7XbMUGkdQiPVXmTX$J#RXS(>Sh_Z5SnJ~=3#m@xOtQeEGi#yd1hpnHM|o=a z9KPa{mxYZX7BY1g6br>Q)Xr1ZRE%aosmM{qLgn-kwRx!yXDr09wi<)j5w$F2Hc^~& zp1Q?CdY=I+(yc;~q6#jK;f0~P(SRmqiwRwrnh3L!dKIAK6J z)7wbUdz-|n+CW;5fP zf-OF3W&%3UuR-sVE!F7B8A*lXgE&n2`g*jl z_~d0_!^Fb=ZIe!y08El?E4U*sRkt3WgS`Br6!Jz7%0w7#j|%~RU9H@6NXhBi=L?;lo0qv zYzbdGqbZ9JM2iX)GjIj-h&D=FC9U3|Kq<@C0i#D*%jeP~o-=L9hd|mM& z66`A!4`$3x5-hP;iBygD`nUEH557t(Oe~}}F%gd$5f`s=MYC|qkM57n3eFP3_+QC_ znRq>*jYD0E+%h#~nkb%vSu4zRn!Xi^h=|a*p+U(oZHqo`z{rUKY8uNJ(8sDcL@4-G zp(huV5J-jNkFE6c0%p=G07`pS*+6&QRFO)JiapK@eg%RhW;P0{;q5!f6=uc-G4m)z q3SaTb%fg0 + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..405ac5e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/AcpiTables/Dsdt.asl @@ -0,0 +1,44 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + // include ("Usb3Host2.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..f27cee8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,354 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO4 PB0 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + + /* Set GPIO4 PC6 output high to power the 4G/LTE module */ + GpioPinWrite (4, GPIO_PIN_PC6, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PC6, GPIO_PIN_OUTPUT); + + /* Set GPIO1 PD2 (TYPEC5V_PWREN) output high to power the type-c port */ + GpioPinWrite (1, GPIO_PIN_PD2, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable on-board LED1\n")); + // GpioPinWrite (2, GPIO_PIN_PC0, TRUE); + // GpioPinSetDirection (2, GPIO_PIN_PC0, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinSetDirection (2, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L0: // rtl8152b + GpioPinSetDirection (4, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L1: // m.2 a+e key + GpioPinSetDirection (4, GPIO_PIN_PC2, GPIO_PIN_OUTPUT); + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: //rtl8152b + GpioPinSetDirection (4, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* output high to enable power */ + + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (2, GPIO_PIN_PC5, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (4, GPIO_PIN_PC2, Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (4, GPIO_PIN_PB3, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinWrite (4, GPIO_PIN_PA4, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (2, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (2, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (2, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + GpioPinSetFunction(1, GPIO_PIN_PC4, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..ec569ea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.Modules.fdf.inc new file mode 100644 index 0000000..25edcdb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-nanopc-t6.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc new file mode 100644 index 0000000..926b9a4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPC-T6/NanoPC-T6.dsc @@ -0,0 +1,116 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Molly Sophia +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = NanoPC-T6 + PLATFORM_VENDOR = FriendlyElec + PLATFORM_GUID = e5022309-24e1-46e0-9d40-dcbc7293e609 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"NanoPC T6" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"FriendlyElec" + gRockchipTokenSpaceGuid.PcdFamilyName|"NanoPi 6" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://wiki.friendlyelec.com/wiki/index.php/NanoPC-T6" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-nanopc-t6" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # NanoPC T6 has two 2.5 GBE wired to the first two PCIE2 ports, while the third one is wired to m.2 a+e key + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..63c8600 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/AcpiTables/Dsdt.asl @@ -0,0 +1,39 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588S", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + //include ("Spi.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..6525824 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,342 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB7, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO4 PB5 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinWrite (4, GPIO_PIN_PB5, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB5, GPIO_PIN_OUTPUT); + + /* Set GPIO1 PD2 (TYPEC5V_PWREN) output high to power the type-c port */ + GpioPinWrite (1, GPIO_PIN_PD2, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable on-board LED WAN\n")); + // GpioPinWrite (1, GPIO_PIN_PC2, TRUE); + // GpioPinSetDirection (1, GPIO_PIN_PC2, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable on-board LED LAN\n")); + // GpioPinWrite (1, GPIO_PIN_PC3, TRUE); + // GpioPinSetDirection (1, GPIO_PIN_PC3, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable on-board LED1\n")); + // GpioPinWrite (1, GPIO_PIN_PC4, TRUE); + // GpioPinSetDirection (1, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE20L1: // RTL8152BG + // GPIO1_A7_u - PCIE20x1_1_PERSTn_M2 + GpioPinSetDirection (1, GPIO_PIN_PA7, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: // M.2 SSD + // GPIO3_D1_d - PCIE20X1_2_PERSTN_M0 + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* nothing to power on */ +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (1, GPIO_PIN_PA7, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (1, GPIO_PIN_PC1, FALSE); + GpioPinSetDirection (1, GPIO_PIN_PC1, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (1, GPIO_PIN_PC1, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..ec569ea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.Modules.fdf.inc new file mode 100644 index 0000000..67fe4d8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.Modules.fdf.inc @@ -0,0 +1,19 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Sergey Tyuryukanov +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6c.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc new file mode 100644 index 0000000..268a600 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6C/NanoPi-R6C.dsc @@ -0,0 +1,114 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Molly Sophia +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Sergey Tyuryukanov +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = NanoPi-R6C + PLATFORM_VENDOR = FriendlyElec + PLATFORM_GUID = e5022309-24e1-46e0-9d40-dcbc7293e609 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"NanoPi R6C" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"FriendlyElec" + gRockchipTokenSpaceGuid.PcdFamilyName|"NanoPi" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R6" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-nanopi-r6c" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..4caa5d5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/AcpiTables/Dsdt.asl @@ -0,0 +1,39 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..403a082 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,329 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB7, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Set GPIO4 PB5 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinSetDirection (4, GPIO_PIN_PB5, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PB5, TRUE); + + /* Set GPIO1 PD2 (TYPEC5V_PWREN) output high to power the type-c port */ + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + GpioPinWrite (1, GPIO_PIN_PD2, TRUE); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* found info from nanopi r6s dtb */ + switch(Segment) { + case PCIE_SEGMENT_PCIE20L1: // rtl8152b + // PCIE20x1_1_PERSTn_M2 + GpioPinSetDirection (1, GPIO_PIN_PA7, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: // rtl8152b + // PCIE20x1_2_PERSTn_M0 + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* nothing to power on */ +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE20L1: // rtl8152b + GpioPinWrite (1, GPIO_PIN_PA7, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: // rtl8152b + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (1, GPIO_PIN_PC1, FALSE); + GpioPinSetDirection (1, GPIO_PIN_PC1, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (1, GPIO_PIN_PC1, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..ec569ea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.Modules.fdf.inc new file mode 100644 index 0000000..6b82ba7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-nanopi-r6s.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc new file mode 100644 index 0000000..fb28705 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FriendlyElec/NanoPi-R6S/NanoPi-R6S.dsc @@ -0,0 +1,112 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Molly Sophia +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = NanoPi-R6S + PLATFORM_VENDOR = FriendlyElec + PLATFORM_GUID = 4a2e5415-53e2-48b5-9a4f-3b34d9e8ef6f + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"NanoPi R6S" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"FriendlyElec" + gRockchipTokenSpaceGuid.PcdFamilyName|"NanoPi 6" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R6S" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-nanopi-r6s" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..689c760 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/AcpiTables/Dsdt.asl @@ -0,0 +1,60 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PC0 + +// +// WORKAROUND: +// SDMMC may be unreliable at UHS-I speeds. +// +#define SDMMC_CAP_DDR50 0 +#define SDMMC_CAP_SDR50 0 +#define SDMMC_CAP_SDR104 0 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f4729189423af42a10b3e261e696f0f574588442 GIT binary patch literal 119030 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 + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.Modules.fdf.inc new file mode 100644 index 0000000..25791fc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023-2024, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # TODO: Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-fydetab-duo.dtb + } + + # Splash screen logo + INF $(PLATFORM_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc new file mode 100644 index 0000000..9604b88 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/FydetabDuo.dsc @@ -0,0 +1,113 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023-2024, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = FydetabDuo + PLATFORM_VENDOR = FydeInnovations + PLATFORM_GUID = de3232fb-1716-4f63-a8fe-67a623ae5297 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # No HDMI output on this platform + DEFINE RK_DW_HDMI_QP_ENABLE = FALSE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Fydetab Duo" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Fyde Innovations" + gRockchipTokenSpaceGuid.PcdFamilyName|"Fydetab" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://fydetabduo.com/" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-fydetab-duo" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x50, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # SD card detect signal is inverted + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(PLATFORM_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/CsotDsiPanel.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/CsotDsiPanel.c new file mode 100644 index 0000000..f0bedf1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/CsotDsiPanel.c @@ -0,0 +1,171 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include + +STATIC UINT8 mCsotDsiInitSequence[] = { + 0x0a, 0x31, 0x58, 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0A, 0x00, 0x06, 0x40, 0x00, 0x28, 0x06, 0x40, 0x06, 0x40, 0x02, 0x00, 0x04, 0x21, 0x00, 0x20, 0x05, 0xD0, 0x00, 0x16, 0x00, 0x0C, 0x02, 0x77, 0x00, 0xDA, 0x18, 0x00, 0x10, 0xE0, 0x03, 0x0C, 0x20, 0x00, 0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B, 0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40, 0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8, 0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6, 0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0x74, + 0x39, 0x00, 0x06, 0xB9, 0x83, 0x12, 0x1A, 0x55, 0x00, + 0x39, 0x00, 0x03, 0x51, 0x08, 0x00, + 0x39, 0x00, 0x02, 0x53, 0x24, + 0x39, 0x00, 0x1D, 0xB1, 0x1C, 0x6B, 0x6B, 0x27, 0xE7, 0x00, 0x1B, 0x12, 0x20, 0x20, 0x2D, 0x2D, 0x1F, 0x33, 0x31, 0x40, 0xCD, 0xFF, 0x1A, 0x05, 0x15, 0x98, 0x00, 0x88, 0xF9, 0xFF, 0xFF, 0xCF, + 0x39, 0x00, 0x12, 0xB2, 0x00, 0x6A, 0x40, 0x00, 0x00, 0x14, 0x6E, 0x40, 0x73, 0x02, 0x80, 0x21, 0x21, 0x00, 0x00, 0x10, 0x27, + 0x39, 0x00, 0x2D, 0xB4, 0x64, 0x00, 0x08, 0x7F, 0x08, 0x7F, 0x00, 0x62, 0x01, 0x72, 0x01, 0x72, 0x00, 0x60, 0x00, 0x00, 0x0A, 0x08, 0x00, 0x29, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x00, 0x00, 0x0F, 0x0F, 0x2D, 0x2D, + 0x39, 0x00, 0x04, 0xB6, 0x8F, 0x8F, 0x03, + 0x39, 0x00, 0x03, 0xBC, 0x06, 0x02, + 0x39, 0x00, 0x07, 0xC0, 0x34, 0x34, 0x44, 0x00, 0x08, 0xD8, + 0x39, 0x00, 0x06, 0xC9, 0x00, 0x1E, 0x80, 0xA5, 0x01, + 0x39, 0x00, 0x07, 0xCB, 0x00, 0x13, 0x38, 0x00, 0x0B, 0x27, + 0x39, 0x00, 0x02, 0xCC, 0x02, + 0x39, 0x00, 0x02, 0xD1, 0x07, + 0x39, 0x00, 0x29, 0xD3, 0x00, 0xC0, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x14, 0x02, 0x07, 0x07, 0x07, 0x31, 0x13, 0x12, 0x12, 0x12, 0x03, 0x03, 0x03, 0x32, 0x10, 0x11, 0x00, 0x11, 0x32, 0x10, 0x03, 0x00, 0x03, 0x32, 0x10, 0x03, 0x00, 0x03, 0x00, 0x00, 0xFF, 0x00, + 0x39, 0x00, 0x31, 0xD5, 0x19, 0x19, 0x18, 0x18, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x00, 0x00, 0x01, 0x01, 0x18, 0x18, 0x40, 0x40, 0x20, 0x20, 0x18, 0x18, 0x18, 0x18, 0x40, 0x40, 0x18, 0x18, 0x2F, 0x2F, 0x31, 0x31, 0x2F, 0x2F, 0x31, 0x31, 0x18, 0x18, 0x41, 0x41, 0x41, 0x41, + 0x39, 0x00, 0x31, 0xD6, 0x40, 0x40, 0x18, 0x18, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x07, 0x07, 0x06, 0x06, 0x18, 0x18, 0x19, 0x19, 0x20, 0x20, 0x18, 0x18, 0x18, 0x18, 0x40, 0x40, 0x18, 0x18, 0x2F, 0x2F, 0x31, 0x31, 0x2F, 0x2F, 0x31, 0x31, 0x18, 0x18, 0x41, 0x41, 0x41, 0x41, + 0x39, 0x00, 0x40, 0xE1, 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0A, 0x00, 0x06, 0x40, 0x00, 0x28, 0x06, 0x40, 0x06, 0x40, 0x02, 0x00, 0x04, 0x21, 0x00, 0x20, 0x05, 0xD0, 0x00, 0x16, 0x00, 0x0C, 0x02, 0x77, 0x00, 0xDA, 0x18, 0x00, 0x10, 0xE0, 0x03, 0x0C, 0x20, 0x00, 0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B, 0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, + 0x39, 0x00, 0x0C, 0xE7, 0x06, 0x14, 0x14, 0x1A, 0x23, 0x38, 0x00, 0x23, 0x5D, 0x02, 0x02, + 0x39, 0x00, 0x02, 0xBD, 0x01, + 0x39, 0x00, 0x04, 0xB1, 0x01, 0x23, 0x00, + 0x39, 0x00, 0x25, 0xD8, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, 0x20, 0x00, 0x02, 0x22, 0x00, 0x00, + 0x39, 0x00, 0x1A, 0xE1, 0x40, 0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8, 0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6, 0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4, + 0x39, 0x00, 0x0D, 0xE7, 0x02, 0x00, 0x40, 0x01, 0x84, 0x13, 0xBE, 0x14, 0x48, 0x00, 0x04, 0x26, + 0x39, 0x00, 0x08, 0xCB, 0x1F, 0x55, 0x03, 0x28, 0x0D, 0x08, 0x0A, + 0x39, 0x00, 0x02, 0xBD, 0x02, + 0x39, 0x00, 0x0D, 0xD8, 0xAF, 0xFF, 0xFA, 0xFA, 0xBF, 0xEA, 0xAF, 0xFF, 0xFA, 0xFA, 0xBF, 0xEA, + 0x39, 0x00, 0x23, 0xE7, 0x01, 0x05, 0x01, 0x03, 0x01, 0x03, 0x04, 0x02, 0x02, 0x24, 0x00, 0x24, 0x81, 0x02, 0x40, 0x00, 0x29, 0x60, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x02, 0xBD, 0x03, + 0x39, 0x00, 0x19, 0xD8, 0xAA, 0xAA, 0xAA, 0xAB, 0xBF, 0xEA, 0xAA, 0xAA, 0xAA, 0xAB, 0xBF, 0xEA, 0xAF, 0xFF, 0xFA, 0xFA, 0xBF, 0xEA, 0xAF, 0xFF, 0xFA, 0xFA, 0xBF, 0xEA, + 0x39, 0x00, 0x03, 0xE1, 0x01, 0x3F, + 0x39, 0x00, 0x02, 0xBD, 0x00, + 0x39, 0x00, 0x2F, 0xE0, 0x00, 0x13, 0x30, 0x36, 0x40, 0x78, 0x8B, 0x94, 0x95, 0x97, 0x94, 0x94, 0x91, 0x8F, 0x8F, 0x8B, 0x8A, 0x8C, 0x8E, 0xA6, 0xB7, 0x4D, 0x7F, 0x00, 0x13, 0x30, 0x36, 0x40, 0x78, 0x8B, 0x94, 0x95, 0x97, 0x94, 0x94, 0x91, 0x8F, 0x8F, 0x8B, 0x8A, 0x8C, 0x8E, 0xA6, 0xB7, 0x4D, 0x7F, + 0x39, 0x00, 0x05, 0xBA, 0x70, 0x03, 0xA8, 0x92, + 0x39, 0x00, 0x25, 0xD8, 0xEA, 0xAA, 0xAA, 0xAE, 0xAA, 0xAF, 0xEA, 0xAA, 0xAA, 0xAE, 0xAA, 0xAF, 0xE0, 0x00, 0x0A, 0x2E, 0x80, 0x2F, 0xE0, 0x00, 0x0A, 0x2E, 0x80, 0x2F, 0xE0, 0x00, 0x0A, 0x2E, 0x80, 0x2F, 0xE0, 0x00, 0x0A, 0x2E, 0x80, 0x2F, + 0x39, 0x00, 0x02, 0xBD, 0x00, + 0x39, 0x00, 0x02, 0xC1, 0x01, + 0x39, 0x00, 0x02, 0xBD, 0x01, + 0x39, 0x00, 0x3B, 0xC1, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x1F, 0x23, 0x27, 0x2B, 0x2F, 0x33, 0x37, 0x3B, 0x3F, 0x43, 0x47, 0x4B, 0x52, 0x5A, 0x62, 0x69, 0x71, 0x79, 0x81, 0x89, 0x91, 0x98, 0xA1, 0xA9, 0xB1, 0xB9, 0xC1, 0xCA, 0xD2, 0xDA, 0xE3, 0xEA, 0xF4, 0xF8, 0xF9, 0xFB, 0xFD, 0xFF, 0x16, 0xA4, 0x44, 0x16, 0x90, 0xE7, 0xF9, 0x71, 0xA0, 0xF3, 0x1F, 0x40, + 0x39, 0x00, 0x02, 0xBD, 0x02, + 0x39, 0x00, 0x3B, 0xC1, 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x31, 0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x55, 0x5D, 0x65, 0x6D, 0x75, 0x7D, 0x85, 0x8D, 0x94, 0x9C, 0xA4, 0xAC, 0xB4, 0xBC, 0xC4, 0xCC, 0xD4, 0xDC, 0xE4, 0xEC, 0xF4, 0xF8, 0xFA, 0xFC, 0xFE, 0xFF, 0x06, 0xAA, 0xFC, 0x5B, 0xFF, 0xFF, 0xA4, 0xF9, 0x86, 0xF9, 0x55, 0x40, + 0x39, 0x00, 0x02, 0xBD, 0x03, + 0x39, 0x00, 0x3B, 0xC1, 0x00, 0x04, 0x07, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F, 0x23, 0x27, 0x2C, 0x30, 0x33, 0x38, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x53, 0x5B, 0x63, 0x6B, 0x72, 0x7A, 0x82, 0x89, 0x91, 0x99, 0xA1, 0xA9, 0xB1, 0xB9, 0xC1, 0xC9, 0xD1, 0xDA, 0xE2, 0xEA, 0xF3, 0xF6, 0xF9, 0xFA, 0xFE, 0xFF, 0x0F, 0x9A, 0xFC, 0x31, 0x40, 0xE4, 0xFB, 0xE9, 0xA3, 0xD9, 0x77, 0x00, + 0x39, 0x00, 0x02, 0xBD, 0x02, + 0x39, 0x00, 0x02, 0xBF, 0x72, + 0x39, 0x00, 0x02, 0xBD, 0x00, + 0x39, 0x00, 0x08, 0xBF, 0xFD, 0x00, 0x80, 0x9C, 0x10, 0x00, 0x80, + 0x39, 0x00, 0x02, 0xE9, 0xDE, + 0x39, 0x00, 0x04, 0xB1, 0xCC, 0x03, 0x00, + 0x39, 0x00, 0x02, 0xE9, 0x3F, + 0x39, 0x00, 0x07, 0xD0, 0x07, 0xC0, 0x08, 0x03, 0x11, 0x00, + 0x39, 0x00, 0x03, 0xB0, 0x00, 0x00, + 0x39, 0x00, 0x02, 0xE9, 0xCF, + 0x39, 0x00, 0x02, 0xBA, 0x03, + 0x39, 0x00, 0x02, 0xE9, 0x3F, + // 0x39, 0x00, 0x04, 0xB9, 0x83, 0x12, 0x1A, + // 0x39, 0x00, 0x02, 0xC7, 0x00, + // 0x39, 0x00, 0x02, 0xCF, 0xFF, + + 0x39, 0x00, 0x01, 0x11, + 0x39, 0x00, 0x01, 0x29, +}; + +EFI_STATUS +EFIAPI +CsotDsiPanelPrepare ( + IN ROCKCHIP_DSI_PANEL_PROTOCOL *This + ) +{ + /* vcc_lcd_en_pin */ + GpioPinWrite (4, GPIO_PIN_PA3, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA3, GPIO_PIN_OUTPUT); + MicroSecondDelay (5 * 1000); + + /* avdd_lcd_gpio */ + GpioPinWrite (3, GPIO_PIN_PA7, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PA7, GPIO_PIN_OUTPUT); + MicroSecondDelay (5 * 1000); + + /* avee_lcd_gpio */ + GpioPinWrite (3, GPIO_PIN_PA6, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PA6, GPIO_PIN_OUTPUT); + MicroSecondDelay (5 * 1000); + + MicroSecondDelay (120 * 1000); + + /* lcd_rst_gpio (inverted) */ + GpioPinWrite (3, GPIO_PIN_PC6, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PC6, GPIO_PIN_OUTPUT); + MicroSecondDelay (120 * 1000); + + /* lcd_rst_gpio (inverted) */ + GpioPinWrite (3, GPIO_PIN_PC6, TRUE); + MicroSecondDelay (120 * 1000); + + return EFI_SUCCESS; +} + +STATIC ROCKCHIP_DSI_PANEL_PROTOCOL mCsotDsiPanel = { + .DsiId = 0, + .DsiLaneRate = 676000, + .DsiLanes = 4, + .DsiFlags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | + MIPI_DSI_MODE_EOT_PACKET, + .DsiFormat = MIPI_DSI_FMT_RGB888, + .DscEnable = TRUE, + .SliceWidth = 1600, + .SliceHeight = 40, + .VersionMajor = 1, + .VersionMinor = 1, + + .InitSequence = mCsotDsiInitSequence, + .InitSequenceLength = ARRAY_SIZE (mCsotDsiInitSequence), + + .NativeMode = { + .CrtcId = 2, + .OscFreq = 275000000, + .Horizontal = { + .Resolution = 1600, + .Sync = 20, + .BackPorch = 40, + .FrontPorch = 60 + }, + .Vertical = { + .Resolution = 2560, + .Sync = 4, + .BackPorch = 18, + .FrontPorch = 112 + }, + .HsyncActive = 0, + .VsyncActive = 0, + .DenActive = 0, + .ClkActive = 0, + .VpsConfigModeID = 1 + }, + + .Prepare = CsotDsiPanelPrepare, +}; + +EFI_STATUS +EFIAPI +AttachCsotDsiPanel ( + VOID + ) +{ + EFI_HANDLE Handle = NULL; + + return gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipDsiPanelProtocolGuid, + &mCsotDsiPanel, + NULL + ); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..1e85741 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,306 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + // RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(3, GPIO_PIN_PB7, 9); //i2c3_scl_m1 + GpioPinSetFunction(3, GPIO_PIN_PC0, 9); //i2c3_sda_m1 + break; + case 4: + GpioPinSetFunction(1, GPIO_PIN_PA3, 9); //i2c4_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PA2, 9); //i2c4_sda_m3 + break; + case 5: + GpioPinSetFunction(1, GPIO_PIN_PB6, 9); //i2c5_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PB7, 9); //i2c5_sda_m3 + break; + case 6: + GpioPinSetFunction(4, GPIO_PIN_PB1, 9); //i2c6_scl_m3 + GpioPinSetFunction(4, GPIO_PIN_PB0, 9); //i2c6_sda_m3 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L2) { // AP6275P Wi-Fi + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + + /* wifi_poweren_gpio */ + GpioPinSetDirection (0, GPIO_PIN_PC7, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + /* wifi_poweren_gpio */ + GpioPinWrite (0, GPIO_PIN_PC7, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + GpioPinWrite (3, GPIO_PIN_PC2, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PC2, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PC2, Enable); +} + +extern +EFI_STATUS +EFIAPI +AttachCsotDsiPanel ( + VOID + ); + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + /* vcc_5v0_en */ + GpioPinWrite (4, GPIO_PIN_PA2, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + + GpioPinSetFunction(1, GPIO_PIN_PC0, 0); //jdet + + /* spk-con-gpio */ + GpioPinWrite (4, GPIO_PIN_PA5, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + + AttachCsotDsiPanel(); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..4f05c41 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/FydeInnovations/FydetabDuo/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,41 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + TimerLib + UefiBootServicesTableLib + +[Protocols] + gRockchipDsiPanelProtocolGuid + +[Sources.common] + RockchipPlatformLib.c + CsotDsiPanel.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9c393fd5d2fdeba7a667d7505463f835f017e2c7 GIT binary patch literal 504138 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.c new file mode 100644 index 0000000..2255b11 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.c @@ -0,0 +1,144 @@ +/** @file + Logo DXE Driver, install Edkii Platform Logo protocol. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..bfc7343 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/AcpiTables/Dsdt.asl @@ -0,0 +1,54 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD5 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac0.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.Modules.fdf.inc new file mode 100644 index 0000000..22f88e6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-hinlink-h88k.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.dsc new file mode 100644 index 0000000..3a14a38 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/H88K.dsc @@ -0,0 +1,121 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2022, Xilin Wu +# Copyright (c) 2023, Jianfeng Liu +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = H88K + PLATFORM_VENDOR = Hinlink + PLATFORM_GUID = 5ecd3024-77d5-47a2-8293-a963ac878d48 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"H88K" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Hinlink" + gRockchipTokenSpaceGuid.PcdFamilyName|"H88K" + gRockchipTokenSpaceGuid.PcdProductUrl|"http://www.hinlink.com/" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-hinlink-h88k" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x2, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x2 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac0Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0x44 + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..ff8a81e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,386 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 0: + /* gmac0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2C_IOMUX_SEL_L = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO4C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO4C_IOMUX_SEL_H = (0x00FFUL << 16) | 0x0011; + + /* phy0 reset */ + GpioPinSetDirection (4, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 0: + /* phy0 reset */ + GpioPinWrite (4, GPIO_PIN_PB3, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PB5, 9); //i2c1_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PB6, 9); //i2c1_sda_m0 + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + GpioPinSetFunction(3, GPIO_PIN_PA6, 9); //i2c4_scl_m0 + GpioPinSetFunction(3, GPIO_PIN_PA5, 9); //i2c4_sda_m0 + break; + case 5: + GpioPinSetFunction(3, GPIO_PIN_PC7, 9); //i2c5_scl_m0 + GpioPinSetFunction(3, GPIO_PIN_PD0, 9); //i2c5_sda_m0 + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO4 PB0 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + /* Set GPIO4 PB0 (USB_HUB_PWREN) output high to power USB ports */ + GpioPinSetDirection (4, GPIO_PIN_PA6, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PA6, FALSE); + MicroSecondDelay (100); + GpioPinWrite (4, GPIO_PIN_PA6, TRUE); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinSetDirection (3, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinSetDirection (0, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* output high to enable power */ + + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (3, GPIO_PIN_PD5, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (0, GPIO_PIN_PB0, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinWrite (4, GPIO_PIN_PA5, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (3, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + GpioPinSetFunction(1, GPIO_PIN_PD5, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..015b7cf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Hinlink/H88K/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + TimerLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.c new file mode 100644 index 0000000..25e877c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.c @@ -0,0 +1,341 @@ +/** @file + * + * Khadas MCU platform driver + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "KhadasMcuDxe.h" + +STATIC CONST EFI_GUID I2cGuid = I2C_GUID; + +STATIC +EFI_STATUS +EFIAPI +KhadasMcuRead ( + IN CONST KHADAS_MCU_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_STATUS Status; + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + KHADAS_MCU_CONTEXT *KhadasMcuContext = KHADAS_MCU_FROM_PROTOCOL (This); + + ASSERT (KhadasMcuContext != NULL); + ASSERT (KhadasMcuContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2; + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RequestPacket->OperationCount = 2; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength; + RequestPacket->Operation[0].Buffer = RegAddress; + + RequestPacket->Operation[1].Flags = I2C_FLAG_READ; + RequestPacket->Operation[1].LengthInBytes = Length; + RequestPacket->Operation[1].Buffer = Buffer; + + Status = KhadasMcuContext->I2cIo->QueueRequest (KhadasMcuContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: error %d during transmission\n", __func__, Status)); + } + + FreePool (RequestPacket); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +KhadasMcuWrite ( + IN CONST KHADAS_MCU_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_STATUS Status; + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + UINT8 *Data; + UINT16 Index; + KHADAS_MCU_CONTEXT *KhadasMcuContext = KHADAS_MCU_FROM_PROTOCOL (This); + + ASSERT (KhadasMcuContext != NULL); + ASSERT (KhadasMcuContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION); + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Data = AllocateZeroPool (RegAddressLength + Length); + if (Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < RegAddressLength; Index++) { + Data[Index] = RegAddress[Index] & 0xff; + } + + for (Index = RegAddressLength; Index < RegAddressLength + Length; Index++) { + Data[Index] = Buffer[Index - RegAddressLength] & 0xff; + } + + RequestPacket->OperationCount = 1; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength + Length; + RequestPacket->Operation[0].Buffer = Data; + + Status = KhadasMcuContext->I2cIo->QueueRequest (KhadasMcuContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: error %d during transmission\n", __func__, Status)); + } + + FreePool (Data); + FreePool (RequestPacket); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +KhadasMcuReadRegister ( + IN CONST KHADAS_MCU_PROTOCOL *This, + IN UINT8 Address, + OUT UINT8 *Value + ) +{ + return KhadasMcuRead (This, &Address, sizeof (UINT8), Value, sizeof (UINT8)); +} + +STATIC +EFI_STATUS +EFIAPI +KhadasMcuWriteRegister ( + IN CONST KHADAS_MCU_PROTOCOL *This, + IN UINT8 Address, + IN UINT8 Value + ) +{ + return KhadasMcuWrite (This, &Address, sizeof (UINT8), &Value, sizeof (UINT8)); +} + +STATIC +EFI_STATUS +EFIAPI +KhadasMcuSetFanSpeedPercentage ( + IN KHADAS_MCU_PROTOCOL *This, + IN UINT8 Percentage + ) +{ + return KhadasMcuWriteRegister (This, MCU_CMD_FAN_STATUS_CTRL_REGv2, + MIN (Percentage, 100)); +} + +EFI_DRIVER_BINDING_PROTOCOL mDriverBindingProtocol = { + KhadasMcuSupported, + KhadasMcuStart, + KhadasMcuStop +}; + +EFI_STATUS +EFIAPI +KhadasMcuSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + UINT8 KhadasMcuAddress; + UINT8 KhadasMcuBus; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + KhadasMcuAddress = PcdGet8 (PcdKhadasMcuAddress); + KhadasMcuBus = PcdGet8 (PcdKhadasMcuBus); + + Status = EFI_UNSUPPORTED; + + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(KhadasMcuBus, KhadasMcuAddress)) { + DEBUG ((DEBUG_INFO, "%a: attached to Khadas MCU device\n", __func__)); + Status = EFI_SUCCESS; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +KhadasMcuStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status; + KHADAS_MCU_CONTEXT *KhadasMcuContext; + KHADAS_MCU_PROTOCOL *KhadasMcuProtocol; + + KhadasMcuContext = AllocateZeroPool (sizeof(KHADAS_MCU_CONTEXT)); + if (KhadasMcuContext == NULL) { + DEBUG ((DEBUG_ERROR, "%a: context allocation failed\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + KhadasMcuContext->ControllerHandle = ControllerHandle; + KhadasMcuContext->Signature = KHADAS_MCU_SIGNATURE; + + KhadasMcuProtocol = &KhadasMcuContext->KhadasMcuProtocol; + KhadasMcuProtocol->SetFanSpeedPercentage = KhadasMcuSetFanSpeedPercentage; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &KhadasMcuContext->I2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to open I2cIo\n", __func__)); + FreePool (KhadasMcuContext); + return EFI_UNSUPPORTED; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gKhadasMcuProtocolGuid, KhadasMcuProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to install KHADAS_MCU_PROTOCOL\n", __func__)); + goto fail; + } + + return Status; + +fail: + FreePool (KhadasMcuContext); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +KhadasMcuStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + KHADAS_MCU_PROTOCOL *KhadasMcuProtocol; + KHADAS_MCU_CONTEXT *KhadasMcuContext; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gKhadasMcuProtocolGuid, + (VOID **) &KhadasMcuProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + KhadasMcuContext = KHADAS_MCU_FROM_PROTOCOL(KhadasMcuProtocol); + + gBS->UninstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gKhadasMcuProtocolGuid, &KhadasMcuContext->KhadasMcuProtocol, + &gEfiDriverBindingProtocolGuid, &mDriverBindingProtocol, + NULL + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + FreePool (KhadasMcuContext); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +KhadasMcuDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, &mDriverBindingProtocol, + NULL + ); + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.h new file mode 100644 index 0000000..b3f2d2e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.h @@ -0,0 +1,64 @@ +/** @file + * + * Khadas MCU platform driver + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __KHADAS_MCU_DXE_H__ +#define __KHADAS_MCU_DXE_H__ + +#include + +#define KHADAS_MCU_SIGNATURE SIGNATURE_32 ('K', 'M', 'C', 'U') + +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +typedef struct { + UINT32 Signature; + EFI_HANDLE ControllerHandle; + EFI_I2C_IO_PROTOCOL *I2cIo; + KHADAS_MCU_PROTOCOL KhadasMcuProtocol; +} KHADAS_MCU_CONTEXT; + +#define KHADAS_MCU_FROM_IO(a) CR (a, KHADAS_MCU_CONTEXT, I2cIo, KHADAS_MCU_SIGNATURE) +#define KHADAS_MCU_FROM_PROTOCOL(a) CR (a, KHADAS_MCU_CONTEXT, KhadasMcuProtocol, KHADAS_MCU_SIGNATURE) + +// +// Registers & fields +// https://docs.khadas.com/products/sbc/edge2/hardware/edge2-boot-flow +// +#define MCU_CMD_FAN_STATUS_CTRL_REGv2 0x8A + +EFI_STATUS +EFIAPI +KhadasMcuSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +KhadasMcuStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +KhadasMcuStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +#endif // __KHADAS_MCU_DXE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf new file mode 100644 index 0000000..5a852c4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf @@ -0,0 +1,48 @@ +#/** @file +# +# Khadas MCU platform driver +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = KhadasMcuDxe + FILE_GUID = a9d195e1-85a0-426f-b364-413e6d2350a7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = KhadasMcuDxeInitialize + +[Sources.common] + KhadasMcuDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Khadas/KhadasPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + PcdLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEfiI2cIoProtocolGuid ## CONSUMES + gEfiDriverBindingProtocolGuid ## PRODUCES + gKhadasMcuProtocolGuid ## PRODUCES + +[Pcd] + gKhadasTokenSpaceGuid.PcdKhadasMcuAddress + gKhadasTokenSpaceGuid.PcdKhadasMcuBus + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2ba1e15f5b42ecc2b2f0b6cd2d7cf95f92fbf541 GIT binary patch literal 330318 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 U2tWV=5P$##AOHafWJ%!v0FOTSq5uE@ literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.c new file mode 100644 index 0000000..2255b11 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.c @@ -0,0 +1,144 @@ +/** @file + Logo DXE Driver, install Edkii Platform Logo protocol. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..725b2a7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8316" +#define BOARD_CODEC_I2C "\\_SB.I2C3" +#define BOARD_CODEC_I2C_ADDR 0x10 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD3 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C3) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.Modules.fdf.inc new file mode 100644 index 0000000..f802319 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.Modules.fdf.inc @@ -0,0 +1,21 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-khadas-edge2.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf + + # Khadas MCU Support + INF $(VENDOR_DIRECTORY)/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc new file mode 100644 index 0000000..59b8c57 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Edge2.dsc @@ -0,0 +1,120 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = Edge2 + PLATFORM_VENDOR = Khadas + PLATFORM_GUID = 584a4095-9cf3-46ea-a9b5-8d55ccd11da0 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Edge2" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Khadas" + gRockchipTokenSpaceGuid.PcdFamilyName|"Edge" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://www.khadas.com/edge2" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-khadas-edge2" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x18, 0x10 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x2, 0x2, 0x3 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x2 + gKhadasTokenSpaceGuid.PcdKhadasMcuAddress|0x18 + gKhadasTokenSpaceGuid.PcdKhadasMcuBus|0x2 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf + + # Khadas MCU Support + $(VENDOR_DIRECTORY)/Drivers/KhadasMcuDxe/KhadasMcuDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..9162eb1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,383 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +STATIC VOID *mKhadasMcuEventRegistration; +STATIC KHADAS_MCU_PROTOCOL *mKhadasMcu; +STATIC UINT8 mTargetFanSpeed; + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + GpioPinSetFunction(1, GPIO_PIN_PA3, 9); //i2c4_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PA2, 9); //i2c4_sda_m3 + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Set VCC_5V0_PWREN_H */ + GpioPinWrite (4, GPIO_PIN_PA2, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + + /* Set USB_HOST_PWREN_H */ + GpioPinWrite (1, GPIO_PIN_PB1, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PB1, GPIO_PIN_OUTPUT); + + /* Set TYPEC0_PWR_EN */ + GpioPinWrite (3, GPIO_PIN_PA4, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L2) { // AP6275P Wi-Fi + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + + /* wifi_poweren_gpio */ + GpioPinSetDirection (0, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + /* wifi_poweren_gpio */ + GpioPinWrite (0, GPIO_PIN_PC4, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +STATIC +VOID +KhadasMcuRegistrationEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_HANDLE Handle; + UINTN BufferSize; + EFI_STATUS Status; + + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle ( + ByRegisterNotify, + NULL, + mKhadasMcuEventRegistration, + &BufferSize, + &Handle); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_WARN, "%a: Failed to locate gKhadasMcuProtocol. Status=%r\n", + __func__, Status)); + } + return; + } + + Status = gBS->HandleProtocol (Handle, + &gKhadasMcuProtocolGuid, (VOID **) &mKhadasMcu); + ASSERT_EFI_ERROR (Status); + + PwmFanSetSpeed (mTargetFanSpeed); + + gBS->CloseEvent (Event); +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + EfiCreateProtocolNotifyEvent ( + &gKhadasMcuProtocolGuid, + TPL_CALLBACK, + KhadasMcuRegistrationEventHandler, + NULL, + &mKhadasMcuEventRegistration); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + UINT32 Percentage + ) +{ + mTargetFanSpeed = (UINT8) Percentage; + + // + // If the protocol is installed, set the speed now. + // Otherwise it will be set by KhadasMcuRegistrationEventHandler + // when ready. + // + if (mKhadasMcu != NULL) { + mKhadasMcu->SetFanSpeedPercentage (mKhadasMcu, mTargetFanSpeed); + } +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Red off, Green for status, Blue for power */ + GpioPinWrite (4, GPIO_PIN_PB4, FALSE); + GpioPinSetDirection (4, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PB2, FALSE); + GpioPinSetDirection (4, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PB3, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (4, GPIO_PIN_PB2, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + GpioPinSetFunction(1, GPIO_PIN_PD3, 0); //jdet + GpioPinSetFunction(1, GPIO_PIN_PD0, 0); //spk_con +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..e36cc27 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Edge2/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,40 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + Platform/Khadas/KhadasPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + UefiLib + UefiBootServicesTableLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c + +[Protocols] + gKhadasMcuProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Include/Protocol/KhadasMcu.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Include/Protocol/KhadasMcu.h new file mode 100644 index 0000000..86365e3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/Include/Protocol/KhadasMcu.h @@ -0,0 +1,30 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __KHADAS_MCU_H__ +#define __KHADAS_MCU_H__ + +#define KHADAS_MCU_PROTOCOL_GUID \ + { 0x162d2a6e, 0x33af, 0x4ca5, { 0xaa, 0x68, 0xbc, 0xd3, 0xb2, 0x4c, 0xca, 0xf5 } } + +typedef struct _KHADAS_MCU_PROTOCOL KHADAS_MCU_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *KHADAS_MCU_SET_FAN_SPEED_PERCENTAGE) ( + IN KHADAS_MCU_PROTOCOL *This, + IN UINT8 Percentage + ); + +struct _KHADAS_MCU_PROTOCOL { + KHADAS_MCU_SET_FAN_SPEED_PERCENTAGE SetFanSpeedPercentage; +}; + +extern EFI_GUID gKhadasMcuProtocolGuid; + +#endif // __KHADAS_MCU_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/KhadasPkg.dec b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/KhadasPkg.dec new file mode 100644 index 0000000..2a1027a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Khadas/KhadasPkg.dec @@ -0,0 +1,26 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = KhadasPkg + PACKAGE_GUID = 7a5b60db-89a8-4749-b4e7-e093197595c2 + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[Protocols] + gKhadasMcuProtocolGuid = { 0x162d2a6e, 0x33af, 0x4ca5, { 0xaa, 0x68, 0xbc, 0xd3, 0xb2, 0x4c, 0xca, 0xf5 } } + +[Guids] + gKhadasTokenSpaceGuid = { 0x2f92c2cf, 0x0e93, 0x45c9, { 0xae, 0x30, 0x38, 0x46, 0x4d, 0x3f, 0xde, 0x8a } } + +[PcdsFixedAtBuild] + gKhadasTokenSpaceGuid.PcdKhadasMcuAddress|0|UINT8|0x00000001 + gKhadasTokenSpaceGuid.PcdKhadasMcuBus|0|UINT8|0x00000002 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..de9b4f39f73864eae7cb6106803c2301a3553206 GIT binary patch literal 224526 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 + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..1f72ac9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/AcpiTables/Dsdt.asl @@ -0,0 +1,40 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac0.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..616a2bc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,341 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 0: + /* gmac0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2C_IOMUX_SEL_L = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO4C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO4C_IOMUX_SEL_H = (0x00FFUL << 16) | 0x0011; + + /* phy0 reset */ + GpioPinSetDirection (4, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 0: + /* phy0 reset */ + GpioPinWrite (4, GPIO_PIN_PB3, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + break; + case 4: + break; + case 5: + GpioPinSetFunction(1, GPIO_PIN_PB6, 9); //i2c5_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PB7, 9); //i2c5_sda_m3 + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Enable USB-C VBUS */ + GpioPinWrite (4, GPIO_PIN_PA7, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA7, GPIO_PIN_OUTPUT); + + /* Enable USB HOST VBUS */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L0) { // AP6275P Wi-Fi + GpioPinSetDirection (1, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + + /* wifi_poweren_gpio */ + GpioPinSetDirection (1, GPIO_PIN_PB1, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L0) { + /* wifi_poweren_gpio */ + GpioPinWrite (1, GPIO_PIN_PB1, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L0) { + GpioPinWrite (1, GPIO_PIN_PB4, !Enable); + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Power button LED used as status indicator */ + GpioPinWrite (3, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..ec569ea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.Modules.fdf.inc new file mode 100644 index 0000000..6317171 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-blueberry-minipc-linux.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.dsc new file mode 100644 index 0000000..aa27f79 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58-Mini/R58-Mini.dsc @@ -0,0 +1,124 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = R58-Mini + PLATFORM_VENDOR = Mekotronics + PLATFORM_GUID = b01621cc-69a0-419f-9f37-aadfbb5db256 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # This board lacks an SD card slot. + DEFINE RK_SD_ENABLE = FALSE + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"R58 Mini" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Mekotronics" + gRockchipTokenSpaceGuid.PcdFamilyName|"R58" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://www.mekotronics.com/h-pd-76.html" + gRockchipTokenSpaceGuid.PcdBoardName|"MINI-PC-RK3588-4D32-V1.0" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-blueberry-minipc-linux" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_SATA) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # PCI Express 3.0 support flags and default values + # + gRK3588TokenSpaceGuid.PcdPcie30Supported|FALSE + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0, 0x1, 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac0Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0x44 + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..9e6f782 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/AcpiTables/Dsdt.asl @@ -0,0 +1,55 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C3" +#define BOARD_CODEC_I2C_ADDR 0x10 +#define BOARD_CODEC_GPIO "\\_SB.GPI3" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PB2 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac0.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C3) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..354433c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,384 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 0: + /* gmac0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO2C_IOMUX_SEL_L = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO4C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + BUS_IOC->GPIO4C_IOMUX_SEL_H = (0x00FFUL << 16) | 0x0011; + + /* phy0 reset */ + GpioPinSetDirection (4, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + break; + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 0: + /* phy0 reset */ + GpioPinWrite (4, GPIO_PIN_PB3, !Enable); + break; + case 1: + /* phy1 reset */ + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + break; + case 5: + GpioPinSetFunction(1, GPIO_PIN_PB6, 9); //i2c5_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PB7, 9); //i2c5_sda_m3 + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* Enable USB-C VBUS */ + GpioPinWrite (4, GPIO_PIN_PA7, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PA7, GPIO_PIN_OUTPUT); + + /* Enable USB HOST VBUS */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: // M.2 M Key + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie30 */ + GpioPinSetDirection (1, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L0: // AP6275P Wi-Fi + /* reset */ + GpioPinSetDirection (1, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + + /* wifi_poweren_gpio */ + GpioPinSetDirection (1, GPIO_PIN_PB1, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + /* vcc3v3_pcie30 */ + GpioPinWrite (1, GPIO_PIN_PC4, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + /* wifi_poweren_gpio */ + GpioPinWrite (1, GPIO_PIN_PB1, Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PB4, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Power button LED used as status indicator */ + GpioPinWrite (3, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + GpioPinSetFunction(3, GPIO_PIN_PB2, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..ec569ea --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.Modules.fdf.inc new file mode 100644 index 0000000..56deaa1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-blueberry-edge-v12-linux.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.dsc new file mode 100644 index 0000000..0236229 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mekotronics/R58X/R58X.dsc @@ -0,0 +1,126 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = R58X + PLATFORM_VENDOR = Mekotronics + PLATFORM_GUID = d947cf02-21c1-4a39-9c80-55969396f733 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"R58X" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Mekotronics" + gRockchipTokenSpaceGuid.PcdFamilyName|"R58" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://www.mekotronics.com/h-pd-75.html" + gRockchipTokenSpaceGuid.PcdBoardName|"EDGE-RK3588-4D32-V1.2" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-blueberry-edge-v12-linux" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x10 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x3 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # Disable HS400 for now, otherwise eMMC is unusable. + gRockchipTokenSpaceGuid.PcdDwcSdhciDisableHs400|TRUE + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_SATA) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0, 0x1, 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac0Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0x44 + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..2221309 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/AcpiTables/Dsdt.asl @@ -0,0 +1,40 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.Modules.fdf.inc new file mode 100644 index 0000000..31670cb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-blade3-v101-linux.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc new file mode 100644 index 0000000..92ba5f8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Blade3.dsc @@ -0,0 +1,109 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = Blade3 + PLATFORM_VENDOR = Mixtile + PLATFORM_GUID = 6058aec7-9db7-4fdf-a2ce-19f58631071d + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # No status LED on this platform. + DEFINE RK_STATUS_LED_ENABLE = FALSE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Blade 3" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Mixtile" + gRockchipTokenSpaceGuid.PcdFamilyName|"Blade" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://www.mixtile.com/blade-3/" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-blade3-v101-linux" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_SATA) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x2, 0x3 } + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..9ab05e9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,345 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); //i2c1_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); //i2c1_sda_m2 + break; + case 2: + break; + case 3: + break; + case 4: + GpioPinSetFunction(3, GPIO_PIN_PA6, 9); //i2c4_scl_m0 + GpioPinSetFunction(3, GPIO_PIN_PA5, 9); //i2c4_sda_m0 + break; + case 5: + GpioPinSetFunction(1, GPIO_PIN_PB6, 9); //i2c5_scl_m3 + GpioPinSetFunction(1, GPIO_PIN_PB7, 9); //i2c5_sda_m3 + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* vbus5v0_typec0 (data-only port) */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + + /* vbus5v0_typec1 (PD + data port) */ + // Won't enable 5V on VBUS for now, unsure if it's okay + // to do it when voltage > 5V is already supplied to this port. + // + // GpioPinWrite (4, GPIO_PIN_PA3, TRUE); + // GpioPinSetDirection (4, GPIO_PIN_PA3, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: // U.2 + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie30 */ + GpioPinSetDirection (1, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L0: // ASM1182e (-> 2x RTL8125) + /* reset */ + GpioPinSetDirection (1, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L1: + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (1, GPIO_PIN_PB2, Enable); + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PB4, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER2, + .ChannelID = PWM_CHANNEL0, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM2_CH0 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (3, GPIO_PIN_PD0, 0xB); // PWM8_M2 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + // No controllable LEDs on this platform +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + // No controllable LEDs on this platform +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Blade3/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8f8677b1aeb214759f40b561ab3d194d4ab6ad57 GIT binary patch literal 172854 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 + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Mixtile/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7292827f6c0130f698d045288fcb6d9dc0fdfe41 GIT binary patch literal 116534 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 Md*6jHRs{wB4{j`#9{>OV literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.c new file mode 100644 index 0000000..2255b11 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.c @@ -0,0 +1,144 @@ +/** @file + Logo DXE Driver, install Edkii Platform Logo protocol. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..796403d --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S1_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C6" +#define BOARD_CODEC_I2C_ADDR 0x10 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD5 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + // include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C6) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..6a1b49d --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,332 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 850000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + /* This is not configured in the OrangePi5's Linux device tree + RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 1100000), */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + /* The OPi is officially configured for the 837500 voltage, but is still marked as avdd_0v75_s0 in the schematic and Linux device tree. rockchip says this voltage is set to improve HDMI stability. */ + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 837500), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB2, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB2, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + break; + case 4: + GpioPinSetFunction(3, GPIO_PIN_PA6, 9); //i2c4_scl_m0 + GpioPinSetFunction(3, GPIO_PIN_PA5, 9); //i2c4_sda_m0 + break; + case 5: + break; + case 6: + GpioPinSetFunction(4, GPIO_PIN_PB1, 9); //i2c6_scl_m3 + GpioPinSetFunction(4, GPIO_PIN_PB0, 9); //i2c6_sda_m3 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO3 PC0 (TYPEC_EN) output high to power Type-C/USB2.0 ports */ + GpioPinWrite (3, GPIO_PIN_PC0, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PC0, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable green led\n")); + // GpioPinWrite (1, GPIO_PIN_PA2, TRUE); + // GpioPinSetDirection (1, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset to gpio output mode */ + if(Segment == PCIE_SEGMENT_PCIE20L2) { // M.2 M Key + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* nothing to power on */ +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER3, + .ChannelID = PWM_CHANNEL2, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM3_CH2 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (4, GPIO_PIN_PB2, 0xB); // PWM14_M1 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (1, GPIO_PIN_PA2, FALSE); + GpioPinSetDirection (1, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (1, GPIO_PIN_PA2, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + + GpioPinSetFunction(1, GPIO_PIN_PD5, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.Modules.fdf.inc new file mode 100644 index 0000000..f6b4446 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-orangepi-5.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.dsc new file mode 100644 index 0000000..b481ad9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5/OrangePi5.dsc @@ -0,0 +1,122 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Willzen Zou +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = OrangePi5 + PLATFORM_VENDOR = OrangePi + PLATFORM_GUID = e6443926-7196-4fc4-9554-91fc1fb34256 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Orange Pi 5" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Orange Pi" + gRockchipTokenSpaceGuid.PcdFamilyName|"Orange Pi 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5.html" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-orangepi-5" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x10 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x6 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x42 + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S1Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/Dsdt.asl new file mode 100644 index 0000000..1d767aa --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8388" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD3 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..15f4a9e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,385 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); //i2c1_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); //i2c1_sda_m2 + break; + case 2: + break; + case 3: + GpioPinSetFunction(1, GPIO_PIN_PC1, 9); //i2c3_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PC0, 9); //i2c3_sda_m0 + break; + case 4: + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* vcc5v0_host_en */ + GpioPinWrite (3, GPIO_PIN_PB7, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + + /* typec5v_pwren */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: // M.2 M Key + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie30 */ + GpioPinSetDirection (2, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L0: // M.2 A+E Key + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + /* vcc3v3_pcie2x1l0 */ + GpioPinSetDirection (2, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L1: // RTL8125B + /* reset */ + GpioPinSetDirection (3, GPIO_PIN_PB3, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: // RTL8125B + /* reset */ + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + break; + default: + break; + } + if (Segment == PCIE_SEGMENT_PCIE20L1 || Segment == PCIE_SEGMENT_PCIE20L2) { + /* vcc3v3_pcie_eth */ + GpioPinSetDirection (3, GPIO_PIN_PB4, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (2, GPIO_PIN_PB6, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (2, GPIO_PIN_PC5, Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + case PCIE_SEGMENT_PCIE20L2: + /* Yes, disabling one would disable the other as well. */ + GpioPinWrite (3, GPIO_PIN_PB4, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (4, GPIO_PIN_PA5, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (3, GPIO_PIN_PB3, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + default: + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER0, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM0_CH3 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (3, GPIO_PIN_PB2, 0xB); // PWM3_IR_M1 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (3, GPIO_PIN_PA6, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PA6, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PA6, Enable); +} + +VOID +EFIAPI +PlatformWiFiEnable ( + IN BOOLEAN Enable + ) +{ + // WiFi - enable + GpioPinWrite (0, GPIO_PIN_PC4, Enable); + GpioPinSetDirection (0, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + PlatformWiFiEnable (TRUE); + + GpioPinSetFunction(1, GPIO_PIN_PD3, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.Modules.fdf.inc new file mode 100644 index 0000000..ce5cea1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-orangepi-5-plus.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc new file mode 100644 index 0000000..99b4b3f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/OrangePi/OrangePi5Plus/OrangePi5Plus.dsc @@ -0,0 +1,119 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = OrangePi5Plus + PLATFORM_VENDOR = OrangePi + PLATFORM_GUID = 6bb03dd4-c246-474a-851c-70ea24a89e43 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Orange Pi 5 Plus" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Orange Pi" + gRockchipTokenSpaceGuid.PcdFamilyName|"Orange Pi 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-5-plus.html" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-orangepi-5-plus" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43, 0x11 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ea4577218879f4797ea8d736b6abd9a0610285d0 GIT binary patch literal 218470 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%0Ag1!Fw>yUYDi;PG4-=F^AVAG~e zTeoiAzI{7X{Ml!pJ#yrT?y_Ahgi+!0QrC_4$xxYObc&%BORGX5`~~CBGb&BuI%e7^ z`*Tp&CFn7W6#~+_e(>Ny$bbi*>C>l+IJA28Y7dMtsp5+-zK~Pj9zA*(IS7fBE7PT1 z{rjtzV|uCUO$T*00u}XoC_S~qeY2uIqpK2BJ-s}ubDOAzizjG*_jFVtt?PgI!yim~ zpa-|4_n++CS-$PW@iOJl1f+G{CFRf-yMF!ppN%#9|7)+krp+4@SGsp^ynjQ4m;UY@ zqNO)rz<>zr8Vp72nN^G+@x6K`K+d)OBo|k(?VYr0@0&g4T^5r^q+*GxNm%0v7L;x0*0ntxGp|W+8 zO=Mf-R{q%D(JL}dfv}Gqw)_+rOj_4>?AYN;yW6Z3^Rn<7-V_gSI!oY+E3UBFXl`ep zHf@@S%UiZ=aoZ9%%8%ORUwP#fH|muu^O8$0QMHA~y54DDjn!E(%}4YQQEu}zHV4|V z=SS)7pJ!skZU-9a~(Q#NY!n4>N0^29Xj~i=22@u_uO+u7|fqPKWb3{Oz`&G zZ<~8JWy+M`n0@J`m#VDwTG#j2A_RcAE~XadYL|P4_0`fr$A{)%`n$?~q0{70$xT;A z)+KJgs(ie+4o+tfw`9$lH7ZAV>OO&^M~{j(k;f_VIGdZBE5ZQs@3C!;RJU>CMsx45 zbpO*&KXs%o`-Kb}HcVx$_qq;&tk|_EvqC7a8J4I<3aZWHHaCs3JkTCWD$-1vm)3QR zW_s`K&GjKCdt+~ILMi&yv3OD~z39&rx~-5sCpEpDfDN{oX= zIH7-tktpf%oy|CW_;8hpzUX>`v_G~GZ$nkas7`Y)tgQC?zE& zs)JZ0x_kHTAeepm<(I3h^-I?qr2X+lCIXq9ouN!B)XJ)zE0|YfQfVVNp^)}TU8!2M zghs{vbb_t${_>Z<1fesC*Z^VC?ii`(7O%NMVAZNsBCX_c8VnE#4#Fr*va+&1_}~MN zjkHr8HZc=y&HViQ_uhNYPF;@V)&9EhQP-i7m351;@w6_(qNPLa=(kDUjt|aBD^_n1 zr?MfGmQwuN%Z&=LqwA>Xj5E%_R)>x>sN01g4uy&gPdy}%o}M1G`QJbO_~Yo&qpdRN z-McqJ)VkeU9V!3*`|r2p9k$BweOU@NO;*|Ljjl&dCQ*qcwy(&oRxbcRgfLYyXHP43 zF3cO)*=VdC@!iYr)Q`Nbn2}LtII~rS*XVTMz=7X>`>iAW(7i%1z-webuX{zHNs}gf z_wIGCku8-BQOBT)oa=}=82qQ1ojZ5p*M(IF(MJBRKpizo9VyovT`!neZ6?h7YOvo1 zroMn@TI;4pqaS7^?5~x$i=Y6_ujtvZDPQvGWlNzDhWufP`3#)$N9O;O-fHtVPLKHd zfBW0tEPbs!ON>Bq%a<>2Y%kCJB7mX06)RSpJbBWy_SdZlfmS4*)FYuGuIw|HmN(L1OUDR;{@ioV`Qpf!F=JGwdZX(pIhmMd7*%>JcQ1*W#*G9RbjM)7 z$;Nk)l{OvRMa5A16pJ_?c;Erd8S|wx7*&dh9@@B{(mpbyLj(#63KlP3jEN}UefOPF z)46dS<0n`qjkpGRd3lbwf(Lg*E&Sw@Pu#H9YMBV6h(9$LZp_Kaal||P?OM5VB?5zC zmujoVNT(k=cC5;HZ*(1%rnPQnw5?pEY6kfj+TU#GIVynmPw`@M^XARI_j7!I5hoNq zL_8L>ecxGvbpqMh+2}Hu0x@C2gqeCD%)i5fwbc&_#OPq;2hm^4%F66K!kRl*TwL6% zS1+uUoH%i!o*!;qLv$AmT)AC({-hZ(@UB+ z>E13D|G~Rb#FRAesCMq+>x1{HXmq1*t4qBc@BXo>0pBmkg&q5umjp;4Fa$i-^}zT| zLr8!GNFZJbP}k$NW$70QkU*jmpspus%hPWXAc1%#KwXd5mZe`LKmv(MfV!TjElA1gPtY+Vb?91V|uW z2~gMLwPooS36Mad5}>XpYRl7a5+H$iB|u$|*OsMUBtQa*N`Shas4Y*wNq_|6l>l`; zUR#!akpKxKDgo+xqP9H!CIJ$NR|3@acx_qwMFJ#{s066%iQ4k?n*>N8UI|dw($lO@ydjLkpKyhKr9oG*7cq}d&aWgw4DSCz=$nb0p1AORAHWdhQ=URG8X%YM^#5+DH*h*tt~y8iw5->0Ug#w!#0MFJ#1 z06OhyOEnBw4F%!B*0wh2Ju}nZt*T;+*6U$E1b`l@~ z5{P3061slu*s+|PoH%Ae*GPZ_NFbI8Na*^41q))?W7D=RCO-KFg$KmsHX_XGrW{qW(#(2pxbv zk^l*i011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ hkN^pg011!)36KB@kN^pg011!)36KB@kU;DZ_ + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..044007e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/AcpiTables/Dsdt.asl @@ -0,0 +1,53 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8316" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PC4 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + include ("Gmac1.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..955ee56 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,330 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + /* Do not override, set by earlier boot stages. */ +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + /* Do not override, set by earlier boot stages. */ +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + switch (Id) { + case 1: + /* gmac1 iomux */ + BUS_IOC->GPIO3B_IOMUX_SEL_H = (0x0FFFUL << 16) | 0x0111; + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | 0x1111; + BUS_IOC->GPIO3B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0FFUL << 16) | 0x1011; + BUS_IOC->GPIO3C_IOMUX_SEL_L = (0xFF00UL << 16) | 0x1100; + + /* phy1 reset */ + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + break; + default: + break; + } +} + +VOID +EFIAPI +GmacIoPhyReset ( + UINT32 Id, + BOOLEAN Enable + ) +{ + switch (Id) { + case 1: + /* phy1 reset */ + GpioPinWrite (3, GPIO_PIN_PB7, !Enable); + break; + default: + break; + } +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + break; + case 2: + GpioPinSetFunction(0, GPIO_PIN_PB7, 9); //i2c2_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC0, 9); //i2c2_sda_m0 + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + + /* vcc5v0_host */ + GpioPinSetDirection (4, GPIO_PIN_PB5, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PB5, TRUE); + + /* vcc_5v0 */ + GpioPinSetDirection (4, GPIO_PIN_PA3, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PA3, TRUE); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + // Set reset and power IO to gpio output mode + GpioPinSetDirection (0, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + GpioPinSetDirection (3, GPIO_PIN_PD1, GPIO_PIN_OUTPUT); + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + /* output high to enable power */ + GpioPinWrite (0, GPIO_PIN_PC5, Enable); + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + if(Segment == PCIE_SEGMENT_PCIE20L2) { + GpioPinWrite (3, GPIO_PIN_PD1, !Enable); + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER0, + .ChannelID = PWM_CHANNEL3, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM0_CH3 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (3, GPIO_PIN_PB2, 0xB); // PWM3_IR_M1 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (3, GPIO_PIN_PD5, FALSE); + GpioPinSetDirection (3, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (3, GPIO_PIN_PD5, Enable); +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + GpioPinSetFunction(1, GPIO_PIN_PC4, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.Modules.fdf.inc new file mode 100644 index 0000000..653ba21 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588s-rock-5a.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.dsc new file mode 100644 index 0000000..e41ca62 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5A/ROCK5A.dsc @@ -0,0 +1,115 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Molly Sophia +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ROCK5A + PLATFORM_VENDOR = Radxa + PLATFORM_GUID = 34bba9d2-8903-4403-969c-1a51b7c05f63 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # RK3588S-based platform + # +!include Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ROCK 5 Model A" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Radxa" + gRockchipTokenSpaceGuid.PcdFamilyName|"ROCK 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://wiki.radxa.com/Rock5/hardware/5a" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588s-rock-5a" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + + # + # GMAC + # + gRK3588TokenSpaceGuid.PcdGmac1Supported|TRUE + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0x3a + gRK3588TokenSpaceGuid.PcdGmac1RxDelay|0x3e + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..bfdd8cf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/AcpiTables/Dsdt.asl @@ -0,0 +1,54 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8316" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD5 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..2b49a67 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,384 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); //i2c1_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); //i2c1_sda_m2 + break; + case 2: + break; + case 3: + break; + case 4: + GpioPinSetFunction(2, GPIO_PIN_PB5, 9); //i2c4_scl_m1 + GpioPinSetFunction(2, GPIO_PIN_PB4, 9); //i2c4_sda_m1 + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO4 PB0 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinWrite (4, GPIO_PIN_PB0, TRUE); + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable blue led\n")); + // GpioPinWrite (0, GPIO_PIN_PB7, TRUE); + // GpioPinSetDirection (0, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); // PCIE30x1_0_{CLKREQN,WAKEN,PERSTN}_M1 + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinSetDirection (3, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 0); // PCIE20x1_2_{CLKREQN,WAKEN,PERSTN}_M0 + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* output high to enable power */ + + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (1, GPIO_PIN_PA4, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PD2, Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: // m.2 a+e key + GpioPinWrite (4, GPIO_PIN_PA5, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: // rtl8125b + GpioPinWrite (3, GPIO_PIN_PB0, !Enable); + break; + default: + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER0, + .ChannelID = PWM_CHANNEL1, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM0_CH1 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (0, GPIO_PIN_PC0, 0x3); // PWM1_M0 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (0, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (0, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (0, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformPcieWiFiEnable ( + IN BOOLEAN Enable + ) +{ + // WiFi - enable + GpioPinWrite (0, GPIO_PIN_PC4, Enable); + GpioPinSetDirection (0, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PA2, Enable); + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + + // bluetooth - enable + GpioPinWrite (3, GPIO_PIN_PD5, Enable); + GpioPinSetDirection (3, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); + GpioPinWrite (3, GPIO_PIN_PA6, Enable); + GpioPinSetDirection (3, GPIO_PIN_PA6, GPIO_PIN_OUTPUT); + +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + PlatformPcieWiFiEnable(TRUE); + GpioPinSetFunction(1, GPIO_PIN_PD5, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.Modules.fdf.inc new file mode 100644 index 0000000..9182ecb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-rock-5b.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc new file mode 100644 index 0000000..efacaa1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5B/ROCK5B.dsc @@ -0,0 +1,120 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2022, Xilin Wu +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ROCK5B + PLATFORM_VENDOR = Radxa + PLATFORM_GUID = cb957236-be75-4077-aa31-0c3eae75c09c + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ROCK 5 Model B" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Radxa" + gRockchipTokenSpaceGuid.PcdFamilyName|"ROCK 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://wiki.radxa.com/Rock5/hardware/5b" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-rock-5b" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..bfdd8cf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/AcpiTables/Dsdt.asl @@ -0,0 +1,54 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8316" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD5 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..67f5984 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,395 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); //i2c1_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); //i2c1_sda_m2 + break; + case 2: + break; + case 3: + break; + case 4: + GpioPinSetFunction(2, GPIO_PIN_PB5, 9); //i2c4_scl_m1 + GpioPinSetFunction(2, GPIO_PIN_PB4, 9); //i2c4_sda_m1 + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO1 PA1 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinWrite (1, GPIO_PIN_PA1, TRUE); + GpioPinSetDirection (1, GPIO_PIN_PA1, GPIO_PIN_OUTPUT); + /* Set GPIO2 PB6 (USB_TYPEC_PWREN) output high to power USB ports */ + GpioPinWrite (2, GPIO_PIN_PB6, TRUE); + GpioPinSetDirection (2, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable blue led\n")); + // GpioPinWrite (0, GPIO_PIN_PB7, TRUE); + // GpioPinSetDirection (0, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); + break; + case PCIE_SEGMENT_PCIE30X2: + GpioPinSetDirection (4, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); // PCIE30x1_0_{CLKREQN,WAKEN,PERSTN}_M1 + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinSetDirection (3, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 0); // PCIE20x1_2_{CLKREQN,WAKEN,PERSTN}_M0 + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* output high to enable power */ + + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + /* fall through */ + case PCIE_SEGMENT_PCIE30X2: + GpioPinWrite (1, GPIO_PIN_PA4, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PD2, Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE30X2: + GpioPinWrite (4, GPIO_PIN_PB0, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: // m.2 a+e key + GpioPinWrite (4, GPIO_PIN_PA5, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + break; + case PCIE_SEGMENT_PCIE20L2: // rtl8125b + GpioPinWrite (3, GPIO_PIN_PB0, !Enable); + break; + default: + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER0, + .ChannelID = PWM_CHANNEL1, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM0_CH1 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (0, GPIO_PIN_PC0, 0x3); // PWM1_M0 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (0, GPIO_PIN_PB7, FALSE); + GpioPinSetDirection (0, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (0, GPIO_PIN_PB7, Enable); +} + +VOID +EFIAPI +PlatformPcieWiFiEnable ( + IN BOOLEAN Enable + ) +{ + // WiFi - enable + GpioPinWrite (0, GPIO_PIN_PC4, Enable); + GpioPinSetDirection (0, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PA2, Enable); + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + + // bluetooth - enable + GpioPinWrite (3, GPIO_PIN_PD5, Enable); + GpioPinSetDirection (3, GPIO_PIN_PD5, GPIO_PIN_OUTPUT); + +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + PlatformPcieWiFiEnable(TRUE); + GpioPinSetFunction(1, GPIO_PIN_PD5, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.Modules.fdf.inc new file mode 100644 index 0000000..0a6cd9e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-rock-5b-plus.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc new file mode 100644 index 0000000..c463f24 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5BPlus/ROCK5BPlus.dsc @@ -0,0 +1,122 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2022, Xilin Wu +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2024, Yun Dou +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ROCK5BPlus + PLATFORM_VENDOR = Radxa + PLATFORM_GUID = b3a14308-f25c-4b69-9387-47e0de34e3b7 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ROCK 5 Model B Plus" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Radxa" + gRockchipTokenSpaceGuid.PcdFamilyName|"ROCK 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://docs.radxa.com/en/rock5/rock5b" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-rock-5bp" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdPcie30PhyModeDefault|0 # NANBNB + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|TRUE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_USB3) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/AcpiTables.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/AcpiTables.inf new file mode 100644 index 0000000..35d333b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/AcpiTables.inf @@ -0,0 +1,58 @@ +#/** @file +# +# ACPI table data and ASL sources required to boot the platform. +# +# Copyright (c) 2019-2021, ARM Limited. All rights reserved. +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiTables + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + MODULE_TYPE = USER_DEFINED + VERSION_STRING = 1.0 + RK_COMMON_ACPI_DIR = Silicon/Rockchip/RK3588/AcpiTables + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + Dsdt.asl + $(RK_COMMON_ACPI_DIR)/Madt.aslc + $(RK_COMMON_ACPI_DIR)/Fadt.aslc + $(RK_COMMON_ACPI_DIR)/Gtdt.aslc + $(RK_COMMON_ACPI_DIR)/Spcr.aslc + $(RK_COMMON_ACPI_DIR)/Mcfg.aslc + $(RK_COMMON_ACPI_DIR)/Dbg2.aslc + $(RK_COMMON_ACPI_DIR)/Pptt.aslc + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[FixedPcd] + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/Dsdt.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/Dsdt.asl new file mode 100755 index 0000000..bfdd8cf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/AcpiTables/Dsdt.asl @@ -0,0 +1,54 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define BOARD_I2S0_TPLG "i2s-jack" + +#define BOARD_AUDIO_CODEC_HID "ESSX8316" +#define BOARD_CODEC_I2C "\\_SB.I2C7" +#define BOARD_CODEC_I2C_ADDR 0x11 +#define BOARD_CODEC_GPIO "\\_SB.GPI1" +#define BOARD_CODEC_GPIO_PIN GPIO_PIN_PD5 + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RKCP ", "RK3588 ", 2) +{ + Scope (\_SB_) + { + include ("DsdtCommon.asl") + + include ("Cpu.asl") + + include ("Pcie.asl") + include ("Sata.asl") + include ("Emmc.asl") + include ("Sdhc.asl") + include ("Dma.asl") + // include ("Gmac.asl") + include ("Gpio.asl") + include ("I2c.asl") + include ("Uart.asl") + // include ("Spi.asl") + + include ("I2s.asl") + + include ("Usb2Host.asl") + include ("Usb3Host0.asl") + include ("Usb3Host1.asl") + include ("Usb3Host2.asl") + + Scope (I2C7) { + include ("Es8388.asl") + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.c new file mode 100644 index 0000000..53941d4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.c @@ -0,0 +1,388 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regulator_init_data rk806_init_data[] = { + /* Master PMIC */ + RK8XX_VOLTAGE_INIT(MASTER_BUCK1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK4, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK5, 850000), + //RK8XX_VOLTAGE_INIT(MASTER_BUCK6, 750000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK7, 2000000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK8, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_BUCK10, 1800000), + + RK8XX_VOLTAGE_INIT(MASTER_NLDO1, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO2, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO3, 750000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO4, 850000), + RK8XX_VOLTAGE_INIT(MASTER_NLDO5, 750000), + + RK8XX_VOLTAGE_INIT(MASTER_PLDO1, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO2, 1800000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO3, 1200000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO4, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO5, 3300000), + RK8XX_VOLTAGE_INIT(MASTER_PLDO6, 1800000), + + /* No dual PMICs on this platform */ +}; + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ) +{ + /* sdmmc0 iomux (microSD socket) */ + BUS_IOC->GPIO4D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //SDMMC_D0,SDMMC_D1,SDMMC_D2,SDMMC_D3 + BUS_IOC->GPIO4D_IOMUX_SEL_H = (0x00FFUL << 16) | (0x0011); //SDMMC_CLK,SDMMC_CMD + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x000FUL << 16) | (0x0001); //SDMMC_DET +} + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ) +{ + /* sdhci0 iomux (eMMC socket) */ + BUS_IOC->GPIO2A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_CMD,EMMC_CLKOUT,EMMC_DATASTROBE,EMMC_RSTN + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x1111); //EMMC_D0,EMMC_D1,EMMC_D2,EMMC_D3 + BUS_IOC->GPIO2D_IOMUX_SEL_H = (0xFFFFUL << 16) | (0x1111); //EMMC_D4,EMMC_D5,EMMC_D6,EMMC_D7 +} + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON59 0x03EC +#define CRU_CLKSEL_CON78 0x0438 + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ) +{ + /* io mux */ + //BUS_IOC->GPIO1A_IOMUX_SEL_H = (0xFFFFUL << 16) | 0x8888; + //BUS_IOC->GPIO1B_IOMUX_SEL_L = (0x000FUL << 16) | 0x0008; + PMU1_IOC->GPIO0A_IOMUX_SEL_H = (0x0FF0UL << 16) | 0x0110; + PMU1_IOC->GPIO0B_IOMUX_SEL_L = (0xF0FFUL << 16) | 0x1011; + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON59, (0x00C0UL << 16) | 0x0080); +} + +VOID +EFIAPI +Rk806Configure ( + VOID + ) +{ + UINTN RegCfgIndex; + + RK806Init(); + + for (RegCfgIndex = 0; RegCfgIndex < ARRAY_SIZE(rk806_init_data); RegCfgIndex++) + RK806RegulatorInit(rk806_init_data[RegCfgIndex]); +} + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ) +{ + struct regulator_init_data Rk806CpuLittleSupply = + RK8XX_VOLTAGE_INIT(MASTER_BUCK2, Microvolts); + + RK806RegulatorInit(Rk806CpuLittleSupply); +} + +VOID +EFIAPI +NorFspiIomux ( + VOID + ) +{ + /* io mux */ + MmioWrite32(NS_CRU_BASE + CRU_CLKSEL_CON78, + (((0x3 << 12) | (0x3f << 6)) << 16) | (0x0 << 12) | (0x3f << 6)); +#define FSPI_M1 +#if defined(FSPI_M0) + /*FSPI M0*/ + BUS_IOC->GPIO2A_IOMUX_SEL_L = ((0xF << 0) << 16) | (2 << 0); //FSPI_CLK_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x2222); //FSPI_D0_M0,FSPI_D1_M0,FSPI_D2_M0,FSPI_D3_M0 + BUS_IOC->GPIO2D_IOMUX_SEL_H = ((0xF << 8) << 16) | (0x2 << 8); //FSPI_CS0N_M0 +#elif defined(FSPI_M1) + /*FSPI M1*/ + BUS_IOC->GPIO2A_IOMUX_SEL_H = (0xFF00UL << 16) | (0x3300); //FSPI_D0_M1,FSPI_D1_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_L = (0xF0FFUL << 16) | (0x3033); //FSPI_D2_M1,FSPI_D3_M1,FSPI_CLK_M1 + BUS_IOC->GPIO2B_IOMUX_SEL_H = (0xF << 16) | (0x3); //FSPI_CS0N_M1 +#else + /*FSPI M2*/ + BUS_IOC->GPIO3A_IOMUX_SEL_L = (0xFFFFUL << 16) | (0x5555); //[FSPI_D0_M2-FSPI_D3_M2] + BUS_IOC->GPIO3A_IOMUX_SEL_H = (0xF0UL << 16) | (0x50); //FSPI_CLK_M2 + BUS_IOC->GPIO3C_IOMUX_SEL_H = (0xF << 16) | (0x2); //FSPI_CS0_M2 +#endif +} + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ) +{ + /* No GMAC here */ +} + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ) +{ + UINTN BaseAddr = (UINTN) CruBase; + + MmioWrite32(BaseAddr + 0x087C, 0x0E000000); +} + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ) +{ + switch (id) { + case 0: + GpioPinSetFunction(0, GPIO_PIN_PD1, 3); //i2c0_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD2, 3); //i2c0_sda_m2 + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD4, 9); //i2c1_scl_m2 + GpioPinSetFunction(0, GPIO_PIN_PD5, 9); //i2c1_sda_m2 + break; + case 2: + break; + case 3: + break; + case 4: + GpioPinSetFunction(2, GPIO_PIN_PB5, 9); //i2c4_scl_m1 + GpioPinSetFunction(2, GPIO_PIN_PB4, 9); //i2c4_sda_m1 + break; + case 5: + break; + case 6: + GpioPinSetFunction(0, GPIO_PIN_PD0, 9); //i2c6_scl_m0 + GpioPinSetFunction(0, GPIO_PIN_PC7, 9); //i2c6_sda_m0 + break; + case 7: + GpioPinSetFunction(1, GPIO_PIN_PD0, 9); //i2c7_scl_m0 + GpioPinSetFunction(1, GPIO_PIN_PD1, 9); //i2c7_sda_m0 + break; + default: + break; + } +} + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ) +{ + DEBUG((DEBUG_INFO, "UsbPortPowerEnable called\n")); + /* Set GPIO4 PB0 (USB_HOST_PWREN) output high to power USB ports */ + GpioPinWrite (3, GPIO_PIN_PB7, TRUE); + GpioPinSetDirection (3, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); + + // DEBUG((DEBUG_INFO, "Trying to enable blue led\n")); + // GpioPinWrite (0, GPIO_PIN_PB7, TRUE); + // GpioPinSetDirection (0, GPIO_PIN_PB7, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ) +{ + MmioWrite32(0xfd5d0008, 0x20000000); + MmioWrite32(0xfd5d4008, 0x20000000); + MmioWrite32(0xfd5d8008, 0x20000000); + MmioWrite32(0xfd5dc008, 0x20000000); + MmioWrite32(0xfd7f0a10, 0x07000700); + MmioWrite32(0xfd7f0a10, 0x07000000); +} + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ) +{ + /* Set reset and power IO to gpio output mode */ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinSetDirection (4, GPIO_PIN_PB6, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PA4, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinSetDirection (4, GPIO_PIN_PA5, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 1); // PCIE30x1_0_{CLKREQN,WAKEN,PERSTN}_M1 + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinSetDirection (4, GPIO_PIN_PA2, GPIO_PIN_OUTPUT); + GpioPinSetDirection (1, GPIO_PIN_PD2, GPIO_PIN_OUTPUT); + break; + case PCIE_SEGMENT_PCIE20L2: + GpioPinSetDirection (3, GPIO_PIN_PB0, GPIO_PIN_OUTPUT); + // PciePinmuxInit(Segment, 0); // PCIE20x1_2_{CLKREQN,WAKEN,PERSTN}_M0 + break; + default: + break; + } +} + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + /* output high to enable power */ + + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (1, GPIO_PIN_PA4, Enable); + break; + case PCIE_SEGMENT_PCIE20L0: + GpioPinWrite (1, GPIO_PIN_PD2, Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (1, GPIO_PIN_PD2, Enable); + break; + case PCIE_SEGMENT_PCIE20L2: + break; + default: + break; + } +} + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ) +{ + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + GpioPinWrite (4, GPIO_PIN_PB6, !Enable); + break; + case PCIE_SEGMENT_PCIE20L0: // m.2 a+e key + GpioPinWrite (4, GPIO_PIN_PA5, !Enable); + break; + case PCIE_SEGMENT_PCIE20L1: + GpioPinWrite (4, GPIO_PIN_PA2, !Enable); + break; + case PCIE_SEGMENT_PCIE20L2: // rtl8125b + GpioPinWrite (3, GPIO_PIN_PB0, !Enable); + break; + default: + break; + } +} + +PWM_DATA pwm_data = { + .ControllerID = PWM_CONTROLLER0, + .ChannelID = PWM_CHANNEL1, + .PeriodNs = 4000000, + .DutyNs = 4000000, + .Polarity = FALSE, +}; // PWM0_CH1 + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ) +{ + GpioPinSetFunction (4, GPIO_PIN_PB2, 0xb); // PWM14_M1 + RkPwmSetConfig (&pwm_data); + RkPwmEnable (&pwm_data); +} + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ) +{ + pwm_data.DutyNs = pwm_data.PeriodNs * Percentage / 100; + RkPwmSetConfig (&pwm_data); +} + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ) +{ + /* Status indicator */ + GpioPinWrite (0, GPIO_PIN_PC0, FALSE); + GpioPinSetDirection (0, GPIO_PIN_PC0, GPIO_PIN_OUTPUT); +} + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ) +{ + GpioPinWrite (0, GPIO_PIN_PC0, Enable); +} + +VOID +EFIAPI +PlatformPcieWiFiEnable ( + IN BOOLEAN Enable + ) +{ + // WiFi - enable + GpioPinWrite (0, GPIO_PIN_PC4, Enable); + GpioPinSetDirection (0, GPIO_PIN_PC4, GPIO_PIN_OUTPUT); + GpioPinWrite (4, GPIO_PIN_PA0, Enable); + GpioPinSetDirection (4, GPIO_PIN_PA0, GPIO_PIN_OUTPUT); + + // bluetooth - enable + GpioPinWrite (4, GPIO_PIN_PC5, Enable); + GpioPinSetDirection (4, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + GpioPinWrite (2, GPIO_PIN_PC5, Enable); + GpioPinSetDirection (2, GPIO_PIN_PC5, GPIO_PIN_OUTPUT); + +} + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ) +{ + // Configure various things specific to this platform + PlatformPcieWiFiEnable(TRUE); + GpioPinSetFunction(1, GPIO_PIN_PD5, 0); //jdet +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.inf new file mode 100644 index 0000000..b0ca955 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/Library/RockchipPlatformLib/RockchipPlatformLib.inf @@ -0,0 +1,35 @@ +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RockchipPlatformLib + FILE_GUID = 5178fa86-2fec-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RockchipPlatformLib + RKPLATLIB_COMMON_DIR = Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + HobLib + IoLib + MemoryAllocationLib + SerialPortLib + CruLib + GpioLib + PWMLib + +[Sources.common] + RockchipPlatformLib.c + $(RKPLATLIB_COMMON_DIR)/RK3588CruLib.c diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.Modules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.Modules.fdf.inc new file mode 100644 index 0000000..f9c5770 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.Modules.fdf.inc @@ -0,0 +1,18 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + # ACPI Support + INF RuleOverride = ACPITABLE $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Device Tree Support + FILE FREEFORM = gDtPlatformDefaultDtbFileGuid { + SECTION RAW = Platform/Rockchip/DeviceTree/rk3588-rock-5-itx.dtb + } + + # Splash screen logo + INF $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc new file mode 100644 index 0000000..8e4df6c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/Radxa/ROCK5ITX/ROCK5ITX.dsc @@ -0,0 +1,126 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2022, Xilin Wu +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = ROCK5ITX + PLATFORM_VENDOR = Radxa + PLATFORM_GUID = cb957236-be75-4077-aa31-0c3eae75c09c + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = Silicon/Rockchip/RK3588/RK3588.fdf + RK_PLATFORM_FVMAIN_MODULES = $(PLATFORM_DIRECTORY)/$(PLATFORM_NAME).Modules.fdf.inc + + # + # HYM8563 RTC support + # I2C location configured by PCDs below. + # + DEFINE RK_RTC8563_ENABLE = TRUE + + # + # RK3588-based platform + # +!include Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +[LibraryClasses.common] + RockchipPlatformLib|$(PLATFORM_DIRECTORY)/Library/RockchipPlatformLib/RockchipPlatformLib.inf + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"ROCK 5 ITX" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Radxa" + gRockchipTokenSpaceGuid.PcdFamilyName|"ROCK 5" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://docs.radxa.com/rock5/rock5itx" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"rk3588-rock-5-itx" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x42, 0x43, 0x51, 0x11 ,0x22} + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0, 0x0, 0x6, 0x7 } + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ FALSE, FALSE, TRUE, FALSE } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x42, 0x43 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0, 0x0 } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ $(SCMI_CLK_CPUB01), $(SCMI_CLK_CPUB23) } + gPcf8563RealTimeClockLibTokenSpaceGuid.PcdI2cSlaveAddress|0x51 + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0x6 + + # + # HDMI1 Display + # + gRockchipTokenSpaceGuid.PcdHdmiId|0x00000001 #hdmi1 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_PCIE) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_PCIE) + + # + # USB/DP Combo PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|TRUE + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|TRUE + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x2, 0x3 } + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 } + + # + # I2S + # + gRK3588TokenSpaceGuid.PcdI2S0Supported|TRUE + + # + # On-Board fan output + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|TRUE + + +################################################################################ +# +# Components Section - list of all EDK II Modules needed by this Platform. +# +################################################################################ +[Components.common] + # ACPI Support + $(PLATFORM_DIRECTORY)/AcpiTables/AcpiTables.inf + + # Splash screen logo + $(VENDOR_DIRECTORY)/Drivers/LogoDxe/LogoDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.bmp b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0499e1884c34cdaa622dd0097900ccc99ec74789 GIT binary patch literal 106738 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 Re^hBS!hV6&@%HuQ{{g9*3o`%! literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.c new file mode 100644 index 0000000..2255b11 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.c @@ -0,0 +1,144 @@ +/** @file + Logo DXE Driver, install Edkii Platform Logo protocol. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + EFI_IMAGE_ID ImageId; + EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute; + INTN OffsetX; + INTN OffsetY; +} LOGO_ENTRY; + +STATIC EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx; +STATIC EFI_HII_HANDLE mHiiHandle; +STATIC LOGO_ENTRY mLogos[] = { + { + IMAGE_TOKEN (IMG_LOGO), + EdkiiPlatformLogoDisplayAttributeCenter, + 0, + 0 + } +}; + +/** + Load a platform logo image and return its data and attributes. + + @param This The pointer to this protocol instance. + @param Instance The visible image instance is found. + @param Image Points to the image. + @param Attribute The display attributes of the image returned. + @param OffsetX The X offset of the image regarding the Attribute. + @param OffsetY The Y offset of the image regarding the Attribute. + + @retval EFI_SUCCESS The image was fetched successfully. + @retval EFI_NOT_FOUND The specified image could not be found. +**/ +STATIC +EFI_STATUS +EFIAPI +GetImage ( + IN EDKII_PLATFORM_LOGO_PROTOCOL *This, + IN OUT UINT32 *Instance, + OUT EFI_IMAGE_INPUT *Image, + OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute, + OUT INTN *OffsetX, + OUT INTN *OffsetY + ) +{ + UINT32 Current; + + if (Instance == NULL || Image == NULL || + Attribute == NULL || OffsetX == NULL || OffsetY == NULL) { + return EFI_INVALID_PARAMETER; + } + + Current = *Instance; + if (Current >= ARRAY_SIZE (mLogos)) { + return EFI_NOT_FOUND; + } + + (*Instance)++; + *Attribute = mLogos[Current].Attribute; + *OffsetX = mLogos[Current].OffsetX; + *OffsetY = mLogos[Current].OffsetY; + + return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, + mLogos[Current].ImageId, Image); +} + +STATIC EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = { + GetImage +}; + +/** + Entrypoint of this module. + + This function is the entrypoint of this module. It installs the Edkii + Platform Logo protocol. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeLogo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HANDLE Handle; + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, + (VOID **) &HiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiImageExProtocolGuid, NULL, + (VOID **) &mHiiImageEx); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HII package list from ImageHandle + // + Status = gBS->OpenProtocol (ImageHandle, &gEfiHiiPackageListProtocolGuid, + (VOID **) &PackageList, ImageHandle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "HII Image Package with logo not found in PE/COFF resource section\n")); + return Status; + } + + // + // Publish HII package list to HII Database. + // + Status = HiiDatabase->NewPackageList (HiiDatabase, PackageList, NULL, + &mHiiHandle); + if (!EFI_ERROR (Status)) { + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo, NULL); + } + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.idf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.idf new file mode 100644 index 0000000..c2d9096 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/Logo.idf @@ -0,0 +1,10 @@ +// @file +// Platform Logo image definition file. +// +// Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +// Copyright (c) 2022 Rockchip Electronics Co. Ltd. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +#image IMG_LOGO Logo.bmp diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/LogoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/LogoDxe.inf new file mode 100644 index 0000000..e7a35de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/Drivers/LogoDxe/LogoDxe.inf @@ -0,0 +1,48 @@ +## @file +# The default logo bitmap picture shown on setup screen. +# +# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
    +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LogoDxe + FILE_GUID = 4b55f0bc-8b1a-11ec-bd4b-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeLogo +# +# This flag specifies whether HII resource section is generated into PE image. +# + UEFI_HII_RESOURCE_SECTION = TRUE + +[Sources] + Logo.bmp + Logo.c + Logo.idf + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiImageExProtocolGuid ## CONSUMES + gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES + gEdkiiPlatformLogoProtocolGuid ## PRODUCES + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiImageExProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/StationM3/StationM3.dsc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/StationM3/StationM3.dsc new file mode 100644 index 0000000..17dd5f8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Platform/StationPC/StationM3/StationM3.dsc @@ -0,0 +1,52 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = StationM3 + PLATFORM_VENDOR = StationPC + PLATFORM_GUID = c292d925-29ff-4327-9ed9-517c9d921840 + PLATFORM_VERSION = 0.2 + DSC_SPECIFICATION = 0x00010019 + OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME) + VENDOR_DIRECTORY = Platform/$(PLATFORM_VENDOR) + PLATFORM_DIRECTORY = $(VENDOR_DIRECTORY)/$(PLATFORM_NAME) + SUPPORTED_ARCHITECTURES = AARCH64 + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + + # + # Platform based on ROC-RK3588S-PC board + # +!include Platform/Firefly/ROC-RK3588S-PC/ROC-RK3588S-PC.dsc.inc + +################################################################################ +# +# Pcd Section - list of all EDK II PCD Entries defined by this Platform. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdPlatformName|"Station M3" + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Station PC" + gRockchipTokenSpaceGuid.PcdFamilyName|"Station M" + gRockchipTokenSpaceGuid.PcdProductUrl|"https://www.stationpc.com/product/stationm3" + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"roc-rk3588s-pc" + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_MAX) diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.c new file mode 100644 index 0000000..2bae038 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.c @@ -0,0 +1,356 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. +Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +CONST CHAR16 ShellI2cDemoFileName[] = L"I2cDemoTestShellCommand"; +EFI_HANDLE ShellI2cDemoHiiHandle = NULL; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"read", TypeFlag}, + {L"write", TypeFlag}, + {L"list", TypeFlag}, + {L"help", TypeFlag}, + {NULL , TypeMax} + }; + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +STATIC +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameI2cDemo ( + VOID + ) +{ + return ShellI2cDemoFileName; +} + +STATIC +VOID +Usage ( + VOID + ) +{ + Print (L"I2C DEMO TEST commands:\n" + "i2cdemo [read] [write] [list] [][

    ] [] [] [] [] \n" + "All modes except 'list' require Address, Length and Chip set.\n\n" + "read - read from i2cdemo device\n" + "write - write Data to i2cdemo device\\n" + "list - list available i2cdemo devices\n\n" + "Bus - I2C bus address\n" + "Address - i2cdemo bus address\n" + "Length - data byte length to read/write\\n" + "RegAddress - address in i2cdemo to read/write\n" + "RegAddressLength - address in i2cdemo length\n" + "Data - data byte to be written\n" + "Examples:\n" + "List devices:\n" + " i2cdemo list\n" + "Read 2 bytes from address 0x10 in chip 0x51@bus2:\n" + " i2cdemo read 2 0x51 2 0x10 1\n" + "Fill 16 bytes with 0xab at address 0x0 in chip 0x57:\n" + " i2cdemo write 2 0x51 1 0x10 1 0x00\n" + ); +} + +STATIC +EFI_STATUS +I2cDemoList ( + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN ProtocolCount; + ROCKCHIP_I2CDEMO_PROTOCOL *I2cDemoProtocol; + UINTN i; + Status = gBS->LocateHandleBuffer ( ByProtocol, + &gRockchipI2cDemoProtocolGuid, + NULL, + &ProtocolCount, + &HandleBuffer + ); + if (ProtocolCount == 0) { + Print (L"0 devices found.\n"); + } else { + Print (L"%u devices found: ", ProtocolCount); + } + + for (i = 0; i < ProtocolCount; i++) { + Status = gBS->OpenProtocol ( + HandleBuffer[i], + &gRockchipI2cDemoProtocolGuid, + (VOID **) &I2cDemoProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ); + Print (L"0x%x at bus %d\n", I2C_DEVICE_ADDRESS(I2cDemoProtocol->Identifier), + I2C_DEVICE_BUS(I2cDemoProtocol->Identifier)); + Status = gBS->CloseProtocol ( HandleBuffer[i], + &gRockchipI2cDemoProtocolGuid, + gImageHandle, + NULL ); + } + Print (L"\n"); + return Status; +} + +STATIC +EFI_STATUS +I2cDemoLocateProtocol ( + IN UINT32 Identifier, + OUT EFI_HANDLE *FoundHandle, + OUT ROCKCHIP_I2CDEMO_PROTOCOL **FoundI2cDemoProtocol + ) +{ + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + UINTN ProtocolCount; + ROCKCHIP_I2CDEMO_PROTOCOL *I2cDemoProtocol; + UINTN i; + Status = gBS->LocateHandleBuffer ( ByProtocol, + &gRockchipI2cDemoProtocolGuid, + NULL, + &ProtocolCount, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + return Status; + } + for (i = 0; i < ProtocolCount; i++) { + Status = gBS->OpenProtocol ( + HandleBuffer[i], + &gRockchipI2cDemoProtocolGuid, + (VOID **) &I2cDemoProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ); + + if (I2cDemoProtocol->Identifier == Identifier) { + *FoundI2cDemoProtocol = I2cDemoProtocol; + *FoundHandle = HandleBuffer[i]; + return EFI_SUCCESS; + } + Status = gBS->CloseProtocol ( HandleBuffer[i], + &gRockchipI2cDemoProtocolGuid, + gImageHandle, + NULL ); + } + *FoundI2cDemoProtocol = NULL; + + return EFI_UNSUPPORTED; +} + +SHELL_STATUS +EFIAPI +ShellCommandRunI2cDemo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + CHAR16 *ProblemParam; + CONST CHAR16 *ValueStr; + UINTN Bus, Address, XferLength, RegAddress, RegAddressLength, Source; + UINT8 *Buffer; + BOOLEAN ReadMode, WriteMode; + EFI_HANDLE Handle, ProtHandle; + ROCKCHIP_I2CDEMO_PROTOCOL *I2cDemoProtocol = NULL; + UINTN HandleSize, i; + UINTN TxData; + + Handle = NULL; + Source = 0; + HandleSize = 2 * sizeof (EFI_HANDLE); + + Status = gBS->LocateHandle (ByProtocol, &gRockchipI2cDemoProtocolGuid, NULL, + &HandleSize, &ProtHandle); + if (EFI_ERROR(Status)) { + Print (L"No I2cDemo protocol, connect I2C stack\n"); + Status = gBS->LocateHandle (ByProtocol, &gEfiI2cMasterProtocolGuid, NULL, + &HandleSize, &ProtHandle); + if (EFI_ERROR(Status)) { + Print (L"Failed to locate I2cMaster protocol, abort!\n"); + return SHELL_ABORTED; + } + Status = gBS->ConnectController (ProtHandle, NULL, NULL, TRUE); + if (EFI_ERROR(Status)) { + Print (L"Cannot connect I2C stack, abort!\n"); + return SHELL_ABORTED; + } + } + + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"Error - failed to initialize shell\n"); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + Print (L"Error - failed to parse command line\n"); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"list")) { + I2cDemoList(); + return SHELL_SUCCESS; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"help")) { + Usage(); + return SHELL_SUCCESS; + } + + ReadMode = ShellCommandLineGetFlag (CheckPackage, L"read"); + WriteMode = ShellCommandLineGetFlag (CheckPackage, L"write"); + + if (!ReadMode && !WriteMode) { + Print (L"Not support mode given.\n"); + Usage(); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetCount(CheckPackage) != 6 && ReadMode) { + Print (L"Not enough arguments given.\n"); + Usage(); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetCount(CheckPackage) != 7 && WriteMode) { + Print (L"Not enough arguments given.\n"); + Usage(); + return SHELL_ABORTED; + } + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 1); + Bus = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 2); + Address = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 3); + XferLength = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 4); + RegAddress = ShellHexStrToUintn (ValueStr); + + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 5); + RegAddressLength = ShellHexStrToUintn (ValueStr); + + if (WriteMode) { + ValueStr = ShellCommandLineGetRawValue(CheckPackage, 6); + TxData = ShellHexStrToUintn (ValueStr); + } + + I2cDemoLocateProtocol (I2C_DEVICE_INDEX(Bus, Address), &Handle, &I2cDemoProtocol); + if (I2cDemoProtocol == NULL) { + Print (L"Failed to locate I2CDEMO protocol.\n"); + return SHELL_INVALID_PARAMETER; + } + + Buffer = AllocateZeroPool (XferLength); + if (Buffer == NULL) { + Status = SHELL_OUT_OF_RESOURCES; + Print (L"Error - out of resources.\n"); + goto out_close; + } + + if (ReadMode) { + Status = I2cDemoProtocol->Read(I2cDemoProtocol, (UINT8 *)&RegAddress, RegAddressLength, Buffer, XferLength); + if (!EFI_ERROR(Status)) { + Print (L"Read data[0 ~ %d]:", XferLength - 1); + for (i = 0; i Write(I2cDemoProtocol, (UINT8 *)&RegAddress, RegAddressLength, (UINT8 *)&TxData, XferLength); + } + + if (EFI_ERROR(Status)) { + Print (L"I2c Operation failed %d.\n", Status); + } else { + Print (L"I2c Operation successfully.\n"); + } + + Status = SHELL_SUCCESS; + + FreePool(Buffer); +out_close: + gBS->CloseProtocol ( Handle, + &gRockchipI2cDemoProtocolGuid, + gImageHandle, + NULL ); + + return Status; +} + +EFI_STATUS +EFIAPI +ShellI2cDemoTestLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + Print (L"~Filed to add Hii package\n"); + ShellI2cDemoHiiHandle = NULL; + + ShellI2cDemoHiiHandle = HiiAddPackages ( + &gShellI2cDemoHiiGuid, gImageHandle, + UefiShellI2cDemoLibStrings, NULL + ); + if (ShellI2cDemoHiiHandle == NULL) { + Print (L"Filed to add Hii package\n"); + return EFI_DEVICE_ERROR; + } + ShellCommandRegisterCommandName ( + L"i2cdemo", ShellCommandRunI2cDemo, ShellCommandGetManFileNameI2cDemo, 0, + L"i2cdemo", TRUE , ShellI2cDemoHiiHandle, STRING_TOKEN (STR_GET_HELP_I2CDEMO) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellI2cDemoTestLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (ShellI2cDemoHiiHandle != NULL) { + HiiRemovePackages (ShellI2cDemoHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf new file mode 100644 index 0000000..8d669e3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf @@ -0,0 +1,45 @@ +# +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellI2cDemoLib + FILE_GUID = adf4b61c-2ca3-4e1a-9597-99282f5a4aa2 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellI2cDemoTestLibConstructor + DESTRUCTOR = ShellI2cDemoTestLibDestructor + +[Sources] + I2cDemoTest.c + I2cDemoTest.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + PcdLib + +[Protocols] + gRockchipI2cDemoProtocolGuid + gEfiI2cMasterProtocolGuid + +[Guids] + gShellI2cDemoHiiGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.uni b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.uni new file mode 100644 index 0000000..e672dfc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.uni @@ -0,0 +1,49 @@ +/******************************************************************************* +Copyright (C) 2016 Marvell International Ltd. +Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +/=# +#langdef en-US "english" + +#string STR_GET_HELP_I2CDEMO #language en-US "" +".TH i2cdemo 0 "Basic I2CDEMO command."\r\n" +".SH NAME\r\n" +"Read/write data from/into I2cDemo Device memory\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"i2cdemo [read] [write] [list] [][
    ] [] []\r\n" +" [] []\r\n" +".SH OPTIONS\r\n" +" \r\n" +"All modes except 'list' require Address, Length and Chip set.\n\n" +"read - read from i2cdemo device\n" +"write - write Data to i2cdemo device\\n" +"list - list available i2cdemo devices\n\n" +"Bus - I2C bus address\n" +"Address - i2cdemo bus address\n" +"Length - data byte length to read/write\\n" +"RegAddress - address in i2cdemo to read/write\n" +"RegAddressLength - address in i2cdemo length\n" +"Data - data byte to be written\n" +"Examples:\n" +"List devices:\n" +" i2cdemo list\n" +" \r\n" +"EXAMPLES:\r\n" +"List devices:\r\n" +" i2cdemo list\r\n" +"Read 2 bytes from address 0x10 in chip 0x51@bus2:\n" +" i2cdemo read 2 0x51 2 0x10 1\n" +"Fill 16 bytes with 0xab at address 0x0 in chip 0x57:\n" +" i2cdemo write 2 0x51 1 0x10 1 0x00\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_ABORTED Error while processing command\r\n" + + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.c new file mode 100755 index 0000000..09edf64 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.c @@ -0,0 +1,417 @@ +/******************************************************************************* +Copyright (c) 2022, Rockchip Corporation. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UNI_NOR_FLASH_PROTOCOL *SpiFlashProtocol; + +CONST CHAR16 gShellSpiFlashFileName[] = L"ShellCommand"; +EFI_HANDLE gShellSfHiiHandle = NULL; + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"read", TypeFlag}, + {L"readfile", TypeFlag}, + {L"write", TypeFlag}, + {L"writefile", TypeFlag}, + {L"erase", TypeFlag}, + {L"update", TypeFlag}, + {L"updatefile", TypeFlag}, + {L"help", TypeFlag}, + {NULL , TypeMax} + }; + +typedef enum { + READ = 2, + READ_FILE = 4, + WRITE = 8, + WRITE_FILE = 16, + ERASE = 32, + UPDATE = 64, + UPDATE_FILE = 128, +} Flags; + +/** + Return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameSpiFlash ( + VOID + ) +{ + + return gShellSpiFlashFileName; +} + +VOID +SfUsage ( + VOID + ) +{ + Print (L"\nBasic SPI command\n" + "sf [read | readfile | write | writefile | erase |" + "update | updatefile]" + "[
    | ] \n\n" + "Address - Address in RAM to store/load data\n" + "FilePath - Path to file to read/write data from/to\n" + "Offset - Offset from beginning of SPI flash to store/load data\n" + "Length - Number of bytes to send\n" + "Examples:\n" + "Check if there is response from SPI flash\n" + "Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\n" + " sf read 0x100000 0xe00000 32\n" + "Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\n" + " sf read 0x300000 0x200000 0x20\n" + "Erase 0x10000 bytes from offset 0x100000 of SPI flash\n" + " sf erase 0x100000 0x100000\n" + "Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\n" + " sf write 0x200000 0x4000000 16\n" + "Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\n" + " sf update 0x100000 0xe00000 100\n" + "Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\n" + " sf readfile fs2:file.bin 0x0 0x3000 \n" + "Update data in SPI flash at 0x3000000 from file Linux.efi\n" + " sf updatefile Linux.efi 0x3000000\n" + ); +} + +STATIC +EFI_STATUS +OpenAndPrepareFile ( + IN CHAR16 *FilePath, + SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINT64 OpenMode; + + OpenMode = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE; + + Status = ShellOpenFileByName (FilePath, FileHandle, OpenMode, 0); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot open file\n"); + return Status; + } + + Status = FileHandleSetPosition(*FileHandle, 0); + + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot set file position to first byte\n"); + ShellCloseFile (FileHandle); + return Status; + } + + return EFI_SUCCESS; +} + +SHELL_STATUS +EFIAPI +ShellCommandRunSpiFlash ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ +EFI_STATUS Status; + LIST_ENTRY *CheckPackage; + EFI_PHYSICAL_ADDRESS Address = 0, Offset = 0; + SHELL_FILE_HANDLE FileHandle = NULL; + UINTN ByteCount, I; + UINT64 FileSize; + UINT8 *Buffer = NULL, *FileBuffer = NULL; + CHAR16 *ProblemParam, *FilePath; + CONST CHAR16 *AddressStr = NULL, *OffsetStr = NULL; + CONST CHAR16 *LengthStr = NULL, *FileStr = NULL; + BOOLEAN AddrFlag = FALSE, LengthFlag = TRUE, FileFlag = FALSE; + UINT8 Flag = 0, CheckFlag = 0; + + Status = gBS->LocateProtocol ( + &gUniNorFlashProtocolGuid, + NULL, + (VOID **)&SpiFlashProtocol + ); + if (EFI_ERROR(Status)) { + Print (L"sf: Cannot locate SpiFlash protocol\n"); + return SHELL_ABORTED; + } + + // Parse Shell command line + Status = ShellInitialize (); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot initialize Shell\n"); + ASSERT_EFI_ERROR (Status); + return SHELL_ABORTED; + } + + Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE); + if (EFI_ERROR (Status)) { + Print (L"sf: Error while parsing command line\n"); + return SHELL_ABORTED; + } + + if (ShellCommandLineGetFlag (CheckPackage, L"help")) { + SfUsage(); + return EFI_SUCCESS; + } + + // Check flags provided by user + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"read") << 1); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"readfile") << 2); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"write") << 3); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"writefile") << 4); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"erase") << 5); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"update") << 6); + Flag |= (ShellCommandLineGetFlag (CheckPackage, L"updatefile") << 7); + + CheckFlag = Flag; + for (I = 0; CheckFlag; CheckFlag >>= 1) { + I += CheckFlag & 1; + if (I > 1) { + Print (L"sf: Too many flags\n"); + SfUsage(); + return SHELL_ABORTED; + } + } + + switch (Flag) { + case READ: + case WRITE: + case UPDATE: + AddressStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); + AddrFlag = TRUE; + break; + case ERASE: + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 1); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 2); + break; + case READ_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthStr = ShellCommandLineGetRawValue (CheckPackage, 3); + FileFlag = TRUE; + break; + case WRITE_FILE: + case UPDATE_FILE: + FileStr = ShellCommandLineGetRawValue (CheckPackage, 1); + OffsetStr = ShellCommandLineGetRawValue (CheckPackage, 2); + LengthFlag = FALSE; + FileFlag = TRUE; + break; + } + + // Read address parameter + if ((AddressStr == NULL) & AddrFlag) { + Print (L"sf: No address parameter!\n"); + return SHELL_ABORTED; + } else if (AddrFlag) { + Address = ShellHexStrToUintn (AddressStr); + if (Address == (UINTN)(-1)) { + Print (L"sf: Wrong address parameter\n"); + return SHELL_ABORTED; + } + } + + // Read offset parameter + if (OffsetStr == NULL) { + Print (L"sf: No offset Parameter!\n"); + return SHELL_ABORTED; + } else { + Offset = ShellHexStrToUintn (OffsetStr); + if (Offset < 0) { + Print (L"sf: Wrong offset parameter: %s", OffsetStr); + return SHELL_ABORTED; + } + } + + // Read length parameter + if ((LengthStr == NULL) & LengthFlag) { + Print (L"sf: No lenght parameter!\n"); + return SHELL_ABORTED; + } else if (LengthFlag) { + ByteCount = ShellStrToUintn (LengthStr); + if (ByteCount < 0) { + Print (L"sf: Wrong length parameter %s!\n", LengthStr); + return SHELL_ABORTED; + } + } + + if (FileFlag) { + // Read FilePath parameter + if (FileStr == NULL) { + Print (L"sf: No FilePath parameter!\n"); + return SHELL_ABORTED; + } else { + FilePath = (CHAR16 *) FileStr; + Status = ShellIsFile (FilePath); + // When read file into flash, file doesn't have to exist + if (EFI_ERROR (Status) && !(Flag & READ_FILE)) { + Print (L"sf: Wrong FilePath parameter!\n"); + return SHELL_ABORTED; + } + } + + Status = OpenAndPrepareFile (FilePath, &FileHandle); + if (EFI_ERROR(Status)) { + Print (L"sf: Error while preparing file\n"); + return SHELL_ABORTED; + } + + // Get file size in order to check correctness at the end of transfer + if (Flag & (WRITE_FILE | UPDATE_FILE)) { + Status = FileHandleGetSize (FileHandle, &FileSize); + if (EFI_ERROR (Status)) { + Print (L"sf: Cannot get file size\n"); + } + ByteCount = (UINTN) FileSize; + } + + FileBuffer = AllocateZeroPool ((UINTN) ByteCount); + if (FileBuffer == NULL) { + Print (L"sf: Cannot allocate memory\n"); + goto Error_Close_File; + } + + // Read file content and store it in FileBuffer + if (Flag & (WRITE_FILE | UPDATE_FILE)) { + Status = FileHandleRead (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR (Status)) { + Print (L"sf: Read from file error\n"); + goto Error_Free_Buffer; + } else if (ByteCount != (UINTN) FileSize) { + Print (L"sf: Not whole file read. Abort\n"); + goto Error_Free_Buffer; + } + } + } + + Buffer = (UINT8 *)(UINTN)Address; + if (FileFlag) { + Buffer = FileBuffer; + } + + switch (Flag) { + case READ: + case READ_FILE: + Status = SpiFlashProtocol->Read (SpiFlashProtocol, Offset, Buffer, ByteCount); + break; + case ERASE: + Status = SpiFlashProtocol->Erase (SpiFlashProtocol, Offset, ByteCount); + break; + case WRITE: + case WRITE_FILE: + Status = SpiFlashProtocol->Write (SpiFlashProtocol, Offset, Buffer, ByteCount); + break; + case UPDATE: + case UPDATE_FILE: + Status = SpiFlashProtocol->Update (SpiFlashProtocol, Offset, Buffer, ByteCount); + break; + } + + if (EFI_ERROR (Status)) { + Print (L"sf: Error while performing spi transfer\n"); + return SHELL_ABORTED; + } + + switch (Flag) { + case ERASE: + Print (L"sf: %d bytes succesfully erased at offset 0x%x\n", ByteCount, + Offset); + break; + case WRITE: + case WRITE_FILE: + Print (L"sf: Write %d bytes at offset 0x%x\n", ByteCount, Offset); + break; + case UPDATE: + case UPDATE_FILE: + Print (L"sf: Update %d bytes at offset 0x%x\n", ByteCount, Offset); + break; + case READ: + Print (L"sf: Read %d bytes from offset 0x%x\n", ByteCount, Offset); + break; + case READ_FILE: + Status = FileHandleWrite (FileHandle, &ByteCount, FileBuffer); + if (EFI_ERROR(Status)) { + Print (L"sf: Error while writing into file\n"); + goto Error_Free_Buffer; + } + break; + } + + if (FileFlag) { + FreePool (FileBuffer); + + if (FileHandle != NULL) { + ShellCloseFile (&FileHandle); + } + } + + return EFI_SUCCESS; + +Error_Free_Buffer: + FreePool (FileBuffer); +Error_Close_File: + ShellCloseFile (&FileHandle); + return SHELL_ABORTED; +} + +EFI_STATUS +EFIAPI +ShellSpiFlashLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellSfHiiHandle = NULL; + + gShellSfHiiHandle = HiiAddPackages ( + &gShellSfHiiGuid, gImageHandle, + UefiShellSpiFlashLibStrings, NULL + ); + if (gShellSfHiiHandle == NULL) { + return EFI_DEVICE_ERROR; + } + + ShellCommandRegisterCommandName ( + L"sf", ShellCommandRunSpiFlash, ShellCommandGetManFileNameSpiFlash, 0, + L"sf", TRUE , gShellSfHiiHandle, STRING_TOKEN (STR_GET_HELP_SF) + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ShellSpiFlashLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + if (gShellSfHiiHandle != NULL) { + HiiRemovePackages (gShellSfHiiHandle); + } + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf new file mode 100644 index 0000000..b71014f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf @@ -0,0 +1,46 @@ +# +# Copyright (c) 2022, Rockchip Limited. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellSpiFlashLib + FILE_GUID = 2f2dd8c9-221f-4acf-afe5-5897264c5774 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 0.1 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellSpiFlashLibConstructor + DESTRUCTOR = ShellSpiFlashLibDestructor + +[Sources] + SpiFlashCmd.c + SpiFlashCmd.uni + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + PcdLib + HiiLib + FileHandleLib + +[Protocols] + gUniNorFlashProtocolGuid + +[Guids] + gShellSfHiiGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.uni b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.uni new file mode 100755 index 0000000..986785d --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.uni @@ -0,0 +1,50 @@ +/******************************************************************************* +Copyright (c) 2022, Rockchip Corporation. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +/=# + +#langdef en-US "english" + +#string STR_GET_HELP_SF #language en-US "" +".TH sf 0 "Basic SPI flash command."\r\n" +".SH NAME\r\n" +"Read/write data from/into SPI flash.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"sf [read | readfile | write | writefile | erase | \r\n" +" update | updatefile] \r\n" +".SH OPTIONS\r\n" +" \r\n" +" Length - Number of bytes to send\r\n" +" Address - Address in RAM to store/load data\r\n" +" Offset - Offset from beginning of SPI flash to store/load data\r\n" +" FilePath - Path to file to read data into or write/update data from \r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +"Check if there is response from SPI flash\r\n" +"Read 32 bytes from 0xe00000 of SPI flash into RAM at address 0x100000\r\n" +" sf read 0x100000 0xe00000 32\r\n" +"Read 0x20 bytes from 0x200000 of SPI flash into RAM at address 0x300000\r\n" +" sf read 0x300000 0x200000 0x20\r\n" +"Erase 0x10000 bytes from offset 0x100000 of SPI flash\r\n" +" sf erase 0x100000 0x100000\r\n" +"Write 16 bytes from 0x200000 at RAM into SPI flash at address 0x4000000\r\n" +" sf write 0x200000 0x4000000 16\r\n" +"Update 100 bytes from 0x100000 at RAM in SPI flash at address 0xe00000\r\n" +" sf update 0x100000 0xe00000 100\r\n" +"Read 0x3000 bytes from 0x0 of SPI flash into file fs2:file.bin\r\n" +" sf readfile fs2:file.bin 0x0 0x3000\r\n" +"Update data in SPI flash at 0x3000000 from file Linux.efi\r\n" +" sf update Linux.efi 0x3000000\r\n" +".SH RETURNVALUES\r\n" +" \r\n" +"RETURN VALUES:\r\n" +" SHELL_SUCCESS The action was completed as requested.\r\n" +" SHELL_ABORTED Error while processing command\r\n" + + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.c new file mode 100644 index 0000000..595d5ec --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.c @@ -0,0 +1,276 @@ +/** @file + * + * Synopsys DesignWare Cores SDHCI eMMC driver + * + * Copyright (c) 2017, Linaro, Ltd. All rights reserved.
    + * Copyright (c) 2022, Patrick Wildt + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "DwcSdhciDxe.h" + +#define EMMC_FORCE_HIGH_SPEED FixedPcdGetBool(PcdDwcSdhciForceHighSpeed) +#define EMMC_DISABLE_HS400 FixedPcdGetBool(PcdDwcSdhciDisableHs400) + +STATIC EFI_HANDLE mSdMmcControllerHandle; + +/** + Override function for SDHCI capability bits + + @param[in] ControllerHandle The EFI_HANDLE of the controller. + @param[in] Slot The 0 based slot index. + @param[in,out] SdMmcHcSlotCapability The SDHCI capability structure. + @param[in,out] BaseClkFreq The base clock frequency value that + optionally can be updated. + + @retval EFI_SUCCESS The override function completed successfully. + @retval EFI_NOT_FOUND The specified controller or slot does not exist. + @retval EFI_INVALID_PARAMETER SdMmcHcSlotCapability is NULL + +**/ +STATIC +EFI_STATUS +EFIAPI +EmmcSdMmcCapability ( + IN EFI_HANDLE ControllerHandle, + IN UINT8 Slot, + IN OUT VOID *SdMmcHcSlotCapability, + IN OUT UINT32 *BaseClkFreq + ) +{ + SD_MMC_HC_SLOT_CAP *Capability = SdMmcHcSlotCapability; + + if (SdMmcHcSlotCapability == NULL) { + return EFI_INVALID_PARAMETER; + } + if (ControllerHandle != mSdMmcControllerHandle) { + return EFI_NOT_FOUND; + } + + // + // Disable ADMA2 to avoid data corruption. + // This controller has the limitation that a single descriptor + // cannot cross 128 MB boundaries and must be split. + // This would require a patch in SdMmcPciHcDxe, but SDMA works + // fine for the time being. + // + Capability->Adma2 = 0; + + Capability->Hs400 = !EMMC_DISABLE_HS400; + + if (EMMC_FORCE_HIGH_SPEED) { + Capability->BaseClkFreq = 52; + Capability->Sdr50 = 0; + Capability->Ddr50 = 0; + Capability->Sdr104 = 0; + Capability->Hs400 = 0; + } + + return EFI_SUCCESS; +} + +/** + + Override function for SDHCI controller operations + + @param[in] ControllerHandle The EFI_HANDLE of the controller. + @param[in] Slot The 0 based slot index. + @param[in] PhaseType The type of operation and whether the + hook is invoked right before (pre) or + right after (post) + @param[in,out] PhaseData The pointer to a phase-specific data. + + @retval EFI_SUCCESS The override function completed successfully. + @retval EFI_NOT_FOUND The specified controller or slot does not exist. + @retval EFI_INVALID_PARAMETER PhaseType is invalid + +**/ +STATIC +EFI_STATUS +EFIAPI +EmmcSdMmcNotifyPhase ( + IN EFI_HANDLE ControllerHandle, + IN UINT8 Slot, + IN EDKII_SD_MMC_PHASE_TYPE PhaseType, + IN OUT VOID *PhaseData + ) +{ + SD_MMC_BUS_MODE *Timing; + UINTN MaxClockFreq; + UINT32 Value, i; + UINT32 TxClkTapNum; + + DEBUG ((DEBUG_INFO, "%a\n", __FUNCTION__)); + + if (ControllerHandle != mSdMmcControllerHandle) { + return EFI_SUCCESS; + } + + ASSERT (Slot == 0); + + switch (PhaseType) { + case EdkiiSdMmcInitHostPost: + /* + * Just before this Notification POWER_CTRL is toggled to power off + * and on the card. On this controller implementation, toggling + * power off also removes SDCLK_ENABLE (BIT2) from from CLOCK_CTRL. + * Since the clock has already been set up prior to the power toggle, + * re-add the SDCLK_ENABLE bit to start the clock. + */ + MmioOr16((UINT32) SD_MMC_HC_CLOCK_CTRL, CLOCK_CTRL_SDCLK_ENABLE); + break; + + case EdkiiSdMmcUhsSignaling: + if (PhaseData == NULL) { + return EFI_INVALID_PARAMETER; + } + + Timing = (SD_MMC_BUS_MODE *)PhaseData; + if (*Timing == SdMmcMmcHs400) { + /* HS400 uses a non-standard setting */ + MmioOr16((UINT32) SD_MMC_HC_HOST_CTRL2, HOST_CTRL2_HS400); + } + break; + + case EdkiiSdMmcSwitchClockFreqPost: + if (PhaseData == NULL) { + return EFI_INVALID_PARAMETER; + } + + Timing = (SD_MMC_BUS_MODE *)PhaseData; + switch (*Timing) { + case SdMmcMmcHs400: + case SdMmcMmcHs200: + MaxClockFreq = 200000000UL; + break; + case SdMmcMmcHsSdr: + case SdMmcMmcHsDdr: + MaxClockFreq = 52000000UL; + break; + default: + MaxClockFreq = 26000000UL; + break; + } + + DwcSdhciSetClockRate (MaxClockFreq); + + if (MaxClockFreq <= 52000000UL) { + MmioWrite32 (EMMC_DLL_CTRL, 0); + MmioWrite32 (EMMC_DLL_RXCLK, 0); + MmioWrite32 (EMMC_DLL_TXCLK, 0); + MmioWrite32 (EMMC_DLL_CMDOUT, 0); + MmioWrite32 (EMMC_DLL_STRBIN, EMMC_DLL_DLYENA | + EMMC_DLL_STRBIN_DELAY_NUM_SEL | + EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT << EMMC_DLL_STRBIN_DELAY_NUM_OFFSET); + break; + } + + /* Switch to eMMC mode */ + MmioOr32 (EMMC_EMMC_CTRL, EMMC_CTRL_CARD_IS_EMMC); + + MmioWrite32(EMMC_DLL_CTRL, EMMC_DLL_CTRL_SRST); + gBS->Stall (1); + MmioWrite32(EMMC_DLL_CTRL, 0); + + MmioWrite32(EMMC_DLL_CTRL, EMMC_DLL_CTRL_START_POINT_DEFAULT | + EMMC_DLL_CTRL_INCREMENT_DEFAULT | EMMC_DLL_CTRL_START); + + for (i = 0; i < 500; i++) { + Value = MmioRead32(EMMC_DLL_STATUS0); + if (Value & EMMC_DLL_STATUS0_DLL_LOCK && + !(Value & EMMC_DLL_STATUS0_DLL_TIMEOUT)) { + break; + } + gBS->Stall (1); + } + + TxClkTapNum = EMMC_DLL_TXCLK_TAPNUM_DEFAULT; + + if (*Timing == SdMmcMmcHs400) { + TxClkTapNum = EMMC_DLL_TXCLK_TAPNUM_90_DEGREES; + + MmioWrite32 (EMMC_DLL_CMDOUT, EMMC_DLL_CMDOUT_SRC_CLK_NEG | + EMMC_DLL_CMDOUT_EN_SRC_CLK_NEG | + EMMC_DLL_DLYENA | + EMMC_DLL_CMDOUT_TAPNUM_90_DEGREES | + EMMC_DLL_TAPNUM_FROM_SW); + } + + MmioWrite32(EMMC_DLL_RXCLK, EMMC_DLL_DLYENA); + + MmioWrite32(EMMC_DLL_TXCLK, EMMC_DLL_DLYENA | + TxClkTapNum | EMMC_DLL_TAPNUM_FROM_SW | + EMMC_DLL_NO_INVERTER); + + MmioWrite32(EMMC_DLL_STRBIN, EMMC_DLL_DLYENA | + EMMC_DLL_STRBIN_TAPNUM_DEFAULT | EMMC_DLL_TAPNUM_FROM_SW); + break; + + default: + break; + } + return EFI_SUCCESS; +} + +STATIC EDKII_SD_MMC_OVERRIDE mSdMmcOverride = { + EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION, + EmmcSdMmcCapability, + EmmcSdMmcNotifyPhase, +}; + +EFI_STATUS +EFIAPI +DwcSdhciDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + DEBUG ((DEBUG_BLKIO, "%a\n", __FUNCTION__)); + + /* Start card on 375 kHz */ + DwcSdhciSetClockRate (375000UL); + + /* Configure pins */ + DwcSdhciSetIoMux (); + + /* Disable Command Conflict Check */ + MmioWrite32 (EMMC_HOST_CTRL3, 0); + + /* Disable DLL for identification */ + MmioWrite32 (EMMC_DLL_CTRL, 0); + MmioWrite32 (EMMC_DLL_RXCLK, 0); + MmioWrite32 (EMMC_DLL_TXCLK, 0); + MmioWrite32 (EMMC_DLL_STRBIN, 0); + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeSdhci, + NonDiscoverableDeviceDmaTypeNonCoherent, + NULL, + &mSdMmcControllerHandle, + 1, + DWC_SDHCI_BASE, 0x10000); + ASSERT_EFI_ERROR (Status); + + Handle = NULL; + Status = gBS->InstallProtocolInterface (&Handle, + &gEdkiiSdMmcOverrideProtocolGuid, + EFI_NATIVE_INTERFACE, (VOID **)&mSdMmcOverride); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.h new file mode 100644 index 0000000..b0b8b02 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.h @@ -0,0 +1,97 @@ +/** @file + * + * Synopsys DesignWare Cores SDHCI eMMC driver + * + * Copyright (c) 2022, Patrick Wildt + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __DWCSDHCIDXE_H__ +#define __DWCSDHCIDXE_H__ + +#define DWC_SDHCI_BASE PcdGet32 (PcdDwcSdhciBaseAddress) + +#define SD_MMC_HC_CLOCK_CTRL (DWC_SDHCI_BASE + 0x2C) +#define SD_MMC_HC_HOST_CTRL2 (DWC_SDHCI_BASE + 0x3E) + +// eMMC Registers +#define EMMC_HOST_CTRL3 (DWC_SDHCI_BASE + 0x508) +#define EMMC_EMMC_CTRL (DWC_SDHCI_BASE + 0x52C) +#define EMMC_DLL_CTRL (DWC_SDHCI_BASE + 0x800) +#define EMMC_DLL_RXCLK (DWC_SDHCI_BASE + 0x804) +#define EMMC_DLL_TXCLK (DWC_SDHCI_BASE + 0x808) +#define EMMC_DLL_STRBIN (DWC_SDHCI_BASE + 0x80C) +#define EMMC_DLL_CMDOUT (DWC_SDHCI_BASE + 0x810) +#define EMMC_DLL_STATUS0 (DWC_SDHCI_BASE + 0x840) +#define EMMC_DLL_STATUS1 (DWC_SDHCI_BASE + 0x844) + +#define CLOCK_CTRL_SDCLK_ENABLE BIT2 + +#define HOST_CTRL2_HS400 (BIT2 | BIT1 | BIT0) + +#define EMMC_CTRL_CARD_IS_EMMC BIT0 + +#define EMMC_DLL_CTRL_SRST BIT1 +#define EMMC_DLL_CTRL_START BIT0 +#define EMMC_DLL_CTRL_START_POINT_DEFAULT (5 << 16) +#define EMMC_DLL_CTRL_INCREMENT_DEFAULT (2 << 8) + +#define EMMC_DLL_NO_INVERTER BIT29 +#define EMMC_DLL_DLYENA BIT27 +#define EMMC_DLL_TAPNUM_FROM_SW BIT24 + +#define EMMC_DLL_TXCLK_TAPNUM_DEFAULT (0x10 << 0) +#define EMMC_DLL_TXCLK_TAPNUM_90_DEGREES 0x9 + +#define EMMC_DLL_STRBIN_TAPNUM_DEFAULT (0x3 << 0) +#define EMMC_DLL_STRBIN_DELAY_NUM_SEL BIT26 +#define EMMC_DLL_STRBIN_DELAY_NUM_OFFSET 16 +#define EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT 0x10 + +#define EMMC_DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 +#define EMMC_DLL_CMDOUT_SRC_CLK_NEG BIT28 +#define EMMC_DLL_CMDOUT_EN_SRC_CLK_NEG BIT29 + +#define EMMC_DLL_STATUS0_DLL_LOCK BIT8 +#define EMMC_DLL_STATUS0_DLL_TIMEOUT BIT9 + +typedef struct { + UINT32 TimeoutFreq : 6; // bit 0:5 + UINT32 Reserved : 1; // bit 6 + UINT32 TimeoutUnit : 1; // bit 7 + UINT32 BaseClkFreq : 8; // bit 8:15 + UINT32 MaxBlkLen : 2; // bit 16:17 + UINT32 BusWidth8 : 1; // bit 18 + UINT32 Adma2 : 1; // bit 19 + UINT32 Reserved2 : 1; // bit 20 + UINT32 HighSpeed : 1; // bit 21 + UINT32 Sdma : 1; // bit 22 + UINT32 SuspRes : 1; // bit 23 + UINT32 Voltage33 : 1; // bit 24 + UINT32 Voltage30 : 1; // bit 25 + UINT32 Voltage18 : 1; // bit 26 + UINT32 SysBus64V4 : 1; // bit 27 + UINT32 SysBus64V3 : 1; // bit 28 + UINT32 AsyncInt : 1; // bit 29 + UINT32 SlotType : 2; // bit 30:31 + UINT32 Sdr50 : 1; // bit 32 + UINT32 Sdr104 : 1; // bit 33 + UINT32 Ddr50 : 1; // bit 34 + UINT32 Reserved3 : 1; // bit 35 + UINT32 DriverTypeA : 1; // bit 36 + UINT32 DriverTypeC : 1; // bit 37 + UINT32 DriverTypeD : 1; // bit 38 + UINT32 DriverType4 : 1; // bit 39 + UINT32 TimerCount : 4; // bit 40:43 + UINT32 Reserved4 : 1; // bit 44 + UINT32 TuningSDR50 : 1; // bit 45 + UINT32 RetuningMod : 2; // bit 46:47 + UINT32 ClkMultiplier : 8; // bit 48:55 + UINT32 Reserved5 : 7; // bit 56:62 + UINT32 Hs400 : 1; // bit 63 +} SD_MMC_HC_SLOT_CAP; + +#endif // __DWCSDHCIDXE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf new file mode 100644 index 0000000..56c5d91 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf @@ -0,0 +1,50 @@ +#/** @file +# +# Synopsys DesignWare Cores SDHCI eMMC driver +# +# Copyright (c) 2014-2017, Linaro Limited. All rights reserved. +# Copyright (c) 2022, Patrick Wildt +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DwcSdhciDxe + FILE_GUID = 4cd3a91b-990e-46a6-b609-9fa5d70d1f5f + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = DwcSdhciDxeInitialize + +[Sources.common] + DwcSdhciDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + IoLib + NonDiscoverableDeviceRegistrationLib + UefiBootServicesTableLib + DwcSdhciPlatformLib + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid ## PRODUCES + gEdkiiSdMmcOverrideProtocolGuid ## PRODUCES + gEfiCpuArchProtocolGuid + gEfiDevicePathProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress + gRockchipTokenSpaceGuid.PcdDwcSdhciForceHighSpeed + gRockchipTokenSpaceGuid.PcdDwcSdhciDisableHs400 + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.c new file mode 100644 index 0000000..6d90461 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.c @@ -0,0 +1,306 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "I2cDemoDxe.h" + +STATIC CONST EFI_GUID I2cGuid = I2C_GUID; + +EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = { + I2cDemoSupported, + I2cDemoStart, + I2cDemoStop +}; + +EFI_STATUS +EFIAPI +I2cDemoSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_UNSUPPORTED; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + UINT8 *I2cDemoAddresses; + UINT8 *I2cDemoBuses; + UINTN i; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "I2cDemoSupported Error status: %d\n", Status)); + return EFI_UNSUPPORTED; + } + + /* get I2CDEMO devices' addresses from PCD */ + I2cDemoAddresses = PcdGetPtr (PcdI2cDemoAddresses); + I2cDemoBuses = PcdGetPtr (PcdI2cDemoBuses); + if (I2cDemoAddresses == 0) { + Status = EFI_UNSUPPORTED; + DEBUG((DEBUG_INFO, "I2cDemoSupported: I2C device found, but it's not I2CDEMO\n")); + goto out; + } + + Status = EFI_UNSUPPORTED; + for (i = 0; I2cDemoAddresses[i] != '\0'; i++) { + /* I2C guid must fit and valid DeviceIndex must be provided */ + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(I2cDemoBuses[i], + I2cDemoAddresses[i])) { + DEBUG ((DEBUG_INFO, "I2cDemoSupported: attached to I2CDEMO device\n")); + Status = EFI_SUCCESS; + break; + } + } + +out: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +I2cDemoRead ( + IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + EFI_STATUS Status = EFI_SUCCESS; + I2CDEMO_CONTEXT *I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(This); + + ASSERT(I2cDemoContext != NULL); + ASSERT(I2cDemoContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2; + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) + return EFI_OUT_OF_RESOURCES; + + RequestPacket->OperationCount = 2; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength; + RequestPacket->Operation[0].Buffer = RegAddress; + + RequestPacket->Operation[1].Flags = I2C_FLAG_READ; + RequestPacket->Operation[1].LengthInBytes = Length; + RequestPacket->Operation[1].Buffer = Buffer; + + Status = I2cDemoContext->I2cIo->QueueRequest(I2cDemoContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR(Status)) + DEBUG((DEBUG_INFO, "I2cDemoTransfer: error %d during transmission\n", Status)); + + FreePool(RequestPacket); + + return Status; +} + +EFI_STATUS +EFIAPI +I2cDemoWrite ( + IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + EFI_STATUS Status = EFI_SUCCESS; + I2CDEMO_CONTEXT *I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(This); + UINT8 *Data; + UINT16 i; + + ASSERT(I2cDemoContext != NULL); + ASSERT(I2cDemoContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION); + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) + return EFI_OUT_OF_RESOURCES; + + Data = AllocateZeroPool ( RegAddressLength + Length ); + if (Data == NULL) + return EFI_OUT_OF_RESOURCES; + + for (i = 0; i < RegAddressLength; i++) + Data[i] = RegAddress[i] & 0xff; + + for (i = RegAddressLength; i < RegAddressLength + Length; i++) + Data[i] = Buffer[i - RegAddressLength] & 0xff; + + RequestPacket->OperationCount = 1; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength + Length; + RequestPacket->Operation[0].Buffer = Data; + + Status = I2cDemoContext->I2cIo->QueueRequest(I2cDemoContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR(Status)) + DEBUG((DEBUG_INFO, "I2cDemoTransfer: error %d during transmission\n", Status)); + + FreePool(Data); + FreePool(RequestPacket); + + return Status; +} + +EFI_STATUS +EFIAPI +I2cDemoStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + I2CDEMO_CONTEXT *I2cDemoContext; + + I2cDemoContext = AllocateZeroPool (sizeof(I2CDEMO_CONTEXT)); + if (I2cDemoContext == NULL) { + DEBUG((DEBUG_ERROR, "I2cDemo: allocation fail\n")); + return EFI_OUT_OF_RESOURCES; + } + + I2cDemoContext->ControllerHandle = ControllerHandle; + I2cDemoContext->Signature = I2CDEMO_SIGNATURE; + I2cDemoContext->I2cDemoProtocol.Read = I2cDemoRead; + I2cDemoContext->I2cDemoProtocol.Write = I2cDemoWrite; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &I2cDemoContext->I2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "I2cDemo: failed to open I2cIo\n")); + FreePool(I2cDemoContext); + return EFI_UNSUPPORTED; + } + + I2cDemoContext->I2cDemoProtocol.Identifier = I2cDemoContext->I2cIo->DeviceIndex; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gRockchipI2cDemoProtocolGuid, &I2cDemoContext->I2cDemoProtocol, + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "I2cDemo: failed to install I2CDEMO protocol\n")); + goto fail; + } + + return Status; + +fail: + FreePool(I2cDemoContext); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +I2cDemoStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + ROCKCHIP_I2CDEMO_PROTOCOL *I2cDemoProtocol; + EFI_STATUS Status; + I2CDEMO_CONTEXT *I2cDemoContext; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gRockchipI2cDemoProtocolGuid, + (VOID **) &I2cDemoProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + I2cDemoContext = I2CDEMO_SC_FROM_I2CDEMO(I2cDemoProtocol); + + gBS->UninstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gRockchipI2cDemoProtocolGuid, &I2cDemoContext->I2cDemoProtocol, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + FreePool(I2cDemoContext); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +I2cDemoInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.h new file mode 100644 index 0000000..6b7f235 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.h @@ -0,0 +1,76 @@ +/******************************************************************************** +Copyright (c) 2021, Rockchip Limited. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +#ifndef __I2CDEMO_H__ +#define __I2CDEMO_H__ + +#include + +#define I2CDEMO_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'D') + +#define MAX_BUFFER_LENGTH 64 + +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +typedef struct { + UINT32 Signature; + EFI_HANDLE ControllerHandle; + EFI_I2C_IO_PROTOCOL *I2cIo; + ROCKCHIP_I2CDEMO_PROTOCOL I2cDemoProtocol; +} I2CDEMO_CONTEXT; + +#define I2CDEMO_SC_FROM_IO(a) CR (a, I2CDEMO_CONTEXT, I2cIo, I2CDEMO_SIGNATURE) +#define I2CDEMO_SC_FROM_I2CDEMO(a) CR (a, I2CDEMO_CONTEXT, I2cDemoProtocol, I2CDEMO_SIGNATURE) + +EFI_STATUS +EFIAPI +I2cDemoSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +I2cDemoStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +I2cDemoStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +EFI_STATUS +EFIAPI +I2cDemoRead ( + IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ); + +EFI_STATUS +EFIAPI +I2cDemoWrite ( + IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ); +#endif // __I2CDEMO_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf new file mode 100644 index 0000000..5681a14 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf @@ -0,0 +1,43 @@ +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = I2cDemoDxe + FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509c + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = I2cDemoInitialise + +[Sources.common] + I2cDemoDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiDriverBindingProtocolGuid + gEfiI2cIoProtocolGuid + gRockchipI2cDemoProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdI2cDemoAddresses + gRockchipTokenSpaceGuid.PcdI2cDemoBuses + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c new file mode 100644 index 0000000..e8dbddf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.c @@ -0,0 +1,1036 @@ +/** @file + * + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "I2cDxe.h" + +#define RK_I2C_DUMPREG 1 + +STATIC CONST I2C_SPEC_VALUES StandardModeSpec = { + .MinLowNs = 4700, + .MinHighNs = 4000, + .MaxRiseNs = 1000, + .MaxFallNs = 300, +}; + +STATIC CONST I2C_SPEC_VALUES FastModeSpec = { + .MinLowNs = 1300, + .MinHighNs = 600, + .MaxRiseNs = 300, + .MaxFallNs = 300, +}; + +STATIC CONST I2C_SPEC_VALUES FastModeplusSpec = { + .MinLowNs = 500, + .MinHighNs = 260, + .MaxRiseNs = 120, + .MaxFallNs = 120, +}; + +STATIC I2C_DEVICE_PATH I2cDevicePathProtocol = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(OFFSET_OF (I2C_DEVICE_PATH, End)), + (UINT8)(OFFSET_OF (I2C_DEVICE_PATH, End) >> 8), + }, + }, + EFI_CALLER_ID_GUID + }, + 0, // Instance + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +STATIC +CONST I2C_SPEC_VALUES * +I2cGetSpec ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Speed + ) +{ + if (Speed == 1000) + return &FastModeplusSpec; + else if (Speed == 400) + return &FastModeSpec; + else + return &StandardModeSpec; +} + +STATIC +UINT32 +I2cRead ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN Off + ) +{ + ASSERT (I2cMasterContext != NULL); + return MmioRead32 (I2cMasterContext->BaseAddress + Off); +} + +STATIC +EFI_STATUS +I2cWrite ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN Off, + IN UINT32 Value + ) +{ + ASSERT (I2cMasterContext != NULL); + return MmioWrite32 (I2cMasterContext->BaseAddress + Off, Value); +} + +STATIC +VOID +I2cShowRegs ( + IN I2C_MASTER_CONTEXT *I2cMasterContex + ) +{ +#if RK_I2C_DUMPREG + UINTN i; + + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_con: 0x%08x\n", I2cRead(I2cMasterContex, I2C_CON))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_clkdiv: 0x%08x\n", I2cRead(I2cMasterContex, I2C_CLKDIV))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_mrxaddr: 0x%08x\n", I2cRead(I2cMasterContex, I2C_MRXADDR))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_mrxraddR: 0x%08x\n", I2cRead(I2cMasterContex, I2C_MRXRADDR))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_mtxcnt: 0x%08x\n", I2cRead(I2cMasterContex, I2C_MTXCNT))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_mrxcnt: 0x%08x\n", I2cRead(I2cMasterContex, I2C_MRXCNT))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_ien: 0x%08x\n", I2cRead(I2cMasterContex, I2C_IEN))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_ipd: 0x%08x\n", I2cRead(I2cMasterContex, I2C_IPD))); + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_fcnt: 0x%08x\n", I2cRead(I2cMasterContex, I2C_FCNT))); + for (i = 0; i < 8; i++) + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_txdata%d: 0x%08x\n", i, I2cRead(I2cMasterContex, I2C_TXDATA_BASE + 4 * i))); + for (i = 0; i < 8; i++) + DEBUG((DEBUG_INFO | DEBUG_LOAD, "i2c_rxdata%d: 0x%08x\n", i, I2cRead(I2cMasterContex,I2C_RXDATA_BASE + 4 * i))); +#endif +} + +STATIC +I2C_VERSION +I2cGetVersion( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ) +{ + I2C_VERSION Version; + + Version = I2cRead(I2cMasterContext, I2C_CON) & I2C_CON_VERSION; + return Version >>= I2C_CON_VERSION_SHIFT; +} + +STATIC +VOID +EFIAPI +I2cVirtualAddressChangeNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + I2C_MASTER_CONTEXT *I2cMasterContext = Context; + + EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->BaseAddress); + EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.SetBusFrequency); + EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.Reset); + EfiConvertPointer (0x0, (VOID **) &I2cMasterContext->I2cMaster.StartRequest); +} + +EFI_STATUS +EFIAPI +I2cInitialiseController ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT32 BusId, + IN BOOLEAN RuntimeSupport + ) +{ + EFI_STATUS Status; + I2C_MASTER_CONTEXT *I2cMasterContext; + I2C_DEVICE_PATH *DevicePath; + EFI_EVENT VirtualAddressChangeEvent = NULL; + + DEBUG ((DEBUG_VERBOSE, "I2cInitialiseController\n")); + DevicePath = AllocateCopyPool (sizeof(I2cDevicePathProtocol), + &I2cDevicePathProtocol); + if (DevicePath == NULL) { + DEBUG((DEBUG_ERROR, "I2cDxe: I2C device path allocation failed\n")); + return EFI_OUT_OF_RESOURCES; + } + DevicePath->Instance = BusId; + + if (RuntimeSupport) { + I2cMasterContext = AllocateRuntimeZeroPool (sizeof (I2C_MASTER_CONTEXT)); + } else { + I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT)); + } + + if (I2cMasterContext == NULL) { + DEBUG((DEBUG_ERROR, "I2cDxe: I2C master context allocation failed\n")); + return EFI_OUT_OF_RESOURCES; + } + I2cMasterContext->Signature = I2C_MASTER_SIGNATURE; + I2cMasterContext->I2cMaster.SetBusFrequency = I2cSetBusFrequency; + I2cMasterContext->I2cMaster.Reset = I2cReset; + I2cMasterContext->I2cMaster.StartRequest = I2cStartRequest; + I2cMasterContext->I2cEnumerate.Enumerate = I2cEnumerate; + I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = I2cEnableConf; + I2cMasterContext->RockchipI2cMaster.Bus = BusId; + I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency); + I2cMasterContext->BaseAddress = BaseAddress; + I2cMasterContext->Bus = BusId; + I2cMasterContext->RuntimeSupport = RuntimeSupport; + + if (RuntimeSupport) { + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + BaseAddress, + I2C_PERIPHERAL_SIZE, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: AddMemorySpace failed. Status=%r\n", + __FUNCTION__, Status)); + goto fail; + } + + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + I2C_PERIPHERAL_SIZE, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: SetMemorySpaceAttributes failed. Status=%r\n", + __FUNCTION__, Status)); + goto fail; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + I2cVirtualAddressChangeNotify, + I2cMasterContext, + &gEfiEventVirtualAddressChangeGuid, + &VirtualAddressChangeEvent); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to register for virtual address change. Status=%r\n", + __FUNCTION__, Status)); + goto fail; + } + } + + if (I2cGetVersion(I2cMasterContext) >= RkI2cVersion1) { + I2cAdapterBaudRate(I2cMasterContext, + PcdGet32 (PcdI2cBaudRate), + I2cMasterContext->TclkFrequency + ); + } else { + I2cCalBaudRate(I2cMasterContext, + PcdGet32 (PcdI2cBaudRate), + I2cMasterContext->TclkFrequency + ); + } + + Status = gBS->InstallMultipleProtocolInterfaces( + &I2cMasterContext->Controller, + &gEfiI2cMasterProtocolGuid, + &I2cMasterContext->I2cMaster, + &gEfiI2cEnumerateProtocolGuid, + &I2cMasterContext->I2cEnumerate, + &gEfiI2cBusConfigurationManagementProtocolGuid, + &I2cMasterContext->I2cBusConf, + &gRockchipI2cMasterProtocolGuid, + &I2cMasterContext->RockchipI2cMaster, + &gEfiDevicePathProtocolGuid, + (EFI_DEVICE_PATH_PROTOCOL *) DevicePath, + NULL); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "I2cDxe: Installing protocol interfaces failed!\n")); + goto fail; + } + + DEBUG ((DEBUG_INFO, "Succesfully installed controller %d at 0x%llx\n", BusId, I2cMasterContext->BaseAddress)); + return EFI_SUCCESS; + +fail: + if (VirtualAddressChangeEvent && RuntimeSupport) { + gBS->CloseEvent (VirtualAddressChangeEvent); + } + + FreePool(I2cMasterContext); + return Status; +} + +STATIC +VOID +EFIAPI +OnEndOfDxe ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + UINTN Index; + + gBS->CloseEvent (Event); + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiI2cMasterProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_WARN, "%a: Couldn't locate gEfiI2cMasterProtocolGuid. Status=%r\n", + __func__, Status)); + return; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->ConnectController (Handles[Index], NULL, NULL, TRUE); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: ConnectController () failed. Status=%r\n", + __func__, Status)); + } + } + + gBS->FreePool (Handles); +} + +EFI_STATUS +EFIAPI +I2cInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_EVENT EndOfDxeEvent; + UINT8 *DeviceBusPcd; + UINT32 DeviceBusCount; + UINT8 *BusRuntimeSupport; + EFI_STATUS Status; + UINTN Index; + BOOLEAN ConfiguredBuses[I2C_COUNT] = {0}; + + DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses); + DeviceBusCount = PcdGetSize (PcdI2cSlaveBuses); + BusRuntimeSupport = PcdGetPtr (PcdI2cSlaveBusesRuntimeSupport); + + /* Initialize enabled chips */ + for (Index = 0; Index < DeviceBusCount; Index++) { + if (DeviceBusPcd[Index] > I2C_COUNT - 1) { + DEBUG ((DEBUG_WARN, "I2cInitialise: invalid bus %d for DeviceBusPcd index %d. Skipping.\n", + DeviceBusPcd[Index], Index)); + continue; + } + + // + // PcdI2cSlaveBuses is used to map devices to their corresponding bus, + // which means we will be looping over duplicate entries when there's + // more than one device on a bus. Don't reinitialize in this case. + // + if (ConfiguredBuses[DeviceBusPcd[Index]]) { + DEBUG ((DEBUG_VERBOSE, "%a: Bus %d already configured. Skipping.\n", + __FUNCTION__, DeviceBusPcd[Index])); + continue; + } + ConfiguredBuses[DeviceBusPcd[Index]] = TRUE; + + BaseAddress = I2C_BASE (DeviceBusPcd[Index]); + + I2cIomux (DeviceBusPcd[Index]); + + Status = I2cInitialiseController( + ImageHandle, + SystemTable, + BaseAddress, + DeviceBusPcd[Index], + BusRuntimeSupport[Index] + ); + + if (EFI_ERROR(Status)) + return Status; + } + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnEndOfDxe, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +STATIC +VOID +I2cCalBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Target, + IN UINT32 ClkRate + ) +{ + int Div, Divl, Divh; + + Div = DIV_ROUND_UP(ClkRate, Target * 8) - 2; + Divh = 0; + Divl = 0; + if (Div >= 0) { + Divl = Div / 2; + if (Div % 2 == 0) + Divh = Div / 2; + else + Divh = DIV_ROUND_UP(Div, 2); + } + + I2cWrite(I2cMasterContext, I2C_CLKDIV, I2C_CLKDIV_VAL(Divl, Divh)); +} + +STATIC +EFI_STATUS +I2cAdapterBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Target, + IN UINT32 ClkRate + ) +{ + CONST I2C_SPEC_VALUES *Spec; + UINT32 MinTotalDiv, MinLowDiv, MinHighDiv, MinHoldDiv; + UINT32 LowDiv, HighDiv, ExtraDiv, ExtraLowDiv; + UINT32 MinLowNs, MinHighNs; + UINT32 StartSetup = 0; + UINT32 Speed; + + if (Target <= 100000 && Target >= 1000) { + StartSetup = 1; + Speed = 100; + } else if (Target <= 400000 && Target >= 100000) { + Speed = 400; + } else if (Target <= 1000000 && Target > 400000) { + Speed = 1000; + } else { + DEBUG ((DEBUG_ERROR, "invalid i2c speed : %d\n", Target)); + return EFI_INVALID_PARAMETER; + } + + Spec = I2cGetSpec(I2cMasterContext, Speed); + ClkRate = DIV_ROUND_UP(ClkRate, 1000); + Speed = DIV_ROUND_UP(Target, 1000); + + MinTotalDiv = DIV_ROUND_UP(ClkRate, Speed * 8); + + MinHighNs = Spec->MaxRiseNs + Spec->MinHighNs; + MinHighDiv = DIV_ROUND_UP(ClkRate * MinHighNs, 8 * 1000000); + + MinLowNs = Spec->MaxFallNs + Spec->MinLowNs; + MinLowDiv = DIV_ROUND_UP(ClkRate * MinLowNs, 8 * 1000000); + + MinHighDiv = (MinHighDiv < 1) ? 2 : MinHighDiv; + MinLowDiv = (MinLowDiv < 1) ? 2 : MinLowDiv; + + MinHoldDiv = MinHighDiv + MinLowDiv; + + if (MinHoldDiv >= MinTotalDiv) { + HighDiv = MinHighDiv; + LowDiv = MinLowDiv; + } else { + ExtraDiv = MinTotalDiv - MinHoldDiv; + ExtraLowDiv = DIV_ROUND_UP(MinLowDiv * ExtraDiv, + MinHoldDiv); + + LowDiv = MinLowDiv + ExtraLowDiv; + HighDiv = MinHighDiv + (ExtraDiv - ExtraLowDiv); + } + + HighDiv--; + LowDiv--; + + if (HighDiv > 0xffff || LowDiv > 0xffff) + return EFI_UNSUPPORTED; + + /* 1 for data hold/setup time is enough */ + I2cMasterContext->Config = I2C_CON_SDA_CFG(1) | I2C_CON_STA_CFG(StartSetup); + I2cWrite(I2cMasterContext, I2C_CLKDIV, (HighDiv << I2C_CLK_DIV_HIGH_SHIFT) | LowDiv); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +I2cSetBusFrequency ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN OUT UINTN *BusClockHertz + ) +{ + // + // Bus frequency is already set in the entry point. + // + // Note that this function is only called by some RTC drivers, + // the I2C I/O upper layer doesn't make any use of it yet. + // + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +I2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ) +{ + DEBUG((DEBUG_VERBOSE, "I2cReset\n")); + return EFI_SUCCESS; +} + +STATIC +VOID +I2cDisable ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ) +{ + DEBUG ((DEBUG_VERBOSE, "I2c I2cDisable.\n")); + + I2cWrite(I2cMasterContext, I2C_IEN, 0); + I2cWrite(I2cMasterContext, I2C_IPD, I2C_IPD_ALL_CLEAN); + I2cWrite(I2cMasterContext, I2C_CON, 0); +} + +/* + * enable and start at same time, Timeout is given in us. + */ +STATIC +EFI_STATUS +I2cStartEnable ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Con, + IN UINTN Timeout + ) +{ + DEBUG ((DEBUG_VERBOSE, "I2cStartEnable\n")); + + I2cWrite(I2cMasterContext, I2C_IPD, I2C_IPD_ALL_CLEAN); + I2cWrite(I2cMasterContext, I2C_IEN, I2C_STARTIEN); + I2cWrite(I2cMasterContext, I2C_CON, I2C_CON_EN | I2C_CON_START | Con |I2cMasterContext->Config); + + while (Timeout--) { + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_STARTIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_STARTIPD); + break; + } + MicroSecondDelay(1); + } + if (Timeout <= 0) { + DEBUG ((DEBUG_ERROR, "I2C Send Start Bit Timeout\n")); + I2cShowRegs(I2cMasterContext); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +I2cStop ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ) +{ + int TimeOut = I2C_READY_TIMEOUT; + + DEBUG ((DEBUG_VERBOSE, "I2c Send Stop bit.\n")); + + I2cWrite(I2cMasterContext, I2C_IPD, I2C_IPD_ALL_CLEAN); + I2cWrite(I2cMasterContext, I2C_CON, I2C_CON_EN | I2C_CON_STOP |I2cMasterContext->Config); + I2cWrite(I2cMasterContext, I2C_IEN, I2C_CON_STOP); + + while (TimeOut--) { + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_STOPIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_STOPIPD); + break; + } + MicroSecondDelay(1); + } + + if (TimeOut <= 0) { + DEBUG ((DEBUG_ERROR, "I2C Send Stop Bit Timeout\n")); + I2cShowRegs(I2cMasterContext); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +I2cReadOperation ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN SlaveAddress, + IN OUT UINT8 *Buf, + IN UINTN Length, + IN OUT UINTN *Read, + IN UINTN Snd, + IN UINTN Timeout + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + int TimeOut = I2C_TIMEOUT_US; + UINT8 *PBuf = Buf; + UINT32 BytesRemainLen = Length; + UINT32 BytesTranferedLen = 0; + UINT32 WordsTranferedLen = 0; + UINT32 Con = 0; + UINT32 RxData; + UINT32 i, j; + UINTN SndChunk = 0; + + DEBUG ((DEBUG_VERBOSE, "I2cRead: base_addr = 0x%x buf = %p, Length = %d\n", + I2cMasterContext->BaseAddress, Buf, Length)); + + /* If the second message for TRX read, resetting internal state. */ + if (Snd) { + I2cWrite(I2cMasterContext, I2C_CON, 0); + } + + I2cWrite(I2cMasterContext, I2C_MRXADDR, I2C_MRXADDR_SET(1, SlaveAddress << 1 | 1)); + + (*Read) = 0; + while (BytesRemainLen) { + if (BytesRemainLen > RK_I2C_FIFO_SIZE) { + Con = I2C_CON_EN; + BytesTranferedLen = 32; + } else { + /* + * The hw can read up to 32 bytes at a time. If we need + * more than one chunk, send an ACK after the last byte. + */ + Con = I2C_CON_EN | I2C_CON_LASTACK; + BytesTranferedLen = BytesRemainLen; + } + WordsTranferedLen = DIV_ROUND_UP(BytesTranferedLen, 4); + + /* + * make sure we are in plain RX mode if we read a second chunk; + * and first rx read need to send start bit. + */ + if (SndChunk) { + Con |= I2C_CON_MOD(I2C_MODE_RX); + I2cWrite(I2cMasterContext, I2C_CON, Con | I2cMasterContext->Config); + } else { + Con |= I2C_CON_MOD(I2C_MODE_TRX); + Status = I2cStartEnable(I2cMasterContext, Con, I2C_TIMEOUT_US); + if (EFI_ERROR(Status)) + goto out; + } + + I2cWrite(I2cMasterContext, I2C_IEN, I2C_MBRFIEN | I2C_NAKRCVIEN); + I2cWrite(I2cMasterContext, I2C_MRXCNT, BytesTranferedLen); + + while (TimeOut--) { + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_NAKRCVIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_NAKRCVIPD); + Status = EFI_NO_RESPONSE; + goto out; + } + + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_MBRFIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_MBRFIPD); + break; + } + MicroSecondDelay(1); + } + + if (TimeOut <= 0) { + DEBUG ((DEBUG_ERROR, "I2C Read Data Timeout\n")); + I2cShowRegs(I2cMasterContext); + Status = EFI_TIMEOUT; + goto out; + } + + for (i = 0; i < WordsTranferedLen; i++) { + RxData = I2cRead(I2cMasterContext, I2C_RXDATA_BASE + i * 4); + DEBUG ((DEBUG_VERBOSE, "I2c Read RXDATA[%d] = 0x%x\n", i, RxData)); + for (j = 0; j < 4; j++) { + if ((i * 4 + j) == BytesTranferedLen) { + break; + } + *PBuf++ = (RxData >> (j * 8)) & 0xff; + } + } + BytesRemainLen -= BytesTranferedLen; + SndChunk = 1; + (*Read) = BytesTranferedLen; + } + + Status = EFI_SUCCESS; + (*Read) = Length; + +out: + return (Status); +} + +STATIC +EFI_STATUS +I2cWriteOperation ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN SlaveAddress, + IN OUT CONST UINT8 *Buf, + IN UINTN Length, + IN OUT UINTN *Sent, + IN UINTN Timeout + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + int TimeOut = I2C_TIMEOUT_US; + CONST UINT8 *PBuf = Buf; + UINT32 BytesRemainLen = Length + 1; + UINT32 BytesTranferedLen = 0; + UINT32 WordsTranferedLen = 0; + UINT32 TxData; + UINT32 i, j; + UINTN Next = 0; + + DEBUG ((DEBUG_VERBOSE, "I2cWrite: base_addr = 0x%x buf = %p, Length = %d\n", + I2cMasterContext->BaseAddress, Buf, Length)); + + (*Sent) = 0; + + while (BytesRemainLen) { + if (BytesRemainLen > RK_I2C_FIFO_SIZE) { + BytesTranferedLen = 32; + } else { + BytesTranferedLen = BytesRemainLen; + } + WordsTranferedLen = DIV_ROUND_UP(BytesTranferedLen, 4); + + for (i = 0; i < WordsTranferedLen; i++) { + TxData = 0; + for (j = 0; j < 4; j++) { + if ((i * 4 + j) == BytesTranferedLen) { + break; + } + + if (i == 0 && j == 0 && PBuf == Buf) { + TxData |= (SlaveAddress << 1); + } else { + TxData |= (*PBuf++)<<(j * 8); + } + } + I2cWrite(I2cMasterContext, I2C_TXDATA_BASE + i * 4, TxData); + DEBUG ((DEBUG_VERBOSE, "I2c Write TXDATA[%d] = 0x%x\n", i, TxData)); + } + + /* If the write is the first, need to send start bit */ + if (!Next) { + Status = I2cStartEnable(I2cMasterContext, I2C_CON_EN | + I2C_CON_MOD(I2C_MODE_TX), I2C_TIMEOUT_US); + if (EFI_ERROR(Status)) { + goto out; + } + Next = 1; + } else { + I2cWrite(I2cMasterContext, I2C_CON, I2C_CON_EN | + I2C_CON_MOD(I2C_MODE_TX) | I2cMasterContext->Config); + } + + I2cWrite(I2cMasterContext, I2C_IEN, I2C_MBTFIEN | I2C_NAKRCVIEN); + I2cWrite(I2cMasterContext, I2C_MTXCNT, BytesTranferedLen); + + while (TimeOut--) { + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_NAKRCVIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_NAKRCVIPD); + Status = EFI_NO_RESPONSE; + goto out; + } + if (I2cRead(I2cMasterContext, I2C_IPD) & I2C_MBTFIPD) { + I2cWrite(I2cMasterContext, I2C_IPD, I2C_MBTFIPD); + break; + } + MicroSecondDelay(1); + } + + if (TimeOut <= 0) { + DEBUG ((DEBUG_ERROR, "I2C Write Data Timeout\n")); + I2cShowRegs(I2cMasterContext); + Status = EFI_TIMEOUT; + goto out; + } + + BytesRemainLen -= BytesTranferedLen; + (*Sent) = BytesTranferedLen; + } + + (*Sent) = Length; + Status = EFI_SUCCESS; +out: + return (Status); +} + + +/* + * I2cStartRequest should be called only by I2cHost. + * I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead. + */ +STATIC +EFI_STATUS +I2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ) +{ + UINTN Count = RequestPacket->OperationCount; + UINTN ReadMode; + UINTN Transmitted; + I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This); + EFI_I2C_OPERATION *Operation; + EFI_STATUS Status = EFI_SUCCESS; + UINTN i; + BOOLEAN AtRuntime; + EFI_TPL Tpl; + + ASSERT (RequestPacket != NULL); + ASSERT (I2cMasterContext != NULL); + + AtRuntime = EfiAtRuntime (); + + // Events do not fire at runtime, so we can't support asynchronous requests. + if (AtRuntime && Event != NULL) { + return EFI_UNSUPPORTED; + } + + DEBUG ((DEBUG_VERBOSE, "I2cStartRequest.\n")); + + if (!AtRuntime) { + // Disable (timer) interrupts. + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + } else if (I2cMasterContext->RuntimeSupport) { + // + // TO-DO: + // Implement some synchronization mechanism between this code path + // and the HLOS I2C driver, to prevent a race condition. + // + // See: https://github.com/edk2-porting/edk2-rk3588/issues/70 + // + } + + if (Count > 2 || ((Count == 2) && (RequestPacket->Operation->Flags & I2C_FLAG_READ))) { + DEBUG ((DEBUG_VERBOSE, "Not support more messages now, split them\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < Count; i++) { + Operation = &RequestPacket->Operation[i]; + ReadMode = Operation->Flags & I2C_FLAG_READ; + + if (Operation->Flags & I2C_FLAG_READ) { + /* If snd is true, it is TRX mode. */ + Status = I2cReadOperation ( I2cMasterContext, + SlaveAddress, + Operation->Buffer, + Operation->LengthInBytes, + &Transmitted, + i == 1, + I2C_TRANSFER_TIMEOUT); + Operation->LengthInBytes = Transmitted; + } else { + Status = I2cWriteOperation ( I2cMasterContext, + SlaveAddress, + Operation->Buffer, + Operation->LengthInBytes, + &Transmitted, + I2C_TRANSFER_TIMEOUT); + Operation->LengthInBytes = Transmitted; + } + + /* I2C transaction was aborted, so stop further transactions */ + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "I2cStartRequest: Failed at Count = %d\n", Count)); + break; + } + } + + I2cStop (I2cMasterContext); + I2cDisable (I2cMasterContext); + + if (!AtRuntime) { + gBS->RestoreTPL (Tpl); + } else if (I2cMasterContext->RuntimeSupport) { + // TO-DO: See above. + } + + if (I2cStatus != NULL) + *I2cStatus = EFI_SUCCESS; + if (Event != NULL) + gBS->SignalEvent(Event); + return EFI_SUCCESS; +} + +STATIC CONST EFI_GUID DevGuid = I2C_GUID; + +STATIC +EFI_STATUS +I2cAllocDevice ( + IN UINT8 SlaveAddress, + IN UINT8 Bus, + IN OUT CONST EFI_I2C_DEVICE **Device + ) +{ + EFI_STATUS Status; + EFI_I2C_DEVICE *Dev; + UINT32 *TmpSlaveArray; + EFI_GUID *TmpGuidP; + + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(EFI_I2C_DEVICE), + (VOID **) &Dev ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "I2cDxe: I2C device memory allocation failed\n")); + return Status; + } + *Device = Dev; + Dev->DeviceIndex = SlaveAddress; + Dev->DeviceIndex = I2C_DEVICE_INDEX(Bus, SlaveAddress); + Dev->SlaveAddressCount = 1; + Dev->I2cBusConfiguration = 0; + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(UINT32), + (VOID **) &TmpSlaveArray); + if (EFI_ERROR(Status)) { + goto fail1; + } + TmpSlaveArray[0] = SlaveAddress; + Dev->SlaveAddressArray = TmpSlaveArray; + + Status = gBS->AllocatePool ( EfiBootServicesData, + sizeof(EFI_GUID), + (VOID **) &TmpGuidP); + if (EFI_ERROR(Status)) { + goto fail2; + } + *TmpGuidP = DevGuid; + Dev->DeviceGuid = TmpGuidP; + + return EFI_SUCCESS; + +fail2: + FreePool(TmpSlaveArray); +fail1: + FreePool(Dev); + + return Status; +} + +/* + * It is called by I2cBus to enumerate devices on I2C bus. In this case, + * enumeration is based on PCD configuration - all Slave addresses specified + * in PCD get their corresponding EFI_I2C_DEVICE structures here. + * + * After enumeration succeeds, Supported() function of drivers that installed + * DriverBinding protocol is called. + */ +STATIC +EFI_STATUS +EFIAPI +I2cEnumerate ( + IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, + IN OUT CONST EFI_I2C_DEVICE **Device + ) +{ + UINT8 *DevicesPcd; + UINT8 *DeviceBusPcd; + UINTN Index, NextIndex, DevCount; + UINT8 NextDeviceAddress; + I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_ENUMERATE(This); + + DevCount = PcdGetSize (PcdI2cSlaveAddresses); + DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses); + DeviceBusPcd = PcdGetPtr (PcdI2cSlaveBuses); + if (*Device == NULL) { + for (Index = 0; Index < DevCount ; Index++) { + if (DeviceBusPcd[Index] != I2cMasterContext->Bus) + continue; + if (Index < DevCount) + I2cAllocDevice (DevicesPcd[Index], I2cMasterContext->Bus, Device); + + return EFI_SUCCESS; + } + } else { + /* Device is not NULL, so something was already allocated */ + for (Index = 0; Index < DevCount; Index++) { + if (DeviceBusPcd[Index] != I2cMasterContext->Bus) + continue; + if (DevicesPcd[Index] == I2C_DEVICE_ADDRESS((*Device)->DeviceIndex)) { + for (NextIndex = Index + 1; NextIndex < DevCount; NextIndex++) { + if (DeviceBusPcd[NextIndex] != I2cMasterContext->Bus) + continue; + NextDeviceAddress = DevicesPcd[NextIndex]; + if (NextIndex < DevCount) + I2cAllocDevice(NextDeviceAddress, I2cMasterContext->Bus, Device); + + return EFI_SUCCESS; + } + } + } + *Device = NULL; + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +I2cEnableConf ( + IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This, + IN UINTN I2cBusConfiguration, + IN EFI_EVENT Event OPTIONAL, + IN EFI_STATUS *I2cStatus OPTIONAL + ) +{ + /* do nothing */ + if (I2cStatus != NULL) + I2cStatus = EFI_SUCCESS; + if (Event != NULL) + gBS->SignalEvent(Event); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h new file mode 100644 index 0000000..c0f7f12 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.h @@ -0,0 +1,327 @@ +/** @file + * + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK_I2C_DXE_H__ +#define __RK_I2C_DXE_H__ + +#include + +#define I2C_PERIPHERAL_SIZE 0x1000 + +#define I2C_SLAVE_ADDR 0x00 +#define I2C_EXT_SLAVE_ADDR 0x10 +#define I2C_DATA 0x04 + +#define I2C_CONTROL 0x08 +#define I2C_CONTROL_ACK (1 << 2) +#define I2C_CONTROL_IFLG (1 << 3) +#define I2C_CONTROL_STOP (1 << 4) +#define I2C_CONTROL_START (1 << 5) +#define I2C_CONTROL_I2CEN (1 << 6) +#define I2C_CONTROL_INTEN (1 << 7) + +#define I2C_STATUS 0x0c +#define I2C_STATUS_START 0x08 +#define I2C_STATUS_RPTD_START 0x10 +#define I2C_STATUS_ADDR_W_ACK 0x18 +#define I2C_STATUS_DATA_WR_ACK 0x28 +#define I2C_STATUS_ADDR_R_ACK 0x40 +#define I2C_STATUS_DATA_RD_ACK 0x50 +#define I2C_STATUS_DATA_RD_NOACK 0x58 + +#define I2C_BAUD_RATE_REG 0x0c +#define I2C_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) +#define I2C_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) +#define I2C_M_FROM_BAUD(baud) (((baud) >> 3) & 0xf) +#define I2C_N_FROM_BAUD(baud) ((baud) & 0x7) + +#define I2C_SOFT_RESET 0x1c +#define I2C_TRANSFER_TIMEOUT 10000 +#define I2C_READY_TIMEOUT 100 + +#define I2C_UNKNOWN 0x0 +#define I2C_SLOW 0x1 +#define I2C_FAST 0x2 +#define I2C_FASTEST 0x3 + +/* rk i2c fifo max transfer bytes */ +#define RK_I2C_FIFO_SIZE 32 + +/* rk i2c device register size */ +#define RK_I2C_REGISTER_SIZE 3 + +/* i2c timerout */ +#define I2C_TIMEOUT_US 100000 // 100000us = 100ms +#define I2C_RETRY_COUNT 3 + +#define I2C_ADAP_SEL_BIT(nr) ((nr) + 11) +#define I2C_ADAP_SEL_MASK(nr) ((nr) + 27) + +#define RK_CEIL(x, y) \ + ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +/* Control register */ +#define I2C_CON 0x000 +#define I2C_CON_EN (1 << 0) +#define I2C_CON_MOD(mod) ((mod) << 1) +#define I2C_MODE_TX 0x00 +#define I2C_MODE_TRX 0x01 +#define I2C_MODE_RX 0x02 +#define I2C_MODE_RRX 0x03 +#define I2C_CON_MASK (3 << 1) + +#define I2C_CON_START (1 << 3) +#define I2C_CON_STOP (1 << 4) +#define I2C_CON_LASTACK (1 << 5) +#define I2C_CON_ACTACK (1 << 6) + +#define I2C_CON_SDA_CFG(cfg) ((cfg) << 8) +#define I2C_CON_STA_CFG(cfg) ((cfg) << 12) +#define I2C_CON_STO_CFG(cfg) ((cfg) << 14 + +#define I2C_CON_VERSION (0xff << 16) +#define I2C_CON_VERSION_SHIFT 16 + +/* Clock dividor register */ +#define I2C_CLKDIV 0x004 +#define I2C_CLK_DIV_HIGH_SHIFT 16 +#define I2C_CLKDIV_VAL(divl, divh) (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000)) + +/* the slave address accessed for master rx mode */ +#define I2C_MRXADDR 0x008 +#define I2C_MRXADDR_SET(vld, addr) (((vld) << 24) | (addr)) + +/* the slave register address accessed for master rx mode */ +#define I2C_MRXRADDR 0x00c +#define I2C_MRXRADDR_SET(vld, raddr) (((vld) << 24) | (raddr)) + +/* master tx count */ +#define I2C_MTXCNT 0x010 + +/* master rx count */ +#define I2C_MRXCNT 0x014 + +/* interrupt enable register */ +#define I2C_IEN 0x018 +#define I2C_BTFIEN (1 << 0) +#define I2C_BRFIEN (1 << 1) +#define I2C_MBTFIEN (1 << 2) +#define I2C_MBRFIEN (1 << 3) +#define I2C_STARTIEN (1 << 4) +#define I2C_STOPIEN (1 << 5) +#define I2C_NAKRCVIEN (1 << 6) + +/* interrupt pending register */ +#define I2C_IPD 0x01c +#define I2C_BTFIPD (1 << 0) +#define I2C_BRFIPD (1 << 1) +#define I2C_MBTFIPD (1 << 2) +#define I2C_MBRFIPD (1 << 3) +#define I2C_STARTIPD (1 << 4) +#define I2C_STOPIPD (1 << 5) +#define I2C_NAKRCVIPD (1 << 6) +#define I2C_IPD_ALL_CLEAN 0x7f + +/* finished count */ +#define I2C_FCNT 0x020 + +/* I2C tx data register */ +#define I2C_TXDATA_BASE 0X100 + +/* I2C rx data register */ +#define I2C_RXDATA_BASE 0x200 + + +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +#define I2C_MASTER_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'M') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Controller; + UINTN TclkFrequency; + UINTN BaseAddress; + INTN Bus; + UINTN Config; + BOOLEAN RuntimeSupport; + EFI_I2C_MASTER_PROTOCOL I2cMaster; + EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate; + EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf; + ROCKCHIP_I2C_MASTER_PROTOCOL RockchipI2cMaster; +} I2C_MASTER_CONTEXT; + +#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE) + +typedef struct { + VENDOR_DEVICE_PATH Guid; + UINTN Instance; + EFI_DEVICE_PATH_PROTOCOL End; +} I2C_DEVICE_PATH; + +typedef struct { + UINT32 MinLowNs; + UINT32 MinHighNs; + UINT32 MaxRiseNs; + UINT32 MaxFallNs; +} I2C_SPEC_VALUES; + +typedef enum { + RkI2cVersion0 = 0, + RkI2cVersion1, + RkI2cVersion5 = 5, +} I2C_VERSION; + +STATIC +UINT32 +I2cRead( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN Off + ); + +STATIC +EFI_STATUS +I2cWrite ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN Off, + IN UINT32 Val + ); + +STATIC +CONST I2C_SPEC_VALUES * +I2cGetSpec ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Speed); + +EFI_STATUS +EFIAPI +I2cInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +STATIC +VOID +I2cCalBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Target, + IN UINT32 ClkRate + ); + +STATIC +EFI_STATUS +I2cAdapterBaudRate ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN CONST UINT32 Target, + IN CONST UINT32 ClkRate + ); + +STATIC +EFI_STATUS +EFIAPI +I2cSetBusFrequency ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN OUT UINTN *BusClockHertz + ); + +EFI_STATUS +EFIAPI +I2cReset ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This + ); + +STATIC +VOID +I2cDisable ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ); + +STATIC +EFI_STATUS +I2cStartEnable ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINT32 Con, + IN UINTN Timeout + ); + +STATIC +EFI_STATUS +I2cStop ( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ); + +STATIC +EFI_STATUS +I2cReadOperation ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN SlaveAddress, + IN OUT UINT8 *buf, + IN UINTN len, + IN OUT UINTN *read, + IN UINTN last, + IN UINTN delay + ); + +STATIC +EFI_STATUS +I2cWriteOperation ( + IN I2C_MASTER_CONTEXT *I2cMasterContext, + IN UINTN SlaveAddress, + IN OUT CONST UINT8 *buf, + IN UINTN len, + IN OUT UINTN *sent, + IN UINTN timeout + ); + +STATIC +EFI_STATUS +EFIAPI +I2cStartRequest ( + IN CONST EFI_I2C_MASTER_PROTOCOL *This, + IN UINTN SlaveAddress, + IN EFI_I2C_REQUEST_PACKET *RequestPacket, + IN EFI_EVENT Event OPTIONAL, + OUT EFI_STATUS *I2cStatus OPTIONAL + ); + +STATIC +EFI_STATUS +EFIAPI +I2cEnumerate ( + IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This, + IN OUT CONST EFI_I2C_DEVICE **Device + ); + +STATIC +EFI_STATUS +EFIAPI +I2cEnableConf ( + IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This, + IN UINTN I2cBusConfiguration, + IN EFI_EVENT Event OPTIONAL, + IN EFI_STATUS *I2cStatus OPTIONAL + ); + +STATIC +I2C_VERSION +I2cGetVersion( + IN I2C_MASTER_CONTEXT *I2cMasterContext + ); + +STATIC +VOID +I2cShowRegs ( + IN I2C_MASTER_CONTEXT *I2cMasterContex + ); + +#endif // __RK_I2C_DXE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf new file mode 100644 index 0000000..1630ee9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf @@ -0,0 +1,61 @@ +#/** @file +# +# Copyright (c) 2021 Rockchip Electronics Co., Ltd. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = I2cDxe + FILE_GUID = 9335a854-4b88-11ec-a8ee-f42a7dcb925d + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = I2cInitialise + +[Sources.common] + I2cDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + IoLib + PcdLib + BaseLib + DebugLib + DxeServicesTableLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeLib + RockchipPlatformLib + TimerLib + +[Protocols] + gEfiI2cMasterProtocolGuid + gEfiDevicePathProtocolGuid + gEfiI2cEnumerateProtocolGuid + gEfiI2cBusConfigurationManagementProtocolGuid + gRockchipI2cMasterProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport + gRockchipTokenSpaceGuid.PcdI2cClockFrequency + gRockchipTokenSpaceGuid.PcdI2cBaudRate + +[Guids] + gEfiEndOfDxeEventGroupGuid + gEfiEventVirtualAddressChangeGuid + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.c new file mode 100644 index 0000000..025cf6b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.c @@ -0,0 +1,546 @@ +/** @file +* +* Copyright (C) 2016 Marvell International Ltd. +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Rk860xRegulatorDxe.h" + +STATIC CONST EFI_GUID I2cGuid = I2C_GUID; + +EFI_DRIVER_BINDING_PROTOCOL gDriverBindingProtocol = { + Rk860xRegulatorSupported, + Rk860xRegulatorStart, + Rk860xRegulatorStop +}; + +EFI_STATUS +EFIAPI +Rk860xRegulatorSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_UNSUPPORTED; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + UINT8 *Rk860xRegulatorAddresses; + UINT8 *Rk860xRegulatorBuses; + UINTN i; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + /* get RK860X_REGULATOR devices' addresses from PCD */ + Rk860xRegulatorAddresses = PcdGetPtr (PcdRk860xRegulatorAddresses); + Rk860xRegulatorBuses = PcdGetPtr (PcdRk860xRegulatorBuses); + if (Rk860xRegulatorAddresses == 0) { + Status = EFI_UNSUPPORTED; + DEBUG((DEBUG_INFO, "Rk860xRegulatorSupported: I2C device found, but it's not RK860X_REGULATOR\n")); + goto out; + } + + Status = EFI_UNSUPPORTED; + for (i = 0; Rk860xRegulatorAddresses[i] != '\0'; i++) { + /* I2C guid must fit and valid DeviceIndex must be provided */ + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(Rk860xRegulatorBuses[i], + Rk860xRegulatorAddresses[i])) { + DEBUG ((DEBUG_INFO, "Rk860xRegulatorSupported: attached to RK860X_REGULATOR device\n")); + Status = EFI_SUCCESS; + break; + } + } + +out: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorRead ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + EFI_STATUS Status = EFI_SUCCESS; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL(This); + + ASSERT(Rk860xRegulatorContext != NULL); + ASSERT(Rk860xRegulatorContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION) * 2; + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) + return EFI_OUT_OF_RESOURCES; + + RequestPacket->OperationCount = 2; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength; + RequestPacket->Operation[0].Buffer = RegAddress; + + RequestPacket->Operation[1].Flags = I2C_FLAG_READ; + RequestPacket->Operation[1].LengthInBytes = Length; + RequestPacket->Operation[1].Buffer = Buffer; + + Status = Rk860xRegulatorContext->I2cIo->QueueRequest(Rk860xRegulatorContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR(Status)) + DEBUG((DEBUG_INFO, "Rk860xRegulatorRead: error %d during transmission\n", Status)); + + FreePool(RequestPacket); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorWrite ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + EFI_STATUS Status = EFI_SUCCESS; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL(This); + UINT8 *Data; + UINT16 i; + + ASSERT(Rk860xRegulatorContext != NULL); + ASSERT(Rk860xRegulatorContext->I2cIo != NULL); + + RequestPacketSize = sizeof(UINTN) + sizeof (EFI_I2C_OPERATION); + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) + return EFI_OUT_OF_RESOURCES; + + Data = AllocateZeroPool ( RegAddressLength + Length ); + if (Data == NULL) + return EFI_OUT_OF_RESOURCES; + + for (i = 0; i < RegAddressLength; i++) + Data[i] = RegAddress[i] & 0xff; + + for (i = RegAddressLength; i < RegAddressLength + Length; i++) + Data[i] = Buffer[i - RegAddressLength] & 0xff; + + RequestPacket->OperationCount = 1; + + RequestPacket->Operation[0].Flags = 0; + RequestPacket->Operation[0].LengthInBytes = RegAddressLength + Length; + RequestPacket->Operation[0].Buffer = Data; + + Status = Rk860xRegulatorContext->I2cIo->QueueRequest(Rk860xRegulatorContext->I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR(Status)) + DEBUG((DEBUG_INFO, "Rk860xRegulatorWrite: error %d during transmission\n", Status)); + + FreePool(Data); + FreePool(RequestPacket); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorReadRegister ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT8 Address, + OUT UINT8 *Value + ) +{ + return Rk860xRegulatorRead(This, &Address, sizeof(UINT8), + Value, sizeof(UINT8)); +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorWriteRegister ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT8 Address, + IN UINT8 Value + ) +{ + return Rk860xRegulatorWrite(This, &Address, sizeof(UINT8), + &Value, sizeof(UINT8)); +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorClearAndSetRegister ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT8 Address, + IN UINT8 Clear, + IN UINT8 Set + ) +{ + UINT8 Value; + EFI_STATUS Status = EFI_SUCCESS; + + Status = Rk860xRegulatorReadRegister(This, Address, &Value); + if (EFI_ERROR(Status)) { + return Status; + } + + Value = (Value & ~Clear) | Set; + + return Rk860xRegulatorWriteRegister(This, Address, Value); +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorGetVoltage ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT UINT32 *Voltage, + IN BOOLEAN Suspend + ) +{ + UINT8 Value; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL (This); + EFI_STATUS Status = EFI_SUCCESS; + + Status = Rk860xRegulatorReadRegister (This, + Suspend ? Rk860xRegulatorContext->Config.SleepReg : Rk860xRegulatorContext->Config.VolReg, + &Value); + if (EFI_ERROR(Status)) { + return Status; + } + + Value &= Rk860xRegulatorContext->Config.VolMask; + *Voltage = (Value * Rk860xRegulatorContext->Config.VselStep) + Rk860xRegulatorContext->Config.VselMin; + + return Status; +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorSetVoltage ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT32 Voltage, + IN BOOLEAN Suspend + ) +{ + UINT8 Value; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL (This); + + Value = (Voltage - Rk860xRegulatorContext->Config.VselMin) / Rk860xRegulatorContext->Config.VselStep; + + return Rk860xRegulatorClearAndSetRegister (This, + Suspend ? Rk860xRegulatorContext->Config.SleepReg : Rk860xRegulatorContext->Config.VolReg, + Rk860xRegulatorContext->Config.VolMask, Value); +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorGetEnable ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT BOOLEAN *Enable, + IN BOOLEAN Suspend + ) +{ + UINT8 Value; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL (This); + EFI_STATUS Status = EFI_SUCCESS; + + Status = Rk860xRegulatorReadRegister (This, + Suspend ? Rk860xRegulatorContext->Config.SleepEnReg : Rk860xRegulatorContext->Config.EnReg, + &Value); + if (EFI_ERROR(Status)) { + return Status; + } + + *Enable = Value & RK860X_VSEL_BUCK_EN; + + return Status; +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorSetEnable ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN BOOLEAN Enable, + IN BOOLEAN Suspend + ) +{ + UINT8 Value; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL (This); + + Value = Enable ? RK860X_VSEL_BUCK_EN : 0; + + return Rk860xRegulatorClearAndSetRegister (This, + Suspend ? Rk860xRegulatorContext->Config.SleepEnReg : Rk860xRegulatorContext->Config.EnReg, + RK860X_VSEL_BUCK_EN, Value); +} + +STATIC +EFI_STATUS +EFIAPI +Rk860xRegulatorInitConfig ( + IN CONST RK860X_REGULATOR_PROTOCOL *This + ) +{ + UINT8 ChipId; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL (This); + EFI_STATUS Status = EFI_SUCCESS; + + Status = Rk860xRegulatorReadRegister (This, RK860X_ID1, &ChipId); + if (EFI_ERROR(Status)) { + return Status; + } + ChipId &= RK860X_DIE_ID_MASK; + + switch (ChipId) { + case RK860X_CHIP_ID_00_01: + Rk860xRegulatorContext->Config.VselMin = 712500; + Rk860xRegulatorContext->Config.VselStep = 12500; + Rk860xRegulatorContext->Config.NumVoltages = RK860X_NVOLTAGES_64; + Rk860xRegulatorContext->Config.VolMask = RK860X_VSEL_A_NSEL_MASK; + Rk860xRegulatorContext->Config.SleepReg = RK860X_VSEL1_A; + Rk860xRegulatorContext->Config.VolReg = RK860X_VSEL0_A; + Rk860xRegulatorContext->Config.EnReg = RK860X_VSEL0_A; + Rk860xRegulatorContext->Config.SleepEnReg = RK860X_VSEL1_A; + break; + case RK860X_CHIP_ID_02_03: + Rk860xRegulatorContext->Config.VselMin = 500000; + Rk860xRegulatorContext->Config.VselStep = 6250; + Rk860xRegulatorContext->Config.NumVoltages = RK860X_NVOLTAGES_160; + Rk860xRegulatorContext->Config.VolMask = RK860X_VSEL_B_NSEL_MASK; + Rk860xRegulatorContext->Config.SleepReg = RK860X_VSEL1_B; + Rk860xRegulatorContext->Config.VolReg = RK860X_VSEL0_B; + Rk860xRegulatorContext->Config.EnReg = RK860X_VSEL0_A; + Rk860xRegulatorContext->Config.SleepEnReg = RK860X_VSEL1_A; + break; + default: + DEBUG((DEBUG_ERROR, "Rk860xRegulatorInitConfig: unsupported chip id %u\n", ChipId)); + return EFI_UNSUPPORTED; + } + + return Status; +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext; + RK860X_REGULATOR_PROTOCOL *Rk860xRegulatorProtocol; + UINT8 *Rk860xRegulatorAddresses; + UINTN Rk860xRegulatorAddressesSize; + UINT8 *Rk860xRegulatorBuses; + UINT8 *Rk860xRegulatorTags; + UINT8 *Rk860xRegulatorMinVoltagesPtr; + UINTN Rk860xRegulatorMinVoltagesSize; + UINT8 *Rk860xRegulatorMaxVoltagesPtr; + UINTN Rk860xRegulatorMaxVoltagesSize; + UINT32 Index; + + Rk860xRegulatorContext = AllocateZeroPool (sizeof(RK860X_REGULATOR_CONTEXT)); + if (Rk860xRegulatorContext == NULL) { + DEBUG((DEBUG_ERROR, "Rk860xRegulator: allocation fail\n")); + return EFI_OUT_OF_RESOURCES; + } + + Rk860xRegulatorProtocol = &Rk860xRegulatorContext->Rk860xRegulatorProtocol; + + Rk860xRegulatorContext->ControllerHandle = ControllerHandle; + Rk860xRegulatorContext->Signature = RK860X_REGULATOR_SIGNATURE; + + Rk860xRegulatorProtocol->GetVoltage = Rk860xRegulatorGetVoltage; + Rk860xRegulatorProtocol->SetVoltage = Rk860xRegulatorSetVoltage; + Rk860xRegulatorProtocol->GetEnable = Rk860xRegulatorGetEnable; + Rk860xRegulatorProtocol->SetEnable = Rk860xRegulatorSetEnable; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &Rk860xRegulatorContext->I2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Rk860xRegulator: failed to open I2cIo\n")); + FreePool(Rk860xRegulatorContext); + return EFI_UNSUPPORTED; + } + + Rk860xRegulatorProtocol->Identifier = Rk860xRegulatorContext->I2cIo->DeviceIndex; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gRk860xRegulatorProtocolGuid, Rk860xRegulatorProtocol, + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Rk860xRegulator: failed to install RK860X_REGULATOR_PROTOCOL\n")); + goto fail; + } + + Status = Rk860xRegulatorInitConfig (Rk860xRegulatorProtocol); + if (EFI_ERROR(Status)) { + goto fail; + } + + Rk860xRegulatorProtocol->SupportedVoltageRange.Min = Rk860xRegulatorContext->Config.VselMin; + Rk860xRegulatorProtocol->SupportedVoltageRange.Max = RK860X_MAX_VOLTAGE; + + Rk860xRegulatorProtocol->PreferredVoltageRange = Rk860xRegulatorProtocol->SupportedVoltageRange; + + Rk860xRegulatorAddresses = PcdGetPtr (PcdRk860xRegulatorAddresses); + Rk860xRegulatorAddressesSize = PcdGetSize (PcdRk860xRegulatorAddresses); + Rk860xRegulatorBuses = PcdGetPtr (PcdRk860xRegulatorBuses); + Rk860xRegulatorTags = PcdGetPtr (PcdRk860xRegulatorTags); + Rk860xRegulatorMinVoltagesPtr = PcdGetPtr (PcdRk860xRegulatorMinVoltages); + Rk860xRegulatorMinVoltagesSize = PcdGetSize (PcdRk860xRegulatorMinVoltages); + Rk860xRegulatorMaxVoltagesPtr = PcdGetPtr (PcdRk860xRegulatorMaxVoltages); + Rk860xRegulatorMaxVoltagesSize = PcdGetSize (PcdRk860xRegulatorMaxVoltages); + + for (Index = 0; Rk860xRegulatorAddresses[Index] != '\0'; Index++) { + if (Rk860xRegulatorContext->I2cIo->DeviceIndex == I2C_DEVICE_INDEX(Rk860xRegulatorBuses[Index], + Rk860xRegulatorAddresses[Index])) { + + Rk860xRegulatorProtocol->Tag = Rk860xRegulatorTags[Index]; + + Index *= sizeof(UINT32); + + if (Rk860xRegulatorMinVoltagesSize / sizeof(UINT32) == Rk860xRegulatorAddressesSize) { + Rk860xRegulatorProtocol->PreferredVoltageRange.Min = Rk860xRegulatorMinVoltagesPtr[Index] | + Rk860xRegulatorMinVoltagesPtr[Index + 1] << 8 | + Rk860xRegulatorMinVoltagesPtr[Index + 2] << 16 | + Rk860xRegulatorMinVoltagesPtr[Index + 3] << 24; + } + if (Rk860xRegulatorMaxVoltagesSize / sizeof(UINT32) == Rk860xRegulatorAddressesSize) { + Rk860xRegulatorProtocol->PreferredVoltageRange.Max = Rk860xRegulatorMaxVoltagesPtr[Index] | + Rk860xRegulatorMaxVoltagesPtr[Index + 1] << 8 | + Rk860xRegulatorMaxVoltagesPtr[Index + 2] << 16 | + Rk860xRegulatorMaxVoltagesPtr[Index + 3] << 24; + } + break; + } + } + return Status; + +fail: + FreePool(Rk860xRegulatorContext); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + RK860X_REGULATOR_PROTOCOL *Rk860xRegulatorProtocol; + EFI_STATUS Status; + RK860X_REGULATOR_CONTEXT *Rk860xRegulatorContext; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gRk860xRegulatorProtocolGuid, + (VOID **) &Rk860xRegulatorProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + Rk860xRegulatorContext = RK860X_REGULATOR_SC_FROM_PROTOCOL(Rk860xRegulatorProtocol); + + gBS->UninstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gRk860xRegulatorProtocolGuid, &Rk860xRegulatorContext->Rk860xRegulatorProtocol, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + FreePool(Rk860xRegulatorContext); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Rk860xRegulatorInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, &gDriverBindingProtocol, + NULL + ); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.h new file mode 100644 index 0000000..f4b610c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.h @@ -0,0 +1,120 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __RK860X_REGULATOR_DXE_H__ +#define __RK860X_REGULATOR_DXE_H__ + +#include + +#define RK860X_REGULATOR_SIGNATURE SIGNATURE_32 ('R', 'K', '8', '6') + +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +typedef struct { + UINT8 VolReg; + UINT8 SleepReg; + UINT8 EnReg; + UINT8 SleepEnReg; + UINT8 VolMask; + UINT16 NumVoltages; + UINT32 VselMin; + UINT32 VselStep; +} RK860X_REGULATOR_CONFIG; + +typedef struct { + UINT32 Signature; + EFI_HANDLE ControllerHandle; + EFI_I2C_IO_PROTOCOL *I2cIo; + RK860X_REGULATOR_PROTOCOL Rk860xRegulatorProtocol; + RK860X_REGULATOR_CONFIG Config; +} RK860X_REGULATOR_CONTEXT; + +#define RK860X_REGULATOR_SC_FROM_IO(a) CR (a, RK860X_REGULATOR_CONTEXT, I2cIo, RK860X_REGULATOR_SIGNATURE) +#define RK860X_REGULATOR_SC_FROM_PROTOCOL(a) CR (a, RK860X_REGULATOR_CONTEXT, Rk860xRegulatorProtocol, RK860X_REGULATOR_SIGNATURE) + +/* Registers & fields */ +#define RK860X_VSEL0_A 0x00 +#define RK860X_VSEL1_A 0x01 +#define RK860X_VSEL0_B 0x06 +#define RK860X_VSEL1_B 0x07 + +#define RK860X_VSEL_BUCK_EN BIT7 +#define RK860X_VSEL_A_NSEL_MASK 0x3F +#define RK860X_VSEL_B_NSEL_MASK 0xff + +#define RK860X_ID1 0x03 +#define RK860X_DIE_ID_MASK 0x0F +#define RK860X_CHIP_ID_00_01 8 +#define RK860X_CHIP_ID_02_03 10 + +#define RK860X_NVOLTAGES_64 64 +#define RK860X_NVOLTAGES_160 160 + +#define RK860X_MAX_VOLTAGE 1500000 + +EFI_STATUS +EFIAPI +Rk860xRegulatorSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorGetVoltage ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT UINT32 *Voltage, + IN BOOLEAN Suspend + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorSetVoltage ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT32 Voltage, + IN BOOLEAN Suspend + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorGetEnable ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT BOOLEAN *Enable, + IN BOOLEAN Suspend + ); + +EFI_STATUS +EFIAPI +Rk860xRegulatorSetEnable ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN BOOLEAN Enable, + IN BOOLEAN Suspend + ); + +#endif // __RK860X_REGULATOR_DXE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf new file mode 100644 index 0000000..b1a9492 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf @@ -0,0 +1,52 @@ +#/** @file +# +# RK860X voltage regulator driver +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Rk860xRegulatorDxe + FILE_GUID = cd5a650e-20e1-47b4-b33a-5e77bf9be42a + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Rk860xRegulatorInitialise + +[Sources.common] + Rk860xRegulatorDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiI2cIoProtocolGuid ## CONSUMES + gEfiDriverBindingProtocolGuid ## PRODUCES + gRk860xRegulatorProtocolGuid ## PRODUCES + +[Pcd] + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMinVoltages + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMaxVoltages + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputBlt.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputBlt.c new file mode 100644 index 0000000..a92f5f8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputBlt.c @@ -0,0 +1,938 @@ +/** @file + + Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "LcdGraphicsOutputDxe.h" + +extern BOOLEAN mDisplayInitialized; + +// +// Function Definitions +// + +STATIC +EFI_STATUS +VideoCopyNoHorizontalOverlap ( + IN UINTN BitsPerPixel, + IN volatile VOID *FrameBufferBase, + IN UINT32 HorizontalResolution, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height +) +{ + EFI_STATUS Status; + UINTN SourceLine; + UINTN DestinationLine; + UINTN WidthInBytes; + UINTN LineCount; + INTN Step; + VOID *SourceAddr; + VOID *DestinationAddr; + + Status = EFI_SUCCESS; + + if( DestinationY <= SourceY ) { + // scrolling up (or horizontally but without overlap) + SourceLine = SourceY; + DestinationLine = DestinationY; + Step = 1; + } else { + // scrolling down + SourceLine = SourceY + Height; + DestinationLine = DestinationY + Height; + Step = -1; + } + + switch (BitsPerPixel) { + + case LcdBitsPerPixel_24: + + WidthInBytes = Width * 4; + + for( LineCount = 0; LineCount < Height; LineCount++ ) { + // Update the start addresses of source & destination using 32bit pointer arithmetic + SourceAddr = (VOID *)((UINT32 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX ); + DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX); + + // Copy the entire line Y from video ram to the temp buffer + CopyMem( DestinationAddr, SourceAddr, WidthInBytes); + + // Update the line numbers + SourceLine += Step; + DestinationLine += Step; + } + break; + + case LcdBitsPerPixel_16_555: + case LcdBitsPerPixel_16_565: + case LcdBitsPerPixel_12_444: + + WidthInBytes = Width * 2; + + for( LineCount = 0; LineCount < Height; LineCount++ ) { + // Update the start addresses of source & destination using 16bit pointer arithmetic + SourceAddr = (VOID *)((UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX ); + DestinationAddr = (VOID *)((UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX); + + // Copy the entire line Y from video ram to the temp buffer + CopyMem( DestinationAddr, SourceAddr, WidthInBytes); + + // Update the line numbers + SourceLine += Step; + DestinationLine += Step; + } + break; + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + default: + // Can't handle this case + DEBUG((DEBUG_ERROR, "ArmVeGraphics_Blt: EfiBltVideoToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel)); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + // break; + + } + + EXIT: + return Status; +} + +STATIC +EFI_STATUS +VideoCopyHorizontalOverlap ( + IN UINTN BitsPerPixel, + IN volatile VOID *FrameBufferBase, + UINT32 HorizontalResolution, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height +) +{ + EFI_STATUS Status; + + UINT32 *PixelBuffer32bit; + UINT32 *SourcePixel32bit; + UINT32 *DestinationPixel32bit; + + UINT16 *PixelBuffer16bit; + UINT16 *SourcePixel16bit; + UINT16 *DestinationPixel16bit; + + UINT32 SourcePixelY; + UINT32 DestinationPixelY; + UINTN SizeIn32Bits; + UINTN SizeIn16Bits; + + Status = EFI_SUCCESS; + + switch (BitsPerPixel) { + + case LcdBitsPerPixel_24: + // Allocate a temporary buffer + + PixelBuffer32bit = (UINT32 *) AllocatePool((Height * Width) * sizeof(UINT32)); + + if (PixelBuffer32bit == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + SizeIn32Bits = Width * 4; + + // Copy from the video ram (source region) to a temp buffer + for (SourcePixelY = SourceY, DestinationPixel32bit = PixelBuffer32bit; + SourcePixelY < SourceY + Height; + SourcePixelY++, DestinationPixel32bit += Width) + { + // Update the start address of line Y (source) + SourcePixel32bit = (UINT32 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX; + + // Copy the entire line Y from video ram to the temp buffer + CopyMem( (VOID *)DestinationPixel32bit, (CONST VOID *)SourcePixel32bit, SizeIn32Bits); + } + + // Copy from the temp buffer to the video ram (destination region) + for (DestinationPixelY = DestinationY, SourcePixel32bit = PixelBuffer32bit; + DestinationPixelY < DestinationY + Height; + DestinationPixelY++, SourcePixel32bit += Width) + { + // Update the start address of line Y (target) + DestinationPixel32bit = (UINT32 *)FrameBufferBase + DestinationPixelY * HorizontalResolution + DestinationX; + + // Copy the entire line Y from the temp buffer to video ram + CopyMem( (VOID *)DestinationPixel32bit, (CONST VOID *)SourcePixel32bit, SizeIn32Bits); + } + + // Free up the allocated memory + FreePool((VOID *) PixelBuffer32bit); + + break; + + + case LcdBitsPerPixel_16_555: + case LcdBitsPerPixel_16_565: + case LcdBitsPerPixel_12_444: + // Allocate a temporary buffer + PixelBuffer16bit = (UINT16 *) AllocatePool((Height * Width) * sizeof(UINT16)); + + if (PixelBuffer16bit == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // Access each pixel inside the source area of the Video Memory and copy it to the temp buffer + + SizeIn16Bits = Width * 2; + + for (SourcePixelY = SourceY, DestinationPixel16bit = PixelBuffer16bit; + SourcePixelY < SourceY + Height; + SourcePixelY++, DestinationPixel16bit += Width) + { + // Calculate the source address: + SourcePixel16bit = (UINT16 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX; + + // Copy the entire line Y from Video to the temp buffer + CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits); + } + + // Copy from the temp buffer into the destination area of the Video Memory + + for (DestinationPixelY = DestinationY, SourcePixel16bit = PixelBuffer16bit; + DestinationPixelY < DestinationY + Height; + DestinationPixelY++, SourcePixel16bit += Width) + { + // Calculate the target address: + DestinationPixel16bit = (UINT16 *)FrameBufferBase + (DestinationPixelY * HorizontalResolution + DestinationX); + + // Copy the entire line Y from the temp buffer to Video + CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits); + } + + // Free the allocated memory + FreePool((VOID *) PixelBuffer16bit); + + break; + + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + default: + // Can't handle this case + DEBUG((DEBUG_ERROR, "ArmVeGraphics_Blt: EfiBltVideoToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel)); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + // break; + + } + +EXIT: + return Status; +} + +STATIC +EFI_STATUS +BltVideoFill ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel, OPTIONAL + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer + ) +{ + EFI_PIXEL_BITMASK* PixelInformation; + EFI_STATUS Status; + UINT32 HorizontalResolution; + LCD_BPP BitsPerPixel; + VOID *FrameBufferBase; + VOID *DestinationAddr; + UINT16 *DestinationPixel16bit; + UINT16 Pixel16bit; + UINT32 DestinationPixelX; + UINT32 DestinationLine; + UINTN WidthInBytes; + + Status = EFI_SUCCESS; + PixelInformation = &This->Mode->Info->PixelInformation; + FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase)); + HorizontalResolution = This->Mode->Info->HorizontalResolution; + + LcdGraphicsGetBpp (This->Mode->Mode, &BitsPerPixel); + + switch (BitsPerPixel) { + case LcdBitsPerPixel_24: + WidthInBytes = Width * 4; + + // Copy the SourcePixel into every pixel inside the target rectangle + for (DestinationLine = DestinationY; + DestinationLine < DestinationY + Height; + DestinationLine++) + { + // Calculate the target address using 32bit pointer arithmetic: + DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX); + + // Fill the entire line + SetMem32 (DestinationAddr, WidthInBytes, *((UINT32 *)EfiSourcePixel)); + } + break; + + case LcdBitsPerPixel_16_555: + // Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel + Pixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red << 7) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green << 2) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask ) +// | ( 0 & PixelInformation->ReservedMask ) + ); + + // Copy the SourcePixel into every pixel inside the target rectangle + for (DestinationLine = DestinationY; + DestinationLine < DestinationY + Height; + DestinationLine++) + { + for (DestinationPixelX = DestinationX; + DestinationPixelX < DestinationX + Width; + DestinationPixelX++) + { + // Calculate the target address: + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + *DestinationPixel16bit = Pixel16bit; + } + } + break; + + case LcdBitsPerPixel_16_565: + // Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel + Pixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red << 8) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green << 3) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask ) + ); + + // Copy the SourcePixel into every pixel inside the target rectangle + for (DestinationLine = DestinationY; + DestinationLine < DestinationY + Height; + DestinationLine++) + { + for (DestinationPixelX = DestinationX; + DestinationPixelX < DestinationX + Width; + DestinationPixelX++) + { + // Calculate the target address: + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + *DestinationPixel16bit = Pixel16bit; + } + } + break; + + case LcdBitsPerPixel_12_444: + // Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel + Pixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red >> 4) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green ) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue << 4) & PixelInformation->BlueMask ) + ); + + // Copy the SourcePixel into every pixel inside the target rectangle + for (DestinationLine = DestinationY; + DestinationLine < DestinationY + Height; + DestinationLine++) + { + for (DestinationPixelX = DestinationX; + DestinationPixelX < DestinationX + Width; + DestinationPixelX++) + { + // Calculate the target address: + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + *DestinationPixel16bit = Pixel16bit; + } + } + break; + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + default: + // Can't handle this case + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltVideoFill: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel)); + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + +STATIC +EFI_STATUS +BltVideoToBltBuffer ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer + ) +{ + EFI_STATUS Status; + UINT32 HorizontalResolution; + LCD_BPP BitsPerPixel; + EFI_PIXEL_BITMASK *PixelInformation; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiDestinationPixel; + VOID *FrameBufferBase; + VOID *SourceAddr; + VOID *DestinationAddr; + UINT16 *SourcePixel16bit; + UINT16 Pixel16bit; + UINT32 SourcePixelX; + UINT32 SourceLine; + UINT32 DestinationPixelX; + UINT32 DestinationLine; + UINT32 BltBufferHorizontalResolution; + UINTN WidthInBytes; + + Status = EFI_SUCCESS; + PixelInformation = &This->Mode->Info->PixelInformation; + HorizontalResolution = This->Mode->Info->HorizontalResolution; + FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase)); + + if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + // Delta is not zero and it is different from the width. + // Divide it by the size of a pixel to find out the buffer's horizontal resolution. + BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + } else { + BltBufferHorizontalResolution = Width; + } + + LcdGraphicsGetBpp (This->Mode->Mode, &BitsPerPixel); + + switch (BitsPerPixel) { + case LcdBitsPerPixel_24: + WidthInBytes = Width * 4; + + // Access each line inside the Video Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) + { + // Calculate the source and target addresses using 32bit pointer arithmetic: + SourceAddr = (VOID *)((UINT32 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX ); + DestinationAddr = (VOID *)((UINT32 *)BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationX); + + // Copy the entire line + CopyMem( DestinationAddr, SourceAddr, WidthInBytes); + } + break; + + case LcdBitsPerPixel_16_555: + // Access each pixel inside the Video Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) + { + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX; + EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX; + + // Snapshot the pixel from the video buffer once, to speed up the operation. + // If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations. + Pixel16bit = *SourcePixel16bit; + + // Copy the pixel into the new target + EfiDestinationPixel->Red = (UINT8) ( (Pixel16bit & PixelInformation->RedMask ) >> 7 ); + EfiDestinationPixel->Green = (UINT8) ( (Pixel16bit & PixelInformation->GreenMask ) >> 2); + EfiDestinationPixel->Blue = (UINT8) ( (Pixel16bit & PixelInformation->BlueMask ) << 3 ); + // EfiDestinationPixel->Reserved = (UINT8) 0; + } + } + break; + + case LcdBitsPerPixel_16_565: + // Access each pixel inside the Video Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) + { + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX; + EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX; + + // Snapshot the pixel from the video buffer once, to speed up the operation. + // If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations. + Pixel16bit = *SourcePixel16bit; + + // Copy the pixel into the new target + // There is no info for the Reserved byte, so we set it to zero + EfiDestinationPixel->Red = (UINT8) ( (Pixel16bit & PixelInformation->RedMask ) >> 8 ); + EfiDestinationPixel->Green = (UINT8) ( (Pixel16bit & PixelInformation->GreenMask ) >> 3); + EfiDestinationPixel->Blue = (UINT8) ( (Pixel16bit & PixelInformation->BlueMask ) << 3 ); + // EfiDestinationPixel->Reserved = (UINT8) 0; + } + } + break; + + case LcdBitsPerPixel_12_444: + // Access each pixel inside the Video Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) + { + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX; + EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX; + + // Snapshot the pixel from the video buffer once, to speed up the operation. + // If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations. + Pixel16bit = *SourcePixel16bit; + + // Copy the pixel into the new target + EfiDestinationPixel->Red = (UINT8) ( (Pixel16bit & PixelInformation->RedMask ) >> 4 ); + EfiDestinationPixel->Green = (UINT8) ( (Pixel16bit & PixelInformation->GreenMask ) ); + EfiDestinationPixel->Blue = (UINT8) ( (Pixel16bit & PixelInformation->BlueMask ) << 4 ); + // EfiDestinationPixel->Reserved = (UINT8) 0; + } + } + break; + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + default: + // Can't handle this case + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltVideoToBltBuffer: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel)); + Status = EFI_INVALID_PARAMETER; + break; + } + return Status; +} + +#if 0 +STATIC +VOID +DebugBitmap ( + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn +) +{ + UINT32 Index = 0; + + for (Index = 0; Index < 0x3000; Index++) { + DEBUG ((DEBUG_WARN, "{%02x,%02x,%02x,%02x} ", (*(BitMapIn + Index)).Red, (*(BitMapIn + Index)).Green, (*(BitMapIn + Index)).Blue, (*(BitMapIn + Index)).Reserved)); + } +} + +STATIC +VOID +DebugMemory ( + UINT32 Reg +) +{ + UINT32 i; + + for (i = 0; i < 0x2000; i += 4) { + if (i % 0x20 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } +} +#endif + +STATIC +EFI_STATUS +BltBufferToVideo ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer + ) +{ + EFI_STATUS Status; + UINT32 HorizontalResolution; + LCD_BPP BitsPerPixel; + EFI_PIXEL_BITMASK *PixelInformation; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel; + VOID *FrameBufferBase; + VOID *SourceAddr; + VOID *DestinationAddr; + UINT16 *DestinationPixel16bit; + UINT32 SourcePixelX; + UINT32 SourceLine; + UINT32 DestinationPixelX; + UINT32 DestinationLine; + UINT32 BltBufferHorizontalResolution; + UINTN WidthInBytes; + + Status = EFI_SUCCESS; + PixelInformation = &This->Mode->Info->PixelInformation; + HorizontalResolution = This->Mode->Info->HorizontalResolution; + FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase)); + + if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) { + // Delta is not zero and it is different from the width. + // Divide it by the size of a pixel to find out the buffer's horizontal resolution. + BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + } else { + BltBufferHorizontalResolution = Width; + } + + LcdGraphicsGetBpp (This->Mode->Mode, &BitsPerPixel); + + switch (BitsPerPixel) { + case LcdBitsPerPixel_24: + WidthInBytes = Width * 4; + +#if 1 + // Access each pixel inside the BltBuffer Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) + { + // Calculate the source and target addresses using 32bit pointer arithmetic: + SourceAddr = (VOID *)((UINT32 *)BltBuffer + SourceLine * BltBufferHorizontalResolution + SourceX ); + DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX); + + // Copy the entire row Y + CopyMem( DestinationAddr, SourceAddr, WidthInBytes); + } +#endif +#if 0 + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) { + + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX; + DestinationPixel32bit = (UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + //DEBUG ((DEBUG_WARN, "(0x%08x) ", DestinationPixel32bit)); + // Copy the pixel into the new target + // Only the most significant bits will be copied across: + // To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits + *DestinationPixel32bit = (UINT32) ( + ( (EfiSourcePixel->Red << 16)) + | ( (EfiSourcePixel->Green << 8)) + | ( (EfiSourcePixel->Blue << 0)) + | ( (EfiSourcePixel->Reserved << 24)) + ); + } + } +#endif + break; + + case LcdBitsPerPixel_16_555: + // Access each pixel inside the BltBuffer Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) { + + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX; + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + // Only the most significant bits will be copied across: + // To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits + *DestinationPixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red << 7) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green << 2) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask ) + // | ( 0 & PixelInformation->ReservedMask ) + ); + } + } + break; + + case LcdBitsPerPixel_16_565: + // Access each pixel inside the BltBuffer Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) { + + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX; + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + // Only the most significant bits will be copied across: + // To convert from 8 bits to 5 or 6 bits per pixel we throw away the 3 or 2 least significant bits + // There is no room for the Reserved byte so we ignore that completely + *DestinationPixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red << 8) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green << 3) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask ) + ); + } + } + break; + + case LcdBitsPerPixel_12_444: + // Access each pixel inside the BltBuffer Memory + for (SourceLine = SourceY, DestinationLine = DestinationY; + SourceLine < SourceY + Height; + SourceLine++, DestinationLine++) { + + for (SourcePixelX = SourceX, DestinationPixelX = DestinationX; + SourcePixelX < SourceX + Width; + SourcePixelX++, DestinationPixelX++) + { + // Calculate the source and target addresses: + EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX; + DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX; + + // Copy the pixel into the new target + // Only the most significant bits will be copied across: + // To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits + *DestinationPixel16bit = (UINT16) ( + ( (EfiSourcePixel->Red << 4) & PixelInformation->RedMask ) + | ( (EfiSourcePixel->Green ) & PixelInformation->GreenMask ) + | ( (EfiSourcePixel->Blue >> 4) & PixelInformation->BlueMask ) + // | ( 0 & PixelInformation->ReservedMask ) + ); + } + } + break; + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + default: + // Can't handle this case + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltBufferToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel)); + Status = EFI_INVALID_PARAMETER; + break; + } + return Status; +} + +STATIC +EFI_STATUS +BltVideoToVideo ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer + ) +{ + EFI_STATUS Status; + UINT32 HorizontalResolution; + LCD_BPP BitsPerPixel; + VOID *FrameBufferBase; + + HorizontalResolution = This->Mode->Info->HorizontalResolution; + FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase)); + + // + // BltVideo to BltVideo: + // + // Source is the Video Memory, + // Destination is the Video Memory + + LcdGraphicsGetBpp (This->Mode->Mode, &BitsPerPixel); + FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase)); + + // The UEFI spec currently states: + // "There is no limitation on the overlapping of the source and destination rectangles" + // Therefore, we must be careful to avoid overwriting the source data + if( SourceY == DestinationY ) { + // Copying within the same height, e.g. horizontal shift + if( SourceX == DestinationX ) { + // Nothing to do + Status = EFI_SUCCESS; + } else if( ((SourceX>DestinationX)?(SourceX - DestinationX):(DestinationX - SourceX)) < Width ) { + // There is overlap + Status = VideoCopyHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height ); + } else { + // No overlap + Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height ); + } + } else { + // Copying from different heights + Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height ); + } + + return Status; +} + +/*************************************** + * GraphicsOutput Protocol function, mapping to + * EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt + * + * PRESUMES: 1 pixel = 4 bytes (32bits) + * ***************************************/ +EFI_STATUS +EFIAPI +LcdGraphicsBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer + ) +{ + EFI_STATUS Status; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + LCD_INSTANCE* Instance; + + Instance = LCD_INSTANCE_FROM_GOP_THIS(This); + + HorizontalResolution = This->Mode->Info->HorizontalResolution; + VerticalResolution = This->Mode->Info->VerticalResolution; + + DEBUG((DEBUG_VERBOSE, "[BLT]LcdGraphicsBlt (BltOperation:%d,DestX:%d,DestY:%d,Width:%d,Height:%d) res(%d,%d)\n", + BltOperation,DestinationX,DestinationY,Width,Height,HorizontalResolution,VerticalResolution)); + + // Check we have reasonable parameters + if (Width == 0 || Height == 0) { + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: ERROR - Invalid dimension: Zero size area.\n" )); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + if ((BltOperation == EfiBltVideoFill) || (BltOperation == EfiBltBufferToVideo) || (BltOperation == EfiBltVideoToBltBuffer)) { + ASSERT( BltBuffer != NULL); + } + + /*if ((DestinationX >= HorizontalResolution) || (DestinationY >= VerticalResolution)) { + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: ERROR - Invalid destination.\n" )); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + }*/ + + // If we are reading data out of the video buffer, check that the source area is within the display limits + if ((BltOperation == EfiBltVideoToBltBuffer) || (BltOperation == EfiBltVideoToVideo)) { + if ((SourceY + Height > VerticalResolution) || (SourceX + Width > HorizontalResolution)) { + DEBUG((DEBUG_INFO, "LcdGraphicsBlt: ERROR - Invalid source resolution.\n" )); + DEBUG((DEBUG_INFO, " - SourceY=%d + Height=%d > VerticalResolution=%d.\n", SourceY, Height, VerticalResolution )); + DEBUG((DEBUG_INFO, " - SourceX=%d + Width=%d > HorizontalResolution=%d.\n", SourceX, Width, HorizontalResolution )); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + } + + // If we are writing data into the video buffer, that the destination area is within the display limits + if ((BltOperation == EfiBltVideoFill) || (BltOperation == EfiBltBufferToVideo) || (BltOperation == EfiBltVideoToVideo)) { + if ((DestinationY + Height > VerticalResolution) || (DestinationX + Width > HorizontalResolution)) { + DEBUG((DEBUG_INFO, "LcdGraphicsBlt: ERROR - Invalid destination resolution.\n" )); + DEBUG((DEBUG_INFO, " - DestinationY=%d + Height=%d > VerticalResolution=%d.\n", DestinationY, Height, VerticalResolution )); + DEBUG((DEBUG_INFO, " - DestinationX=%d + Width=%d > HorizontalResolution=%d.\n", DestinationX, Width, HorizontalResolution )); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + } + + // + // Perform the Block Transfer Operation + // + + switch (BltOperation) { + case EfiBltVideoFill: + Status = BltVideoFill (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); + break; + + case EfiBltVideoToBltBuffer: + Status = BltVideoToBltBuffer (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); + break; + + case EfiBltBufferToVideo: + Status = BltBufferToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); + break; + + case EfiBltVideoToVideo: + Status = BltVideoToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); + break; + + case EfiGraphicsOutputBltOperationMax: + default: + DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: Invalid Operation\n")); + Status = EFI_INVALID_PARAMETER; + break; + } + + WriteBackDataCacheRange ((void*)(Instance->Mode.FrameBufferBase), Instance->Mode.FrameBufferSize); + +EXIT: + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c new file mode 100644 index 0000000..8882240 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.c @@ -0,0 +1,738 @@ +/** @file + This file implements the Graphics Output protocol for Arm platforms + + Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + Copyright (c) 2023, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "LcdGraphicsOutputDxe.h" + + +// +// Global variables +// +STATIC LIST_ENTRY mDisplayStateList; + +//STATIC DISPLAY_PROTOCOL mDisplayProtocol; + +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; + +typedef enum { + ROCKCHIP_VOP2_CLUSTER0 = 0, + ROCKCHIP_VOP2_CLUSTER1, + ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_SMART0, + ROCKCHIP_VOP2_SMART1, + ROCKCHIP_VOP2_CLUSTER2, + ROCKCHIP_VOP2_CLUSTER3, + ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_ESMART3, + ROCKCHIP_VOP2_LAYER_MAX, +} VOP2_LAYER_PHY_ID; + +STATIC OVER_SCAN mDefaultOverScanParas = { + .LeftMargin = 100, + .RightMargin = 100, + .TopMargin = 100, + .BottomMargin = 100 +}; + +STATIC DISPLAY_MODE mDisplayModes[] = { + { + 2, + 148500000, + {1920, 32, 200, 48}, + {1080, 5, 37, 3}, + 0, + 0, + 0, + 0, + 1 + }, +}; + +STATIC CONST UINT32 mMaxMode = ARRAY_SIZE (mDisplayModes); + +LCD_INSTANCE mLcdTemplate = { + LCD_INSTANCE_SIGNATURE, + NULL, // Handle + { // ModeInfo + 0, // Version + 0, // HorizontalResolution + 0, // VerticalResolution + PixelBltOnly, // PixelFormat + { 0 }, // PixelInformation + 0, // PixelsPerScanLine + }, + { + 0, // MaxMode; + 0, // Mode; + NULL, // Info; + 0, // SizeOfInfo; + 0, // FrameBufferBase; + 0 // FrameBufferSize; + }, + { // Gop + LcdGraphicsQueryMode, // QueryMode + LcdGraphicsSetMode, // SetMode + LcdGraphicsBlt, // Blt + NULL // *Mode + }, + { // DevicePath + { + { + HARDWARE_DEVICE_PATH, HW_VENDOR_DP, + { + (UINT8)(sizeof (VENDOR_DEVICE_PATH)), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) + }, + }, + // Hardware Device Path for Lcd + EFI_CALLER_ID_GUID // Use the driver's GUID + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } + }, + (EFI_EVENT)NULL, // ExitBootServicesEvent +}; + +EFI_STATUS +LcdInstanceContructor ( + OUT LCD_INSTANCE** NewInstance + ) +{ + LCD_INSTANCE* Instance; + + Instance = AllocateCopyPool (sizeof (LCD_INSTANCE), &mLcdTemplate); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->Gop.Mode = &Instance->Mode; + Instance->Gop.Mode->MaxMode = mMaxMode; + Instance->Mode.Info = &Instance->ModeInfo; + + *NewInstance = Instance; + return EFI_SUCCESS; +} + +// +// Function Definitions +// + +EFIAPI +EFI_STATUS +DisplayGetTiming ( + OUT DISPLAY_STATE *DisplayState + ) +{ + DRM_DISPLAY_MODE *Mode = &DisplayState->ConnectorState.DisplayMode; + UINT32 ModeNumber = DisplayState->ModeNumber; + UINT32 HActive, VActive, PixelClock; + UINT32 HFrontPorch, HBackPorch, HSyncLen; + UINT32 VFrontPorch, VBackPorch, VSyncLen; + UINT32 Flags = 0; + UINT32 Val = 0; + + HActive = mDisplayModes[ModeNumber].Horizontal.Resolution; + VActive = mDisplayModes[ModeNumber].Vertical.Resolution; + PixelClock = mDisplayModes[ModeNumber].OscFreq; + HSyncLen = mDisplayModes[ModeNumber].Horizontal.Sync; + HFrontPorch = mDisplayModes[ModeNumber].Horizontal.FrontPorch; + HBackPorch = mDisplayModes[ModeNumber].Horizontal.BackPorch; + VSyncLen = mDisplayModes[ModeNumber].Vertical.Sync; + VFrontPorch = mDisplayModes[ModeNumber].Vertical.FrontPorch; + VBackPorch = mDisplayModes[ModeNumber].Vertical.BackPorch; + + Val = mDisplayModes[ModeNumber].HsyncActive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + Flags |= Val; + Val = mDisplayModes[ModeNumber].VsyncActive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; + Flags |= Val; + Val = mDisplayModes[ModeNumber].ClkActive ? DRM_MODE_FLAG_PPIXDATA : 0; + Flags |= Val; + + Mode->HDisplay = HActive; + Mode->HSyncStart = Mode->HDisplay + HFrontPorch; + Mode->HSyncEnd = Mode->HSyncStart + HSyncLen; + Mode->HTotal = Mode->HSyncEnd + HBackPorch; + + Mode->VDisplay = VActive; + Mode->VSyncStart = Mode->VDisplay + VFrontPorch; + Mode->VSyncEnd = Mode->VSyncStart + VSyncLen; + Mode->VTotal = Mode->VSyncEnd + VBackPorch; + + Mode->Clock = PixelClock / 1000; + Mode->Flags = Flags; + + /* not to set fix --- todo */ + Mode->VScan = 0; + + return EFI_SUCCESS; +} + +STATIC +UINT32 +DisplayBppConvert ( + IN LCD_BPP LcdBpp + ) +{ + UINT32 DisplayBpp; + + switch (LcdBpp) { + case LcdBitsPerPixel_24: + DisplayBpp = 32; + break; + default: + DisplayBpp = 32; + break; + } + + return DisplayBpp; +} + +STATIC +EFI_STATUS +DisplayPreInit ( + IN LCD_INSTANCE* Instance + ) +{ + EFI_STATUS Status; + DISPLAY_STATE *StateInterate; + ROCKCHIP_CRTC_PROTOCOL *Crtc; + ROCKCHIP_CONNECTOR_PROTOCOL *Connector; + + LIST_FOR_EACH_ENTRY(StateInterate, &mDisplayStateList, ListHead) { + if (StateInterate->IsEnable) { + CRTC_STATE *CrtcState = &StateInterate->CrtcState; + CONNECTOR_STATE *ConnectorState = &StateInterate->ConnectorState; + Crtc = (ROCKCHIP_CRTC_PROTOCOL*)StateInterate->CrtcState.Crtc; + Connector = (ROCKCHIP_CONNECTOR_PROTOCOL *)StateInterate->ConnectorState.Connector; + + if (Connector && Connector->Preinit) + Status = Connector->Preinit(Connector, StateInterate); + + Crtc->Vps[CrtcState->CrtcID].OutputType = ConnectorState->Type; + + if (Crtc && Crtc->Preinit) { + Status = Crtc->Preinit(Crtc, StateInterate); + if (EFI_ERROR (Status)) { + goto EXIT; + } + } + } + } + +EXIT: + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +LcdGraphicsOutputInit ( + VOID + ) +{ + EFI_STATUS Status; + LCD_INSTANCE *Instance; + DISPLAY_STATE *DisplayState; + DISPLAY_MODE *Mode; + UINTN ModeIndex; + ROCKCHIP_CRTC_PROTOCOL *Crtc; + UINTN ConnectorCount; + EFI_HANDLE *ConnectorHandles; + UINTN Index; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + + Status = LcdInstanceContructor (&Instance); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, + (VOID**)&mCpu); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gRockchipCrtcProtocolGuid, NULL, + (VOID **) &Crtc); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Can not locate the RockchipCrtcProtocol. Status=%r\n", + __func__, Status)); + return Status; + } + + Status = gBS->LocateHandleBuffer (ByProtocol, + &gRockchipConnectorProtocolGuid, + NULL, + &ConnectorCount, + &ConnectorHandles); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Can not locate gRockchipConnectorProtocolGuid. Status=%r\n", + __func__, Status)); + return Status; + } + + // + // TO-DO: When EDID is implemented. + // If native resolution is preferred (rather than custom, via PCDs), + // we should pick the maximum mode supported by all connected displays. + // + // Why? Because we provide a single GOP and framebuffer shared between + // all outputs. + // + // It is possible to install a GOP for each display, but then OSes would + // only draw on the primary (usually first) one. This needs additional + // logic to let users choose the primary display through a setup option. + // + + // + // Assume mode #0 is the highest supported mode for now. + // + ModeIndex = 0; + Mode = &mDisplayModes[ModeIndex]; + + InitializeListHead (&mDisplayStateList); + + for (Index = 0; Index < ConnectorCount; Index++) { + DisplayState = AllocateZeroPool (sizeof(DISPLAY_STATE)); + InitializeListHead (&DisplayState->ListHead); + + Status = gBS->HandleProtocol (ConnectorHandles[Index], + &gRockchipConnectorProtocolGuid, + (VOID **) &DisplayState->ConnectorState.Connector); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: HandleProtocol gRockchipConnectorProtocolGuid [%d] failed. Status=%r\n", + __func__, Index, Status)); + return Status; + } + + // + // DSI panel has a hardcoded mode. Overwrite the current one. + // This is all pretty ugly and prevents using multiple displays, + // but whatever... + // + ROCKCHIP_DSI_PANEL_PROTOCOL *DsiPanel; + + Status = gBS->HandleProtocol (ConnectorHandles[Index], + &gRockchipDsiPanelProtocolGuid, + (VOID **) &DsiPanel); + if (!EFI_ERROR (Status)) { + CopyMem (Mode, &DsiPanel->NativeMode, sizeof (*Mode)); + } + + /* adapt to UEFI architecture */ + DisplayState->ModeNumber = ModeIndex; + DisplayState->VpsConfigModeID = Mode->VpsConfigModeID; + + DisplayState->CrtcState.Crtc = (VOID *) Crtc; + DisplayState->CrtcState.CrtcID = Mode->CrtcId; + + DisplayState->ConnectorState.OverScan.LeftMargin = mDefaultOverScanParas.LeftMargin; + DisplayState->ConnectorState.OverScan.RightMargin = mDefaultOverScanParas.RightMargin; + DisplayState->ConnectorState.OverScan.TopMargin = mDefaultOverScanParas.TopMargin; + DisplayState->ConnectorState.OverScan.BottomMargin = mDefaultOverScanParas.BottomMargin; + + /* set MEDIA_BUS_FMT_RBG888_1X24 by default when using panel */ + /* move to panel driver later -- todo*/ + DisplayState->ConnectorState.BusFormat = MEDIA_BUS_FMT_RBG888_1X24; + + /* add BCSH data if needed --- todo */ + DisplayState->ConnectorState.DispInfo = NULL; + + Crtc->Vps[Mode->CrtcId].Enable = TRUE; + DisplayState->IsEnable = TRUE; + + InsertTailList (&mDisplayStateList, &DisplayState->ListHead); + } + + Status = DisplayPreInit (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: DisplayPreInit fail. Exit Status=%r\n", + __func__, Status)); + return Status; + } + + // Register for an ExitBootServicesEvent + // When ExitBootServices starts, this function will make sure that the + // graphics driver shuts down properly, i.e. it will free up all + // allocated memory and perform any necessary hardware re-configuration. + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_NOTIFY, + LcdGraphicsExitBootServicesEvent, + NULL, + &Instance->ExitBootServicesEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Can not install the ExitBootServicesEvent handler. Exit Status=%r\n", + __func__, Status)); + return Status; + } + + // Install the Graphics Output Protocol and the Device Path + Status = gBS->InstallMultipleProtocolInterfaces ( + &Instance->Handle, + &gEfiGraphicsOutputProtocolGuid, + &Instance->Gop, + &gEfiDevicePathProtocolGuid, + &Instance->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Can not install the protocol. Status=%r\n", + __func__, Status)); + return Status; + } + + return EFI_SUCCESS; +} + +VOID +EFIAPI +LcdGraphicsOutputEndOfDxeEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gBS->CloseEvent (Event); + + LcdGraphicsOutputInit (); +} + +EFI_STATUS +EFIAPI +LcdGraphicsOutputDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT EndOfDxeEvent; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + LcdGraphicsOutputEndOfDxeEventHandler, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + return Status; +} + +/** This function should be called + on Event: ExitBootServices + to free up memory, stop the driver + and uninstall the protocols +**/ +VOID +LcdGraphicsExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // By default, this PCD is FALSE. But if a platform starts a predefined OS + // that does not use a framebuffer then we might want to disable the display + // controller to avoid to display corrupted information on the screen. + if (FeaturePcdGet (PcdGopDisableOnExitBootServices)) { + // Turn-off the Display controller + } +} + +/** GraphicsOutput Protocol function, mapping to + EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode +**/ +EFI_STATUS +EFIAPI +LcdGraphicsQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +{ + EFI_STATUS Status; + LCD_INSTANCE *Instance; + + Instance = LCD_INSTANCE_FROM_GOP_THIS (This); + + // Error checking + if ((This == NULL) || + (Info == NULL) || + (SizeOfInfo == NULL) || + (ModeNumber >= This->Mode->MaxMode)) { + DEBUG ((DEBUG_ERROR, "LcdGraphicsQueryMode: ERROR - For mode number %d : Invalid Parameter.\n", ModeNumber)); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + + *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + if (*Info == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + (*Info)->Version = 0; + (*Info)->HorizontalResolution = mDisplayModes[ModeNumber].Horizontal.Resolution; + (*Info)->VerticalResolution = mDisplayModes[ModeNumber].Vertical.Resolution; + (*Info)->PixelsPerScanLine = mDisplayModes[ModeNumber].Horizontal.Resolution; + (*Info)->PixelFormat = FixedPcdGet32 (PcdLcdPixelFormat); + + return EFI_SUCCESS; + +EXIT: + return Status; +} + +/** GraphicsOutput Protocol function, mapping to + EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode +**/ +EFI_STATUS +EFIAPI +LcdGraphicsSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL FillColour; + LCD_INSTANCE* Instance; + LCD_BPP Bpp; + EFI_PHYSICAL_ADDRESS VramBaseAddress; + UINTN VramSize; + UINTN NumVramPages; + UINTN NumPreviousVramPages; + DISPLAY_MODE *Mode; + DRM_DISPLAY_MODE *DrmMode; + DISPLAY_STATE *StateInterate; + ROCKCHIP_CRTC_PROTOCOL *Crtc; + CRTC_STATE *CrtcState; + ROCKCHIP_CONNECTOR_PROTOCOL *Connector; + CONNECTOR_STATE *ConnectorState; + + Instance = LCD_INSTANCE_FROM_GOP_THIS (This); + + // Check if this mode is supported + if (ModeNumber >= This->Mode->MaxMode) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Unsupported mode number %d .\n", + __func__, ModeNumber)); + Status = EFI_UNSUPPORTED; + goto EXIT; + } + + Mode = &mDisplayModes[ModeNumber]; + + Status = LcdGraphicsGetBpp (ModeNumber, &Bpp); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Couldn't get bytes per pixel, status: %r\n", + __func__, Status)); + goto EXIT; + } + + VramBaseAddress = This->Mode->FrameBufferBase; + + VramSize = Mode->Horizontal.Resolution + * Mode->Vertical.Resolution + * GetBytesPerPixel (Bpp); + + NumVramPages = EFI_SIZE_TO_PAGES (VramSize); + NumPreviousVramPages = EFI_SIZE_TO_PAGES (This->Mode->FrameBufferSize); + + if (NumPreviousVramPages < NumVramPages) { + if (NumPreviousVramPages != 0) { + gBS->FreePages (VramBaseAddress, NumPreviousVramPages); + This->Mode->FrameBufferSize = 0; + } + + VramBaseAddress = SIZE_4GB - 1; // VOP2 only supports 32-bit addresses + Status = gBS->AllocatePages (AllocateMaxAddress, EfiRuntimeServicesData, + NumVramPages, &VramBaseAddress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Could not allocate %u pages for mode %u: %r\n", + __func__, NumVramPages, ModeNumber, Status)); + return Status; + } + + Status = mCpu->SetMemoryAttributes (mCpu, VramBaseAddress, + ALIGN_VALUE (VramSize, EFI_PAGE_SIZE), + EFI_MEMORY_WC); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Couldn't set framebuffer attributes: %r\n", + __func__, Status)); + goto EXIT; + } + } + + // Update the UEFI mode information + This->Mode->Mode = ModeNumber; + + Instance->ModeInfo.Version = 0; + Instance->ModeInfo.HorizontalResolution = mDisplayModes[ModeNumber].Horizontal.Resolution; + Instance->ModeInfo.VerticalResolution = mDisplayModes[ModeNumber].Vertical.Resolution; + Instance->ModeInfo.PixelsPerScanLine = mDisplayModes[ModeNumber].Horizontal.Resolution; + Instance->ModeInfo.PixelFormat = FixedPcdGet32 (PcdLcdPixelFormat); + Instance->Mode.SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + This->Mode->FrameBufferBase = VramBaseAddress; + This->Mode->FrameBufferSize = VramSize; + + // The UEFI spec requires that we now clear the visible portions of the + // output display to black. + + // Set the fill colour to black + SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); + + // Fill the entire visible area with the same colour. + Status = This->Blt ( + This, + &FillColour, + EfiBltVideoFill, + 0, + 0, + 0, + 0, + This->Mode->Info->HorizontalResolution, + This->Mode->Info->VerticalResolution, + 0 + ); + + LIST_FOR_EACH_ENTRY(StateInterate, &mDisplayStateList, ListHead) { + if (StateInterate->ModeNumber == ModeNumber && StateInterate->IsEnable) { + Crtc = (ROCKCHIP_CRTC_PROTOCOL*)StateInterate->CrtcState.Crtc; + Connector = (ROCKCHIP_CONNECTOR_PROTOCOL *)StateInterate->ConnectorState.Connector; + CrtcState = &StateInterate->CrtcState; + ConnectorState = &StateInterate->ConnectorState; + DrmMode = &StateInterate->ConnectorState.DisplayMode; + + StateInterate->ModeNumber = ModeNumber; + + if (Connector && Connector->Init) + Status = Connector->Init(Connector, StateInterate); + + /* move to panel protocol --- todo */ + DisplayGetTiming (StateInterate); + + DEBUG ((DEBUG_INIT, "[INIT]detailed mode clock %u kHz, flags[%x]\n" + " H: %04d %04d %04d %04d\n" + " V: %04d %04d %04d %04d\n" + " bus_format: %x\n", + DrmMode->Clock, DrmMode->Flags, + DrmMode->HDisplay, DrmMode->HSyncStart, + DrmMode->HSyncEnd, DrmMode->HTotal, + DrmMode->VDisplay, DrmMode->VSyncStart, + DrmMode->VSyncEnd, DrmMode->VTotal, + ConnectorState->BusFormat)); + + Status = DisplaySetCrtcInfo(DrmMode, CRTC_INTERLACE_HALVE_V); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + if (Crtc && Crtc->Init) { + Status = Crtc->Init (Crtc, StateInterate); + if (EFI_ERROR (Status)) { + goto EXIT; + } + } + + /* adapt to uefi display architecture */ + CrtcState->Format = ROCKCHIP_FMT_ARGB8888; + CrtcState->SrcW = ConnectorState->DisplayMode.HDisplay; + CrtcState->SrcH = ConnectorState->DisplayMode.VDisplay; + CrtcState->SrcX = 0; + CrtcState->SrcY = 0; + CrtcState->CrtcW = ConnectorState->DisplayMode.HDisplay; + CrtcState->CrtcH = ConnectorState->DisplayMode.VDisplay; + CrtcState->CrtcX = 0; + CrtcState->CrtcY = 0; + CrtcState->YMirror = 0; + CrtcState->RBSwap = 0; + + CrtcState->XVirtual = ALIGN(CrtcState->SrcW * DisplayBppConvert (Bpp), 32) >> 5; + CrtcState->DMAAddress = (UINT32)VramBaseAddress; + + if (Crtc && Crtc->SetPlane) + Crtc->SetPlane (Crtc, StateInterate); + + if (Crtc && Crtc->Enable) + Crtc->Enable (Crtc, StateInterate); + + if (Connector && Connector->Enable) + Connector->Enable (Connector, StateInterate); + } + } + +EXIT: + return Status; +} + +EFI_STATUS +EFIAPI +LcdGraphicsGetBpp ( + IN UINT32 ModeNumber, + OUT LCD_BPP* Bpp + ) +{ + if (ModeNumber >= mMaxMode) { + return EFI_INVALID_PARAMETER; + } + + *Bpp = LcdBitsPerPixel_24; + + return EFI_SUCCESS; +} + +UINTN +GetBytesPerPixel ( + IN LCD_BPP Bpp + ) +{ + switch (Bpp) { + case LcdBitsPerPixel_24: + return 4; + + case LcdBitsPerPixel_16_565: + case LcdBitsPerPixel_16_555: + case LcdBitsPerPixel_12_444: + return 2; + + case LcdBitsPerPixel_8: + case LcdBitsPerPixel_4: + case LcdBitsPerPixel_2: + case LcdBitsPerPixel_1: + return 1; + + default: + return 0; + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.h new file mode 100644 index 0000000..66b7256 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.h @@ -0,0 +1,122 @@ +/** @file + + Copyright (c) 2011-2018, ARM Ltd. All rights reserved.
    + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef LCD_GRAPHICS_OUTPUT_DXE_H_ +#define LCD_GRAPHICS_OUTPUT_DXE_H_ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/** The enumeration maps the PL111 LcdBpp values used in the LCD Control + Register +**/ +typedef enum { + LcdBitsPerPixel_1 = 0, + LcdBitsPerPixel_2, + LcdBitsPerPixel_4, + LcdBitsPerPixel_8, + LcdBitsPerPixel_16_555, + LcdBitsPerPixel_24, + LcdBitsPerPixel_16_565, + LcdBitsPerPixel_12_444, + LcdBitsPerPixel_Max +} LCD_BPP; + +// +// Device structures +// +typedef struct { + VENDOR_DEVICE_PATH Guid; + EFI_DEVICE_PATH_PROTOCOL End; +} LCD_GRAPHICS_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInfo; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE Mode; + EFI_GRAPHICS_OUTPUT_PROTOCOL Gop; + LCD_GRAPHICS_DEVICE_PATH DevicePath; + EFI_EVENT ExitBootServicesEvent; +} LCD_INSTANCE; + +#define LCD_INSTANCE_SIGNATURE SIGNATURE_32('l', 'c', 'd', '0') + +#define LCD_INSTANCE_FROM_GOP_THIS(a) CR (a, LCD_INSTANCE, Gop, LCD_INSTANCE_SIGNATURE) + +// +// Function Prototypes +// + +VOID +LcdGraphicsExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context +); + +EFI_STATUS +EFIAPI +LcdGraphicsQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info +); + +EFI_STATUS +EFIAPI +LcdGraphicsSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber +); + +EFI_STATUS +EFIAPI +LcdGraphicsBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL +); + +EFI_STATUS +EFIAPI +LcdGraphicsGetBpp ( + IN UINT32 ModeNumber, + OUT LCD_BPP* Bpp + ); + +UINTN +GetBytesPerPixel ( + IN LCD_BPP Bpp + ); + +EFI_STATUS +EFIAPI +GraphicsOutputDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +); + +#endif /* LCD_GRAPHICS_OUTPUT_DXE_H_ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf new file mode 100644 index 0000000..bd2eb1f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf @@ -0,0 +1,62 @@ +#/** @file +# +# Component description file for LcdGraphicsOutputDxe module +# +# Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
    +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = LcdGraphicsOutputDxe + FILE_GUID = eaf89ad8-92e1-11ec-b51d-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = LcdGraphicsOutputDxeInitialize + +[Sources.common] + LcdGraphicsOutputBlt.c + LcdGraphicsOutputDxe.c + LcdGraphicsOutputDxe.h + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + CacheMaintenanceLib + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + RockchipDisplayLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDevicePathProtocolGuid + gEfiGraphicsOutputProtocolGuid + gRockchipCrtcProtocolGuid + gRockchipConnectorProtocolGuid + gRockchipDsiPanelProtocolGuid + +[Guids] + gEfiEndOfDxeEventGroupGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdLcdPixelFormat + +[FeaturePcd] + gArmPlatformTokenSpaceGuid.PcdGopDisableOnExitBootServices + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.c new file mode 100644 index 0000000..6ba68fe --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.c @@ -0,0 +1,1214 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2022 Rockchip Electronics Co., Ltd. + */ +#include +#include "Soc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAL_SNOR_DEBUG +#ifdef HAL_SNOR_DEBUG +#define DEBUG_SNOR DEBUG_WARN +#else +#define DEBUG_SNOR DEBUG_INFO +#endif + +struct FLASH_INFO { + UINT32 id; + + UINT8 blockSize; + UINT8 sectorSize; + UINT8 readCmd; + UINT8 progCmd; + + UINT8 readCmd_4; + UINT8 progCmd_4; + UINT8 sectorEraseCmd; + UINT8 blockEraseCmd; + + UINT8 feature; + UINT8 density; /* (1 << density) sectors */ + UINT8 QEBits; + UINT8 reserved2; +}; + +/* FLASH_INFO feature */ +#define FEA_STATUE_MASK (0x3 << 0) +#define FEA_STATUE_MODE0 0 /* Readstatus0 05h-SR1, 35h-SR2, Writestatus0 01h-SR1, 31h-SR2 */ +#define FEA_STATUE_MODE1 1 /* Readstatus0 05h-SR1, 35h-SR2, Writestatus1 01h-SR1-SR2 */ +#define FEA_STATUE_MODE2 2 /* Readstatus1 05h-SR1, 15h-CR1, Writestatus1 01h-SR1-CR1 */ +#define FEA_4BIT_READ BIT(2) +#define FEA_4BIT_PROG BIT(3) +#define FEA_4BYTE_ADDR BIT(4) +#define FEA_4BYTE_ADDR_MODE BIT(5) + +/*Manufactory ID*/ +#define MID_WINBOND 0xEF +#define MID_GIGADEV 0xC8 +#define MID_MICRON 0x2C +#define MID_MACRONIX 0xC2 +#define MID_SPANSION 0x01 +#define MID_EON 0x1C +#define MID_ST 0x20 +#define MID_XTX 0x0B +#define MID_PUYA 0x85 +#define MID_XMC 0x20 + +/* Used for Macronix and Winbond flashes. */ +#define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ +#define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ + +/* Used for SST flashes only. */ +#define SPINOR_OP_WRDI 0x04 /* Write disable */ + +#define SPINOR_OP_MAX_SIZE 0x40 +#define UINT_MAX (~0U) + +#define READ_MAX_IOSIZE (1024 * 8) /* 8KB */ + +/********************* Private Structure Definition **************************/ + +/********************* Private Variable Definition ***************************/ +static const struct FLASH_INFO s_spiFlashbl[] = { + /* GD25Q32B */ + { 0xc84016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 13, 9, 0 }, + /* GD25Q64B */ + { 0xc84017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* GD25Q127C and GD25Q128C*/ + { 0xc84018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* GD25Q256B/C/D */ + { 0xc84019, 128, 8, 0x13, 0x12, 0x6C, 0x3E, 0x21, 0xDC, 0x1C, 16, 6, 0 }, + /* GD25LQ64C */ + { 0xc86017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* GD25LQ32E */ + { 0xc86016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 13, 9, 0 }, + /* GD25Q256E */ + { 0xc86019, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 16, 9, 0 }, + + /* W25Q32JV */ + { 0xef4016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 9, 0 }, + /* W25Q64JVSSIQ */ + { 0xef4017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + /* W25Q128FV and W25Q128JV*/ + { 0xef4018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* W25Q256F/J */ + { 0xef4019, 128, 8, 0x13, 0x02, 0x6C, 0x32, 0x20, 0xD8, 0x3C, 16, 9, 0 }, + /* 25Q32JW */ + { 0xef6016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 9, 0 }, + /* W25Q256JWEQ*/ + { 0xef6019, 128, 8, 0x13, 0x02, 0x6C, 0x32, 0x20, 0xD8, 0x3C, 16, 9, 0 }, + /* W25Q64FWSSIG */ + { 0xef6017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + /* W25Q64JVSIQ */ + { 0xef7017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + /* W25Q128JVSIM */ + { 0xef7018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + + /* MX25L3233FM2I-08G */ + { 0xc22016, 128, 8, 0x03, 0x02, 0x6B, 0x38, 0x20, 0xD8, 0x0E, 13, 6, 0 }, + /* MX25L6433F */ + { 0xc22017, 128, 8, 0x03, 0x02, 0x6B, 0x38, 0x20, 0xD8, 0x0E, 14, 6, 0 }, + /* MX25L12835E/F MX25L12833FMI-10G */ + { 0xc22018, 128, 8, 0x03, 0x02, 0x6B, 0x38, 0x20, 0xD8, 0x0E, 15, 6, 0 }, + /* MX25U12832F */ + { 0xc22538, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0E, 15, 6, 0 }, + /* MX25L25635E/F MX25L25645G MX25L25645GMI-08G */ + { 0xc22019, 128, 8, 0x13, 0x12, 0x6C, 0x3E, 0x21, 0xDC, 0x1E, 16, 6, 0 }, + + /* XM25QH32C */ + { 0x204016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 9, 0 }, + /* XM25QH64B */ + { 0x206017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 6, 0 }, + /* XM25QH128B */ + { 0x206018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 15, 6, 0 }, + /* XM25QH(QU)256B */ + { 0x206019, 128, 8, 0x13, 0x12, 0x6C, 0x3E, 0x21, 0xDC, 0x1D, 16, 6, 0 }, + /* XM25QH64A */ + { 0x207017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 0, 0 }, + /* XM25QU128C */ + { 0x204118, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* XM25QU64C */ + { 0x204117, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + + /* XT25F64BSSIGU-5 */ + { 0x0b4017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* XT25F128BSSIGU */ + { 0x0b4018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 15, 9, 0 }, + /* XT25F32BS */ + { 0x0b4016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 13, 9, 0 }, + /* XT25F16BS */ + { 0x0b4015, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 12, 9, 0 }, + + /* EN25QH64A */ + { 0x1c7017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 0, 0 }, + /* EN25QH128A */ + { 0x1c7018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 0, 0 }, + /* EN25QH32B */ + { 0x1c7016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 0, 0 }, + /* EN25S16A */ + { 0x1c3815, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 12, 0, 0 }, + /* EN25S32A */ + { 0x1c3816, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 0, 0 }, + /* EN25S64A */ + { 0x1c3817, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 0, 0 }, + /* EN25QH256A */ + { 0x1c7019, 128, 8, 0x13, 0x12, 0x6C, 0x34, 0x21, 0xDC, 0x3C, 16, 0, 0 }, + + /* P25Q64H */ + { 0x856017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + /* P25Q128H */ + { 0x856018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* P25Q16H-SUH-IT */ + { 0x856015, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 12, 9, 0 }, + /* FM25Q64A */ + { 0xf83217, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* FM25M64C */ + { 0xf84317, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* P25Q32SL */ + { 0x856016, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 13, 9, 0 }, + + /* ZB25VQ64 */ + { 0x5e4017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + /* ZB25VQ128 */ + { 0x5e4018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* ZB25LQ128 */ + { 0x5e5018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + + /* BH25Q128AS */ + { 0x684018, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 15, 9, 0 }, + /* BH25Q64BS */ + { 0x684017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + + /* P25Q64H */ + { 0x856017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + + /* FM25Q64-SOB-T-G */ + { 0xA14017, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0C, 14, 9, 0 }, + + /* FM25Q64A */ + { 0xf83217, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 14, 9, 0 }, + /* FM25M4AA */ + { 0xf84218, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x0D, 15, 9, 0 }, +}; +STATIC struct HAL_FSPI_HOST *g_spi; +STATIC struct SPI_NOR *g_nor; +STATIC EFI_EVENT mNorVirtualAddrChangeEvent; +/* Support single line case + * - id: get from SPI Nor device information + * - capacity: initial by SPI Nor id byte + * - QE bits: no need + * */ +static struct FLASH_INFO s_commonSpiFlash = { 0, 128, 8, 0x03, 0x02, 0x6B, 0x32, 0x20, 0xD8, 0x00, 0, 0, 0 }; + +/********************* Private Function Definition ***************************/ +static RETURN_STATUS SNOR_ReadWriteReg(struct SPI_NOR *nor, struct HAL_SPI_MEM_OP *op, void *buf) +{ + if (op->data.dir == HAL_SPI_MEM_DATA_IN) { + op->data.buf.in = buf; + } else { + op->data.buf.out = buf; + } + + return HAL_FSPI_SpiXfer(nor->spi, op); +} + +static RETURN_STATUS SNOR_ReadReg(struct SPI_NOR *nor, UINT8 code, UINT8 *val, UINT32 len) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(code, 1), + HAL_SPI_MEM_OP_NO_ADDR, + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_DATA_IN(len, NULL, 1)); + RETURN_STATUS ret; + + ret = SNOR_ReadWriteReg(nor, &op, val); + if (ret) { + DEBUG ((DEBUG_SNOR, "error %d reading %x\n", ret, code)); + } + + return ret; +} + +static RETURN_STATUS SNOR_WriteReg(struct SPI_NOR *nor, UINT8 opcode, UINT8 *buf, UINT32 len) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(opcode, 1), + HAL_SPI_MEM_OP_NO_ADDR, + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_DATA_OUT(len, NULL, 1)); + + /* DEBUG ((DEBUG_SNOR, "%s %x %ld\n", __func__, opcode, len)); */ + + return SNOR_ReadWriteReg(nor, &op, buf); +} + +static INT32 SNOR_ReadData(struct SPI_NOR *nor, UINT32 from, UINT32 len, UINT8 *buf) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(nor->readOpcode, 1), + HAL_SPI_MEM_OP_ADDR(nor->addrWidth, from, 1), + HAL_SPI_MEM_OP_DUMMY(nor->readDummy, 1), + HAL_SPI_MEM_OP_DATA_IN(len, buf, 1)); + INT32 ret; + + /* get transfer protocols. */ + op.cmd.buswidth = 1; + op.addr.buswidth = SNOR_GET_PROTOCOL_ADDR_BITS(nor->readProto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = SNOR_GET_PROTOCOL_DATA_BITS(nor->readProto); + + /* DEBUG ((DEBUG_SNOR, "%s %x %lx %lx %lx\n", __func__, nor->readDummy, op.data.nbytes, from, op.addr.val)); */ + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (nor->readDummy * op.dummy.buswidth) >> 3; + + ret = HAL_FSPI_SpiXfer(nor->spi, &op); + if (ret) { + return 0; + } + + return len; +} + +static INT32 SNOR_WriteData(struct SPI_NOR *nor, UINT32 to, UINT32 len, const UINT8 *buf) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(nor->programOpcode, 1), + HAL_SPI_MEM_OP_ADDR(nor->addrWidth, to, 1), + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_DATA_OUT(len, buf, 1)); + INT32 ret; + + /* get transfer protocols. */ + op.cmd.buswidth = 1; + op.addr.buswidth = SNOR_GET_PROTOCOL_ADDR_BITS(nor->writeProto); + op.data.buswidth = SNOR_GET_PROTOCOL_DATA_BITS(nor->writeProto); + + op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes; + + ret = HAL_FSPI_SpiXfer(nor->spi, &op); + if (ret) { + return 0; + } + + return op.data.nbytes; +} + +/* + * Initiate the erasure of a single sector + */ +static RETURN_STATUS SNOR_EraseSec(struct SPI_NOR *nor, UINT32 addr) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(nor->eraseOpcodeSec, 1), + HAL_SPI_MEM_OP_ADDR(nor->addrWidth, addr, 1), + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_NO_DATA); + + /* + * Default implementation, if driver doesn't have a specialized HW + * control + */ + return HAL_FSPI_SpiXfer(nor->spi, &op); +} + +/* + * Initiate the erasure of a single sector + */ +static RETURN_STATUS SNOR_EraseBlk(struct SPI_NOR *nor, UINT32 addr) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(nor->eraseOpcodeBlk, 1), + HAL_SPI_MEM_OP_ADDR(nor->addrWidth, addr, 1), + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_NO_DATA); + + /* + * Default implementation, if driver doesn't have a specialized HW + * control + */ + return HAL_FSPI_SpiXfer(nor->spi, &op); +} + +static RETURN_STATUS SNOR_EraseChip(struct SPI_NOR *nor, UINT32 addr) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 1), + HAL_SPI_MEM_OP_NO_ADDR, + HAL_SPI_MEM_OP_NO_DUMMY, + HAL_SPI_MEM_OP_NO_DATA); + /* + * Default implementation, if driver doesn't have a specialized HW + * control + */ + return HAL_FSPI_SpiXfer(nor->spi, &op); +} + +static const struct FLASH_INFO *SNOR_GerFlashInfo(UINT8 *flashId) +{ + UINT32 i; + UINT32 id = (flashId[0] << 16) | (flashId[1] << 8) | (flashId[2] << 0); + + for (i = 0; i < ARRAY_SIZE(s_spiFlashbl); i++) { + if (s_spiFlashbl[i].id == id) { + return &s_spiFlashbl[i]; + } + } + + return NULL; +} + +static RETURN_STATUS SNOR_WriteEnable(struct SPI_NOR *nor) +{ + return SNOR_WriteReg(nor, SPINOR_OP_WREN, NULL, 0); +} + +/* + * Service routine to read status register until ready, or timeout occurs. + * Returns non-zero if error. + */ +static RETURN_STATUS SNOR_WaitBusy(struct SPI_NOR *nor, unsigned long timeout) +{ + RETURN_STATUS ret; + UINT32 i; + UINT8 status; + + /* DEBUG ((DEBUG_SNOR, "%s %lx\n", __func__, timeout)); */ + for (i = 0; i < timeout; i++) { + ret = SNOR_ReadReg(nor, SPINOR_OP_RDSR, &status, 1); + if (ret != RETURN_SUCCESS) { + return ret; + } + + if ((status & 0x01) == 0) { + return RETURN_SUCCESS; + } + + NanoSecondDelay(500); + } + DEBUG ((DEBUG_SNOR, "%s error %ld\n", __func__, timeout)); + + return RETURN_NOT_READY; +} + +static RETURN_STATUS SNOR_ReadStatus(struct SPI_NOR *nor, UINT32 regIndex, UINT8 *status) +{ + UINT8 readStatCmd[] = { SPINOR_OP_RDSR, SPINOR_OP_RDSR1, SPINOR_OP_RDSR2 }; + UINT8 i = nor->info->feature & FEA_STATUE_MASK; + + if (i == FEA_STATUE_MODE2) { /* Readstatus1 */ + readStatCmd[1] = SPINOR_OP_RDCR; + } + + return SNOR_ReadReg(nor, readStatCmd[regIndex], status, 1); +} + +static RETURN_STATUS SNOR_WriteStatus(struct SPI_NOR *nor, UINT32 regIndex, UINT8 *status) +{ + UINT8 WriteStatCmd[2] = { SPINOR_OP_WRSR, SPINOR_OP_WRSR1 }; + UINT8 i = nor->info->feature & FEA_STATUE_MASK; + RETURN_STATUS ret; + + if (i == FEA_STATUE_MODE0) { /* Writestatus0 */ + SNOR_WriteEnable(nor); + + ret = SNOR_WriteReg(nor, WriteStatCmd[regIndex], status, 1); + if (ret) { + DEBUG ((DEBUG_SNOR, "error while writing configuration register\n")); + + return RETURN_DEVICE_ERROR; + } + + ret = SNOR_WaitBusy(nor, 10000); + if (ret) { + DEBUG ((DEBUG_SNOR, "timeout while writing configuration register\n")); + + return ret; + } + } else { /* Writestatus1 */ + UINT8 readIndex; + UINT8 status2[2]; + + status2[regIndex] = *status; + readIndex = (regIndex == 0) ? 1 : 0; + ret = SNOR_ReadStatus(nor, readIndex, &status2[readIndex]); + if (ret != RETURN_SUCCESS) { + return ret; + } + + SNOR_WriteEnable(nor); + ret = SNOR_WriteReg(nor, SPINOR_OP_WRSR, &status2[0], 2); + if (ret != RETURN_SUCCESS) { + return ret; + } + + ret = SNOR_WaitBusy(nor, 10000); + } + + return RETURN_SUCCESS; +} + +static RETURN_STATUS SNOR_EnableQE(struct SPI_NOR *nor) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + int regIndex; + int bitOffset; + UINT8 status; + + regIndex = nor->info->QEBits >> 3; + bitOffset = nor->info->QEBits & 0x7; + ret = SNOR_ReadStatus(nor, regIndex, &status); + if (ret != RETURN_SUCCESS) { + return ret; + } + + if (status & (1 << bitOffset)) { //is QE bit set + return RETURN_SUCCESS; + } + + status |= (1 << bitOffset); + ret = SNOR_WriteStatus(nor, regIndex, &status); + + return ret; +} + +/* Enable/disable 4-byte addressing mode. */ +static RETURN_STATUS SNOR_Enter4byte(struct SPI_NOR *nor) +{ + return SNOR_WriteReg(nor, SPINOR_OP_EN4B, NULL, 0); +} + +RETURN_STATUS SNOR_ReadSFDP(struct SPI_NOR *nor, UINT32 addr, UINT8 *data) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(SPINOR_OP_READ_SFDP, 1), + HAL_SPI_MEM_OP_ADDR(3, addr, 1), + HAL_SPI_MEM_OP_DUMMY(1, 1), + HAL_SPI_MEM_OP_DATA_IN(1, data, 1)); + + return HAL_FSPI_SpiXfer(nor->spi, &op); +} + +static void *SNOR_InfoAdjust(struct SPI_NOR *nor, struct FLASH_INFO *info) +{ + UINT32 addr; + UINT8 para; + + if (info->id == 0xc84019) { + addr = 0x09; + SNOR_ReadSFDP(nor, addr, ¶); + if (para == 0x06) { + info->QEBits = 9; + info->progCmd_4 = 0x34; + } + } + + return 0; +} + +/** + * @brief Flash continuous writing. + * @param nor: nor dev. + * @param from: byte address. + * @param buf: source address. + * @param len: number of bytes. + * @return If the transfer is successful, return the transfer length, or error code. + */ +RETURN_STATUS HAL_SNOR_ReadData(struct SPI_NOR *nor, UINT32 from, void *buf, UINT32 len) +{ + RETURN_STATUS ret; + UINT8 *pBuf = (UINT8 *)buf; + UINT32 size, remain = len; + + /* DEBUG ((DEBUG_SNOR, "%s from 0x%08lx, len %lx\n", __func__, from, len)); */ + if (from >= nor->size || len > nor->size || (from + len) > nor->size) { + return RETURN_DEVICE_ERROR; + } + + while (remain) { + size = MIN(READ_MAX_IOSIZE, remain); + ret = SNOR_ReadData(nor, from, size, pBuf); + if (ret != (RETURN_STATUS)size) { + DEBUG ((DEBUG_SNOR, "%s %lu ret= %ld\n", __func__, from >> 9, ret)); + + return ret; + } + remain -= size; + from += size; + pBuf += size; + } + + return len; +} + +/** + * @brief Flash continuous reading. + * @param nor: nor dev. + * @param to: byte address. + * @param buf: source address. + * @param len: number of bytes. + * @return If the transfer is successful, return the transfer length, or error code. + */ +RETURN_STATUS HAL_SNOR_ProgData(struct SPI_NOR *nor, UINT32 to, void *buf, UINT32 len) +{ + RETURN_STATUS ret; + UINT8 *pBuf = (UINT8 *)buf; + UINT32 size, remain = len, pageOffset; + + /* DEBUG ((DEBUG_SNOR, "%s to 0x%08lx, len %lx\n", __func__, to, len)); */ + if (to >= nor->size || len > nor->size || (to + len) > nor->size) { + return RETURN_DEVICE_ERROR; + } + + while (remain) { + pageOffset = to & (nor->pageSize - 1); + size = MIN(nor->pageSize - pageOffset, remain); + SNOR_WriteEnable(nor); + ret = SNOR_WriteData(nor, to, size, pBuf); + if (ret != (RETURN_STATUS)size) { + DEBUG ((DEBUG_SNOR, "%s %lu ret= %ld\n", __func__, to >> 9, ret)); + + return ret; + } + SNOR_WaitBusy(nor, 10000); + remain -= size; + to += size; + pBuf += size; + } + + return len; +} + +/** + * @brief Flash erase with erase type. + * @param nor: nor dev. + * @param addr: byte address. + * @param eraseType: erase type. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_SNOR_Erase(struct SPI_NOR *nor, UINT32 addr, NOR_ERASE_TYPE eraseType) +{ + RETURN_STATUS ret; + INT32 timeout[] = { 400, 2000, 40000 }; + + /* DEBUG ((DEBUG_SNOR, "%s addr %lx\n", __func__, addr)); */ + if (addr >= nor->size) { + return RETURN_DEVICE_ERROR; + } + + SNOR_WriteEnable(nor); + if (eraseType == ERASE_SECTOR) { + ret = SNOR_EraseSec(nor, addr); + } else if (eraseType == ERASE_BLOCK64K) { + ret = SNOR_EraseBlk(nor, addr); + } else { + ret = SNOR_EraseChip(nor, addr); + } + if (ret != RETURN_SUCCESS) { + return ret; + } + + return SNOR_WaitBusy(nor, timeout[eraseType] * 1000); +} + +/** + * @brief Flash continuous reading according to sectors. + * @param nor: nor dev. + * @param sec: sector address. + * @param nSec: number of sectors. + * @param pData: destination address. + * @return If the transfer is successful, return the transfer length, or error code. + */ +RETURN_STATUS HAL_SNOR_Read(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + + /* DEBUG ((DEBUG_SNOR, "%s sec 0x%08lx, nSec %lx\n", __func__, sec, nSec)); */ + ret = HAL_SNOR_ReadData(nor, sec * nor->sectorSize, pData, nSec * nor->sectorSize); + if (ret != (RETURN_STATUS)(nSec * nor->sectorSize)) { + return ret; + } + + return (RETURN_STATUS)nSec; +} + +/** + * @brief Flash continuous writing according to sectors. + * @param nor: nor dev. + * @param sec: sector address. + * @param nSec: number of sectors. + * @param pData: source address. + * @return If the transfer is successful, return the transfer length, or error code. + */ +RETURN_STATUS HAL_SNOR_Write(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + + /* DEBUG ((DEBUG_SNOR, "%s sec 0x%08lx, nSec %lx\n", __func__, sec, nSec)); */ + ret = HAL_SNOR_ProgData(nor, sec * nor->sectorSize, pData, nSec * nor->sectorSize); + if (ret != (RETURN_STATUS)(nSec * nor->sectorSize)) { + return ret; + } + + return (RETURN_STATUS)nSec; +} + +/** + * @brief Flash continuous writing according to sectors. + * @param nor: nor dev. + * @param sec: sector address. + * @param nSec: number of sectors. + * @param pData: source address. + * @return If the transfer is successful, return the transfer length, or error code. + */ +RETURN_STATUS HAL_SNOR_OverWrite(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + UINT8 *pBuf = (UINT8 *)pData; + UINT32 remaining = nSec; + + /* DEBUG ((DEBUG_SNOR, "%s sec 0x%08lx, nSec %lx\n", __func__, sec, nSec)); */ + while (remaining) { + ret = HAL_SNOR_Erase(nor, sec * nor->sectorSize, ERASE_SECTOR); + if (ret != RETURN_SUCCESS) { + return ret; + } + + ret = HAL_SNOR_ProgData(nor, sec * nor->sectorSize, (void *)pBuf, nor->sectorSize); + if (ret != (RETURN_STATUS)(nor->sectorSize)) { + return ret; + } + + pBuf += nor->sectorSize; + remaining--; + sec++; + } + + return (RETURN_STATUS)nSec; +} + +/** @} */ + +/** @defgroup SNOR_Exported_Functions_Group4 Init and DeInit Functions + + This section provides functions allowing to init and deinit the module: + + ...to do or delete this row + + * @{ + */ + +/** + * @brief SFC NOR flash module init. + * @param nor: nor dev. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_SNOR_Init(struct SPI_NOR *nor) +{ + UINT8 idByte[5]; + const struct FLASH_INFO *info; + INT32 ret = RETURN_SUCCESS; + + if (!nor->spi) { + DEBUG ((DEBUG_SNOR, "%a no host\n", __func__)); + + return RETURN_DEVICE_ERROR; + } + //nor->read = SNOR_ReadData; + //nor->write = SNOR_WriteData; + //nor->readReg = SNOR_ReadReg; + //nor->writeReg = SNOR_WriteReg; + + HAL_SNOR_ReadID(nor, idByte); + DEBUG ((DEBUG_SNOR, "SPI Nor ID: %x %x %x\n", idByte[0], idByte[1], idByte[2])); + + if ((idByte[0] == 0xFF) || (idByte[0] == 0x00)) { + return RETURN_DEVICE_ERROR; + } + + info = SNOR_GerFlashInfo(idByte); + if (!info) { + if (nor->spi->mode & HAL_SPI_RX_QUAD || + nor->spi->mode & HAL_SPI_TX_QUAD) { + return RETURN_NO_MEDIA; + } + s_commonSpiFlash.id = (idByte[0] << 16) | (idByte[1] << 8) | idByte[2]; + s_commonSpiFlash.density = idByte[2] - 9; + info = &s_commonSpiFlash; + } else { + SNOR_InfoAdjust(nor, (struct FLASH_INFO *)info); + } + + nor->info = info; + nor->pageSize = 256; + nor->addrWidth = 3; + nor->eraseOpcodeSec = info->sectorEraseCmd; + nor->eraseOpcodeBlk = info->blockEraseCmd; + nor->readOpcode = info->readCmd; + nor->readProto = SNOR_PROTO_1_1_1; + nor->readDummy = 0; + nor->programOpcode = info->progCmd; + nor->writeProto = SNOR_PROTO_1_1_1; + //nor->name = "spi-nor"; + nor->sectorSize = info->sectorSize * 512; + nor->size = 1 << (info->density + 9); + nor->eraseSize = nor->sectorSize; + if (nor->spi->mode & HAL_SPI_RX_QUAD) { + ret = RETURN_SUCCESS; + if (info->QEBits) { + ret = SNOR_EnableQE(nor); + } + if (ret == RETURN_SUCCESS) { + nor->readOpcode = info->readCmd_4; + switch (nor->readOpcode) { + case SPINOR_OP_READ_1_4_4: + nor->readDummy = 6; + nor->readProto = SNOR_PROTO_1_4_4; + break; + default: + nor->readDummy = 8; + nor->readProto = SNOR_PROTO_1_1_4; + break; + } + } + } else if (nor->spi->mode & HAL_SPI_RX_DUAL) { + nor->readOpcode = SPINOR_OP_READ_1_1_2; + nor->readDummy = 8; + nor->readProto = SNOR_PROTO_1_1_2; + } + if (nor->spi->mode & HAL_SPI_TX_QUAD && + info->QEBits) { + if (SNOR_EnableQE(nor) == RETURN_SUCCESS) { + nor->programOpcode = info->progCmd_4; + switch (nor->programOpcode) { + case SPINOR_OP_PP_1_4_4: + nor->writeProto = SNOR_PROTO_1_4_4; + break; + default: + nor->writeProto = SNOR_PROTO_1_1_4; + break; + } + } + } + if (info->feature & FEA_4BYTE_ADDR) { + nor->addrWidth = 4; + } + + if (info->feature & FEA_4BYTE_ADDR_MODE) { + SNOR_Enter4byte(nor); + } + + DEBUG ((DEBUG_SNOR, "nor->addrWidth: %x\n", nor->addrWidth)); + DEBUG ((DEBUG_SNOR, "nor->readProto: %x\n", nor->readProto)); + DEBUG ((DEBUG_SNOR, "nor->writeProto: %x\n", nor->writeProto)); + DEBUG ((DEBUG_SNOR, "nor->readCmd: %x\n", nor->readOpcode)); + DEBUG ((DEBUG_SNOR, "nor->programCmd: %x\n", nor->programOpcode)); + DEBUG ((DEBUG_SNOR, "nor->eraseOpcodeBlk: %x\n", nor->eraseOpcodeBlk)); + DEBUG ((DEBUG_SNOR, "nor->eraseOpcodeSec: %x\n", nor->eraseOpcodeSec)); + DEBUG ((DEBUG_SNOR, "nor->size: %ldMB\n", nor->size >> 20)); + DEBUG ((DEBUG_SNOR, "nor->size: %ldMB\n", nor->size >> 20)); + + return RETURN_SUCCESS; +} + +/** + * @brief SFC NOR flash module deinit. + * @param nor: nor dev. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_SNOR_DeInit(struct SPI_NOR *nor) +{ + return RETURN_SUCCESS; +} + +/** @} */ + +/** @defgroup SNOR_Exported_Functions_Group5 Other Functions + * @{ + */ + +/** + * @brief Read flash ID. + * @param nor: nor dev. + * @param data: address to storage flash ID value. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_SNOR_ReadID(struct SPI_NOR *nor, UINT8 *data) +{ + INT32 ret; + UINT8 *id = data; + + ret = SNOR_ReadReg(nor, SPINOR_OP_RDID, id, 3); + if (ret) { + DEBUG ((DEBUG_SNOR, "error reading JEDEC ID%x %x %x\n", id[0], id[1], id[2])); + + return RETURN_DEVICE_ERROR; + } + + return RETURN_SUCCESS; +} + +/** + * @brief Get flash capacity. + * @param nor: nor dev. + * @return UINT32: flash capacity, n bytes. + */ +UINT32 HAL_SNOR_GetCapacity(struct SPI_NOR *nor) +{ + return nor->size; +} + +/** + * @brief Check if the flash support. + * @param flashId: flash id. + * @return HAL_Check. + */ +BOOLEAN HAL_SNOR_IsFlashSupported(UINT8 *flashId) +{ + UINT32 i; + UINT32 id = (flashId[0] << 16) | (flashId[1] << 8) | (flashId[2] << 0); + + for (i = 0; i < ARRAY_SIZE(s_spiFlashbl); i++) { + if (s_spiFlashbl[i].id == id) { + return TRUE; + } + } + + return FALSE; +} + +RETURN_STATUS HAL_SNOR_ReadUUID(struct SPI_NOR *nor, void *buf) +{ + struct HAL_SPI_MEM_OP op = HAL_SPI_MEM_OP_FORMAT(HAL_SPI_MEM_OP_CMD(SPINOR_OP_READ_UUID, 1), + HAL_SPI_MEM_OP_ADDR(4, 0, 1), + HAL_SPI_MEM_OP_DUMMY(0, 1), + HAL_SPI_MEM_OP_DATA_IN(8, buf, 1)); + + return HAL_FSPI_SpiXfer(nor->spi, &op); +} + +EFI_STATUS Erase( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT32 ulLen + ) +{ + EFI_STATUS Status; + UINTN EraseSize; + + if (EfiAtRuntime ()) + NorFspiEnableClock(g_nor->spi->CruBase); + + EraseSize = g_nor->sectorSize; + + // Check input parameters + if (Offset % EraseSize || ulLen % EraseSize) { + DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length is not multiple of erase size\n")); + return EFI_DEVICE_ERROR; + } + + while (ulLen) { + Status = HAL_SNOR_Erase(g_nor, Offset, ERASE_SECTOR); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while erase target address\n")); + return Status; + } + Offset += EraseSize; + ulLen -= EraseSize; + } + return EFI_SUCCESS; +} + +UINT32 GetSize( + IN UNI_NOR_FLASH_PROTOCOL *This + ) +{ + return HAL_SNOR_GetCapacity(g_nor); +} + +EFI_STATUS Write( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT8 *Buffer, + UINT32 ulLen + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if (EfiAtRuntime ()) + NorFspiEnableClock(g_nor->spi->CruBase); + + //DEBUG ((DEBUG_ERROR, "[%a]:[%dL]: %x!......................\n", __FUNCTION__,__LINE__,Offset)); + Status = HAL_SNOR_ProgData(g_nor, Offset, Buffer, ulLen); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n")); + } + return Status; +} + +EFI_STATUS Read( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN OUT UINT8 *Buffer, + IN UINT32 ulLen + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if (EfiAtRuntime ()) + NorFspiEnableClock(g_nor->spi->CruBase); + + //DEBUG ((DEBUG_ERROR, "[%a]:[%dL]: %x!......................\n", __FUNCTION__,__LINE__,Offset)); + Status = HAL_SNOR_ReadData(g_nor, Offset, Buffer, ulLen); + return Status; +} + +STATIC +EFI_STATUS +SpiFlashUpdateBlock ( + IN UINT32 Offset, + IN UINT32 Align, + IN UINTN ToUpdate, + IN UINT8 *Buf, + IN UINT8 *TmpBuf, + IN UINTN EraseSize + ) +{ + + EFI_STATUS Status; + + if (EfiAtRuntime ()) + NorFspiEnableClock(g_nor->spi->CruBase); + + // Read backup + if (ToUpdate != EraseSize) { + Status = HAL_SNOR_ReadData (g_nor, Offset - Align, TmpBuf, EraseSize); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n")); + return Status; + } + } + // Erase entire sector + Status = HAL_SNOR_Erase (g_nor, Offset, ERASE_SECTOR); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n")); + return Status; + } + + if (Align) { + CopyMem (&TmpBuf[Align], Buf, ToUpdate); + Status = HAL_SNOR_ProgData (g_nor, Offset - Align, TmpBuf, EraseSize); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n")); + return Status; + } + return EFI_SUCCESS; + } + + // Write new data + Status = HAL_SNOR_ProgData (g_nor, Offset, Buf, ToUpdate); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n")); + return Status; + } + + // Write backup + if (ToUpdate != EraseSize) { + Status = HAL_SNOR_ProgData (g_nor, Offset + ToUpdate, &TmpBuf[ToUpdate], EraseSize - ToUpdate); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n")); + return Status; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS Update( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT8 *Buffer, + UINT32 ulLength + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT64 SectorSize, ToUpdate, Align, Scale = 1; + UINT8 *TmpBuf, *End; + //DEBUG ((DEBUG_ERROR, "[%a]:%x %x!......................\n", __FUNCTION__, Offset, ulLength)); + + SectorSize = g_nor->sectorSize; + Align = Offset & (SectorSize -1); + End = Buffer + ulLength; + + TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize); + if (TmpBuf == NULL) { + DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + if (End - Buffer >= 200) + Scale = (End - Buffer) / 100; + + for (; Buffer < End; Buffer += ToUpdate, Offset += ToUpdate) { + ToUpdate = MIN((UINT64)(End - Buffer), SectorSize); + Print (L" \rUpdating, %d%%", 100 - (End - Buffer) / Scale); + Status = SpiFlashUpdateBlock (Offset, Align, ToUpdate, Buffer, TmpBuf, SectorSize); + + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n")); + break; + } + } + + Print(L"\n"); + FreePool (TmpBuf); + + return Status; +} + +UNI_NOR_FLASH_PROTOCOL gUniNorFlash = { + GetSize, + Erase, + Write, + Read, + Update +}; + +#if 0 +#define maxest_sector 4 +static UINT32 pread32[maxest_sector * 4096 + 64]; +static UINT32 pwrite32[maxest_sector * 4096 + 64]; +#define FLASH_SKIP_LBA 0x100 /* About 1M space skip */ + +static RETURN_STATUS SNOR_STRESS_RANDOM_TEST(UINT32 testEndLBA) +{ + UINT32 ret, j; + UINT32 testCount, testLBA = 0; + UINT32 testSecCount = 1; + + DEBUG ((DEBUG_ERROR, "---------%a %lx---------\n", __func__, testEndLBA)); + DEBUG ((DEBUG_ERROR, "---------%a---------\n", __func__)); + for (j = 0; j < testSecCount * (UINT32)g_nor->sectorSize / 4; j++) + pwrite32[j] = j + (0xFFFF0000 - j); + + for (testCount = 0; testCount < testEndLBA;) { + testLBA = testCount; + pwrite32[0] = testLBA; + ret = HAL_SNOR_OverWrite(g_nor, testLBA, testSecCount, pwrite32); + if (ret != testSecCount) { + return RETURN_DEVICE_ERROR; + } + pread32[0] = -1; + ret = HAL_SNOR_Read(g_nor, testLBA, testSecCount, pread32); + if (ret != testSecCount) { + return RETURN_DEVICE_ERROR; + } + for (j = 0; j < testSecCount * (UINT32)g_nor->sectorSize / 4; j++) { + if (pwrite32[j] != pread32[j]) { + DEBUG ((DEBUG_ERROR, + "check not match:row=%lx, num=%lx, write=%lx, read=%lx %lx %lx %lx\n", + testLBA, j, pwrite32[j], pread32[j], pread32[j + 1], pread32[j + 2], pread32[j - 1])); + while (1) { + ; + } + } + } + DEBUG ((DEBUG_ERROR, "testCount= %lx testLBA= %lx\n", testCount, testLBA)); + testCount += testSecCount; + } + DEBUG ((DEBUG_ERROR, "---------%a SUCCESS---------\n", __func__)); + + return RETURN_SUCCESS; +} +#endif + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +STATIC +VOID +EFIAPI +NorVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // Convert SPI device description + EfiConvertPointer (0, (VOID**)&g_nor->spi->instance); + EfiConvertPointer (0, (VOID**)&g_nor->spi->CruBase); + EfiConvertPointer (0, (VOID**)&g_nor->spi); + EfiConvertPointer (0, (VOID**)&g_nor->info); + EfiConvertPointer (0, (VOID**)&g_nor); + + return; +} + + +EFI_STATUS +EFIAPI InitializeFlash ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status = RETURN_SUCCESS; + + g_spi = AllocateRuntimeZeroPool (sizeof (struct HAL_FSPI_HOST)); + g_nor = AllocateRuntimeZeroPool (sizeof (struct SPI_NOR)); + if (g_spi == NULL || g_nor == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + + g_spi->instance = (struct FSPI_REG *)FixedPcdGet32(FspiBaseAddr); + g_spi->CruBase = (UINT32 *)FixedPcdGet32(CruBaseAddr); + + NorFspiIomux(); + HAL_FSPI_Init(g_spi); + g_nor->spi = g_spi; + g_nor->spi->mode = HAL_SPI_MODE_3; + g_nor->spi->mode |= (HAL_SPI_TX_QUAD | HAL_SPI_RX_QUAD); + Status = HAL_SNOR_Init(g_nor); + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gUniNorFlashProtocolGuid, + EFI_NATIVE_INTERFACE, + &gUniNorFlash); + if(EFI_SUCCESS != Status) + { + DEBUG ((DEBUG_ERROR, "[%a]:[%dL]:Install Protocol Interface %r!\n", __FUNCTION__,__LINE__,Status)); + } + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + NorVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mNorVirtualAddrChangeEvent); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__)); + goto ErrorSetMemAttr; + } + + return Status; +ErrorSetMemAttr: + gBS->UninstallProtocolInterface (gImageHandle, + &gUniNorFlashProtocolGuid, + NULL); + + FreePool (g_nor); + FreePool (g_spi); + + return Status; + +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf new file mode 100644 index 0000000..0e37f34 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf @@ -0,0 +1,61 @@ +#/** @file +# +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = NorFlashDxe + FILE_GUID = ce7de226-ae7c-11ec-a154-f42a7dcb925d + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeFlash + +[Sources.common] + NorFlashDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + BaseLib + DebugLib + IoLib + SerialPortLib + ArmLib + CacheMaintenanceLib + UefiLib + PrintLib + PcdLib + TimerLib + DxeServicesTableLib + FspiLib + RockchipPlatformLib + + HobLib + UefiRuntimeLib + BaseMemoryLib + DevicePathLib + MemoryAllocationLib + UefiRuntimeServicesTableLib + +[Guids] + gEfiEventVirtualAddressChangeGuid +[Protocols] + gUniNorFlashProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.FspiBaseAddr + gRockchipTokenSpaceGuid.CruBaseAddr + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.c new file mode 100644 index 0000000..7e690a7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.c @@ -0,0 +1,219 @@ +/** @file +UEFI Component Name and Name2 protocol for OHCI driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = { + OhciComponentNameGetDriverName, + OhciComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = { + { "eng;en", L"Usb Ohci Driver" }, + { NULL, NULL } +}; + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mOhciDriverNameTable, + DriverName, + (BOOLEAN)(This == &gOhciComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *OhciDev; + EFI_USB_HC_PROTOCOL *UsbHc; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gOhciDriverBinding.DriverBindingHandle, + &gOhciDeviceProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHc, + gOhciDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc); + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + OhciDev->ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gOhciComponentName) + ); + +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.h new file mode 100644 index 0000000..c54cd63 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/ComponentName.h @@ -0,0 +1,141 @@ +/** @file +This file contains the delarations for componet name routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _COMPONENT_NAME_H_ +#define _COMPONENT_NAME_H_ + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OhciComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Descriptor.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Descriptor.h new file mode 100644 index 0000000..14a619b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Descriptor.h @@ -0,0 +1,132 @@ +/** @file +This file contains the descriptor definination of OHCI spec + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _DESCRIPTOR_H +#define _DESCRIPTOR_H + +#define ED_FUNC_ADD 0x0001 +#define ED_ENDPT_NUM 0x0002 +#define ED_DIR 0x0004 +#define ED_SPEED 0x0008 +#define ED_SKIP 0x0010 +#define ED_FORMAT 0x0020 +#define ED_MAX_PACKET 0x0040 +#define ED_TDTAIL_PTR 0x0080 +#define ED_HALTED 0x0100 +#define ED_DTTOGGLE 0x0200 +#define ED_TDHEAD_PTR 0x0400 +#define ED_NEXT_EDPTR 0x0800 +#define ED_PDATA 0x1000 +#define ED_ZERO 0x2000 + +#define TD_BUFFER_ROUND 0x0001 +#define TD_DIR_PID 0x0002 +#define TD_DELAY_INT 0x0004 +#define TD_DT_TOGGLE 0x0008 +#define TD_ERROR_CNT 0x0010 +#define TD_COND_CODE 0x0020 +#define TD_CURR_BUFFER_PTR 0x0040 +#define TD_NEXT_PTR 0x0080 +#define TD_BUFFER_END_PTR 0x0100 +#define TD_PDATA 0x0200 + +#define ED_FROM_TD_DIR 0x0 +#define ED_OUT_DIR 0x1 +#define ED_IN_DIR 0x2 +#define ED_FROM_TD_ALSO_DIR 0x3 + +#define TD_SETUP_PID 0x00 +#define TD_OUT_PID 0x01 +#define TD_IN_PID 0x02 +#define TD_NODATA_PID 0x03 + +#define HI_SPEED 0 +#define LO_SPEED 1 + +#define TD_NO_ERROR 0x00 +#define TD_CRC_ERROR 0x01 +#define TD_BITSTUFFING_ERROR 0x02 +#define TD_TOGGLE_ERROR 0x03 +#define TD_DEVICE_STALL 0x04 +#define TD_NO_RESPONSE 0x05 +#define TD_PIDCHK_FAIL 0x06 +#define TD_PID_UNEXPECTED 0x07 +#define TD_DATA_OVERRUN 0x08 +#define TD_DATA_UNDERRUN 0x09 +#define TD_BUFFER_OVERRUN 0x0C +#define TD_BUFFER_UNDERRUN 0x0D +#define TD_TOBE_PROCESSED 0x0E +#define TD_TOBE_PROCESSED_2 0x0F + +#define TD_NO_DELAY 0x7 + +#define TD_INT 0x1 +#define TD_CTL 0x2 +#define TD_BLK 0x3 + +typedef struct { + UINT32 Reserved:18; + UINT32 BufferRounding:1; + UINT32 DirPID:2; + UINT32 DelayInterrupt:3; + UINT32 DataToggle:2; + UINT32 ErrorCount:2; + UINT32 ConditionCode:4; +} TD_DESCRIPTOR_WORD0; + +typedef struct _TD_DESCRIPTOR { + TD_DESCRIPTOR_WORD0 Word0; + UINT32 CurrBufferPointer; // 32-bit Physical Address of buffer + UINT32 NextTD; // 32-bit Physical Address of TD_DESCRIPTOR + UINT32 BufferEndPointer; // 32-bit Physical Address of buffer + UINT32 NextTDPointer; // 32-bit Physical Address of TD_DESCRIPTOR + UINT32 DataBuffer; // 32-bit Physical Address of buffer + UINT32 ActualSendLength; + UINT32 Reserved; +} TD_DESCRIPTOR; + +typedef struct { + UINT32 FunctionAddress:7; + UINT32 EndPointNum:4; + UINT32 Direction:2; + UINT32 Speed:1; + UINT32 Skip:1; + UINT32 Format:1; + UINT32 MaxPacketSize:11; + UINT32 FreeSpace:5; +} ED_DESCRIPTOR_WORD0; + +typedef struct { + UINT32 Halted:1; + UINT32 ToggleCarry:1; + UINT32 Zero:2; + UINT32 TdHeadPointer:28; +} ED_DESCRIPTOR_WORD2; + +typedef struct _ED_DESCRIPTOR { + ED_DESCRIPTOR_WORD0 Word0; + UINT32 TdTailPointer; // 32-bit Physical Address of TD_DESCRIPTOR + ED_DESCRIPTOR_WORD2 Word2; + UINT32 NextED; // 32-bit Physical Address of ED_DESCRIPTOR +} ED_DESCRIPTOR; + +#define TD_PTR(p) ((TD_DESCRIPTOR *)(UINTN)((p) << 4)) +#define ED_PTR(p) ((ED_DESCRIPTOR *)(UINTN)((p) << 4)) +#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4) + +typedef enum { + CONTROL_LIST, + BULK_LIST, + INTERRUPT_LIST, + ISOCHRONOUS_LIST +} DESCRIPTOR_LIST_TYPE; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.c new file mode 100644 index 0000000..46956bb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.c @@ -0,0 +1,2416 @@ +/** @file +This file contains the implementation of Usb Hc Protocol. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +STATIC OHCI_DEVICE_PATH OhciDevicePathProtocol = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(OFFSET_OF (OHCI_DEVICE_PATH, End)), + (UINT8)(OFFSET_OF (OHCI_DEVICE_PATH, End) >> 8), + }, + }, + EFI_CALLER_ID_GUID + }, + 0, // Instance + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof(EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +/** + Provides software reset for the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. + + @retval EFI_SUCCESS The reset operation succeeded. + @retval EFI_INVALID_PARAMETER Attributes is not valid. + @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is + not currently supported by the host controller. + @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. + +**/ +EFI_STATUS +EFIAPI +OhciReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + UINT8 Index; + UINT8 NumOfPorts; + UINT32 PowerOnGoodTime; + UINT32 Data32; + BOOLEAN Flag = FALSE; + + if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) { + gBS->Stall (50 * 1000); + Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (50 * 1000); + // + // Wait for host controller reset. + // + PowerOnGoodTime = 50; + do { + gBS->Stall (1 * 1000); + Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + if ((Data32 & HC_RESET) == 0) { + Flag = TRUE; + break; + } + }while(PowerOnGoodTime--); + if (!Flag){ + return EFI_DEVICE_ERROR; + } + } + OhciFreeIntTransferMemory (Ohc); + Status = OhciInitializeInterruptList (Ohc); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) { + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (50 * 1000); + } + // + // Initialize host controller operational registers + // + OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + OhciSetPeriodicStart (Ohc, 0x2a2f); + OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3); + OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0); + OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0); + OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0); + //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1); + + OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0); + OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff); + OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE); + OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER); + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + for (Index = 0; Index < NumOfPorts; Index++) { + if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) { + gBS->Stall (200 * 1000); + OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset); + gBS->Stall (1000); + OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable); + gBS->Stall (1000); + } + } + OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock); + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/ + OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + gBS->Stall (50*1000); + // + // Wait till first SOF occurs, and then clear it + // + while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0); + OhciClearInterruptStatus (Ohc, START_OF_FRAME); + gBS->Stall (1000); + + return Status; +} + +/** + Retrieve the current state of the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State Variable to return the current host controller + state. + + @retval EFI_SUCCESS Host controller state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + @retval EFI_DEVICE_ERROR An error was encountered while attempting to + retrieve the host controller's current state. + +**/ + +EFI_STATUS +EFIAPI +OhciGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ) +{ + USB_OHCI_HC_DEV *Ohc; + UINT32 FuncState; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE); + + switch (FuncState) { + case HC_STATE_RESET: + case HC_STATE_RESUME: + *State = EfiUsbHcStateHalt; + break; + + case HC_STATE_OPERATIONAL: + *State = EfiUsbHcStateOperational; + break; + + case HC_STATE_SUSPEND: + *State = EfiUsbHcStateSuspend; + break; + + default: + ASSERT (FALSE); + } + return EFI_SUCCESS; +} + +/** + Sets the USB host controller to a specific state. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State The state of the host controller that will be set. + + @retval EFI_SUCCESS The USB host controller was successfully placed + in the state specified by State. + @retval EFI_INVALID_PARAMETER State is invalid. + @retval EFI_DEVICE_ERROR Failed to set the state due to device error. + +**/ + +EFI_STATUS +EFIAPI +OhciSetState( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + + Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); + + switch (State) { + case EfiUsbHcStateHalt: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + break; + + case EfiUsbHcStateOperational: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + break; + + case EfiUsbHcStateSuspend: + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND); + break; + + default: + Status = EFI_INVALID_PARAMETER; + } + + gBS->Stall (1000); + + return Status; +} + +/** + + Submits control transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPaketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Request A pointer to the USB device request that will be sent + to the USB device. + @param TransferDirection Specifies the data direction for the transfer. + There are three values available, DataIn, DataOut + and NoData. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TimeOut Indicates the maximum time, in microseconds, + which the transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_SUCCESS The control transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The control transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ + + +EFI_STATUS +EFIAPI +OhciControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *HeadEd; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *SetupTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *StatusTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT32 DataPidDir; + UINT32 StatusPidDir; + UINTN TimeCount; + OHCI_ED_RESULT EdResult; + + DMA_MAP_OPERATION MapOp; + + UINTN ActualSendLength; + UINTN LeftLength; + UINT8 DataToggle; + + VOID *ReqMapping = NULL; + UINTN ReqMapLength = 0; + EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0; + + VOID *DataMapping = NULL; + UINTN DataMapLength = 0; + EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0; + + HeadTd = NULL; + DataTd = NULL; + + if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn && + TransferDirection != EfiUsbNoData) || + Request == NULL || DataLength == NULL || TransferResult == NULL || + (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) || + (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) || + (IsSlowDevice && MaxPacketLength != 8) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + if (*DataLength > MAX_BYTES_PER_TD) { + DEBUG ((DEBUG_ERROR, "OhciControlTransfer: Request data size is too large\r\n")); + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS(This); + + if (TransferDirection == EfiUsbDataIn) { + DataPidDir = TD_IN_PID; + StatusPidDir = TD_OUT_PID; + } else { + DataPidDir = TD_OUT_PID; + StatusPidDir = TD_IN_PID; + } + + Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + gBS->Stall(20 * 1000); + + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n")); + goto CTRL_EXIT; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, 0); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL); + // + // Setup Stage + // + if(Request != NULL) { + ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST); + MapOp = MapOperationBusMasterRead; + Status = DmaMap (MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n")); + goto FREE_ED_BUFF; + } + } + SetupTd = OhciCreateTD (Ohc); + if (SetupTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n")); + goto UNMAP_SETUP_BUFF; + } + HeadTd = SetupTd; + OhciSetTDField (SetupTd, TD_PDATA, 0); + OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID); + OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2); + OhciSetTDField (SetupTd, TD_ERROR_CNT, 0); + OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr); + OhciSetTDField (SetupTd, TD_NEXT_PTR, 0); + OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1)); + SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST); + SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr; + SetupTd->NextTDPointer = 0; + + if (TransferDirection == EfiUsbDataIn) { + MapOp = MapOperationBusMasterWrite; + } else { + MapOp = MapOperationBusMasterRead; + } + DataMapLength = *DataLength; + if ((Data != NULL) && (DataMapLength != 0)) { + Status = DmaMap (MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n")); + goto FREE_TD_BUFF; + } + } + // + //Data Stage + // + LeftLength = DataMapLength; + ActualSendLength = DataMapLength; + DataToggle = 1; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)DataMapPhyAddr; + DataTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, DataTd); + DataToggle ^= 1; + DataMapPhyAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Status Stage + // + StatusTd = OhciCreateTD (Ohc); + if (StatusTd == NULL) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (StatusTd, TD_PDATA, 0); + OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir); + OhciSetTDField (StatusTd, TD_DELAY_INT, 7); + OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3); + OhciSetTDField (StatusTd, TD_ERROR_CNT, 0); + OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (StatusTd, TD_NEXT_PTR, 0); + OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0); + StatusTd->ActualSendLength = 0; + StatusTd->DataBuffer = 0; + StatusTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, StatusTd); + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UNMAP_DATA_BUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = 0; + EmptyTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + // + // For debugging, dump ED & TD buffer befor transferring + // + // + //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE); + // + OhciSetEDField (Ed, ED_SKIP, 0); + Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + goto UNMAP_DATA_BUFF; + } + Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + goto UNMAP_DATA_BUFF; + } + gBS->Stall(20 * 1000); + + + TimeCount = 0; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); + + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + gBS->Stall (1000); + TimeCount++; + Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult); + } + // + // For debugging, dump ED & TD buffer after transferring + // + //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE); + // + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + + if (EdResult.ErrorCode != TD_NO_ERROR) { + if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((DEBUG_ERROR, "Control pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((DEBUG_ERROR, "Control pipe broken\r\n")); + } + *DataLength = 0; + } else { + DEBUG ((DEBUG_INFO, "Control transfer successed\r\n")); + } + +UNMAP_DATA_BUFF: + OhciSetEDField (Ed, ED_SKIP, 1); + if (HeadEd == Ed) { + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + } else { + HeadEd->NextED = Ed->NextED; + } + if(DataMapping != NULL) { + DmaUnmap(DataMapping); + } + +FREE_TD_BUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + +UNMAP_SETUP_BUFF: + if(ReqMapping != NULL) { + DmaUnmap(ReqMapping); + } + +FREE_ED_BUFF: + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + +CTRL_EXIT: + return Status; +} + +/** + + Submits bulk transfer to a bulk endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an + endpoint direction of the target USB device. + Each endpoint address supports data transfer in + one direction except the control endpoint + (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents a bulk endpoint. + @param MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength When input, indicates the size, in bytes, of the data buffer + specified by Data. When output, indicates the actually + transferred data size. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the bulk transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The bulk transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The bulk transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +**/ + + +EFI_STATUS +EFIAPI +OhciBulkTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + ED_DESCRIPTOR *HeadEd; + ED_DESCRIPTOR *Ed; + UINT32 DataPidDir; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *EmptyTd; + EFI_STATUS Status; + UINT8 EndPointNum; + UINTN TimeCount; + OHCI_ED_RESULT EdResult; + + DMA_MAP_OPERATION MapOp; + VOID *Mapping; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS MapPyhAddr; + UINTN LeftLength; + UINTN ActualSendLength; + BOOLEAN FirstTD; + + Mapping = NULL; + MapLength = 0; + MapPyhAddr = 0; + LeftLength = 0; + Status = EFI_SUCCESS; + + if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || + *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || + (MaxPacketLength != 8 && MaxPacketLength != 16 && + MaxPacketLength != 32 && MaxPacketLength != 64)) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if ((EndPointAddress & 0x80) != 0) { + DataPidDir = TD_IN_PID; + MapOp = MapOperationBusMasterWrite; + } else { + DataPidDir = TD_OUT_PID; + MapOp = MapOperationBusMasterRead; + } + + EndPointNum = (EndPointAddress & 0xF); + EdResult.NextToggle = *DataToggle; + + Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n")); + *TransferResult = EFI_USB_ERR_SYSTEM; + return EFI_DEVICE_ERROR; + } + gBS->Stall(20 * 1000); + + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + return EFI_OUT_OF_RESOURCES; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, HI_SPEED); + OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA, 0); + OhciSetEDField (Ed, ED_ZERO, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); + + if(Data != NULL) { + MapLength = *DataLength; + Status = DmaMap (MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n")); + goto FREE_ED_BUFF; + } + } + // + //Data Stage + // + LeftLength = MapLength; + ActualSendLength = MapLength; + HeadTd = NULL; + FirstTD = TRUE; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + DEBUG ((DEBUG_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)MapPyhAddr; + DataTd->NextTDPointer = 0; + if (FirstTD) { + HeadTd = DataTd; + FirstTD = FALSE; + } else { + OhciLinkTD (HeadTd, DataTd); + } + *DataToggle ^= 1; + MapPyhAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + // + // Empty Stage + // + EmptyTd = OhciCreateTD (Ohc); + if (EmptyTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (EmptyTd, TD_PDATA, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptyTd, TD_DIR_PID, 0); + OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); + EmptyTd->Word0.DataToggle = 0; + OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptyTd, TD_COND_CODE, 0); + OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); + EmptyTd->ActualSendLength = 0; + EmptyTd->DataBuffer = 0; + EmptyTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptyTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd; + OhciAttachTDListToED (Ed, HeadTd); + + OhciSetEDField (Ed, ED_SKIP, 0); + Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); + if (EFI_ERROR(Status)) { + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n")); + goto FREE_OHCI_TDBUFF; + } + Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1); + if (EFI_ERROR(Status)) { + *TransferResult = EFI_USB_ERR_SYSTEM; + Status = EFI_DEVICE_ERROR; + DEBUG ((DEBUG_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n")); + goto FREE_OHCI_TDBUFF; + } + gBS->Stall(20 * 1000); + + TimeCount = 0; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); + while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { + gBS->Stall (1000); + TimeCount++; + Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult); + } + + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + + if (EdResult.ErrorCode != TD_NO_ERROR) { + if (EdResult.ErrorCode == TD_TOBE_PROCESSED) { + DEBUG ((DEBUG_ERROR, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); + } else { + DEBUG ((DEBUG_ERROR, "Bulk pipe broken\r\n")); + *DataToggle = EdResult.NextToggle; + } + *DataLength = 0; + } else { + DEBUG ((DEBUG_INFO, "Bulk transfer successed\r\n")); + } + //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); + +FREE_OHCI_TDBUFF: + OhciSetEDField (Ed, ED_SKIP, 1); + if (HeadEd == Ed) { + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + }else { + HeadEd->NextED = Ed->NextED; + } + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + + if(Mapping != NULL) { + DmaUnmap(Mapping); + } + +FREE_ED_BUFF: + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return Status; +} +/** + + Submits an interrupt transfer to an interrupt endpoint of a USB device. + + @param Ohc Device private data + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param UCBuffer Uncacheable buffer + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + @param IsPeriodic Periodic interrupt or not + @param OutputED The correspoding ED carried out + @param OutputTD The correspoding TD carried out + + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + +EFI_STATUS +OhciInterruptTransfer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN VOID *UCBuffer OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL, + IN BOOLEAN IsPeriodic OPTIONAL, + OUT ED_DESCRIPTOR **OutputED OPTIONAL, + OUT TD_DESCRIPTOR **OutputTD OPTIONAL + ) +{ + ED_DESCRIPTOR *Ed; + UINT8 EdDir; + ED_DESCRIPTOR *HeadEd; + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *EmptTd; + UINTN Depth; + UINTN Index; + EFI_STATUS Status; + UINT8 EndPointNum; + UINT32 DataPidDir; + INTERRUPT_CONTEXT_ENTRY *Entry; + EFI_TPL OldTpl; + BOOLEAN FirstTD; + + VOID *Mapping; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS MapPyhAddr; + UINTN LeftLength; + UINTN ActualSendLength; + + if (DataLength > MAX_BYTES_PER_TD) { + DEBUG ((DEBUG_ERROR, "OhciInterruptTransfer: Error param\r\n")); + return EFI_INVALID_PARAMETER; + } + + if ((EndPointAddress & 0x80) != 0) { + EdDir = ED_IN_DIR; + DataPidDir = TD_IN_PID; + } else { + EdDir = ED_OUT_DIR; + DataPidDir = TD_OUT_PID; + } + + EndPointNum = (EndPointAddress & 0xF); + if (!IsNewTransfer) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0); + OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle); + Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum); + OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); + gBS->RestoreTPL (OldTpl); + return Status; + } + MapLength = DataLength; + Status = DmaMap( + MapOperationBusMasterWrite, + UCBuffer, + &MapLength, + &MapPyhAddr, + &Mapping + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "OhciInterruptTransfer: Fail to Map buffer \r\n")); + goto EXIT; + } + Depth = 5; + Index = 1; + while (PollingInterval >= Index * 2 && Depth > 0) { + Index *= 2; + Depth--; + } + // + //ED Stage + // + HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth); + if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) { + OhciSetEDField (Ed, ED_SKIP, 1); + } else { + Ed = OhciCreateED (Ohc); + if (Ed == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n")); + goto UNMAP_OHCI_XBUFF; + } + OhciSetEDField (Ed, ED_SKIP, 1); + OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); + OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); + OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); + OhciSetEDField (Ed, ED_SPEED, IsSlowDevice); + OhciSetEDField (Ed, ED_FORMAT, 0); + OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); + OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0); + OhciSetEDField (Ed, ED_TDHEAD_PTR, 0); + OhciSetEDField (Ed, ED_TDTAIL_PTR, 0); + OhciSetEDField (Ed, ED_NEXT_EDPTR, 0); + OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd); + } + // + //Data Stage + // + LeftLength = MapLength; + ActualSendLength = MapLength; + HeadTd = NULL; + FirstTD = TRUE; + while (LeftLength > 0) { + ActualSendLength = LeftLength; + if (LeftLength > MaxPacketLength) { + ActualSendLength = MaxPacketLength; + } + DataTd = OhciCreateTD (Ohc); + if (DataTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (DataTd, TD_PDATA, 0); + OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); + OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); + OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); + OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle); + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); + OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1)); + OhciSetTDField (DataTd, TD_NEXT_PTR, 0); + DataTd->ActualSendLength = (UINT32)ActualSendLength; + DataTd->DataBuffer = (UINT32)(UINTN)MapPyhAddr; + DataTd->NextTDPointer = 0; + if (FirstTD) { + HeadTd = DataTd; + FirstTD = FALSE; + } else { + OhciLinkTD (HeadTd, DataTd); + } + *DataToggle ^= 1; + MapPyhAddr += ActualSendLength; + LeftLength -= ActualSendLength; + } + + EmptTd = OhciCreateTD (Ohc); + if (EmptTd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n")); + goto FREE_OHCI_TDBUFF; + } + OhciSetTDField (EmptTd, TD_PDATA, 0); + OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0); + OhciSetTDField (EmptTd, TD_DIR_PID, 0); + OhciSetTDField (EmptTd, TD_DELAY_INT, 0); + //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle); + EmptTd->Word0.DataToggle = 0; + OhciSetTDField (EmptTd, TD_ERROR_CNT, 0); + OhciSetTDField (EmptTd, TD_COND_CODE, 0); + OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0); + OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0); + OhciSetTDField (EmptTd, TD_NEXT_PTR, 0); + EmptTd->ActualSendLength = 0; + EmptTd->DataBuffer = 0; + EmptTd->NextTDPointer = 0; + OhciLinkTD (HeadTd, EmptTd); + Ed->TdTailPointer = (UINT32)(UINTN)EmptTd; + OhciAttachTDListToED (Ed, HeadTd); + + if (OutputED != NULL) { + *OutputED = Ed; + } + if (OutputTD != NULL) { + *OutputTD = HeadTd; + } + + if (CallBackFunction != NULL) { + Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY)); + if (Entry == NULL) { + goto FREE_OHCI_TDBUFF; + } + + Entry->DeviceAddress = DeviceAddress; + Entry->EndPointAddress = EndPointAddress; + Entry->Ed = Ed; + Entry->DataTd = HeadTd; + Entry->IsSlowDevice = IsSlowDevice; + Entry->MaxPacketLength = MaxPacketLength; + Entry->PollingInterval = PollingInterval; + Entry->CallBackFunction = CallBackFunction; + Entry->Context = Context; + Entry->IsPeriodic = IsPeriodic; + Entry->UCBuffer = UCBuffer; + Entry->UCBufferMapping = Mapping; + Entry->DataLength = DataLength; + Entry->Toggle = DataToggle; + Entry->NextEntry = NULL; + OhciAddInterruptContextEntry (Ohc, Entry); + } + OhciSetEDField (Ed, ED_SKIP, 0); + + if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) { + Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1); + gBS->Stall (1000); + } + + return EFI_SUCCESS; + +FREE_OHCI_TDBUFF: + while (HeadTd) { + DataTd = HeadTd; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); + } + +//FREE_OHCI_EDBUFF: + if ((HeadEd != Ed) && HeadEd && Ed) { + while(HeadEd->NextED != (UINT32)(UINTN)Ed) { + HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED); + } + HeadEd->NextED = Ed->NextED; + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + } + +UNMAP_OHCI_XBUFF: + DmaUnmap(Mapping); + +EXIT: + return Status; +} + + +/** + + Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxiumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + + +EFI_STATUS +EFIAPI +OhciAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL + ) +{ + EFI_STATUS Status; + USB_OHCI_HC_DEV *Ohc; + VOID *UCBuffer; + UINTN Pages; + if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 || + (IsNewTransfer && (DataLength == 0 || + (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if ( IsNewTransfer ) { + Pages = EFI_SIZE_TO_PAGES (DataLength); + Status = DmaAllocateBuffer ( + EfiBootServicesData, + Pages, + &UCBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + } else { + UCBuffer = NULL; + } + + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + IsNewTransfer, + DataToggle, + PollingInterval, + UCBuffer, + DataLength, + CallBackFunction, + Context, + TRUE, + NULL, + NULL + ); + + if ( UCBuffer ) { + if (EFI_ERROR(Status)) { + DmaFreeBuffer (Pages, UCBuffer); + } + } + return Status; +} + + +/** + + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint + address supports data transfer in one direction + except the control endpoint (whose default + endpoint address is 0). It is the caller's responsibility + to make sure that the EndPointAddress represents + an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength On input, the size, in bytes, of the data buffer specified + by Data. On output, the number of bytes transferred. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the synchronous interrupt + transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent synchronous interrupt transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information from + the synchronous interrupt transfer. + + @retval EFI_UNSUPPORTED This interface not available. + @retval EFI_INVALID_PARAMETER Parameters not follow spec + +**/ + + +EFI_STATUS +EFIAPI +OhciSyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *HeadTd; + OHCI_ED_RESULT EdResult; + VOID *UCBuffer; + + if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 || + (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) || + DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + UCBuffer = AllocatePool (*DataLength); + if (UCBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + TRUE, + DataToggle, + 1, + UCBuffer, + *DataLength, + NULL, + NULL, + FALSE, + &Ed, + &HeadTd + ); + + if (!EFI_ERROR (Status)) { + Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); + while (Status == EFI_NOT_READY && TimeOut > 0) { + gBS->Stall (1000); + TimeOut--; + Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult); + } + + *TransferResult = ConvertErrorCode (EdResult.ErrorCode); + } + CopyMem(Data, UCBuffer, *DataLength); + Status = OhciInterruptTransfer ( + Ohc, + DeviceAddress, + EndPointAddress, + IsSlowDevice, + MaxPacketLength, + FALSE, + DataToggle, + 0, + NULL, + 0, + NULL, + NULL, + FALSE, + NULL, + NULL + ); + + return Status; +} +/** + + Submits isochronous transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL + +**/ + + +EFI_STATUS +EFIAPI +OhciIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + OUT UINT32 *TransferResult + ) +{ + if (Data == NULL || DataLength == 0 || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + +/** + + Submits Async isochronous transfer to a target USB device. + + @param his A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param IsochronousCallBack When the transfer complete, the call back function will be called + @param Context Pass to the call back function as parameter + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 + +**/ + +EFI_STATUS +EFIAPI +OhciAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ) +{ + + if (Data == NULL || DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + +/** + + Retrieves the number of root hub ports. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param NumOfPorts A pointer to the number of the root hub ports. + + @retval EFI_SUCCESS The port number was retrieved successfully. +**/ +EFI_STATUS +EFIAPI +OhciGetRootHubNumOfPorts ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *NumOfPorts + ) +{ + USB_OHCI_HC_DEV *Ohc; + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + if (NumOfPorts == NULL) { + return EFI_INVALID_PARAMETER; + } + + *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); + + return EFI_SUCCESS; +} +/** + + Retrieves the current status of a USB root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port from which the status + is to be retrieved. This value is zero-based. For example, + if a root hub has two ports, then the first port is numbered 0, + and the second port is numbered 1. + @param PortStatus A pointer to the current port status bits and + port status change bits. + + @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber + was returned in PortStatus. + @retval EFI_INVALID_PARAMETER Port number not valid +**/ + + +EFI_STATUS +EFIAPI +OhciGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ) +{ + USB_OHCI_HC_DEV *Ohc; + UINT8 NumOfPorts; + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) { + PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_RESET; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) { + PortStatus->PortStatus |= USB_PORT_STAT_POWER; + } + if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) { + PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT; + } + if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) { + PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET; + } + + return EFI_SUCCESS; +} +/** + + Sets a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port whose feature + is requested to be set. + @param PortFeature Indicates the feature selector associated + with the feature set request. + + @retval EFI_SUCCESS The feature specified by PortFeature was set for the + USB root hub port specified by PortNumber. + @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. +**/ +EFI_STATUS +EFIAPI +OhciSetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + Status = EFI_SUCCESS; + + + switch (PortFeature) { + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 || + OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + + OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + break; + + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + + Clears a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param PortNumber Specifies the root hub port whose feature + is requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the + USB root hub port specified by PortNumber. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @retval EFI_DEVICE_ERROR Some error happened when clearing feature +**/ +EFI_STATUS +EFIAPI +OhciClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + UINT8 NumOfPorts; + UINTN RetryTimes; + + + OhciGetRootHubNumOfPorts (This, &NumOfPorts); + if (PortNumber >= NumOfPorts) { + return EFI_INVALID_PARAMETER; + } + + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + Status = EFI_SUCCESS; + + switch (PortFeature) { + case EfiUsbPortEnable: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspend: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortReset: + break; + + case EfiUsbPortPower: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortConnectChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortResetChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + + case EfiUsbPortEnableChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortSuspendChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + case EfiUsbPortOverCurrentChange: + Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE); + + // + // Verify the state + // + RetryTimes = 0; + do { + gBS->Stall (1000); + RetryTimes++; + } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 && + RetryTimes < MAX_RETRY_TIMES); + + if (RetryTimes >= MAX_RETRY_TIMES) { + return EFI_DEVICE_ERROR; + } + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return Status; +} + + +EFI_STATUS +OhcInitHC ( +IN USB_OHCI_HC_DEV *Ohc +) +{ +EFI_STATUS Status; +UINT8 Index; +UINT8 NumOfPorts; +UINT32 PowerOnGoodTime; +UINT32 Data32; +BOOLEAN Flag = FALSE; + + Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->Stall (50 * 1000); + // + // Wait for host controller reset. + // + PowerOnGoodTime = 50; + do { + gBS->Stall(1000); + Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS ); + if ((Data32 & HC_RESET) == 0) { + Flag = TRUE; + break; + } + }while(PowerOnGoodTime--); + if (!Flag){ + return EFI_DEVICE_ERROR; + } + OhciInitializeInterruptList(Ohc); + + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + gBS->Stall (50 * 1000); + // + // Initialize host controller operational registers + // + OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778); + OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf); + OhciSetPeriodicStart (Ohc, 0x2a2f); + OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3); + OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0); + OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0); + OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1); + + OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0); + OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff); + OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE); + OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER); + NumOfPorts = OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS); + + for (Index = 0; Index < NumOfPorts; Index++) { + if (!EFI_ERROR (OhciSetRootHubPortFeature (&Ohc->UsbHc, Index, EfiUsbPortReset))) { + gBS->Stall (200 * 1000); + OhciClearRootHubPortFeature (&Ohc->UsbHc, Index, EfiUsbPortReset); + gBS->Stall (1000); + OhciSetRootHubPortFeature (&Ohc->UsbHc, Index, EfiUsbPortEnable); + gBS->Stall (1000); + } + } + + OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock); + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL); + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); + OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL); + + // + // Wait till first SOF occurs, and then clear it + // + while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0); + OhciClearInterruptStatus (Ohc, START_OF_FRAME); + gBS->Stall (1000); + + return EFI_SUCCESS; +} + + +/** + + Free the OHCI device and release its associated resources. + + @param Ohc The OHCI device to release. + +**/ +VOID +OhciFreeDev ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + OhciFreeFixedIntMemory (Ohc); + + if (Ohc->HouseKeeperTimer != NULL) { + gBS->CloseEvent (Ohc->HouseKeeperTimer); + } + + if (Ohc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Ohc->ExitBootServiceEvent); + } + + if (Ohc->MemPool != NULL) { + UsbHcFreeMemPool (Ohc->MemPool); + } + + if (Ohc->HccaMemoryMapping != NULL ) { + + DmaFreeBuffer (Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf); + } + + if (Ohc->ControllerNameTable != NULL) { + FreeUnicodeStringTable (Ohc->ControllerNameTable); + } + + FreePool (Ohc); +} +/** + + Uninstall all Ohci Interface. + + @param Controller Controller handle. + @param This Protocol instance pointer. + +**/ +VOID +OhciCleanDevUp ( + IN EFI_HANDLE Controller, + IN EFI_USB_HC_PROTOCOL *This + ) +{ + USB_OHCI_HC_DEV *Ohc; + + // + // Retrieve private context structure + // + Ohc = USB_OHCI_HC_DEV_FROM_THIS (This); + + // + // Uninstall the USB_HC and USB_HC2 protocol + // + gBS->UninstallProtocolInterface ( + Controller, + &gEfiUsbHcProtocolGuid, + &Ohc->UsbHc + ); + + // + // Cancel the timer event + // + gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0); + + // + // Stop the host controller + // + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); + This->Reset (This, EFI_USB_HC_RESET_GLOBAL); + This->SetState (This, EfiUsbHcStateHalt); + + // + // Free resources + // + OhciFreeDynamicIntMemory (Ohc); + + // + // Free the private context structure + // + OhciFreeDev (Ohc); +} + +/** + + One notified function to stop the Host Controller when gBS->ExitBootServices() called. + + @param Event Pointer to this event + @param Context Event handler private data +**/ +VOID +EFIAPI +OhcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_USB_HC_PROTOCOL *UsbHc; + Ohc = (USB_OHCI_HC_DEV *) Context; + + UsbHc = &Ohc->UsbHc; + // + // Stop the Host Controller + // + //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT); + OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0); + UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL); + UsbHc->SetState (UsbHc, EfiUsbHcStateHalt); + + return; +} + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has UsbHcProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + OHCI_DEVICE_PROTOCOL *Dev; + EFI_STATUS Status; + + // + // Connect to the non-discoverable device + // + Status = gBS->OpenProtocol (ControllerHandle, + &gOhciDeviceProtocolGuid, + (VOID **)&Dev, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clean up. + // + gBS->CloseProtocol (ControllerHandle, + &gOhciDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); + + return EFI_SUCCESS; +} + +/** + + Allocate and initialize the empty OHCI device. + + @param OriginalPciAttributes The original PCI attributes. + + @return Allocated OHCI device If err, return NULL. + +**/ + +EFI_STATUS +EFIAPI +OHCIDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + USB_OHCI_HC_DEV *Ohc; + EFI_STATUS Status; + VOID *Buf; + EFI_PHYSICAL_ADDRESS PhyAddr; + VOID *Map; + UINTN Pages; + UINTN Bytes; + + Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV)); + if (Ohc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->OpenProtocol (ControllerHandle, + &gOhciDeviceProtocolGuid, + (VOID **)&Ohc->Protocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Couldn't open protocol: %r\n", __FUNCTION__, Status)); + goto FREE_OHC; + } + + Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE; + + Ohc->UsbHc.Reset = OhciReset; + Ohc->UsbHc.GetState = OhciGetState; + Ohc->UsbHc.SetState = OhciSetState; + Ohc->UsbHc.ControlTransfer = OhciControlTransfer; + Ohc->UsbHc.BulkTransfer = OhciBulkTransfer; + Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer; + Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer; + Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer; + Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer; + Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts; + Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus; + Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature; + Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature; + Ohc->UsbHc.MajorRevision = 0x1; + Ohc->UsbHc.MinorRevision = 0x1; + Ohc->UsbHcBaseAddress = Ohc->Protocol->BaseAddress; + Ohc->HccaMemoryBlock = NULL; + Ohc->HccaMemoryMapping = NULL; + Ohc->HccaMemoryBuf = NULL; + Ohc->HccaMemoryPages = 0; + Ohc->InterruptContextList = NULL; + Ohc->ControllerNameTable = NULL; + Ohc->HouseKeeperTimer = NULL; + + Ohc->MemPool = UsbHcInitMemPool(TRUE, 0); + if(Ohc->MemPool == NULL) { + goto FREE_DEV_BUFFER; + } + + Bytes = 4096; + Pages = EFI_SIZE_TO_PAGES (Bytes); + + Status = DmaAllocateBuffer ( + EfiBootServicesData, + Pages, + &Buf + ); + + if (EFI_ERROR (Status)) { + goto FREE_MEM_POOL; + } + + Status = DmaMap ( + MapOperationBusMasterCommonBuffer, + Buf, + &Bytes, + &PhyAddr, + &Map + ); + + if (EFI_ERROR (Status) || (Bytes != 4096)) { + goto FREE_MEM_PAGE; + } + + Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr; + Ohc->HccaMemoryMapping = Map; + Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf; + Ohc->HccaMemoryPages = Pages; + + // + //Install Host Controller Protocol + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbHcProtocolGuid, + EFI_NATIVE_INTERFACE, + &Ohc->UsbHc + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Install protocol error")); + goto FREE_OHC; + } + + // + // Create event to stop the HC on exit boot services. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OhcExitBootService, + Ohc, + &gEfiEventExitBootServicesGuid, + &Ohc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Create exit boot event error")); + goto UNINSTALL_USBHC; + } + + // + // Set 0.01 s timer + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OhciHouseKeeper, + Ohc, + &Ohc->HouseKeeperTimer + ); + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + + Status = OhcInitHC (Ohc); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "failed to init ohci host controller\n")); + goto UNINSTALL_USBHC; + } + + Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10); + if (EFI_ERROR (Status)) { + goto FREE_OHC; + } + DEBUG ((DEBUG_INFO, "OHCI started for controller @ %p, base address: 0x%p\n", + ControllerHandle, Ohc->UsbHcBaseAddress)); + return EFI_SUCCESS; + +FREE_OHC: + OhciFreeDev (Ohc); +UNINSTALL_USBHC: + gBS->UninstallMultipleProtocolInterfaces ( + ControllerHandle, + &gEfiUsbHcProtocolGuid, + &Ohc->UsbHc, + NULL + ); + gBS->CloseProtocol (ControllerHandle, + &gOhciDeviceProtocolGuid, + This->DriverBindingHandle, + ControllerHandle); +FREE_MEM_PAGE: + DmaFreeBuffer (Pages, Buf); +FREE_MEM_POOL: + UsbHcFreeMemPool (Ohc->MemPool); +FREE_DEV_BUFFER: + FreePool(Ohc); + + return Status; +} + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_USB_HC_PROTOCOL *UsbHc; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **)&UsbHc, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + OhciCleanDevUp(Controller, UsbHc); + + gBS->CloseProtocol ( + Controller, + &gOhciDeviceProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; +} + +EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = { + OHCIDriverBindingSupported, + OHCIDriverBindingStart, + OHCIDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +OhciInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOhciDriverBinding, + ImageHandle, + &gOhciComponentName, + &gOhciComponentName2 + ); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.h new file mode 100644 index 0000000..06a2b33 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/Ohci.h @@ -0,0 +1,668 @@ +/** @file +Provides the definition of Usb Hc Protocol and OHCI controller +private data structure. + +Copyright (c) 2013-2016 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_H +#define _OHCI_H + + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV; + +#include "UsbHcMem.h" +#include "OhciReg.h" +#include "OhciSched.h" +#include "OhciUrb.h" +#include "Descriptor.h" +#include "OhciDebug.h" +#include "ComponentName.h" + +extern EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2; + +#define USB_OHCI_HC_DEV_SIGNATURE SIGNATURE_32('o','h','c','i') + +typedef struct _HCCA_MEMORY_BLOCK{ + UINT32 HccaInterruptTable[32]; // 32-bit Physical Address to ED_DESCRIPTOR + UINT16 HccaFrameNumber; + UINT16 HccaPad; + UINT32 HccaDoneHead; // 32-bit Physical Address to TD_DESCRIPTOR + UINT8 Reserved[116]; +} HCCA_MEMORY_BLOCK; + +typedef struct { + VENDOR_DEVICE_PATH Guid; + UINTN Instance; + EFI_DEVICE_PATH_PROTOCOL End; +} OHCI_DEVICE_PATH; + +struct _USB_OHCI_HC_DEV { + UINTN Signature; + EFI_USB_HC_PROTOCOL UsbHc; + EFI_USB2_HC_PROTOCOL Usb2Hc; + UINT32 UsbHcBaseAddress; + HCCA_MEMORY_BLOCK *HccaMemoryBlock; + VOID *HccaMemoryBuf; + VOID *HccaMemoryMapping; + UINTN HccaMemoryPages; + ED_DESCRIPTOR *IntervalList[6][32]; + INTERRUPT_CONTEXT_ENTRY *InterruptContextList; + VOID *MemPool; + + UINT32 ToggleFlag; + + EFI_EVENT HouseKeeperTimer; + // + // ExitBootServicesEvent is used to stop the OHC DMA operation + // after exit boot service. + // + EFI_EVENT ExitBootServiceEvent; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + OHCI_DEVICE_PROTOCOL *Protocol; +}; + +#define USB_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, UsbHc, USB_OHCI_HC_DEV_SIGNATURE) + +// +// Func List +// + +/** + Provides software reset for the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param Attributes A bit mask of the reset operation to perform. + + @retval EFI_SUCCESS The reset operation succeeded. + @retval EFI_INVALID_PARAMETER Attributes is not valid. + @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is + not currently supported by the host controller. + @retval EFI_DEVICE_ERROR Host controller isn't halted to reset. + +**/ +EFI_STATUS +EFIAPI +OhciReset ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 Attributes + ); +/** + Retrieve the current state of the USB host controller. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State Variable to return the current host controller + state. + + @retval EFI_SUCCESS Host controller state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + @retval EFI_DEVICE_ERROR An error was encountered while attempting to + retrieve the host controller's current state. + +**/ + +EFI_STATUS +EFIAPI +OhciGetState ( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State + ); +/** + Sets the USB host controller to a specific state. + + @param This This EFI_USB_HC_PROTOCOL instance. + @param State The state of the host controller that will be set. + + @retval EFI_SUCCESS The USB host controller was successfully placed + in the state specified by State. + @retval EFI_INVALID_PARAMETER State is invalid. + @retval EFI_DEVICE_ERROR Failed to set the state due to device error. + +**/ + +EFI_STATUS +EFIAPI +OhciSetState( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State + ); +/** + + Submits control transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPaketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Request A pointer to the USB device request that will be sent + to the USB device. + @param TransferDirection Specifies the data direction for the transfer. + There are three values available, DataIn, DataOut + and NoData. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TimeOut Indicates the maximum time, in microseconds, + which the transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_SUCCESS The control transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The control transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +--*/ + + +EFI_STATUS +EFIAPI +OhciControlTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data OPTIONAL, + IN OUT UINTN *DataLength OPTIONAL, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); +/** + + Submits bulk transfer to a bulk endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an + endpoint direction of the target USB device. + Each endpoint address supports data transfer in + one direction except the control endpoint + (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents a bulk endpoint. + @param MaximumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength When input, indicates the size, in bytes, of the data buffer + specified by Data. When output, indicates the actually + transferred data size. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the bulk transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent bulk transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + TransferResult A pointer to the detailed result information of the + bulk transfer. + + @retval EFI_SUCCESS The bulk transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT The bulk transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error. + Caller should check TranferResult for detailed error information. + +**/ + + +EFI_STATUS +EFIAPI +OhciBulkTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); +/** + + Submits an interrupt transfer to an interrupt endpoint of a USB device. + + @param Ohc Device private data + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param UCBuffer Uncacheable buffer + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + @param IsPeriodic Periodic interrupt or not + @param OutputED The correspoding ED carried out + @param OutputTD The correspoding TD carried out + + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + +EFI_STATUS +OhciInterruptTransfer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN VOID *UCBuffer OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL, + IN BOOLEAN IsPeriodic OPTIONAL, + OUT ED_DESCRIPTOR **OutputED OPTIONAL, + OUT TD_DESCRIPTOR **OutputTD OPTIONAL + ); +/** + + Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint address + supports data transfer in one direction except the + control endpoint (whose default endpoint address is 0). + It is the caller's responsibility to make sure that + the EndPointAddress represents an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxiumPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between + the host and the target interrupt endpoint. + If FALSE, the specified asynchronous interrupt pipe + is canceled. + @param DataToggle A pointer to the data toggle value. On input, it is valid + when IsNewTransfer is TRUE, and it indicates the initial + data toggle value the asynchronous interrupt transfer + should adopt. + On output, it is valid when IsNewTransfer is FALSE, + and it is updated to indicate the data toggle value of + the subsequent asynchronous interrupt transfer. + @param PollingInterval Indicates the interval, in milliseconds, that the + asynchronous interrupt transfer is polled. + This parameter is required when IsNewTransfer is TRUE. + @param DataLength Indicates the length of data to be received at the + rate specified by PollingInterval from the target + asynchronous interrupt endpoint. This parameter + is only required when IsNewTransfer is TRUE. + @param CallBackFunction The Callback function.This function is called at the + rate specified by PollingInterval.This parameter is + only required when IsNewTransfer is TRUE. + @param Context The context that is passed to the CallBackFunction. + This is an optional parameter and may be NULL. + + @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully + submitted or canceled. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ + + +EFI_STATUS +EFIAPI +OhciAsyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle OPTIONAL, + IN UINTN PollingInterval OPTIONAL, + IN UINTN DataLength OPTIONAL, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL, + IN VOID *Context OPTIONAL + ); +/** + + Submits synchronous interrupt transfer to an interrupt endpoint + of a USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress The combination of an endpoint number and an endpoint + direction of the target USB device. Each endpoint + address supports data transfer in one direction + except the control endpoint (whose default + endpoint address is 0). It is the caller's responsibility + to make sure that the EndPointAddress represents + an interrupt endpoint. + @param IsSlowDevice Indicates whether the target device is slow device + or full-speed device. + @param MaxPacketLength Indicates the maximum packet size the target endpoint + is capable of sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength On input, the size, in bytes, of the data buffer specified + by Data. On output, the number of bytes transferred. + @param DataToggle A pointer to the data toggle value. On input, it indicates + the initial data toggle value the synchronous interrupt + transfer should adopt; + on output, it is updated to indicate the data toggle value + of the subsequent synchronous interrupt transfer. + @param TimeOut Indicates the maximum time, in microseconds, which the + transfer is allowed to complete. + @param TransferResult A pointer to the detailed result information from + the synchronous interrupt transfer. + + @retval EFI_UNSUPPORTED This interface not available. + @retval EFI_INVALID_PARAMETER Parameters not follow spec + +**/ + + +EFI_STATUS +EFIAPI +OhciSyncInterruptTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN TimeOut, + OUT UINT32 *TransferResult + ); +/** + + Submits isochronous transfer to a target USB device. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param DataLength Indicates the size, in bytes, of the data buffer + specified by Data. + @param TransferResult A pointer to the detailed result information generated + by this control transfer. + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL + +**/ + + +EFI_STATUS +EFIAPI +OhciIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + OUT UINT32 *TransferResult + ); +/** + + Submits Async isochronous transfer to a target USB device. + + @param his A pointer to the EFI_USB_HC_PROTOCOL instance. + @param DeviceAddress Represents the address of the target device on the USB, + which is assigned during USB enumeration. + @param EndPointAddress End point address + @param MaximumPacketLength Indicates the maximum packet size that the + default control transfer endpoint is capable of + sending or receiving. + @param Data A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + @param IsochronousCallBack When the transfer complete, the call back function will be called + @param Context Pass to the call back function as parameter + + @retval EFI_UNSUPPORTED This interface not available + @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0 + +**/ + +EFI_STATUS +EFIAPI +OhciAsyncIsochronousTransfer ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ); + +/** + + Retrieves the number of root hub ports. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param NumOfPorts A pointer to the number of the root hub ports. + + @retval EFI_SUCCESS The port number was retrieved successfully. +**/ +EFI_STATUS +EFIAPI +OhciGetRootHubNumOfPorts ( + IN EFI_USB_HC_PROTOCOL *This, + OUT UINT8 *NumOfPorts + ); +/** + + Retrieves the current status of a USB root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port from which the status + is to be retrieved. This value is zero-based. For example, + if a root hub has two ports, then the first port is numbered 0, + and the second port is numbered 1. + @param PortStatus A pointer to the current port status bits and + port status change bits. + + @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber + was returned in PortStatus. + @retval EFI_INVALID_PARAMETER Port number not valid +**/ + + +EFI_STATUS +EFIAPI +OhciGetRootHubPortStatus ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus + ); + +/** + + Sets a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL. + @param PortNumber Specifies the root hub port whose feature + is requested to be set. + @param PortFeature Indicates the feature selector associated + with the feature set request. + + @retval EFI_SUCCESS The feature specified by PortFeature was set for the + USB root hub port specified by PortNumber. + @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. +**/ +EFI_STATUS +EFIAPI +OhciSetRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ); +/** + + Clears a feature for the specified root hub port. + + @param This A pointer to the EFI_USB_HC_PROTOCOL instance. + @param PortNumber Specifies the root hub port whose feature + is requested to be cleared. + @param PortFeature Indicates the feature selector associated with the + feature clear request. + + @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the + USB root hub port specified by PortNumber. + @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid. + @retval EFI_DEVICE_ERROR Some error happened when clearing feature +**/ +EFI_STATUS +EFIAPI +OhciClearRootHubPortFeature ( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature + ); + + +/** + Test to see if this driver supports ControllerHandle. Any + ControllerHandle that has UsbHcProtocol installed will be supported. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @return EFI_SUCCESS This driver supports this device. + @return EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI + +OHCIDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starting the Usb OHCI Driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath Not used. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + EFI_OUT_OF_RESOURCES- Failed due to resource shortage. + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop this driver on ControllerHandle. Support stopping any child handles + created by this driver. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Number of Children in the ChildHandleBuffer. + @param ChildHandleBuffer List of handles for the children we need to stop. + + @return EFI_SUCCESS + @return others + +**/ +EFI_STATUS +EFIAPI +OHCIDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.c new file mode 100644 index 0000000..e467499 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.c @@ -0,0 +1,85 @@ +/** @file +This file provides the information dump support for OHCI when in debug mode. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +/*++ + + Print the data of ED and the TDs attached to the ED + + @param Uhc Pointer to OHCI private data + @param Ed Pointer to a ED to free + @param Td Pointer to the Td head + + @retval EFI_SUCCESS ED + +**/ +EFI_STATUS +OhciDumpEdTdInfo ( + IN USB_OHCI_HC_DEV *Uhc, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *Td, + BOOLEAN Stage + ) +{ + UINT32 Index; + + if (Stage) { + DEBUG ((DEBUG_INFO, "\n Before executing command\n")); + }else{ + DEBUG ((DEBUG_INFO, "\n after executing command\n")); + } + if (Ed != NULL) { + DEBUG ((DEBUG_INFO, "\nED Address:%p, ED buffer:\n", Ed)); + DEBUG ((DEBUG_INFO, "DWord0 :TD Tail :TD Head :Next ED\n")); + for (Index = 0; Index < sizeof (ED_DESCRIPTOR)/4; Index ++) { + DEBUG ((DEBUG_INFO, "%8x ", *((UINT32*)(Ed) + Index) )); + } + DEBUG ((DEBUG_INFO, "\nNext TD buffer:%p\n", Td)); + } + while (Td != NULL) { + if (Td->Word0.DirPID == TD_SETUP_PID) { + DEBUG ((DEBUG_INFO, "\nSetup PID ")); + }else if (Td->Word0.DirPID == TD_OUT_PID) { + DEBUG ((DEBUG_INFO, "\nOut PID ")); + }else if (Td->Word0.DirPID == TD_IN_PID) { + DEBUG ((DEBUG_INFO, "\nIn PID ")); + }else if (Td->Word0.DirPID == TD_NODATA_PID) { + DEBUG ((DEBUG_INFO, "\nNo data PID ")); + } + DEBUG ((DEBUG_INFO, "TD Address:%p, TD buffer:\n", Td)); + DEBUG ((DEBUG_INFO, "DWord0 :CuBuffer:Next TD :Buff End:Next TD :DataBuff:ActLength\n")); + for (Index = 0; Index < sizeof (TD_DESCRIPTOR)/4; Index ++) { + DEBUG ((DEBUG_INFO, "%8x ", *((UINT32*)(Td) + Index) )); + } + DEBUG ((DEBUG_INFO, "\nCurrent TD Data buffer(size%d)\n", (UINT32)Td->ActualSendLength)); + for (Index = 0; Index < Td->ActualSendLength; Index ++) { + DEBUG ((DEBUG_INFO, "%2x ", *(UINT8 *)(UINTN)(Td->DataBuffer + Index) )); + } + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + } + DEBUG ((DEBUG_INFO, "\n TD buffer End\n")); + + return EFI_SUCCESS; +} + +VOID +OhciDumpReg ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + UINT32 Data; + for(int i=0;i < 22; i++){ + Data = MmioRead32 (Ohc->UsbHcBaseAddress + 0x04*i); + DEBUG ((DEBUG_INFO, "OhcDumpReg 0x%x = 0x%x\n",Ohc->UsbHcBaseAddress +0x04*i, Data)); + } +} + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.h new file mode 100644 index 0000000..97c89d1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDebug.h @@ -0,0 +1,46 @@ +/** @file +This file contains the definination for host controller +debug support routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +/*++ + +Routine Description: + + Print the data of ED and the TDs attached to the ED + + @param Uhc Pointer to OHCI private data + @param Ed Pointer to a ED to free + @param Td Pointer to the Td head + + @retval EFI_SUCCESS ED + +**/ +EFI_STATUS +OhciDumpEdTdInfo ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *Td, + BOOLEAN Stage + ); + +/*++ + + Print the register data of ohci host controller + + @param Ohc Pointer to OHCI private data + +**/ + +VOID +OhciDumpReg ( + IN USB_OHCI_HC_DEV *Ohc + ); + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf new file mode 100644 index 0000000..a586a88 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf @@ -0,0 +1,77 @@ +## @file +# OHCI USB Host Controller UEFI Driver +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OhciDxe + FILE_GUID = 3914AE34-B946-11EC-9D33-F42A7DCB925D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = OhciInitialise + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# +[Sources] + Descriptor.h + Ohci.c + Ohci.h + OhciSched.c + OhciSched.h + OhciReg.c + OhciReg.h + OhciUrb.c + OhciUrb.h + OhciDebug.c + OhciDebug.h + UsbHcMem.c + UsbHcMem.h + ComponentName.c + ComponentName.h + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PcdLib + ReportStatusCodeLib + RockchipPlatformLib + DmaLib + +[Guids] + gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event + gEfiEndOfDxeEventGroupGuid + +[Protocols] + gOhciDeviceProtocolGuid ## TO_START + gEfiUsbHcProtocolGuid ## BY_START + +[Depex] + TRUE + +# +# [Event] +# ## +# # Periodic timer event for checking the result of interrupt transfer execution. +# # +# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES +# diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.c new file mode 100644 index 0000000..8c4038f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.c @@ -0,0 +1,1383 @@ +/** @file +The OHCI register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +/** + + Get OHCI operational reg value + + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset + ) +{ + UINT32 Value; + + Value = MmioRead32(Ohc->UsbHcBaseAddress + Offset); + + return Value; +} +/** + + Set OHCI operational reg value + + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ + + +EFI_STATUS +OhciSetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + Status = MmioWrite32(Ohc->UsbHcBaseAddress + Offset, Value); + + return Status; +} +/** + + Get HcRevision reg value + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg (Ohc, HC_REVISION); +} +/** + + Set HcReset reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ) +{ + HcRESET Reset; + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR); + + if (Field & RESET_SYSTEM_BUS) { + Reset.FSBIR = Value; + } + + if (Field & RESET_HOST_CONTROLLER) { + Reset.FHR = Value; + } + + if (Field & RESET_CLOCK_GENERATION) { + Reset.CGR = Value; + } + + if (Field & RESET_SSE_GLOBAL) { + Reset.SSE = Value; + } + + if (Field & RESET_PSPL) { + Reset.PSPL = Value; + } + + if (Field & RESET_PCPL) { + Reset.PCPL = Value; + } + + if (Field & RESET_SSEP1) { + Reset.SSEP1 = Value; + } + + if (Field & RESET_SSEP2) { + Reset.SSEP2 = Value; + } + + if (Field & RESET_SSEP3) { + Reset.SSEP3 = Value; + } + + OhciSetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR, *(UINT32 *) &Reset); + + return EFI_SUCCESS; +} + +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ) +{ + HcRESET Reset; + UINT32 Value; + + + *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR); + Value = 0; + + switch (Field) { + case RESET_SYSTEM_BUS: + Value = Reset.FSBIR; + break; + + case RESET_HOST_CONTROLLER: + Value = Reset.FHR; + break; + + case RESET_CLOCK_GENERATION: + Value = Reset.CGR; + break; + + case RESET_SSE_GLOBAL: + Value = Reset.SSE; + break; + + case RESET_PSPL: + Value = Reset.PSPL; + break; + + case RESET_PCPL: + Value = Reset.PCPL; + break; + + case RESET_SSEP1: + Value = Reset.SSEP1; + break; + + case RESET_SSEP2: + Value = Reset.SSEP2; + break; + + case RESET_SSEP3: + Value = Reset.SSEP3; + break; + + default: + ASSERT (FALSE); + } + + + return Value; +} + +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCONTROL Control; + + + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL); + + if (Field & CONTROL_BULK_RATIO) { + Control.ControlBulkRatio = Value; + } + + if (Field & HC_FUNCTIONAL_STATE) { + Control.FunctionalState = Value; + } + + if (Field & PERIODIC_ENABLE) { + Control.PeriodicEnable = Value; + } + + if (Field & CONTROL_ENABLE) { + Control.ControlEnable = Value; + } + + if (Field & ISOCHRONOUS_ENABLE) { + Control.IsochronousEnable = Value; + } + + if (Field & BULK_ENABLE) { + Control.BulkEnable = Value; + } + + if (Field & INTERRUPT_ROUTING) { + Control.InterruptRouting = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_CONTROL, *(UINT32 *) &Control); + + return Status; +} + + +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCONTROL Control; + + *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL); + + switch (Field) { + case CONTROL_BULK_RATIO: + return Control.ControlBulkRatio; + break; + case PERIODIC_ENABLE: + return Control.PeriodicEnable; + break; + case CONTROL_ENABLE: + return Control.ControlEnable; + break; + case BULK_ENABLE: + return Control.BulkEnable; + break; + case ISOCHRONOUS_ENABLE: + return Control.IsochronousEnable; + break; + case HC_FUNCTIONAL_STATE: + return Control.FunctionalState; + break; + case INTERRUPT_ROUTING: + return Control.InterruptRouting; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcCOMMAND_STATUS CommandStatus; + + ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS)); + + if(Field & HC_RESET){ + CommandStatus.HcReset = Value; + } + + if(Field & CONTROL_LIST_FILLED){ + CommandStatus.ControlListFilled = Value; + } + + if(Field & BULK_LIST_FILLED){ + CommandStatus.BulkListFilled = Value; + } + + if(Field & CHANGE_OWNER_REQUEST){ + CommandStatus.ChangeOwnerRequest = Value; + } + + if(Field & SCHEDULE_OVERRUN_COUNT){ + CommandStatus.ScheduleOverrunCount = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_COMMAND_STATUS, *(UINT32 *) &CommandStatus); + + return Status; +} + +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcCOMMAND_STATUS CommandStatus; + + *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS); + + switch (Field){ + case HC_RESET: + return CommandStatus.HcReset; + break; + case CONTROL_LIST_FILLED: + return CommandStatus.ControlListFilled; + break; + case BULK_LIST_FILLED: + return CommandStatus.BulkListFilled; + break; + case CHANGE_OWNER_REQUEST: + return CommandStatus.ChangeOwnerRequest; + break; + case SCHEDULE_OVERRUN_COUNT: + return CommandStatus.ScheduleOverrunCount; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcINTERRUPT_STATUS InterruptStatus; + + ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS)); + + if(Field & SCHEDULE_OVERRUN){ + InterruptStatus.SchedulingOverrun = 1; + } + + if(Field & WRITEBACK_DONE_HEAD){ + InterruptStatus.WriteBackDone = 1; + } + if(Field & START_OF_FRAME){ + InterruptStatus.Sof = 1; + } + + if(Field & RESUME_DETECT){ + InterruptStatus.ResumeDetected = 1; + } + + if(Field & UNRECOVERABLE_ERROR){ + InterruptStatus.UnrecoverableError = 1; + } + + if(Field & FRAME_NUMBER_OVERFLOW){ + InterruptStatus.FrameNumOverflow = 1; + } + + if(Field & ROOTHUB_STATUS_CHANGE){ + InterruptStatus.RHStatusChange = 1; + } + + if(Field & OWNERSHIP_CHANGE){ + InterruptStatus.OwnerChange = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_STATUS, *(UINT32 *) &InterruptStatus); + + return Status; +} + +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_STATUS InterruptStatus; + + *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc, HC_INTERRUPT_STATUS); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptStatus.SchedulingOverrun; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptStatus.WriteBackDone; + break; + + case START_OF_FRAME: + return InterruptStatus.Sof; + break; + + case RESUME_DETECT: + return InterruptStatus.ResumeDetected; + break; + + case UNRECOVERABLE_ERROR: + return InterruptStatus.UnrecoverableError; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptStatus.FrameNumOverflow; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptStatus.RHStatusChange; + break; + + case OWNERSHIP_CHANGE: + return InterruptStatus.OwnerChange; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcINTERRUPT_CONTROL InterruptState; + + + ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL)); + + if(Field & SCHEDULE_OVERRUN) { + InterruptState.SchedulingOverrunInt = Value; + } + + if(Field & WRITEBACK_DONE_HEAD) { + InterruptState.WriteBackDoneInt = Value; + } + if(Field & START_OF_FRAME) { + InterruptState.SofInt = Value; + } + + if(Field & RESUME_DETECT) { + InterruptState.ResumeDetectedInt = Value; + } + + if(Field & UNRECOVERABLE_ERROR) { + InterruptState.UnrecoverableErrorInt = Value; + } + + if(Field & FRAME_NUMBER_OVERFLOW) { + InterruptState.FrameNumOverflowInt = Value; + } + + if(Field & ROOTHUB_STATUS_CHANGE) { + InterruptState.RHStatusChangeInt = Value; + } + + if(Field & OWNERSHIP_CHANGE) { + InterruptState.OwnerChangedInt = Value; + } + + if(Field & MASTER_INTERRUPT) { + InterruptState.MasterInterruptEnable = Value; + } + + if (StatEnable) { + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_ENABLE, *(UINT32 *) &InterruptState); + } else { + Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_DISABLE, *(UINT32 *) &InterruptState); + } + + return Status; +} + +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcINTERRUPT_CONTROL InterruptState; + + *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc, HC_INTERRUPT_ENABLE); + + switch (Field){ + case SCHEDULE_OVERRUN: + return InterruptState.SchedulingOverrunInt; + break; + + case WRITEBACK_DONE_HEAD: + return InterruptState.WriteBackDoneInt; + break; + + case START_OF_FRAME: + return InterruptState.SofInt; + break; + + case RESUME_DETECT: + return InterruptState.ResumeDetectedInt; + break; + + case UNRECOVERABLE_ERROR: + return InterruptState.UnrecoverableErrorInt; + break; + + case FRAME_NUMBER_OVERFLOW: + return InterruptState.FrameNumOverflowInt; + break; + + case ROOTHUB_STATUS_CHANGE: + return InterruptState.RHStatusChangeInt; + break; + + case OWNERSHIP_CHANGE: + return InterruptState.OwnerChangedInt; + break; + + case MASTER_INTERRUPT: + return InterruptState.MasterInterruptEnable; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType, + IN VOID *Value + ) +{ + EFI_STATUS Status; + UINT32 Verify; + + Status = OhciSetOperationalReg (Ohc, PointerType, (UINT32)(UINTN)Value); + + if (EFI_ERROR (Status)) { + return Status; + } + + Verify = OhciGetOperationalReg (Ohc, PointerType); + while (Verify != (UINT32)(UINTN) Value) { + gBS->Stall(1000); + Verify = OhciGetOperationalReg (Ohc, PointerType); + }; + + return Status; +} + +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType + ) +{ + + return (VOID *)(UINTN) OhciGetOperationalReg (Ohc, PointerType); +} + + +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRM_INTERVAL FrameInterval; + + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc, HC_FRM_INTERVAL); + + if (Field & FRAME_INTERVAL) { + FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle; + FrameInterval.FrameInterval = Value; + } + + if (Field & FS_LARGEST_DATA_PACKET) { + FrameInterval.FSMaxDataPacket = Value; + } + + if (Field & FRMINT_TOGGLE) { + FrameInterval.FrmIntervalToggle = Value; + } + + Status = OhciSetOperationalReg ( + Ohc, + HC_FRM_INTERVAL, + *(UINT32 *) &FrameInterval + ); + + return Status; +} + + +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcFRM_INTERVAL FrameInterval; + + *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc, HC_FRM_INTERVAL); + + switch (Field){ + case FRAME_INTERVAL: + return FrameInterval.FrameInterval; + break; + + case FS_LARGEST_DATA_PACKET: + return FrameInterval.FSMaxDataPacket; + break; + + case FRMINT_TOGGLE: + return FrameInterval.FrmIntervalToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING); + + FrameRemaining.FrameRemaining = Value; + FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle; + + Status = OhciSetOperationalReg (Ohc, HC_FRM_REMAINING, *(UINT32 *) &FrameRemaining); + + return Status; +} +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) + +{ + HcFRAME_REMAINING FrameRemaining; + + + *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING); + + switch (Field){ + case FRAME_REMAINING: + return FrameRemaining.FrameRemaining; + break; + + case FRAME_REMAIN_TOGGLE: + return FrameRemaining.FrameRemainingToggle; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + Status = OhciSetOperationalReg (Ohc, HC_FRM_NUMBER, Value); + + return Status; +} + +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_FRM_NUMBER); +} + +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc, HC_PERIODIC_START, Value); + + return Status; +} + + +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_PERIODIC_START); +} + + +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + + + Status = OhciSetOperationalReg (Ohc, HC_LS_THREASHOLD, Value); + + return Status; +} + + +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + return OhciGetOperationalReg(Ohc, HC_LS_THREASHOLD); +} + +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + + if (Field & (RH_DEV_REMOVABLE | RH_PORT_PWR_CTRL_MASK)) { + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B); + + if(Field & RH_DEV_REMOVABLE) { + DescriptorB.DeviceRemovable = Value; + } + if(Field & RH_PORT_PWR_CTRL_MASK) { + DescriptorB.PortPowerControlMask = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_B, *(UINT32 *) &DescriptorB); + + return Status; + } + + *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A); + + if(Field & RH_NUM_DS_PORTS) { + DescriptorA.NumDownStrmPorts = Value; + } + if(Field & RH_NO_PSWITCH) { + DescriptorA.NoPowerSwitch = Value; + } + if(Field & RH_PSWITCH_MODE) { + DescriptorA.PowerSwitchMode = Value; + } + if(Field & RH_DEVICE_TYPE) { + DescriptorA.DeviceType = Value; + } + if(Field & RH_OC_PROT_MODE) { + DescriptorA.OverCurrentProtMode = Value; + } + if(Field & RH_NOC_PROT) { + DescriptorA.NoOverCurrentProtMode = Value; + } + if(Field & RH_NO_POTPGT) { + DescriptorA.PowerOnToPowerGoodTime = Value; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_A, *(UINT32 *) &DescriptorA); + + return Status; +} + + +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_DESC_A DescriptorA; + HcRH_DESC_B DescriptorB; + + *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A); + *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B); + + switch (Field){ + case RH_DEV_REMOVABLE: + return DescriptorB.DeviceRemovable; + break; + + case RH_PORT_PWR_CTRL_MASK: + return DescriptorB.PortPowerControlMask; + break; + + case RH_NUM_DS_PORTS: + return DescriptorA.NumDownStrmPorts; + break; + + case RH_NO_PSWITCH: + return DescriptorA.NoPowerSwitch; + break; + + case RH_PSWITCH_MODE: + return DescriptorA.PowerSwitchMode; + break; + + case RH_DEVICE_TYPE: + return DescriptorA.DeviceType; + break; + + case RH_OC_PROT_MODE: + return DescriptorA.OverCurrentProtMode; + break; + + case RH_NOC_PROT: + return DescriptorA.NoOverCurrentProtMode; + break; + + case RH_NO_POTPGT: + return DescriptorA.PowerOnToPowerGoodTime; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRH_STATUS RootHubStatus; + + + ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS)); + + if(Field & RH_LOCAL_PSTAT){ + RootHubStatus.LocalPowerStat = 1; + } + if(Field & RH_OC_ID){ + RootHubStatus.OverCurrentIndicator = 1; + } + if(Field & RH_REMOTE_WK_ENABLE){ + RootHubStatus.DevRemoteWakeupEnable = 1; + } + if(Field & RH_LOCAL_PSTAT_CHANGE){ + RootHubStatus.LocalPowerStatChange = 1; + } + if(Field & RH_OC_ID_CHANGE){ + RootHubStatus.OverCurrentIndicatorChange = 1; + } + if(Field & RH_CLR_RMT_WK_ENABLE){ + RootHubStatus.ClearRemoteWakeupEnable = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_STATUS, *(UINT32 *) &RootHubStatus); + + return Status; +} + + +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ) +{ + HcRH_STATUS RootHubStatus; + + + *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc, HC_RH_STATUS); + + switch (Field) { + case RH_LOCAL_PSTAT: + return RootHubStatus.LocalPowerStat; + break; + case RH_OC_ID: + return RootHubStatus.OverCurrentIndicator; + break; + case RH_REMOTE_WK_ENABLE: + return RootHubStatus.DevRemoteWakeupEnable; + break; + case RH_LOCAL_PSTAT_CHANGE: + return RootHubStatus.LocalPowerStatChange; + break; + case RH_OC_ID_CHANGE: + return RootHubStatus.OverCurrentIndicatorChange; + break; + case RH_CLR_RMT_WK_ENABLE: + return RootHubStatus.ClearRemoteWakeupEnable; + break; + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + EFI_STATUS Status; + HcRHPORT_STATUS PortStatus; + + + ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS)); + + if (Field & RH_CLEAR_PORT_ENABLE) { + PortStatus.CurrentConnectStat = 1; + } + if (Field & RH_SET_PORT_ENABLE) { + PortStatus.EnableStat = 1; + } + if (Field & RH_SET_PORT_SUSPEND) { + PortStatus.SuspendStat = 1; + } + if (Field & RH_CLEAR_SUSPEND_STATUS) { + PortStatus.OCIndicator = 1; + } + if (Field & RH_SET_PORT_RESET) { + PortStatus.ResetStat = 1; + } + if (Field & RH_SET_PORT_POWER) { + PortStatus.PowerStat = 1; + } + if (Field & RH_CLEAR_PORT_POWER) { + PortStatus.LsDeviceAttached = 1; + } + if (Field & RH_CONNECT_STATUS_CHANGE) { + PortStatus.ConnectStatChange = 1; + } + if (Field & RH_PORT_ENABLE_STAT_CHANGE) { + PortStatus.EnableStatChange = 1; + } + if (Field & RH_PORT_SUSPEND_STAT_CHANGE) { + PortStatus.SuspendStatChange = 1; + } + if (Field & RH_OC_INDICATOR_CHANGE) { + PortStatus.OCIndicatorChange = 1; + } + if (Field & RH_PORT_RESET_STAT_CHANGE ) { + PortStatus.ResetStatChange = 1; + } + + Status = OhciSetOperationalReg (Ohc, HC_RH_PORT_STATUS + (Index * 4), *(UINT32 *) &PortStatus); + + return Status; +} + + +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ) +{ + HcRHPORT_STATUS PortStatus; + + *(UINT32 *) &PortStatus = OhciGetOperationalReg ( + Ohc, + HC_RH_PORT_STATUS + (Index * 4) + ); + + switch (Field){ + case RH_CURR_CONNECT_STAT: + return PortStatus.CurrentConnectStat; + break; + case RH_PORT_ENABLE_STAT: + return PortStatus.EnableStat; + break; + case RH_PORT_SUSPEND_STAT: + return PortStatus.SuspendStat; + break; + case RH_PORT_OC_INDICATOR: + return PortStatus.OCIndicator; + break; + case RH_PORT_RESET_STAT: + return PortStatus.ResetStat; + break; + case RH_PORT_POWER_STAT: + return PortStatus.PowerStat; + break; + case RH_LSDEVICE_ATTACHED: + return PortStatus.LsDeviceAttached; + break; + case RH_CONNECT_STATUS_CHANGE: + return PortStatus.ConnectStatChange; + break; + case RH_PORT_ENABLE_STAT_CHANGE: + return PortStatus.EnableStatChange; + break; + case RH_PORT_SUSPEND_STAT_CHANGE: + return PortStatus.SuspendStatChange; + break; + case RH_OC_INDICATOR_CHANGE: + return PortStatus.OCIndicatorChange; + break; + case RH_PORT_RESET_STAT_CHANGE: + return PortStatus.ResetStatChange; + break; + default: + ASSERT (FALSE); + } + + return 0; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.h new file mode 100644 index 0000000..6214e31 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciReg.h @@ -0,0 +1,920 @@ +/** @file +This file contains the definination for host controller +register operation routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_REG_H +#define _OHCI_REG_H + +#define HC_STATE_RESET 0x0 +#define HC_STATE_RESUME 0x1 +#define HC_STATE_OPERATIONAL 0x2 +#define HC_STATE_SUSPEND 0x3 + +#define PERIODIC_ENABLE 0x01 +#define ISOCHRONOUS_ENABLE 0x02 +#define CONTROL_ENABLE 0x04 +#define BULK_ENABLE 0x08 +#define CONTROL_BULK_RATIO 0x10 + +#define HC_FUNCTIONAL_STATE 0x20 +#define INTERRUPT_ROUTING 0x40 + +#define HC_RESET 0x01 +#define CONTROL_LIST_FILLED 0x02 +#define BULK_LIST_FILLED 0x04 +#define CHANGE_OWNER_REQUEST 0x08 + +#define SCHEDULE_OVERRUN_COUNT 0x10 + +#define SCHEDULE_OVERRUN 0x00001 +#define WRITEBACK_DONE_HEAD 0x00002 +#define START_OF_FRAME 0x00004 +#define RESUME_DETECT 0x00008 +#define UNRECOVERABLE_ERROR 0x00010 +#define FRAME_NUMBER_OVERFLOW 0x00020 +#define ROOTHUB_STATUS_CHANGE 0x00040 +#define OWNERSHIP_CHANGE 0x00080 + +#define MASTER_INTERRUPT 0x00400 + +#define CONTROL_HEAD 0x001 +#define BULK_HEAD 0x002 +#define DONE_HEAD 0x004 + +#define Hc_HCCA 0x001 +#define Hc_PERIODIC_CURRENT 0x002 +#define Hc_CONTOL_HEAD 0x004 +#define Hc_CONTROL_CURRENT_PTR 0x008 +#define Hc_BULK_HEAD 0x010 +#define Hc_BULK_CURRENT_PTR 0x020 +#define Hc_DONE_HEAD 0x040 + +#define FRAME_INTERVAL 0x008 +#define FS_LARGEST_DATA_PACKET 0x010 +#define FRMINT_TOGGLE 0x020 +#define FRAME_REMAINING 0x040 +#define FRAME_REMAIN_TOGGLE 0x080 + +#define RH_DESC_A 0x00001 +#define RH_DESC_B 0x00002 +#define RH_NUM_DS_PORTS 0x00004 +#define RH_NO_PSWITCH 0x00008 +#define RH_PSWITCH_MODE 0x00010 +#define RH_DEVICE_TYPE 0x00020 +#define RH_OC_PROT_MODE 0x00040 +#define RH_NOC_PROT 0x00080 +#define RH_POTPGT 0x00100 +#define RH_NO_POTPGT 0x00200 +#define RH_DEV_REMOVABLE 0x00400 +#define RH_PORT_PWR_CTRL_MASK 0x00800 + +#define RH_LOCAL_PSTAT 0x00001 +#define RH_OC_ID 0x00002 +#define RH_REMOTE_WK_ENABLE 0x00004 +#define RH_LOCAL_PSTAT_CHANGE 0x00008 +#define RH_OC_ID_CHANGE 0x00010 +#define RH_CLR_RMT_WK_ENABLE 0x00020 + +#define RH_CLEAR_PORT_ENABLE 0x0001 +#define RH_SET_PORT_ENABLE 0x0002 +#define RH_SET_PORT_SUSPEND 0x0004 +#define RH_CLEAR_SUSPEND_STATUS 0x0008 +#define RH_SET_PORT_RESET 0x0010 +#define RH_SET_PORT_POWER 0x0020 +#define RH_CLEAR_PORT_POWER 0x0040 +#define RH_CONNECT_STATUS_CHANGE 0x10000 +#define RH_PORT_ENABLE_STAT_CHANGE 0x20000 +#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000 +#define RH_OC_INDICATOR_CHANGE 0x80000 +#define RH_PORT_RESET_STAT_CHANGE 0x100000 + +#define RH_CURR_CONNECT_STAT 0x0001 +#define RH_PORT_ENABLE_STAT 0x0002 +#define RH_PORT_SUSPEND_STAT 0x0004 +#define RH_PORT_OC_INDICATOR 0x0008 +#define RH_PORT_RESET_STAT 0x0010 +#define RH_PORT_POWER_STAT 0x0020 +#define RH_LSDEVICE_ATTACHED 0x0040 + +#define RESET_SYSTEM_BUS (1 << 0) +#define RESET_HOST_CONTROLLER (1 << 1) +#define RESET_CLOCK_GENERATION (1 << 2) +#define RESET_SSE_GLOBAL (1 << 5) +#define RESET_PSPL (1 << 6) +#define RESET_PCPL (1 << 7) +#define RESET_SSEP1 (1 << 9) +#define RESET_SSEP2 (1 << 10) +#define RESET_SSEP3 (1 << 11) + +#define ONE_SECOND 1000000 +#define ONE_MILLI_SEC 1000 +#define MAX_BYTES_PER_TD 0x1000 +#define MAX_RETRY_TIMES 100 +#define PORT_NUMBER_ON_MAINSTONE2 1 + + +// +// Operational Register Offsets +// + +// +// Command & Status Registers Offsets +// +#define HC_REVISION 0x00 +#define HC_CONTROL 0x04 +#define HC_COMMAND_STATUS 0x08 +#define HC_INTERRUPT_STATUS 0x0C +#define HC_INTERRUPT_ENABLE 0x10 +#define HC_INTERRUPT_DISABLE 0x14 + +// +// Memory Pointer Offsets +// +#define HC_HCCA 0x18 +#define HC_PERIODIC_CURRENT 0x1C +#define HC_CONTROL_HEAD 0x20 +#define HC_CONTROL_CURRENT_PTR 0x24 +#define HC_BULK_HEAD 0x28 +#define HC_BULK_CURRENT_PTR 0x2C +#define HC_DONE_HEAD 0x30 + +// +// Frame Register Offsets +// +#define HC_FRM_INTERVAL 0x34 +#define HC_FRM_REMAINING 0x38 +#define HC_FRM_NUMBER 0x3C +#define HC_PERIODIC_START 0x40 +#define HC_LS_THREASHOLD 0x44 + +// +// Root Hub Register Offsets +// +#define HC_RH_DESC_A 0x48 +#define HC_RH_DESC_B 0x4C +#define HC_RH_STATUS 0x50 +#define HC_RH_PORT_STATUS 0x54 + +#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register + +#define OHC_BAR_INDEX 0 + +// +// Usb Host controller register offset +// +#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register +#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register +#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register +#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register +#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register +#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register +#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area +#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor +#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor +#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register +#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register +#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register +#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register +#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register +#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register +#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register +#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register +#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register +#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register + +// +// Usb Host controller register bit fields +// +#pragma pack(1) + +typedef struct { + UINT8 ProgInterface; + UINT8 SubClassCode; + UINT8 BaseCode; +} USB_CLASSC; + +typedef struct { + UINT32 Revision:8; + UINT32 Rsvd:24; +} HcREVISION; + +typedef struct { + UINT32 ControlBulkRatio:2; + UINT32 PeriodicEnable:1; + UINT32 IsochronousEnable:1; + UINT32 ControlEnable:1; + UINT32 BulkEnable:1; + UINT32 FunctionalState:2; + UINT32 InterruptRouting:1; + UINT32 RemoteWakeup:1; + UINT32 RemoteWakeupEnable:1; + UINT32 Reserved:21; +} HcCONTROL; + +typedef struct { + UINT32 HcReset:1; + UINT32 ControlListFilled:1; + UINT32 BulkListFilled:1; + UINT32 ChangeOwnerRequest:1; + UINT32 Reserved1:12; + UINT32 ScheduleOverrunCount:2; + UINT32 Reserved:14; +} HcCOMMAND_STATUS; + +typedef struct { + UINT32 SchedulingOverrun:1; + UINT32 WriteBackDone:1; + UINT32 Sof:1; + UINT32 ResumeDetected:1; + UINT32 UnrecoverableError:1; + UINT32 FrameNumOverflow:1; + UINT32 RHStatusChange:1; + UINT32 Reserved1:23; + UINT32 OwnerChange:1; + UINT32 Reserved2:1; +} HcINTERRUPT_STATUS; + +typedef struct { + UINT32 SchedulingOverrunInt:1; + UINT32 WriteBackDoneInt:1; + UINT32 SofInt:1; + UINT32 ResumeDetectedInt:1; + UINT32 UnrecoverableErrorInt:1; + UINT32 FrameNumOverflowInt:1; + UINT32 RHStatusChangeInt:1; + UINT32 Reserved:23; + UINT32 OwnerChangedInt:1; + UINT32 MasterInterruptEnable:1; +} HcINTERRUPT_CONTROL; + +typedef struct { + UINT32 Rerserved:8; + UINT32 Hcca:24; +} HcHCCA; + +typedef struct { + UINT32 Reserved:4; + UINT32 MemoryPtr:28; +} HcMEMORY_PTR; + +typedef struct { + UINT32 FrameInterval:14; + UINT32 Reserved:2; + UINT32 FSMaxDataPacket:15; + UINT32 FrmIntervalToggle:1; +} HcFRM_INTERVAL; + +typedef struct { + UINT32 FrameRemaining:14; + UINT32 Reserved:17; + UINT32 FrameRemainingToggle:1; +} HcFRAME_REMAINING; + +typedef struct { + UINT32 FrameNumber:16; + UINT32 Reserved:16; +} HcFRAME_NUMBER; + +typedef struct { + UINT32 PeriodicStart:14; + UINT32 Reserved:18; +} HcPERIODIC_START; + +typedef struct { + UINT32 LsThreshold:12; + UINT32 Reserved:20; +} HcLS_THRESHOLD; + +typedef struct { + UINT32 NumDownStrmPorts:8; + UINT32 PowerSwitchMode:1; + UINT32 NoPowerSwitch:1; + UINT32 DeviceType:1; + UINT32 OverCurrentProtMode:1; + UINT32 NoOverCurrentProtMode:1; + UINT32 Reserved:11; + UINT32 PowerOnToPowerGoodTime:8; +} HcRH_DESC_A; + +typedef struct { + UINT32 DeviceRemovable:16; + UINT32 PortPowerControlMask:16; +} HcRH_DESC_B; + +typedef struct { + UINT32 LocalPowerStat:1; + UINT32 OverCurrentIndicator:1; + UINT32 Reserved1:13; + UINT32 DevRemoteWakeupEnable:1; + UINT32 LocalPowerStatChange:1; + UINT32 OverCurrentIndicatorChange:1; + UINT32 Reserved2:13; + UINT32 ClearRemoteWakeupEnable:1; +} HcRH_STATUS; + +typedef struct { + UINT32 CurrentConnectStat:1; + UINT32 EnableStat:1; + UINT32 SuspendStat:1; + UINT32 OCIndicator:1; + UINT32 ResetStat:1; + UINT32 Reserved1:3; + UINT32 PowerStat:1; + UINT32 LsDeviceAttached:1; + UINT32 Reserved2:6; + UINT32 ConnectStatChange:1; + UINT32 EnableStatChange:1; + UINT32 SuspendStatChange:1; + UINT32 OCIndicatorChange:1; + UINT32 ResetStatChange:1; + UINT32 Reserved3:11; +} HcRHPORT_STATUS; + +typedef struct { + UINT32 FSBIR:1; + UINT32 FHR:1; + UINT32 CGR:1; + UINT32 SSDC:1; + UINT32 UIT:1; + UINT32 SSE:1; + UINT32 PSPL:1; + UINT32 PCPL:1; + UINT32 Reserved0:1; + UINT32 SSEP1:1; + UINT32 SSEP2:1; + UINT32 SSEP3:1; + UINT32 Reserved1:20; +} HcRESET; + + +#pragma pack() + +// +// Func List +// + + +/** + + Get OHCI operational reg value + + @param PciIo PciIo protocol instance + @param Offset Offset of the operational reg + + @retval Value of the register + +**/ +UINT32 +OhciGetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset + ); + +/** + + Set OHCI operational reg value + + @param PciIo PCI Bus Io protocol instance + @param Offset Offset of the operational reg + @param Value Value to set + + @retval EFI_SUCCESS Value set to the reg + +**/ + + +EFI_STATUS +OhciSetOperationalReg ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Offset, + IN UINT32 Value + ); + + +/** + + Get HcRevision reg value + + @param PciIo PCI Bus Io protocol instance + + @retval Value of the register + +**/ + + +UINT32 +OhciGetHcRevision ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Set HcReset reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field, + IN UINT32 Value + ); +/** + + Get specific field of HcReset reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcReset ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Field + ); +/** + + Set HcControl reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get specific field of HcControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + + +UINT32 +OhciGetHcControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set HcCommand reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + +/** + + Get specific field of HcCommand reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcCommandStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Clear specific fields of Interrupt Status + + @param Ohc UHC private data + @param Field Field to clear + + @retval EFI_SUCCESS Fields cleared + +**/ + +EFI_STATUS +OhciClearInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Get fields of HcInterrupt reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set Interrupt Control reg value + + @param Ohc UHC private data + @param StatEnable Enable or Disable + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN BOOLEAN StatEnable, + IN UINTN Field, + IN UINT32 Value + ); + +/** + + Get field of HcInterruptControl reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetHcInterruptControl ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of the pointer to set + @param Value Value to set + + @retval EFI_SUCCESS Memory pointer set + +**/ + +EFI_STATUS +OhciSetMemoryPointer( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType, + IN VOID *Value + ); + +/** + + Get memory pointer of specific type + + @param Ohc UHC private data + @param PointerType Type of pointer + + @retval Memory pointer of the specific type + +**/ + +VOID * +OhciGetMemoryPointer ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 PointerType + ); + +/** + + Set Frame Interval value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get field of frame interval reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetFrameInterval ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set Frame Remaining reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get value of frame remaining reg + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of frame remaining reg + +**/ +UINT32 +OhciGetFrameRemaining ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set frame number reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetFrameNumber( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get frame number reg value + + @param Ohc UHC private data + + @retval Value of frame number reg + +**/ + +UINT32 +OhciGetFrameNumber ( + IN USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Set period start reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + + +/** + + Get periodic start reg value + + @param Ohc UHC private data + + @param Value of periodic start reg + +**/ + +UINT32 +OhciGetPeriodicStart ( + IN USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Set Ls Threshold reg value + + @param Ohc UHC private data + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Value + ); + +/** + + Get Ls Threshold reg value + + @param Ohc UHC private data + + @retval Value of Ls Threshold reg + +**/ + +UINT32 +OhciGetLsThreshold ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Set Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to set + @param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field, + IN UINT32 Value + ); + + +/** + + Get Root Hub Descriptor reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubDescriptor ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + +/** + + Set Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Get Root Hub Status reg value + + @param Ohc UHC private data + @param Field Field to get + + @retval Value of the field + +**/ + +UINT32 +OhciGetRootHubStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINTN Field + ); + + +/** + + Set Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to set + + @retval EFI_SUCCESS Value set + +**/ + +EFI_STATUS +OhciSetRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); + + +/** + + Get Root Hub Port Status reg value + + @param Ohc UHC private data + @param Index Index of the port + @param Field Field to get + + @retval Value of the field and index + +**/ + +UINT32 +OhciReadRootHubPortStatus ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Index, + IN UINTN Field + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.c new file mode 100644 index 0000000..8aee833 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.c @@ -0,0 +1,531 @@ +/** @file +OHCI transfer scheduling routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + +/** + + Add an item of interrupt context + + @param Ohc UHC private data + @param NewEntry New entry to add + + @retval EFI_SUCCESS Item successfully added + +**/ +EFI_STATUS +OhciAddInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *NewEntry + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + EFI_TPL OriginalTPL; + + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + if (Ohc->InterruptContextList == NULL) { + Ohc->InterruptContextList = NewEntry; + } else { + Entry = Ohc->InterruptContextList; + while (Entry->NextEntry != NULL) { + Entry = Entry->NextEntry; + } + Entry->NextEntry = NewEntry; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + + +/** + + Free a interrupt context entry + + @param Ohc UHC private data + @param Entry Pointer to an interrupt context entry + + @retval EFI_SUCCESS Entry freed + @retval EFI_INVALID_PARAMETER Entry is NULL + +**/ +EFI_STATUS +OhciFreeInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *Entry + ) +{ + TD_DESCRIPTOR *Td; + if (Entry == NULL) { + return EFI_INVALID_PARAMETER; + } + if (Entry->UCBufferMapping != NULL) { + DmaUnmap(Entry->UCBufferMapping); + } + if (Entry->UCBuffer != NULL) { + UINTN Pages = EFI_SIZE_TO_PAGES (Entry->DataLength); + DmaFreeBuffer (Pages, Entry->UCBuffer); + } + while (Entry->DataTd) { + Td = Entry->DataTd; + Entry->DataTd = (TD_DESCRIPTOR *)(UINTN)(Entry->DataTd->NextTDPointer); + UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR)); + } + FreePool(Entry); + return EFI_SUCCESS; +} + + +/** + + Free entries match the device address and endpoint address + + @Param Ohc UHC private date + @Param DeviceAddress Item to free must match this device address + @Param EndPointAddress Item to free must match this end point address + @Param DataToggle DataToggle for output + + @retval EFI_SUCCESS Items match the requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptContext( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + INTERRUPT_CONTEXT_ENTRY *TempEntry; + EFI_TPL OriginalTPL; + + + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + while (Ohc->InterruptContextList != NULL && + Ohc->InterruptContextList->DeviceAddress == DeviceAddress && + Ohc->InterruptContextList->EndPointAddress == EndPointAddress) { + TempEntry = Ohc->InterruptContextList; + Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry; + if (DataToggle != NULL) { + *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1); + } + OhciFreeInterruptContextEntry (Ohc, TempEntry); + } + + Entry = Ohc->InterruptContextList; + if (Entry == NULL) { + gBS->RestoreTPL (OriginalTPL); + return EFI_SUCCESS; + } + while (Entry->NextEntry != NULL) { + if (Entry->NextEntry->DeviceAddress == DeviceAddress && + Entry->NextEntry->EndPointAddress == EndPointAddress) { + TempEntry = Entry->NextEntry; + Entry->NextEntry = Entry->NextEntry->NextEntry; + if (DataToggle != NULL) { + *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1); + } + OhciFreeInterruptContextEntry (Ohc, TempEntry); + } else { + Entry = Entry->NextEntry; + } + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ) +{ + UINT32 TransferResult; + + switch (ErrorCode) { + case TD_NO_ERROR: + TransferResult = EFI_USB_NOERROR; + break; + + case TD_TOBE_PROCESSED: + case TD_TOBE_PROCESSED_2: + TransferResult = EFI_USB_ERR_NOTEXECUTE; + break; + + case TD_DEVICE_STALL: + TransferResult = EFI_USB_ERR_STALL; + break; + + case TD_BUFFER_OVERRUN: + case TD_BUFFER_UNDERRUN: + TransferResult = EFI_USB_ERR_BUFFER; + break; + + case TD_CRC_ERROR: + TransferResult = EFI_USB_ERR_CRC; + break; + + case TD_NO_RESPONSE: + TransferResult = EFI_USB_ERR_TIMEOUT; + break; + + case TD_BITSTUFFING_ERROR: + TransferResult = EFI_USB_ERR_BITSTUFF; + break; + + default: + TransferResult = EFI_USB_ERR_SYSTEM; + } + + return TransferResult; +} + + +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ) +{ + UINT32 TdCompletionCode; + + *Result = EFI_USB_NOERROR; + + while (Td) { + TdCompletionCode = Td->Word0.ConditionCode; + + *Result |= ConvertErrorCode(TdCompletionCode); + // + // if any error encountered, stop processing the left TDs. + // + if (*Result) { + return FALSE; + } + + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + } + return TRUE; + +} + + +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ) +{ + while(HeadTd != NULL) { + if (HeadTd->NextTDPointer == 0) { + return TD_NO_ERROR; + } + if (HeadTd->Word0.ConditionCode != 0) { + return HeadTd->Word0.ConditionCode; + } + EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0; + HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); + } + if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) { + return TD_TOBE_PROCESSED; + } + return TD_NO_ERROR; +} + +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ) +{ + EdResult->ErrorCode = TD_TOBE_PROCESSED; + + switch (ListType) { + case CONTROL_LIST: + if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + case BULK_LIST: + if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) { + return EFI_NOT_READY; + } + break; + default: + break; + } + + EdResult->ErrorCode = CheckEDStatus (Ed, HeadTd, EdResult); + + if (EdResult->ErrorCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } else if (EdResult->ErrorCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } else { + return EFI_DEVICE_ERROR; + } +} + + +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ) +{ + if (ConditionCode == TD_NO_ERROR) { + return EFI_SUCCESS; + } + + if (ConditionCode == TD_TOBE_PROCESSED) { + return EFI_NOT_READY; + } + + return EFI_DEVICE_ERROR; +} + +/** + + Invoke callbacks hooked on done TDs + + @Param Entry Interrupt transfer transaction information data structure + @Param Context Ohc private data + +**/ + +VOID +OhciInvokeInterruptCallBack( + IN INTERRUPT_CONTEXT_ENTRY *Entry, + IN UINT32 Result +) +{ + //Generally speaking, Keyboard driver should not + //check the Keyboard buffer if an error happens, it will be robust + //if we NULLed the buffer once error happens + if (Result) { + Entry->CallBackFunction ( + NULL, + 0, + Entry->Context, + Result + ); + }else{ + Entry->CallBackFunction ( + (VOID *)(UINTN)(Entry->DataTd->DataBuffer), + Entry->DataTd->ActualSendLength, + Entry->Context, + Result + ); + } +} + + +/** + + Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs + + @param Event Event handle + @param Context Device private data + +**/ + +VOID +EFIAPI +OhciHouseKeeper ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + + USB_OHCI_HC_DEV *Ohc; + INTERRUPT_CONTEXT_ENTRY *Entry; + INTERRUPT_CONTEXT_ENTRY *PreEntry; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *DataTd; + TD_DESCRIPTOR *HeadTd; + + UINT8 Toggle; + EFI_TPL OriginalTPL; + UINT32 Result; + + Ohc = (USB_OHCI_HC_DEV *) Context; + OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY); + + Entry = Ohc->InterruptContextList; + PreEntry = NULL; + + while(Entry != NULL) { + + OhciCheckTDsResults(Ohc, Entry->DataTd, &Result ); + if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) || + ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) { + PreEntry = Entry; + Entry = Entry->NextEntry; + continue; + } + + if (Entry->CallBackFunction != NULL) { + OhciInvokeInterruptCallBack (Entry, Result); + if (Ohc->InterruptContextList == NULL) { + gBS->RestoreTPL (OriginalTPL); + return; + } + } + if (Entry->IsPeriodic) { + + Ed = Entry->Ed; + HeadTd = Entry->DataTd; + DataTd = HeadTd; + Toggle = 0; + if (Result == EFI_USB_NOERROR) { + // + // Update toggle if there is no error, and re-submit the interrupt Ed&Tds + // + if ((Ed != NULL) && (DataTd != NULL)) { + Ed->Word0.Skip = 1; + } + // + // From hcir1_0a.pdf 4.2.2 + // ToggleCarry:This bit is the data toggle carry bit, + // Whenever a TD is retired, this bit is written to + // contain the last data toggle value(LSb of data Toggel + // file) from the retired TD. + // This field is not used for Isochronous Endpoints + // + if (Ed == NULL) { + return; + } + Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); + while(DataTd != NULL) { + if (DataTd->NextTDPointer == 0) { + DataTd->Word0.DataToggle = 0; + break; + } else { + OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle); + } + DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); + Toggle ^= 1; + } + // + // HC will only update DataToggle, ErrorCount, ConditionCode + // CurrentBufferPointer & NextTD, so we only need to update + // them once we want to active them again + // + DataTd = HeadTd; + while (DataTd != NULL) { + if (DataTd->NextTDPointer == 0) { + OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0); + break; + } + OhciSetTDField (DataTd, TD_ERROR_CNT, 0); + OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); + DataTd->NextTD = DataTd->NextTDPointer; + DataTd->CurrBufferPointer = DataTd->DataBuffer; + DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); + } + // + // Active current Ed,Td + // + // HC will only update Halted, ToggleCarry & TDQueueHeadPointer, + // So we only need to update them once we want to active them again. + // + if ((Ed != NULL) && (DataTd != NULL)) { + Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4); + OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0); + Ed->Word0.Skip = 0; + } + } else { + return; + } + } else { + if (PreEntry == NULL) { + Ohc->InterruptContextList = Entry->NextEntry; + } else { + PreEntry = Entry; + PreEntry->NextEntry = Entry->NextEntry; + } + OhciFreeInterruptContextEntry (Ohc, PreEntry); + gBS->RestoreTPL (OriginalTPL); + return; + } + PreEntry = Entry; + Entry = Entry->NextEntry; + } + gBS->RestoreTPL (OriginalTPL); +} + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.h new file mode 100644 index 0000000..1c4114c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciSched.h @@ -0,0 +1,225 @@ +/** @file +This file contains the definination for host controller schedule routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#ifndef _OHCI_SCHED_H +#define _OHCI_SCHED_H + +#include "Descriptor.h" + +#define HCCA_MEM_SIZE 256 +#define GRID_SIZE 16 +#define GRID_SHIFT 4 + +typedef struct _INTERRUPT_CONTEXT_ENTRY INTERRUPT_CONTEXT_ENTRY; + +struct _INTERRUPT_CONTEXT_ENTRY{ + UINT8 DeviceAddress; + UINT8 EndPointAddress; + ED_DESCRIPTOR *Ed; + TD_DESCRIPTOR *DataTd; + BOOLEAN IsSlowDevice; + UINT8 MaxPacketLength; + UINTN PollingInterval; + EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction; + VOID *Context; + BOOLEAN IsPeriodic; + VOID *Buffer; + UINTN DataLength; + VOID *UCBuffer; + VOID *UCBufferMapping; + UINT8 *Toggle; + INTERRUPT_CONTEXT_ENTRY *NextEntry; +}; + + +typedef struct { + UINT32 ErrorCode; + UINT8 NextToggle; +} OHCI_ED_RESULT; + +/** + + Add an item of interrupt context + + @param Ohc UHC private data + @param NewEntry New entry to add + + @retval EFI_SUCCESS Item successfully added + +**/ +EFI_STATUS +OhciAddInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *NewEntry + ); + +/** + + Free a interrupt context entry + + @param Ohc UHC private data + @param Entry Pointer to an interrupt context entry + + @retval EFI_SUCCESS Entry freed + @retval EFI_INVALID_PARAMETER Entry is NULL + +**/ +EFI_STATUS +OhciFreeInterruptContextEntry ( + IN USB_OHCI_HC_DEV *Ohc, + IN INTERRUPT_CONTEXT_ENTRY *Entry + ); + +/** + + Free entries match the device address and endpoint address + + @Param Ohc UHC private date + @Param DeviceAddress Item to free must match this device address + @Param EndPointAddress Item to free must match this end point address + @Param DataToggle DataToggle for output + + @retval EFI_SUCCESS Items match the requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptContext( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + OUT UINT8 *DataToggle + ); + + +/** + + Convert Error code from OHCI format to EFI format + + @Param ErrorCode ErrorCode in OHCI format + + @retval ErrorCode in EFI format + +**/ +UINT32 +ConvertErrorCode ( + IN UINT32 ErrorCode + ); + + +/** + + Check TDs Results + + @Param Ohc UHC private data + @Param Td TD_DESCRIPTOR + @Param Result Result to return + + @retval TRUE means OK + @retval FLASE means Error or Short packet + +**/ +BOOLEAN +OhciCheckTDsResults ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td, + OUT UINT32 *Result + ); +/** + + Check the task status on an ED + + @Param Ed Pointer to the ED task that TD hooked on + @Param HeadTd TD header for current transaction + + @retval Task Status Code + +**/ + +UINT32 +CheckEDStatus ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ); +/** + + Check the task status + + @Param Ohc UHC private data + @Param ListType Pipe type + @Param Ed Pointer to the ED task hooked on + @Param HeadTd Head of TD corresponding to the task + @Param ErrorCode return the ErrorCode + + @retval EFI_SUCCESS Task done + @retval EFI_NOT_READY Task on processing + @retval EFI_DEVICE_ERROR Some error occured + +**/ +EFI_STATUS +CheckIfDone ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd, + OUT OHCI_ED_RESULT *EdResult + ); + +/** + + Convert TD condition code to Efi Status + + @Param ConditionCode Condition code to convert + + @retval EFI_SUCCESS No error occured + @retval EFI_NOT_READY TD still on processing + @retval EFI_DEVICE_ERROR Error occured in processing TD + +**/ + +EFI_STATUS +OhciTDConditionCodeToStatus ( + IN UINT32 ConditionCode + ); + +/** + + Invoke callbacks hooked on done TDs + + @Param Entry Interrupt transfer transaction information data structure + @Param Context Ohc private data + +**/ + +VOID +OhciInvokeInterruptCallBack( + IN INTERRUPT_CONTEXT_ENTRY *Entry, + IN UINT32 Result +); + + +/** + + Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs + + @param Event Event handle + @param Context Device private data + +**/ + +VOID +EFIAPI +OhciHouseKeeper ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.c new file mode 100644 index 0000000..fb0b56a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.c @@ -0,0 +1,889 @@ +/** @file +This file contains URB request, each request is warpped in a +URB (Usb Request Block). + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + + +#include "Ohci.h" + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + TD_DESCRIPTOR *Td; + + Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR)); + if (Td == NULL) { + DEBUG ((DEBUG_INFO, "STV allocate TD fail !\r\n")); + return NULL; + } + Td->CurrBufferPointer = 0; + Td->NextTD = 0; + Td->BufferEndPointer = 0; + Td->NextTDPointer = 0; + + return Td; +} + + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ) +{ + if (Td == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR)); + + return EFI_SUCCESS; +} + + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ) +{ + ED_DESCRIPTOR *Ed; + Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR)); + if (Ed == NULL) { + DEBUG ((DEBUG_INFO, "STV allocate ED fail !\r\n")); + return NULL; + } + Ed->Word0.Skip = 1; + Ed->TdTailPointer = 0; + Ed->Word2.TdHeadPointer = 0; + Ed->NextED = 0; + + return Ed; +} + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + if (Ed == NULL) { + return EFI_SUCCESS; + } + UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); + + return EFI_SUCCESS; +} + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ) +{ + TD_DESCRIPTOR *HeadTd; + TD_DESCRIPTOR *TailTd; + TD_DESCRIPTOR *Td; + TD_DESCRIPTOR *TempTd; + + if (Ed == NULL) { + return EFI_SUCCESS; + } + + HeadTd = TD_PTR (Ed->Word2.TdHeadPointer); + TailTd = (TD_DESCRIPTOR *)(UINTN)(Ed->TdTailPointer); + + Td = HeadTd; + while (Td != TailTd) { + TempTd = Td; + Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer); + OhciFreeTD (Ohc, TempTd); + } + + return EFI_SUCCESS; +} + +/** + + Find a working ED match the requirement + + @Param EdHead Head of the ED list + @Param DeviceAddress Device address to search + @Param EndPointNum End point num to search + @Param EdDir ED Direction to search + + @retval ED descriptor searched + +**/ + +ED_DESCRIPTOR * +OhciFindWorkingEd ( + IN ED_DESCRIPTOR *EdHead, + IN UINT8 DeviceAddress, + IN UINT8 EndPointNum, + IN UINT8 EdDir + ) +{ + ED_DESCRIPTOR *Ed; + + for (Ed = EdHead; Ed != NULL; Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED)) { + if (Ed->Word2.Halted == 0 && Ed->Word0.Skip == 0 && + Ed->Word0.FunctionAddress == DeviceAddress && Ed->Word0.EndPointNum == EndPointNum && + Ed->Word0.Direction == EdDir) { + break; + } + } + + return Ed; +} + + +/** + + Initialize interrupt list. + + @Param Ohc Device private data + + @retval EFI_SUCCESS Initialization done + +**/ +EFI_STATUS +OhciInitializeInterruptList ( + USB_OHCI_HC_DEV *Ohc + ) +{ + static UINT32 Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, + 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; + UINT32 *HccaInterruptTable; + UINTN Index; + UINTN Level; + UINTN Count; + ED_DESCRIPTOR *NewEd; + + HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable; + + for (Index = 0; Index < 32; Index++) { + NewEd = OhciCreateED (Ohc); + if (NewEd == NULL) { + return EFI_OUT_OF_RESOURCES; + } + HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd; + } + + for (Index = 0; Index < 32; Index++) { + Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]]; + } + + Count = 32; + for (Level = 1; Level <= 5; Level++) { + Count = Count >> 1; + + for (Index = 0; Index < Count; Index++) { + Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc); + if (HccaInterruptTable[Index] == 0) { + return EFI_OUT_OF_RESOURCES; + } + Ohc->IntervalList[Level - 1][Index * 2 ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; + Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index]; + } + } + + return EFI_SUCCESS; +} + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ) +{ + ED_DESCRIPTOR *Temp; + + if (Ed == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Ed->NextED == 0){ + Ed->NextED = (UINT32)(UINTN)NewEd; + } else { + Temp = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Ed->NextED = (UINT32)(UINTN)NewEd; + NewEd->NextED = (UINT32)(UINTN)Temp; + } + + return EFI_SUCCESS; +} + + +/** + + Count ED number on a ED chain + + @Param Ed Head of the ED chain + + @retval ED number on the chain + +**/ + +UINTN +CountEdNum ( + IN ED_DESCRIPTOR *Ed + ) +{ + UINTN Count; + + Count = 0; + + while (Ed) { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Count++; + } + + return Count; +} + +/** + + Find the minimal burn ED list on a specific depth level + + @Param Ohc Device private data + @Param Depth Depth level + + @retval ED list found + +**/ + +ED_DESCRIPTOR * +OhciFindMinInterruptEDList ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Depth + ) +{ + UINTN EdNum; + UINTN MinEdNum; + ED_DESCRIPTOR *TempEd; + ED_DESCRIPTOR *HeadEd; + UINTN Index; + + if (Depth > 5) { + return NULL; + } + + MinEdNum = 0xFFFFFFFF; + TempEd = NULL; + for (Index = 0; Index < (UINTN)(32 >> Depth); Index++) { + HeadEd = Ohc->IntervalList[Depth][Index]; + EdNum = CountEdNum (HeadEd); + if (EdNum < MinEdNum) { + MinEdNum = EdNum; + TempEd = HeadEd; + } + } + + ASSERT (TempEd != NULL); + + return TempEd; +} + + +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +ED_DESCRIPTOR * +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ) +{ + ED_DESCRIPTOR *HeadEd; + + HeadEd = NULL; + switch(ListType) { + case CONTROL_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed); + HeadEd = Ed; + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case BULK_LIST: + HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD); + if (HeadEd == NULL) { + OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed); + HeadEd = Ed; + } else { + OhciAttachED (HeadEd, Ed); + } + break; + + case INTERRUPT_LIST: + OhciAttachED (EdList, Ed); + break; + + default: + ASSERT (FALSE); + } + + return HeadEd; +} + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param IntEd The address of Interrupt endpoint + + @retval EFI_SUCCESS EDs match requirement removed + +**/ + +EFI_STATUS +OhciFreeInterruptEdByEd ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *IntEd + ) +{ + ED_DESCRIPTOR *Ed; + ED_DESCRIPTOR *TempEd; + UINTN Index; + + if (IntEd == NULL) + return EFI_SUCCESS; + + for (Index = 0; Index < 32; Index++) { + Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index]; + if (Ed == NULL) { + continue; + } + while (Ed->NextED != 0) { + if (Ed->NextED == (UINT32)(UINTN)IntEd ) { + TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + Ed->NextED = TempEd->NextED; + OhciFreeED (Ohc, TempEd); + } else { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + } + } + } + return EFI_SUCCESS; +} + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param FunctionAddress Requirement on function address + @Param EndPointNum Requirement on end point number + + @retval EFI_SUCCESS EDs match requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptEdByAddr ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 FunctionAddress, + IN UINT8 EndPointNum + ) +{ + ED_DESCRIPTOR *Ed; + ED_DESCRIPTOR *TempEd; + UINTN Index; + + for (Index = 0; Index < 32; Index++) { + Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index]; + if (Ed == NULL) { + continue; + } + + while (Ed->NextED != 0) { + TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + if (TempEd->Word0.FunctionAddress == FunctionAddress && + TempEd->Word0.EndPointNum == EndPointNum ) { + Ed->NextED = TempEd->NextED; + OhciFreeED (Ohc, TempEd); + } else { + Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED); + } + } + } + + return EFI_SUCCESS; +} + + +/** + + Link Td2 to the end of Td1 + + @Param Td1 TD to be linked + @Param Td2 TD to link + + @retval EFI_SUCCESS TD successfully linked + @retval EFI_INVALID_PARAMETER Td1 is NULL + +**/ +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ) +{ + TD_DESCRIPTOR *TempTd; + + if (Td1 == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Td1 == Td2) { + return EFI_SUCCESS; + } + + TempTd = Td1; + while (TempTd->NextTD != 0) { + TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD); + } + + TempTd->NextTD = (UINT32)(UINTN)Td2; + TempTd->NextTDPointer = (UINT32)(UINTN)Td2; + + return EFI_SUCCESS; +} + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ) +{ + TD_DESCRIPTOR *TempTd; + + TempTd = TD_PTR (Ed->Word2.TdHeadPointer); + + if (TempTd != NULL) { + while (TempTd->NextTD != 0) { + TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD); + } + TempTd->NextTD = (UINT32)(UINTN)HeadTd; + TempTd->NextTDPointer = (UINT32)(UINTN)HeadTd; + } else { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32)(UINTN)HeadTd); + } + + return EFI_SUCCESS; +} + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & ED_FUNC_ADD) { + Ed->Word0.FunctionAddress = Value; + } + if (Field & ED_ENDPT_NUM) { + Ed->Word0.EndPointNum = Value; + } + if (Field & ED_DIR) { + Ed->Word0.Direction = Value; + } + if (Field & ED_SPEED) { + Ed->Word0.Speed = Value; + } + if (Field & ED_SKIP) { + Ed->Word0.Skip = Value; + } + if (Field & ED_FORMAT) { + Ed->Word0.Format = Value; + } + if (Field & ED_MAX_PACKET) { + Ed->Word0.MaxPacketSize = Value; + } + if (Field & ED_PDATA) { + Ed->Word0.FreeSpace = Value; + } + if (Field & ED_ZERO) { + Ed->Word2.Zero = Value; + } + if (Field & ED_TDTAIL_PTR) { + Ed->TdTailPointer = Value; + } + + if (Field & ED_HALTED) { + Ed->Word2.Halted = Value; + } + if (Field & ED_DTTOGGLE) { + Ed->Word2.ToggleCarry = Value; + } + if (Field & ED_TDHEAD_PTR) { + Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value); + } + + if (Field & ED_NEXT_EDPTR) { + Ed->NextED = Value; + } + + return EFI_SUCCESS; +} + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ) +{ + switch (Field) { + case ED_FUNC_ADD: + return Ed->Word0.FunctionAddress; + break; + case ED_ENDPT_NUM: + return Ed->Word0.EndPointNum; + break; + case ED_DIR: + return Ed->Word0.Direction; + break; + case ED_SPEED: + return Ed->Word0.Speed; + break; + case ED_SKIP: + return Ed->Word0.Skip; + break; + case ED_FORMAT: + return Ed->Word0.Format; + break; + case ED_MAX_PACKET: + return Ed->Word0.MaxPacketSize; + break; + + case ED_TDTAIL_PTR: + return Ed->TdTailPointer; + break; + + case ED_HALTED: + return Ed->Word2.Halted; + break; + + case ED_DTTOGGLE: + return Ed->Word2.ToggleCarry; + break; + + case ED_TDHEAD_PTR: + return Ed->Word2.TdHeadPointer << 4; + break; + + case ED_NEXT_EDPTR: + return Ed->NextED; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ) +{ + if (Field & TD_PDATA) { + Td->Word0.Reserved = Value; + } + if (Field & TD_BUFFER_ROUND) { + Td->Word0.BufferRounding = Value; + } + if (Field & TD_DIR_PID) { + Td->Word0.DirPID = Value; + } + if (Field & TD_DELAY_INT) { + Td->Word0.DelayInterrupt = Value; + } + if (Field & TD_DT_TOGGLE) { + Td->Word0.DataToggle = Value | 0x2; + } + if (Field & TD_ERROR_CNT) { + Td->Word0.ErrorCount = Value; + } + if (Field & TD_COND_CODE) { + Td->Word0.ConditionCode = Value; + } + + if (Field & TD_CURR_BUFFER_PTR) { + Td->CurrBufferPointer = Value; + } + + + if (Field & TD_NEXT_PTR) { + Td->NextTD = Value; + } + + if (Field & TD_BUFFER_END_PTR) { + Td->BufferEndPointer = Value; + } + + return EFI_SUCCESS; +} + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ) +{ + switch (Field){ + case TD_BUFFER_ROUND: + return Td->Word0.BufferRounding; + break; + case TD_DIR_PID: + return Td->Word0.DirPID; + break; + case TD_DELAY_INT: + return Td->Word0.DelayInterrupt; + break; + case TD_DT_TOGGLE: + return Td->Word0.DataToggle; + break; + case TD_ERROR_CNT: + return Td->Word0.ErrorCount; + break; + case TD_COND_CODE: + return Td->Word0.ConditionCode; + break; + case TD_CURR_BUFFER_PTR: + return Td->CurrBufferPointer; + break; + + case TD_NEXT_PTR: + return Td->NextTD; + break; + + case TD_BUFFER_END_PTR: + return Td->BufferEndPointer; + break; + + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + + Free the Ed,Td,buffer that were created during transferring + + @Param Ohc Device private data +**/ + +VOID +OhciFreeDynamicIntMemory( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + INTERRUPT_CONTEXT_ENTRY *Entry; + if (Ohc != NULL) { + while (Ohc->InterruptContextList != NULL) { + Entry = Ohc->InterruptContextList; + Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry; + OhciFreeInterruptEdByEd (Ohc, Entry->Ed); + OhciFreeInterruptContextEntry (Ohc, Entry); + } + } +} +/** + + Free the Ed that were initilized during driver was starting, + those memory were used as interrupt ED head + + @Param Ohc Device private data + + +**/ +VOID +OhciFreeFixedIntMemory ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + static UINT32 Leaf[] = {32,16,8,4,2,1}; + UINTN Index; + UINTN Level; + + for (Level = 0; Level < 6; Level++) { + for (Index = 0; Index < Leaf[Level]; Index++) { + if (Ohc->IntervalList[Level][Index] != NULL) { + UsbHcFreeMem(Ohc->MemPool, Ohc->IntervalList[Level][Index], sizeof(ED_DESCRIPTOR)); + } + } + } +} +/** + + Release all OHCI used memory when OHCI going to quit + + @Param Ohc Device private data + + @retval EFI_SUCCESS Memory released + +**/ + +EFI_STATUS +OhciFreeIntTransferMemory ( + IN USB_OHCI_HC_DEV *Ohc + ) +{ + // + // Free the Ed,Td,buffer that were created during transferring + // + OhciFreeDynamicIntMemory (Ohc); + // + // Free the Ed that were initilized during driver was starting + // + OhciFreeFixedIntMemory (Ohc); + return EFI_SUCCESS; +} + + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.h new file mode 100644 index 0000000..6bf2fe7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/OhciUrb.h @@ -0,0 +1,387 @@ +/** @file +Provides some data struct used by OHCI controller driver. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _OHCI_URB_H +#define _OHCI_URB_H + +#include "Descriptor.h" + + +// +// Func List +// + + +/** + + Create a TD + + @Param Ohc UHC private data + + @retval TD structure pointer + +**/ +TD_DESCRIPTOR * +OhciCreateTD ( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Free a TD + + @Param Ohc UHC private data + @Param Td Pointer to a TD to free + + @retval EFI_SUCCESS TD freed + +**/ +EFI_STATUS +OhciFreeTD ( + IN USB_OHCI_HC_DEV *Ohc, + IN TD_DESCRIPTOR *Td + ); + +/** + + Create a ED + + @Param Ohc Device private data + + @retval ED descriptor pointer + +**/ +ED_DESCRIPTOR * +OhciCreateED ( + USB_OHCI_HC_DEV *Ohc + ); + + +/** + + Free a ED + + @Param Ohc UHC private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ + +EFI_STATUS +OhciFreeED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Free ED + + @Param Ohc Device private data + @Param Ed Pointer to a ED to free + + @retval EFI_SUCCESS ED freed + +**/ +EFI_STATUS +OhciFreeAllTDFromED ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *Ed + ); + +/** + + Find a working ED match the requirement + + @Param EdHead Head of the ED list + @Param DeviceAddress Device address to search + @Param EndPointNum End point num to search + @Param EdDir ED Direction to search + + @retval ED descriptor searched + +**/ + +ED_DESCRIPTOR * +OhciFindWorkingEd ( + IN ED_DESCRIPTOR *EdHead, + IN UINT8 DeviceAddress, + IN UINT8 EndPointNum, + IN UINT8 EdDir + ); + + +/** + + Initialize interrupt list. + + @Param Ohc Device private data + + @retval EFI_SUCCESS Initialization done + +**/ +EFI_STATUS +OhciInitializeInterruptList ( + USB_OHCI_HC_DEV *Ohc + ); + +/** + + Attach an ED + + @Param Ed Ed to be attached + @Param NewEd Ed to attach + + @retval EFI_SUCCESS NewEd attached to Ed + @retval EFI_INVALID_PARAMETER Ed is NULL + +**/ +EFI_STATUS +OhciAttachED ( + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *NewEd + ); + +/** + + Count ED number on a ED chain + + @Param Ed Head of the ED chain + + @retval ED number on the chain + +**/ + +UINTN +CountEdNum ( + IN ED_DESCRIPTOR *Ed + ); + +/** + + Find the minimal burn ED list on a specific depth level + + @Param Ohc Device private data + @Param Depth Depth level + + @retval ED list found + +**/ + +ED_DESCRIPTOR * +OhciFindMinInterruptEDList ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT32 Depth + ); + +/** + + Attach an ED to an ED list + + @Param OHC UHC private data + @Param ListType Type of the ED list + @Param Ed ED to attach + @Param EdList ED list to be attached + + @retval EFI_SUCCESS ED attached to ED list + +**/ +ED_DESCRIPTOR * +OhciAttachEDToList ( + IN USB_OHCI_HC_DEV *Ohc, + IN DESCRIPTOR_LIST_TYPE ListType, + IN ED_DESCRIPTOR *Ed, + IN ED_DESCRIPTOR *EdList + ); + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param IntEd The address of Interrupt endpoint + + @retval EFI_SUCCESS EDs match requirement removed + +**/ + +EFI_STATUS +OhciFreeInterruptEdByEd ( + IN USB_OHCI_HC_DEV *Ohc, + IN ED_DESCRIPTOR *IntEd + ); + +/** + + Remove interrupt EDs that match requirement + + @Param Ohc UHC private data + @Param FunctionAddress Requirement on function address + @Param EndPointNum Requirement on end point number + + @retval EFI_SUCCESS EDs match requirement removed + +**/ +EFI_STATUS +OhciFreeInterruptEdByAddr ( + IN USB_OHCI_HC_DEV *Ohc, + IN UINT8 FunctionAddress, + IN UINT8 EndPointNum + ); + + +/** + + Link Td2 to the end of Td1 + + @Param Td1 TD to be linked + @Param Td2 TD to link + + @retval EFI_SUCCESS TD successfully linked + @retval EFI_INVALID_PARAMETER Td1 is NULL + +**/ +EFI_STATUS +OhciLinkTD ( + IN TD_DESCRIPTOR *Td1, + IN TD_DESCRIPTOR *Td2 + ); + + +/** + + Attach TD list to ED + + @Param Ed ED which TD list attach on + @Param HeadTd Head of the TD list to attach + + @retval EFI_SUCCESS TD list attached on the ED + +**/ +EFI_STATUS +OhciAttachTDListToED ( + IN ED_DESCRIPTOR *Ed, + IN TD_DESCRIPTOR *HeadTd + ); + + +/** + + Set value to ED specific field + + @Param Ed ED to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from an ED's specific field + + @Param Ed ED pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ +UINT32 +OhciGetEDField ( + IN ED_DESCRIPTOR *Ed, + IN UINT32 Field + ); + + +/** + + Set value to TD specific field + + @Param Td TD to be set + @Param Field Field to be set + @Param Value Value to set + + @retval EFI_SUCCESS Value set + +**/ +EFI_STATUS +OhciSetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field, + IN UINT32 Value + ); + + +/** + + Get value from ED specific field + + @Param Td TD pointer + @Param Field Field to get value from + + @retval Value of the field + +**/ + +UINT32 +OhciGetTDField ( + IN TD_DESCRIPTOR *Td, + IN UINT32 Field + ); +/** + + Free the Ed,Td,buffer that were created during transferring + + @Param Ohc Device private data +**/ + +VOID +OhciFreeDynamicIntMemory( + IN USB_OHCI_HC_DEV *Ohc + ); + +/** + + Free the Ed that were initilized during driver was starting, + those memory were used as interrupt ED head + + @Param Ohc Device private data + + +**/ +VOID +OhciFreeFixedIntMemory ( + IN USB_OHCI_HC_DEV *Ohc + ); +/** + + Release all OHCI used memory when OHCI going to quit + + @Param Ohc Device private data + + @retval EFI_SUCCESS Memory released + +**/ + +EFI_STATUS +OhciFreeIntTransferMemory ( + IN USB_OHCI_HC_DEV *Ohc + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.c new file mode 100644 index 0000000..c70f7e6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.c @@ -0,0 +1,546 @@ +/** @file +Routine procedures for memory allocate/free. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "Ohci.h" + + +/** + Allocate a block of memory to be used by the buffer pool. + + @param Pool The buffer pool to allocate memory for. + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +USBHC_MEM_BLOCK * +UsbHcAllocMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Pages + ) +{ + USBHC_MEM_BLOCK *Block; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + UINTN Bytes; + EFI_STATUS Status; + + Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK)); + if (Block == NULL) { + return NULL; + } + + // + // each bit in the bit array represents USBHC_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8); + Block->Bits = AllocateZeroPool (Block->BitsLen); + + if (Block->Bits == NULL) { + gBS->FreePool (Block); + return NULL; + } + + // + // Allocate the number of Pages of memory, then map it for + // bus master read and write. + // + Status = DmaAllocateBuffer ( + EfiBootServicesData, + Pages, + &BufHost + ); + + if (EFI_ERROR (Status)) { + goto FREE_BITARRAY; + } + + Bytes = EFI_PAGES_TO_SIZE (Pages); + Status = DmaMap ( + MapOperationBusMasterCommonBuffer, + BufHost, + &Bytes, + &MappedAddr, + &Mapping + ); + + if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) { + goto FREE_BUFFER; + } + + // + // Check whether the data structure used by the host controller + // should be restricted into the same 4G + // + if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) { + DmaUnmap (Mapping); + goto FREE_BUFFER; + } + + Block->BufHost = BufHost; + Block->Buf = (UINT8 *) ((UINTN) MappedAddr); + Block->Mapping = Mapping; + + return Block; + +FREE_BUFFER: + DmaFreeBuffer (Pages, BufHost); + +FREE_BITARRAY: + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); + return NULL; +} + + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +UsbHcFreeMemBlock ( + IN USBHC_MEM_POOL *Pool, + IN USBHC_MEM_BLOCK *Block + ) +{ + ASSERT ((Pool != NULL) && (Block != NULL)); + + // + // Unmap the common buffer then free the structures + // + DmaUnmap (Block->Mapping); + DmaFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost); + + gBS->FreePool (Block->Bits); + gBS->FreePool (Block); +} + + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return The pointer to the allocated memory. If couldn't allocate the needed memory, + the return value is NULL. + +**/ +VOID * +UsbHcAllocMemFromBlock ( + IN USBHC_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consective number of zero bit. + // + if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + NEXT_BIT (Byte, Bit); + + } else { + NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT; +} + +/** + Calculate the corresponding address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the pci memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINTN AllocSize; + EFI_PHYSICAL_ADDRESS PhyAddr; + UINTN Offset; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + + if (Mem == NULL) { + return 0; + } + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the allocated memory. + // + if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) { + break; + } + } + + ASSERT ((Block != NULL)); + // + // calculate the pci memory address for host memory address. + // + Offset = (UINT8 *)Mem - Block->BufHost; + PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset); + return PhyAddr; +} + + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +UsbHcInsertMemBlockToPool ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @retval TRUE The memory block is empty. + @retval FALSE The memory block isn't empty. + +**/ +BOOLEAN +UsbHcIsMemBlockEmpty ( + IN USBHC_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Unlink the memory block from the pool's list. + + @param Head The block list head of the memory's pool. + @param BlockToUnlink The memory block to unlink. + +**/ +VOID +UsbHcUnlinkMemBlock ( + IN USBHC_MEM_BLOCK *Head, + IN USBHC_MEM_BLOCK *BlockToUnlink + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT ((Head != NULL) && (BlockToUnlink != NULL)); + + for (Block = Head; Block != NULL; Block = Block->Next) { + if (Block->Next == BlockToUnlink) { + Block->Next = BlockToUnlink->Next; + BlockToUnlink->Next = NULL; + break; + } + } +} + + +/** + Initialize the memory management pool for the host controller. + + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN BOOLEAN Check4G, + IN UINT32 Which4G + ) +{ + USBHC_MEM_POOL *Pool; + + Pool = AllocatePool (sizeof (USBHC_MEM_POOL)); + + if (Pool == NULL) { + return Pool; + } + + Pool->Check4G = Check4G; + Pool->Which4G = Which4G; + Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + gBS->FreePool (Pool); + Pool = NULL; + } + + return Pool; +} + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ) +{ + USBHC_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // UsbHcUnlinkMemBlock can't be used to unlink and free the + // first block. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + UsbHcUnlinkMemBlock (Pool->Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + UsbHcFreeMemBlock (Pool, Pool->Head); + gBS->FreePool (Pool); + return EFI_SUCCESS; +} + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + USBHC_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = USBHC_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = USBHC_MEM_DEFAULT_PAGES; + } + + NewBlock = UsbHcAllocMemBlock (Pool, Pages); + + if (NewBlock == NULL) { + DEBUG ((DEBUG_INFO, "UsbHcAllocateMem: failed to allocate block\n")); + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + UsbHcInsertMemBlockToPool (Head, NewBlock); + Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + USBHC_MEM_BLOCK *Head; + USBHC_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = USBHC_MEM_ROUND (Size); + ToFree = (UINT8 *) Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8; + Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8; + + // + // reset associated bits in bit arry + // + for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) { + ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit)); + NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) { + UsbHcUnlinkMemBlock (Head, Block); + UsbHcFreeMemBlock (Pool, Block); + } + + return ; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.h new file mode 100644 index 0000000..3948ea5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/OhciDxe/UsbHcMem.h @@ -0,0 +1,150 @@ +/** @file +This file contains the definination for host controller memory +management routines. + +Copyright (c) 2013-2015 Intel Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _USB_HC_MEM_H_ +#define _USB_HC_MEM_H_ + +#define USB_HC_BIT(a) ((UINTN)(1 << (a))) + +#define USB_HC_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit))) + +#define USB_HC_HIGH_32BIT(Addr64) \ + ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF)) + +typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK; +struct _USBHC_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + USBHC_MEM_BLOCK *Next; +}; + +// +// USBHC_MEM_POOL is used to manage the memory used by USB +// host controller. EHCI requires the control memory and transfer +// data to be on the same 4G memory. +// +typedef struct _USBHC_MEM_POOL { + BOOLEAN Check4G; + UINT32 Which4G; + USBHC_MEM_BLOCK *Head; +} USBHC_MEM_POOL; + +// +// Memory allocation unit, must be 2^n, n>4 +// +#define USBHC_MEM_UNIT 64 + +#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1) +#define USBHC_MEM_DEFAULT_PAGES 16 + +#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + + + +/** + Initialize the memory management pool for the host controller. + + @param PciIo The PciIo that can be used to access the host controller. + @param Check4G Whether the host controller requires allocated memory + from one 4G address space. + @param Which4G The 4G memory area each memory allocated should be from. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool. + +**/ +USBHC_MEM_POOL * +UsbHcInitMemPool ( + IN BOOLEAN Check4G, + IN UINT32 Which4G + ); + + +/** + Release the memory management pool. + + @param Pool The USB memory pool to free. + + @retval EFI_SUCCESS The memory pool is freed. + @retval EFI_DEVICE_ERROR Failed to free the memory pool. + +**/ +EFI_STATUS +UsbHcFreeMemPool ( + IN USBHC_MEM_POOL *Pool + ); + + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +UsbHcAllocateMem ( + IN USBHC_MEM_POOL *Pool, + IN UINTN Size + ); + + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +UsbHcFreeMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +/** + Calculate the corresponding address according to the Mem parameter. + + @param Pool The memory pool of the host controller. + @param Mem The pointer to host memory. + @param Size The size of the memory region. + + @return the memory address +**/ +EFI_PHYSICAL_ADDRESS +UsbHcGetAddressForHostMem ( + IN USBHC_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.c new file mode 100644 index 0000000..845aec4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.c @@ -0,0 +1,869 @@ +/** @file + * + * PCA9555 GPIO driver for Rockchip platforms. + * + * Contribs: + * + * Copyright (c) 2018, Marvell International Ltd. All rights reserved. + * Copyright (c) 2023, Mario Bălănică + * Copyright (c) 2023, Shimrra Shai + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Pca9555Dxe.h" + +STATIC CONST EFI_GUID I2cGuid = I2C_GUID; + +/* Much of the driver below is ripped from the Marvell version, with + * some adaptation. + */ + +/* --- Low-level Methods --- */ + +EFI_STATUS +EFIAPI +Pca95xxI2cTransfer ( + IN EFI_I2C_IO_PROTOCOL *I2cIo, + IN UINT8 Address, + IN UINT8 *Buffer, + IN BOOLEAN Read + ) +{ + EFI_I2C_REQUEST_PACKET *RequestPacket; + UINTN RequestPacketSize; + UINT8 AddressBuffer; + UINT8 WritePacketBuffer[2]; + EFI_STATUS Status; + UINTN NumOps; + + if (Read) { + NumOps = 2; + } else { + NumOps = 1; + } + + RequestPacketSize = sizeof (UINTN) + + sizeof (EFI_I2C_OPERATION) * NumOps; + RequestPacket = AllocateZeroPool (RequestPacketSize); + if (RequestPacket == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + /* Operations contain address and payload, consecutively. */ + /* Note: in the Rockchip I2C driver, a special control byte is sent with + * each operation *implicitly*. PCA9555 expects this only ONCE. So + * unlike the Marvell driver, we should encode the whole operation + * on a single buffer. + */ + if (Read) { + RequestPacket->OperationCount = NumOps; + RequestPacket->Operation[0].LengthInBytes = 1; + RequestPacket->Operation[0].Buffer = &AddressBuffer; + RequestPacket->Operation[0].Buffer[0] = Address & MAX_UINT8; + RequestPacket->Operation[0].Flags = 0; + + RequestPacket->Operation[1].LengthInBytes = 1; + RequestPacket->Operation[1].Buffer = Buffer; + RequestPacket->Operation[1].Flags = I2C_FLAG_READ; + } else { + RequestPacket->OperationCount = NumOps; + RequestPacket->Operation[0].LengthInBytes = 2; + RequestPacket->Operation[0].Buffer = WritePacketBuffer; + RequestPacket->Operation[0].Buffer[0] = Address & MAX_UINT8; + RequestPacket->Operation[0].Buffer[1] = Buffer[0]; + RequestPacket->Operation[0].Flags = 0; + } + + Status = I2cIo->QueueRequest (I2cIo, 0, NULL, RequestPacket, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: transmission error: 0x%d\n", + __FUNCTION__, + Status)); + } + + gBS->FreePool(RequestPacket); + + return Status; +} + +STATIC +EFI_STATUS +Pca95xxReadRegs ( + IN EFI_I2C_IO_PROTOCOL *I2cIo, + IN UINT8 Reg, + OUT UINT8 *RegVal + ) +{ + return Pca95xxI2cTransfer (I2cIo, Reg, RegVal, TRUE); +} + +STATIC +EFI_STATUS +Pca95xxWriteRegs ( + IN EFI_I2C_IO_PROTOCOL *I2cIo, + IN UINTN Reg, + IN UINT8 RegVal + ) +{ + return Pca95xxI2cTransfer (I2cIo, Reg, &RegVal, FALSE); +} + +#if 0 +VOID +EFIAPI +DumpRegs ( + IN EFI_I2C_IO_PROTOCOL *I2cIo + ) +{ + UINT8 Regs[6]; + Pca95xxReadRegs(I2cIo, 0x0, &Regs[0]); + Pca95xxReadRegs(I2cIo, 0x1, &Regs[1]); + Pca95xxReadRegs(I2cIo, 0x2, &Regs[2]); + Pca95xxReadRegs(I2cIo, 0x3, &Regs[3]); + Pca95xxReadRegs(I2cIo, 0x4, &Regs[4]); + Pca95xxReadRegs(I2cIo, 0x5, &Regs[5]); + Pca95xxReadRegs(I2cIo, 0x6, &Regs[6]); + Pca95xxReadRegs(I2cIo, 0x7, &Regs[7]); + + DEBUG ((DEBUG_INFO, "PCA9555 state:\n")); + DEBUG ((DEBUG_INFO, "reg 0 = 0x%02X\n", Regs[0])); + DEBUG ((DEBUG_INFO, "reg 1 = 0x%02X\n", Regs[1])); + DEBUG ((DEBUG_INFO, "reg 2 = 0x%02X\n", Regs[2])); + DEBUG ((DEBUG_INFO, "reg 3 = 0x%02X\n", Regs[3])); + DEBUG ((DEBUG_INFO, "reg 4 = 0x%02X\n", Regs[4])); + DEBUG ((DEBUG_INFO, "reg 5 = 0x%02X\n", Regs[5])); + DEBUG ((DEBUG_INFO, "reg 6 = 0x%02X\n", Regs[6])); + DEBUG ((DEBUG_INFO, "reg 7 = 0x%02X\n", Regs[7])); + DEBUG ((DEBUG_INFO, "\n")); +} +#endif + +/* ------------------------- */ + +/* --- Driver Methods --- */ +STATIC PCA9555_CONTEXT *mPca9555Context = NULL; + +/* Probe the device, bringing it up. */ +EFI_STATUS +EFIAPI +Pca9555Probe ( + IN EFI_I2C_IO_PROTOCOL *I2c + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT8 Zero = 0x00; + UINTN Index; + + if (mPca9555Context != NULL) { + /* The device has already been brought online. Nothing to do. */ + return EFI_SUCCESS; + } + + mPca9555Context = AllocateZeroPool (sizeof(PCA9555_CONTEXT)); + if (mPca9555Context == NULL) { + DEBUG ((DEBUG_ERROR, "%a: context allocation failed\n", __func__)); + Status = EFI_OUT_OF_RESOURCES; + goto fail; + } + + mPca9555Context->Signature = PCA95XX_SIGNATURE; + + mPca9555Context->I2cAddress = PcdGet8 (PcdPca9555Address); + mPca9555Context->I2cBus = PcdGet8 (PcdPca9555Bus); + + /* Device setup: disable polarity inversion on all pins */ + for (Index = 0; Index < PCA9555_NUM_BANKS; ++Index) { + Status = Pca95xxWriteRegs(I2c, PCA9555_INVERSION_REG_BASE + Index, Zero); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: setup failed!\n", __FUNCTION__)); + goto fail; + } + } + + /* and preset all outputs to 0 */ + for (Index = 0; Index < PCA9555_NUM_BANKS; ++Index) { + Status = Pca95xxWriteRegs(I2c, PCA9555_OUTPUT_REG_BASE + Index, Zero); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: setup failed!\n", __FUNCTION__)); + goto fail; + } + } + + DEBUG ((DEBUG_INFO, + "%a: PCA9555 bound at I2C addr 0x%02X, bus 0x%02X\n", + __FUNCTION__, + mPca9555Context->I2cAddress, + mPca9555Context->I2cBus + )); + + return EFI_SUCCESS; +fail: + if (mPca9555Context != NULL) { + FreePool (mPca9555Context); + mPca9555Context = NULL; + } + + return Status; +} + +/* Shut down the device */ +EFI_STATUS +EFIAPI +Pca9555Unprobe ( + IN EFI_I2C_IO_PROTOCOL *I2c +) +{ + if (mPca9555Context != NULL) { + FreePool (mPca9555Context); + mPca9555Context = NULL; + + DEBUG ((DEBUG_INFO, "%a: PCA9555 has been shut down.", __FUNCTION__)); + } + + return EFI_SUCCESS; +} + +/* Read a pin register */ +EFI_STATUS +EFIAPI +Pca9555ReadPinReg ( + IN EFI_I2C_IO_PROTOCOL *I2c, + IN UINT8 BaseReg, + IN UINTN GpioPin, + OUT UINTN *Value + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Bank; + UINT8 RegVal = 0x00; + + if (mPca9555Context == NULL) { + DEBUG ((DEBUG_ERROR, "%a: device not probed", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + Bank = GpioPin / PCA95XX_BANK_SIZE; + Status = Pca95xxReadRegs (I2c, BaseReg + Bank, &RegVal); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: read failure", __FUNCTION__)); + return Status; + } + + if (RegVal & (1 << (GpioPin % PCA95XX_BANK_SIZE))) { + *Value = 1; + } else { + *Value = 0; + } + + return EFI_SUCCESS; +} + +/* Write the output pin register */ +EFI_STATUS +EFIAPI +Pca9555WritePinOutReg ( + IN EFI_I2C_IO_PROTOCOL *I2c, + IN UINTN GpioPin, + IN UINTN Value + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Bank; + UINT8 RegVal = 0x00; + + if (mPca9555Context == NULL) { + DEBUG ((DEBUG_ERROR, "%a: device not probed", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + Bank = GpioPin / PCA95XX_BANK_SIZE; + + Status = Pca95xxReadRegs (I2c, + PCA9555_OUTPUT_REG_BASE + Bank, + &RegVal + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: read failure", __FUNCTION__)); + return Status; + } + + if (Value) { + RegVal |= (1 << (GpioPin % PCA95XX_BANK_SIZE)); + } else { + RegVal &= ~(1 << (GpioPin % PCA95XX_BANK_SIZE)); + } + + Status = Pca95xxWriteRegs (I2c, + PCA9555_OUTPUT_REG_BASE + Bank, + RegVal + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: write failure", __FUNCTION__)); + return Status; + } + + return EFI_SUCCESS; +} + +/* Write the pin control register */ +EFI_STATUS +EFIAPI +Pca9555WritePinCtrlReg ( + IN EFI_I2C_IO_PROTOCOL *I2c, + IN UINTN GpioPin, + IN UINTN Value + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Bank; + UINT8 RegVal = 0x00; + + if (mPca9555Context == NULL) { + DEBUG ((DEBUG_ERROR, "%a: device not probed", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + Bank = GpioPin / PCA95XX_BANK_SIZE; + + Status = Pca95xxReadRegs (I2c, + PCA9555_CONTROL_REG_BASE + Bank, + &RegVal); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: read failure", __FUNCTION__)); + return Status; + } + + if (Value) { + RegVal |= (1 << (GpioPin % PCA95XX_BANK_SIZE)); + } else { + RegVal &= ~(1 << (GpioPin % PCA95XX_BANK_SIZE)); + } + + Status = Pca95xxWriteRegs (I2c, + PCA9555_CONTROL_REG_BASE + Bank, + RegVal); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: write failure", __FUNCTION__)); + return Status; + } + + return EFI_SUCCESS; +} + +/* ---------------------- */ + +/* --- Embedded GPIO Protocol --- */ + +/* Get the I2C */ +EFI_STATUS +EFIAPI +Pca9555GetI2c ( + IN OUT EFI_I2C_IO_PROTOCOL **I2cIo + ) +{ + UINTN I2cBus, I2cAddress; + UINTN HandleCount, Index; + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + + if (mPca9555Context == NULL) { + DEBUG ((DEBUG_ERROR, "%a: device not probed\n", __FUNCTION__)); + return EFI_UNSUPPORTED; + } + + I2cBus = mPca9555Context->I2cBus; + I2cAddress = mPca9555Context->I2cAddress; + + /* Locate Handles of all EfiI2cIoProtocol producers */ + Status = gBS->LocateHandleBuffer (ByProtocol, + &gEfiI2cIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Unable to locate handles\n", __FUNCTION__)); + return Status; + } + + /* Iterate over all protocol producers and pick one upon DeviceIndex match */ + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->OpenProtocol (HandleBuffer[Index], + &gEfiI2cIoProtocolGuid, + (VOID **)I2cIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Unable to open protocol\n", __FUNCTION__)); + gBS->FreePool (HandleBuffer); + return Status; + } + if ((*I2cIo)->DeviceIndex == I2C_DEVICE_INDEX (I2cBus, I2cAddress)) { + gBS->FreePool (HandleBuffer); + return EFI_SUCCESS; + } + } + + gBS->FreePool (HandleBuffer); + + return EFI_NOT_FOUND; +} + +#if !defined(MDEPKG_NDEBUG) +/* A validator; unlike Marvell version we only assume 1 chip */ +STATIC +EFI_STATUS +Pca9555ValidatePin ( + IN UINTN GpioPin + ) +{ + UINTN ControllerId; + + if (GpioPin >= PCA9555_NUM_GPIO) { + DEBUG ((DEBUG_ERROR, + "%a: GPIO pin #%d not available\n", + __FUNCTION__, + GpioPin)); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} +#endif + +/** + +Routine Description: + + Gets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to read + Value - state of the pin + +Returns: + + EFI_SUCCESS - GPIO state returned in Value + EFI_INVALID_PARAMETER - Value is NULL pointer or Gpio pin is out of range +**/ +STATIC +EFI_STATUS +Pca9555Get ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT UINTN *Value + ) +{ + EFI_I2C_IO_PROTOCOL *I2cIo; + EFI_STATUS Status; + UINTN GpioPin; + UINT8 RegVal; + UINTN Bank; + + GpioPin = GPIO_PIN (Gpio); + + ASSERT_EFI_ERROR (Pca9555ValidatePin (GpioPin)); + + Status = Pca9555GetI2c (&I2cIo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__)); + return Status; + } + + Status = Pca9555ReadPinReg(I2cIo, PCA9555_INPUT_REG_BASE, Gpio, Value); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: register read failure\n", __FUNCTION__)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + +Routine Description: + + Sets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to modify + Mode - mode to set + +Returns: + + EFI_SUCCESS - GPIO set as requested + EFI_UNSUPPORTED - Mode is not supported + EFI_INVALID_PARAMETER - Gpio pin is out of range +**/ +STATIC +EFI_STATUS +Pca9555Set ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_MODE Mode + ) +{ + EFI_I2C_IO_PROTOCOL *I2cIo; + EFI_STATUS Status; + UINTN GpioPin; + UINTN Bit; + + GpioPin = GPIO_PIN (Gpio); + + ASSERT_EFI_ERROR (Pca9555ValidatePin (GpioPin)); + + Status = Pca9555GetI2c (&I2cIo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__)); + return Status; + } + +#if 0 + DEBUG ((DEBUG_INFO, "Status before set of pin %d to mode 0x%02X:\n", Gpio, Mode)); + DumpRegs(I2cIo); +#endif + + switch (Mode) { + case GPIO_MODE_OUTPUT_0: + case GPIO_MODE_OUTPUT_1: + if (Mode == GPIO_MODE_OUTPUT_0) { + Bit = 0; + } else { + Bit = 1; + } + + Status = Pca9555WritePinOutReg (I2cIo, GpioPin, Bit); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to set ouput value\n", __FUNCTION__)); + return Status; + } + + Status = Pca9555WritePinCtrlReg (I2cIo, GpioPin, 0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to set direction\n", __FUNCTION__)); + return Status; + } + + break; + case GPIO_MODE_INPUT: + Status = Pca9555WritePinCtrlReg (I2cIo, GpioPin, 1); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to set direction\n", __FUNCTION__)); + return Status; + } + break; + + default: + return EFI_UNSUPPORTED; + } + +#if 0 + DEBUG ((DEBUG_INFO, "Status after set:\n")); + DumpRegs(I2cIo); +#endif + + return EFI_SUCCESS; +} + +/** + +Routine Description: + + Gets the mode (function) of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Mode - pointer to output mode value + +Returns: + + EFI_SUCCESS - mode value retrieved + EFI_INVALID_PARAMETER - Mode is a null pointer or Gpio pin is out of range + +**/ +STATIC +EFI_STATUS +Pca9555GetMode ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT EMBEDDED_GPIO_MODE *Mode + ) +{ + EFI_I2C_IO_PROTOCOL *I2cIo; + EFI_STATUS Status; + UINTN GpioPin; + UINTN RegVal; + + GpioPin = GPIO_PIN (Gpio); + + ASSERT_EFI_ERROR (Pca9555ValidatePin (GpioPin)); + + Status = Pca9555GetI2c (&I2cIo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: fail to get I2C protocol\n", __FUNCTION__)); + return Status; + } + + Status = Pca9555ReadPinReg(I2cIo, PCA9555_CONTROL_REG_BASE, Gpio, &RegVal); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: register read failure\n", __FUNCTION__)); + return Status; + } + + if (RegVal == 0) { + /* output modes */ + Status = Pca9555ReadPinReg(I2cIo, PCA9555_OUTPUT_REG_BASE, Gpio, &RegVal); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: register read failure\n", __FUNCTION__)); + return Status; + } + + if (RegVal) { + *Mode = GPIO_MODE_OUTPUT_1; + } else { + *Mode = GPIO_MODE_OUTPUT_0; + } + } else { + /* input mode */ + *Mode = GPIO_MODE_INPUT; + } + + return EFI_SUCCESS; +} + +/** + +Routine Description: + + Sets the pull-up / pull-down resistor of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Direction - pull-up, pull-down, or none + +Returns: + + EFI_UNSUPPORTED - Can not perform the requested operation + +**/ +EFI_STATUS +EFIAPI +Pca9555SetPull ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_PULL Direction + ) +{ + return EFI_UNSUPPORTED; +} + +PCA95XX_PROTOCOL mPca95xxProtocol = { + .GpioProtocol = { + .Get = Pca9555Get, + .Set = Pca9555Set, + .GetMode = Pca9555GetMode, + .SetPull = Pca9555SetPull, + }, +}; + +/* ------------------------------ */ + +/* --- Binding Protocol --- */ +EFI_DRIVER_BINDING_PROTOCOL mDriverBindingProtocol = { + Pca9555Supported, + Pca9555Start, + Pca9555Stop, +}; + +EFI_STATUS +EFIAPI +Pca9555Supported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_UNSUPPORTED; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + UINT8 Pca9555Address = 0x00; + UINT8 Pca9555Bus = 0x00; + UINTN i; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Pca9555Address = PcdGet8 (PcdPca9555Address); + Pca9555Bus = PcdGet8 (PcdPca9555Bus); + + DEBUG ((DEBUG_INFO, + "%a: addr = 0x%02X, bus = 0x%02X\n", + __FUNCTION__, + Pca9555Address, + Pca9555Bus)); + + if (CompareGuid(TmpI2cIo->DeviceGuid, &I2cGuid) && + TmpI2cIo->DeviceIndex == I2C_DEVICE_INDEX(Pca9555Bus, Pca9555Address)) { + DEBUG ((DEBUG_INFO, "%a: PCA9555 device is supported\n", __FUNCTION__)); + Status = EFI_SUCCESS; + } + +/*out:*/ + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +Pca9555Start ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_I2C_IO_PROTOCOL *TmpI2cIo; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + (VOID **) &TmpI2cIo, + gImageHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Status = Pca9555Probe (TmpI2cIo); + if (EFI_ERROR (Status)) { + goto fail; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gPca95xxProtocolGuid, + &mPca95xxProtocol, + NULL); + if (EFI_ERROR (Status)) { + goto fail; + } + + Status = EFI_SUCCESS; + +fail: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + + return Status; +} + +EFI_STATUS +EFIAPI +Pca9555Stop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + gBS->UninstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gPca95xxProtocolGuid, &mPca95xxProtocol, + &gEfiDriverBindingProtocolGuid, &mDriverBindingProtocol, + NULL + ); + + /* (SS) is this necessary? */ + + /* + Status = Pca9555Unprobe(); + gBS->CloseProtocol ( + ControllerHandle, + &gEfiI2cIoProtocolGuid, + gImageHandle, + ControllerHandle + ); + */ + + return EFI_SUCCESS; +} +/* ------------------------ */ + +EFI_STATUS +EFIAPI +Pca9555DxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverBindingProtocolGuid, &mDriverBindingProtocol, + NULL + ); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.h new file mode 100644 index 0000000..530978e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.h @@ -0,0 +1,76 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* Copyright (c) 2023, Shimrra Shai +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __PCA9555_DXE_H__ +#define __PCA9555_DXE_H__ + +#include + +#define PCA95XX_SIGNATURE SIGNATURE_32 ('P', '9', '5', 'X') + +#define I2C_GUID \ + { \ + 0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \ + } + +/* NB: Only PCA9555 is supported now. This driver can/should be generalized to + * whole PCA95XX family. + */ +#define PCA9555_INPUT_REG_BASE 0x00 +#define PCA9555_OUTPUT_REG_BASE 0x02 +#define PCA9555_INVERSION_REG_BASE 0x04 +#define PCA9555_CONTROL_REG_BASE 0x06 + +#define PCA9555_NUM_GPIO 16 +#define PCA9555_NUM_BANKS 2 + +#define PCA95XX_BANK_SIZE 8 /* bits */ +#define PCA95XX_MAX_BANK 5 + +typedef struct { + UINT32 Signature; + + UINT8 I2cAddress; + UINT8 I2cBus; +} PCA9555_CONTEXT; + +/* --- Method Prototypes --- */ +EFI_STATUS +EFIAPI +Pca9555Supported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pca9555Start ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pca9555Stop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer OPTIONAL + ); + +EFI_STATUS +EFIAPI +Pca9555DxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif // __PCA9555_DXE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf new file mode 100644 index 0000000..cfb22aa --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf @@ -0,0 +1,48 @@ +#/** @file +# +# PCA9555 GPIO initializer for Rockchip platforms. +# +# Copyright (c) 2023, Mario Bălănică +# Copyright (c) 2023, Shimrra Shai +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = Pca9555Dxe + FILE_GUID = 2ee8d685-8066-4f37-ae0e-5235730b9cc7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Pca9555DxeInitialize + +[Sources.common] + Pca9555Dxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + DebugLib + +[Protocols] + gEfiDriverBindingProtocolGuid + gEfiI2cIoProtocolGuid ## CONSUMES + gPca95xxProtocolGuid ## PRODUCES + gRockchipI2cMasterProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdPca9555Address + gRockchipTokenSpaceGuid.PcdPca9555Bus + +[Depex] + TRUE + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/Crc32Table.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/Crc32Table.h new file mode 100644 index 0000000..fbbaf93 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/Crc32Table.h @@ -0,0 +1,266 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 mCrcTable[256] = { + 0x00000000, + 0x77073096, + 0xEE0E612C, + 0x990951BA, + 0x076DC419, + 0x706AF48F, + 0xE963A535, + 0x9E6495A3, + 0x0EDB8832, + 0x79DCB8A4, + 0xE0D5E91E, + 0x97D2D988, + 0x09B64C2B, + 0x7EB17CBD, + 0xE7B82D07, + 0x90BF1D91, + 0x1DB71064, + 0x6AB020F2, + 0xF3B97148, + 0x84BE41DE, + 0x1ADAD47D, + 0x6DDDE4EB, + 0xF4D4B551, + 0x83D385C7, + 0x136C9856, + 0x646BA8C0, + 0xFD62F97A, + 0x8A65C9EC, + 0x14015C4F, + 0x63066CD9, + 0xFA0F3D63, + 0x8D080DF5, + 0x3B6E20C8, + 0x4C69105E, + 0xD56041E4, + 0xA2677172, + 0x3C03E4D1, + 0x4B04D447, + 0xD20D85FD, + 0xA50AB56B, + 0x35B5A8FA, + 0x42B2986C, + 0xDBBBC9D6, + 0xACBCF940, + 0x32D86CE3, + 0x45DF5C75, + 0xDCD60DCF, + 0xABD13D59, + 0x26D930AC, + 0x51DE003A, + 0xC8D75180, + 0xBFD06116, + 0x21B4F4B5, + 0x56B3C423, + 0xCFBA9599, + 0xB8BDA50F, + 0x2802B89E, + 0x5F058808, + 0xC60CD9B2, + 0xB10BE924, + 0x2F6F7C87, + 0x58684C11, + 0xC1611DAB, + 0xB6662D3D, + 0x76DC4190, + 0x01DB7106, + 0x98D220BC, + 0xEFD5102A, + 0x71B18589, + 0x06B6B51F, + 0x9FBFE4A5, + 0xE8B8D433, + 0x7807C9A2, + 0x0F00F934, + 0x9609A88E, + 0xE10E9818, + 0x7F6A0DBB, + 0x086D3D2D, + 0x91646C97, + 0xE6635C01, + 0x6B6B51F4, + 0x1C6C6162, + 0x856530D8, + 0xF262004E, + 0x6C0695ED, + 0x1B01A57B, + 0x8208F4C1, + 0xF50FC457, + 0x65B0D9C6, + 0x12B7E950, + 0x8BBEB8EA, + 0xFCB9887C, + 0x62DD1DDF, + 0x15DA2D49, + 0x8CD37CF3, + 0xFBD44C65, + 0x4DB26158, + 0x3AB551CE, + 0xA3BC0074, + 0xD4BB30E2, + 0x4ADFA541, + 0x3DD895D7, + 0xA4D1C46D, + 0xD3D6F4FB, + 0x4369E96A, + 0x346ED9FC, + 0xAD678846, + 0xDA60B8D0, + 0x44042D73, + 0x33031DE5, + 0xAA0A4C5F, + 0xDD0D7CC9, + 0x5005713C, + 0x270241AA, + 0xBE0B1010, + 0xC90C2086, + 0x5768B525, + 0x206F85B3, + 0xB966D409, + 0xCE61E49F, + 0x5EDEF90E, + 0x29D9C998, + 0xB0D09822, + 0xC7D7A8B4, + 0x59B33D17, + 0x2EB40D81, + 0xB7BD5C3B, + 0xC0BA6CAD, + 0xEDB88320, + 0x9ABFB3B6, + 0x03B6E20C, + 0x74B1D29A, + 0xEAD54739, + 0x9DD277AF, + 0x04DB2615, + 0x73DC1683, + 0xE3630B12, + 0x94643B84, + 0x0D6D6A3E, + 0x7A6A5AA8, + 0xE40ECF0B, + 0x9309FF9D, + 0x0A00AE27, + 0x7D079EB1, + 0xF00F9344, + 0x8708A3D2, + 0x1E01F268, + 0x6906C2FE, + 0xF762575D, + 0x806567CB, + 0x196C3671, + 0x6E6B06E7, + 0xFED41B76, + 0x89D32BE0, + 0x10DA7A5A, + 0x67DD4ACC, + 0xF9B9DF6F, + 0x8EBEEFF9, + 0x17B7BE43, + 0x60B08ED5, + 0xD6D6A3E8, + 0xA1D1937E, + 0x38D8C2C4, + 0x4FDFF252, + 0xD1BB67F1, + 0xA6BC5767, + 0x3FB506DD, + 0x48B2364B, + 0xD80D2BDA, + 0xAF0A1B4C, + 0x36034AF6, + 0x41047A60, + 0xDF60EFC3, + 0xA867DF55, + 0x316E8EEF, + 0x4669BE79, + 0xCB61B38C, + 0xBC66831A, + 0x256FD2A0, + 0x5268E236, + 0xCC0C7795, + 0xBB0B4703, + 0x220216B9, + 0x5505262F, + 0xC5BA3BBE, + 0xB2BD0B28, + 0x2BB45A92, + 0x5CB36A04, + 0xC2D7FFA7, + 0xB5D0CF31, + 0x2CD99E8B, + 0x5BDEAE1D, + 0x9B64C2B0, + 0xEC63F226, + 0x756AA39C, + 0x026D930A, + 0x9C0906A9, + 0xEB0E363F, + 0x72076785, + 0x05005713, + 0x95BF4A82, + 0xE2B87A14, + 0x7BB12BAE, + 0x0CB61B38, + 0x92D28E9B, + 0xE5D5BE0D, + 0x7CDCEFB7, + 0x0BDBDF21, + 0x86D3D2D4, + 0xF1D4E242, + 0x68DDB3F8, + 0x1FDA836E, + 0x81BE16CD, + 0xF6B9265B, + 0x6FB077E1, + 0x18B74777, + 0x88085AE6, + 0xFF0F6A70, + 0x66063BCA, + 0x11010B5C, + 0x8F659EFF, + 0xF862AE69, + 0x616BFFD3, + 0x166CCF45, + 0xA00AE278, + 0xD70DD2EE, + 0x4E048354, + 0x3903B3C2, + 0xA7672661, + 0xD06016F7, + 0x4969474D, + 0x3E6E77DB, + 0xAED16A4A, + 0xD9D65ADC, + 0x40DF0B66, + 0x37D83BF0, + 0xA9BCAE53, + 0xDEBB9EC5, + 0x47B2CF7F, + 0x30B5FFE9, + 0xBDBDF21C, + 0xCABAC28A, + 0x53B39330, + 0x24B4A3A6, + 0xBAD03605, + 0xCDD70693, + 0x54DE5729, + 0x23D967BF, + 0xB3667A2E, + 0xC4614AB8, + 0x5D681B02, + 0x2A6F2B94, + 0xB40BBE37, + 0xC30C8EA1, + 0x5A05DF1B, + 0x2D02EF8D +}; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c new file mode 100644 index 0000000..8a2cf3c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.c @@ -0,0 +1,1168 @@ +/** @file + * + * Static SMBIOS Table for RK35xx based platforms + * Derived from the quartz64_uefi, RaspberryPi and EmulatorPkg packages. + * + * Note - Arm SBBR ver 1.2 required and recommended SMBIOS structures: + * BIOS Information (Type 0) + * System Information (Type 1) + * Board Information (Type 2) - Recommended + * System Enclosure (Type 3) + * Processor Information (Type 4) - CPU Driver + * Cache Information (Type 7) - For cache that is external to processor + * Port Information (Type 8) - Recommended for platforms with physical ports + * System Slots (Type 9) - If system has slots + * OEM Strings (Type 11) - Recommended + * BIOS Language Information (Type 13) - Recommended + * System Event Log (Type 15) - Recommended (does not exit on RPi) + * Physical Memory Array (Type 16) + * Memory Device (Type 17) - For each socketed system-memory Device + * Memory Array Mapped Address (Type 19) - One per contiguous block per Physical Memroy Array + * System Boot Information (Type 32) + * IPMI Device Information (Type 38) - Required for platforms with IPMIv1.0 BMC Host Interface (not applicable to RPi) + * Onboard Devices Extended Information (Type 41) - Recommended + * Redfish Host Interface (Type 42) - Required for platforms supporting Redfish Host Interface (not applicable to RPi) + * + * Copyright (c) 2017-2021, Andrey Warkentin + * Copyright (c) 2013, Linaro.org + * Copyright (c) 2012, Apple Inc. All rights reserved.
    + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2020, ARM Limited. All rights reserved. + * Copyright (c) 2021 Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Crc32Table.h" + +#define SMB_IS_DIGIT(c) (((c) >= '0') && ((c) <= '9')) + +STATIC UINT64 mMemorySize = 0; + +UINT32 +EFIAPI +CalculateCrc32NoComp( + IN UINT32 Crc, + IN VOID *Buffer, + IN UINTN Length + ) +{ + UINTN Index; + UINT8 *Ptr; + + ASSERT (Buffer != NULL); + ASSERT (Length <= (MAX_ADDRESS - ((UINTN) Buffer) + 1)); + + // + // Compute CRC + // + for (Index = 0, Ptr = Buffer; Index < Length; Index++, Ptr++) { + Crc = (Crc >> 8) ^ mCrcTable[(UINT8) Crc ^ *Ptr]; + } + + return Crc; +} + +/*********************************************************************** + SMBIOS data definition TYPE0 BIOS Information +************************************************************************/ +SMBIOS_TABLE_TYPE0 mBIOSInfoType0 = { + { EFI_SMBIOS_TYPE_BIOS_INFORMATION, sizeof (SMBIOS_TABLE_TYPE0), 0 }, + 1, // Vendor String + 2, // BiosVersion String + (UINT16) (FixedPcdGet32 (PcdFdBaseAddress) / 0x10000), // BiosSegment + 3, // BiosReleaseDate String + (UINT8) (FixedPcdGet32 (PcdFdSize) / 0x10000), // BiosSize (in 64KB) + { // BiosCharacteristics + 0, // Reserved :2; ///< Bits 0-1. + 0, // Unknown :1; + 0, // BiosCharacteristicsNotSupported :1; + 0, // IsaIsSupported :1; + 0, // McaIsSupported :1; + 0, // EisaIsSupported :1; + 0, // PciIsSupported :1; /// No PCIe support since we hide ECAM from the OS + 0, // PcmciaIsSupported :1; + 0, // PlugAndPlayIsSupported :1; + 0, // ApmIsSupported :1; + 1, // BiosIsUpgradable :1; + 0, // BiosShadowingAllowed :1; + 0, // VlVesaIsSupported :1; + 0, // EscdSupportIsAvailable :1; + 0, // BootFromCdIsSupported :1; + 1, // SelectableBootIsSupported :1; + 0, // RomBiosIsSocketed :1; + 0, // BootFromPcmciaIsSupported :1; + 0, // EDDSpecificationIsSupported :1; + 0, // JapaneseNecFloppyIsSupported :1; + 0, // JapaneseToshibaFloppyIsSupported :1; + 0, // Floppy525_360IsSupported :1; + 0, // Floppy525_12IsSupported :1; + 0, // Floppy35_720IsSupported :1; + 0, // Floppy35_288IsSupported :1; + 0, // PrintScreenIsSupported :1; + 0, // Keyboard8042IsSupported :1; + 0, // SerialIsSupported :1; + 0, // PrinterIsSupported :1; + 0, // CgaMonoIsSupported :1; + 0, // NecPc98 :1; + 0 // ReservedForVendor :32; ///< Bits 32-63. Bits 32-47 reserved for BIOS vendor + ///< and bits 48-63 reserved for System Vendor. + }, + { // BIOSCharacteristicsExtensionBytes[] + 0x01, // AcpiIsSupported :1; + // UsbLegacyIsSupported :1; + // AgpIsSupported :1; + // I2OBootIsSupported :1; + // Ls120BootIsSupported :1; + // AtapiZipDriveBootIsSupported :1; + // Boot1394IsSupported :1; + // SmartBatteryIsSupported :1; + // BIOSCharacteristicsExtensionBytes[1] + 0x0c, // BiosBootSpecIsSupported :1; + // FunctionKeyNetworkBootIsSupported :1; + // TargetContentDistributionEnabled :1; + // UefiSpecificationSupported :1; + // VirtualMachineSupported :1; + // ExtensionByte2Reserved :3; + }, + 0, // SystemBiosMajorRelease + 0, // SystemBiosMinorRelease + 0, // EmbeddedControllerFirmwareMajorRelease + 0, // EmbeddedControllerFirmwareMinorRelease + { (UINT16) (FixedPcdGet32 (PcdFdSize) / 0x100000) }, // BiosSize (in MB since Bits 15:14 = 00b) +}; + +CHAR8 mBiosVendor[128] = "EDK2"; +CHAR8 mBiosVersion[128] = "EDK2-DEV"; +CHAR8 mBiosDate[12] = "00/00/0000"; + +CHAR8 *mBIOSInfoType0Strings[] = { + mBiosVendor, // Vendor + mBiosVersion, // Version + mBiosDate, // Release Date + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE1 System Information +************************************************************************/ +SMBIOS_TABLE_TYPE1 mSysInfoType1 = { + { EFI_SMBIOS_TYPE_SYSTEM_INFORMATION, sizeof (SMBIOS_TABLE_TYPE1), 0 }, + 1, // Manufacturer String + 2, // ProductName String + 3, // Version String + 4, // SerialNumber String + { 0x25EF0280, 0xEC82, 0x42B0, { 0x8F, 0xB6, 0x10, 0xAD, 0xCC, 0xC6, 0x7C, 0x02 } }, + SystemWakeupTypePowerSwitch, + 5, // SKUNumber String + 6, // Family String +}; + +CHAR8 mSysInfoManufName[128]; +CHAR8 mSysInfoProductName[128]; +CHAR8 mSysInfoFamilyName[128]; +CHAR8 mSysInfoVersionName[128]; +CHAR8 mSysInfoSerial[sizeof (UINT64) * 2 + 1]; +CHAR8 mSysInfoSKU[sizeof (UINT64) * 2 + 1]; + +CHAR8 *mSysInfoType1Strings[] = { + mSysInfoManufName, + mSysInfoProductName, + mSysInfoVersionName, + mSysInfoSerial, + mSysInfoSKU, + mSysInfoFamilyName, + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE2 Board Information +************************************************************************/ +SMBIOS_TABLE_TYPE2 mBoardInfoType2 = { + { EFI_SMBIOS_TYPE_BASEBOARD_INFORMATION, sizeof (SMBIOS_TABLE_TYPE2), 0 }, + 1, // Manufacturer String + 2, // ProductName String + 3, // Version String + 4, // SerialNumber String + 5, // AssetTag String + { // FeatureFlag + 1, // Motherboard :1; + 0, // RequiresDaughterCard :1; + 0, // Removable :1; + 0, // Replaceable :1; + 0, // HotSwappable :1; + 0, // Reserved :3; + }, + 6, // LocationInChassis String + 0, // ChassisHandle; + BaseBoardTypeMotherBoard, // BoardType; + 0, // NumberOfContainedObjectHandles; + { 0 } // ContainedObjectHandles[1]; +}; + +CHAR8 mBoardInfoManufName[128]; +CHAR8 mBoardInfoProductName[128]; +CHAR8 mChassisAssetTag[128]; + +CHAR8 *mBoardInfoType2Strings[] = { + mBoardInfoManufName, + mBoardInfoProductName, + mSysInfoVersionName, + mSysInfoSerial, + mChassisAssetTag, + "Internal", + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE3 Enclosure Information +************************************************************************/ +SMBIOS_TABLE_TYPE3 mEnclosureInfoType3 = { + { EFI_SMBIOS_TYPE_SYSTEM_ENCLOSURE, sizeof (SMBIOS_TABLE_TYPE3), 0 }, + 1, // Manufacturer String + MiscChassisEmbeddedPc, // Type; + 2, // Version String + 3, // SerialNumber String + 4, // AssetTag String + ChassisStateSafe, // BootupState; + ChassisStateSafe, // PowerSupplyState; + ChassisStateSafe, // ThermalState; + ChassisSecurityStatusNone,// SecurityStatus; + { 0, 0, 0, 0 }, // OemDefined[4]; + 0, // Height; + 1, // NumberofPowerCords; + 0, // ContainedElementCount; + 0, // ContainedElementRecordLength; + { { 0 } }, // ContainedElements[1]; +}; +CHAR8 *mEnclosureInfoType3Strings[] = { + mSysInfoManufName, + mSysInfoProductName, + mSysInfoSerial, + mChassisAssetTag, + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE4 Processor Information +************************************************************************/ +SMBIOS_TABLE_TYPE4 mProcessorInfoType4 = { + { EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, sizeof (SMBIOS_TABLE_TYPE4), 0}, + 1, // Socket String + CentralProcessor, // ProcessorType; ///< The enumeration value from PROCESSOR_TYPE_DATA. + ProcessorFamilyIndicatorFamily2, // ProcessorFamily; ///< The enumeration value from PROCESSOR_FAMILY2_DATA. + 2, // ProcessorManufacture String; + { // ProcessorId; + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 } + }, + 3, // ProcessorVersion String; + { // Voltage; + 1, // ProcessorVoltageCapability5V :1; + 1, // ProcessorVoltageCapability3_3V :1; + 1, // ProcessorVoltageCapability2_9V :1; + 0, // ProcessorVoltageCapabilityReserved :1; ///< Bit 3, must be zero. + 0, // ProcessorVoltageReserved :3; ///< Bits 4-6, must be zero. + 0 // ProcessorVoltageIndicateLegacy :1; + }, + 0, // ExternalClock; + 0, // MaxSpeed; + 0, // CurrentSpeed; + 0x41, // Status; + ProcessorUpgradeNone, // ProcessorUpgrade; ///< The enumeration value from PROCESSOR_UPGRADE. + 0xFFFF, // L1CacheHandle; + 0xFFFF, // L2CacheHandle; + 0xFFFF, // L3CacheHandle; + 0, // SerialNumber; + 0, // AssetTag; + 0, // PartNumber; + 4, // CoreCount; + 4, // EnabledCoreCount; + 4, // ThreadCount; + 0x6C, // ProcessorCharacteristics; ///< The enumeration value from PROCESSOR_CHARACTERISTIC_FLAGS + // ProcessorReserved1 :1; + // ProcessorUnknown :1; + // Processor64BitCapble :1; + // ProcessorMultiCore :1; + // ProcessorHardwareThread :1; + // ProcessorExecuteProtection :1; + // ProcessorEnhancedVirtualization :1; + // ProcessorPowerPerformanceCtrl :1; + // Processor128bitCapble :1; + // ProcessorReserved2 :7; + ProcessorFamilyARM, // ARM Processor Family; + 0, // CoreCount2; + 0, // EnabledCoreCount2; + 0, // ThreadCount2; +}; + +CHAR8 mCpuName[128] = "Unknown ARM CPU"; + +CHAR8 *mProcessorInfoType4Strings[] = { + "Socket", + "Rockchip", + mCpuName, + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE7 Cache Information +************************************************************************/ +SMBIOS_TABLE_TYPE7 mCacheInfoType7_L1I = { + { EFI_SMBIOS_TYPE_CACHE_INFORMATION, sizeof (SMBIOS_TABLE_TYPE7), 0 }, + 1, // SocketDesignation String + 0x380, // Cache Configuration + //Cache Level :3 (L1) + //Cache Socketed :1 (Not Socketed) + //Reserved :1 + //Location :2 (Internal) + //Enabled/Disabled :1 (Enabled) + //Operational Mode :2 (Unknown) + //Reserved :6 + 0x0020, // Maximum Size (32KB) + 0x0020, // Install Size (32KB) + { // Supported SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + { // Current SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + 0, // Cache Speed unknown + CacheErrorParity, // Error Correction + CacheTypeInstruction, // System Cache Type + CacheAssociativity2Way // Associativity (RPi4 L1 Instruction cache is 3-way set associative, but SMBIOS spec does not define that) +}; +CHAR8 *mCacheInfoType7Strings_L1I[] = { + "L1 Instruction", + NULL +}; + +SMBIOS_TABLE_TYPE7 mCacheInfoType7_L1D = { + { EFI_SMBIOS_TYPE_CACHE_INFORMATION, sizeof (SMBIOS_TABLE_TYPE7), 0 }, + 1, // SocketDesignation String + 0x180, // Cache Configuration + //Cache Level :3 (L1) + //Cache Socketed :1 (Not Socketed) + //Reserved :1 + //Location :2 (Internal) + //Enabled/Disabled :1 (Enabled) + //Operational Mode :2 (WB) + //Reserved :6 + 0x0020, // Maximum Size (32KB) + 0x0020, // Install Size (32KB) + { // Supported SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + { // Current SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + 0, // Cache Speed unknown + CacheErrorSingleBit, // Error Correction + CacheTypeData, // System Cache Type + CacheAssociativity4Way // Associativity +}; +CHAR8 *mCacheInfoType7Strings_L1D[] = { + "L1 Data", + NULL +}; + +SMBIOS_TABLE_TYPE7 mCacheInfoType7_L2 = { + { EFI_SMBIOS_TYPE_CACHE_INFORMATION, sizeof (SMBIOS_TABLE_TYPE7), 0 }, + 1, // SocketDesignation String + 0x0181, // Cache Configuration + //Cache Level :3 (L2) + //Cache Socketed :1 (Not Socketed) + //Reserved :1 + //Location :2 (Internal) + //Enabled/Disabled :1 (Enabled) + //Operational Mode :2 (WB) + //Reserved :6 + 0x0200, // Maximum Size (512KB) + 0x0200, // Install Size (512KB) + { // Supported SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + { // Current SRAM Type + 0, //Other :1 + 0, //Unknown :1 + 0, //NonBurst :1 + 1, //Burst :1 + 0, //PiplelineBurst :1 + 1, //Synchronous :1 + 0, //Asynchronous :1 + 0 //Reserved :9 + }, + 0, // Cache Speed unknown + CacheErrorSingleBit, // Error Correction Multi + CacheTypeUnified, // System Cache Type + CacheAssociativity16Way // Associativity +}; +CHAR8 *mCacheInfoType7Strings_L2[] = { + "L2", + NULL +}; +/*********************************************************************** + SMBIOS data definition TYPE9 System Slot Information +************************************************************************/ +SMBIOS_TABLE_TYPE9 mSysSlotInfoType9 = { + { EFI_SMBIOS_TYPE_SYSTEM_SLOTS, sizeof (SMBIOS_TABLE_TYPE9), 0 }, + 1, // SlotDesignation String + SlotTypeOther, // SlotType; ///< The enumeration value from MISC_SLOT_TYPE. + SlotDataBusWidthOther, // SlotDataBusWidth; ///< The enumeration value from MISC_SLOT_DATA_BUS_WIDTH. + SlotUsageAvailable, // CurrentUsage; ///< The enumeration value from MISC_SLOT_USAGE. + SlotLengthOther, // SlotLength; ///< The enumeration value from MISC_SLOT_LENGTH. + 0, // SlotID; + { // SlotCharacteristics1; + 1, // CharacteristicsUnknown :1; + 0, // Provides50Volts :1; + 0, // Provides33Volts :1; + 0, // SharedSlot :1; + 0, // PcCard16Supported :1; + 0, // CardBusSupported :1; + 0, // ZoomVideoSupported :1; + 0, // ModemRingResumeSupported:1; + }, + { // SlotCharacteristics2; + 0, // PmeSignalSupported :1; + 0, // HotPlugDevicesSupported :1; + 0, // SmbusSignalSupported :1; + 0, // Reserved :5; ///< Set to 0. + }, + 0xFFFF, // SegmentGroupNum; + 0xFF, // BusNum; + 0xFF, // DevFuncNum; +}; +CHAR8 *mSysSlotInfoType9Strings[] = { + "SD Card", + NULL +}; + + +/*********************************************************************** + SMBIOS data definition TYPE 11 OEM Strings +************************************************************************/ + +CHAR8 mOemInfoProductUrl[128]; +CHAR8 mOemInfoDeviceTreeName[128]; + +SMBIOS_TABLE_TYPE11 mOemStringsType11 = { + { EFI_SMBIOS_TYPE_OEM_STRINGS, sizeof (SMBIOS_TABLE_TYPE11), 0 }, + 2 // StringCount +}; +CHAR8 *mOemStringsType11Strings[] = { + mOemInfoProductUrl, + mOemInfoDeviceTreeName, + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE16 Physical Memory ArrayInformation +************************************************************************/ +SMBIOS_TABLE_TYPE16 mPhyMemArrayInfoType16 = { + { EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY, sizeof (SMBIOS_TABLE_TYPE16), 0 }, + MemoryArrayLocationSystemBoard, // Location; ///< The enumeration value from MEMORY_ARRAY_LOCATION. + MemoryArrayUseSystemMemory, // Use; ///< The enumeration value from MEMORY_ARRAY_USE. + MemoryErrorCorrectionUnknown, // MemoryErrorCorrection; ///< The enumeration value from MEMORY_ERROR_CORRECTION. + 0x00000000, // MaximumCapacity; + 0xFFFE, // MemoryErrorInformationHandle; + 1, // NumberOfMemoryDevices; + 0x00000000ULL, // ExtendedMaximumCapacity; +}; +CHAR8 *mPhyMemArrayInfoType16Strings[] = { + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE17 Memory Device Information +************************************************************************/ +CHAR8 mMemDevInfoVendor[128]; + +SMBIOS_TABLE_TYPE17 mMemDevInfoType17 = { + { EFI_SMBIOS_TYPE_MEMORY_DEVICE, sizeof (SMBIOS_TABLE_TYPE17), 0 }, + 0, // MemoryArrayHandle; // Should match SMBIOS_TABLE_TYPE16.Handle, initialized at runtime, refer to PhyMemArrayInfoUpdateSmbiosType16() + 0xFFFE, // MemoryErrorInformationHandle; (not provided) + 0xFFFF, // TotalWidth; (unknown) + 0xFFFF, // DataWidth; (unknown) + 0xFFFF, // Size; // When bit 15 is 0: Size in MB + // When bit 15 is 1: Size in KB, and continues in ExtendedSize + // initialized at runtime, refer to PhyMemArrayInfoUpdateSmbiosType16() + MemoryFormFactorChip, // FormFactor; ///< The enumeration value from MEMORY_FORM_FACTOR. + 0, // DeviceSet; + 1, // DeviceLocator String + 0, // BankLocator String + MemoryTypeLpddr4, // MemoryType; ///< The enumeration value from MEMORY_DEVICE_TYPE. + { // TypeDetail; + 0, // Reserved :1; + 0, // Other :1; + 1, // Unknown :1; + 0, // FastPaged :1; + 0, // StaticColumn :1; + 0, // PseudoStatic :1; + 0, // Rambus :1; + 0, // Synchronous :1; + 0, // Cmos :1; + 0, // Edo :1; + 0, // WindowDram :1; + 0, // CacheDram :1; + 0, // Nonvolatile :1; + 0, // Registered :1; + 0, // Unbuffered :1; + 0, // Reserved1 :1; + }, + 0, // Speed; (unknown) + 2, // Manufacturer String + 0, // SerialNumber String + 0, // AssetTag String + 0, // PartNumber String + 0, // Attributes; (unknown rank) + 0, // ExtendedSize; (since Size < 32GB-1) + 0, // ConfiguredMemoryClockSpeed; (unknown) + 0, // MinimumVoltage; (unknown) + 0, // MaximumVoltage; (unknown) + 0, // ConfiguredVoltage; (unknown) + MemoryTechnologyDram, // MemoryTechnology ///< The enumeration value from MEMORY_DEVICE_TECHNOLOGY + {{ // MemoryOperatingModeCapability + 0, // Reserved :1; + 0, // Other :1; + 0, // Unknown :1; + 1, // VolatileMemory :1; + 0, // ByteAccessiblePersistentMemory :1; + 0, // BlockAccessiblePersistentMemory :1; + 0 // Reserved :10; + }}, + 0, // FirwareVersion + 0, // ModuleManufacturerID (unknown) + 0, // ModuleProductID (unknown) + 0, // MemorySubsystemControllerManufacturerID (unknown) + 0, // MemorySubsystemControllerProductID (unknown) + 0, // NonVolatileSize + 0xFFFFFFFFFFFFFFFFULL,// VolatileSize // initialized at runtime, refer to PhyMemArrayInfoUpdateSmbiosType16() + 0, // CacheSize + 0, // LogicalSize (since MemoryType is not MemoryTypeLogicalNonVolatileDevice) + 0, // ExtendedSpeed, + 0 // ExtendedConfiguredMemorySpeed +}; +CHAR8 *mMemDevInfoType17Strings[] = { + "SDRAM", + mMemDevInfoVendor, + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE19 Memory Array Mapped Address Information +************************************************************************/ +SMBIOS_TABLE_TYPE19 mMemArrMapInfoType19 = { + { EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS, sizeof (SMBIOS_TABLE_TYPE19), 0 }, + 0x00000000, // StartingAddress; + 0x00000000, // EndingAddress; + 0, // MemoryArrayHandle; // Should match SMBIOS_TABLE_TYPE16.Handle, initialized at runtime, refer to PhyMemArrayInfoUpdateSmbiosType16() + 1, // PartitionWidth; + 0, // ExtendedStartingAddress; // not used + 0, // ExtendedEndingAddress; // not used +}; +CHAR8 *mMemArrMapInfoType19Strings[] = { + NULL +}; + +/*********************************************************************** + SMBIOS data definition TYPE32 Boot Information +************************************************************************/ +SMBIOS_TABLE_TYPE32 mBootInfoType32 = { + { EFI_SMBIOS_TYPE_SYSTEM_BOOT_INFORMATION, sizeof (SMBIOS_TABLE_TYPE32), 0 }, + { 0, 0, 0, 0, 0, 0 }, // Reserved[6]; + BootInformationStatusNoError // BootStatus +}; + +CHAR8 *mBootInfoType32Strings[] = { + NULL +}; + + +/** + + Create SMBIOS record. + + Converts a fixed SMBIOS structure and an array of pointers to strings into + an SMBIOS record where the strings are cat'ed on the end of the fixed record + and terminated via a double NULL and add to SMBIOS table. + + SMBIOS_TABLE_TYPE32 gSmbiosType12 = { + { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 }, + 1 // StringCount + }; + + CHAR8 *gSmbiosType12Strings[] = { + "Not Found", + NULL + }; + + ... + + LogSmbiosData ( + (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12, + gSmbiosType12Strings + ); + + @param Template Fixed SMBIOS structure, required. + @param StringPack Array of strings to convert to an SMBIOS string pack. + NULL is OK. + @param DataSmbiosHandle The new SMBIOS record handle. + NULL is OK. +**/ + +EFI_STATUS +EFIAPI +LogSmbiosData ( + IN EFI_SMBIOS_TABLE_HEADER *Template, + IN CHAR8 **StringPack, + OUT EFI_SMBIOS_HANDLE *DataSmbiosHandle + ) +{ + EFI_STATUS Status; + EFI_SMBIOS_PROTOCOL *Smbios; + EFI_SMBIOS_HANDLE SmbiosHandle; + EFI_SMBIOS_TABLE_HEADER *Record; + UINTN Index; + UINTN StringSize; + UINTN Size; + CHAR8 *Str; + + // + // Locate Smbios protocol. + // + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID**)&Smbios); + + if (EFI_ERROR (Status)) { + return Status; + } + + // Calculate the size of the fixed record and optional string pack + + Size = Template->Length; + if (StringPack == NULL) { + // At least a double null is required + Size += 2; + } else { + for (Index = 0; StringPack[Index] != NULL; Index++) { + StringSize = AsciiStrSize (StringPack[Index]); + Size += StringSize; + } + if (StringPack[0] == NULL) { + // At least a double null is required + Size += 1; + } + + // Don't forget the terminating double null + Size += 1; + } + + // Copy over Template + Record = (EFI_SMBIOS_TABLE_HEADER*)AllocateZeroPool (Size); + if (Record == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (Record, Template, Template->Length); + + // Append string pack + Str = ((CHAR8*)Record) + Record->Length; + + for (Index = 0; StringPack[Index] != NULL; Index++) { + StringSize = AsciiStrSize (StringPack[Index]); + CopyMem (Str, StringPack[Index], StringSize); + Str += StringSize; + } + + *Str = 0; + SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; + Status = Smbios->Add ( + Smbios, + gImageHandle, + &SmbiosHandle, + Record + ); + + if ((Status == EFI_SUCCESS) && (DataSmbiosHandle != NULL)) { + *DataSmbiosHandle = SmbiosHandle; + } + + ASSERT_EFI_ERROR (Status); + FreePool (Record); + return Status; +} + +/*********************************************************************** + SMBIOS data update TYPE0 BIOS Information +************************************************************************/ +VOID +BIOSInfoUpdateSmbiosType0 ( + VOID + ) +{ + INTN i; + INTN State = 0; + INTN Value[2]; + INTN Year = TIME_BUILD_YEAR; + INTN Month = TIME_BUILD_MONTH; + INTN Day = TIME_BUILD_DAY; + + mBIOSInfoType0.EmbeddedControllerFirmwareMajorRelease = 0; + mBIOSInfoType0.EmbeddedControllerFirmwareMinorRelease = 0; + + // mBiosVendor and mBiosVersion, which are referenced in mBIOSInfoType0Strings, + // are left unchanged if the following calls fail. + UnicodeStrToAsciiStrS ((CHAR16*)PcdGetPtr (PcdFirmwareVendor), + mBiosVendor, sizeof (mBiosVendor)); + UnicodeStrToAsciiStrS ((CHAR16*)PcdGetPtr (PcdFirmwareVersionString), + mBiosVersion, sizeof (mBiosVersion)); + ASSERT (Year >= 0 && Year <= 9999); + ASSERT (Month >= 1 && Month <= 12); + ASSERT (Day >= 1 && Day <= 31); + AsciiSPrint (mBiosDate, sizeof (mBiosDate), "%02d/%02d/%04d", Month, Day, Year); + + // Look for a "x.y" numeric string anywhere in mBiosVersion and + // try to parse it to populate the BIOS major and minor. + for (i = 0; (i < AsciiStrLen (mBiosVersion)) && (State < 4); i++) { + switch (State) { + case 0: + if (!SMB_IS_DIGIT (mBiosVersion[i])) + break; + Value[0] = Value[1] = 0; + State++; + // Fall through + case 1: + case 3: + if (SMB_IS_DIGIT (mBiosVersion[i])) { + Value[State / 2] = (Value[State / 2] * 10) + (mBiosVersion[i] - '0'); + if (Value[State / 2] > 255) { + while (SMB_IS_DIGIT (mBiosVersion[i + 1])) + i++; + // Reset our state (we may have something like "Firmware X83737.1 v1.23") + State = 0; + } + } else { + State++; + } + if (State != 2) + break; + // Fall through + case 2: + if ((mBiosVersion[i] == '.') && (SMB_IS_DIGIT (mBiosVersion[i + 1]))) { + State++; + } else { + State = 0; + } + break; + } + } + if ((State == 3) || (State == 4)) { + mBIOSInfoType0.SystemBiosMajorRelease = (UINT8)Value[0]; + mBIOSInfoType0.SystemBiosMinorRelease = (UINT8)Value[1]; + } + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mBIOSInfoType0, mBIOSInfoType0Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE1 System Information +************************************************************************/ +VOID +I64ToHexString ( + IN OUT CHAR8* TargetStringSz, + IN UINT32 TargetStringSize, + IN UINT64 Value + ) +{ + static CHAR8 ItoH[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + UINT8 StringInx; + INT8 NibbleInx; + + ZeroMem ((void*)TargetStringSz, TargetStringSize); + + // + // Convert each nibble to hex string, starting from + // the highest non-zero nibble. + // + StringInx = 0; + for (NibbleInx = sizeof (UINT64) * 2; NibbleInx > 0; --NibbleInx) { + UINT64 NibbleMask = (((UINT64)0xF) << ((NibbleInx - 1) * 4)); + UINT8 Nibble = (UINT8)((Value & NibbleMask) >> ((NibbleInx - 1) * 4)); + + ASSERT (Nibble <= 0xF); + + if (StringInx < (TargetStringSize - 1)) { + TargetStringSz[StringInx++] = ItoH[Nibble]; + } else { + break; + } + } +} + +VOID +SysInfoUpdateSmbiosType1 ( + VOID + ) +{ + UINT8 OtpData[16]; + UINT8 SerialLo[8]; + UINT8 SerialHi[8]; + UINT32 BoardRevision = 0; + UINT64 BoardSerial = 0; + UINTN Index; + + // Get serial number from OTP + OtpReadId (OtpData); + for (Index = 0; Index < 8; Index++) { + SerialLo[Index] = OtpData[Index * 2 + 1]; + SerialHi[Index] = OtpData[Index * 2]; + } + BoardSerial = CalculateCrc32NoComp (0, SerialLo, sizeof SerialLo); + BoardSerial |= (UINT64)CalculateCrc32NoComp (BoardSerial, SerialHi, sizeof SerialHi) << 32; + + AsciiStrCpyS (mSysInfoProductName, sizeof (mSysInfoProductName), (CHAR8 *) PcdGetPtr(PcdPlatformName)); + AsciiStrCpyS (mSysInfoFamilyName, sizeof (mSysInfoFamilyName), (CHAR8 *) PcdGetPtr(PcdFamilyName)); + AsciiStrCpyS (mSysInfoManufName, sizeof (mSysInfoManufName), (CHAR8 *) PcdGetPtr(PcdPlatformVendorName)); + AsciiSPrint (mSysInfoVersionName, sizeof (mSysInfoVersionName), "%X", BoardRevision); + + I64ToHexString (mSysInfoSKU, sizeof (mSysInfoSKU), BoardRevision); + I64ToHexString (mSysInfoSerial, sizeof (mSysInfoSerial), BoardSerial); + + DEBUG ((DEBUG_INFO, "Board Serial Number: %a\n", mSysInfoSerial)); + + mSysInfoType1.Uuid.Data1 = BoardRevision; + mSysInfoType1.Uuid.Data2 = 0x0; + mSysInfoType1.Uuid.Data3 = 0x0; + // Swap endianness, so that the serial is more user-friendly as a UUID + BoardSerial = SwapBytes64 (BoardSerial); + CopyMem (mSysInfoType1.Uuid.Data4, &BoardSerial, sizeof (BoardSerial)); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mSysInfoType1, mSysInfoType1Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE2 Board Information +************************************************************************/ +VOID +BoardInfoUpdateSmbiosType2 ( + VOID + ) +{ + CHAR8 *BoardName; + CHAR8 *BoardManuf; + CHAR8 *PlatformName; + CHAR8 *PlatformManuf; + + BoardName = (CHAR8 *) PcdGetPtr(PcdBoardName); + BoardManuf = (CHAR8 *) PcdGetPtr(PcdBoardVendorName); + PlatformName = (CHAR8 *) PcdGetPtr(PcdPlatformName); + PlatformManuf = (CHAR8 *) PcdGetPtr(PcdPlatformVendorName); + + AsciiStrCpyS (mBoardInfoProductName, sizeof (mBoardInfoProductName), + (AsciiStrCmp(BoardName, "Unknown") == 0) ? PlatformName : BoardName); + + AsciiStrCpyS (mBoardInfoManufName, sizeof (mBoardInfoManufName), + (AsciiStrCmp(BoardManuf, "Unknown") == 0) ? PlatformManuf : BoardManuf); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mBoardInfoType2, mBoardInfoType2Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE3 Enclosure Information +************************************************************************/ +VOID +EnclosureInfoUpdateSmbiosType3 ( + VOID + ) +{ + EFI_SMBIOS_HANDLE SmbiosHandle; + + // SMBIOS referenced strings cannot be NULL. If no AssetTag is set, default to a blank space. + UnicodeStrToAsciiStrS(L" ", mChassisAssetTag, sizeof(mChassisAssetTag)); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mEnclosureInfoType3, mEnclosureInfoType3Strings, &SmbiosHandle); + + // Set Type2 ChassisHandle to point to the newly added Type3 handle + mBoardInfoType2.ChassisHandle = (UINT16) SmbiosHandle; +} + + +STATIC UINT32 +ProcessorGetRate ( + VOID + ) +{ + EFI_STATUS Status; + SCMI_CLOCK_PROTOCOL *ClockProtocol; + EFI_GUID ClockProtocolGuid = ARM_SCMI_CLOCK_PROTOCOL_GUID; + UINT64 Rate; + UINT32 ClockId = 0; + + // If we can't query SCMI, fallback to reading from CRU registers + //Rate = CruGetCoreClockRate (); + + Rate = 1200; + + Status = gBS->LocateProtocol ( + &ClockProtocolGuid, + NULL, + (VOID**)&ClockProtocol + ); + if (EFI_ERROR (Status)) { + return (UINT32)Rate; + } + + ClockProtocol->RateGet (ClockProtocol, ClockId, &Rate); + + DEBUG ((DEBUG_INFO, "SCMI: SMBIOS reported rate %luHz\n", Rate)); + + return (UINT32)Rate; +} + +/*********************************************************************** + SMBIOS data update TYPE4 Processor Information +************************************************************************/ +VOID +ProcessorInfoUpdateSmbiosType4 ( + IN UINTN MaxCpus + ) +{ + UINT32 Rate; + UINT64 *ProcessorId; + + mProcessorInfoType4.CoreCount = (UINT8)MaxCpus; + mProcessorInfoType4.CoreCount2 = (UINT8)MaxCpus; + mProcessorInfoType4.EnabledCoreCount = (UINT8)MaxCpus; + mProcessorInfoType4.EnabledCoreCount2 = (UINT8)MaxCpus; + mProcessorInfoType4.ThreadCount = (UINT8)MaxCpus; + mProcessorInfoType4.ThreadCount2 = (UINT8)MaxCpus; + + Rate = ProcessorGetRate (); + mProcessorInfoType4.MaxSpeed = Rate / 1000000; + mProcessorInfoType4.CurrentSpeed = Rate / 1000000; + + AsciiStrCpyS (mCpuName, sizeof(mCpuName), (CHAR8 *) PcdGetPtr (PcdProcessorName)); + + ProcessorId = (UINT64 *)&(mProcessorInfoType4.ProcessorId); + *ProcessorId = ArmReadMidr(); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mProcessorInfoType4, mProcessorInfoType4Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE7 Cache Information +************************************************************************/ +VOID +CacheInfoUpdateSmbiosType7 ( + VOID + ) +{ + EFI_SMBIOS_HANDLE SmbiosHandle; + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mCacheInfoType7_L1I, mCacheInfoType7Strings_L1I, NULL); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mCacheInfoType7_L1D, mCacheInfoType7Strings_L1D, &SmbiosHandle); + // Set Type4 L1CacheHandle to point to the newly added L1 Data Cache + mProcessorInfoType4.L1CacheHandle = (UINT16) SmbiosHandle; + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mCacheInfoType7_L2, mCacheInfoType7Strings_L2, &SmbiosHandle); + // Set Type4 L2CacheHandle to point to the newly added L2 Cache + mProcessorInfoType4.L2CacheHandle = (UINT16) SmbiosHandle; +} + +/*********************************************************************** + SMBIOS data update TYPE9 System Slot Information +************************************************************************/ +VOID +SysSlotInfoUpdateSmbiosType9 ( + VOID + ) +{ + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mSysSlotInfoType9, mSysSlotInfoType9Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE11 OEM Strings +************************************************************************/ +VOID +OemStringsUpdateSmbiosType11 ( + VOID + ) +{ + AsciiStrCpyS (mOemInfoProductUrl, sizeof (mOemInfoProductUrl), (CHAR8 *) PcdGetPtr(PcdProductUrl)); + AsciiStrCpyS (mOemInfoDeviceTreeName, sizeof (mOemInfoDeviceTreeName), (CHAR8 *) PcdGetPtr(PcdDeviceTreeName)); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mOemStringsType11, mOemStringsType11Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE16 Physical Memory Array Information +************************************************************************/ +VOID +PhyMemArrayInfoUpdateSmbiosType16 ( + VOID + ) +{ + EFI_SMBIOS_HANDLE MemArraySmbiosHandle; + + // + // Update memory size fields: + // - Type 16 MaximumCapacity in KB + // - Type 17 size in MB (since bit 15 = 0) + // - Type 17 VolatileSize in Bytes + // + + mMemDevInfoType17.Size = mMemorySize / (1024 * 1024); + + mPhyMemArrayInfoType16.MaximumCapacity = mMemDevInfoType17.Size * 1024; // Size in KB + mMemDevInfoType17.VolatileSize = MultU64x32 (mMemDevInfoType17.Size, 1024 * 1024); // Size in Bytes + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mPhyMemArrayInfoType16, mPhyMemArrayInfoType16Strings, &MemArraySmbiosHandle); + + // + // Update the memory device information and memory array map with the newly added type 16 handle + // + mMemDevInfoType17.MemoryArrayHandle = MemArraySmbiosHandle; + mMemArrMapInfoType19.MemoryArrayHandle = MemArraySmbiosHandle; +} + +/*********************************************************************** + SMBIOS data update TYPE17 Memory Device Information +************************************************************************/ +VOID +MemDevInfoUpdateSmbiosType17 ( + VOID + ) +{ + AsciiStrCpyS (mMemDevInfoVendor, sizeof (mMemDevInfoVendor), (CHAR8 *) PcdGetPtr(PcdMemoryVendorName)); + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mMemDevInfoType17, mMemDevInfoType17Strings, NULL); +} + +/*********************************************************************** + SMBIOS data update TYPE19 Memory Array Map Information +************************************************************************/ +VOID +MemArrMapInfoUpdateSmbiosType19 ( + VOID + ) +{ + // Note: Type 19 addresses are expressed in KB, not bytes + mMemArrMapInfoType19.StartingAddress = PcdGet64(PcdSystemMemoryBase) / 1024; + + mMemArrMapInfoType19.EndingAddress = mMemArrMapInfoType19.StartingAddress + + mMemorySize / 1024 - 1; + + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mMemArrMapInfoType19, mMemArrMapInfoType19Strings, NULL); +} + + +/*********************************************************************** + SMBIOS data update TYPE32 Boot Information +************************************************************************/ +VOID +BootInfoUpdateSmbiosType32 ( + VOID + ) +{ + LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER*)&mBootInfoType32, mBootInfoType32Strings, NULL); +} + +/*********************************************************************** + Driver Entry +************************************************************************/ +EFI_STATUS +EFIAPI +PlatformSmbiosDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + DEBUG ((DEBUG_INFO, "PlatformSmbiosDriverEntryPoint() called\n")); + + mMemorySize = SdramGetMemorySize (); + + BIOSInfoUpdateSmbiosType0 (); + + SysInfoUpdateSmbiosType1 (); + + EnclosureInfoUpdateSmbiosType3 (); // Add Type 3 first to get chassis handle for use in Type 2 + + BoardInfoUpdateSmbiosType2 (); + + CacheInfoUpdateSmbiosType7 (); // Add Type 7 first to get Cache handle for use in Type 4 + + ProcessorInfoUpdateSmbiosType4 (4); //One example for creating and updating + + SysSlotInfoUpdateSmbiosType9 (); + + OemStringsUpdateSmbiosType11 (); + + PhyMemArrayInfoUpdateSmbiosType16 (); + + MemDevInfoUpdateSmbiosType17 (); + + MemArrMapInfoUpdateSmbiosType19 (); + + BootInfoUpdateSmbiosType32 (); + + DEBUG ((DEBUG_INFO, "PlatformSmbiosDriverEntryPoint() returning\n")); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf new file mode 100644 index 0000000..81b40e0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf @@ -0,0 +1,73 @@ + +#/** @file +# +# SMBIOS Table for RK35xx platforms +# +# Copyright (c) 2021 Jared McNeill +# Copyright (c) 2017-2021 Andrei Warkentin +# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) 2013 Linaro.org +# Copyright (c) 2020, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = PlatformSmbiosDxe + FILE_GUID = 196E5BEB-983E-4B58-8292-BC310F6962DF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PlatformSmbiosDriverEntryPoint + +[Sources] + PlatformSmbiosDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + BaseLib + UefiLib + UefiDriverEntryPoint + DebugLib + PrintLib + TimeBaseLib + CruLib + SdramLib + OtpLib + +[Protocols] + gEfiSmbiosProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + +[Guids] + +[Depex] + gEfiSmbiosProtocolGuid + +[Pcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + gRockchipTokenSpaceGuid.PcdProcessorName + gRockchipTokenSpaceGuid.PcdPlatformName + gRockchipTokenSpaceGuid.PcdPlatformVendorName + gRockchipTokenSpaceGuid.PcdBoardName + gRockchipTokenSpaceGuid.PcdBoardVendorName + gRockchipTokenSpaceGuid.PcdProductUrl + gRockchipTokenSpaceGuid.PcdDeviceTreeName + gRockchipTokenSpaceGuid.PcdFamilyName + gRockchipTokenSpaceGuid.PcdMemoryVendorName + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.c new file mode 100644 index 0000000..ff5f768 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.c @@ -0,0 +1,1458 @@ +/** @file + * + * Firmware Volume Block driver for non-volatile data storage on + * SPI NOR (persistent at runtime) or SD/eMMC (persistent only at boot time). + * + * Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + * Copyright (c) 2017 Marvell International Ltd. + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RkFvbDxe.h" + +RKATAG_BOOTDEV_TYPE mBootDeviceType; +VOID *mDiskIoRegistration; +STATIC EFI_EVENT mFvbVirtualAddrChangeEvent; +STATIC FVB_DEVICE *mFvbDevice; +STATIC CONST FVB_DEVICE mRkFvbFlashInstanceTemplate = { + NULL, // SpiFlashProtocol ... NEED TO BE FILLED + FALSE, // IsSpiFlashAvailable ... NEED TO BE FILLED + FALSE, // IsFvbHeaderValid ... NEED TO BE FILLED + + NULL, // DiskDevice ... NEED TO BE FILLED + 0, // DiskMediaId ... NEED TO BE FILLED + FALSE, // DiskDataInvalidated ... NEED TO BE FILLED + + NULL, // Handle ... NEED TO BE FILLED + + FVB_FLASH_SIGNATURE, // Signature + + 0, // DeviceBaseAddress ... NEED TO BE FILLED + 0, // RegionBaseAddress ... NEED TO BE FILLED + SIZE_256KB, // Size + 0, // FvbOffset ... NEED TO BE FILLED + 0, // FvbSize ... NEED TO BE FILLED + 0, // StartLba + + { + 0, // MediaId ... NEED TO BE FILLED + FALSE, // RemovableMedia + TRUE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching; + 0, // BlockSize ... NEED TO BE FILLED + 4, // IoAlign + 0, // LastBlock ... NEED TO BE FILLED + 0, // LowestAlignedLba + 1, // LogicalBlocksPerPhysicalBlock + }, //Media; + + { + FvbGetAttributes, // GetAttributes + FvbSetAttributes, // SetAttributes + FvbGetPhysicalAddress, // GetPhysicalAddress + FvbGetBlockSize, // GetBlockSize + FvbRead, // Read + FvbWrite, // Write + FvbEraseBlocks, // EraseBlocks + NULL, // ParentHandle + }, // FvbProtocol; + + { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)sizeof (VENDOR_DEVICE_PATH), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + } // DevicePath +}; + +// +// The Firmware Volume Block Protocol is the low-level interface +// to a firmware volume. File-level access to a firmware volume +// should not be done using the Firmware Volume Block Protocol. +// Normal access to a firmware volume must use the Firmware +// Volume Protocol. Typically, only the file system driver that +// produces the Firmware Volume Protocol will bind to the +// Firmware Volume Block Protocol. +// + +/** + Initialises the FV Header and Variable Store Header + to support variable operations. + + @param[in] Ptr - Location to initialise the headers + +**/ +STATIC +EFI_STATUS +FvbInitFvAndVariableStoreHeaders ( + IN FVB_DEVICE *FlashInstance + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_STATUS Status; + VOID* Headers; + UINTN HeadersLength; + UINTN BlockSize; + + HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + + sizeof (VARIABLE_STORE_HEADER); + Headers = AllocateZeroPool (HeadersLength); + + BlockSize = FlashInstance->Media.BlockSize; + + // + // FirmwareVolumeHeader->FvLength is declared to have the Variable area + // AND the FTW working area AND the FTW Spare contiguous. + // + ASSERT (PcdGet64 (PcdFlashNvStorageVariableBase64) + + PcdGet32 (PcdFlashNvStorageVariableSize) == + PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)); + ASSERT (PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) == + PcdGet64 (PcdFlashNvStorageFtwSpareBase64)); + + // Check if the size of the area is at least one block size + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && + (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)); + + // Ensure the Variable areas are aligned on block size boundaries + //ASSERT ((PcdGet64 (PcdFlashNvStorageVariableBase64) % BlockSize) == 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % BlockSize) == 0); + ASSERT ((PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % BlockSize) == 0); + + // + // EFI_FIRMWARE_VOLUME_HEADER + // + FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers; + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid); + FirmwareVolumeHeader->FvLength = FlashInstance->FvbSize; + FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE; + FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP | + EFI_FVB2_READ_STATUS | + EFI_FVB2_STICKY_WRITE | + EFI_FVB2_ERASE_POLARITY | + EFI_FVB2_WRITE_STATUS | + EFI_FVB2_WRITE_ENABLED_CAP | + EFI_FVB2_MEMORY_MAPPED; + + FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + + sizeof (EFI_FV_BLOCK_MAP_ENTRY); + FirmwareVolumeHeader->Revision = EFI_FVH_REVISION; + FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->Media.LastBlock + 1; + FirmwareVolumeHeader->BlockMap[0].Length = FlashInstance->Media.BlockSize; + FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0; + FirmwareVolumeHeader->BlockMap[1].Length = 0; + FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ( + (UINT16 *)FirmwareVolumeHeader, + FirmwareVolumeHeader->HeaderLength); + + // + // VARIABLE_STORE_HEADER + // + VariableStoreHeader = (VOID *)((UINTN)Headers + + FirmwareVolumeHeader->HeaderLength); + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid); + VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - + FirmwareVolumeHeader->HeaderLength; + VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED; + VariableStoreHeader->State = VARIABLE_STORE_HEALTHY; + + // Install the combined super-header in the flash device + Status = FvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers); + + FreePool (Headers); + + return Status; +} + +/** + Check the integrity of firmware volume header. + + @param[in] FwVolHeader - A pointer to a firmware volume header + + @retval EFI_SUCCESS - The firmware volume is consistent + @retval EFI_NOT_FOUND - The firmware volume has been corrupted. + +**/ +STATIC +EFI_STATUS +FvbValidateFvHeader ( + IN FVB_DEVICE *FlashInstance + ) +{ + UINT16 Checksum; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN VariableStoreLength; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress; + + // Verify the header revision, header signature, length + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength != FlashInstance->FvbSize)) { + DEBUG ((DEBUG_ERROR, + "%a: No Firmware Volume header present\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + // Check the Firmware Volume Guid + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) { + DEBUG ((DEBUG_ERROR, + "%a: Firmware Volume Guid non-compatible\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + // Verify the header checksum + Checksum = CalculateSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength); + if (Checksum != 0) { + DEBUG ((DEBUG_ERROR, + "%a: FV checksum is invalid (Checksum:0x%x)\n", + __FUNCTION__, + Checksum)); + return EFI_NOT_FOUND; + } + + VariableStoreHeader = (VOID *)((UINTN)FwVolHeader + FwVolHeader->HeaderLength); + + // Check the Variable Store Guid + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) && + !CompareGuid (&VariableStoreHeader->Signature, + &gEfiAuthenticatedVariableGuid)) { + DEBUG ((DEBUG_ERROR, + "%a: Variable Store Guid non-compatible\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - + FwVolHeader->HeaderLength; + if (VariableStoreHeader->Size != VariableStoreLength) { + DEBUG ((DEBUG_ERROR, + "%a: Variable Store Length does not match\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + The GetAttributes() function retrieves the attributes and + current settings of the block. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and + current settings are returned. + Type EFI_FVB_ATTRIBUTES_2 is defined in + EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were returned. + + **/ +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FVB_ATTRIBUTES_2 *FlashFvbAttributes; + FVB_DEVICE *FlashInstance; + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress; + FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FwVolHeader->Attributes); + + *Attributes = *FlashFvbAttributes; + + return EFI_SUCCESS; +} + +/** + The SetAttributes() function sets configurable firmware volume attributes + and returns the new settings of the firmware volume. + + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes On input, Attributes is a pointer to + EFI_FVB_ATTRIBUTES_2 that contains the desired + firmware volume settings. + On successful return, it contains the new + settings of the firmware volume. + + @retval EFI_SUCCESS The firmware volume attributes were returned. + + @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with + the capabilities as declared in the firmware + volume header. + + **/ +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FVB_ATTRIBUTES_2 OldAttributes; + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; + FVB_DEVICE *FlashInstance; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + // + // Obtain attributes from FVB header + // + FvbGetAttributes (This, &FlashFvbAttributes); + + OldAttributes = FlashFvbAttributes; + Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus = OldAttributes & EFI_FVB2_STATUS; + NewStatus = *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP | \ + EFI_FVB2_STICKY_WRITE | \ + EFI_FVB2_ERASE_POLARITY | \ + EFI_FVB2_READ_LOCK_CAP | \ + EFI_FVB2_WRITE_LOCK_CAP | \ + EFI_FVB2_ALIGNMENT | \ + EFI_FVB2_MEMORY_MAPPED; + + // + // Some attributes of FV is read only can *not* be set + // + if ((OldAttributes & UnchangedAttributes) ^ + (*Attributes & UnchangedAttributes)) { + return EFI_INVALID_PARAMETER; + } + // + // If firmware volume is locked, no status bit can be updated + // + if (OldAttributes & EFI_FVB2_LOCK_STATUS) { + if (OldStatus ^ NewStatus) { + return EFI_ACCESS_DENIED; + } + } + // + // Test read disable + // + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test read enable + // + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write disable + // + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test write enable + // + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + // + // Test lock + // + if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { + if (NewStatus & EFI_FVB2_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); + FlashFvbAttributes = FlashFvbAttributes | NewStatus; + *Attributes = FlashFvbAttributes; + + return EFI_SUCCESS; +} + +/** + The GetPhysicalAddress() function retrieves the base address of + a memory-mapped firmware volume. This function should be called + only for memory-mapped firmware volumes. + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Address Pointer to a caller-allocated + EFI_PHYSICAL_ADDRESS that, on successful + return from GetPhysicalAddress(), contains the + base address of the firmware volume. + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped. + + **/ +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + FVB_DEVICE *FlashInstance; + + ASSERT (Address != NULL); + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + *Address = FlashInstance->RegionBaseAddress; + + return EFI_SUCCESS; +} + +/** + The GetBlockSize() function retrieves the size of the requested + block. It also returns the number of additional blocks with + the identical size. The GetBlockSize() function is used to + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER). + + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba Indicates the block whose size to return + + @param BlockSize Pointer to a caller-allocated UINTN in which + the size of the block is returned. + + @param NumberOfBlocks Pointer to a caller-allocated UINTN in + which the number of consecutive blocks, + starting with Lba, is returned. All + blocks in this range have a size of + BlockSize. + + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. + + **/ +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +{ + FVB_DEVICE *FlashInstance; + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + if (Lba > FlashInstance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, + "%a: Error: Requested LBA %ld is beyond the last available LBA (%ld).\n", + __FUNCTION__, + Lba, + FlashInstance->Media.LastBlock)); + return EFI_INVALID_PARAMETER; + } else { + // Assume equal sized blocks in all flash devices + *BlockSize = (UINTN)FlashInstance->Media.BlockSize; + *NumberOfBlocks = (UINTN)(FlashInstance->Media.LastBlock - Lba + 1); + + return EFI_SUCCESS; + } +} + +/** + Reads the specified number of bytes into a buffer from the specified block. + + The Read() function reads the requested number of bytes from the + requested block and stores them in the provided buffer. + Implementations should be mindful that the firmware volume + might be in the ReadDisabled state. If it is in this state, + the Read() function must return the status code + EFI_ACCESS_DENIED without modifying the contents of the + buffer. The Read() function must also prevent spanning block + boundaries. If a read is requested that would span a block + boundary, the read must read up to the boundary but not + beyond. The output parameter NumBytes must be set to correctly + indicate the number of bytes actually read. The caller must be + aware that a read may be partially completed. + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index from which to read + + @param Offset Offset into the block at which to begin reading. + + @param NumBytes Pointer to a UINTN. + At entry, *NumBytes contains the total size of the + buffer. + At exit, *NumBytes contains the total number of + bytes read. + + @param Buffer Pointer to a caller-allocated buffer that will be + used to hold the data that is read. + + @retval EFI_SUCCESS The firmware volume was read successfully, and + contents are in Buffer. + + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. + On output, NumBytes contains the total number of + bytes returned in Buffer. + + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. + + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and + could not be read. + + **/ +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ) +{ + FVB_DEVICE *FlashInstance; + UINTN BlockSize; + UINTN DataOffset; + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = FlashInstance->Media.BlockSize; + + // + // The read must not span block boundaries. + // We need to check each variable individually because adding two large + // values together overflows. + // + if (Offset >= BlockSize || + *NumBytes > BlockSize || + (Offset + *NumBytes) > BlockSize) { + DEBUG ((DEBUG_ERROR, + "%a: Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", + __FUNCTION__, + Offset, + *NumBytes, + BlockSize)); + return EFI_BAD_BUFFER_SIZE; + } + + // No bytes to read + if (*NumBytes == 0) { + return EFI_SUCCESS; + } + + DataOffset = GET_DATA_OFFSET (FlashInstance->RegionBaseAddress + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->Media.BlockSize); + + // Read the memory-mapped data + CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes); + + return EFI_SUCCESS; +} + +/** + Writes the specified number of bytes from the input buffer to the block. + + The Write() function writes the specified number of bytes from + the provided buffer to the specified block and offset. If the + firmware volume is sticky write, the caller must ensure that + all the bits of the specified range to write are in the + EFI_FVB_ERASE_POLARITY state before calling the Write() + function, or else the result will be unpredictable. This + unpredictability arises because, for a sticky-write firmware + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY + state but cannot flip it back again. Before calling the + Write() function, it is recommended for the caller to first call + the EraseBlocks() function to erase the specified block to + write. A block erase cycle will transition bits from the + (NOT)EFI_FVB_ERASE_POLARITY state back to the + EFI_FVB_ERASE_POLARITY state. Implementations should be + mindful that the firmware volume might be in the WriteDisabled + state. If it is in this state, the Write() function must + return the status code EFI_ACCESS_DENIED without modifying the + contents of the firmware volume. The Write() function must + also prevent spanning block boundaries. If a write is + requested that spans a block boundary, the write must store up + to the boundary but not beyond. The output parameter NumBytes + must be set to correctly indicate the number of bytes actually + written. The caller must be aware that a write may be + partially completed. All writes, partial or otherwise, must be + fully flushed to the hardware before the Write() service + returns. + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index to write to. + + @param Offset Offset into the block at which to begin writing. + + @param NumBytes The pointer to a UINTN. + At entry, *NumBytes contains the total size of the + buffer. + At exit, *NumBytes contains the total number of + bytes actually written. + + @param Buffer The pointer to a caller-allocated buffer that + contains the source for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully. + + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary. + On output, NumBytes contains the total number of + bytes actually written. + + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. + + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be + written. + + + **/ +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + FVB_DEVICE *FlashInstance; + UINTN DataOffset; + + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + DataOffset = GET_DATA_OFFSET (FlashInstance->FvbOffset + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->Media.BlockSize); + + if (FlashInstance->IsSpiFlashAvailable) { + Status = FlashInstance->SpiFlashProtocol->Write (FlashInstance->SpiFlashProtocol, + DataOffset, + Buffer, + *NumBytes); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to write to Spi device\n", __FUNCTION__)); + return Status; + } + } + + // Update shadow buffer + DataOffset = GET_DATA_OFFSET (FlashInstance->RegionBaseAddress + Offset, + FlashInstance->StartLba + Lba, + FlashInstance->Media.BlockSize); + + CopyMem ((UINTN *)DataOffset, Buffer, *NumBytes); + + // Must sync the data if it's on a disk + FlashInstance->DiskDataInvalidated = TRUE; + + return EFI_SUCCESS; +} + +/** + Erases and initialises a firmware volume block. + + The EraseBlocks() function erases one or more blocks as denoted + by the variable argument list. The entire parameter list of + blocks must be verified before erasing any blocks. If a block is + requested that does not exist within the associated firmware + volume (it has a larger index than the last block of the + firmware volume), the EraseBlocks() function must return the + status code EFI_INVALID_PARAMETER without modifying the contents + of the firmware volume. Implementations should be mindful that + the firmware volume might be in the WriteDisabled state. If it + is in this state, the EraseBlocks() function must return the + status code EFI_ACCESS_DENIED without modifying the contents of + the firmware volume. All calls to EraseBlocks() must be fully + flushed to the hardware before the EraseBlocks() service + returns. + + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL + instance. + + @param ... The variable argument list is a list of tuples. + Each tuple describes a range of LBAs to erase + and consists of the following: + - An EFI_LBA that indicates the starting LBA + - A UINTN that indicates the number of blocks + to erase. + + The list is terminated with an + EFI_LBA_LIST_TERMINATOR. + + @retval EFI_SUCCESS The erase request successfully completed. + + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled + state. + + @retval EFI_DEVICE_ERROR The block device is not functioning correctly + and could not be written. + The firmware device may have been partially + erased. + + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable + argument list do not exist in the firmware + volume. + + **/ +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ) +{ + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; + FVB_DEVICE *FlashInstance; + EFI_STATUS Status; + VA_LIST Args; + UINTN BlockAddress; // Physical address of Lba to erase + EFI_LBA StartingLba; // Lba from which we start erasing + UINTN NumOfLba; // Number of Lba blocks to erase + + FlashInstance = INSTANCE_FROM_FVB_THIS (This); + + Status = EFI_SUCCESS; + + if(FlashInstance->IsFvbHeaderValid == TRUE) { + // Detect WriteDisabled state + FvbGetAttributes (This, &FlashFvbAttributes); + if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) { + DEBUG ((DEBUG_ERROR, + "%a: Device is in WriteDisabled state.\n", + __FUNCTION__)); + return EFI_ACCESS_DENIED; + } + } + + // + // Before erasing, check the entire list of parameters to ensure + // all specified blocks are valid. + // + VA_START (Args, This); + do { + // Get the Lba from which we start erasing + StartingLba = VA_ARG (Args, EFI_LBA); + + // Have we reached the end of the list? + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + //Exit the while loop + break; + } + + // How many Lba blocks are we requested to erase? + NumOfLba = VA_ARG (Args, UINT32); + + // All blocks must be within range + if (NumOfLba == 0 || + (FlashInstance->StartLba + StartingLba + NumOfLba - 1) > + FlashInstance->Media.LastBlock) { + + DEBUG ((DEBUG_ERROR, + "%a: Error: Requested LBA are beyond the last available LBA (%ld).\n", + __FUNCTION__, + FlashInstance->Media.LastBlock)); + + VA_END (Args); + + return EFI_INVALID_PARAMETER; + } + } while (TRUE); + VA_END (Args); + + // + // Start erasing + // + VA_START (Args, This); + do { + // Get the Lba from which we start erasing + StartingLba = VA_ARG (Args, EFI_LBA); + + // Have we reached the end of the list? + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + // Exit the while loop + break; + } + + // How many Lba blocks are we requested to erase? + NumOfLba = VA_ARG (Args, UINT32); + + // Go through each one and erase it + while (NumOfLba > 0) { + + // Get the physical address of Lba to erase + BlockAddress = GET_DATA_OFFSET (FlashInstance->FvbOffset, + FlashInstance->StartLba + StartingLba, + FlashInstance->Media.BlockSize); + // Erase single block + if (FlashInstance->IsSpiFlashAvailable) { + Status = FlashInstance->SpiFlashProtocol->Erase (FlashInstance->SpiFlashProtocol, + BlockAddress, + FlashInstance->Media.BlockSize); + if (EFI_ERROR (Status)) { + VA_END (Args); + return EFI_DEVICE_ERROR; + } + } + + // Update shadow buffer + BlockAddress = GET_DATA_OFFSET (FlashInstance->RegionBaseAddress, + FlashInstance->StartLba + StartingLba, + FlashInstance->Media.BlockSize); + + SetMem ((UINTN *)BlockAddress, FlashInstance->Media.BlockSize, 0xFF); + + // Must sync the data if it's on a disk + FlashInstance->DiskDataInvalidated = TRUE; + + // Move to the next Lba + StartingLba++; + NumOfLba--; + } + } while (TRUE); + VA_END (Args); + + return EFI_SUCCESS; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +STATIC +VOID +EFIAPI +FvbVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // Convert SPI memory mapped region + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->RegionBaseAddress); + + // Convert SPI device description + //EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.Info); + //EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.HostRegisterBaseAddress); + //EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice); + + // Convert SpiFlashProtocol + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Erase); + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Write); + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Read); + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->GetSize); + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol); + + return; +} + +STATIC +EFI_STATUS +FvbPrepareFvHeader ( + IN FVB_DEVICE *FlashInstance + ) +{ + EFI_BOOT_MODE BootMode; + EFI_STATUS Status; + + // Check if it is required to use default environment + BootMode = GetBootModeHob (); + if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { + Status = EFI_INVALID_PARAMETER; + } else { + // Validate header at the beginning of FV region + Status = FvbValidateFvHeader (FlashInstance); + } + + // Install the default FVB header if required + if (EFI_ERROR (Status)) { + // There is no valid header, so time to install one. + DEBUG ((DEBUG_ERROR, "%a: The FVB Header is not valid.\n", __FUNCTION__)); + DEBUG ((DEBUG_ERROR, + "%a: Installing a correct one for this volume.\n", + __FUNCTION__)); + + FlashInstance->IsFvbHeaderValid = FALSE; + + // Erase entire region that is reserved for variable storage + Status = FvbEraseBlocks (&FlashInstance->FvbProtocol, + (EFI_LBA) 0, + FlashInstance->FvbSize / FlashInstance->Media.BlockSize, + EFI_LBA_LIST_TERMINATOR); + if (EFI_ERROR (Status)) { + return Status; + } + + // Install all appropriate headers + Status = FvbInitFvAndVariableStoreHeaders (FlashInstance); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + FlashInstance->IsFvbHeaderValid = TRUE; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +FvbConfigureFlashInstance ( + IN OUT FVB_DEVICE *FlashInstance + ) +{ + EFI_STATUS Status; + UINTN DataOffset; + UINTN VariableSize, FtwWorkingSize, FtwSpareSize, MemorySize; + + // Locate SPI protocols + Status = gBS->LocateProtocol (&gUniNorFlashProtocolGuid, + NULL, + (VOID **)&FlashInstance->SpiFlashProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: Cannot locate SpiFlash protocol\n", __FUNCTION__)); + } else { + // Probe the SPI flash + if (FlashInstance->SpiFlashProtocol->GetSize(FlashInstance->SpiFlashProtocol)) { + FlashInstance->IsSpiFlashAvailable = TRUE; + } else { + DEBUG ((DEBUG_WARN, "%a: SPI flash not present.\n", __FUNCTION__)); + } + } + + // Fill remaining flash description + VariableSize = PcdGet32 (PcdFlashNvStorageVariableSize); + FtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + FtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + FlashInstance->FvbSize = VariableSize + FtwWorkingSize + FtwSpareSize; + FlashInstance->FvbOffset = PcdGet64 (PcdFlashNvStorageVariableBase64); + + FlashInstance->Media.MediaId = 0; + FlashInstance->Media.BlockSize = SIZE_4KB;//FlashInstance->SpiDevice.Info->SectorSize; + FlashInstance->Media.LastBlock = FlashInstance->Size / + FlashInstance->Media.BlockSize - 1; + + // U-Boot maps NV data into memory at the same address as in flash. + FlashInstance->RegionBaseAddress = FlashInstance->FvbOffset; + + if (FlashInstance->IsSpiFlashAvailable + && mBootDeviceType != RkAtagBootDevTypeSpiNor + && mBootDeviceType != RkAtagBootDevTypeMtdBlkSpiNor) { + // + // SPI flash is available but UEFI was booted from another storage, + // check if user still prefers the NV data to be on the flash. + // + if (FixedPcdGetBool (PcdNvStoragePreferSpiFlash)) { + // + // Ignore the memory mapped NV data from the boot device and + // read it directly from SPI flash. + // + DataOffset = GET_DATA_OFFSET (FlashInstance->FvbOffset, + FlashInstance->StartLba, + FlashInstance->Media.BlockSize); + Status = FlashInstance->SpiFlashProtocol->Read (FlashInstance->SpiFlashProtocol, + DataOffset, + (VOID *)FlashInstance->RegionBaseAddress, + FlashInstance->FvbSize); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // Mark SPI flash as being unavailable, we'll dump the NV data on + // the boot device if possible. + // + FlashInstance->IsSpiFlashAvailable = FALSE; + } + } + + Status = gBS->InstallMultipleProtocolInterfaces (&FlashInstance->Handle, + &gEfiDevicePathProtocolGuid, &FlashInstance->DevicePath, + &gEfiFirmwareVolumeBlockProtocolGuid, &FlashInstance->FvbProtocol, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvbPrepareFvHeader (FlashInstance); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces (&FlashInstance->Handle, + &gEfiDevicePathProtocolGuid, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL); + } + + return Status; +} + +STATIC +EFI_STATUS +FvbDiskDumpNvData ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN UINT32 MediaId + ) +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo = NULL; + EFI_HANDLE Handle; + UINTN DataOffset; + + Status = gBS->LocateDevicePath (&gEfiDiskIoProtocolGuid, &Device, &Handle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol (Handle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo); + if (EFI_ERROR (Status)) { + return Status; + } + + DataOffset = GET_DATA_OFFSET (mFvbDevice->FvbOffset, + mFvbDevice->StartLba, + mFvbDevice->Media.BlockSize); + + Status = DiskIo->WriteDisk (DiskIo, + MediaId, + DataOffset, + mFvbDevice->FvbSize, + (VOID *) mFvbDevice->FvbOffset); + + return Status; +} + +STATIC +VOID +EFIAPI +FvbDiskNvDumpEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + if (mFvbDevice->DiskDevice == NULL) { + DEBUG ((DEBUG_WARN, "%a: NV disk device not found (yet?)\n", __FUNCTION__)); + return; + } + + if (!mFvbDevice->DiskDataInvalidated) { + return; + } + + Status = FvbDiskDumpNvData (mFvbDevice->DiskDevice, mFvbDevice->DiskMediaId); + if (EFI_ERROR (Status)) { + CHAR16* DevicePathText = ConvertDevicePathToText (mFvbDevice->DiskDevice, FALSE, FALSE); + DEBUG ((DEBUG_ERROR, "%a: Couldn't dump NV data to disk [%s]\n", + __FUNCTION__, DevicePathText)); + if (DevicePathText != NULL) { + gBS->FreePool (DevicePathText); + } + + ASSERT_EFI_ERROR (Status); + return; + } + + DEBUG ((DEBUG_INFO, "NV data dumped!\n")); + + mFvbDevice->DiskDataInvalidated = FALSE; +} + +STATIC +VOID +FvbReadyToBootEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_EVENT ImageInstallEvent; + VOID *ImageRegistration; + + Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FvbDiskNvDumpEventHandler, + NULL, + &ImageInstallEvent); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify (&gEfiLoadedImageProtocolGuid, + ImageInstallEvent, + &ImageRegistration); + ASSERT_EFI_ERROR (Status); + + FvbDiskNvDumpEventHandler (NULL, NULL); + + Status = gBS->CloseEvent (Event); + ASSERT_EFI_ERROR (Status); +} + +STATIC +BOOLEAN +FvbCheckIsBootDevice ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DeviceHandle; + NON_DISCOVERABLE_DEVICE *Device; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + + DevicePath = DevicePathFromHandle (Handle); + + DEBUG ((DEBUG_INFO, "%a: DevPath type 0x%x subtype 0x%x\n", + __FUNCTION__, DevicePath->Type, DevicePath->SubType)); + + if (DevicePath->Type != HARDWARE_DEVICE_PATH + || DevicePath->SubType != HW_VENDOR_DP) { + return FALSE; + } + + Status = gBS->LocateDevicePath (&gEdkiiNonDiscoverableDeviceProtocolGuid, + &DevicePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = gBS->HandleProtocol (DeviceHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **) &Device); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Descriptor = &Device->Resources[0]; + + if (Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR || + Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { + return FALSE; + } + + if (mBootDeviceType == RkAtagBootDevTypeEmmc) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdDwcSdhciBaseAddress); + } + if (mBootDeviceType == RkAtagBootDevTypeSd0) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdRkSdmmcBaseAddress); + } + + return FALSE; +} + +STATIC +VOID +EFIAPI +FvbDiskIoRegistrationHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN HandleSize; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *Device; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + CHAR16 *DevicePathText = NULL; + + if (mFvbDevice->DiskDevice != NULL) { + // + // We've already found the NV disk before, + // and it is not removed from the system (hopefully). + // + return; + } + + while (TRUE) { + HandleSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle (ByRegisterNotify, + NULL, + mDiskIoRegistration, + &HandleSize, + &Handle); + if (Status == EFI_NOT_FOUND) { + break; + } + + ASSERT_EFI_ERROR (Status); + + if (!FvbCheckIsBootDevice (Handle)) { + continue; + } + + Device = NULL; + Status = gBS->HandleProtocol (Handle, + &gEfiBlockIoProtocolGuid, + (VOID*)&BlkIo); + if (EFI_ERROR (Status)) { + continue; + } + Device = DuplicateDevicePath (DevicePathFromHandle (Handle)); + ASSERT (Device != NULL); + + if (DevicePathText != NULL) { + gBS->FreePool (DevicePathText); + } + DevicePathText = ConvertDevicePathToText (Device, FALSE, FALSE); + + if (!BlkIo->Media->MediaPresent) { + DEBUG ((DEBUG_ERROR, "%a: [%s] Media not present!\n", + __FUNCTION__, DevicePathText)); + continue; + } + if (BlkIo->Media->ReadOnly) { + DEBUG ((DEBUG_ERROR, "%a: [%s] Media is read-only!\n", + __FUNCTION__, DevicePathText)); + continue; + } + + Status = FvbDiskDumpNvData (Device, BlkIo->Media->MediaId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: [%s] Couldn't update NV data!\n", + __FUNCTION__, DevicePathText)); + ASSERT_EFI_ERROR (Status); + continue; + } + + if (mFvbDevice->DiskDevice != NULL) { + gBS->FreePool (mFvbDevice->DiskDevice); + } + + DEBUG ((DEBUG_INFO, "%a: [%s] Found boot disk for NV storage!\n", + __FUNCTION__, DevicePathText)); + + mFvbDevice->DiskDevice = Device; + mFvbDevice->DiskMediaId = BlkIo->Media->MediaId; + break; + } + + if (DevicePathText != NULL) { + gBS->FreePool (DevicePathText); + } +} + +STATIC +VOID +FvbInstallDiskNvDumpEventHandlers ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT ResetEvent; + EFI_EVENT ReadyToBootEvent; + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FvbDiskNvDumpEventHandler, + NULL, + &gRockchipEventResetGuid, + &ResetEvent); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FvbReadyToBootEventHandler, + NULL, + &gEfiEventReadyToBootGuid, + &ReadyToBootEvent); + ASSERT_EFI_ERROR (Status); +} + +STATIC +VOID +FvbInstallDiskNotifyHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FvbDiskIoRegistrationHandler, + NULL, + &Event); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify (&gEfiDiskIoProtocolGuid, + Event, + &mDiskIoRegistration); + ASSERT_EFI_ERROR (Status); +} + +EFI_STATUS +EFIAPI +RkFvbEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status = 0; + RKATAG_BOOTDEV *BootDevice; + + BootDevice = RkAtagsGetBootDev (); + if (BootDevice != NULL) { + mBootDeviceType = BootDevice->DevType; + DEBUG ((DEBUG_INFO, "%a: BootDevice->DevType = 0x%x\n", __FUNCTION__, mBootDeviceType)); + } else { + DEBUG ((DEBUG_ERROR, "%a: Couldn't identify boot device.\n", __FUNCTION__)); + mBootDeviceType = RkAtagBootDevTypeUnknown; + } + + // + // Create FVB flash device + // + mFvbDevice = AllocateRuntimeCopyPool (sizeof (mRkFvbFlashInstanceTemplate), + &mRkFvbFlashInstanceTemplate); + if (mFvbDevice == NULL) { + DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + + // + // Detect and configure flash device + // + Status = FvbConfigureFlashInstance (mFvbDevice); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to configure Fvb device\n", __FUNCTION__)); + goto ErrorConfigureFlash; + } + + // + // The driver implementing the variable read service can now be dispatched; + // the varstore headers are in place. + // + Status = gBS->InstallProtocolInterface (&gImageHandle, + &gEdkiiNvVarStoreFormattedGuid, + EFI_NATIVE_INTERFACE, + NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n", + __FUNCTION__)); + goto ErrorInstallNvVarStoreFormatted; + } + + // + // Register for the virtual address change event + // + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FvbVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mFvbVirtualAddrChangeEvent); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__)); + goto ErrorSetMemAttr; + } + + // + // If SPI flash isn't available (or preferred), attempt to identify + // and set up persistent NV storage on the boot device. + // + if (!mFvbDevice->IsSpiFlashAvailable) { + FvbInstallDiskNotifyHandler (); + FvbInstallDiskNvDumpEventHandlers (); + } + + return Status; +ErrorSetMemAttr: + gBS->UninstallProtocolInterface (gImageHandle, + &gEdkiiNvVarStoreFormattedGuid, + NULL); + +ErrorInstallNvVarStoreFormatted: + gBS->UninstallMultipleProtocolInterfaces (&mFvbDevice->Handle, + &gEfiDevicePathProtocolGuid, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL); + +ErrorConfigureFlash: + FreePool (mFvbDevice); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.h new file mode 100644 index 0000000..920053f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.h @@ -0,0 +1,126 @@ +/** @file + * + * Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + * Copyright (c) 2017 Marvell International Ltd. + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __FVB_FLASH_DXE_H__ +#define __FVB_FLASH_DXE_H__ + +#include +#include +#include + +#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lba) * (LbaSize))) + +#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r') +#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE) + +// +// Define two helper macro to extract the Capability field or Status field in FVB +// bit fields. +// +#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP) + +#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | \ + EFI_FVB2_WRITE_STATUS | \ + EFI_FVB2_LOCK_STATUS) + +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL End; +} FVB_DEVICE_PATH; + +typedef struct { + UNI_NOR_FLASH_PROTOCOL *SpiFlashProtocol; + BOOLEAN IsSpiFlashAvailable; + BOOLEAN IsFvbHeaderValid; + + EFI_DEVICE_PATH_PROTOCOL *DiskDevice; + UINT32 DiskMediaId; + BOOLEAN DiskDataInvalidated; + + EFI_HANDLE Handle; + + UINT32 Signature; + + UINTN DeviceBaseAddress; + UINTN RegionBaseAddress; + UINTN Size; + UINTN FvbOffset; + UINTN FvbSize; + EFI_LBA StartLba; + + EFI_BLOCK_IO_MEDIA Media; + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; + + FVB_DEVICE_PATH DevicePath; +} FVB_DEVICE; + +EFI_STATUS +EFIAPI +FvbGetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + OUT EFI_FVB_ATTRIBUTES_2* Attributes +); + +EFI_STATUS +EFIAPI +FvbSetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + IN OUT EFI_FVB_ATTRIBUTES_2* Attributes +); + +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + OUT EFI_PHYSICAL_ADDRESS* Address +); + +EFI_STATUS +EFIAPI +FvbGetBlockSize( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + IN EFI_LBA Lba, + OUT UINTN* BlockSize, + OUT UINTN* NumberOfBlocks +); + +EFI_STATUS +EFIAPI +FvbRead( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN* NumBytes, + IN OUT UINT8* Buffer +); + +EFI_STATUS +EFIAPI +FvbWrite( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN* NumBytes, + IN UINT8* Buffer +); + +EFI_STATUS +EFIAPI +FvbEraseBlocks( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This, + ... +); + +#endif /* __FVB_FLASH_DXE_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf new file mode 100644 index 0000000..88dcb38 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf @@ -0,0 +1,82 @@ +#/** @file +# +# Firmware Volume Block driver for non-volatile data storage on +# SPI NOR (persistent at runtime) or SD/eMMC (persistent only at boot time). +# +# Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. +# Copyright (c) 2017 Marvell International Ltd. +# Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = RkFvbDxe + FILE_GUID = df325b7e-ae7c-11ec-a154-f42a7dcb925d + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = RkFvbEntryPoint + +[Sources] + RkFvbDxe.c + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + IoLib + BaseLib + DebugLib + HobLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeLib + BaseMemoryLib + DevicePathLib + DxeServicesTableLib + MemoryAllocationLib + UefiRuntimeServicesTableLib + RkAtagsLib + +[Guids] + gEdkiiNvVarStoreFormattedGuid + gEfiAuthenticatedVariableGuid + gEfiEventVirtualAddressChangeGuid + gEfiSystemNvDataFvGuid + gEfiVariableGuid + gEfiEventReadyToBootGuid + gRockchipEventResetGuid + +[Protocols] + gEfiDevicePathProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + gUniNorFlashProtocolGuid + gEfiDiskIoProtocolGuid + gEfiBlockIoProtocolGuid + gEdkiiNonDiscoverableDeviceProtocolGuid + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gRockchipTokenSpaceGuid.PcdNvStoragePreferSpiFlash + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + +[Depex] + TRUE + #gEfiCpuArchProtocolGuid AND + #gUniNorFlashProtocolGuid \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.c new file mode 100644 index 0000000..a890fc3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.c @@ -0,0 +1,169 @@ +/** @file + * + * Synopsys DesignWare MSHC platform driver for Rockchip SDMMC + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include + +#include +#include + +#define DW_MMC_BASE FixedPcdGet32(PcdRkSdmmcBaseAddress) +#define DW_MMC_SIZE SIZE_16KB + +#pragma pack (1) +typedef struct { + VENDOR_DEVICE_PATH Vendor; + UINT64 BaseAddress; + UINT8 ResourceType; + EFI_DEVICE_PATH_PROTOCOL End; +} NON_DISCOVERABLE_DEVICE_PATH; + +typedef struct { + NON_DISCOVERABLE_DEVICE_PATH DevicePath; + NON_DISCOVERABLE_DEVICE Device; +} DW_MMC_DEVICE; +#pragma pack () + +STATIC EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR mDwMmcDeviceDesc[] = { + { + ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3, // Len + ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType + 0, // GenFlag + 0, // SpecificFlag + 32, // AddrSpaceGranularity + DW_MMC_BASE, // AddrRangeMin + DW_MMC_SIZE + DW_MMC_SIZE - 1, // AddrRangeMax + 0, // AddrTranslationOffset + DW_MMC_SIZE // AddrLen + } +}; + +STATIC DW_MMC_DEVICE mDwMmcDevice = { + { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (OFFSET_OF (NON_DISCOVERABLE_DEVICE_PATH, End)), + (UINT8) ((OFFSET_OF (NON_DISCOVERABLE_DEVICE_PATH, End)) >> 8) + } + }, + EDKII_NON_DISCOVERABLE_DEVICE_PROTOCOL_GUID + }, + DW_MMC_BASE, + ACPI_ADDRESS_SPACE_TYPE_MEM, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } + }, + { + &gDwMmcHcNonDiscoverableDeviceGuid, + NonDiscoverableDeviceDmaTypeNonCoherent, + NULL, + mDwMmcDeviceDesc + } +}; + +STATIC DW_MMC_HC_SLOT_CAP mDwMmcCapability = { + .HighSpeed = 1, + .BusWidth = 4, + .SlotType = RemovableSlot, + .CardType = SdCardType, + .Voltage30 = 1, + .BaseClkFreq = 52000 +}; + +STATIC +EFI_STATUS +EFIAPI +RkSdmmcGetCapability ( + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT DW_MMC_HC_SLOT_CAP *Capability + ) +{ + if (Controller != mDwMmcCapability.Controller || Capability == NULL) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (Capability, &mDwMmcCapability, sizeof (DW_MMC_HC_SLOT_CAP)); + + return EFI_SUCCESS; +} + +STATIC +BOOLEAN +EFIAPI +RkSdmmcCardDetect ( + IN EFI_HANDLE Controller, + IN UINT8 Slot + ) +{ + RKSDMMC_CARD_PRESENCE_STATE PresenceState; + + if (Controller != mDwMmcCapability.Controller) { + return FALSE; + } + + PresenceState = RkSdmmcGetCardPresenceState (); + + if ((PresenceState == RkSdmmcCardPresenceUnsupported) || + FixedPcdGetBool (PcdRkSdmmcCardDetectBroken)) { + return TRUE; // let the driver do software detection + } + + return PresenceState == RkSdmmcCardPresent; +} + +STATIC PLATFORM_DW_MMC_PROTOCOL mDwMmcDeviceProtocol = { + RkSdmmcGetCapability, + RkSdmmcCardDetect +}; + +EFI_STATUS +EFIAPI +RkSdmmcDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + RkSdmmcSetIoMux (); + + RkSdmmcSetClockRate (mDwMmcCapability.BaseClkFreq * 1000); + + Status = gBS->InstallMultipleProtocolInterfaces(&mDwMmcCapability.Controller, + &gEfiDevicePathProtocolGuid, &mDwMmcDevice.DevicePath, + &gEdkiiNonDiscoverableDeviceProtocolGuid, &mDwMmcDevice.Device, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gPlatformDwMmcProtocolGuid, + EFI_NATIVE_INTERFACE, + &mDwMmcDeviceProtocol + ); + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf new file mode 100644 index 0000000..6143303 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf @@ -0,0 +1,49 @@ +#/** @file +# +# Synopsys DesignWare MSHC platform driver for Rockchip SDMMC +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RkSdmmcDxe + FILE_GUID = b6c84293-d505-4e5c-84ba-c7ff183fa566 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = RkSdmmcDxeInitialize + +[Sources.common] + RkSdmmcDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Synopsys/DesignWare/DesignWarePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + UefiBootServicesTableLib + RkSdmmcPlatformLib + +[Protocols] + gEfiDevicePathProtocolGuid ## PRODUCES + gEdkiiNonDiscoverableDeviceProtocolGuid ## PRODUCES + gPlatformDwMmcProtocolGuid ## PRODUCES + +[Guids] + gDwMmcHcNonDiscoverableDeviceGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.c new file mode 100644 index 0000000..593663e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.c @@ -0,0 +1,98 @@ +/** @file + * + * Pcf8563RealTimeClockLib initializer for Rockchip platforms. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include + +STATIC +VOID +EFIAPI +RockchipI2cMasterRegistrationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN NumHandles; + ROCKCHIP_I2C_MASTER_PROTOCOL *RockchipI2cMaster; + UINTN Index; + + Handles = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gRockchipI2cMasterProtocolGuid, + NULL, + &NumHandles, + &Handles + ); + if (EFI_ERROR(Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG((DEBUG_WARN, "%a: Failed to locate gRockchipI2cMasterProtocolGuid. Status=%r\n", + __FUNCTION__, Status)); + } + return; + } + + for (Index = 0; Index < NumHandles; Index++) { + Status = gBS->HandleProtocol ( + Handles[Index], + &gRockchipI2cMasterProtocolGuid, + (VOID **)&RockchipI2cMaster + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to get RockchipI2cMaster: %r\n", __FUNCTION__, Status)); + continue; + } + + if (RockchipI2cMaster->Bus != FixedPcdGet8 (PcdRtc8563Bus)) { + continue; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handles[Index], + &gPcf8563RealTimeClockLibI2cMasterProtocolGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to install gPcf8563RealTimeClockLibI2cMasterProtocolGuid: %r\n", + __FUNCTION__, Status)); + continue; + } + + gBS->CloseEvent (Event); + } + + FreePool (Handles); +} + +EFI_STATUS +EFIAPI +Rtc8563PlatformDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Registration = NULL; + + EfiCreateProtocolNotifyEvent ( + &gRockchipI2cMasterProtocolGuid, + TPL_CALLBACK, + RockchipI2cMasterRegistrationEvent, + NULL, + &Registration + ); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf new file mode 100644 index 0000000..f944ec3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf @@ -0,0 +1,42 @@ +#/** @file +# +# Pcf8563RealTimeClockLib initializer for Rockchip platforms. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RtcPlatformDxe + FILE_GUID = b4d6e6b1-b2a0-4c79-8bf1-3af8c485ec3d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Rtc8563PlatformDxeInitialize + +[Sources.common] + Rtc8563PlatformDxe.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/NXP/Library/Pcf8563RealTimeClockLib/Pcf8563RealTimeClockLib.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + UefiBootServicesTableLib + MemoryAllocationLib + DebugLib + +[Protocols] + gRockchipI2cMasterProtocolGuid ## CONSUMES + gPcf8563RealTimeClockLibI2cMasterProtocolGuid ## PRODUCES + +[Pcd] + gRockchipTokenSpaceGuid.PcdRtc8563Bus + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.c new file mode 100644 index 0000000..44d0431 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.c @@ -0,0 +1,278 @@ +/** @file + * + * Platform Status LED controller + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#define REPEAT_INFINITE MAX_UINT32 + +#define LONG_PULSE_PERIOD_MS 840 +#define SHORT_PULSE_PERIOD_MS 140 + +#define MILLIS_TO_MICROS(x) (x * 1000) + +// Timer for async execution +EFI_EVENT mTimerEvent; + +// Parameters +UINT32 mAsyncLongPulseCount; +UINT32 mAsyncShortPulseCount; +UINT32 mAsyncRepeatCount; +UINT32 mAsyncPatternDelayMs; +UINT32 mAsyncContinueWithIdlePattern; + +// State variables +UINT32 mAsyncRepeatIndex; +UINT32 mAsyncShortPulseIndex; +UINT32 mAsyncLongPulseIndex; + +BOOLEAN mLedEnabled; + +STATIC +VOID +SetLed ( + IN BOOLEAN Enable + ) +{ + PlatformSetStatusLed (Enable); + mLedEnabled = Enable; +} + +STATIC +VOID +InitLed ( + VOID + ) +{ + PlatformInitLeds (); +} + +STATIC +VOID +BlinkLedAsync ( + IN UINT32 LongPulseCount, + IN UINT32 ShortPulseCount, + IN UINT32 RepeatCount, + IN UINT32 PatternDelayMs, + IN BOOLEAN ContinueWithIdlePattern + ) +{ + gBS->SetTimer (mTimerEvent, TimerCancel, 0); + + mAsyncLongPulseCount = LongPulseCount; + mAsyncShortPulseCount = ShortPulseCount; + mAsyncRepeatCount = RepeatCount; + mAsyncPatternDelayMs = PatternDelayMs; + mAsyncContinueWithIdlePattern = ContinueWithIdlePattern; + mAsyncRepeatIndex = 0; + mAsyncShortPulseIndex = 0; + mAsyncLongPulseIndex = 0; + + SetLed (FALSE); + + gBS->SetTimer (mTimerEvent, TimerRelative, 0); +} + +STATIC +VOID +BlinkLedIdleAsync ( + VOID + ) +{ + BlinkLedAsync (0, 1, REPEAT_INFINITE, 2000, FALSE); +} + +STATIC +VOID +TimerHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Process long pulses + // + if (mAsyncLongPulseIndex < mAsyncLongPulseCount) { + if (mLedEnabled) { + mAsyncLongPulseIndex++; + } + SetLed (!mLedEnabled); + + gBS->SetTimer (mTimerEvent, TimerRelative, + EFI_TIMER_PERIOD_MILLISECONDS (LONG_PULSE_PERIOD_MS)); + return; + } + + // + // Process short pulses + // + if (mAsyncShortPulseIndex < mAsyncShortPulseCount) { + if (mLedEnabled) { + mAsyncShortPulseIndex++; + } + SetLed (!mLedEnabled); + + gBS->SetTimer (mTimerEvent, TimerRelative, + EFI_TIMER_PERIOD_MILLISECONDS (SHORT_PULSE_PERIOD_MS)); + return; + } + + // + // Completion happens at mAsyncRepeatCount + 1, because + // we schedule this routine one more time just to wait + // for mAsyncPatternDelayMs and thus introduce a pause + // before the next pattern. + // + if (mAsyncRepeatIndex > mAsyncRepeatCount) { + if (mAsyncContinueWithIdlePattern) { + BlinkLedIdleAsync (); + } + return; + } + + // + // Do we need to repeat the pattern? Reset the pulse indexes. + // + if (mAsyncRepeatIndex < mAsyncRepeatCount) { + mAsyncShortPulseIndex = 0; + mAsyncLongPulseIndex = 0; + } + + // + // Keep repeating until completion above. + // + if (mAsyncRepeatCount != REPEAT_INFINITE) { + mAsyncRepeatIndex++; + } + + gBS->SetTimer (mTimerEvent, TimerRelative, + EFI_TIMER_PERIOD_MILLISECONDS (mAsyncPatternDelayMs)); +} + +STATIC +VOID +BlinkLedSync ( + IN UINT32 LongPulseCount, + IN UINT32 ShortPulseCount, + IN UINT32 RepeatCount, + IN UINT32 PatternDelayMs, + IN BOOLEAN ContinueWithIdlePattern + ) +{ + UINT32 RepeatIndex = 0; + UINT32 PulseIndex = 0; + + gBS->SetTimer (mTimerEvent, TimerCancel, 0); + SetLed (FALSE); + + while (RepeatIndex <= RepeatCount) { + for (PulseIndex = 0; PulseIndex < LongPulseCount; PulseIndex++) { + SetLed (TRUE); + gBS->Stall (MILLIS_TO_MICROS(LONG_PULSE_PERIOD_MS)); + SetLed (FALSE); + gBS->Stall (MILLIS_TO_MICROS(LONG_PULSE_PERIOD_MS)); + } + + for (PulseIndex = 0; PulseIndex < ShortPulseCount; PulseIndex++) { + SetLed (TRUE); + gBS->Stall (MILLIS_TO_MICROS(SHORT_PULSE_PERIOD_MS)); + SetLed (FALSE); + gBS->Stall (MILLIS_TO_MICROS(SHORT_PULSE_PERIOD_MS)); + } + + gBS->Stall (MILLIS_TO_MICROS(PatternDelayMs)); + + if (RepeatCount != REPEAT_INFINITE) { + RepeatIndex++; + } + } + + if (ContinueWithIdlePattern) { + BlinkLedIdleAsync (); + } +} + +STATIC +VOID +EFIAPI +NotifyPlatformBmAfterConsole ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // All platform drivers have been dispatched and configured + // at this point. Start the idle pattern to indicate that the + // firmware is alive and (hopefully) well. + // + BlinkLedIdleAsync (); +} + +STATIC +VOID +EFIAPI +NotifyExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Turn off the LED in case the timer didn't have a chance to. + // + SetLed (FALSE); +} + +EFI_STATUS +EFIAPI +StatusLedDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event = NULL; + + InitLed (); + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, // Type + TPL_NOTIFY, // NotifyTpl + TimerHandler, // NotifyFunction + NULL, // NotifyContext + &mTimerEvent // Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Initial firmware loading pattern + BlinkLedAsync (0, 1, REPEAT_INFINITE, 0, FALSE); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_NOTIFY, // NotifyTpl + NotifyPlatformBmAfterConsole, // NotifyFunction + NULL, // NotifyContext + &gRockchipEventPlatformBmAfterConsoleGuid, // EventGroup + &Event // Event + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_NOTIFY, // NotifyTpl + NotifyExitBootServices, // NotifyFunction + NULL, // NotifyContext + &gEfiEventExitBootServicesGuid, // EventGroup + &Event // Event + ); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf new file mode 100644 index 0000000..0b319bb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf @@ -0,0 +1,41 @@ +#/** @file +# +# Platform Status LED controller +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = StatusLedDxe + FILE_GUID = b1f3fd14-9bd1-48cc-9258-e2807ecb1b84 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = StatusLedDxeInitialize + +[Sources.common] + StatusLedDxe.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + UefiBootServicesTableLib + RockchipPlatformLib + +[Pcd] + +[Protocols] + +[Guids] + gEfiEventExitBootServicesGuid + gRockchipEventPlatformBmAfterConsoleGuid + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.c new file mode 100644 index 0000000..b05317a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.c @@ -0,0 +1,419 @@ +/** @file + + Copyright 2017, 2020 NXP + Copyright 2021, Jared McNeill + Copyright (c) 2023, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "UsbHcd.h" + +STATIC +VOID +XhciSetBeatBurstLength ( + IN UINTN UsbReg + ) +{ + DWC3 *Dwc3Reg; + + Dwc3Reg = (VOID *)(UsbReg + DWC3_REG_OFFSET); + + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GSBusCfg0, ~USB3_ENABLE_BEAT_BURST_MASK, + USB3_ENABLE_BEAT_BURST); + + MmioOr32 ((UINTN)&Dwc3Reg->GSBusCfg1, USB3_SET_BEAT_BURST_LIMIT); +} + +STATIC +VOID +Dwc3SetFladj ( + IN DWC3 *Dwc3Reg, + IN UINT32 Val + ) +{ + MmioOr32 ((UINTN)&Dwc3Reg->GFLAdj, GFLADJ_30MHZ_REG_SEL | + GFLADJ_30MHZ (Val)); +} + +STATIC +VOID +Dwc3SetMode ( + IN DWC3 *Dwc3Reg, + IN UINT32 Mode + ) +{ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GCtl, + ~(DWC3_GCTL_PRTCAPDIR (DWC3_GCTL_PRTCAP_OTG)), + DWC3_GCTL_PRTCAPDIR (Mode)); +} + +/** + This function issues phy reset and core soft reset + + @param Dwc3Reg Pointer to DWC3 register. + +**/ +STATIC +VOID +Dwc3CoreSoftReset ( + IN DWC3 *Dwc3Reg + ) +{ + // + // Put core in reset before resetting PHY + // + MmioOr32 ((UINTN)&Dwc3Reg->GCtl, DWC3_GCTL_CORESOFTRESET); + + // + // Assert USB2 PHY reset + // + MmioOr32 ((UINTN)&Dwc3Reg->GUsb3PipeCtl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + // + // Assert USB3 PHY reset + // + MmioOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], DWC3_GUSB2PHYCFG_PHYSOFTRST); + + MemoryFence (); + + // + // Clear USB3 PHY reset + // + MmioAnd32 ((UINTN)&Dwc3Reg->GUsb3PipeCtl[0], ~DWC3_GUSB3PIPECTL_PHYSOFTRST); + + // + // Clear USB2 PHY reset + // + MmioAnd32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], ~DWC3_GUSB2PHYCFG_PHYSOFTRST); + + MemoryFence (); + + // + // Take core out of reset, PHYs are stable now + // + MmioAnd32 ((UINTN)&Dwc3Reg->GCtl, ~DWC3_GCTL_CORESOFTRESET); +} + +/** + This function performs low-level initialization of DWC3 Core + + @param Dwc3Reg Pointer to DWC3 register. + +**/ +STATIC +EFI_STATUS +Dwc3CoreInit ( + IN DWC3 *Dwc3Reg + ) +{ + UINT32 Revision; + UINT32 Reg; + UINTN Dwc3Hwparams1; + + Revision = MmioRead32 ((UINTN)&Dwc3Reg->GSnpsId); + // + // This should read as 0x5533, ascii of U3(DWC_usb3) followed by revision num + // + if ((Revision & DWC3_GSNPSID_MASK) != DWC3_SYNOPSYS_ID) { + DEBUG ((DEBUG_ERROR,"This is not a DesignWare USB3 DRD Core.\n")); + return EFI_NOT_FOUND; + } + + Dwc3CoreSoftReset (Dwc3Reg); + + Reg = MmioRead32 ((UINTN)&Dwc3Reg->GCtl); + Reg &= ~DWC3_GCTL_SCALEDOWN_MASK; + Reg &= ~DWC3_GCTL_DISSCRAMBLE; + + Dwc3Hwparams1 = MmioRead32 ((UINTN)&Dwc3Reg->GHwParams1); + + if (DWC3_GHWPARAMS1_EN_PWROPT (Dwc3Hwparams1) == + DWC3_GHWPARAMS1_EN_PWROPT_CLK) { + Reg &= ~DWC3_GCTL_DSBLCLKGTNG; + } else { + DEBUG ((DEBUG_WARN,"No power optimization available.\n")); + } + + if ((Revision & DWC3_RELEASE_MASK) < DWC3_RELEASE_190a) { + Reg |= DWC3_GCTL_U2RSTECN; + } + + MmioWrite32 ((UINTN)&Dwc3Reg->GCtl, Reg); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +XhciCoreInit ( + IN UINTN UsbReg + ) +{ + EFI_STATUS Status; + DWC3 *Dwc3Reg; + + Dwc3Reg = (VOID *)(UsbReg + DWC3_REG_OFFSET); + + Status = Dwc3CoreInit (Dwc3Reg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Dwc3CoreInit Failed for controller 0x%x (0x%r) \n", + UsbReg, Status)); + + return Status; + } + + Dwc3SetMode (Dwc3Reg, DWC3_GCTL_PRTCAP_HOST); + + Dwc3SetFladj (Dwc3Reg, GFLADJ_30MHZ_DEFAULT); + + /* UTMI+ mode */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK, DWC3_GUSB2PHYCFG_USBTRDTIM(5)); + MmioOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], DWC3_GUSB2PHYCFG_PHYIF); + + /* snps,dis_enblslpm_quirk */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], ~DWC3_GUSB2PHYCFG_ENBLSLPM, 0); + /* snps,dis-u2-freeclk-exists-quirk */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS, 0); + /* snps,dis_u2_susphy_quirk */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GUsb2PhyCfg[0], ~DWC3_GUSB2PHYCFG_SUSPHY, 0); + /* snps,dis-del-phy-power-chg-quirk */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->GUsb3PipeCtl[0], ~DWC3_GUSB3PIPECTL_DEPOCHANGE, 0); + /* snps,dis-tx-ipgap-linecheck-quirk */ + MmioOr32 ((UINTN)&Dwc3Reg->GUctl1, DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS); + /* snps,parkmode-disable-ss-quirk */ + MmioOr32 ((UINTN)&Dwc3Reg->GUctl1, DWC3_GUCTL1_PARKMODE_DISABLE_SS); + + /* Set max speed */ + MmioAndThenOr32 ((UINTN)&Dwc3Reg->DCfg, ~DCFG_SPEED_MASK, DCFG_SPEED_SS); + + return Status; +} + +EFIAPI +EFI_STATUS +InitializeXhciController ( + IN NON_DISCOVERABLE_DEVICE *This + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS UsbReg = This->Resources->AddrRangeMin; + + DEBUG ((DEBUG_INFO, "XHCI: Initialize DWC3 at 0x%lX\n", UsbReg)); + + Status = XhciCoreInit (UsbReg); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "XHCI: Controller init Failed for 0x%lX (0x%r)\n", + UsbReg, Status)); + return EFI_DEVICE_ERROR; + } + + // + // Change beat burst and outstanding pipelined transfers requests + // + XhciSetBeatBurstLength (UsbReg); + + return EFI_SUCCESS; +} + +#pragma pack (1) +typedef struct { + VENDOR_DEVICE_PATH Vendor; + UINT32 BaseAddress; + EFI_DEVICE_PATH_PROTOCOL End; +} OHCI_DEVICE_PATH; +#pragma pack () + +STATIC +EFI_STATUS +EFIAPI +RegisterOhciController ( + IN UINT32 BaseAddress + ) +{ + EFI_STATUS Status; + OHCI_DEVICE_PROTOCOL *OhciDevice; + OHCI_DEVICE_PATH *OhciDevicePath; + EFI_HANDLE Handle; + + OhciDevice = (OHCI_DEVICE_PROTOCOL*)AllocateZeroPool (sizeof(*OhciDevice)); + if (OhciDevice == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + OhciDevice->BaseAddress = BaseAddress; + + OhciDevicePath = (OHCI_DEVICE_PATH*)CreateDeviceNode ( + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + sizeof (*OhciDevicePath) + ); + if (OhciDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeOhciDevice; + } + + CopyGuid (&OhciDevicePath->Vendor.Guid, &gOhciDeviceProtocolGuid); + + /* Device paths must be unique */ + OhciDevicePath->BaseAddress = OhciDevice->BaseAddress; + + SetDevicePathNodeLength (&OhciDevicePath->Vendor, + sizeof (*OhciDevicePath) - sizeof (OhciDevicePath->End)); + SetDevicePathEndNode (&OhciDevicePath->End); + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEfiDevicePathProtocolGuid, OhciDevicePath, + &gOhciDeviceProtocolGuid, OhciDevice, + NULL); + if (EFI_ERROR (Status)) { + goto FreeOhciDevicePath; + } + + return EFI_SUCCESS; + +FreeOhciDevicePath: + FreePool (OhciDevicePath); +FreeOhciDevice: + FreePool (OhciDevice); + + return Status; +} + +/** + This function gets registered as a callback to perform USB controller intialization + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +UsbEndOfDxeCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINT32 NumUsb2Controller; + UINTN XhciControllerAddrArraySize; + UINT8 *XhciControllerAddrArrayPtr; + UINT32 XhciControllerAddr; + UINT32 EhciControllerAddr; + UINT32 OhciControllerAddr; + UINT32 Index; + + gBS->CloseEvent (Event); + + XhciControllerAddrArrayPtr = PcdGetPtr (PcdDwc3BaseAddresses); + XhciControllerAddrArraySize = PcdGetSize (PcdDwc3BaseAddresses); + + if (XhciControllerAddrArraySize % sizeof(UINT32) != 0) { + DEBUG ((DEBUG_ERROR, "Invalid DWC3 address byte array size, skipping init.\n")); + XhciControllerAddrArraySize = 0; + } + + NumUsb2Controller = PcdGet32 (PcdNumEhciController); + + /* Enable USB PHYs */ + Usb2PhyResume (); + + UsbPortPowerEnable (); + + /* Register USB3 controllers */ + for (Index = 0; Index < XhciControllerAddrArraySize; Index += sizeof(UINT32)) { + XhciControllerAddr = XhciControllerAddrArrayPtr[Index] | + XhciControllerAddrArrayPtr[Index + 1] << 8 | + XhciControllerAddrArrayPtr[Index + 2] << 16 | + XhciControllerAddrArrayPtr[Index + 3] << 24; + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeXhci, + NonDiscoverableDeviceDmaTypeNonCoherent, + InitializeXhciController, + NULL, + 1, + XhciControllerAddr, PcdGet32 (PcdDwc3Size) + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to register XHCI device 0x%x, error 0x%r \n", + XhciControllerAddr, Status)); + } + } + + /* Register USB2 controllers */ + for (Index = 0; Index < NumUsb2Controller; Index++) { + EhciControllerAddr = PcdGet32 (PcdEhciBaseAddress) + + (Index * (PcdGet32 (PcdEhciSize) + PcdGet32 (PcdOhciSize))); + OhciControllerAddr = EhciControllerAddr + PcdGet32 (PcdOhciSize); + + Status = RegisterNonDiscoverableMmioDevice ( + NonDiscoverableDeviceTypeEhci, + NonDiscoverableDeviceDmaTypeNonCoherent, + NULL, + NULL, + 1, + EhciControllerAddr, PcdGet32 (PcdEhciSize) + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to register EHCI device 0x%x, error 0x%r \n", + EhciControllerAddr, Status)); + } + + Status = RegisterOhciController (OhciControllerAddr); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to register OHCI device 0x%x, error 0x%r \n", + OhciControllerAddr, Status)); + } + } +} + +/** + The Entry Point of module. It follows the standard UEFI driver model. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeUsbHcd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT EndOfDxeEvent; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + UsbEndOfDxeCallback, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.h new file mode 100644 index 0000000..216fa14 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.h @@ -0,0 +1,157 @@ +/** @file + + Copyright 2017, 2020 NXP + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef USB_HCD_H_ +#define USB_HCD_H_ + +#include + +/* Global constants */ +#define DWC3_GSNPSID_MASK 0xffff0000 +#define DWC3_SYNOPSYS_ID 0x55330000 +#define DWC3_RELEASE_MASK 0xffff +#define DWC3_REG_OFFSET 0xC100 +#define DWC3_RELEASE_190a 0x190a + +/* Global Configuration Register */ +#define DWC3_GCTL_U2RSTECN BIT16 +#define DWC3_GCTL_PRTCAPDIR(N) ((N) << 12) +#define DWC3_GCTL_PRTCAP_HOST 1 +#define DWC3_GCTL_PRTCAP_OTG 3 +#define DWC3_GCTL_CORESOFTRESET BIT11 +#define DWC3_GCTL_SCALEDOWN(N) ((N) << 4) +#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) +#define DWC3_GCTL_DISSCRAMBLE BIT3 +#define DWC3_GCTL_DSBLCLKGTNG BIT0 + +/* Global HWPARAMS1 Register */ +#define DWC3_GHWPARAMS1_EN_PWROPT(N) (((N) & (3 << 24)) >> 24) +#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 + +/* Global UCTL1 Register */ +#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT28 +#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT17 + +/* Global USB2 PHY Configuration Register */ +#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT31 +#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT30 +#define DWC3_GUSB2PHYCFG_USBTRDTIM(N) (((N) & 0xf) << 10) +#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf) +#define DWC3_GUSB2PHYCFG_SUSPHY BIT6 +#define DWC3_GUSB2PHYCFG_PHYIF BIT3 +#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT0 + +/* Global USB3 PIPE Control Register */ +#define DWC3_GUSB3PIPECTL_PHYSOFTRST BIT31 +#define DWC3_GUSB3PIPECTL_DEPOCHANGE BIT18 + +/* Global Frame Length Adjustment Register */ +#define GFLADJ_30MHZ_REG_SEL BIT7 +#define GFLADJ_30MHZ(N) ((N) & 0x3f) +#define GFLADJ_30MHZ_DEFAULT 0x20 + +/* Default to the FSL XHCI defines */ +#define USB3_ENABLE_BEAT_BURST 0xF +#define USB3_ENABLE_BEAT_BURST_MASK 0xFF +#define USB3_SET_BEAT_BURST_LIMIT 0xF00 + +/* DCFG Register */ +#define DCFG_SPEED_MASK (BIT2|BIT1|BIT0) +#define DCFG_SPEED_HS 0 +#define DCFG_SPEED_FS 1 +#define DCFG_SPEED_LS 2 +#define DCFG_SPEED_SS 4 +#define DCFG_SPEED_SS_PLUS 5 + +typedef struct { + UINT32 GEvntAdrLo; + UINT32 GEvntAdrHi; + UINT32 GEvntSiz; + UINT32 GEvntCount; +} G_EVENT_BUFFER; + +typedef struct { + UINT32 DDepCmdPar2; + UINT32 DDepCmdPar1; + UINT32 DDepCmdPar0; + UINT32 DDepCmd; +} D_PHYSICAL_EP; + +typedef struct { + UINT32 GSBusCfg0; + UINT32 GSBusCfg1; + UINT32 GTxThrCfg; + UINT32 GRxThrCfg; + UINT32 GCtl; + UINT32 Res1; + UINT32 GSts; + UINT32 GUctl1; + UINT32 GSnpsId; + UINT32 GGpio; + UINT32 GUid; + UINT32 GUctl; + UINT64 GBusErrAddr; + UINT64 GPrtbImap; + UINT32 GHwParams0; + UINT32 GHwParams1; + UINT32 GHwParams2; + UINT32 GHwParams3; + UINT32 GHwParams4; + UINT32 GHwParams5; + UINT32 GHwParams6; + UINT32 GHwParams7; + UINT32 GDbgFifoSpace; + UINT32 GDbgLtssm; + UINT32 GDbgLnmcc; + UINT32 GDbgBmu; + UINT32 GDbgLspMux; + UINT32 GDbgLsp; + UINT32 GDbgEpInfo0; + UINT32 GDbgEpInfo1; + UINT64 GPrtbImapHs; + UINT64 GPrtbImapFs; + UINT32 Res3[28]; + UINT32 GUsb2PhyCfg[16]; + UINT32 GUsb2I2cCtl[16]; + UINT32 GUsb2PhyAcc[16]; + UINT32 GUsb3PipeCtl[16]; + UINT32 GTxFifoSiz[32]; + UINT32 GRxFifoSiz[32]; + G_EVENT_BUFFER GEvntBuf[32]; + UINT32 GHwParams8; + UINT32 Res4[11]; + UINT32 GFLAdj; + UINT32 Res5[51]; + UINT32 DCfg; + UINT32 DCtl; + UINT32 DEvten; + UINT32 DSts; + UINT32 DGCmdPar; + UINT32 DGCmd; + UINT32 Res6[2]; + UINT32 DAlepena; + UINT32 Res7[55]; + D_PHYSICAL_EP DPhyEpCmd[32]; + UINT32 Res8[128]; + UINT32 OCfg; + UINT32 OCtl; + UINT32 OEvt; + UINT32 OEvtEn; + UINT32 OSts; + UINT32 Res9[3]; + UINT32 AdpCfg; + UINT32 AdpCtl; + UINT32 AdpEvt; + UINT32 AdpEvten; + UINT32 BcCfg; + UINT32 Res10; + UINT32 BcEvt; + UINT32 BcEvten; +} DWC3; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf new file mode 100644 index 0000000..ff52c8c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf @@ -0,0 +1,53 @@ +# UsbHcd.inf +# +# Copyright 2017, 2020 NXP +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = UsbHcdDxe + FILE_GUID = 196e7c2a-37b2-4b85-8683-718588952449 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeUsbHcd + +[Sources.common] + UsbHcd.c + UsbHcd.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + MemoryAllocationLib + NonDiscoverableDeviceRegistrationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + RockchipPlatformLib + DevicePathLib + +[FixedPcd] + gRockchipTokenSpaceGuid.PcdOhciSize + gRockchipTokenSpaceGuid.PcdEhciBaseAddress + gRockchipTokenSpaceGuid.PcdNumEhciController + gRockchipTokenSpaceGuid.PcdEhciSize + gRockchipTokenSpaceGuid.PcdDwc3BaseAddresses + gRockchipTokenSpaceGuid.PcdDwc3Size + +[Protocols] + gOhciDeviceProtocolGuid ## PRODUCES + +[Guids] + gEfiEndOfDxeEventGroupGuid + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.c new file mode 100644 index 0000000..56592bc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.c @@ -0,0 +1,2574 @@ +/** @file + Vop2 DXE Driver, install RK_CRTC_PROTOCOL. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "Vop2Dxe.h" + +STATIC VPS_CONFIG mVpsConfigs[][VOP2_VP_MAX] = { + { + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER0 | 1 << ROCKCHIP_VOP2_ESMART0), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART0, + }, + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER1 | 1 << ROCKCHIP_VOP2_ESMART1), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART1, + }, + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER2 | 1 << ROCKCHIP_VOP2_ESMART2), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART2, + }, + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER3 | 1 << ROCKCHIP_VOP2_ESMART3), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART3, + }, + }, + { + { + .PlaneMask = 0, + .PrimaryPlane = 0, + }, + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER0 | 1 << ROCKCHIP_VOP2_ESMART0 | + 1 << ROCKCHIP_VOP2_CLUSTER1 | 1 << ROCKCHIP_VOP2_ESMART1), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART1, + }, + { + .PlaneMask = (1 << ROCKCHIP_VOP2_CLUSTER2 | 1 << ROCKCHIP_VOP2_ESMART2 | + 1 << ROCKCHIP_VOP2_CLUSTER3 | 1 << ROCKCHIP_VOP2_ESMART3), + .PrimaryPlane = ROCKCHIP_VOP2_ESMART2, + }, + { + .PlaneMask = 0, + .PrimaryPlane = 0, + }, + }, +}; + +STATIC UINT32 mVpsConfigsSize = ARRAY_SIZE (mVpsConfigs); + +STATIC CONST INT32 mSinTable[] = { + 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c, + 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd, + 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e, + 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44, + 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb, + 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1, + 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04, + 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82, + 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039, + 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879, + 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf, + 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af, + 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884, + 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095, + 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e, + 0x7fffffff +}; + +STATIC VOP2_VP_PLANE_MASK mVpPlaneMaskRK3588[VOP2_VP_MAX][VOP2_VP_MAX] = { + { /* one display policy */ + {/* main display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART0, + .AttachedLayersNr = 8, + .AttachedLayers = { + ROCKCHIP_VOP2_CLUSTER0, ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_CLUSTER1, ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_CLUSTER2, ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_CLUSTER3, ROCKCHIP_VOP2_ESMART3 + }, + }, + {/* second display */}, + {/* third display */}, + {/* fourth display */}, + }, + + { /* two display policy */ + {/* main display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART0, + .AttachedLayersNr = 4, + .AttachedLayers = { + ROCKCHIP_VOP2_CLUSTER0, ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_CLUSTER1, ROCKCHIP_VOP2_ESMART1 + }, + }, + + {/* second display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART2, + .AttachedLayersNr = 4, + .AttachedLayers = { + ROCKCHIP_VOP2_CLUSTER2, ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_CLUSTER3, ROCKCHIP_VOP2_ESMART3 + }, + }, + {/* third display */}, + {/* fourth display */}, + }, + + { /* three display policy */ + {/* main display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART0, + .AttachedLayersNr = 3, + .AttachedLayers = { + ROCKCHIP_VOP2_CLUSTER0, ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_CLUSTER1 + }, + }, + + {/* second display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART1, + .AttachedLayersNr = 3, + .AttachedLayers = { + ROCKCHIP_VOP2_CLUSTER2, ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_CLUSTER3 + }, + }, + + {/* third display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART2, + .AttachedLayersNr = 2, + .AttachedLayers = { ROCKCHIP_VOP2_ESMART2, ROCKCHIP_VOP2_ESMART3 }, + }, + + {/* fourth display */}, + }, + + { /* four display policy */ + {/* main display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART0, + .AttachedLayersNr = 2, + .AttachedLayers = { ROCKCHIP_VOP2_CLUSTER0, ROCKCHIP_VOP2_ESMART0 }, + }, + + {/* second display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART1, + .AttachedLayersNr = 2, + .AttachedLayers = { ROCKCHIP_VOP2_CLUSTER1, ROCKCHIP_VOP2_ESMART1 }, + }, + + {/* third display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART2, + .AttachedLayersNr = 2, + .AttachedLayers = { ROCKCHIP_VOP2_CLUSTER2, ROCKCHIP_VOP2_ESMART2 }, + }, + + {/* fourth display */ + .PrimaryPlaneId = ROCKCHIP_VOP2_ESMART3, + .AttachedLayersNr = 2, + .AttachedLayers = { ROCKCHIP_VOP2_CLUSTER3, ROCKCHIP_VOP2_ESMART3 }, + }, + }, +}; + +STATIC VOP2_VP_DATA mVpDataRK3588[4] = { + { + .Feature = VOP_FEATURE_OUTPUT_10BIT, + .PreScanMaxDly = 42, + .MaxDclk = 600000, + .MaxOutput = {7680, 4320}, + }, + { + .Feature = VOP_FEATURE_OUTPUT_10BIT, + .PreScanMaxDly = 40, + .MaxDclk = 600000, + .MaxOutput = {4096, 2304}, + }, + { + .Feature = VOP_FEATURE_OUTPUT_10BIT, + .PreScanMaxDly = 52, + .MaxDclk = 600000, + .MaxOutput = {4096, 2304}, + }, + { + .Feature = 0, + .PreScanMaxDly = 52, + .MaxDclk = 200000, + .MaxOutput = {1920, 1080}, + }, +}; + +static VOP2_POWER_DOMAIN_DATA mCluster0PdDataRK3588 = { + .PdEnShift = RK3588_CLUSTER0_PD_EN_SHIFT, + .PdStatusShift = RK3588_CLUSTER0_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_CLUSTER0_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_CLUSTER0_REPAIR_EN_SHIFT, +}; + +static VOP2_POWER_DOMAIN_DATA mCluster1PdDataRK3588 = { + .PdEnShift = RK3588_CLUSTER1_PD_EN_SHIFT, + .PdStatusShift = RK3588_CLUSTER1_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_CLUSTER1_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_CLUSTER1_REPAIR_EN_SHIFT, + .ParentPdData = &mCluster0PdDataRK3588, +}; + +static VOP2_POWER_DOMAIN_DATA mCluster2PdDataRK3588 = { + .PdEnShift = RK3588_CLUSTER2_PD_EN_SHIFT, + .PdStatusShift = RK3588_CLUSTER2_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_CLUSTER2_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_CLUSTER2_REPAIR_EN_SHIFT, + .ParentPdData = &mCluster0PdDataRK3588, +}; + +static VOP2_POWER_DOMAIN_DATA mCluster3PdDataRK3588 = { + .PdEnShift = RK3588_CLUSTER3_PD_EN_SHIFT, + .PdStatusShift = RK3588_CLUSTER3_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_CLUSTER3_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_CLUSTER3_REPAIR_EN_SHIFT, + .ParentPdData = &mCluster0PdDataRK3588, +}; + +static VOP2_POWER_DOMAIN_DATA mEsmartPdDataRK3588 = { + .PdEnShift = RK3588_ESMART_PD_EN_SHIFT, + .PdStatusShift = RK3588_ESMART_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_ESMART_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_ESMART_REPAIR_EN_SHIFT, +}; + +static VOP2_POWER_DOMAIN_DATA mDsc8KPdDataRK3588 = { + .PdEnShift = RK3588_DSC_8K_PD_EN_SHIFT, + .PdStatusShift = RK3588_DSC_8K_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_DSC_8K_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_DSC_8K_REPAIR_EN_SHIFT, +}; + +static VOP2_POWER_DOMAIN_DATA mDsc4KPdDataRK3588 = { + .PdEnShift = RK3588_DSC_4K_PD_EN_SHIFT, + .PdStatusShift = RK3588_DSC_4K_PD_STATUS_SHIFT, + .PmuStatusShift = RK3588_PD_DSC_4K_PWR_STAT_SHIFI, + .BisrEnStatusShift = RK3588_PD_DSC_4K_REPAIR_EN_SHIFT, +}; + +static VOP2_WIN_DATA mWinDataRK3588[8] = { + { + .Name = "Cluster0", + .PhysID = ROCKCHIP_VOP2_CLUSTER0, + .Type = CLUSTER_LAYER, + .WinSelPortOffset = 0, + .LayerSelWinID = 0, + .RegOffset = 0, + .PdData = &mCluster0PdDataRK3588, + }, + + { + .Name = "Cluster1", + .PhysID = ROCKCHIP_VOP2_CLUSTER1, + .Type = CLUSTER_LAYER, + .WinSelPortOffset = 1, + .LayerSelWinID = 1, + .RegOffset = 0x200, + .PdData = &mCluster1PdDataRK3588, + }, + + { + .Name = "Cluster2", + .PhysID = ROCKCHIP_VOP2_CLUSTER2, + .Type = CLUSTER_LAYER, + .WinSelPortOffset = 2, + .LayerSelWinID = 4, + .RegOffset = 0x400, + .PdData = &mCluster2PdDataRK3588, + }, + + { + .Name = "Cluster3", + .PhysID = ROCKCHIP_VOP2_CLUSTER3, + .Type = CLUSTER_LAYER, + .WinSelPortOffset = 3, + .LayerSelWinID = 5, + .RegOffset = 0x600, + .PdData = &mCluster3PdDataRK3588, + }, + + { + .Name = "Esmart0", + .PhysID = ROCKCHIP_VOP2_ESMART0, + .Type = ESMART_LAYER, + .WinSelPortOffset = 4, + .LayerSelWinID = 2, + .RegOffset = 0, + .PdData = &mEsmartPdDataRK3588, + }, + + { + .Name = "Esmart1", + .PhysID = ROCKCHIP_VOP2_ESMART1, + .Type = ESMART_LAYER, + .WinSelPortOffset = 5, + .LayerSelWinID = 3, + .RegOffset = 0x200, + .PdData = &mEsmartPdDataRK3588, + }, + + { + .Name = "Esmart2", + .PhysID = ROCKCHIP_VOP2_ESMART2, + .Type = ESMART_LAYER, + .WinSelPortOffset = 6, + .LayerSelWinID = 6, + .RegOffset = 0x400, + .PdData = &mEsmartPdDataRK3588, + }, + + { + .Name = "Esmart3", + .PhysID = ROCKCHIP_VOP2_ESMART3, + .Type = ESMART_LAYER, + .WinSelPortOffset = 7, + .LayerSelWinID = 7, + .RegOffset = 0x600, + .PdData = &mEsmartPdDataRK3588, + }, +}; + +STATIC VOP2_DSC_DATA mDscDataRK3588[] = { + { + .id = ROCKCHIP_VOP2_DSC_8K, + .PdData = &mDsc8KPdDataRK3588, + .max_slice_num = 8, + .max_linebuf_depth = 11, + .min_bits_per_pixel = 8, + .dsc_txp_clk_src_name = "dsc_8k_txp_clk_src", + .dsc_txp_clk_name = "dsc_8k_txp_clk", + .dsc_pxl_clk_name = "dsc_8k_pxl_clk", + .dsc_cds_clk_name = "dsc_8k_cds_clk", + }, + + { + .id = ROCKCHIP_VOP2_DSC_4K, + .PdData = &mDsc4KPdDataRK3588, + .max_slice_num = 2, + .max_linebuf_depth = 11, + .min_bits_per_pixel = 8, + .dsc_txp_clk_src_name = "dsc_4k_txp_clk_src", + .dsc_txp_clk_name = "dsc_4k_txp_clk", + .dsc_pxl_clk_name = "dsc_4k_pxl_clk", + .dsc_cds_clk_name = "dsc_4k_cds_clk", + }, +}; + +STATIC VOP2_DATA mVop2RK3588 = { + .Version = VOP_VERSION_RK3588, + .NrVps = 4, + .VpData = mVpDataRK3588, + .WinData = mWinDataRK3588, + .DscData = mDscDataRK3588, +/* + .plane_table = rk3588_plane_table, +*/ + .PlaneMask = mVpPlaneMaskRK3588[0], + .NrLayers = 8, + .NrMixers = 7, + .NrGammas = 4, + .NrDscs = 2, +}; + +STATIC UINT8 RK3588Vop2VpPrimaryPlaneOrder[VOP2_VP_MAX] = { + ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_ESMART3, +}; + +STATIC UINT8 RK3568Vop2VpPrimaryPlaneOrder[VOP2_VP_MAX] = { + ROCKCHIP_VOP2_SMART0, + ROCKCHIP_VOP2_SMART1, + ROCKCHIP_VOP2_ESMART1, +}; + +STATIC UINT32 mRegsBackup[RK3568_MAX_REG] = {0}; + +STATIC CHAR8* mDisplayIfName[] = { + " RGB", + " BT1120", + " BT656", + " LVDS0", + " LVDS1", + " MIPI0", + " MIPI1", + " eDP0", + " eDP1", + " DP0", + " DP1", + " HDMI0", + " HDMI1" +}; + +STATIC VOP2 *RockchipVop2; + +INLINE +UINT32 +LogCalculate ( + IN UINT32 Input + ) +{ + INT32 Count = -1; + + if (Input == 0) + return 0; + + while (Input) { + Input >>= 1; + Count++; + } + + return Count; +} + +INLINE +VOID +Vop2MaskWrite ( + IN UINTN Address, + IN UINT32 Offset, + IN UINT32 Mask, + IN UINT32 Shift, + IN UINT32 Value, + IN BOOLEAN WriteMask + ) +{ + UINT32 CachedVal; + + if (!Mask) + return; + + if (WriteMask) { + Value = ((Value & Mask) << Shift) | (Mask << (Shift + 16)); + } else { + CachedVal = mRegsBackup[Offset >> 2]; + + Value = (CachedVal & ~(Mask << Shift)) | ((Value & Mask) << Shift); + mRegsBackup[Offset >> 2] = Value; + } + + MmioWrite32(Address + Offset, Value); +} + +INLINE +VOID +Vop2Writel ( + IN UINTN Address, + IN UINT32 Offset, + IN UINT32 Value +) +{ + MmioWrite32(Address + Offset, Value); + mRegsBackup[Offset >> 2] = Value; +} + +INLINE +VOID +Vop2GrfWrite ( + IN UINTN Address, + IN UINT32 Offset, + IN UINT32 Mask, + IN UINT32 Shift, + IN UINT32 Value + ) +{ + UINT32 TempVal = 0; + + TempVal = (Value << Shift) | (Mask << (Shift + 16)); + MmioWrite32(Address + Offset, TempVal); +} + +INLINE +UINT32 +Vop2GrfRead ( + IN UINTN Address, + IN UINT32 Offset, + IN UINT32 Mask, + IN UINT32 Shift + ) +{ + return (MmioRead32(Address + Offset) >> Shift) & Mask; +} + +INLINE +UINT32 GenericHWeight32 ( + IN UINT32 W + ) +{ + UINT32 Res = (W & 0x55555555) + ((W >> 1) & 0x55555555); + Res = (Res & 0x33333333) + ((Res >> 2) & 0x33333333); + Res = (Res & 0x0F0F0F0F) + ((Res >> 4) & 0x0F0F0F0F); + Res = (Res & 0x00FF00FF) + ((Res >> 8) & 0x00FF00FF); + return (Res & 0x0000FFFF) + ((Res >> 16) & 0x0000FFFF); +} + +INLINE +INT32 FFS(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) + r += 1; + return r; +} + +STATIC +INT32 +Vop2GetPrimaryPlane ( + OUT VOP2 *Vop2, + IN UINT32 PlaneMask + ) +{ + UINT32 i = 0; + UINT8 *Vop2VpPrimaryPlaneOrder; + UINT8 DefaultPrimaryPlane; + + if (Vop2->Version == VOP_VERSION_RK3588) { + Vop2VpPrimaryPlaneOrder = RK3588Vop2VpPrimaryPlaneOrder; + DefaultPrimaryPlane = ROCKCHIP_VOP2_ESMART0; + } else { + Vop2VpPrimaryPlaneOrder = RK3568Vop2VpPrimaryPlaneOrder; + DefaultPrimaryPlane = ROCKCHIP_VOP2_SMART0; + } + + for (i = 0; i < Vop2->Data->NrVps; i++) { + if (PlaneMask & BIT(Vop2VpPrimaryPlaneOrder[i])) + return Vop2VpPrimaryPlaneOrder[i]; + } + + return DefaultPrimaryPlane; +} + +STATIC +CHAR8 * +GetPlaneName ( + IN UINT32 PlaneID + ) +{ + CHAR8 *Name = NULL; + + switch (PlaneID) { + case ROCKCHIP_VOP2_CLUSTER0: + Name = "Cluster0"; + break; + case ROCKCHIP_VOP2_CLUSTER1: + Name = "Cluster1"; + break; + case ROCKCHIP_VOP2_ESMART0: + Name = "Esmart0"; + break; + case ROCKCHIP_VOP2_ESMART1: + Name = "Esmart1"; + break; + case ROCKCHIP_VOP2_SMART0: + Name = "Smart0"; + break; + case ROCKCHIP_VOP2_SMART1: + Name = "Smart1"; + break; + case ROCKCHIP_VOP2_CLUSTER2: + Name = "Cluster2"; + break; + case ROCKCHIP_VOP2_CLUSTER3: + Name = "Cluster3"; + break; + case ROCKCHIP_VOP2_ESMART2: + Name = "Esmart2"; + break; + case ROCKCHIP_VOP2_ESMART3: + Name = "Esmart3"; + break; + } + + return Name; +} + +VOID +Vop2DumpRegisters ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2_WIN_DATA *WinData + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 WinOffset = 0; + UINT8 PrimaryPlaneID = 0; + INT32 i = 0; + UINT32 Reg = 0; + + /* sys registers */ + Reg = RK3588_VOP2_REG_BASE; + DEBUG ((DEBUG_WARN, "SYS:")); + for (i = 0; i < 0x100; i += 4) { + if (i % 0x10 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "\n")); + + /* ovl registers */ + Reg = RK3588_VOP2_REG_BASE + RK3568_OVL_CTRL; + DEBUG ((DEBUG_WARN, "OVL:")); + for (i = 0; i < 0x100; i += 4) { + if (i % 0x10 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "\n")); + + /* hdr registers */ + Reg = RK3588_VOP2_REG_BASE + 0x2000; + DEBUG ((DEBUG_WARN, "HDR:")); + for (i = 0; i < 0x40; i += 4) { + if (i % 0x10 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "\n")); + + /* vp registers */ + Reg = RK3588_VOP2_REG_BASE + RK3568_VP0_DSP_CTRL + VPOffset; + DEBUG ((DEBUG_WARN, "VP%d:", CrtcState->CrtcID)); + for (i = 0; i < 0x100; i += 4) { + if (i % 0x10 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "\n")); + + /* plane registers */ + if (WinData) { + WinOffset = WinData->RegOffset; + if (WinData->Type == CLUSTER_LAYER) + Reg = RK3588_VOP2_REG_BASE + RK3568_CLUSTER0_WIN0_CTRL0 + WinOffset; + else + Reg = RK3588_VOP2_REG_BASE + RK3568_ESMART0_CTRL0 + WinOffset; + PrimaryPlaneID = Vop2->VpPlaneMask[CrtcState->CrtcID].PrimaryPlaneId; + + DEBUG ((DEBUG_WARN, "%a:", GetPlaneName(PrimaryPlaneID))); + for (i = 0; i < 0x100; i += 4) { + if (i % 0x10 == 0) { + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "%x:", Reg + i)); + } + + DEBUG ((DEBUG_WARN, " %08x", MmioRead32(Reg + i))); + } + DEBUG ((DEBUG_WARN, "\n")); + DEBUG ((DEBUG_WARN, "\n")); + } +} + +STATIC +VOP2_WIN_DATA * +Vop2FindWinByPhysID ( + OUT VOP2 *Vop2, + IN INT32 PhysID + ) +{ + INT32 i = 0; + for (i = 0; i < Vop2->Data->NrLayers; i++) { + if (Vop2->Data->WinData[i].PhysID == PhysID) + return &Vop2->Data->WinData[i]; + } + + return NULL; +} + +INLINE +BOOLEAN +IsHotPlugDevices ( + IN INT32 OutputType + ) +{ + switch (OutputType) { + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + case DRM_MODE_CONNECTOR_TV: + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_Unknown: + return TRUE; + default: + return FALSE; + } +} + +STATIC +VOID +Vop2GlobalInitial ( + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + ROCKCHIP_CRTC_PROTOCOL *Crtc = (ROCKCHIP_CRTC_PROTOCOL*)CrtcState->Crtc; + VOP2_WIN_DATA *WinData; + VOP2_VP_PLANE_MASK *PlaneMask; + UINT32 BakIndex; + UINT32 i = 0, j = 0; + UINT32 LayerNr = 0; + UINT8 Shift = 0, TotalUsedLayer = 0; + INT32 PortMux = 0; + INT32 LayerPhyID = 0; + + if (Vop2->GlobalInit) + return; + + /* open the vop global pd */ + MmioWrite32 (0xfd8d8150, 0xffff0000); + MicroSecondDelay (10); + + if (DisplayState->VpsConfigModeID < 0 || DisplayState->VpsConfigModeID >= mVpsConfigsSize) { + INT32 MainVpIndex = -1; + INT32 ActiveVpNum = 0; + + for (i = 0; i < Vop2->Data->NrVps; i++) { + if (Crtc->Vps[i].Enable) + ActiveVpNum++; + } + + PlaneMask = Vop2->Data->PlaneMask; + PlaneMask += (ActiveVpNum - 1) * VOP2_VP_MAX; + + /* find the first unplug devices and set it as main display */ + for (i = 0; i < Vop2->Data->NrVps; i++) { + if (!IsHotPlugDevices (Crtc->Vps[i].OutputType)) { + Vop2->VpPlaneMask[i] = PlaneMask[0]; + MainVpIndex = i; + break; + } + } + + /* if no find unplug devices, use vp0 as main display */ + if (MainVpIndex < 0) { + ActiveVpNum = 0; + Vop2->VpPlaneMask[0] = PlaneMask[0]; + } + + /* plane_mask[0] store main display, so we from plane_mask[1] */ + j = 1; + + /* init other display except main display */ + for (i = 0; i < Vop2->Data->NrVps; i++) { + if (i == MainVpIndex || !Crtc->Vps[i].Enable) { + continue; + } + Vop2->VpPlaneMask[i] = PlaneMask[j++]; + } + + for (i = 0; i < Vop2->Data->NrVps; i++) { + LayerNr = Vop2->VpPlaneMask[i].AttachedLayersNr; + for (j = 0; j < LayerNr; j++) { + LayerPhyID = Vop2->VpPlaneMask[i].AttachedLayers[j]; + Vop2->VpPlaneMask[i].PlaneMask |= BIT(LayerPhyID); + } + } + } else { + UINT32 PlaneMask; + UINT32 PrimaryPlaneID; + + for (i = 0; i < Vop2->Data->NrVps; i++) { + PlaneMask = mVpsConfigs[DisplayState->VpsConfigModeID][i].PlaneMask; + Vop2->VpPlaneMask[i].PlaneMask = PlaneMask; + LayerNr = GenericHWeight32 (PlaneMask); + Vop2->VpPlaneMask[i].AttachedLayersNr = LayerNr; + PrimaryPlaneID = Vop2GetPrimaryPlane (Vop2, PlaneMask); + Vop2->VpPlaneMask[i].PrimaryPlaneId = PrimaryPlaneID; + Vop2->VpPlaneMask[i].PlaneMask = PlaneMask; + for (j = 0; j < LayerNr; j++) { + Vop2->VpPlaneMask[i].AttachedLayers[j] = FFS (PlaneMask) - 1; + PlaneMask &= ~BIT(Vop2->VpPlaneMask[i].AttachedLayers[j]); + } + } + } + + /* open the vop plane pd(esmart) */ + /* status checkout --- todo */ + MmioWrite32 (0xfdd90034, 0x00000000); + MicroSecondDelay (10); + + /* vop2 regs backup */ + for (BakIndex = 0; BakIndex < (RK3568_MAX_REG >> 2); BakIndex++) { + mRegsBackup[BakIndex] = MmioRead32(Vop2->BaseAddress + 4 * BakIndex); + } + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_OVL_CTRL, EN_MASK, + OVL_PORT_MUX_REG_DONE_IMD_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_POL, EN_MASK, + IF_CTRL_REG_DONE_IMD_SHIFT, 1, FALSE); + + for (i = 0; i < Vop2->Data->NrVps; i++) { + DEBUG ((DEBUG_INIT, "vp%d have layer nr:%d[", i, Vop2->VpPlaneMask[i].AttachedLayersNr)); + for (j = 0; j < Vop2->VpPlaneMask[i].AttachedLayersNr; j++) + DEBUG ((DEBUG_INIT, "%d ", Vop2->VpPlaneMask[i].AttachedLayers[j])); + DEBUG ((DEBUG_INIT, "], primary plane: %d\n", Vop2->VpPlaneMask[i].PrimaryPlaneId)); + } + + Shift = 0; + /* layer sel win id */ + for (i = 0; i < Vop2->Data->NrVps; i++) { + LayerNr = Vop2->VpPlaneMask[i].AttachedLayersNr; + for (j = 0; j < LayerNr; j++) { + LayerPhyID = Vop2->VpPlaneMask[i].AttachedLayers[j]; + WinData = Vop2FindWinByPhysID (Vop2, LayerPhyID); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_OVL_LAYER_SEL, LAYER_SEL_MASK, + Shift, WinData->LayerSelWinID, FALSE); + Shift += 4; + } + } + + /* win sel port */ + for (i = 0; i < Vop2->Data->NrVps; i++) { + LayerNr = Vop2->VpPlaneMask[i].AttachedLayersNr; + for (j = 0; j < LayerNr; j++) { + if (!Vop2->VpPlaneMask[i].AttachedLayers[j]) + continue; + LayerPhyID = Vop2->VpPlaneMask[i].AttachedLayers[j]; + WinData = Vop2FindWinByPhysID (Vop2, LayerPhyID); + Shift = WinData->WinSelPortOffset * 2; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_OVL_PORT_SEL, LAYER_SEL_PORT_MASK, + LAYER_SEL_PORT_SHIFT + Shift, i, FALSE); + } + } + + /* + * port mux config + */ + for (i = 0; i < Vop2->Data->NrVps; i++) { + Shift = i * 4; + if (Vop2->VpPlaneMask[i].AttachedLayersNr) { + TotalUsedLayer += Vop2->VpPlaneMask[i].AttachedLayersNr; + PortMux = TotalUsedLayer - 1; + } else { + PortMux = 8; + } + + if (i == (Vop2->Data->NrVps - 1)) + PortMux = Vop2->Data->NrMixers; + + Crtc->Vps[i].BgOvlDly = (Vop2->Data->NrMixers - PortMux) << 1; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_OVL_PORT_SEL, PORT_MUX_MASK, + PORT_MUX_SHIFT + Shift, PortMux, FALSE); + } + + Vop2->GlobalInit = TRUE; +} + +STATIC +UINT64 +Vop2CalcDclk ( + IN UINT32 ChildClk, + IN UINT32 MaxDclk + ) +{ + if (ChildClk * 4 <= MaxDclk) + return ChildClk * 4; + else if (ChildClk * 2 <= MaxDclk) + return ChildClk * 2; + else if (ChildClk <= MaxDclk) + return ChildClk; + else + return 0; +} + +STATIC +UINT64 +Vop2CalcCruConfig ( + IN DISPLAY_STATE *DisplayState, + OUT UINT32 *DclkCoreDiv, + OUT UINT32 *DclkOutDiv, + OUT UINT32 *IfPixclkDiv, + OUT UINT32 *IfDclkDiv + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *DisplayMode = &ConnectorState->DisplayMode; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + UINT64 VPixclk = DisplayMode->Clock; + UINT64 DclkCoreRate = VPixclk >> 2; + UINT64 DclkRate = VPixclk; + UINT64 IfDclkRate; + UINT64 IfPixclkRate; + UINT64 DclkOutRate; + INT32 OutputType = ConnectorState->Type; + INT32 OutputMode = ConnectorState->OutputMode; + UINT8 K = 1; + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE && + OutputMode == ROCKCHIP_OUT_MODE_YUV420) { + DEBUG ((DEBUG_ERROR, "Dual channel and YUV420 can't work together\n")); + return -RETURN_INVALID_PARAMETER; + } + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE || + OutputMode == ROCKCHIP_OUT_MODE_YUV420) + K = 2; + + if (OutputType == DRM_MODE_CONNECTOR_HDMIA) { + /* + * K = 2: dclk_core = if_pixclk_rate > if_dclk_rate + * K = 1: dclk_core = hdmie_edp_dclk > if_pixclk_rate + */ + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE || + OutputMode == ROCKCHIP_OUT_MODE_YUV420) { + DclkRate = DclkRate >> 1; + K = 2; + } + + IfPixclkRate = (DclkCoreRate << 1) / K; + IfDclkRate = DclkCoreRate / K; + + if (VPixclk > VOP2_MAX_DCLK_RATE) + DclkRate = Vop2CalcDclk (DclkCoreRate, Vop2->Data->VpData->MaxDclk); + + if (!DclkRate) { + DEBUG ((DEBUG_ERROR, "DP IfPixclkRate out of range(MaxDclk: %d KHZ, DclkCore: %lld KHZ)\n", + Vop2->Data->VpData->MaxDclk, IfPixclkRate)); + return -RETURN_INVALID_PARAMETER; + } + *IfPixclkDiv = DclkRate / IfPixclkRate; + *IfDclkDiv = DclkRate / IfDclkRate; + *DclkCoreDiv = DclkRate / DclkCoreRate; + DEBUG ((DEBUG_INFO, "DclkRate:%lu,IfPixclkDiv;%d,IfDclkDiv:%d\n", + DclkRate, *IfPixclkDiv, *IfDclkDiv)); + } else if (OutputType == DRM_MODE_CONNECTOR_eDP) { + /* edp_pixclk = edp_dclk > dclk_core */ + IfPixclkRate = VPixclk / K; + IfDclkRate = VPixclk / K; + DclkRate = IfPixclkRate * K; + *DclkCoreDiv = DclkRate / DclkCoreRate; + *IfPixclkDiv = DclkRate / IfPixclkRate; + *IfDclkDiv = *IfPixclkDiv; + } else if (OutputType == DRM_MODE_CONNECTOR_DisplayPort) { + DclkOutRate = VPixclk >> 2; + DclkOutRate = DclkOutRate / K; + + DclkRate = Vop2CalcDclk(DclkOutRate, + Vop2->Data->VpData->MaxDclk); + if (!DclkRate) { + DEBUG ((DEBUG_ERROR, "DP dclk_core out of range(max_dclk: %d KHZ, dclk_core: %ld KHZ)\n", + Vop2->Data->VpData->MaxDclk, DclkCoreRate)); + return EFI_INVALID_PARAMETER; + } + *DclkOutDiv = DclkRate / DclkOutRate; + *DclkCoreDiv = DclkRate / DclkCoreRate; + } else if (OutputType == DRM_MODE_CONNECTOR_DSI) { + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + K = 2; + if (CrtcState->dsc_enable) + /* dsc output is 96bit, dsi input is 192 bit */ + IfPixclkRate = CrtcState->dsc_cds_clk_rate >> 1; + else + IfPixclkRate = DclkCoreRate / K; + /* dclk_core = dclk_out * K = if_pixclk * K = VPixclk / 4 */ + DclkOutRate = DclkCoreRate / K; + /* DclkRate = N * DclkCoreRate N = (1,2,4 ), we get a little factor here */ + DclkRate = Vop2CalcDclk(DclkOutRate, + Vop2->Data->VpData->MaxDclk); + if (!DclkRate) { + DEBUG ((DEBUG_INFO, "MIPI dclk out of range(max_dclk: %d KHZ, DclkRate: %ld KHZ)\n", + Vop2->Data->VpData->MaxDclk, DclkRate)); + return -EINVAL; + } + + if (CrtcState->dsc_enable) + DclkRate /= CrtcState->dsc_slice_num; + + *DclkOutDiv = DclkRate / DclkOutRate; + *DclkCoreDiv = DclkRate / DclkCoreRate; + *IfPixclkDiv = 1; /*mipi pixclk == dclk_out*/ + if (CrtcState->dsc_enable) + *IfPixclkDiv = DclkOutRate * 1000LL / IfPixclkRate; + } + + *IfPixclkDiv = LogCalculate(*IfPixclkDiv); + *IfDclkDiv = LogCalculate(*IfDclkDiv); + *DclkCoreDiv = LogCalculate(*DclkCoreDiv); + *DclkOutDiv = LogCalculate(*DclkOutDiv); + + DEBUG ((DEBUG_INFO, "[VOP2](CalcCru)DclkRate = %ld(divide: %d)\n", DclkRate, *DclkOutDiv)); + DEBUG ((DEBUG_INFO, " DclkCoreRate = %ld(divide: %d)\n", DclkCoreRate, *DclkCoreDiv)); + DEBUG ((DEBUG_INFO, " IfDclkRate = %ld(divide: %d)\n", IfDclkRate, *IfDclkDiv)); + DEBUG ((DEBUG_INFO, " IfPixclkRate = %ld(divide: %d)\n", IfPixclkRate, *IfPixclkDiv)); + + return DclkRate; +} + +STATIC +EFI_STATUS +Vop2CalcDscClk ( + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *DisplayMode = &ConnectorState->DisplayMode; + UINT64 VPixclk = DisplayMode->CrtcClock * 1000LL; /* video timing pixclk */ + UINT8 K = 1; + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + K = 2; + + CrtcState->dsc_txp_clk_rate = VPixclk; + do_div(CrtcState->dsc_txp_clk_rate, (CrtcState->dsc_pixel_num * K)); + + CrtcState->dsc_pxl_clk_rate = VPixclk; + do_div(CrtcState->dsc_pxl_clk_rate, (CrtcState->dsc_slice_num * K)); + + /* dsc_cds = crtc_clock / (cds_dat_width / bits_per_pixel) + * cds_dat_width = 96; + * bits_per_pixel = [8-12]; + * As cds clk is div from txp clk and only support 1/2/4 div, + * so when txp_clk is equal to VPixclk, we set dsc_cds = crtc_clock / 4, + * otherwise dsc_cds = crtc_clock / 8; + */ + CrtcState->dsc_cds_clk_rate = VPixclk / (CrtcState->dsc_txp_clk_rate == VPixclk ? 4 : 8); + + return 0; +} + +STATIC +UINT32 +Vop2IfConfig ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2 + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *DisplayMode = &ConnectorState->DisplayMode; + struct rockchip_dsc_sink_cap *dsc_sink_cap = &CrtcState->dsc_sink_cap; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 OutputIf = ConnectorState->OutputInterface; + UINT32 DclkCoreDiv = 0; + UINT32 DclkOutDiv = 0; + UINT32 IfPixclkDiv = 0; + UINT32 IfDclkDiv = 0; + UINT32 DclkRate; + UINT32 Val; + + if (OutputIf & (VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1)) { + Val = (DisplayMode->Flags & DRM_MODE_FLAG_NHSYNC) ? BIT(HSYNC_POSITIVE) : 0; + Val |= (DisplayMode->Flags & DRM_MODE_FLAG_NVSYNC) ? BIT(VSYNC_POSITIVE) : 0; + } else { + Val = (DisplayMode->Flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE); + Val |= (DisplayMode->Flags & DRM_MODE_FLAG_NVSYNC) ? 0 : BIT(VSYNC_POSITIVE); + } + + if (CrtcState->dsc_enable) { + UINT32 K = 1; + + if (!Vop2->Data->NrDscs) { + DEBUG ((DEBUG_ERROR, "Unsupported DSC\n")); + return 0; + } + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + K = 2; + + CrtcState->dsc_id = OutputIf & (VOP_OUTPUT_IF_MIPI0 | VOP_OUTPUT_IF_HDMI0) ? 0 : 1; + CrtcState->dsc_slice_num = DisplayMode->CrtcHDisplay / dsc_sink_cap->slice_width / K; + CrtcState->dsc_pixel_num = CrtcState->dsc_slice_num > 4 ? 4 : CrtcState->dsc_slice_num; + + Vop2CalcDscClk(DisplayState); + DEBUG ((DEBUG_INFO, "Enable DSC%d slice:%dx%d, slice num:%d\n", + CrtcState->dsc_id, dsc_sink_cap->slice_width, + dsc_sink_cap->slice_height, CrtcState->dsc_slice_num)); + } + + DclkRate = Vop2CalcCruConfig(DisplayState, &DclkCoreDiv, &DclkOutDiv, &IfPixclkDiv, &IfDclkDiv); + CrtcState->DclkCoreDiv = DclkCoreDiv; + CrtcState->DclkOutDiv = DclkOutDiv; + + if (OutputIf & VOP_OUTPUT_IF_MIPI0) { + if (CrtcState->CrtcID == 2) + Val = 0; + else + Val = 1; + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_MIPI_DS_MODE) + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, EN_MASK, + RK3588_MIPI_DSI0_MODE_SEL_SHIFT, 1, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, RK3588_MIPI0_EN_SHIFT, + 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, 1, RK3588_MIPI0_MUX_SHIFT, Val, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 3, MIPI0_PIXCLK_DIV_SHIFT, + IfPixclkDiv, FALSE); + + if (ConnectorState->hold_mode) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, + EN_MASK, EDPI_TE_EN, TRUE, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, + EN_MASK, EDPI_WMS_HOLD_EN, 1, FALSE); + } + } + + if (OutputIf & VOP_OUTPUT_IF_MIPI1) { + if (CrtcState->CrtcID == 2) + Val = 0; + else if (CrtcState->CrtcID == 3) + Val = 1; + else + Val = 3; /*VP1*/ + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_MIPI_DS_MODE) + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, EN_MASK, + RK3588_MIPI_DSI1_MODE_SEL_SHIFT, 1, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, RK3588_MIPI1_EN_SHIFT, + 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, MIPI1_MUX_SHIFT, + Val, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 3, MIPI1_PIXCLK_DIV_SHIFT, + IfPixclkDiv, FALSE); + + if (ConnectorState->hold_mode) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, + EN_MASK, EDPI_TE_EN, TRUE, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, + EN_MASK, EDPI_WMS_HOLD_EN, 1, FALSE); + } + } + + if (OutputIf & VOP_OUTPUT_IF_eDP0) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_EDP0_EN_SHIFT, 1, FALSE); + /* temp eDP0 fixed vp2 */ + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_HDMI_EDP0_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP0_DCLK_DIV_SHIFT, IfDclkDiv, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP0_PIXCLK_DIV_SHIFT, IfPixclkDiv, FALSE); + Vop2GrfWrite (RK3588_VOP_GRF_BASE, RK3588_GRF_VOP_CON2, EN_MASK, + RK3588_GRF_EDP0_ENABLE_SHIFT, 1); + } + + if (OutputIf & VOP_OUTPUT_IF_eDP1) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_EDP1_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_HDMI_EDP1_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP1_DCLK_DIV_SHIFT, IfDclkDiv, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP1_PIXCLK_DIV_SHIFT, IfPixclkDiv, FALSE); + Vop2GrfWrite (RK3588_VOP_GRF_BASE, RK3588_GRF_VOP_CON2, EN_MASK, + RK3588_GRF_EDP1_ENABLE_SHIFT, 1); + } + + if (OutputIf & VOP_OUTPUT_IF_HDMI0) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_HDMI0_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_HDMI_EDP0_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP0_DCLK_DIV_SHIFT, IfDclkDiv, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP0_PIXCLK_DIV_SHIFT, IfPixclkDiv, FALSE); + Vop2GrfWrite (RK3588_VOP_GRF_BASE, RK3588_GRF_VOP_CON2, EN_MASK, + RK3588_GRF_HDMITX0_ENABLE_SHIFT, 1); + Vop2GrfWrite (RK3588_VO1_GRF_BASE, RK3588_GRF_VO1_CON0, HDMI_SYNC_POL_MASK, + HDMI0_SYNC_POL_SHIFT, Val); + } + + if (OutputIf & VOP_OUTPUT_IF_HDMI1) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_HDMI1_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_HDMI_EDP1_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP1_DCLK_DIV_SHIFT, IfDclkDiv, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_CTRL, 0x3, + HDMI_EDP1_PIXCLK_DIV_SHIFT, IfPixclkDiv, FALSE); + Vop2GrfWrite (RK3588_VOP_GRF_BASE, RK3588_GRF_VOP_CON2, EN_MASK, + RK3588_GRF_HDMITX1_ENABLE_SHIFT, 1); + Vop2GrfWrite (RK3588_VO1_GRF_BASE, RK3588_GRF_VO1_CON0, HDMI_SYNC_POL_MASK, + HDMI1_SYNC_POL_SHIFT, Val); + } + + if (OutputIf & VOP_OUTPUT_IF_DP0) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_DP0_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_DP0_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_POL, RK3588_IF_PIN_POL_MASK, + RK3588_DP0_PIN_POL_SHIFT, Val, FALSE); + } + + if (OutputIf & VOP_OUTPUT_IF_DP1) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, EN_MASK, + RK3588_DP1_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_EN, IF_MUX_MASK, + RK3588_DP1_MUX_SHIFT, CrtcState->CrtcID, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_DSP_IF_POL, RK3588_IF_PIN_POL_MASK, + RK3588_DP1_PIN_POL_SHIFT, Val, FALSE); + } + + Vop2MaskWrite (Vop2->BaseAddress, RK3588_VP0_CLK_CTRL + VPOffset, 0x3, + DCLK_CORE_DIV_SHIFT, DclkCoreDiv, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_VP0_CLK_CTRL + VPOffset, 0x3, + DCLK_OUT_DIV_SHIFT, DclkOutDiv, FALSE); + + return DclkRate; +} + +STATIC +BOOLEAN +IsUVSwap ( + IN UINT32 BusFormat, + IN UINT32 OutputMode + ) +{ + /* + * FIXME: + * + * There is no media type for YUV444 output, + * so when out_mode is AAAA or P888, assume output is YUV444 on + * yuv format. + * + * From H/W testing, YUV444 mode need a rb swap. + */ + if ((BusFormat == MEDIA_BUS_FMT_YUV8_1X24 || + BusFormat == MEDIA_BUS_FMT_YUV10_1X30) && + (OutputMode == ROCKCHIP_OUT_MODE_AAAA || + OutputMode == ROCKCHIP_OUT_MODE_P888)) + return TRUE; + else + return FALSE; +} + +STATIC +BOOLEAN +IsYUVOutput ( + IN UINT32 BusFormat + ) +{ + switch (BusFormat) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YVYU8_1X16: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_VYUY8_1X16: + return TRUE; + default: + return FALSE; +} +} + +INLINE +UINT32 +Vop2ConvertCSCMode ( + IN UINT32 CSCMode + ) +{ + switch (CSCMode) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return CSC_BT601L; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SMPTE240M: + case V4L2_COLORSPACE_DEFAULT: + return CSC_BT709L; + case V4L2_COLORSPACE_JPEG: + return CSC_BT601F; + case V4L2_COLORSPACE_BT2020: + return CSC_BT2020; + default: + return CSC_BT709L; + } +} + +INLINE +INT32 +Interpolate ( + IN INT32 X1, + IN INT32 Y1, + IN INT32 X2, + IN INT32 Y2, + IN INT32 X + ) +{ + return Y1 + (Y2 - Y1) * (X - X1) / (X2 - X1); +} + +INLINE +INT32 +__Fixp_Sin32 ( + IN UINT32 Degrees + ) +{ + INT32 Ret; + BOOLEAN Negative = FALSE; + + if (Degrees > 180) { + Negative = TRUE; + Degrees -= 180; + } + if (Degrees > 90) + Degrees = 180 - Degrees; + + Ret = mSinTable[Degrees]; + + return Negative ? -Ret : Ret; +} + +INLINE +INT32 +FixpSin32 ( + IN UINT32 Degrees + ) +{ + Degrees = (Degrees % 360 + 360) % 360; + + return __Fixp_Sin32(Degrees); +} +#define FixpCos32(v) FixpSin32((v) + 90) +#define FixpSin16(v) (FixpSin32(v) >> 16) +#define FixpCos16(v) (FixpCos32(v) >> 16) + +STATIC +VOID +Vop2TVConfigUpdate ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2 + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + BASE_BCSH_INFO *BCSHInfo; + UINT32 Brightness, Contrast, Saturation, Hue, SinHue, CosHue; + BOOLEAN BCSHEnable = FALSE; + BOOLEAN R2YEnable = FALSE; + BOOLEAN Y2REnable = FALSE; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 PostCSCMode; + + /* base2_disp_info --- todo */ + if (!ConnectorState->DispInfo) + return; + + BCSHInfo = &ConnectorState->DispInfo->BCSHInfo; + if (!BCSHInfo) + return; + + if (BCSHInfo->Brightness != 50 || + BCSHInfo->Contrast != 50 || + BCSHInfo->Saturation != 50 || + BCSHInfo->Hue != 50) + BCSHEnable = TRUE; + + if (BCSHEnable) { + if (!CrtcState->YUVOverlay) + R2YEnable = TRUE; + if (!IsYUVOutput(ConnectorState->BusFormat)) + Y2REnable = TRUE; + } else { + if (!CrtcState->YUVOverlay && IsYUVOutput(ConnectorState->BusFormat)) + R2YEnable = TRUE; + if (CrtcState->YUVOverlay && !IsYUVOutput(ConnectorState->BusFormat)) + Y2REnable = TRUE; + } + + PostCSCMode = Vop2ConvertCSCMode(ConnectorState->ColorSpace); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_CTRL + VPOffset, BCSH_CTRL_R2Y_MASK, + BCSH_CTRL_R2Y_SHIFT, R2YEnable, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_CTRL + VPOffset, BCSH_CTRL_Y2R_MASK, + BCSH_CTRL_Y2R_SHIFT, Y2REnable, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_CTRL + VPOffset, BCSH_CTRL_R2Y_CSC_MODE_MASK, + BCSH_CTRL_R2Y_CSC_MODE_SHIFT, PostCSCMode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_CTRL + VPOffset, BCSH_CTRL_Y2R_CSC_MODE_MASK, + BCSH_CTRL_Y2R_CSC_MODE_SHIFT, PostCSCMode, FALSE); + if (!BCSHEnable) { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_COLOR + VPOffset, BCSH_EN_MASK, + BCSH_EN_SHIFT, 0, FALSE); + return; + } + + if (CrtcState->Feature & VOP_FEATURE_OUTPUT_10BIT) + Brightness = Interpolate(0, -128, 100, 127, BCSHInfo->Brightness); + else + Brightness = Interpolate(0, -32, 100, 31, BCSHInfo->Brightness); + Contrast = Interpolate(0, 0, 100, 511, BCSHInfo->Contrast); + Saturation = Interpolate(0, 0, 100, 511, BCSHInfo->Saturation); + Hue = Interpolate(0, -30, 100, 30, BCSHInfo->Hue); + + /* + * a:[-30~0): + * sin_hue = 0x100 - sin(a)*256; + * cos_hue = cos(a)*256; + * a:[0~30] + * sin_hue = sin(a)*256; + * cos_hue = cos(a)*256; + */ + SinHue = FixpSin32(Hue) >> 23; + CosHue = FixpCos32(Hue) >> 23; + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_BCS + VPOffset, BCSH_BRIGHTNESS_MASK, + BCSH_BRIGHTNESS_SHIFT, Brightness, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_BCS + VPOffset, BCSH_CONTRAST_MASK, + BCSH_CONTRAST_SHIFT, Contrast, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_BCS + VPOffset, BCSH_SATURATION_MASK, + BCSH_SATURATION_SHIFT, Saturation, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_H + VPOffset, BCSH_SIN_HUE_MASK, + BCSH_SIN_HUE_SHIFT, SinHue, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_H + VPOffset, BCSH_COS_HUE_MASK, + BCSH_COS_HUE_SHIFT, CosHue, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_BCS + VPOffset, BCSH_OUT_MODE_MASK, + BCSH_OUT_MODE_SHIFT, BCSH_OUT_MODE_NORMAL_VIDEO, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BCSH_COLOR + VPOffset, BCSH_EN_MASK, + BCSH_EN_SHIFT, 1, FALSE); +} + +INLINE +UINT16 SclCalScale2 ( + IN INT32 Src, + IN INT32 Dst + ) +{ + return ((Src - 1) << 12) / (Dst - 1); +} + +STATIC +VOID +Vop2PostConfig ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2 + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + ROCKCHIP_CRTC_PROTOCOL *Crtc = (ROCKCHIP_CRTC_PROTOCOL *)CrtcState->Crtc; + DRM_DISPLAY_MODE *Mode = &ConnectorState->DisplayMode; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT16 HDisplay = Mode->CrtcHDisplay; + UINT16 HActStart = Mode->CrtcHTotal - Mode->CrtcHSyncStart; + UINT16 VDisplay = Mode->CrtcVDisplay; + UINT16 VTotal = Mode->CrtcVTotal; + UINT16 VActStart = Mode->CrtcVTotal - Mode->CrtcVSyncStart; + UINT16 HSize = HDisplay * (ConnectorState->OverScan.LeftMargin + + ConnectorState->OverScan.RightMargin) /200; + UINT16 VSize = VDisplay * (ConnectorState->OverScan.TopMargin + + ConnectorState->OverScan.BottomMargin) /200; + UINT16 HActEnd, VActEnd; + UINT32 Val; + + UINT32 BgOvlDly, BgDly, PreScanDly; + UINT16 HSyncLen = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart; + + HSize = ROUNDDOWN (HSize, 2); + VSize = ROUNDDOWN (VSize, 2); + + HActStart += HDisplay * (100 - ConnectorState->OverScan.LeftMargin) / 200; + HActEnd = HActStart + HSize; + Val = HActStart << 16; + Val |= HActEnd; + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_POST_DSP_HACT_INFO + VPOffset, Val); + + VActStart += VDisplay * (100 - ConnectorState->OverScan.TopMargin) / 200; + VActEnd = VActStart + VSize; + Val = VActStart << 16; + Val |= VActEnd; + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_POST_DSP_VACT_INFO + VPOffset, Val); + + Val = SclCalScale2 (VDisplay, VSize) << 16; + Val |= SclCalScale2 (VDisplay, VSize); + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_POST_SCL_FACTOR_YRGB + VPOffset, Val); + +#define POST_HORIZONTAL_SCALEDOWN_EN(x) ((x) << 0) +#define POST_VERTICAL_SCALEDOWN_EN(x) ((x) << 1) + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_POST_SCL_CTRL + VPOffset, + POST_HORIZONTAL_SCALEDOWN_EN(HDisplay != HSize) | + POST_VERTICAL_SCALEDOWN_EN(VDisplay != VSize)); + + if (Mode->Flags & DRM_MODE_FLAG_INTERLACE) { + UINT16 VActStartF1 = VTotal + VActStart + 1; + UINT16 VActEndF1 = VActStartF1 + VDisplay; + + Val = VActStartF1 << 16 | VActEndF1; + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_POST_DSP_VACT_INFO_F1 + VPOffset, Val); + } + + BgOvlDly = Crtc->Vps[CrtcState->CrtcID].BgOvlDly; + BgDly = Vop2->Data->VpData[CrtcState->CrtcID].PreScanMaxDly; + BgDly -= BgOvlDly; + PreScanDly = BgDly + (HDisplay >> 1) - 1; + if (Vop2->Version == VOP_VERSION_RK3588 && HSyncLen < 8) + HSyncLen = 8; + PreScanDly = (PreScanDly << 16) | HSyncLen; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_BG_MIX_CTRL + CrtcState->CrtcID * 4, BG_MIX_CTRL_MASK, + BG_MIX_CTRL_SHIFT, BgDly, FALSE); + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_PRE_SCAN_HTIMING + VPOffset, PreScanDly); + + MmioWrite32 (0xfdd906e8, 0x34000000); +} + +STATIC +INT32 +Vop2WaitPowerDomainOn ( + OUT VOP2 *Vop2, + OUT VOP2_POWER_DOMAIN_DATA *PdData + ) +{ + UINT32 Val = 0; + BOOLEAN IsBisrEn = FALSE; + + IsBisrEn = Vop2GrfRead (Vop2->SysPmu, RK3588_PMU_BISR_CON3, EN_MASK, PdData->BisrEnStatusShift); + if (IsBisrEn) { + return readl_poll_timeout(Vop2->SysPmu + RK3588_PMU_BISR_STATUS5, Val, + ((Val >> PdData->PmuStatusShift) & 0x1), 50 * 1000); + } else { + return readl_poll_timeout(Vop2->BaseAddress + RK3568_SYS_STATUS0, Val, + !((Val >> PdData->PdStatusShift) & 0x1), 50 * 1000); + } +} + +STATIC +EFI_STATUS +Vop2PowerDomainOn ( + OUT VOP2 *Vop2, + OUT VOP2_POWER_DOMAIN_DATA *PdData + ) +{ + INT32 Ret = 0; + + if (!PdData) + return 0; + + if (PdData->ParentPdData) { + Ret = Vop2PowerDomainOn (Vop2, PdData->ParentPdData); + if (Ret) { + DEBUG ((DEBUG_ERROR, "can't open parent power domain\n")); + return EFI_INVALID_PARAMETER; + } + } + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_SYS_PD_CTRL, EN_MASK, + PdData->PdEnShift, 0, FALSE); + Ret = Vop2WaitPowerDomainOn(Vop2, PdData); + if (Ret) { + DEBUG ((DEBUG_ERROR, "wait vop2 power domain timeout\n")); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +Vop2SetClk ( + IN UINT32 CrtcId, + IN UINT64 Rate +) +{ + /* only support VP2 for now */ + ASSERT (CrtcId == 2); + + /* CRU_MODE_CON00: set clock modes */ + MmioWrite32(CRU_BASE + 0x0280, 0xFFFF0155); + + HAL_CRU_ClkSetFreq (DCLK_VOP2_SRC, Rate); + + DEBUG ((DEBUG_INFO, "%a: V0PLL=%lu, DCLK_VOP2_SRC=%lu\n", + __func__, HAL_CRU_ClkGetFreq (PLL_V0PLL), HAL_CRU_ClkGetFreq (DCLK_VOP2_SRC))); + + return EFI_SUCCESS; +} + +STATIC +CHAR8 * +GetOutputIfName ( + IN UINT32 OutputIf + ) +{ + INT32 i = 0; + INT32 Shift = 0; + + for (i = 0; i < VOP_OUTPUT_IF_NUMS; i++) { + Shift = 1 << i; + if (OutputIf & Shift) { + return mDisplayIfName[i]; + } + } + + return mDisplayIfName[0]; +} + +EFI_STATUS +Vop2PreInit ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + + if (!RockchipVop2) { + RockchipVop2 = AllocatePool (sizeof(*RockchipVop2)); + RockchipVop2->BaseAddress = RK3588_VOP2_REG_BASE; + RockchipVop2->SysPmu = SYS_PMU_BASE; + RockchipVop2->Version = mVop2RK3588.Version; + RockchipVop2->Data = &mVop2RK3588; + RockchipVop2->GlobalInit = FALSE; + ZeroMem (RockchipVop2->VpPlaneMask, sizeof(VOP2_VP_PLANE_MASK) * VOP2_VP_MAX); + } + + CrtcState->Private = RockchipVop2; + CrtcState->MaxOutput = RockchipVop2->Data->VpData[CrtcState->CrtcID].MaxOutput; + CrtcState->Feature = RockchipVop2->Data->VpData[CrtcState->CrtcID].Feature; + + /* fix the plane mask about */ + Vop2GlobalInitial (DisplayState); + + return EFI_SUCCESS; +} + +#define OUTPUT_IF_IS_HDMI(x) ((x) & (VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1)) +#define OUTPUT_IF_IS_DP(x) ((x) & (VOP_OUTPUT_IF_DP0 | VOP_OUTPUT_IF_DP1)) + +STATIC +VOID +Vop2PostColorSwap ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2 + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 OutputIf = ConnectorState->OutputInterface; + UINT32 DateSwap = 0; + + if (IsUVSwap(ConnectorState->BusFormat, ConnectorState->OutputMode)) + DateSwap = DSP_RB_SWAP; + + if (Vop2->Version == VOP_VERSION_RK3588 && + (OUTPUT_IF_IS_HDMI(OutputIf) || OUTPUT_IF_IS_DP(OutputIf)) && + (ConnectorState->BusFormat == MEDIA_BUS_FMT_YUV8_1X24 || + ConnectorState->BusFormat == MEDIA_BUS_FMT_YUV10_1X30)) + DateSwap |= DSP_RG_SWAP; + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, DATA_SWAP_MASK, + DATA_SWAP_SHIFT, DateSwap, FALSE); +} + +STATIC +VOID +Vop2CalcDscCruCfg ( + OUT DISPLAY_STATE *DisplayState, + OUT UINT32 *dsc_txp_clk_div, + OUT UINT32 *dsc_pxl_clk_div, + OUT UINT32 *dsc_cds_clk_div, + IN UINT64 dclk_rate + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + + *dsc_txp_clk_div = dclk_rate / CrtcState->dsc_txp_clk_rate; + *dsc_pxl_clk_div = dclk_rate / CrtcState->dsc_pxl_clk_rate; + *dsc_cds_clk_div = dclk_rate / CrtcState->dsc_cds_clk_rate; + + *dsc_txp_clk_div = LogCalculate(*dsc_txp_clk_div); + *dsc_pxl_clk_div = LogCalculate(*dsc_pxl_clk_div); + *dsc_cds_clk_div = LogCalculate(*dsc_cds_clk_div); +} + +STATIC +VOID +Vop2LoadPps ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2, + IN UINT8 dsc_id + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + struct drm_dsc_picture_parameter_set *pps = &CrtcState->pps; + struct drm_dsc_picture_parameter_set config_pps; + const VOP2_DSC_DATA *dsc_data = &Vop2->Data->DscData[dsc_id]; + UINT32 *pps_val = (UINT32 *)&config_pps; + UINT32 decoder_regs_offset = (dsc_id * 0x100); + UINT32 i = 0; + + memcpy(&config_pps, pps, sizeof(config_pps)); + + if ((config_pps.pps_3 & 0xf) > dsc_data->max_linebuf_depth) { + config_pps.pps_3 &= 0xf0; + config_pps.pps_3 |= dsc_data->max_linebuf_depth; + DEBUG((DEBUG_INFO, "DSC%d max_linebuf_depth is: %d, current set value is: %d\n", + dsc_id, dsc_data->max_linebuf_depth, config_pps.pps_3 & 0xf)); + } + + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + config_pps.rc_range_parameters[i] = + (pps->rc_range_parameters[i] >> 3 & 0x1f) | + ((pps->rc_range_parameters[i] >> 14 & 0x3) << 5) | + ((pps->rc_range_parameters[i] >> 0 & 0x7) << 7) | + ((pps->rc_range_parameters[i] >> 8 & 0x3f) << 10); + } + + for (i = 0; i < ROCKCHIP_DSC_PPS_SIZE_BYTE / 4; i++) + Vop2Writel (Vop2->BaseAddress, RK3588_DSC_8K_PPS0_3 + decoder_regs_offset + i * 4, *pps_val++); +} + +STATIC +VOID +Vop2DscEnable ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2 *Vop2, + IN UINT8 dsc_id, + IN UINT64 dclk_rate + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *Mode = &ConnectorState->DisplayMode; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + struct rockchip_dsc_sink_cap *dsc_sink_cap = &CrtcState->dsc_sink_cap; + const VOP2_DSC_DATA *dsc_data = &Vop2->Data->DscData[dsc_id]; + BOOLEAN mipi_ds_mode = FALSE; + UINT8 dsc_interface_mode = 0; + UINT16 hsync_len = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart; + UINT16 hdisplay = Mode->CrtcHDisplay; + UINT16 htotal = Mode->CrtcHTotal; + UINT16 hact_st = Mode->CrtcHTotal - Mode->CrtcHSyncStart; + UINT16 vdisplay = Mode->CrtcVDisplay; + UINT16 vtotal = Mode->CrtcVTotal; + UINT16 vsync_len = Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart; + UINT16 vact_st = Mode->CrtcVTotal - Mode->CrtcVSyncStart; + UINT16 vact_end = vact_st + vdisplay; + UINT32 ctrl_regs_offset = (dsc_id * 0x30); + UINT32 decoder_regs_offset = (dsc_id * 0x100); + UINT32 dsc_txp_clk_div = 0; + UINT32 dsc_pxl_clk_div = 0; + UINT32 dsc_cds_clk_div = 0; + UINT32 val = 0; + + if (!Vop2->Data->NrDscs) { + DEBUG ((DEBUG_ERROR, "Unsupported DSC\n")); + return; + } + + if (CrtcState->dsc_slice_num > dsc_data->max_slice_num) + DEBUG ((DEBUG_INFO, "DSC%d supported max slice is: %d, current is: %d\n", + dsc_data->id, dsc_data->max_slice_num, CrtcState->dsc_slice_num)); + + if (dsc_data->PdData) { + if (Vop2PowerDomainOn (Vop2, dsc_data->PdData)) + DEBUG ((DEBUG_ERROR, "open dsc%d pd fail\n", dsc_id)); + } + + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_INIT_DLY + ctrl_regs_offset, EN_MASK, + SCAN_TIMING_PARA_IMD_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_PORT_SEL_MASK, + DSC_PORT_SEL_SHIFT, CrtcState->CrtcID, FALSE); + if (ConnectorState->OutputInterface & (VOP_OUTPUT_IF_HDMI0 | VOP_OUTPUT_IF_HDMI1)) { + dsc_interface_mode = VOP_DSC_IF_HDMI; + } else { + mipi_ds_mode = !!(ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_MIPI_DS_MODE); + if (mipi_ds_mode) + dsc_interface_mode = VOP_DSC_IF_MIPI_DS_MODE; + else + dsc_interface_mode = VOP_DSC_IF_MIPI_VIDEO_MODE; + } + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_MAN_MODE_MASK, + DSC_MAN_MODE_SHIFT, 0, FALSE); + else + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_MAN_MODE_MASK, + DSC_MAN_MODE_SHIFT, 1, FALSE); + + Vop2CalcDscCruCfg(DisplayState, &dsc_txp_clk_div, &dsc_pxl_clk_div, &dsc_cds_clk_div, dclk_rate); + + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_INTERFACE_MODE_MASK, + DSC_INTERFACE_MODE_SHIFT, dsc_interface_mode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_PIXEL_NUM_MASK, + DSC_PIXEL_NUM_SHIFT, CrtcState->dsc_pixel_num >> 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_TXP_CLK_DIV_MASK, + DSC_TXP_CLK_DIV_SHIFT, dsc_txp_clk_div, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_PXL_CLK_DIV_MASK, + DSC_PXL_CLK_DIV_SHIFT, dsc_pxl_clk_div, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_CDS_CLK_DIV_MASK, + DSC_CDS_CLK_DIV_SHIFT, dsc_cds_clk_div, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, EN_MASK, + DSC_SCAN_EN_SHIFT, !mipi_ds_mode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_SYS_CTRL + ctrl_regs_offset, DSC_CDS_CLK_DIV_MASK, + DSC_HALT_EN_SHIFT, mipi_ds_mode, FALSE); + + if (!mipi_ds_mode) { + UINT16 dsc_hsync, dsc_htotal, dsc_hact_st, dsc_hact_end; + UINT32 target_bpp = dsc_sink_cap->target_bits_per_pixel_x16; + UINT64 dsc_cds_rate = CrtcState->dsc_cds_clk_rate; + UINT32 v_pixclk_mhz = Mode->CrtcClock / 1000; /* video timing pixclk */ + UINT32 dly_num, dsc_cds_rate_mhz, val = 0; + UINT32 k = 1; + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) + k = 2; + + if (target_bpp >> 4 < dsc_data->min_bits_per_pixel) + DEBUG ((DEBUG_WARN, "Unsupported bpp less than: %d\n", dsc_data->min_bits_per_pixel)); + + /* + * dly_num = delay_line_num * T(one-line) / T (dsc_cds) + * T (one-line) = 1/v_pixclk_mhz * htotal = htotal/v_pixclk_mhz + * T (dsc_cds) = 1 / dsc_cds_rate_mhz + * + * HDMI: + * delay_line_num: according the pps initial_xmit_delay to adjust vop dsc delay + * delay_line_num = 4 - BPP / 8 + * = (64 - target_bpp / 8) / 16 + * dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * (64 - target_bpp / 8) / 16; + * + * MIPI DSI[4320 and 9216 is buffer size for DSC]: + * DSC0:delay_line_num = 4320 * 8 / slince_num / chunk_size; + * delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + * DSC1:delay_line_num = 9216 * 2 / slince_num / chunk_size; + * delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + * dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * delay_line_num + */ + do_div(dsc_cds_rate, 1000000); /* hz to Mhz */ + dsc_cds_rate_mhz = dsc_cds_rate; + dsc_hsync = hsync_len / 2; + if (dsc_interface_mode == VOP_DSC_IF_HDMI) { + dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * (64 - target_bpp / 8) / 16; + } else { + UINT32 dsc_buf_size = dsc_id == 0 ? 4320 * 8 : 9216 * 2; + UINT32 delay_line_num = dsc_buf_size / CrtcState->dsc_slice_num / + be16_to_cpu(CrtcState->pps.chunk_size); + + delay_line_num = delay_line_num > 5 ? 5 : delay_line_num; + dly_num = htotal * dsc_cds_rate_mhz / v_pixclk_mhz * delay_line_num; + + /* The dsc mipi video mode dsc_hsync minimum size is 8 pixels */ + if (dsc_hsync < 8) + dsc_hsync = 8; + } + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_INIT_DLY + ctrl_regs_offset, DSC_INIT_DLY_MODE_MASK, + DSC_INIT_DLY_MODE_SHIFT, 0, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_INIT_DLY + ctrl_regs_offset, DSC_INIT_DLY_NUM_MASK, + DSC_INIT_DLY_NUM_SHIFT, dly_num, FALSE); + + /* + * htotal / dclk_core = dsc_htotal /cds_clk + * + * dclk_core = DCLK / (1 << dclk_core->div_val) + * cds_clk = txp_clk / (1 << dsc_cds_clk->div_val) + * txp_clk = DCLK / (1 << dsc_txp_clk->div_val) + * + * dsc_htotal = htotal * (1 << dclk_core->div_val) / + * ((1 << dsc_txp_clk->div_val) * (1 << dsc_cds_clk->div_val)) + */ + dsc_htotal = htotal * (1 << CrtcState->DclkCoreDiv) / + ((1 << dsc_txp_clk_div) * (1 << dsc_cds_clk_div)); + val = dsc_htotal << 16 | dsc_hsync; + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_HTOTAL_HS_END + ctrl_regs_offset, DSC_HTOTAL_PW_MASK, + DSC_HTOTAL_PW_SHIFT, val, FALSE); + + dsc_hact_st = hact_st / 2; + dsc_hact_end = (hdisplay / k * target_bpp >> 4) / 24 + dsc_hact_st; + val = dsc_hact_end << 16 | dsc_hact_st; + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_HACT_ST_END + ctrl_regs_offset, DSC_HACT_ST_END_MASK, + DSC_HACT_ST_END_SHIFT, val, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_VTOTAL_VS_END + ctrl_regs_offset, DSC_VTOTAL_PW_MASK, + DSC_VTOTAL_PW_SHIFT, vtotal << 16 | vsync_len, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_VACT_ST_END + ctrl_regs_offset, DSC_VACT_ST_END_MASK, + DSC_VACT_ST_END_SHIFT, vact_end << 16 | vact_st, FALSE); + } + + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_RST + ctrl_regs_offset, RST_DEASSERT_MASK, + RST_DEASSERT_SHIFT, 1, FALSE); + udelay(10); + + val |= DSC_CTRL0_DEF_CON | (LogCalculate(CrtcState->dsc_slice_num) << DSC_NSLC_SHIFT) | + ((dsc_sink_cap->version_minor == 2 ? 1 : 0) << DSC_IFEP_SHIFT); + Vop2Writel (Vop2->BaseAddress, RK3588_DSC_8K_CTRL0 + decoder_regs_offset, val); + + Vop2LoadPps(DisplayState, Vop2, dsc_id); + + val |= (1 << DSC_PPS_UPD_SHIFT); + Vop2Writel (Vop2->BaseAddress, RK3588_DSC_8K_CTRL0 + decoder_regs_offset, val); + + DEBUG ((DEBUG_INFO, "DSC%d: txp:%lld div:%d, pxl:%lld div:%d, dsc:%lld div:%d\n", + dsc_id, + CrtcState->dsc_txp_clk_rate, dsc_txp_clk_div, + CrtcState->dsc_pxl_clk_rate, dsc_pxl_clk_div, + CrtcState->dsc_cds_clk_rate, dsc_cds_clk_div)); +} + +EFI_STATUS +Vop2Init ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *Mode = &ConnectorState->DisplayMode; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private;; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 LineFlagOffset = CrtcState->CrtcID * 0x4; + UINT16 HSyncLen, HDisplay, HTotal, HActStart, HActEnd; + UINT16 VSyncLen, VDisplay, VTotal, VActStart, VActEnd; + UINT32 Val, ActEnd; + UINT8 DitherDownEn; + UINT8 PreDitherDownEn; + BOOLEAN YUVOverlay; + UINT64 DclkRate; + + HSyncLen = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart; + HDisplay = Mode->CrtcHDisplay; + HTotal = Mode->CrtcHTotal; + HActStart = Mode->CrtcHTotal - Mode->CrtcHSyncStart; + HActEnd = HActStart + HDisplay; + + VSyncLen = Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart; + VDisplay = Mode->CrtcVDisplay; + VTotal = Mode->CrtcVTotal; + VActStart = Mode->CrtcVTotal - Mode->CrtcVSyncStart; + VActEnd = VActStart + VDisplay; + + DEBUG((DEBUG_INIT, "[INIT]VOP update mode to: %dx%d%a%d, type:%a for VP%d\n", + Mode->HDisplay, Mode->VDisplay, + Mode->Flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", + Mode->VScan, + GetOutputIfName(ConnectorState->OutputInterface), + CrtcState->CrtcID)); + + DclkRate = Vop2IfConfig (DisplayState, Vop2); + + if (ConnectorState->OutputMode == ROCKCHIP_OUT_MODE_AAAA && + !(CrtcState->Feature & VOP_FEATURE_OUTPUT_10BIT)) + ConnectorState->OutputMode = ROCKCHIP_OUT_MODE_P888; + + Vop2PostColorSwap (DisplayState, Vop2); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, OUT_MODE_MASK, + OUT_MODE_SHIFT, ConnectorState->OutputMode, FALSE); + + switch (ConnectorState->BusFormat) { + case MEDIA_BUS_FMT_RGB565_1X16: + DitherDownEn = 1; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA: + DitherDownEn = 1; + break; + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + DitherDownEn = 0; + PreDitherDownEn = 1; + break; + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + default: + DitherDownEn = 0; + PreDitherDownEn = 0; + break; + } + + if (ConnectorState->OutputMode == ROCKCHIP_OUT_MODE_AAAA) + PreDitherDownEn = 0; + else + PreDitherDownEn = 1; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + DITHER_DOWN_EN_SHIFT, DitherDownEn, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + PRE_DITHER_DOWN_EN_SHIFT, PreDitherDownEn, FALSE); + + YUVOverlay = IsYUVOutput (ConnectorState->BusFormat) ? 1 : 0; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_OVL_CTRL, EN_MASK, + CrtcState->CrtcID, YUVOverlay, FALSE); + CrtcState->YUVOverlay = YUVOverlay; + + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_HTOTAL_HS_END + VPOffset, + (HTotal << 16) | HSyncLen); + Val = HActStart << 16; + Val |= HActEnd; + + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_HACT_ST_END + VPOffset, Val); + Val = VActStart << 16; + Val |= VActEnd; + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_VACT_ST_END + VPOffset, Val); + if (Mode->Flags & DRM_MODE_FLAG_INTERLACE) { + UINT16 VActStartF1 = VTotal + VActStart + 1; + UINT16 VActEndF1 = VActStartF1 + VDisplay; + + Val = VActStartF1 << 16 | VActEndF1; + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_VACT_ST_END_F1 + VPOffset, Val); + Val = VTotal << 16 | (VTotal + VSyncLen); + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_VS_ST_END_F1 + VPOffset, Val); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + INTERLACE_EN_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + DSP_FILED_POL, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + P2I_EN_SHIFT, 1, FALSE); + VTotal += VTotal + 1; + ActEnd = VActEndF1; + } + else { + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + INTERLACE_EN_SHIFT, 0, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + P2I_EN_SHIFT, 0, FALSE); + ActEnd = VActEnd; + } + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_VTOTAL_VS_END + VPOffset, + (VTotal << 16) | VSyncLen); + + if (Vop2->Version == VOP_VERSION_RK3568) { + if (Mode->Flags & DRM_MODE_FLAG_DBLCLK || + ConnectorState->OutputInterface & VOP_OUTPUT_IF_BT656) + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + CORE_DCLK_DIV_EN_SHIFT, 1, FALSE); + else + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + CORE_DCLK_DIV_EN_SHIFT, 0, FALSE); + } + + if (ConnectorState->OutputMode == ROCKCHIP_OUT_MODE_YUV420) + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, DCLK_DIV2_MASK, + DCLK_DIV2_SHIFT, 0x3, FALSE); + else + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_MIPI_CTRL + VPOffset, DCLK_DIV2_MASK, + DCLK_DIV2_SHIFT, 0x0, FALSE); + + if (YUVOverlay) + Val = 0x20010200; + else + Val = 0; + + Vop2Writel (Vop2->BaseAddress, RK3568_VP0_DSP_BG + VPOffset, 0); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + POST_DSP_OUT_R2Y_SHIFT, YUVOverlay, FALSE); + + Vop2TVConfigUpdate (DisplayState, Vop2); + Vop2PostConfig (DisplayState, Vop2); + + if (CrtcState->dsc_enable) { + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) { + Vop2DscEnable(DisplayState, Vop2, 0, DclkRate * 1000LL); + Vop2DscEnable(DisplayState, Vop2, 1, DclkRate * 1000LL); + } else { + Vop2DscEnable(DisplayState, Vop2, CrtcState->dsc_id, DclkRate * 1000LL); + } + } + + Vop2SetClk (CrtcState->CrtcID, DclkRate * 1000); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_SYS_CTRL_LINE_FLAG0 + LineFlagOffset, LINE_FLAG_NUM_MASK, + RK3568_DSP_LINE_FLAG_NUM0_SHIFT, ActEnd, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_SYS_CTRL_LINE_FLAG0 + LineFlagOffset, LINE_FLAG_NUM_MASK, + RK3568_DSP_LINE_FLAG_NUM0_SHIFT, ActEnd, FALSE); + + return EFI_SUCCESS; +} + +INLINE +SCALE_MODE +GetSclMode ( + IN UINT32 Src, + IN UINT32 Dst + ) +{ + if (Src < Dst) + return SCALE_UP; + else if (Src > Dst) + return SCALE_DOWN; + + return SCALE_NONE; +} + +/* + * bli_sd_factor = (src - 1) / (dst - 1) << 12; + * avg_sd_factor: + * bli_su_factor: + * bic_su_factor: + * = (src - 1) / (dst - 1) << 16; + * + * gt2 enable: dst get one line from two line of the src + * gt4 enable: dst get one line from four line of the src. + * + */ +#define VOP2_BILI_SCL_DN(src, dst) (((src - 1) << 12) / (dst - 1)) +#define VOP2_COMMON_SCL(src, dst) (((src - 1) << 16) / (dst - 1)) + +#define VOP2_BILI_SCL_FAC_CHECK(src, dst, fac) \ + (fac * (dst - 1) >> 12 < (src - 1)) +#define VOP2_COMMON_SCL_FAC_CHECK(src, dst, fac) \ + (fac * (dst - 1) >> 16 < (src - 1)) + +STATIC +UINT16 +Vop2ScaleFactor ( + IN SCALE_MODE Mode, + IN VOP2_SCALE_DOWN_MODE FilterMode, + IN UINT32 Src, + IN UINT32 Dst + ) +{ + UINT32 Factor = 0; + INT32 i = 0; + + if (Mode == SCALE_NONE) + return 0; + + if ((Mode == SCALE_DOWN) && (FilterMode == VOP2_SCALE_DOWN_BIL)) { + Factor = VOP2_BILI_SCL_DN(Src, Dst); + for (i = 0; i < 100; i++) { + if (VOP2_BILI_SCL_FAC_CHECK(Src, Dst, Factor)) + break; + Factor -= 1; + DEBUG ((DEBUG_INFO, "down fac cali: src:%d, dst:%d, fac:0x%x\n", Src, Dst, Factor)); + } + } else { + for (i = 0; i < 100; i++) { + if (VOP2_COMMON_SCL_FAC_CHECK(Src, Dst, Factor)) + break; + Factor -= 1; + DEBUG ((DEBUG_INFO, "up fac cali: src:%d, dst:%d, fac:0x%x\n", Src, Dst, Factor)); + } + } + + return Factor; +} + +STATIC +VOID +Vop2SetupScale ( + OUT VOP2 *Vop2, + OUT VOP2_WIN_DATA *WinData, + IN UINT32 SrcW, + IN UINT32 SrcH, + IN UINT32 DstW, + IN UINT32 DstH + ) +{ + UINT16 YrgbHorSclMode, YrgbVerSclMode; + UINT16 HsclFilterMode, VsclFilterMode; + UINT8 GT2 = 0, GT4 =0; + UINT32 XFac = 0, YFac = 0; + VOP2_SCALE_UP_MODE HSUFilterMode = VOP2_SCALE_UP_BIC; + VOP2_SCALE_DOWN_MODE HSDFilterMode = VOP2_SCALE_DOWN_BIL; + VOP2_SCALE_UP_MODE VSUFilterMode = VOP2_SCALE_UP_BIL; + VOP2_SCALE_DOWN_MODE VSDFilterMode = VOP2_SCALE_DOWN_BIL; + UINT32 WinOffset = WinData->RegOffset; + + if (SrcH > (4 * DstH)) + GT4 = 1; + else if (SrcH >= (2 * DstH)) + GT2 = 1; + + if (GT4) + SrcH >>= 2; + else if (GT2) + SrcH >>= 1; + + YrgbHorSclMode = GetSclMode(SrcW, DstW); + YrgbVerSclMode = GetSclMode(SrcH, DstH); + + if (YrgbHorSclMode == SCALE_UP) + HsclFilterMode = HSUFilterMode; + else + HsclFilterMode = HSDFilterMode; + + if (YrgbVerSclMode == SCALE_UP) + VsclFilterMode = VSUFilterMode; + else + VsclFilterMode = VSDFilterMode; + + /* + * RK3568 VOP Esmart/Smart DstW should be even pixel + * at scale down mode + */ + if ((YrgbHorSclMode == SCALE_DOWN) && (DstW & 0x1)) { + DEBUG ((DEBUG_INFO, "win dst_w[%d] should align as 2 pixel\n", DstW)); + DstW += 1; + } + + XFac = Vop2ScaleFactor (YrgbHorSclMode, HsclFilterMode, SrcW, DstW); + YFac = Vop2ScaleFactor (YrgbVerSclMode, VsclFilterMode, SrcH, DstH); + + if (WinData->Type == CLUSTER_LAYER) { + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_SCL_FACTOR_YRGB + WinOffset, YFac << 16 | XFac); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL1 + WinOffset, YRGB_GT2_MASK, + CLUSTER_YRGB_GT2_SHIFT, GT2, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL1 + WinOffset, YRGB_GT4_MASK, + CLUSTER_YRGB_GT4_SHIFT, GT4, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL1 + WinOffset, YRGB_XSCL_MODE_MASK, + CLUSTER_YRGB_XSCL_MODE_SHIFT, YrgbHorSclMode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL1 + WinOffset, YRGB_YSCL_MODE_MASK, + CLUSTER_YRGB_YSCL_MODE_SHIFT, YrgbVerSclMode, FALSE); + } else { + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_SCL_FACTOR_YRGB + WinOffset, YFac << 16 | XFac); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_CTRL + WinOffset, YRGB_GT2_MASK, + YRGB_GT2_SHIFT, GT2, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_CTRL + WinOffset, YRGB_GT4_MASK, + YRGB_GT4_SHIFT, GT4, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_SCL_CTRL + WinOffset, YRGB_XSCL_MODE_MASK, + YRGB_XSCL_MODE_SHIFT, YrgbHorSclMode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_SCL_CTRL + WinOffset, YRGB_YSCL_MODE_MASK, + YRGB_YSCL_MODE_SHIFT, YrgbVerSclMode, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_SCL_CTRL + WinOffset, YRGB_XSCL_FILTER_MODE_MASK, + YRGB_XSCL_FILTER_MODE_SHIFT, HsclFilterMode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_SCL_CTRL + WinOffset, YRGB_YSCL_FILTER_MODE_MASK, + YRGB_YSCL_FILTER_MODE_SHIFT, VsclFilterMode, FALSE); + } +} + +STATIC +VOID +Vop2SetClusterWin ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2_WIN_DATA *WinData + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *Mode = &ConnectorState->DisplayMode; + VOP2 *Vop2 = CrtcState->Private; + INT32 SrcW = CrtcState->SrcW; + INT32 SrcH = CrtcState->SrcH; + INT32 CrtcW = CrtcState->CrtcW; + INT32 CrtcH = CrtcState->CrtcH; + INT32 CrtcX = CrtcState->CrtcX; + INT32 CrtcY = CrtcState->CrtcY; + INT32 XVirtual = CrtcState->XVirtual; + INT32 YMirror = 0; + INT32 CSCMode; + UINT32 ActInfo, DspInfo, DspSt, DspStx, DspSty; + UINT32 WinOffset = WinData->RegOffset; + UINT32 CfgDone = CFG_DONE_EN | BIT(CrtcState->CrtcID) | (BIT(CrtcState->CrtcID) << 16); + + ActInfo = (SrcH - 1) << 16; + ActInfo |= (SrcW - 1) & 0xffff; + + DspInfo = (CrtcH - 1) << 16; + DspInfo |= (CrtcW - 1) & 0xffff; + + DspStx = CrtcX; + DspSty = CrtcY; + DspSt = DspSty << 16 | (DspStx & 0xffff); + + if (Mode->Flags & DRM_MODE_FLAG_YMIRROR) + YMirror = 1; + else + YMirror = 0; + + Vop2SetupScale(Vop2, WinData, SrcW, SrcH, CrtcW, CrtcH); + + if (YMirror) + DEBUG ((DEBUG_WARN, "WARN: y mirror is unsupported by cluster window\n")); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL0 + WinOffset, WIN_FORMAT_MASK, + WIN_FORMAT_SHIFT, CrtcState->Format, FALSE); + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_VIR + WinOffset, XVirtual); + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_YRGB_MST + WinOffset, CrtcState->DMAAddress); + + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_ACT_INFO + WinOffset, ActInfo); + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_DSP_INFO + WinOffset, DspInfo); + Vop2Writel (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_DSP_ST + WinOffset, DspSt); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL0 + WinOffset, EN_MASK, + WIN_EN_SHIFT, 1, FALSE); + + CSCMode = Vop2ConvertCSCMode(ConnectorState->ColorSpace); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL0 + WinOffset, EN_MASK, + CLUSTER_RGB2YUV_EN_SHIFT, IsYUVOutput(ConnectorState->BusFormat), FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_WIN0_CTRL0 + WinOffset, CSC_MODE_MASK, + CLUSTER_CSC_MODE_SHIFT, CSCMode, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_CLUSTER0_CTRL + WinOffset, EN_MASK, + CLUSTER_EN_SHIFT, 1, FALSE); + + Vop2Writel (Vop2->BaseAddress, RK3568_REG_CFG_DONE, CfgDone); +} + +STATIC +VOID +Vop2SetSmartWin ( + OUT DISPLAY_STATE *DisplayState, + OUT VOP2_WIN_DATA *WinData + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + DRM_DISPLAY_MODE *Mode = &ConnectorState->DisplayMode; + VOP2 *Vop2 = CrtcState->Private; + INT32 SrcW = CrtcState->SrcW; + INT32 SrcH = CrtcState->SrcH; + INT32 CrtcW = CrtcState->CrtcW; + INT32 CrtcH = CrtcState->CrtcH; + INT32 CrtcX = CrtcState->CrtcX; + INT32 CrtcY = CrtcState->CrtcY; + INT32 XVirtual = CrtcState->XVirtual; + INT32 YMirror = 0; + INT32 CSCMode; + UINT32 ActInfo, DspInfo, DspSt, DspStx, DspSty; + UINT32 WinOffset = WinData->RegOffset; + UINT32 CfgDone = CFG_DONE_EN | BIT(CrtcState->CrtcID) | (BIT(CrtcState->CrtcID) << 16); + + /* + * This is workaround solution for IC design: + * esmart can't support scale down when actual_w % 16 == 1. + */ + if (SrcW > CrtcW && (SrcW & 0xf) == 1) { + DEBUG ((DEBUG_WARN, "WARN: vp%d unsupported act_w[%d] mode 16 = 1 when scale down\n", CrtcState->CrtcID, SrcW)); + SrcW -= 1; + } + + ActInfo = (SrcH - 1) << 16; + ActInfo |= (SrcW - 1) & 0xffff; + + DspInfo = (CrtcH - 1) << 16; + DspInfo |= (CrtcW - 1) & 0xffff; + + DspStx = CrtcX; + DspSty = CrtcY; + DspSt = DspSty << 16 | (DspStx & 0xffff); + + if (Mode->Flags & DRM_MODE_FLAG_YMIRROR) + YMirror = 1; + else + YMirror = 0; + + Vop2SetupScale(Vop2, WinData, SrcW, SrcH, CrtcW, CrtcH); + + if (YMirror) + CrtcState->DMAAddress += (SrcH - 1) * XVirtual * 4; + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_CTRL1 + WinOffset, EN_MASK, + YMIRROR_EN_SHIFT, YMirror, FALSE); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_CTRL + WinOffset, WIN_FORMAT_MASK, + WIN_FORMAT_SHIFT, CrtcState->Format, FALSE); + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_VIR + WinOffset, XVirtual); + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_YRGB_MST + WinOffset, CrtcState->DMAAddress); + + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_ACT_INFO + WinOffset, ActInfo); + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_DSP_INFO + WinOffset, DspInfo); + Vop2Writel (Vop2->BaseAddress, RK3568_ESMART0_REGION0_DSP_ST + WinOffset, DspSt); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_REGION0_CTRL + WinOffset, EN_MASK, + WIN_EN_SHIFT, 1, FALSE); + + CSCMode = Vop2ConvertCSCMode(ConnectorState->ColorSpace); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_CTRL0 + WinOffset, EN_MASK, + RGB2YUV_EN_SHIFT, IsYUVOutput(ConnectorState->BusFormat), FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3568_ESMART0_CTRL0 + WinOffset, CSC_MODE_MASK, + CSC_MODE_SHIFT, CSCMode, FALSE); + + Vop2Writel (Vop2->BaseAddress, RK3568_REG_CFG_DONE, CfgDone); +} + +EFI_STATUS +Vop2SetPlane ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + VOP2_WIN_DATA *WinData; + UINT8 PrimaryPlaneID = Vop2->VpPlaneMask[CrtcState->CrtcID].PrimaryPlaneId; + + if (CrtcState->CrtcW > CrtcState->MaxOutput.Width) { + DEBUG ((DEBUG_ERROR, "ERROR: output w[%d] exceeded max width[%d]\n", + CrtcState->CrtcW, CrtcState->MaxOutput.Width)); + return -EFI_INVALID_PARAMETER; + } + + WinData = Vop2FindWinByPhysID (Vop2, PrimaryPlaneID); + if (!WinData) { + DEBUG ((DEBUG_ERROR, "invalid win id %d\n", PrimaryPlaneID)); + return -EFI_INVALID_PARAMETER; + } + + if (WinData->Type == CLUSTER_LAYER) + Vop2SetClusterWin (DisplayState, WinData); + else + Vop2SetSmartWin (DisplayState, WinData); + + DEBUG ((DEBUG_INFO, "VOP VP%d enable %a[%dx%d->%dx%d@%dx%d] fmt[%d] addr[0x%x]\n", + CrtcState->CrtcID, GetPlaneName(PrimaryPlaneID), + CrtcState->SrcW, CrtcState->SrcH, CrtcState->CrtcW, CrtcState->CrtcH, + CrtcState->CrtcX, CrtcState->CrtcY, CrtcState->Format, + CrtcState->DMAAddress)); + + return EFI_SUCCESS; +} + +STATIC +VOID +Vop2DscCfgDone ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + UINT8 dsc_id = CrtcState->dsc_id; + UINT32 ctrl_regs_offset = (dsc_id * 0x30); + + if (ConnectorState->OutputFlags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE) { + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_CFG_DONE, EN_MASK, + DSC_CFG_DONE_SHIFT, 1, FALSE); + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_CFG_DONE + 0x30, EN_MASK, + DSC_CFG_DONE_SHIFT, 1, FALSE); + } else { + Vop2MaskWrite (Vop2->BaseAddress, RK3588_DSC_8K_CFG_DONE + ctrl_regs_offset, EN_MASK, + DSC_CFG_DONE_SHIFT, 1, FALSE); + } +} + +EFI_STATUS +Vop2Enable ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 CfgDone = CFG_DONE_EN | BIT(CrtcState->CrtcID) | (BIT(CrtcState->CrtcID) << 16); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + STANDBY_EN_SHIFT, 0, FALSE); + Vop2Writel (Vop2->BaseAddress, RK3568_REG_CFG_DONE, CfgDone); + + if (CrtcState->dsc_enable) { + Vop2DscCfgDone(This, DisplayState); + } + +#ifdef DEBUG_DUMP_REG + Vop2DumpRegisters (DisplayState, Vop2FindWinByPhysID (Vop2, Vop2->VpPlaneMask[CrtcState->CrtcID].PrimaryPlaneId)); +#endif + + return EFI_SUCCESS; +} + +EFI_STATUS +Vop2Disable ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CRTC_STATE *CrtcState = &DisplayState->CrtcState; + VOP2 *Vop2 = CrtcState->Private; + UINT32 VPOffset = CrtcState->CrtcID * 0x100; + UINT32 CfgDone = CFG_DONE_EN | BIT(CrtcState->CrtcID) | (BIT(CrtcState->CrtcID) << 16); + + Vop2MaskWrite (Vop2->BaseAddress, RK3568_VP0_DSP_CTRL + VPOffset, EN_MASK, + STANDBY_EN_SHIFT, 1, FALSE); + Vop2Writel (Vop2->BaseAddress, RK3568_REG_CFG_DONE, CfgDone); + + return EFI_SUCCESS; +} + +STATIC ROCKCHIP_CRTC_PROTOCOL mVop2 = { + &mVop2RK3588, + Vop2PreInit, + Vop2Init, + NULL, + Vop2SetPlane, + NULL, + Vop2Enable, + Vop2Disable, + NULL, + { + }, + {}, + FALSE, + FALSE, + FALSE +}; + +EFI_STATUS +Vop2DxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipCrtcProtocolGuid, + &mVop2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.h new file mode 100644 index 0000000..92b1375 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.h @@ -0,0 +1,230 @@ +/** @file + Vop2 DXE Driver, install RK_CRTC_PROTOCOL. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __VOP2_H__ +#define __VOP2_H__ + +#include + +/* + * major: IP major vertion, used for IP structure + * minor: big feature change under same structure + */ +#define VOP_VERSION(major, minor) ((major) << 8 | (minor)) +#define VOP_MAJOR(version) ((version) >> 8) +#define VOP_MINOR(version) ((version) & 0xFF) + +#define VOP_VERSION_RK3568 VOP_VERSION(0x40, 0x15) +#define VOP_VERSION_RK3588 VOP_VERSION(0x40, 0x17) + +/* + * display output interface supported by rockchip lcdc + */ +#define ROCKCHIP_OUT_MODE_P888 0 +#define ROCKCHIP_OUT_MODE_BT1120 0 +#define ROCKCHIP_OUT_MODE_P666 1 +#define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_BT656 5 +#define ROCKCHIP_OUT_MODE_S888 8 +#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 +#define ROCKCHIP_OUT_MODE_YUV420 14 +/* for use special outface */ +#define ROCKCHIP_OUT_MODE_AAAA 15 + +#define VOP_OUTPUT_IF_RGB BIT(0) +#define VOP_OUTPUT_IF_BT1120 BIT(1) +#define VOP_OUTPUT_IF_BT656 BIT(2) +#define VOP_OUTPUT_IF_LVDS0 BIT(3) +#define VOP_OUTPUT_IF_LVDS1 BIT(4) +#define VOP_OUTPUT_IF_MIPI0 BIT(5) +#define VOP_OUTPUT_IF_MIPI1 BIT(6) +#define VOP_OUTPUT_IF_eDP0 BIT(7) +#define VOP_OUTPUT_IF_eDP1 BIT(8) +#define VOP_OUTPUT_IF_DP0 BIT(9) +#define VOP_OUTPUT_IF_DP1 BIT(10) +#define VOP_OUTPUT_IF_HDMI0 BIT(11) +#define VOP_OUTPUT_IF_HDMI1 BIT(12) + +#define VOP_OUTPUT_IF_NUMS 13 + +#define VOP2_LAYER_MAX 8 + +#define VOP_FEATURE_OUTPUT_10BIT BIT(0) + +/* KHz */ +#define VOP2_MAX_DCLK_RATE 600000 + +/* + * vop2 dsc id + */ +#define ROCKCHIP_VOP2_DSC_8K 0 +#define ROCKCHIP_VOP2_DSC_4K 1 + +/* + * vop2 internal power domain id, + * should be all none zero, 0 will be + * treat as invalid; + */ +#define VOP2_PD_CLUSTER0 BIT(0) +#define VOP2_PD_CLUSTER1 BIT(1) +#define VOP2_PD_CLUSTER2 BIT(2) +#define VOP2_PD_CLUSTER3 BIT(3) +#define VOP2_PD_DSC_8K BIT(5) +#define VOP2_PD_DSC_4K BIT(6) +#define VOP2_PD_ESMART BIT(7) + +typedef enum { + CSC_BT601L, + CSC_BT709L, + CSC_BT601F, + CSC_BT2020, +} VOP2_CSC_FORMAT; + +typedef enum { + HSYNC_POSITIVE = 0, + VSYNC_POSITIVE = 1, + DEN_NEGATIVE = 2, + DCLK_INVERT = 3 +} VOP2_POL; + +typedef enum { + BCSH_OUT_MODE_BLACK, + BCSH_OUT_MODE_BLUE, + BCSH_OUT_MODE_COLOR_BAR, + BCSH_OUT_MODE_NORMAL_VIDEO, +} VOP2_BCSH_OUT_MODE; + +typedef enum { + VOP2_VP0, + VOP2_VP1, + VOP2_VP2, + VOP2_VP3, + VOP2_VP_MAX, +} VOP2_VIDEO_PORTS_ID; + +typedef enum { + ROCKCHIP_VOP2_CLUSTER0 = 0, + ROCKCHIP_VOP2_CLUSTER1, + ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_SMART0, + ROCKCHIP_VOP2_SMART1, + ROCKCHIP_VOP2_CLUSTER2, + ROCKCHIP_VOP2_CLUSTER3, + ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_ESMART3, + ROCKCHIP_VOP2_LAYER_MAX, +} VOP2_LAYER_PHY_ID; + +typedef enum { + CLUSTER_LAYER = 0, + ESMART_LAYER = 1, + SMART_LAYER = 2, +} VOP2_LAYER_TYPE; + +typedef enum { + VOP2_SCALE_UP_NRST_NBOR, + VOP2_SCALE_UP_BIL, + VOP2_SCALE_UP_BIC, +} VOP2_SCALE_UP_MODE; + +typedef enum { + VOP2_SCALE_DOWN_NRST_NBOR, + VOP2_SCALE_DOWN_BIL, + VOP2_SCALE_DOWN_AVG, +} VOP2_SCALE_DOWN_MODE; + +typedef enum { + SCALE_NONE = 0x0, + SCALE_UP = 0x1, + SCALE_DOWN = 0x2, +} SCALE_MODE; + +typedef enum { + VOP_DSC_IF_DISABLE = 0, + VOP_DSC_IF_HDMI = 1, + VOP_DSC_IF_MIPI_DS_MODE = 2, + VOP_DSC_IF_MIPI_VIDEO_MODE = 3, +} VOP2_DSC_INTERFACE_MODE; + +typedef struct VOP2_POWER_DOMAIN_DATA { + CHAR8 PdEnShift; + CHAR8 PdStatusShift; + CHAR8 PmuStatusShift; + CHAR8 BisrEnStatusShift; + struct VOP2_POWER_DOMAIN_DATA *ParentPdData; +} VOP2_POWER_DOMAIN_DATA; + +typedef struct { + VOP2_LAYER_TYPE Type; + CHAR8 *Name; + UINT8 PhysID; + UINT8 WinSelPortOffset; + UINT8 LayerSelWinID; + UINT32 RegOffset; + VOP2_POWER_DOMAIN_DATA *PdData; +} VOP2_WIN_DATA; + +typedef struct { + UINT32 Feature; + UINT32 MaxDclk; + UINT8 PreScanMaxDly; + VOP_RECT MaxOutput; +} VOP2_VP_DATA; + +typedef struct { + UINT8 PrimaryPlaneId; /* use this win to show logo */ + UINT8 AttachedLayersNr; /* number layers attach to this vp */ + UINT8 AttachedLayers[VOP2_LAYER_MAX]; /* the layers attached to this vp */ + UINT32 PlaneMask; + INT32 CursorPlaneID; +} VOP2_VP_PLANE_MASK; + +typedef struct { + UINT8 id; + VOP2_POWER_DOMAIN_DATA *PdData; + UINT8 max_slice_num; + UINT8 max_linebuf_depth; /* used to generate the bitstream */ + UINT8 min_bits_per_pixel; /* bit num after encoder compress */ + const CHAR8 *dsc_txp_clk_src_name; + const CHAR8 *dsc_txp_clk_name; + const CHAR8 *dsc_pxl_clk_name; + const CHAR8 *dsc_cds_clk_name; +} VOP2_DSC_DATA; + +typedef struct { + UINT32 Version; + VOP2_VP_DATA *VpData; + VOP2_WIN_DATA *WinData; + /* + struct vop2_plane_table *plane_table; + */ + VOP2_VP_PLANE_MASK *PlaneMask; + + VOP2_DSC_DATA *DscData; + + UINT8 NrVps; + UINT8 NrLayers; + UINT8 NrMixers; + UINT8 NrGammas; + UINT8 NrDscs; + UINT32 RegLen; +} VOP2_DATA; + +typedef struct { + UINT32 BaseAddress; + UINTN SysPmu; + UINT32 Version; + BOOLEAN GlobalInit; + VOP2_DATA *Data; + VOP2_VP_PLANE_MASK VpPlaneMask[VOP2_VP_MAX]; +} VOP2; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf new file mode 100644 index 0000000..b247971 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf @@ -0,0 +1,44 @@ +## @file +# The Vop2 driver file. +# +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = Vop2Dxe + FILE_GUID = 1cbb3666-99fe-11ec-9927-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = Vop2DxeInitialize + +[Sources] + Vop2Dxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + TimerLib + IoLib + DebugLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + RockchipDisplayLib + UefiDriverEntryPoint + CruLib + +[Protocols] + gRockchipCrtcProtocolGuid + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvCompactModules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvCompactModules.fdf.inc new file mode 100644 index 0000000..e6a95a6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvCompactModules.fdf.inc @@ -0,0 +1,9 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + INF ArmPlatformPkg/PrePi/PeiUniCore.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainAprioriDxe.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainAprioriDxe.fdf.inc new file mode 100644 index 0000000..1e5f9fd --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainAprioriDxe.fdf.inc @@ -0,0 +1,13 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +!if $(RK_STATUS_LED_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf +!endif + + INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainModules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainModules.fdf.inc new file mode 100644 index 0000000..6c0a264 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvMainModules.fdf.inc @@ -0,0 +1,229 @@ +## @file +# +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + INF MdeModulePkg/Core/Dxe/DxeMain.inf + INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf + + # + # PI DXE Drivers producing Architectural Protocols (EFI Services) + # + INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf + INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf + INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + INF EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf + INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf + INF EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf + INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf +!if $(SECURE_BOOT_ENABLE) == TRUE +!include ArmPlatformPkg/SecureBootDefaultKeys.fdf.inc + INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + INF SecurityPkg/VariableAuthenticated/SecureBootDefaultKeysDxe/SecureBootDefaultKeysDxe.inf +!endif + INF SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf + INF SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf + + # + # Status LED support + # +!if $(RK_STATUS_LED_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf +!endif + + # + # Non-volatile FVB support + # + # RkFvbDxe does not have a hard dependency on NorFlashDxe to provide + # its services, but we want it to load earlier so the protocol can + # get installed by the time RkFvbDxe tries to locate it on initialization. + # +!if $(RK_NOR_FLASH_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf +!endif + INF Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf + + # + # Multiple Console IO support + # + INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf + INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf + INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf + INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf + INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf + + # + # Arm GIC + # + INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf + + # + # Timer + # + INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf + INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf + + # + # SCMI Support + # + INF ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf + + # + # ACPI Support + # + INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf + INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + + # + # SMBIOS Support + # + INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf + INF Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf + + # + # I2C Bus & Devices + # + INF MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf + INF Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf +!if $(RK_860X_REGULATOR_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf +!endif +!if $(RK_RTC8563_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf +!endif +!if $(RK_PCA9555_ENABLE) == TRUE + INF Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf +!endif + # INF Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf + + # + # Display Support + # + INF Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf + # INF Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf +!if $(RK_DW_HDMI_QP_ENABLE) == TRUE + INF Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf +!endif + INF Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf + INF Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf + INF Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf + + # + # USB Support + # + INF MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf + INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + INF Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf + + # USB controllers installer + INF Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf + + INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf + + # + # PCI Support + # + INF MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf + + # + # SD/eMMC upper layer drivers + # +!if $(RK_SD_ENABLE) == TRUE || $(RK_EMMC_ENABLE) == TRUE + INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf +!endif + + # + # SD Support + # +!if $(RK_SD_ENABLE) == TRUE + INF Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf + INF Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf +!endif + + # + # eMMC Support + # +!if $(RK_EMMC_ENABLE) == TRUE + INF MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf + INF Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf +!endif + + # + # AHCI Support + # +!if $(RK_AHCI_ENABLE) == TRUE + INF MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf + INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf +!endif + + # + # FAT filesystem + GPT/MBR partitioning + # + INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf + INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf + INF FatPkg/EnhancedFatDxe/Fat.inf + INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf + + # + # RAM Disk Support + # + INF MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf + + # + # UEFI Network Stack + # +!include NetworkPkg/Network.fdf.inc + +!if $(NETWORK_ENABLE) == TRUE + # + # Realtek PCIe UNDI Driver + # + INF Drivers/Realtek/Bus/Pcie/PcieNetworking/RtkUndiDxe.inf + + # + # Realtek USB UNDI Driver + # + INF Drivers/Realtek/Bus/Usb/UsbNetworking/RtkUsbUndiDxe.inf + + # + # AX88772 Ethernet Driver for Apple Ethernet Adapter + # + INF Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf +!endif + + # + # Bds + # + INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf + INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf + INF MdeModulePkg/Application/UiApp/UiApp.inf + + # + # UEFI applications + # + INF ShellPkg/Application/Shell/Shell.inf +!ifdef $(INCLUDE_TFTP_COMMAND) + INF ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf +!endif #$(INCLUDE_TFTP_COMMAND) + + # I2C Demo application + # INF Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf + + # SPI Flash Cmd application + # INF Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvRules.fdf.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvRules.fdf.inc new file mode 100644 index 0000000..e15b127 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/FvRules.fdf.inc @@ -0,0 +1,139 @@ +#/** @file +# +# Copyright (c) 2021, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +################################################################################ +# +# Rules are use with the [FV] section's module INF type to define +# how an FFS file is created for a given INF file. The following Rule are the default +# rules for the different module type. User can add the customized rules to define the +# content of the FFS file. +# +################################################################################ + +############################################################################ +# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section # +############################################################################ +# +#[Rule.Common.DXE_DRIVER] +# FILE DRIVER = $(NAMED_GUID) { +# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex +# COMPRESS PI_STD { +# GUIDED { +# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi +# UI STRING="$(MODULE_NAME)" Optional +# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) +# } +# } +# } +# +############################################################################ + +[Rule.Common.SEC] + FILE SEC = $(NAMED_GUID) RELOCS_STRIPPED { + TE TE Align = 4K $(INF_OUTPUT)/$(MODULE_NAME).efi + } + +[Rule.Common.PEI_CORE] + FILE PEI_CORE = $(NAMED_GUID) { + TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING ="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM] + FILE PEIM = $(NAMED_GUID) { + PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM.BINARY] + FILE PEIM = $(NAMED_GUID) { + PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + TE TE Align = Auto |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM.FMP_IMAGE_DESC] + FILE PEIM = $(NAMED_GUID) { + RAW BIN |.acpi + PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 Align=4K $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.DXE_CORE] + FILE DXE_CORE = $(NAMED_GUID) { + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_DRIVER.BINARY] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_RUNTIME_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_APPLICATION] + FILE APPLICATION = $(NAMED_GUID) { + UI STRING ="$(MODULE_NAME)" Optional + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + } + +[Rule.Common.UEFI_DRIVER.BINARY] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.UEFI_APPLICATION.BINARY] + FILE APPLICATION = $(NAMED_GUID) { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) + } + +[Rule.Common.DXE_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex + PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + UI STRING="$(MODULE_NAME)" Optional + RAW ACPI Optional |.acpi + RAW ASL Optional |.aml + } + +[Rule.Common.USER_DEFINED.ACPITABLE] + FILE FREEFORM = $(NAMED_GUID) { + RAW ACPI |.acpi + RAW ASL |.aml + } diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AcpiNextLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AcpiNextLib.h new file mode 100644 index 0000000..ea2aa34 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AcpiNextLib.h @@ -0,0 +1,98 @@ +/** @file +* +* Copyright (c) 2011-2015, ARM Limited. All rights reserved. +* Copyright (c) 2015, Hisilicon Limited. All rights reserved. +* Copyright (c) 2015, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + + + +#ifndef __ACPI_NEXT_LIB_H__ +#define __ACPI_NEXT_LIB_H__ + +#include + +/// +/// ITS Affinity Structure Definition +/// +#pragma pack(1) +typedef struct { + UINT8 Type; + UINT8 Length; + UINT32 ProximityDomain; + UINT16 Reserved; + UINT32 ItsHwId; +} EFI_ACPI_6_2_ITS_AFFINITY_STRUCTURE; +#pragma pack() + +#define EFI_ACPI_6_1_GIC_ITS_INIT(GicITSHwId, GicITSBase) \ + { \ + EFI_ACPI_6_1_GIC_ITS, sizeof (EFI_ACPI_6_1_GIC_ITS_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicITSHwId, GicITSBase, EFI_ACPI_RESERVED_DWORD\ + } + +#define EFI_ACPI_5_1_GICR_STRUCTURE_INIT( \ + GicRBase, GicRlength) \ + { \ + EFI_ACPI_5_1_GICR, sizeof (EFI_ACPI_5_1_GICR_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicRBase, GicRlength \ + } + +#define EFI_ACPI_6_1_GICC_AFFINITY_STRUCTURE_INIT( \ + ProximityDomain, ACPIProcessorUID, Flags, ClockDomain) \ + { \ + 3, sizeof (EFI_ACPI_6_1_GICC_AFFINITY_STRUCTURE),ProximityDomain , \ + ACPIProcessorUID, Flags, ClockDomain \ + } + +#define EFI_ACPI_6_2_ITS_AFFINITY_STRUCTURE_INIT( \ + ProximityDomain, ItsId) \ + { \ + 4, sizeof (EFI_ACPI_6_2_ITS_AFFINITY_STRUCTURE), ProximityDomain, \ + EFI_ACPI_RESERVED_WORD, ItsId \ + } + +#define EFI_ACPI_6_1_MEMORY_AFFINITY_STRUCTURE_INIT( \ + ProximityDomain, AddressBaseLow, AddressBaseHigh, LengthLow, LengthHigh, Flags) \ + { \ + 1, sizeof (EFI_ACPI_6_1_MEMORY_AFFINITY_STRUCTURE),ProximityDomain , EFI_ACPI_RESERVED_WORD, \ + AddressBaseLow, AddressBaseHigh, LengthLow, LengthHigh, EFI_ACPI_RESERVED_DWORD, Flags, \ + EFI_ACPI_RESERVED_QWORD \ + } + +#define EFI_ACPI_6_1_GICC_STRUCTURE_INIT(GicId, AcpiCpuUid, Mpidr, Flags, PmuIrq, \ + GicBase, GicVBase, GicHBase, GsivId, GicRBase, ProcessorPowerEfficiencyClass) \ + { \ + EFI_ACPI_6_1_GIC, sizeof (EFI_ACPI_6_1_GIC_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicId, AcpiCpuUid, Flags, 0, PmuIrq, 0, GicBase, GicVBase, GicHBase, \ + GsivId, GicRBase, Mpidr, ProcessorPowerEfficiencyClass, {0, 0, 0} \ + } + +#define EFI_ACPI_6_1_GIC_DISTRIBUTOR_INIT(GicDistHwId, GicDistBase, GicDistVector, GicVersion) \ + { \ + EFI_ACPI_6_1_GICD, sizeof (EFI_ACPI_6_1_GIC_DISTRIBUTOR_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicDistHwId, GicDistBase, GicDistVector, GicVersion, \ + {EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE} \ + } + + +#pragma pack(1) +// +// Define the number of each table type. +// This is where the table layout is modified. +// +#define EFI_ACPI_PROCESSOR_LOCAL_GICC_AFFINITY_STRUCTURE_COUNT (MAX_SOCKET*CORE_NUM_PER_SOCKET) + +typedef struct { + EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER Header; + EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE Memory[EFI_ACPI_MEMORY_AFFINITY_STRUCTURE_COUNT]; + EFI_ACPI_6_2_GICC_AFFINITY_STRUCTURE Gicc[EFI_ACPI_PROCESSOR_LOCAL_GICC_AFFINITY_STRUCTURE_COUNT]; + EFI_ACPI_6_2_ITS_AFFINITY_STRUCTURE Its[EFI_ACPI_6_2_ITS_AFFINITY_STRUCTURE_COUNT]; +} EFI_ACPI_STATIC_RESOURCE_AFFINITY_TABLE; + +#pragma pack() +#endif + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AnalogixDpLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AnalogixDpLib.h new file mode 100644 index 0000000..6ae5ea3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/AnalogixDpLib.h @@ -0,0 +1,1032 @@ +/** @file LcdHwLib.h + + This file contains interface functions for LcdHwLib of ArmPlatformPkg + + Copyright (c) 2017, ARM Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __ANALOGIXDP_H__ +#define __ANALOGIXDP_H__ + +#include +#include +#include +#include +#include +#include + +#define REG_DUMP 0 + +#define EREMOTEIO 121 /* Remote I/O error */ +#define EINVAL 22 /* Invalid argument */ +#define ETIMEDOUT 110 /* Connection timed out */ + +#define ANALOGIX_DP0_REG_BASE 0xFDEC0000 +#define ANALOGIX_DP1_REG_BASE 0xFDED0000 + +#define ANALOGIX_DP_TX_SW_RESET 0x14 +#define ANALOGIX_DP_FUNC_EN_1 0x18 +#define ANALOGIX_DP_FUNC_EN_2 0x1C +#define ANALOGIX_DP_VIDEO_CTL_1 0x20 +#define ANALOGIX_DP_VIDEO_CTL_2 0x24 +#define ANALOGIX_DP_VIDEO_CTL_3 0x28 + +#define ANALOGIX_DP_VIDEO_CTL_8 0x3C +#define ANALOGIX_DP_VIDEO_CTL_10 0x44 + +#define ANALOGIX_DP_TOTAL_LINE_CFG_L 0x48 +#define ANALOGIX_DP_TOTAL_LINE_CFG_H 0x4C +#define ANALOGIX_DP_ACTIVE_LINE_CFG_L 0x50 +#define ANALOGIX_DP_ACTIVE_LINE_CFG_H 0x54 +#define ANALOGIX_DP_V_F_PORCH_CFG 0x58 +#define ANALOGIX_DP_V_SYNC_WIDTH_CFG 0x5C +#define ANALOGIX_DP_V_B_PORCH_CFG 0x60 +#define ANALOGIX_DP_TOTAL_PIXEL_CFG_L 0x64 +#define ANALOGIX_DP_TOTAL_PIXEL_CFG_H 0x68 +#define ANALOGIX_DP_ACTIVE_PIXEL_CFG_L 0x6C +#define ANALOGIX_DP_ACTIVE_PIXEL_CFG_H 0x70 +#define ANALOGIX_DP_H_F_PORCH_CFG_L 0x74 +#define ANALOGIX_DP_H_F_PORCH_CFG_H 0x78 +#define ANALOGIX_DP_H_SYNC_CFG_L 0x7C +#define ANALOGIX_DP_H_SYNC_CFG_H 0x80 +#define ANALOGIX_DP_H_B_PORCH_CFG_L 0x84 +#define ANALOGIX_DP_H_B_PORCH_CFG_H 0x88 + +#define ANALOGIX_DP_PLL_REG_1 0xfc +#define ANALOGIX_DP_PLL_REG_2 0x9e4 +#define ANALOGIX_DP_PLL_REG_3 0x9e8 +#define ANALOGIX_DP_PLL_REG_4 0x9ec +#define ANALOGIX_DP_PLL_REG_5 0xa00 + +#define ANALOGIX_DP_BIAS 0x124 +#define ANALOGIX_DP_PD 0x12c + +#define ANALOGIX_DP_LANE_MAP 0x35C + +#define ANALOGIX_DP_ANALOG_CTL_1 0x370 +#define ANALOGIX_DP_ANALOG_CTL_2 0x374 +#define ANALOGIX_DP_ANALOG_CTL_3 0x378 +#define ANALOGIX_DP_PLL_FILTER_CTL_1 0x37C +#define ANALOGIX_DP_TX_AMP_TUNING_CTL 0x380 + +#define ANALOGIX_DP_AUX_HW_RETRY_CTL 0x390 + +#define ANALOGIX_DP_COMMON_INT_STA_1 0x3C4 +#define ANALOGIX_DP_COMMON_INT_STA_2 0x3C8 +#define ANALOGIX_DP_COMMON_INT_STA_3 0x3CC +#define ANALOGIX_DP_COMMON_INT_STA_4 0x3D0 + +#define ANALOGIX_DP_INT_STA 0x3DC +#define ANALOGIX_DP_COMMON_INT_MASK_1 0x3E0 +#define ANALOGIX_DP_COMMON_INT_MASK_2 0x3E4 +#define ANALOGIX_DP_COMMON_INT_MASK_3 0x3E8 +#define ANALOGIX_DP_COMMON_INT_MASK_4 0x3EC +#define ANALOGIX_DP_INT_STA_MASK 0x3F8 +#define ANALOGIX_DP_INT_CTL 0x3FC + +#define ANALOGIX_DP_SYS_CTL_1 0x600 +#define ANALOGIX_DP_SYS_CTL_2 0x604 +#define ANALOGIX_DP_SYS_CTL_3 0x608 +#define ANALOGIX_DP_SYS_CTL_4 0x60C + +#define ANALOGIX_DP_PKT_SEND_CTL 0x640 +#define ANALOGIX_DP_HDCP_CTL 0x648 + +#define ANALOGIX_DP_LINK_BW_SET 0x680 +#define ANALOGIX_DP_LANE_COUNT_SET 0x684 +#define ANALOGIX_DP_TRAINING_PTN_SET 0x688 +#define ANALOGIX_DP_LN0_LINK_TRAINING_CTL 0x68C +#define ANALOGIX_DP_LN1_LINK_TRAINING_CTL 0x690 +#define ANALOGIX_DP_LN2_LINK_TRAINING_CTL 0x694 +#define ANALOGIX_DP_LN3_LINK_TRAINING_CTL 0x698 + +#define ANALOGIX_DP_DEBUG_CTL 0x6C0 +#define ANALOGIX_DP_HPD_DEGLITCH_L 0x6C4 +#define ANALOGIX_DP_HPD_DEGLITCH_H 0x6C8 +#define ANALOGIX_DP_LINK_DEBUG_CTL 0x6E0 + +#define ANALOGIX_DP_M_VID_0 0x700 +#define ANALOGIX_DP_M_VID_1 0x704 +#define ANALOGIX_DP_M_VID_2 0x708 +#define ANALOGIX_DP_N_VID_0 0x70C +#define ANALOGIX_DP_N_VID_1 0x710 +#define ANALOGIX_DP_N_VID_2 0x714 + +#define ANALOGIX_DP_PLL_CTL 0x71C +#define ANALOGIX_DP_PHY_PD 0x720 +#define ANALOGIX_DP_PHY_TEST 0x724 + +#define ANALOGIX_DP_VIDEO_FIFO_THRD 0x730 +#define ANALOGIX_DP_AUDIO_MARGIN 0x73C + +#define ANALOGIX_DP_M_VID_GEN_FILTER_TH 0x764 +#define ANALOGIX_DP_M_AUD_GEN_FILTER_TH 0x778 +#define ANALOGIX_DP_AUX_CH_STA 0x780 +#define ANALOGIX_DP_AUX_CH_DEFER_CTL 0x788 +#define ANALOGIX_DP_AUX_RX_COMM 0x78C +#define ANALOGIX_DP_BUFFER_DATA_CTL 0x790 +#define ANALOGIX_DP_AUX_CH_CTL_1 0x794 +#define ANALOGIX_DP_AUX_ADDR_7_0 0x798 +#define ANALOGIX_DP_AUX_ADDR_15_8 0x79C +#define ANALOGIX_DP_AUX_ADDR_19_16 0x7A0 +#define ANALOGIX_DP_AUX_CH_CTL_2 0x7A4 + +#define ANALOGIX_DP_BUF_DATA_0 0x7C0 + +#define ANALOGIX_DP_SOC_GENERAL_CTL 0x800 + +/* ANALOGIX_DP_TX_SW_RESET */ +#define RESET_DP_TX (0x1 << 0) + +/* ANALOGIX_DP_FUNC_EN_1 */ +#define MASTER_VID_FUNC_EN_N (0x1 << 7) +#define SLAVE_VID_FUNC_EN_N (0x1 << 5) +#define AUD_FIFO_FUNC_EN_N (0x1 << 4) +#define AUD_FUNC_EN_N (0x1 << 3) +#define HDCP_FUNC_EN_N (0x1 << 2) +#define CRC_FUNC_EN_N (0x1 << 1) +#define SW_FUNC_EN_N (0x1 << 0) + +/* ANALOGIX_DP_FUNC_EN_2 */ +#define SSC_FUNC_EN_N (0x1 << 7) +#define AUX_FUNC_EN_N (0x1 << 2) +#define SERDES_FIFO_FUNC_EN_N (0x1 << 1) +#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0) + +/* ANALOGIX_DP_VIDEO_CTL_1 */ +#define VIDEO_EN (0x1 << 7) +#define HDCP_VIDEO_MUTE (0x1 << 6) + +/* ANALOGIX_DP_VIDEO_CTL_1 */ +#define IN_D_RANGE_MASK (0x1 << 7) +#define IN_D_RANGE_SHIFT (7) +#define IN_D_RANGE_CEA (0x1 << 7) +#define IN_D_RANGE_VESA (0x0 << 7) +#define IN_BPC_MASK (0x7 << 4) +#define IN_BPC_SHIFT (4) +#define IN_BPC_12_BITS (0x3 << 4) +#define IN_BPC_10_BITS (0x2 << 4) +#define IN_BPC_8_BITS (0x1 << 4) +#define IN_BPC_6_BITS (0x0 << 4) +#define IN_COLOR_F_MASK (0x3 << 0) +#define IN_COLOR_F_SHIFT (0) +#define IN_COLOR_F_YCBCR444 (0x2 << 0) +#define IN_COLOR_F_YCBCR422 (0x1 << 0) +#define IN_COLOR_F_RGB (0x0 << 0) + +/* ANALOGIX_DP_VIDEO_CTL_3 */ +#define IN_YC_COEFFI_MASK (0x1 << 7) +#define IN_YC_COEFFI_SHIFT (7) +#define IN_YC_COEFFI_ITU709 (0x1 << 7) +#define IN_YC_COEFFI_ITU601 (0x0 << 7) +#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4) +#define VID_CHK_UPDATE_TYPE_SHIFT (4) +#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) +#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) + +/* ANALOGIX_DP_VIDEO_CTL_8 */ +#define VID_HRES_TH(x) (((x) & 0xf) << 4) +#define VID_VRES_TH(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_VIDEO_CTL_10 */ +#define FORMAT_SEL (0x1 << 4) +#define INTERACE_SCAN_CFG (0x1 << 2) +#define VSYNC_POLARITY_CFG (0x1 << 1) +#define HSYNC_POLARITY_CFG (0x1 << 0) + +/* ANALOGIX_DP_TOTAL_LINE_CFG_L */ +#define TOTAL_LINE_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_TOTAL_LINE_CFG_H */ +#define TOTAL_LINE_CFG_H(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_ACTIVE_LINE_CFG_L */ +#define ACTIVE_LINE_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_ACTIVE_LINE_CFG_H */ +#define ACTIVE_LINE_CFG_H(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_V_F_PORCH_CFG */ +#define V_F_PORCH_CFG(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_V_SYNC_WIDTH_CFG */ +#define V_SYNC_WIDTH_CFG(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_V_B_PORCH_CFG */ +#define V_B_PORCH_CFG(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_TOTAL_PIXEL_CFG_L */ +#define TOTAL_PIXEL_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_TOTAL_PIXEL_CFG_H */ +#define TOTAL_PIXEL_CFG_H(x) (((x) & 0x3f) << 0) + +/* ANALOGIX_DP_ACTIVE_PIXEL_CFG_L */ +#define ACTIVE_PIXEL_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_ACTIVE_PIXEL_CFG_H */ +#define ACTIVE_PIXEL_CFG_H(x) (((x) & 0x3f) << 0) + +/* ANALOGIX_DP_H_F_PORCH_CFG_L */ +#define H_F_PORCH_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_H_F_PORCH_CFG_H */ +#define H_F_PORCH_CFG_H(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_H_SYNC_CFG_L */ +#define H_SYNC_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_H_SYNC_CFG_H */ +#define H_SYNC_CFG_H(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_H_B_PORCH_CFG_L */ +#define H_B_PORCH_CFG_L(x) (((x) & 0xff) << 0) + +/* ANALOGIX_DP_H_B_PORCH_CFG_H */ +#define H_B_PORCH_CFG_H(x) (((x) & 0xf) << 0) + +/* ANALOGIX_DP_PLL_REG_1 */ +#define REF_CLK_24M (0x1 << 0) +#define REF_CLK_27M (0x0 << 0) +#define REF_CLK_MASK (0x1 << 0) + +/* ANALOGIX_DP_LANE_MAP */ +#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) +#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) +#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6) +#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6) +#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4) +#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4) +#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4) +#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4) +#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2) +#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2) +#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2) +#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2) +#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0) +#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0) +#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) +#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) + +/* ANALOGIX_DP_ANALOG_CTL_1 */ +#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4) + +/* ANALOGIX_DP_ANALOG_CTL_2 */ +#define SEL_24M (0x1 << 3) +#define TX_DVDD_BIT_1_0625V (0x4 << 0) + +/* ANALOGIX_DP_ANALOG_CTL_3 */ +#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5) +#define VCO_BIT_600_MICRO (0x5 << 0) + +/* ANALOGIX_DP_PLL_FILTER_CTL_1 */ +#define PD_RING_OSC (0x1 << 6) +#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) +#define TX_CUR1_2X (0x1 << 2) +#define TX_CUR_16_MA (0x3 << 0) + +/* ANALOGIX_DP_TX_AMP_TUNING_CTL */ +#define CH3_AMP_400_MV (0x0 << 24) +#define CH2_AMP_400_MV (0x0 << 16) +#define CH1_AMP_400_MV (0x0 << 8) +#define CH0_AMP_400_MV (0x0 << 0) + +/* ANALOGIX_DP_AUX_HW_RETRY_CTL */ +#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) +#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) +#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3) +#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3) +#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3) +#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3) +#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0) + +/* ANALOGIX_DP_COMMON_INT_STA_1 */ +#define VSYNC_DET (0x1 << 7) +#define PLL_LOCK_CHG (0x1 << 6) +#define SPDIF_ERR (0x1 << 5) +#define SPDIF_UNSTBL (0x1 << 4) +#define VID_FORMAT_CHG (0x1 << 3) +#define AUD_CLK_CHG (0x1 << 2) +#define VID_CLK_CHG (0x1 << 1) +#define SW_INT (0x1 << 0) + +/* ANALOGIX_DP_COMMON_INT_STA_2 */ +#define ENC_EN_CHG (0x1 << 6) +#define HW_BKSV_RDY (0x1 << 3) +#define HW_SHA_DONE (0x1 << 2) +#define HW_AUTH_STATE_CHG (0x1 << 1) +#define HW_AUTH_DONE (0x1 << 0) + +/* ANALOGIX_DP_COMMON_INT_STA_3 */ +#define AFIFO_UNDER (0x1 << 7) +#define AFIFO_OVER (0x1 << 6) +#define R0_CHK_FLAG (0x1 << 5) + +/* ANALOGIX_DP_COMMON_INT_STA_4 */ +#define PSR_ACTIVE (0x1 << 7) +#define PSR_INACTIVE (0x1 << 6) +#define SPDIF_BI_PHASE_ERR (0x1 << 5) +#define HOTPLUG_CHG (0x1 << 2) +#define HPD_LOST (0x1 << 1) +#define PLUG (0x1 << 0) + +/* ANALOGIX_DP_INT_STA */ +#define INT_HPD (0x1 << 6) +#define HW_TRAINING_FINISH (0x1 << 5) +#define RPLY_RECEIV (0x1 << 1) +#define AUX_ERR (0x1 << 0) + +/* ANALOGIX_DP_INT_CTL */ +#define SOFT_INT_CTRL (0x1 << 2) +#define INT_POL1 (0x1 << 1) +#define INT_POL0 (0x1 << 0) + +/* ANALOGIX_DP_SYS_CTL_1 */ +#define DET_STA (0x1 << 2) +#define FORCE_DET (0x1 << 1) +#define DET_CTRL (0x1 << 0) + +/* ANALOGIX_DP_SYS_CTL_2 */ +#define CHA_CRI(x) (((x) & 0xf) << 4) +#define CHA_STA (0x1 << 2) +#define FORCE_CHA (0x1 << 1) +#define CHA_CTRL (0x1 << 0) + +/* ANALOGIX_DP_SYS_CTL_3 */ +#define HPD_STATUS (0x1 << 6) +#define F_HPD (0x1 << 5) +#define HPD_CTRL (0x1 << 4) +#define HDCP_RDY (0x1 << 3) +#define STRM_VALID (0x1 << 2) +#define F_VALID (0x1 << 1) +#define VALID_CTRL (0x1 << 0) + +/* ANALOGIX_DP_SYS_CTL_4 */ +#define FIX_M_AUD (0x1 << 4) +#define ENHANCED (0x1 << 3) +#define FIX_M_VID (0x1 << 2) +#define M_VID_UPDATE_CTRL (0x3 << 0) + +/* ANALOGIX_DP_TRAINING_PTN_SET */ +#define SCRAMBLER_TYPE (0x1 << 9) +#define HW_LINK_TRAINING_PATTERN (0x1 << 8) +#define SCRAMBLING_DISABLE (0x1 << 5) +#define SCRAMBLING_ENABLE (0x0 << 5) +#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2) +#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2) +#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2) +#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2) +#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0) +#define SW_TRAINING_PATTERN_SET_PTN3 (0x3 << 0) +#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0) +#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0) +#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) + +/* ANALOGIX_DP_LN0_LINK_TRAINING_CTL */ +#define PRE_EMPHASIS_SET_MASK (0x3 << 3) +#define PRE_EMPHASIS_SET_SHIFT (3) + +/* ANALOGIX_DP_DEBUG_CTL */ +#define PLL_LOCK (0x1 << 4) +#define F_PLL_LOCK (0x1 << 3) +#define PLL_LOCK_CTRL (0x1 << 2) +#define PN_INV (0x1 << 0) + +/* ANALOGIX_DP_PLL_CTL */ +#define DP_PLL_PD (0x1 << 7) +#define DP_PLL_RESET (0x1 << 6) +#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4) +#define DP_PLL_REF_BIT_1_1250V (0x5 << 0) +#define DP_PLL_REF_BIT_1_2500V (0x7 << 0) + +/* ANALOGIX_DP_PHY_PD */ +#define DP_PHY_PD (0x1 << 5) +#define AUX_PD (0x1 << 4) +#define CH3_PD (0x1 << 3) +#define CH2_PD (0x1 << 2) +#define CH1_PD (0x1 << 1) +#define CH0_PD (0x1 << 0) + +/* ANALOGIX_DP_PHY_TEST */ +#define MACRO_RST (0x1 << 5) +#define CH1_TEST (0x1 << 1) +#define CH0_TEST (0x1 << 0) + +/* ANALOGIX_DP_AUX_CH_STA */ +#define AUX_BUSY (0x1 << 4) +#define AUX_STATUS_MASK (0xf << 0) + +/* ANALOGIX_DP_AUX_CH_DEFER_CTL */ +#define DEFER_CTRL_EN (0x1 << 7) +#define DEFER_COUNT(x) (((x) & 0x7f) << 0) + +/* ANALOGIX_DP_AUX_RX_COMM */ +#define AUX_RX_COMM_I2C_DEFER (0x2 << 2) +#define AUX_RX_COMM_AUX_DEFER (0x2 << 0) + +/* ANALOGIX_DP_BUFFER_DATA_CTL */ +#define BUF_CLR (0x1 << 7) +#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0) + +/* ANALOGIX_DP_AUX_CH_CTL_1 */ +#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4) +#define AUX_TX_COMM_MASK (0xf << 0) +#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3) +#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3) +#define AUX_TX_COMM_MOT (0x1 << 2) +#define AUX_TX_COMM_WRITE (0x0 << 0) +#define AUX_TX_COMM_READ (0x1 << 0) + +/* ANALOGIX_DP_AUX_ADDR_7_0 */ +#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff) + +/* ANALOGIX_DP_AUX_ADDR_15_8 */ +#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff) + +/* ANALOGIX_DP_AUX_ADDR_19_16 */ +#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f) + +/* ANALOGIX_DP_AUX_CH_CTL_2 */ +#define ADDR_ONLY (0x1 << 1) +#define AUX_EN (0x1 << 0) + +/* ANALOGIX_DP_SOC_GENERAL_CTL */ +#define AUDIO_MODE_SPDIF_MODE (0x1 << 8) +#define AUDIO_MODE_MASTER_MODE (0x0 << 8) +#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4) +#define VIDEO_MASTER_CLK_SEL (0x1 << 2) +#define VIDEO_MASTER_MODE_EN (0x1 << 1) +#define VIDEO_MODE_MASK (0x1 << 0) +#define VIDEO_MODE_SLAVE_MODE (0x1 << 0) +#define VIDEO_MODE_MASTER_MODE (0x0 << 0) + +#define DP_TIMEOUT_LOOP_COUNT 100 +#define MAX_CR_LOOP 5 +#define MAX_EQ_LOOP 5 + +/* I2C EDID Chip ID, Slave Address */ +#define I2C_EDID_DEVICE_ADDR 0x50 +#define I2C_E_EDID_DEVICE_ADDR 0x30 + +#define EDID_BLOCK_LENGTH 0x80 +#define EDID_HEADER_PATTERN 0x00 +#define EDID_EXTENSION_FLAG 0x7e +#define EDID_CHECKSUM 0x7f + +/* DP_MAX_LANE_COUNT */ +#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) +#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) + +/* DP_LANE_COUNT_SET */ +#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) + +/* DP_TRAINING_LANE0_SET */ +#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) +#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) +#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) +#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) + +/* HDPTXPHy_GRF*/ +#define HDPTXPHY0_GRF_BASE 0xFD5E0000 +#define HDPTXPHY1_GRF_BASE 0xFD5E4000 +#define HDPTXPHY_GRF_CON0 0x00 +#define HDPTXPHY_GRF_CON1 0x04 +#define HDPTXPHY_GRF_STATUS0 0x80 +#define PCS_BIASES 0x27c +#define O_PLL_LOCK 0x280 +#define O_PLL_LOCK_done (0x1<<3) +#define O_PHY_RDY ((0x1<<1)&(0x1<<3)) + +/* ENABLE_BIASES */ +#define ENABLE_BIASES_LANE6 (0x1<<6) +#define ENABLE_BIASES_LANE7 (0x1<<7) + +/* INITIAL POR RESET*/ +#define INITIAL_POR_RESET_LANE2 (0x1<<2) +#define INITIAL_POR_RESET_LANE3 (0x1<<3) + +/* DRM_DP_HELPER */ +#define DP_RECEIVER_CAP_SIZE 0xf +#define EDP_PSR_RECEIVER_CAP_SIZE 2 +#define EDP_DISPLAY_CTL_CAP_SIZE 3 + +#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +# define DP_TRAINING_AUX_RD_MASK 0x7F /* XXX 1.2? */ +# define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */ + +#define DP_SET_POWER 0x600 +# define DP_SET_POWER_D0 0x1 +# define DP_SET_POWER_D3 0x2 +# define DP_SET_POWER_MASK 0x3 +# define DP_SET_POWER_D3_AUX_ON 0x5 + +#define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ +# define DP_EDP_11 0x00 +# define DP_EDP_12 0x01 +# define DP_EDP_13 0x02 +# define DP_EDP_14 0x03 + +#define DP_TRAINING_LANE0_SET 0x103 +#define DP_TRAINING_LANE1_SET 0x104 +#define DP_TRAINING_LANE2_SET 0x105 +#define DP_TRAINING_LANE3_SET 0x106 + +# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 +# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 +# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0) + +# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3) + +# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 +# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + +#define DP_TEST_REQUEST 0x218 +# define DP_TEST_LINK_TRAINING (1 << 0) +# define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) +# define DP_TEST_LINK_EDID_READ (1 << 2) +# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ +# define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ + +#define DP_ADJUST_REQUEST_LANE0_1 0x206 +#define DP_TEST_RESPONSE 0x260 +# define DP_TEST_ACK (1 << 0) +# define DP_TEST_NAK (1 << 1) +# define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) + +#define DP_TEST_EDID_CHECKSUM 0x261 + +/* AUX CH addresses */ +/* DPCD */ +#define DP_DPCD_REV 0x000 +# define DP_DPCD_REV_10 0x10 +# define DP_DPCD_REV_11 0x11 +# define DP_DPCD_REV_12 0x12 +# define DP_DPCD_REV_13 0x13 +# define DP_DPCD_REV_14 0x14 + +#define EDP0TX_PHY_BASE 0xFED60000 +#define EDP1TX_PHY_BASE 0xFED70000 + +#define DP_MAX_LANE_COUNT 0x002 +# define DP_MAX_LANE_COUNT_MASK 0x1f +# define DP_TPS3_SUPPORTED (1 << 6) /* 1.2 */ +# define DP_ENHANCED_FRAME_CAP (1 << 7) +#define DP_INC_BG (0x1 << 7) +#define DP_EXP_BG (0x1 << 6) +#define RK_AUX_PD (0x1 << 5) +#define AUX_PD (0x1 << 4) +#define RK_PLL_PD (0x1 << 4) +#define CH3_PD (0x1 << 3) +#define CH2_PD (0x1 << 2) +#define CH1_PD (0x1 << 1) +#define CH0_PD (0x1 << 0) + +enum LinkLaneCountType { + LANE_COUNT1 = 1, + LANE_COUNT2 = 2, + LANE_COUNT4 = 4 +}; + +enum LinkTrainingState { + START, + CLOCK_RECOVERY, + EQUALIZER_TRAINING, + FINISHED, + FAILED +}; + +enum VoltageSwingLevel { + VOLTAGE_LEVEL_0, + VOLTAGE_LEVEL_1, + VOLTAGE_LEVEL_2, + VOLTAGE_LEVEL_3, +}; + +enum PreEmphasisLevel { + PRE_EMPHASIS_LEVEL_0, + PRE_EMPHASIS_LEVEL_1, + PRE_EMPHASIS_LEVEL_2, + PRE_EMPHASIS_LEVEL_3, +}; + +enum PatternSet { + PRBS7, + D10_2, + TRAINING_PTN1, + TRAINING_PTN2, + TRAINING_PTN3, + DP_NONE +}; + +enum ColorSpace { + COLOR_RGB, + COLOR_YCBCR422, + COLOR_YCBCR444 +}; + +enum ColorDepth { + COLOR_6, + COLOR_8, + COLOR_10, + COLOR_12 +}; + +enum ColorCoefficient { + COLOR_YCBCR601, + COLOR_YCBCR709 +}; + +enum DynamicRange { + VESA, + CEA +}; + +enum PllStatus { + PLL_UNLOCKED, + PLL_LOCKED +}; + +enum ClockRecoveryMValueType { + CALCULATED_M, + REGISTER_M +}; + +enum VideoTimingRecognitionType { + VIDEO_TIMING_FROM_CAPTURE, + VIDEO_TIMING_FROM_REGISTER +}; + +enum AnalogPowerBlock { + AUX_BLOCK, + CH0_BLOCK, + CH1_BLOCK, + CH2_BLOCK, + CH3_BLOCK, + ANALOG_TOTAL, + POWER_ALL +}; + +struct VideoInfo { + char *Name; + + BOOLEAN HSyncPolarity; + BOOLEAN VSyncPolarity; + BOOLEAN Interlaced; + + enum ColorSpace ColorSpace; + enum DynamicRange DynamicRange; + enum ColorCoefficient Ycbcr_Coeff; + enum ColorDepth ColorDepth; + + UINTN MaxLinkRate; + enum LinkLaneCountType MaxLaneCount; +}; + +struct LinkTrain { + INT32 EqLoop; + INT32 CrLoop[4]; + UINT8 LinkRate; + UINT8 LaneCount; + UINT8 TrainingLane[4]; + BOOLEAN SSC; + + enum LinkTrainingState LtState; +}; + +struct AnalogixDpDevice { + UINT32 Id; + BOOLEAN ForceHpd; + struct VideoInfo VideoInfo; + struct LinkTrain LinkTrain; + struct DrmDisplayMode *MODE; + unsigned char EDID[EDID_BLOCK_LENGTH * 2]; + UINT8 Dpcd[DP_RECEIVER_CAP_SIZE]; + UINT8 Edid[EDID_BLOCK_LENGTH * 2]; + UINT32 LaneMap[4]; +}; + +/* Rockchip Htx Phy */ + +struct RockchipHdptxPhy { + UINT32 Id; + UINT32 LANE_POLARITY_INVERT[4]; +}; + +struct PhyConfigureOptsDp { + UINTN LINKRATE; + UINTN LANES; + UINTN VOLTAGE[4]; + UINTN PRE[4]; + UINT8 SSC : 1; + UINT8 SETRATE : 1; + UINT8 SETLANES : 1; + UINT8 SETVOLTAGES : 1; +}; + +/* AnalogixDpReg.c */ +VOID +AnalogixDpRegWrite ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 Offset, + IN UINT32 Value + ); + +UINT32 +AnalogixDpRegRead ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 Offset + ); + +VOID +AnalogixDpEnableVideoMute ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ); + +VOID +AnalogixDpLaneSwap ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ); + +VOID +AnalogixDpStopVideo ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpReset ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpSwreset ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpInitAnalogParam ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpInitInterrupt ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpEnableSwFunction ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpConfigInterrupt ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpSetPllPowerDown ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ); + +VOID +AnalogixDpInitHpd ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpClearHotplugInterrupts ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpInitAux ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpResetAux ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpInitAnalogFunc ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpSetAnalogPowerDown ( + OUT struct AnalogixDpDevice *Dp, + enum AnalogPowerBlock Block, + BOOLEAN Enable + ); + +BOOLEAN +AnalogixDpTps3Supported ( + OUT struct AnalogixDpDevice *Dp + ); + +INT32 +AnalogixDpReadByteFromDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT8 *Data + ); + +INT32 +AnalogixDpWriteByteToDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT8 Data + ); + +INT32 +AnalogixDpStartAuxTransaction ( + OUT struct AnalogixDpDevice *Dp + ); + +INT32 +AnalogixDpReadBytesFromDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT32 Count, + IN UINT8 Data[] + ); + +INT32 +AnalogixDpWriteBytesToDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT32 Count, + IN UINT8 Data[] + ); + +VOID +AnalogixDpSetTrainingPattern ( + OUT struct AnalogixDpDevice *Dp, + OUT enum PatternSet Pattern + ); + +UINT32 +AnalogixDpGetLaneLinkTraining ( + OUT struct AnalogixDpDevice *Dp, + IN UINT8 Lane + ); + +VOID +AnalogixDpGetLinkBandwidth ( + OUT struct AnalogixDpDevice *Dp, + UINT32 *BwType + ); + +VOID +AnalogixDpGetLaneCount ( + OUT struct AnalogixDpDevice *Dp, + UINT32 *Count + ); + +VOID +AnalogixDpEnableVideoMaster ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ); + +VOID +AnalogixDpStartVideo ( + OUT struct AnalogixDpDevice *Dp + ); + +INTN AnalogixDpIsVideoStreamOn ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpEnableScrambling ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpDisableScrambling ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +AnalogixDpSetVideoFormat ( + OUT struct AnalogixDpDevice *Dp, + OUT CONST DRM_DISPLAY_MODE *Mode + ); + +INTN +AnalogixDpSelectI2cDevice ( + OUT struct AnalogixDpDevice *Dp, + UINTN DeviceAddr, + UINTN RegAddr + ); + +INTN +AnalogixDpReadByteFromI2c ( + struct AnalogixDpDevice *dp, + UINTN DeviceAddr, + UINTN RegAddr, + UINTN *DATA + ); + +INTN +AnalogixDpReadBytesFromI2c ( + OUT struct AnalogixDpDevice *Dp, + UINTN DeviceAddr, + UINTN RegAddr, + UINTN Count, + UINT8 Edid[] + ); + +VOID +AnalogixDpSetLaneLinkTraining ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +RockchipHdptxPhyInit ( + OUT struct RockchipHdptxPhy *Hdptx + ); + +INTN +RockchipHdptxPhySetRate ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ); + +INTN +RockchipHdptxPhySetVoltages ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ); + +INTN +RockchipHdptxPhyConfigure ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ); + +INT32 +AnalogixDpIsSlaveVideoStreamClockOn ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +DumpDpRegisters ( + OUT struct AnalogixDpDevice *Dp + ); + +VOID +DumpHdptxPhyRegisters ( + OUT struct AnalogixDpDevice *Dp + ); + +EFI_STATUS +AnalogixDpConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +AnalogixDpConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +AnalogixDpConnectorGetEdid ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +AnalogixDpConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +AnalogixDpConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +AnalogixDpConnectorDetect ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/BaseVariableLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/BaseVariableLib.h new file mode 100644 index 0000000..7cfdf92 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/BaseVariableLib.h @@ -0,0 +1,90 @@ +/** @file + * + * Read-only non-volatile variable service library for early SEC phase. + * Based on FaultTolerantWritePei and VariablePei, without using any HOBs. + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
    + * Copyright (c) Microsoft Corporation.
    + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __BASE_VARIABLE_LIB_H__ +#define __BASE_VARIABLE_LIB_H__ + +#include + +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + May be NULL with a zero DataSize in order to determine the size of the buffer needed. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +BaseGetVariable ( + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ); + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + + @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +BaseGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ); + +#endif // __BASE_VARIABLE_LIB_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/CruLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/CruLib.h new file mode 100644 index 0000000..606cfe3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/CruLib.h @@ -0,0 +1,304 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +/** @addtogroup RK_HAL_Driver + * @{ + */ + +/** @addtogroup CRU + * @{ + */ + +#ifndef _HAL_CRU_H_ +#define _HAL_CRU_H_ + +#include "HalDef.h" + +/*************************** MACRO Definition ****************************/ +/** @defgroup CRU_Exported_Definition_Group1 Basic Definition + * @{ + */ + +#define MHZ 1000000 +#define KHZ 1000 + +#ifndef PLL_INPUT_OSC_RATE +#define PLL_INPUT_OSC_RATE (24 * MHZ) +#endif + +#define CRU_CON_REG_ADDRESS(_regBase, _offset, _index) \ + ((_regBase) + (_offset) + ((_index) * sizeof(uint32_t))) + +#define CLK_RESET_GET_REG_OFFSET(x) ((uint32_t)((x) / 16)) +#define CLK_RESET_GET_BITS_SHIFT(x) ((uint32_t)((x) % 16)) + +#define CLK_GATE_GET_REG_OFFSET(x) ((uint32_t)((x) / 16)) +#define CLK_GATE_GET_BITS_SHIFT(x) ((uint32_t)((x) % 16)) + +#define WIDTH_TO_MASK(width) ((1 << (width)) - 1) + +#define CLK_MUX_REG_OFFSET_SHIFT 0U +#define CLK_MUX_REG_OFFSET_MASK 0x0000FFFFU +#define CLK_MUX_SHIFT_SHIFT 16U +#define CLK_MUX_SHIFT_MASK 0x00FF0000U +#define CLK_MUX_WIDTH_SHIFT 24U +#define CLK_MUX_WIDTH_MASK 0xFF000000U + +#define CLK_MUX_GET_REG_OFFSET(x) \ + (((uint32_t)(x) & CLK_MUX_REG_OFFSET_MASK) >> CLK_MUX_REG_OFFSET_SHIFT) +#define CLK_MUX_GET_BITS_SHIFT(x) \ + (((uint32_t)(x) & CLK_MUX_SHIFT_MASK) >> CLK_MUX_SHIFT_SHIFT) +#define CLK_MUX_GET_MASK(x) \ + WIDTH_TO_MASK((((uint32_t)(x) & CLK_MUX_WIDTH_MASK) >> CLK_MUX_WIDTH_SHIFT)) \ + << CLK_MUX_GET_BITS_SHIFT(x) + +#define CLK_DIV_REG_OFFSET_SHIFT 0U +#define CLK_DIV_REG_OFFSET_MASK 0x0000FFFFU +#define CLK_DIV_SHIFT_SHIFT 16U +#define CLK_DIV_SHIFT_MASK 0x00FF0000U +#define CLK_DIV_WIDTH_SHIFT 24U +#define CLK_DIV_WIDTH_MASK 0xFF000000U + +#define CLK_DIV_GET_REG_OFFSET(x) \ + (((uint32_t)(x) & CLK_DIV_REG_OFFSET_MASK) >> CLK_DIV_REG_OFFSET_SHIFT) +#define CLK_DIV_GET_BITS_SHIFT(x) \ + (((uint32_t)(x) & CLK_DIV_SHIFT_MASK) >> CLK_DIV_SHIFT_SHIFT) +#define CLK_DIV_GET_MASK(x) \ + WIDTH_TO_MASK((((uint32_t)(x) & CLK_DIV_WIDTH_MASK) >> CLK_DIV_WIDTH_SHIFT)) \ + << CLK_DIV_GET_BITS_SHIFT(x) + +#define RK_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, \ + _frac) \ + { \ + .rate = _rate##U, .fbDiv = _fbdiv, .postDiv1 = _postdiv1, \ + .refDiv = _refdiv, .postDiv2 = _postdiv2, .dsmpd = _dsmpd, \ + .frac = _frac, \ + } + +#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k) \ + { \ + .rate = _rate##U, .p = _p, .m = _m, \ + .s = _s, .k = _k, \ + } + +struct PLL_CONFIG { + uint32_t rate; + uint32_t fbDiv; + uint32_t postDiv1; + uint32_t refDiv; + uint32_t postDiv2; + uint32_t dsmpd; + uint32_t frac; + uint32_t m; + uint32_t p; + uint32_t s; + uint32_t k; +}; + +struct PLL_SETUP { + __IO uint32_t *conOffset0; + __IO uint32_t *conOffset1; + __IO uint32_t *conOffset2; + __IO uint32_t *conOffset3; + __IO uint32_t *conOffset6; + __IO uint32_t *modeOffset; + __I uint32_t *stat0; + uint32_t modeShift; + uint32_t lockShift; + uint32_t modeMask; + const struct PLL_CONFIG *rateTable; +}; + +typedef enum { + GLB_SRST_FST = 0xfdb9, + GLB_SRST_SND = 0xeca8, +} eCRU_GlbSrstType; + +typedef enum { + GLB_RST_FST_WDT0 = 0U, + GLB_RST_SND_WDT0, + GLB_RST_FST_WDT1, + GLB_RST_SND_WDT1, + GLB_RST_FST_WDT2, + GLB_RST_SND_WDT2, +} eCRU_WdtRstType; + +typedef enum { + CLOCK_SUPPORT_MUX = 1 << 0, + CLOCK_SUPPORT_DIV = 1 << 1, + CLOCK_SUPPORT_GATE = 1 << 2, + CLOCK_SUPPORT_ALL = 0xFFFFFFFF +} CRU_CLOCK_SUPPORT_FLAGS; + +#define CRU_CLOCK_INIT(_id, _regBase, _muxOffset, _mux, \ + _divOffset, _div, _gateOffset, _gate) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_ALL, \ + .muxOffset = _muxOffset, \ + .mux = _mux, \ + .divOffset = _divOffset, \ + .div = _div, \ + .gateOffset = _gateOffset, \ + .gate = _gate, \ + } + +#define CRU_CLOCK_NOMUX_INIT(_id, _regBase, \ + _divOffset, _div, _gateOffset, _gate) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_ALL & ~CLOCK_SUPPORT_MUX, \ + .divOffset = _divOffset, \ + .div = _div, \ + .gateOffset = _gateOffset, \ + .gate = _gate, \ + } + +#define CRU_CLOCK_NODIV_INIT(_id, _regBase, _muxOffset, _mux, \ + _gateOffset, _gate) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_ALL & ~CLOCK_SUPPORT_DIV, \ + .muxOffset = _muxOffset, \ + .mux = _mux, \ + .gateOffset = _gateOffset, \ + .gate = _gate, \ + } + +#define CRU_CLOCK_NOGATE_INIT(_id, _regBase, _muxOffset, _mux, \ + _divOffset, _div) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_ALL & ~CLOCK_SUPPORT_GATE, \ + .muxOffset = _muxOffset, \ + .mux = _mux, \ + .divOffset = _divOffset, \ + .div = _div, \ + } + +#define CRU_CLOCK_MUX_INIT(_id, _regBase, _muxOffset, _mux) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_MUX, \ + .muxOffset = _muxOffset, \ + .mux = _mux, \ + } + +#define CRU_CLOCK_DIV_INIT(_id, _regBase, _divOffset, _div) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_DIV, \ + .divOffset = _divOffset, \ + .div = _div, \ + } + +#define CRU_CLOCK_GATE_INIT(_id, _regBase, _gateOffset, _gate) \ + [_id] = { \ + .regBase = _regBase, \ + .flags = CLOCK_SUPPORT_GATE, \ + .gateOffset = _gateOffset, \ + .gate = _gate, \ + } + +#define CRU_RESET_INIT(id, _regBase, _srstOffset, _srst) \ + [_id] = { \ + .regBase = _regBase, \ + .srstOffset = _srstOffset, \ + .srst = _srst, \ + } + +/***************************** Structure Definition **************************/ + +typedef struct { + uint64_t regBase; + CRU_CLOCK_SUPPORT_FLAGS flags; + uint32_t muxOffset; + uint32_t mux; + uint32_t divOffset; + uint32_t div; + uint32_t gateOffset; + uint32_t gate; +} CRU_CLOCK; + +typedef struct { + uint64_t regBase; + uint32_t srstOffset; + uint32_t srst; +} CRU_RESET; + +/** @} */ +/***************************** Function Declare ******************************/ +/** @defgroup CRU_Public_Function_Declare Public Function Declare + * @{ + */ + +CRU_CLOCK * HAL_CRU_ClkGetById(uint32_t clockId); +CRU_RESET * HAL_CRU_RstGetById(uint32_t resetId); + +uint32_t HAL_CRU_GetPllFreq(struct PLL_SETUP *pSetup); +HAL_Status HAL_CRU_SetPllFreq(struct PLL_SETUP *pSetup, uint32_t rate); +HAL_Status HAL_CRU_SetPllPowerUp(struct PLL_SETUP *pSetup); +HAL_Status HAL_CRU_SetPllPowerDown(struct PLL_SETUP *pSetup); + +uint32_t HAL_CRU_GetPllV1Freq(struct PLL_SETUP *pSetup); +HAL_Status HAL_CRU_SetPllV1Freq(struct PLL_SETUP *pSetup, uint32_t rate); + +HAL_Check HAL_CRU_ClkIsEnabled(uint32_t clockId); +HAL_Status HAL_CRU_ClkEnable(uint32_t clockId); +HAL_Status HAL_CRU_ClkDisable(uint32_t clockId); + +HAL_Status HAL_CRU_ClkSetDiv(uint32_t clockId, uint32_t divValue); +uint32_t HAL_CRU_ClkGetDiv(uint32_t clockId); + +HAL_Status HAL_CRU_ClkSetMux(uint32_t clockId, uint32_t muxValue); +uint32_t HAL_CRU_ClkGetMux(uint32_t clockId); + +HAL_Status HAL_CRU_FracdivGetConfig(uint32_t rateOut, uint32_t rate, + uint32_t *numerator, + uint32_t *denominator); + +uint32_t HAL_CRU_ClkGetFreq(uint32_t clockId); +HAL_Status HAL_CRU_ClkSetFreq(uint32_t clockId, uint32_t rate); + +HAL_Status HAL_CRU_VopDclkEnable(uint32_t gateId); +HAL_Status HAL_CRU_VopDclkDisable(uint32_t gateId); + +HAL_Status HAL_CRU_ClkNp5BestDiv(uint32_t clockId, uint32_t rate, uint32_t pRate, uint32_t *bestdiv); + +HAL_Status HAL_CRU_SetGlbSrst(eCRU_GlbSrstType type); + +HAL_Status HAL_CRU_WdtGlbRstEnable(eCRU_WdtRstType wdtType); + +HAL_Status HAL_CRU_PllCompensation(uint32_t clockId, int ppm); + +HAL_Check HAL_CRU_RstIsAsserted(uint32_t resetId); +HAL_Status HAL_CRU_RstAssert(uint32_t resetId); +HAL_Status HAL_CRU_RstDeassert(uint32_t resetId); + +#ifdef HAL_CRU_AS_FEATURE_ENABLED +/** + * @brief it is for AS init. + */ +void HAL_CRU_AsInit(void); + +/** + * @brief it is for AS enable. + * @param ch: channel + * @param en: 1 is enable, 0 is disable. + */ +void HAL_CRU_AsEnable(uint8_t ch, uint8_t en); +#endif + +/** @} */ + +#endif + +/** @} */ + +/** @} */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DrmModes.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DrmModes.h new file mode 100644 index 0000000..88a8247 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DrmModes.h @@ -0,0 +1,161 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _DRM_MODES_H +#define _DRM_MODES_H + +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_CONNECTOR_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +/* Video mode flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_FLAG_PHSYNC (1 << 0) +#define DRM_MODE_FLAG_NHSYNC (1 << 1) +#define DRM_MODE_FLAG_PVSYNC (1 << 2) +#define DRM_MODE_FLAG_NVSYNC (1 << 3) +#define DRM_MODE_FLAG_INTERLACE (1 << 4) +#define DRM_MODE_FLAG_DBLSCAN (1 << 5) +#define DRM_MODE_FLAG_CSYNC (1 << 6) +#define DRM_MODE_FLAG_PCSYNC (1 << 7) +#define DRM_MODE_FLAG_NCSYNC (1 << 8) +#define DRM_MODE_FLAG_HSKEW (1 << 9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1 << 10) +#define DRM_MODE_FLAG_PIXMUX (1 << 11) +#define DRM_MODE_FLAG_DBLCLK (1 << 12) +#define DRM_MODE_FLAG_CLKDIV2 (1 << 13) +#define DRM_MODE_FLAG_PPIXDATA BIT(31) + +/* Panel Mirror control */ +#define DRM_MODE_FLAG_XMIRROR (1<<28) +#define DRM_MODE_FLAG_YMIRROR (1<<29) +#define DRM_MODE_FLAG_XYMIRROR (DRM_MODE_FLAG_XMIRROR | DRM_MODE_FLAG_YMIRROR) + +/* Picture aspect ratio options */ +#define DRM_MODE_PICTURE_ASPECT_NONE 0 +#define DRM_MODE_PICTURE_ASPECT_4_3 1 +#define DRM_MODE_PICTURE_ASPECT_16_9 2 +#define DRM_MODE_PICTURE_ASPECT_64_27 3 +#define DRM_MODE_PICTURE_ASPECT_256_135 4 + +/* Aspect ratio flag bitmask (4 bits 22:19) */ +#define DRM_MODE_FLAG_PIC_AR_MASK (0x0F << 19) +#define DRM_MODE_FLAG_PIC_AR_NONE \ + (DRM_MODE_PICTURE_ASPECT_NONE << 19) +#define DRM_MODE_FLAG_PIC_AR_4_3 \ + (DRM_MODE_PICTURE_ASPECT_4_3 << 19) +#define DRM_MODE_FLAG_PIC_AR_16_9 \ + (DRM_MODE_PICTURE_ASPECT_16_9 << 19) +#define DRM_MODE_FLAG_PIC_AR_64_27 \ + (DRM_MODE_PICTURE_ASPECT_64_27 << 19) +#define DRM_MODE_FLAG_PIC_AR_256_135 \ + (DRM_MODE_PICTURE_ASPECT_256_135 << 19) + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 +#define DRM_MODE_CONNECTOR_TV 13 +#define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUA 15 +#define DRM_MODE_CONNECTOR_DSI 16 +#define DRM_MODE_CONNECTOR_DPI 17 + +#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1) +#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2) +#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3) +#define DRM_EDID_PT_STEREO (1 << 5) +#define DRM_EDID_PT_INTERLACED (1 << 7) + + /* see also http://vektor.theorem.ca/graphics/ycbcr/ */ + enum v4l2_colorspace { + /* + * Default colorspace, i.e. let the driver figure it out. + * Can only be used with video capture. + */ + V4L2_COLORSPACE_DEFAULT = 0, + + /* SMPTE 170M: used for broadcast NTSC/PAL SDTV */ + V4L2_COLORSPACE_SMPTE170M = 1, + + /* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */ + V4L2_COLORSPACE_SMPTE240M = 2, + + /* Rec.709: used for HDTV */ + V4L2_COLORSPACE_REC709 = 3, + + /* + * Deprecated, do not use. No driver will ever return this. This was + * based on a misunderstanding of the bt878 datasheet. + */ + V4L2_COLORSPACE_BT878 = 4, + + /* + * NTSC 1953 colorspace. This only makes sense when dealing with + * really, really old NTSC recordings. Superseded by SMPTE 170M. + */ + V4L2_COLORSPACE_470_SYSTEM_M = 5, + + /* + * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when + * dealing with really old PAL/SECAM recordings. Superseded by + * SMPTE 170M. + */ + V4L2_COLORSPACE_470_SYSTEM_BG = 6, + + /* + * Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601 + * and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG. + */ + V4L2_COLORSPACE_JPEG = 7, + + /* For RGB colorspaces such as produces by most webcams. */ + V4L2_COLORSPACE_SRGB = 8, + + /* AdobeRGB colorspace */ + V4L2_COLORSPACE_ADOBERGB = 9, + + /* BT.2020 colorspace, used for UHDTV. */ + V4L2_COLORSPACE_BT2020 = 10, + + /* Raw colorspace: for RAW unprocessed images */ + V4L2_COLORSPACE_RAW = 11, + + /* DCI-P3 colorspace, used by cinema projectors */ + V4L2_COLORSPACE_DCI_P3 = 12, + }; + +#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ +#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ +#define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */ +#define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */ +#define CRTC_STEREO_DOUBLE_ONLY (CRTC_STEREO_DOUBLE | CRTC_NO_DBLSCAN | \ + CRTC_NO_VSCAN) + +#define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwHdmiQpLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwHdmiQpLib.h new file mode 100644 index 0000000..c0127fd --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwHdmiQpLib.h @@ -0,0 +1,1000 @@ +/** @file LcdHwLib.h + + This file contains interface functions for LcdHwLib of ArmPlatformPkg + + Copyright (c) 2017, ARM Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __DWHDMIQP_H__ +#define __DWHDMIQP_H__ + +#include +#include +#include +#include +#include +#include + +#define EREMOTEIO 121 /* Remote I/O error */ +#define EINVAL 22 /* Invalid argument */ +#define ETIMEDOUT 110 /* Connection timed out */ + +/* Main Unit Registers */ +#define CORE_ID 0x0 +#define VER_NUMBER 0x4 +#define VER_TYPE 0x8 +#define CONFIG_REG 0xc +#define CONFIG_CEC BIT(28) +#define CONFIG_AUD_UD BIT(23) +#define CORE_TIMESTAMP_HHMM 0x14 +#define CORE_TIMESTAMP_MMDD 0x18 +#define CORE_TIMESTAMP_YYYY 0x1c +/* Reset Manager Registers */ +#define GLOBAL_SWRESET_REQUEST 0x40 +#define EARCRX_CMDC_SWINIT_P BIT(27) +#define AVP_DATAPATH_PACKET_AUDIO_SWINIT_P BIT(10) +#define AVP_DATAPATH_SWINIT_P BIT(6) +#define GLOBAL_SWDISABLE 0x44 +#define CEC_SWDISABLE BIT(17) +#define AVP_DATAPATH_PACKET_AUDIO_SWDISABLE BIT(10) +#define AVP_DATAPATH_VIDEO_SWDISABLE BIT(6) +#define RESET_MANAGER_CONFIG0 0x48 +#define RESET_MANAGER_STATUS0 0x50 +#define RESET_MANAGER_STATUS1 0x54 +#define RESET_MANAGER_STATUS2 0x58 +/* Timer Base Registers */ +#define TIMER_BASE_CONFIG0 0x80 +#define TIMER_BASE_STATUS0 0x84 +/* CMU Registers */ +#define CMU_CONFIG0 0xa0 +#define CMU_CONFIG1 0xa4 +#define CMU_CONFIG2 0xa8 +#define CMU_CONFIG3 0xac +#define CMU_STATUS 0xb0 +#define EARC_BPCLK_OFF BIT(9) +#define AUDCLK_OFF BIT(7) +#define LINKQPCLK_OFF BIT(5) +#define VIDQPCLK_OFF BIT(3) +#define IPI_CLK_OFF BIT(1) +#define CMU_IPI_CLK_FREQ 0xb4 +#define CMU_VIDQPCLK_FREQ 0xb8 +#define CMU_LINKQPCLK_FREQ 0xbc +#define CMU_AUDQPCLK_FREQ 0xc0 +#define CMU_EARC_BPCLK_FREQ 0xc4 +/* I2CM Registers */ +#define I2CM_SM_SCL_CONFIG0 0xe0 +#define I2CM_FM_SCL_CONFIG0 0xe4 +#define I2CM_CONFIG0 0xe8 +#define I2CM_CONTROL0 0xec +#define I2CM_STATUS0 0xf0 +#define I2CM_INTERFACE_CONTROL0 0xf4 +#define I2CM_ADDR 0xff000 +#define I2CM_SLVADDR 0xfe0 +#define I2CM_WR_MASK 0x1e +#define I2CM_EXT_READ BIT(4) +#define I2CM_SHORT_READ BIT(3) +#define I2CM_FM_READ BIT(2) +#define I2CM_FM_WRITE BIT(1) +#define I2CM_FM_EN BIT(0) +#define I2CM_INTERFACE_CONTROL1 0xf8 +#define I2CM_SEG_PTR 0x7f80 +#define I2CM_SEG_ADDR 0x7f +#define I2CM_INTERFACE_WRDATA_0_3 0xfc +#define I2CM_INTERFACE_WRDATA_4_7 0x100 +#define I2CM_INTERFACE_WRDATA_8_11 0x104 +#define I2CM_INTERFACE_WRDATA_12_15 0x108 +#define I2CM_INTERFACE_RDDATA_0_3 0x10c +#define I2CM_INTERFACE_RDDATA_4_7 0x110 +#define I2CM_INTERFACE_RDDATA_8_11 0x114 +#define I2CM_INTERFACE_RDDATA_12_15 0x118 +/* SCDC Registers */ +#define SCDC_CONFIG0 0x140 +#define SCDC_I2C_FM_EN BIT(12) +#define SCDC_UPD_FLAGS_AUTO_CLR BIT(6) +#define SCDC_UPD_FLAGS_POLL_EN BIT(4) +#define SCDC_CONTROL0 0x148 +#define SCDC_STATUS0 0x150 +#define STATUS_UPDATE BIT(0) +#define FRL_START BIT(4) +#define FLT_UPDATE BIT(5) +/* FLT Registers */ +#define FLT_CONFIG0 0x160 +#define FLT_CONFIG1 0x164 +#define FLT_CONFIG2 0x168 +#define FLT_CONTROL0 0x170 +/* Main Unit 2 Registers */ +#define MAINUNIT_STATUS0 0x180 +/* Video Interface Registers */ +#define VIDEO_INTERFACE_CONFIG0 0x800 +#define VIDEO_INTERFACE_CONFIG1 0x804 +#define VIDEO_INTERFACE_CONFIG2 0x808 +#define VIDEO_INTERFACE_CONTROL0 0x80c +#define VIDEO_INTERFACE_STATUS0 0x814 +/* Video Packing Registers */ +#define VIDEO_PACKING_CONFIG0 0x81c +/* Audio Interface Registers */ +#define AUDIO_INTERFACE_CONFIG0 0x820 +#define AUD_IF_SEL_MSK 0x3 +#define AUD_IF_SPDIF 0x2 +#define AUD_IF_I2S 0x1 +#define AUD_IF_PAI 0x0 +#define AUD_FIFO_INIT_ON_OVF_MSK BIT(2) +#define AUD_FIFO_INIT_ON_OVF_EN BIT(2) +#define I2S_LINES_EN_MSK GENMASK(7, 4) +#define I2S_LINES_EN(x) BIT((x) + 4) +#define I2S_BPCUV_RCV_MSK BIT(12) +#define I2S_BPCUV_RCV_EN BIT(12) +#define I2S_BPCUV_RCV_DIS 0 +#define SPDIF_LINES_EN GENMASK(19, 16) +#define AUD_FORMAT_MSK GENMASK(26, 24) +#define AUD_3DOBA (0x7 << 24) +#define AUD_3DASP (0x6 << 24) +#define AUD_MSOBA (0x5 << 24) +#define AUD_MSASP (0x4 << 24) +#define AUD_HBR (0x3 << 24) +#define AUD_DST (0x2 << 24) +#define AUD_OBA (0x1 << 24) +#define AUD_ASP (0x0 << 24) +#define AUDIO_INTERFACE_CONFIG1 0x824 +#define AUDIO_INTERFACE_CONTROL0 0x82c +#define AUDIO_FIFO_CLR_P BIT(0) +#define AUDIO_INTERFACE_STATUS0 0x834 +/* Frame Composer Registers */ +#define FRAME_COMPOSER_CONFIG0 0x840 +#define FRAME_COMPOSER_CONFIG1 0x844 +#define FRAME_COMPOSER_CONFIG2 0x848 +#define FRAME_COMPOSER_CONFIG3 0x84c +#define FRAME_COMPOSER_CONFIG4 0x850 +#define FRAME_COMPOSER_CONFIG5 0x854 +#define FRAME_COMPOSER_CONFIG6 0x858 +#define FRAME_COMPOSER_CONFIG7 0x85c +#define FRAME_COMPOSER_CONFIG8 0x860 +#define FRAME_COMPOSER_CONFIG9 0x864 +#define KEEPOUT_REKEY_CFG GENMASK(9, 8) +#define KEEPOUT_REKEY_ALWAYS (0x2 << 8) +#define FRAME_COMPOSER_CONTROL0 0x86c +/* Video Monitor Registers */ +#define VIDEO_MONITOR_CONFIG0 0x880 +#define VIDEO_MONITOR_STATUS0 0x884 +#define VIDEO_MONITOR_STATUS1 0x888 +#define VIDEO_MONITOR_STATUS2 0x88c +#define VIDEO_MONITOR_STATUS3 0x890 +#define VIDEO_MONITOR_STATUS4 0x894 +#define VIDEO_MONITOR_STATUS5 0x898 +#define VIDEO_MONITOR_STATUS6 0x89c +/* HDCP2 Logic Registers */ +#define HDCP2LOGIC_CONFIG0 0x8e0 +#define HDCP2_BYPASS BIT(0) +#define HDCP2LOGIC_ESM_GPIO_IN 0x8e4 +#define HDCP2LOGIC_ESM_GPIO_OUT 0x8e8 +/* HDCP14 Registers */ +#define HDCP14_CONFIG0 0x900 +#define HDCP14_CONFIG1 0x904 +#define HDCP14_CONFIG2 0x908 +#define HDCP14_CONFIG3 0x90c +#define HDCP14_KEY_SEED 0x914 +#define HDCP14_KEY_H 0x918 +#define HDCP14_KEY_L 0x91c +#define HDCP14_KEY_STATUS 0x920 +#define HDCP14_AKSV_H 0x924 +#define HDCP14_AKSV_L 0x928 +#define HDCP14_AN_H 0x92c +#define HDCP14_AN_L 0x930 +#define HDCP14_STATUS0 0x934 +#define HDCP14_STATUS1 0x938 +/* Scrambler Registers */ +#define SCRAMB_CONFIG0 0x960 +/* Video Configuration Registers */ +#define LINK_CONFIG0 0x968 +#define OPMODE_FRL_4LANES BIT(8) +#define OPMODE_DVI BIT(4) +#define OPMODE_FRL BIT(0) +/* TMDS FIFO Registers */ +#define TMDS_FIFO_CONFIG0 0x970 +#define TMDS_FIFO_CONTROL0 0x974 +/* FRL RSFEC Registers */ +#define FRL_RSFEC_CONFIG0 0xa20 +#define FRL_RSFEC_STATUS0 0xa30 +/* FRL Packetizer Registers */ +#define FRL_PKTZ_CONFIG0 0xa40 +#define FRL_PKTZ_CONTROL0 0xa44 +#define FRL_PKTZ_CONTROL1 0xa50 +#define FRL_PKTZ_STATUS1 0xa54 +/* Packet Scheduler Registers */ +#define PKTSCHED_CONFIG0 0xa80 +#define PKTSCHED_PRQUEUE0_CONFIG0 0xa84 +#define PKTSCHED_PRQUEUE1_CONFIG0 0xa88 +#define PKTSCHED_PRQUEUE2_CONFIG0 0xa8c +#define PKTSCHED_PRQUEUE2_CONFIG1 0xa90 +#define PKTSCHED_PRQUEUE2_CONFIG2 0xa94 +#define PKTSCHED_PKT_CONFIG0 0xa98 +#define PKTSCHED_PKT_CONFIG1 0xa9c +#define PKTSCHED_VSI_FIELDRATE BIT(14) +#define PKTSCHED_AVI_FIELDRATE BIT(12) +#define PKTSCHED_PKT_CONFIG2 0xaa0 +#define PKTSCHED_PKT_CONFIG3 0xaa4 +#define PKTSCHED_PKT_EN 0xaa8 +#define PKTSCHED_DRMI_TX_EN BIT(17) +#define PKTSCHED_AUDI_TX_EN BIT(15) +#define PKTSCHED_AVI_TX_EN BIT(13) +#define PKTSCHED_VSI_TX_EN BIT(12) +#define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) +#define PKTSCHED_AMD_TX_EN BIT(8) +#define PKTSCHED_GCP_TX_EN BIT(3) +#define PKTSCHED_AUDS_TX_EN BIT(2) +#define PKTSCHED_ACR_TX_EN BIT(1) +#define PKTSCHED_NULL_TX_EN BIT(0) +#define PKTSCHED_PKT_CONTROL0 0xaac +#define PKTSCHED_PKT_SEND 0xab0 +#define PKTSCHED_PKT_STATUS0 0xab4 +#define PKTSCHED_PKT_STATUS1 0xab8 +#define PKT_NULL_CONTENTS0 0xb00 +#define PKT_NULL_CONTENTS1 0xb04 +#define PKT_NULL_CONTENTS2 0xb08 +#define PKT_NULL_CONTENTS3 0xb0c +#define PKT_NULL_CONTENTS4 0xb10 +#define PKT_NULL_CONTENTS5 0xb14 +#define PKT_NULL_CONTENTS6 0xb18 +#define PKT_NULL_CONTENTS7 0xb1c +#define PKT_ACP_CONTENTS0 0xb20 +#define PKT_ACP_CONTENTS1 0xb24 +#define PKT_ACP_CONTENTS2 0xb28 +#define PKT_ACP_CONTENTS3 0xb2c +#define PKT_ACP_CONTENTS4 0xb30 +#define PKT_ACP_CONTENTS5 0xb34 +#define PKT_ACP_CONTENTS6 0xb38 +#define PKT_ACP_CONTENTS7 0xb3c +#define PKT_ISRC1_CONTENTS0 0xb40 +#define PKT_ISRC1_CONTENTS1 0xb44 +#define PKT_ISRC1_CONTENTS2 0xb48 +#define PKT_ISRC1_CONTENTS3 0xb4c +#define PKT_ISRC1_CONTENTS4 0xb50 +#define PKT_ISRC1_CONTENTS5 0xb54 +#define PKT_ISRC1_CONTENTS6 0xb58 +#define PKT_ISRC1_CONTENTS7 0xb5c +#define PKT_ISRC2_CONTENTS0 0xb60 +#define PKT_ISRC2_CONTENTS1 0xb64 +#define PKT_ISRC2_CONTENTS2 0xb68 +#define PKT_ISRC2_CONTENTS3 0xb6c +#define PKT_ISRC2_CONTENTS4 0xb70 +#define PKT_ISRC2_CONTENTS5 0xb74 +#define PKT_ISRC2_CONTENTS6 0xb78 +#define PKT_ISRC2_CONTENTS7 0xb7c +#define PKT_GMD_CONTENTS0 0xb80 +#define PKT_GMD_CONTENTS1 0xb84 +#define PKT_GMD_CONTENTS2 0xb88 +#define PKT_GMD_CONTENTS3 0xb8c +#define PKT_GMD_CONTENTS4 0xb90 +#define PKT_GMD_CONTENTS5 0xb94 +#define PKT_GMD_CONTENTS6 0xb98 +#define PKT_GMD_CONTENTS7 0xb9c +#define PKT_AMD_CONTENTS0 0xba0 +#define PKT_AMD_CONTENTS1 0xba4 +#define PKT_AMD_CONTENTS2 0xba8 +#define PKT_AMD_CONTENTS3 0xbac +#define PKT_AMD_CONTENTS4 0xbb0 +#define PKT_AMD_CONTENTS5 0xbb4 +#define PKT_AMD_CONTENTS6 0xbb8 +#define PKT_AMD_CONTENTS7 0xbbc +#define PKT_VSI_CONTENTS0 0xbc0 +#define PKT_VSI_CONTENTS1 0xbc4 +#define PKT_VSI_CONTENTS2 0xbc8 +#define PKT_VSI_CONTENTS3 0xbcc +#define PKT_VSI_CONTENTS4 0xbd0 +#define PKT_VSI_CONTENTS5 0xbd4 +#define PKT_VSI_CONTENTS6 0xbd8 +#define PKT_VSI_CONTENTS7 0xbdc +#define PKT_AVI_CONTENTS0 0xbe0 +#define HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT BIT(4) +#define HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR 0x04 +#define HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR 0x08 +#define HDMI_FC_AVICONF2_IT_CONTENT_VALID 0x80 +#define PKT_AVI_CONTENTS1 0xbe4 +#define PKT_AVI_CONTENTS2 0xbe8 +#define PKT_AVI_CONTENTS3 0xbec +#define PKT_AVI_CONTENTS4 0xbf0 +#define PKT_AVI_CONTENTS5 0xbf4 +#define PKT_AVI_CONTENTS6 0xbf8 +#define PKT_AVI_CONTENTS7 0xbfc +#define PKT_SPDI_CONTENTS0 0xc00 +#define PKT_SPDI_CONTENTS1 0xc04 +#define PKT_SPDI_CONTENTS2 0xc08 +#define PKT_SPDI_CONTENTS3 0xc0c +#define PKT_SPDI_CONTENTS4 0xc10 +#define PKT_SPDI_CONTENTS5 0xc14 +#define PKT_SPDI_CONTENTS6 0xc18 +#define PKT_SPDI_CONTENTS7 0xc1c +#define PKT_AUDI_CONTENTS0 0xc20 +#define PKT_AUDI_CONTENTS1 0xc24 +#define PKT_AUDI_CONTENTS2 0xc28 +#define PKT_AUDI_CONTENTS3 0xc2c +#define PKT_AUDI_CONTENTS4 0xc30 +#define PKT_AUDI_CONTENTS5 0xc34 +#define PKT_AUDI_CONTENTS6 0xc38 +#define PKT_AUDI_CONTENTS7 0xc3c +#define PKT_NVI_CONTENTS0 0xc40 +#define PKT_NVI_CONTENTS1 0xc44 +#define PKT_NVI_CONTENTS2 0xc48 +#define PKT_NVI_CONTENTS3 0xc4c +#define PKT_NVI_CONTENTS4 0xc50 +#define PKT_NVI_CONTENTS5 0xc54 +#define PKT_NVI_CONTENTS6 0xc58 +#define PKT_NVI_CONTENTS7 0xc5c +#define PKT_DRMI_CONTENTS0 0xc60 +#define PKT_DRMI_CONTENTS1 0xc64 +#define PKT_DRMI_CONTENTS2 0xc68 +#define PKT_DRMI_CONTENTS3 0xc6c +#define PKT_DRMI_CONTENTS4 0xc70 +#define PKT_DRMI_CONTENTS5 0xc74 +#define PKT_DRMI_CONTENTS6 0xc78 +#define PKT_DRMI_CONTENTS7 0xc7c +#define PKT_GHDMI1_CONTENTS0 0xc80 +#define PKT_GHDMI1_CONTENTS1 0xc84 +#define PKT_GHDMI1_CONTENTS2 0xc88 +#define PKT_GHDMI1_CONTENTS3 0xc8c +#define PKT_GHDMI1_CONTENTS4 0xc90 +#define PKT_GHDMI1_CONTENTS5 0xc94 +#define PKT_GHDMI1_CONTENTS6 0xc98 +#define PKT_GHDMI1_CONTENTS7 0xc9c +#define PKT_GHDMI2_CONTENTS0 0xca0 +#define PKT_GHDMI2_CONTENTS1 0xca4 +#define PKT_GHDMI2_CONTENTS2 0xca8 +#define PKT_GHDMI2_CONTENTS3 0xcac +#define PKT_GHDMI2_CONTENTS4 0xcb0 +#define PKT_GHDMI2_CONTENTS5 0xcb4 +#define PKT_GHDMI2_CONTENTS6 0xcb8 +#define PKT_GHDMI2_CONTENTS7 0xcbc +/* EMP Packetizer Registers */ +#define PKT_EMP_CONFIG0 0xce0 +#define PKT_EMP_CONTROL0 0xcec +#define PKT_EMP_CONTROL1 0xcf0 +#define PKT_EMP_CONTROL2 0xcf4 +#define PKT_EMP_VTEM_CONTENTS0 0xd00 +#define PKT_EMP_VTEM_CONTENTS1 0xd04 +#define PKT_EMP_VTEM_CONTENTS2 0xd08 +#define PKT_EMP_VTEM_CONTENTS3 0xd0c +#define PKT_EMP_VTEM_CONTENTS4 0xd10 +#define PKT_EMP_VTEM_CONTENTS5 0xd14 +#define PKT_EMP_VTEM_CONTENTS6 0xd18 +#define PKT_EMP_VTEM_CONTENTS7 0xd1c +#define PKT0_EMP_CVTEM_CONTENTS0 0xd20 +#define PKT0_EMP_CVTEM_CONTENTS1 0xd24 +#define PKT0_EMP_CVTEM_CONTENTS2 0xd28 +#define PKT0_EMP_CVTEM_CONTENTS3 0xd2c +#define PKT0_EMP_CVTEM_CONTENTS4 0xd30 +#define PKT0_EMP_CVTEM_CONTENTS5 0xd34 +#define PKT0_EMP_CVTEM_CONTENTS6 0xd38 +#define PKT0_EMP_CVTEM_CONTENTS7 0xd3c +#define PKT1_EMP_CVTEM_CONTENTS0 0xd40 +#define PKT1_EMP_CVTEM_CONTENTS1 0xd44 +#define PKT1_EMP_CVTEM_CONTENTS2 0xd48 +#define PKT1_EMP_CVTEM_CONTENTS3 0xd4c +#define PKT1_EMP_CVTEM_CONTENTS4 0xd50 +#define PKT1_EMP_CVTEM_CONTENTS5 0xd54 +#define PKT1_EMP_CVTEM_CONTENTS6 0xd58 +#define PKT1_EMP_CVTEM_CONTENTS7 0xd5c +#define PKT2_EMP_CVTEM_CONTENTS0 0xd60 +#define PKT2_EMP_CVTEM_CONTENTS1 0xd64 +#define PKT2_EMP_CVTEM_CONTENTS2 0xd68 +#define PKT2_EMP_CVTEM_CONTENTS3 0xd6c +#define PKT2_EMP_CVTEM_CONTENTS4 0xd70 +#define PKT2_EMP_CVTEM_CONTENTS5 0xd74 +#define PKT2_EMP_CVTEM_CONTENTS6 0xd78 +#define PKT2_EMP_CVTEM_CONTENTS7 0xd7c +#define PKT3_EMP_CVTEM_CONTENTS0 0xd80 +#define PKT3_EMP_CVTEM_CONTENTS1 0xd84 +#define PKT3_EMP_CVTEM_CONTENTS2 0xd88 +#define PKT3_EMP_CVTEM_CONTENTS3 0xd8c +#define PKT3_EMP_CVTEM_CONTENTS4 0xd90 +#define PKT3_EMP_CVTEM_CONTENTS5 0xd94 +#define PKT3_EMP_CVTEM_CONTENTS6 0xd98 +#define PKT3_EMP_CVTEM_CONTENTS7 0xd9c +#define PKT4_EMP_CVTEM_CONTENTS0 0xda0 +#define PKT4_EMP_CVTEM_CONTENTS1 0xda4 +#define PKT4_EMP_CVTEM_CONTENTS2 0xda8 +#define PKT4_EMP_CVTEM_CONTENTS3 0xdac +#define PKT4_EMP_CVTEM_CONTENTS4 0xdb0 +#define PKT4_EMP_CVTEM_CONTENTS5 0xdb4 +#define PKT4_EMP_CVTEM_CONTENTS6 0xdb8 +#define PKT4_EMP_CVTEM_CONTENTS7 0xdbc +#define PKT5_EMP_CVTEM_CONTENTS0 0xdc0 +#define PKT5_EMP_CVTEM_CONTENTS1 0xdc4 +#define PKT5_EMP_CVTEM_CONTENTS2 0xdc8 +#define PKT5_EMP_CVTEM_CONTENTS3 0xdcc +#define PKT5_EMP_CVTEM_CONTENTS4 0xdd0 +#define PKT5_EMP_CVTEM_CONTENTS5 0xdd4 +#define PKT5_EMP_CVTEM_CONTENTS6 0xdd8 +#define PKT5_EMP_CVTEM_CONTENTS7 0xddc +/* Audio Packetizer Registers */ +#define AUDPKT_CONTROL0 0xe20 +#define AUDPKT_CHSTATUS_OVR_EN_MASK BIT(0) +#define AUDPKT_CHSTATUS_OVR_EN BIT(0) +#define AUDPKT_CONTROL1 0xe24 +#define AUDPKT_ACR_CONTROL0 0xe40 +#define AUDPKT_ACR_N_VALUE 0xfffff +#define AUDPKT_ACR_CONTROL1 0xe44 +#define AUDPKT_ACR_CTS_OVR_VAL_MSK GENMASK(23, 4) +#define AUDPKT_ACR_CTS_OVR_VAL(x) ((x) << 4) +#define AUDPKT_ACR_CTS_OVR_EN_MSK BIT(1) +#define AUDPKT_ACR_CTS_OVR_EN BIT(1) +#define AUDPKT_ACR_STATUS0 0xe4c +#define AUDPKT_CHSTATUS_OVR0 0xe60 +#define AUDPKT_CHSTATUS_OVR1 0xe64 +/* IEC60958 Byte 3: Sampleing frenuency Bits 24 to 27 */ +#define AUDPKT_CHSTATUS_SR_MASK GENMASK(3, 0) +#define AUDPKT_CHSTATUS_SR_22050 0x4 +#define AUDPKT_CHSTATUS_SR_24000 0x6 +#define AUDPKT_CHSTATUS_SR_32000 0x3 +#define AUDPKT_CHSTATUS_SR_44100 0x0 +#define AUDPKT_CHSTATUS_SR_48000 0x2 +#define AUDPKT_CHSTATUS_SR_88200 0x8 +#define AUDPKT_CHSTATUS_SR_96000 0xa +#define AUDPKT_CHSTATUS_SR_176400 0xc +#define AUDPKT_CHSTATUS_SR_192000 0xe +#define AUDPKT_CHSTATUS_SR_768000 0x9 +#define AUDPKT_CHSTATUS_SR_NOT_INDICATED 0x1 +/* IEC60958 Byte 4: Original Sampleing frenuency Bits 36 to 39 */ +#define AUDPKT_CHSTATUS_0SR_MASK GENMASK(15, 12) +#define AUDPKT_CHSTATUS_OSR_8000 0x6 +#define AUDPKT_CHSTATUS_OSR_11025 0xa +#define AUDPKT_CHSTATUS_OSR_12000 0x2 +#define AUDPKT_CHSTATUS_OSR_16000 0x8 +#define AUDPKT_CHSTATUS_OSR_22050 0xb +#define AUDPKT_CHSTATUS_OSR_24000 0x9 +#define AUDPKT_CHSTATUS_OSR_32000 0xc +#define AUDPKT_CHSTATUS_OSR_44100 0xf +#define AUDPKT_CHSTATUS_OSR_48000 0xd +#define AUDPKT_CHSTATUS_OSR_88200 0x7 +#define AUDPKT_CHSTATUS_OSR_96000 0x5 +#define AUDPKT_CHSTATUS_OSR_176400 0x3 +#define AUDPKT_CHSTATUS_OSR_192000 0x1 +#define AUDPKT_CHSTATUS_OSR_NOT_INDICATED 0x0 +#define AUDPKT_CHSTATUS_OVR2 0xe68 +#define AUDPKT_CHSTATUS_OVR3 0xe6c +#define AUDPKT_CHSTATUS_OVR4 0xe70 +#define AUDPKT_CHSTATUS_OVR5 0xe74 +#define AUDPKT_CHSTATUS_OVR6 0xe78 +#define AUDPKT_CHSTATUS_OVR7 0xe7c +#define AUDPKT_CHSTATUS_OVR8 0xe80 +#define AUDPKT_CHSTATUS_OVR9 0xe84 +#define AUDPKT_CHSTATUS_OVR10 0xe88 +#define AUDPKT_CHSTATUS_OVR11 0xe8c +#define AUDPKT_CHSTATUS_OVR12 0xe90 +#define AUDPKT_CHSTATUS_OVR13 0xe94 +#define AUDPKT_CHSTATUS_OVR14 0xe98 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC0 0xea0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC1 0xea4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC2 0xea8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC3 0xeac +#define AUDPKT_USRDATA_OVR_MSG_GENERIC4 0xeb0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC5 0xeb4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC6 0xeb8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC7 0xebc +#define AUDPKT_USRDATA_OVR_MSG_GENERIC8 0xec0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC9 0xec4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC10 0xec8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC11 0xecc +#define AUDPKT_USRDATA_OVR_MSG_GENERIC12 0xed0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC13 0xed4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC14 0xed8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC15 0xedc +#define AUDPKT_USRDATA_OVR_MSG_GENERIC16 0xee0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC17 0xee4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC18 0xee8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC19 0xeec +#define AUDPKT_USRDATA_OVR_MSG_GENERIC20 0xef0 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC21 0xef4 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC22 0xef8 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC23 0xefc +#define AUDPKT_USRDATA_OVR_MSG_GENERIC24 0xf00 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC25 0xf04 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC26 0xf08 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC27 0xf0c +#define AUDPKT_USRDATA_OVR_MSG_GENERIC28 0xf10 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC29 0xf14 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC30 0xf18 +#define AUDPKT_USRDATA_OVR_MSG_GENERIC31 0xf1c +#define AUDPKT_USRDATA_OVR_MSG_GENERIC32 0xf20 +#define AUDPKT_VBIT_OVR0 0xf24 +/* CEC Registers */ +#define CEC_TX_CONTROL 0x1000 +#define CEC_STATUS 0x1004 +#define CEC_CONFIG 0x1008 +#define CEC_ADDR 0x100c +#define CEC_TX_COUNT 0x1020 +#define CEC_TX_DATA3_0 0x1024 +#define CEC_TX_DATA7_4 0x1028 +#define CEC_TX_DATA11_8 0x102c +#define CEC_TX_DATA15_12 0x1030 +#define CEC_RX_COUNT_STATUS 0x1040 +#define CEC_RX_DATA3_0 0x1044 +#define CEC_RX_DATA7_4 0x1048 +#define CEC_RX_DATA11_8 0x104c +#define CEC_RX_DATA15_12 0x1050 +#define CEC_LOCK_CONTROL 0x1054 +#define CEC_RXQUAL_BITTIME_CONFIG 0x1060 +#define CEC_RX_BITTIME_CONFIG 0x1064 +#define CEC_TX_BITTIME_CONFIG 0x1068 +/* eARC RX CMDC Registers */ +#define EARCRX_CMDC_CONFIG0 0x1800 +#define EARCRX_XACTREAD_STOP_CFG BIT(26) +#define EARCRX_XACTREAD_RETRY_CFG BIT(25) +#define EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 BIT(24) +#define EARCRX_CMDC_XACT_RESTART_EN BIT(18) +#define EARCRX_CMDC_CONFIG1 0x1804 +#define EARCRX_CMDC_CONTROL 0x1808 +#define EARCRX_CMDC_HEARTBEAT_LOSS_EN BIT(4) +#define EARCRX_CMDC_DISCOVERY_EN BIT(3) +#define EARCRX_CONNECTOR_HPD BIT(1) +#define EARCRX_CMDC_WHITELIST0_CONFIG 0x180c +#define EARCRX_CMDC_WHITELIST1_CONFIG 0x1810 +#define EARCRX_CMDC_WHITELIST2_CONFIG 0x1814 +#define EARCRX_CMDC_WHITELIST3_CONFIG 0x1818 +#define EARCRX_CMDC_STATUS 0x181c +#define EARCRX_CMDC_XACT_INFO 0x1820 +#define EARCRX_CMDC_XACT_ACTION 0x1824 +#define EARCRX_CMDC_HEARTBEAT_RXSTAT_SE 0x1828 +#define EARCRX_CMDC_HEARTBEAT_STATUS 0x182c +#define EARCRX_CMDC_XACT_WR0 0x1840 +#define EARCRX_CMDC_XACT_WR1 0x1844 +#define EARCRX_CMDC_XACT_WR2 0x1848 +#define EARCRX_CMDC_XACT_WR3 0x184c +#define EARCRX_CMDC_XACT_WR4 0x1850 +#define EARCRX_CMDC_XACT_WR5 0x1854 +#define EARCRX_CMDC_XACT_WR6 0x1858 +#define EARCRX_CMDC_XACT_WR7 0x185c +#define EARCRX_CMDC_XACT_WR8 0x1860 +#define EARCRX_CMDC_XACT_WR9 0x1864 +#define EARCRX_CMDC_XACT_WR10 0x1868 +#define EARCRX_CMDC_XACT_WR11 0x186c +#define EARCRX_CMDC_XACT_WR12 0x1870 +#define EARCRX_CMDC_XACT_WR13 0x1874 +#define EARCRX_CMDC_XACT_WR14 0x1878 +#define EARCRX_CMDC_XACT_WR15 0x187c +#define EARCRX_CMDC_XACT_WR16 0x1880 +#define EARCRX_CMDC_XACT_WR17 0x1884 +#define EARCRX_CMDC_XACT_WR18 0x1888 +#define EARCRX_CMDC_XACT_WR19 0x188c +#define EARCRX_CMDC_XACT_WR20 0x1890 +#define EARCRX_CMDC_XACT_WR21 0x1894 +#define EARCRX_CMDC_XACT_WR22 0x1898 +#define EARCRX_CMDC_XACT_WR23 0x189c +#define EARCRX_CMDC_XACT_WR24 0x18a0 +#define EARCRX_CMDC_XACT_WR25 0x18a4 +#define EARCRX_CMDC_XACT_WR26 0x18a8 +#define EARCRX_CMDC_XACT_WR27 0x18ac +#define EARCRX_CMDC_XACT_WR28 0x18b0 +#define EARCRX_CMDC_XACT_WR29 0x18b4 +#define EARCRX_CMDC_XACT_WR30 0x18b8 +#define EARCRX_CMDC_XACT_WR31 0x18bc +#define EARCRX_CMDC_XACT_WR32 0x18c0 +#define EARCRX_CMDC_XACT_WR33 0x18c4 +#define EARCRX_CMDC_XACT_WR34 0x18c8 +#define EARCRX_CMDC_XACT_WR35 0x18cc +#define EARCRX_CMDC_XACT_WR36 0x18d0 +#define EARCRX_CMDC_XACT_WR37 0x18d4 +#define EARCRX_CMDC_XACT_WR38 0x18d8 +#define EARCRX_CMDC_XACT_WR39 0x18dc +#define EARCRX_CMDC_XACT_WR40 0x18e0 +#define EARCRX_CMDC_XACT_WR41 0x18e4 +#define EARCRX_CMDC_XACT_WR42 0x18e8 +#define EARCRX_CMDC_XACT_WR43 0x18ec +#define EARCRX_CMDC_XACT_WR44 0x18f0 +#define EARCRX_CMDC_XACT_WR45 0x18f4 +#define EARCRX_CMDC_XACT_WR46 0x18f8 +#define EARCRX_CMDC_XACT_WR47 0x18fc +#define EARCRX_CMDC_XACT_WR48 0x1900 +#define EARCRX_CMDC_XACT_WR49 0x1904 +#define EARCRX_CMDC_XACT_WR50 0x1908 +#define EARCRX_CMDC_XACT_WR51 0x190c +#define EARCRX_CMDC_XACT_WR52 0x1910 +#define EARCRX_CMDC_XACT_WR53 0x1914 +#define EARCRX_CMDC_XACT_WR54 0x1918 +#define EARCRX_CMDC_XACT_WR55 0x191c +#define EARCRX_CMDC_XACT_WR56 0x1920 +#define EARCRX_CMDC_XACT_WR57 0x1924 +#define EARCRX_CMDC_XACT_WR58 0x1928 +#define EARCRX_CMDC_XACT_WR59 0x192c +#define EARCRX_CMDC_XACT_WR60 0x1930 +#define EARCRX_CMDC_XACT_WR61 0x1934 +#define EARCRX_CMDC_XACT_WR62 0x1938 +#define EARCRX_CMDC_XACT_WR63 0x193c +#define EARCRX_CMDC_XACT_WR64 0x1940 +#define EARCRX_CMDC_XACT_RD0 0x1960 +#define EARCRX_CMDC_XACT_RD1 0x1964 +#define EARCRX_CMDC_XACT_RD2 0x1968 +#define EARCRX_CMDC_XACT_RD3 0x196c +#define EARCRX_CMDC_XACT_RD4 0x1970 +#define EARCRX_CMDC_XACT_RD5 0x1974 +#define EARCRX_CMDC_XACT_RD6 0x1978 +#define EARCRX_CMDC_XACT_RD7 0x197c +#define EARCRX_CMDC_XACT_RD8 0x1980 +#define EARCRX_CMDC_XACT_RD9 0x1984 +#define EARCRX_CMDC_XACT_RD10 0x1988 +#define EARCRX_CMDC_XACT_RD11 0x198c +#define EARCRX_CMDC_XACT_RD12 0x1990 +#define EARCRX_CMDC_XACT_RD13 0x1994 +#define EARCRX_CMDC_XACT_RD14 0x1998 +#define EARCRX_CMDC_XACT_RD15 0x199c +#define EARCRX_CMDC_XACT_RD16 0x19a0 +#define EARCRX_CMDC_XACT_RD17 0x19a4 +#define EARCRX_CMDC_XACT_RD18 0x19a8 +#define EARCRX_CMDC_XACT_RD19 0x19ac +#define EARCRX_CMDC_XACT_RD20 0x19b0 +#define EARCRX_CMDC_XACT_RD21 0x19b4 +#define EARCRX_CMDC_XACT_RD22 0x19b8 +#define EARCRX_CMDC_XACT_RD23 0x19bc +#define EARCRX_CMDC_XACT_RD24 0x19c0 +#define EARCRX_CMDC_XACT_RD25 0x19c4 +#define EARCRX_CMDC_XACT_RD26 0x19c8 +#define EARCRX_CMDC_XACT_RD27 0x19cc +#define EARCRX_CMDC_XACT_RD28 0x19d0 +#define EARCRX_CMDC_XACT_RD29 0x19d4 +#define EARCRX_CMDC_XACT_RD30 0x19d8 +#define EARCRX_CMDC_XACT_RD31 0x19dc +#define EARCRX_CMDC_XACT_RD32 0x19e0 +#define EARCRX_CMDC_XACT_RD33 0x19e4 +#define EARCRX_CMDC_XACT_RD34 0x19e8 +#define EARCRX_CMDC_XACT_RD35 0x19ec +#define EARCRX_CMDC_XACT_RD36 0x19f0 +#define EARCRX_CMDC_XACT_RD37 0x19f4 +#define EARCRX_CMDC_XACT_RD38 0x19f8 +#define EARCRX_CMDC_XACT_RD39 0x19fc +#define EARCRX_CMDC_XACT_RD40 0x1a00 +#define EARCRX_CMDC_XACT_RD41 0x1a04 +#define EARCRX_CMDC_XACT_RD42 0x1a08 +#define EARCRX_CMDC_XACT_RD43 0x1a0c +#define EARCRX_CMDC_XACT_RD44 0x1a10 +#define EARCRX_CMDC_XACT_RD45 0x1a14 +#define EARCRX_CMDC_XACT_RD46 0x1a18 +#define EARCRX_CMDC_XACT_RD47 0x1a1c +#define EARCRX_CMDC_XACT_RD48 0x1a20 +#define EARCRX_CMDC_XACT_RD49 0x1a24 +#define EARCRX_CMDC_XACT_RD50 0x1a28 +#define EARCRX_CMDC_XACT_RD51 0x1a2c +#define EARCRX_CMDC_XACT_RD52 0x1a30 +#define EARCRX_CMDC_XACT_RD53 0x1a34 +#define EARCRX_CMDC_XACT_RD54 0x1a38 +#define EARCRX_CMDC_XACT_RD55 0x1a3c +#define EARCRX_CMDC_XACT_RD56 0x1a40 +#define EARCRX_CMDC_XACT_RD57 0x1a44 +#define EARCRX_CMDC_XACT_RD58 0x1a48 +#define EARCRX_CMDC_XACT_RD59 0x1a4c +#define EARCRX_CMDC_XACT_RD60 0x1a50 +#define EARCRX_CMDC_XACT_RD61 0x1a54 +#define EARCRX_CMDC_XACT_RD62 0x1a58 +#define EARCRX_CMDC_XACT_RD63 0x1a5c +#define EARCRX_CMDC_XACT_RD64 0x1a60 +#define EARCRX_CMDC_SYNC_CONFIG 0x1b00 +/* eARC RX DMAC Registers */ +#define EARCRX_DMAC_PHY_CONTROL 0x1c00 +#define EARCRX_DMAC_CONFIG 0x1c08 +#define EARCRX_DMAC_CONTROL0 0x1c0c +#define EARCRX_DMAC_AUDIO_EN BIT(1) +#define EARCRX_DMAC_EN BIT(0) +#define EARCRX_DMAC_CONTROL1 0x1c10 +#define EARCRX_DMAC_STATUS 0x1c14 +#define EARCRX_DMAC_CHSTATUS0 0x1c18 +#define EARCRX_DMAC_CHSTATUS1 0x1c1c +#define EARCRX_DMAC_CHSTATUS2 0x1c20 +#define EARCRX_DMAC_CHSTATUS3 0x1c24 +#define EARCRX_DMAC_CHSTATUS4 0x1c28 +#define EARCRX_DMAC_CHSTATUS5 0x1c2c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC0 0x1c30 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC1 0x1c34 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC2 0x1c38 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC3 0x1c3c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC4 0x1c40 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC5 0x1c44 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC6 0x1c48 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC7 0x1c4c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC8 0x1c50 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC9 0x1c54 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC10 0x1c58 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC11 0x1c5c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT0 0x1c60 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT1 0x1c64 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT2 0x1c68 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT3 0x1c6c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT4 0x1c70 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT5 0x1c74 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT6 0x1c78 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT7 0x1c7c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT8 0x1c80 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT9 0x1c84 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT10 0x1c88 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT11 0x1c8c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT0 0x1c90 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT1 0x1c94 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT2 0x1c98 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT3 0x1c9c +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT4 0x1ca0 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT5 0x1ca4 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT6 0x1ca8 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT7 0x1cac +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT8 0x1cb0 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT9 0x1cb4 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT10 0x1cb8 +#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT11 0x1cbc +#define EARCRX_DMAC_USRDATA_MSG_GENERIC0 0x1cc0 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC1 0x1cc4 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC2 0x1cc8 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC3 0x1ccc +#define EARCRX_DMAC_USRDATA_MSG_GENERIC4 0x1cd0 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC5 0x1cd4 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC6 0x1cd8 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC7 0x1cdc +#define EARCRX_DMAC_USRDATA_MSG_GENERIC8 0x1ce0 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC9 0x1ce4 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC10 0x1ce8 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC11 0x1cec +#define EARCRX_DMAC_USRDATA_MSG_GENERIC12 0x1cf0 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC13 0x1cf4 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC14 0x1cf8 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC15 0x1cfc +#define EARCRX_DMAC_USRDATA_MSG_GENERIC16 0x1d00 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC17 0x1d04 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC18 0x1d08 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC19 0x1d0c +#define EARCRX_DMAC_USRDATA_MSG_GENERIC20 0x1d10 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC21 0x1d14 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC22 0x1d18 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC23 0x1d1c +#define EARCRX_DMAC_USRDATA_MSG_GENERIC24 0x1d20 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC25 0x1d24 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC26 0x1d28 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC27 0x1d2c +#define EARCRX_DMAC_USRDATA_MSG_GENERIC28 0x1d30 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC29 0x1d34 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC30 0x1d38 +#define EARCRX_DMAC_USRDATA_MSG_GENERIC31 0x1d3c +#define EARCRX_DMAC_USRDATA_MSG_GENERIC32 0x1d40 +#define EARCRX_DMAC_CHSTATUS_STREAMER0 0x1d44 +#define EARCRX_DMAC_CHSTATUS_STREAMER1 0x1d48 +#define EARCRX_DMAC_CHSTATUS_STREAMER2 0x1d4c +#define EARCRX_DMAC_CHSTATUS_STREAMER3 0x1d50 +#define EARCRX_DMAC_CHSTATUS_STREAMER4 0x1d54 +#define EARCRX_DMAC_CHSTATUS_STREAMER5 0x1d58 +#define EARCRX_DMAC_CHSTATUS_STREAMER6 0x1d5c +#define EARCRX_DMAC_CHSTATUS_STREAMER7 0x1d60 +#define EARCRX_DMAC_CHSTATUS_STREAMER8 0x1d64 +#define EARCRX_DMAC_CHSTATUS_STREAMER9 0x1d68 +#define EARCRX_DMAC_CHSTATUS_STREAMER10 0x1d6c +#define EARCRX_DMAC_CHSTATUS_STREAMER11 0x1d70 +#define EARCRX_DMAC_CHSTATUS_STREAMER12 0x1d74 +#define EARCRX_DMAC_CHSTATUS_STREAMER13 0x1d78 +#define EARCRX_DMAC_CHSTATUS_STREAMER14 0x1d7c +#define EARCRX_DMAC_USRDATA_STREAMER0 0x1d80 +/* Main Unit Interrupt Registers */ +#define MAIN_INTVEC_INDEX 0x3000 +#define MAINUNIT_0_INT_STATUS 0x3010 +#define MAINUNIT_0_INT_MASK_N 0x3014 +#define MAINUNIT_0_INT_CLEAR 0x3018 +#define MAINUNIT_0_INT_FORCE 0x301c +#define MAINUNIT_1_INT_STATUS 0x3020 +#define FLT_EXIT_TO_LTSL_IRQ BIT(22) +#define FLT_EXIT_TO_LTS4_IRQ BIT(21) +#define FLT_EXIT_TO_LTSP_IRQ BIT(20) +#define SCDC_NACK_RCVD_IRQ BIT(12) +#define SCDC_RR_REPLY_STOP_IRQ BIT(11) +#define SCDC_UPD_FLAGS_CLR_IRQ BIT(10) +#define SCDC_UPD_FLAGS_CHG_IRQ BIT(9) +#define SCDC_UPD_FLAGS_RD_IRQ BIT(8) +#define I2CM_NACK_RCVD_IRQ BIT(2) +#define I2CM_READ_REQUEST_IRQ BIT(1) +#define I2CM_OP_DONE_IRQ BIT(0) +#define MAINUNIT_1_INT_MASK_N 0x3024 +#define I2CM_NACK_RCVD_MASK_N BIT(2) +#define I2CM_READ_REQUEST_MASK_N BIT(1) +#define I2CM_OP_DONE_MASK_N BIT(0) +#define MAINUNIT_1_INT_CLEAR 0x3028 +#define I2CM_NACK_RCVD_CLEAR BIT(2) +#define I2CM_READ_REQUEST_CLEAR BIT(1) +#define I2CM_OP_DONE_CLEAR BIT(0) +#define MAINUNIT_1_INT_FORCE 0x302c +/* AVPUNIT Interrupt Registers */ +#define AVP_INTVEC_INDEX 0x3800 +#define AVP_0_INT_STATUS 0x3810 +#define AVP_0_INT_MASK_N 0x3814 +#define AVP_0_INT_CLEAR 0x3818 +#define AVP_0_INT_FORCE 0x381c +#define AVP_1_INT_STATUS 0x3820 +#define AVP_1_INT_MASK_N 0x3824 +#define HDCP14_AUTH_CHG_MASK_N BIT(6) +#define AVP_1_INT_CLEAR 0x3828 +#define AVP_1_INT_FORCE 0x382c +#define AVP_2_INT_STATUS 0x3830 +#define AVP_2_INT_MASK_N 0x3834 +#define AVP_2_INT_CLEAR 0x3838 +#define AVP_2_INT_FORCE 0x383c +#define AVP_3_INT_STATUS 0x3840 +#define AVP_3_INT_MASK_N 0x3844 +#define AVP_3_INT_CLEAR 0x3848 +#define AVP_3_INT_FORCE 0x384c +#define AVP_4_INT_STATUS 0x3850 +#define AVP_4_INT_MASK_N 0x3854 +#define AVP_4_INT_CLEAR 0x3858 +#define AVP_4_INT_FORCE 0x385c +#define AVP_5_INT_STATUS 0x3860 +#define AVP_5_INT_MASK_N 0x3864 +#define AVP_5_INT_CLEAR 0x3868 +#define AVP_5_INT_FORCE 0x386c +#define AVP_6_INT_STATUS 0x3870 +#define AVP_6_INT_MASK_N 0x3874 +#define AVP_6_INT_CLEAR 0x3878 +#define AVP_6_INT_FORCE 0x387c +/* CEC Interrupt Registers */ +#define CEC_INT_STATUS 0x4000 +#define CEC_INT_MASK_N 0x4004 +#define CEC_INT_CLEAR 0x4008 +#define CEC_INT_FORCE 0x400c +/* eARC RX Interrupt Registers */ +#define EARCRX_INTVEC_INDEX 0x4800 +#define EARCRX_0_INT_STATUS 0x4810 +#define EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ BIT(9) +#define EARCRX_CMDC_DISCOVERY_DONE_IRQ BIT(8) +#define EARCRX_0_INT_MASK_N 0x4814 +#define EARCRX_0_INT_CLEAR 0x4818 +#define EARCRX_0_INT_FORCE 0x481c +#define EARCRX_1_INT_STATUS 0x4820 +#define EARCRX_1_INT_MASK_N 0x4824 +#define EARCRX_1_INT_CLEAR 0x4828 +#define EARCRX_1_INT_FORCE 0x482c + +/* SCDC Registers */ +#define SCDC_SINK_VERSION 0x01 +#define SCDC_SOURCE_VERSION 0x02 + +#define SCDC_UPDATE_0 0x10 +#define SCDC_READ_REQUEST_TEST BIT(2) +#define SCDC_CED_UPDATE BIT(1) +#define SCDC_STATUS_UPDATE BIT(0) +#define SCDC_UPDATE_1 0x11 + +#define SCDC_TMDS_CONFIG 0x20 +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 BIT(1) +#define SCDC_TMDS_BIT_CLOCK_RATIO_BY_10 (0 << 1) +#define SCDC_SCRAMBLING_ENABLE BIT(0) +#define SCDC_SCRAMBLER_STATUS 0x21 +#define SCDC_SCRAMBLING_STATUS BIT(0) + +#define SCDC_CONFIG_0 0x30 +#define SCDC_READ_REQUEST_ENABLE BIT(0) + +#define SCDC_STATUS_FLAGS_0 0x40 +#define SCDC_CH2_LOCK BIT(3) +#define SCDC_CH1_LOCK BIT(2) +#define SCDC_CH0_LOCK BIT(1) +#define SCDC_CH_LOCK_MASK (SCDC_CH2_LOCK | SCDC_CH1_LOCK | SCDC_CH0_LOCK) +#define SCDC_CLOCK_DETECT BIT(0) +#define SCDC_STATUS_FLAGS_1 0x41 + +#define SCDC_ERR_DET_0_L 0x50 +#define SCDC_ERR_DET_0_H 0x51 +#define SCDC_ERR_DET_1_L 0x52 +#define SCDC_ERR_DET_1_H 0x53 +#define SCDC_ERR_DET_2_L 0x54 +#define SCDC_ERR_DET_2_H 0x55 +#define SCDC_CHANNEL_VALID BIT(7) +#define SCDC_ERR_DET_CHECKSUM 0x56 + +#define SCDC_TEST_CONFIG_0 0xc0 +#define SCDC_TEST_READ_REQUEST BIT(7) +#define SCDC_TEST_READ_REQUEST_DELAY(x) ((x) & 0x7f) + +#define SCDC_MANUFACTURER_IEEE_OUI 0xd0 +#define SCDC_MANUFACTURER_IEEE_OUI_SIZE 3 +#define SCDC_DEVICE_ID 0xd3 +#define SCDC_DEVICE_ID_SIZE 8 +#define SCDC_DEVICE_HARDWARE_REVISION 0xdb +#define SCDC_DEVICE_HARDWARE_REVISION_MAJOR(x) (((x) >> 4) & 0xf) +#define SCDC_DEVICE_HARDWARE_REVISION_MINOR(x) (((x) >> 0) & 0xf) +#define SCDC_DEVICE_SOFTWARE_MAJOR_REVISION 0xdc +#define SCDC_DEVICE_SOFTWARE_MINOR_REVISION 0xdd + +#define SCDC_MANUFACTURER_SPECIFIC 0xde +#define SCDC_MANUFACTURER_SPECIFIC_SIZE 34 + +#define HDMI0_BASE 0xFDE80000 +#define HDMI1_BASE 0xFDEA0000 + +#define HDMI0TX_PHY_BASE 0xFED60000 +#define HDMI1TX_PHY_BASE 0xFED70000 + +#define HDPTXPHY0_GRF_BASE 0xFD5E0000 +#define HDPTXPHY1_GRF_BASE 0xFD5E4000 + +#define PMU1CRU_SOFTRST_CON03 0xA0C +#define PMU1CRU_SOFTRST_CON04 0xA10 + +struct DwHdmiQpI2c { + BOOLEAN Cmp; + UINT32 Stat; + UINT32 PinMux; + + UINT8 SlaveReg; + BOOLEAN IsSegment; + BOOLEAN IsRegAddr; +}; + +struct DwHdmiQpDevice { + UINT32 Id; + BOOLEAN ForceHpd; + struct DwHdmiQpI2c I2c; + UINT32 ScdcIntr; + UINT32 FltIntr; + UINT32 EarcIntr; + + BOOLEAN FltCmp; +}; + +struct i2c_msg { + UINT16 addr; + UINT16 flags; +#define I2C_M_RD 0x0001 /* guaranteed to be 0x0001! */ +#define I2C_M_TEN 0x0010 /* use only if I2C_FUNC_10BIT_ADDR */ +#define I2C_M_DMA_SAFE 0x0200 /* use only in kernel space */ +#define I2C_M_RECV_LEN 0x0400 /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */ +#define I2C_M_NO_RD_ACK 0x0800 /* use only if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_IGNORE_NAK 0x1000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_REV_DIR_ADDR 0x2000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_NOSTART 0x4000 /* use only if I2C_FUNC_NOSTART */ +#define I2C_M_STOP 0x8000 /* use only if I2C_FUNC_PROTOCOL_MANGLING */ + UINT16 len; + UINT8 *buf; +}; + +/* Rockchip Htx Phy */ + +struct RockchipHdptxPhyHdmi { + UINT32 Id; +}; + +EFI_STATUS +DwHdmiQpConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +DwHdmiQpConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +DwHdmiQpConnectorGetEdid ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +DwHdmiQpConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +DwHdmiQpConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +EFI_STATUS +DwHdmiQpConnectorDetect ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ); + +UINT32 +HdptxRopllTmdsModeConfig ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ); + +UINT32 +HdptxRopllCmnConfig ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ); +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwcSdhciPlatformLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwcSdhciPlatformLib.h new file mode 100644 index 0000000..6e53ccf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/DwcSdhciPlatformLib.h @@ -0,0 +1,21 @@ +/** @file + * + * DwcSdhciDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +EFI_STATUS +EFIAPI +DwcSdhciSetClockRate ( + IN UINTN Frequency + ); + +VOID +EFIAPI +DwcSdhciSetIoMux ( + VOID + ); diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Fspi.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Fspi.h new file mode 100644 index 0000000..9ec2bc9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Fspi.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ +#ifndef _HAL_FSPI_H_ +#define _HAL_FSPI_H_ + +#define HAL_FSPI_QUAD_ENABLE +#define HAL_FSPI_SPEED_THRESHOLD 100000000 + +/***************************** Structure Definition **************************/ +/** FSPI_CTRL register datalines, addrlines and cmdlines value */ +#define FSPI_LINES_X1 (0) +#define FSPI_LINES_X2 (1) +#define FSPI_LINES_X4 (2) + +/** FSPI_CTRL bit union */ +typedef union { + UINT32 d32; + struct { + unsigned mode : 1; /**< spi mode select */ + unsigned sps : 1; /**< shift in phase at: posedge 1: negedge */ + unsigned reserved3_2 : 2; + unsigned scic : 4; /**< sclk_idle_level_cycles */ + unsigned cmdlines : 2; /**< cmd bits number */ + unsigned addrlines : 2; /**< address bits number */ + unsigned datalines : 2; /**< data bits number */ + unsigned reserved14_15 : 2; + unsigned addrbits : 5; + unsigned reserved31_21 : 11; + } b; +} FSPICTRL_DATA; + +/** FSPI_CMD register rw value without shift */ +#define FSPI_READ (0) +#define FSPI_WRITE (1) + +/** FSPI_CMD regitser addrbits value without shift */ +#define FSPI_ADDR_0BITS (0) +#define FSPI_ADDR_24BITS (1) +#define FSPI_ADDR_32BITS (2) +#define FSPI_ADDR_XBITS (3) + +/** FSPI_CMD bit union */ +typedef union { + UINT32 d32; + struct { + unsigned cmd : 8; /**< command that will send to Serial Flash */ + unsigned dummybits : 4; /**< dummy bits number */ + unsigned rw : 1; /**< 0:read, 1: write */ + unsigned readmode : 1; /**< continuous read mode */ + unsigned addrbits : 2; /**< address bits number */ + unsigned datasize : 14; /**< transferred bytes number */ + unsigned cs : 2; /**< chip select */ + } b; +} FSPICMD_DATA; + +typedef enum { + DEV_UNKNON = 0, + DEV_NOR, + DEV_PSRAM, +} eFSPI_devType; + +struct HAL_FSPI_XMMC_DEV { + eFSPI_devType type; + UINT32 ctrl; + UINT32 readCmd; + UINT32 writeCmd; +}; + +/** XIP may be not accessble, so place it in sram or psram */ +struct HAL_FSPI_HOST { + struct FSPI_REG *instance; + UINT32 *CruBase; + UINT8 cs; /**< Should be defined by user in each operation */ + UINT8 mode; /**< Should be defined by user, referring to hal_spi_mem.h */ + UINT8 cell; /**< Record DLL cell for PM resume, Set depend on corresponding device */ +}; + +#define HAL_FSPI_MAX_DELAY_LINE_CELLS (0xFFU) +RETURN_STATUS HAL_FSPI_Init(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_DeInit(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_XferStart(struct HAL_FSPI_HOST *host, struct HAL_SPI_MEM_OP *op); +RETURN_STATUS HAL_FSPI_XferData(struct HAL_FSPI_HOST *host, UINT32 len, void *data, UINT32 dir); +RETURN_STATUS HAL_FSPI_XferData_DMA(struct HAL_FSPI_HOST *host, UINT32 len, void *data, UINT32 dir); +RETURN_STATUS HAL_FSPI_XferDone(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_SpiXfer(struct HAL_FSPI_HOST *host, struct HAL_SPI_MEM_OP *op); +RETURN_STATUS HAL_FSPI_IRQHelper(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_MaskDMAInterrupt(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_UnmaskDMAInterrupt(struct HAL_FSPI_HOST *host); +RETURN_STATUS HAL_FSPI_XmmcSetting(struct HAL_FSPI_HOST *host, struct HAL_SPI_MEM_OP *op); +RETURN_STATUS HAL_FSPI_XmmcRequest(struct HAL_FSPI_HOST *host, UINT8 on); +RETURN_STATUS HAL_FSPI_SetDelayLines(struct HAL_FSPI_HOST *host, UINT8 cells); +RETURN_STATUS HAL_FSPI_DLLDisable(struct HAL_FSPI_HOST *host); +UINT32 HAL_FSPI_GetXMMCStatus(struct HAL_FSPI_HOST *host); +UINT32 HAL_FSPI_GetMaxIoSize(struct HAL_FSPI_HOST *host); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/HalDef.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/HalDef.h new file mode 100644 index 0000000..c43e341 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/HalDef.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#ifndef _HAL_DEF_H_ +#define _HAL_DEF_H_ + +#include "Soc.h" + +/* SOC OPS Marco */ +#define SET_BIT(REG, BIT) ((*(volatile uint32_t *)&(REG)) |= (BIT)) +#define CLEAR_BIT(REG, MASK) ((*(volatile uint32_t *)&(REG)) &= ~(MASK)) +#define READ_BIT(REG, MASK) ((*(volatile const uint32_t *)&(REG)) & (MASK)) +#define CLEAR_REG(REG) ((*(volatile uint32_t *)&(REG)) = (0x0)) +#define WRITE_REG(REG, VAL) ((*(volatile uint32_t *)&(REG)) = (VAL)) +#define READ_REG(REG) ((*(volatile const uint32_t *)&(REG))) +#define MODIFY_REG(REG, CLEARMASK, SETMASK) \ + WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) +#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) + +#if defined(__GNUC__) || defined(__CC_ARM) +#define MASK_TO_WE(msk) (__builtin_constant_p(msk) ? ((msk) > 0xFFFFU ? 0 : ((msk) << 16)) : ((msk) << 16)) +#else +#define MASK_TO_WE(msk) ((msk) << 16) +#endif +#define VAL_MASK_WE(msk, val) ((MASK_TO_WE(msk)) | (val)) +#define WRITE_REG_MASK_WE(reg, msk, val) WRITE_REG(reg, (VAL_MASK_WE(msk, val))) + +/* Misc OPS Marco */ +#define HAL_MAX_DELAY 0xFFFFFFFFU + +#define RESET 0 +#define HAL_IS_BIT_SET(REG, MASK) (((*(volatile uint32_t *)&(REG)) & (MASK)) != RESET) +#define HAL_IS_BIT_CLR(REG, MASK) (((*(volatile uint32_t *)&(REG)) & (MASK)) == RESET) + +#define HAL_BIT(nr) (1UL << (nr)) +#define HAL_ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#define HAL_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define HAL_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define HAL_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) + +#define HAL_IS_ALIGNED(x, a) (((x) & (a - 1)) == 0) +#ifdef CACHE_LINE_SIZE +#define HAL_IS_CACHELINE_ALIGNED(x) HAL_IS_ALIGNED((uint32_t)(x), CACHE_LINE_SIZE) +#else +#define HAL_IS_CACHELINE_ALIGNED(x) HAL_IS_ALIGNED((uint32_t)(x), 4) +#endif + +/* Compiller Macro */ +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) || defined(__ICCARM__) +#define HAL_UNUSED __attribute__((__unused__)) +#else +#define HAL_UNUSED +#endif + +#ifdef CACHE_LINE_SIZE +#define HAL_CACHELINE_ALIGNED __ALIGNED(CACHE_LINE_SIZE) +#else +#define HAL_CACHELINE_ALIGNED +#endif + +#ifdef HAL_SRAM_SECTION_ENABLED +#define HAL_SECTION_SRAM_CODE __attribute__((section(".sram_code"))) +#define HAL_SECTION_SRAM_RODATA __attribute__((section(".sram_rodata"))) +#define HAL_SECTION_SRAM_DATA __attribute__((section(".sram_data"))) +#define HAL_SECTION_SRAM_BSS __attribute__((section(".sram_bss"))) +#else +#define HAL_SECTION_SRAM_CODE +#define HAL_SECTION_SRAM_RODATA +#define HAL_SECTION_SRAM_DATA +#define HAL_SECTION_SRAM_BSS +#endif + +#ifdef HAL_PSRAM_SECTION_ENABLED +#define HAL_SECTION_PSRAM_CODE __attribute__((section(".psram_code"))) +#define HAL_SECTION_PSRAM_RODATA __attribute__((section(".psram_rodata"))) +#define HAL_SECTION_PSRAM_DATA __attribute__((section(".psram_data"))) +#define HAL_SECTION_PSRAM_BSS __attribute__((section(".psram_bss"))) +#else +#define HAL_SECTION_PSRAM_CODE +#define HAL_SECTION_PSRAM_RODATA +#define HAL_SECTION_PSRAM_DATA +#define HAL_SECTION_PSRAM_BSS +#endif + +#ifdef HAL_XIP_SECTION_ENABLED +#define HAL_SECTION_XIP_CODE __attribute__((section(".xip_code"))) +#define HAL_SECTION_XIP_RODATA __attribute__((section(".xip_rodata"))) +#else +#define HAL_SECTION_XIP_CODE +#define HAL_SECTION_XIP_RODATA +#endif + +typedef enum { + HAL_SYSTICK_CLKSRC_CORE, + HAL_SYSTICK_CLKSRC_EXT +} eHAL_systickClkSource; + +#define IS_SYSTICK_SOURCE(s) (((s) == HAL_SYSTICK_CLKSRC_CORE) || ((s) == HAL_SYSTICK_CLKSRC_EXT)) + +/***************************** Structure Definition **************************/ +typedef enum { + HAL_FALSE = 0x00U, + HAL_TRUE = 0x01U +} HAL_Check; + +typedef enum { + HAL_OK = 0x00U, + HAL_ERROR = (-1), + HAL_BUSY = (-16), + HAL_NODEV = (-19), + HAL_INVAL = (-22), + HAL_NOSYS = (-38), + HAL_TIMEOUT = (-110) +} HAL_Status; + +typedef enum { + HAL_DISABLE = 0x00U, + HAL_ENABLE = 0x01U +} HAL_FuncStatus; + +typedef enum { + HAL_UNLOCKED = 0x00U, + HAL_LOCKED = 0x01U +} HAL_LockStatus; + +typedef enum { + GPIO_BANK0 = 0, + GPIO_BANK1 = 1, + GPIO_BANK2 = 2, + GPIO_BANK3 = 3, + GPIO_BANK4 = 4, + GPIO_BANK_NUM +} eGPIO_bankId; + +typedef void (*pFunc)(void); + +/***************************** Function Declare ******************************/ + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/MediaBusFormat.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/MediaBusFormat.h new file mode 100644 index 0000000..405514b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/MediaBusFormat.h @@ -0,0 +1,163 @@ +/* + * Media Bus API header + * + * Copyright (C) 2009, Guennadi Liakhovetski + * Copyright (c) 2022 Rockchip Electronics Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ + +#ifndef __LINUX_MEDIA_BUS_FORMAT_H +#define __LINUX_MEDIA_BUS_FORMAT_H + +/* + * These bus formats uniquely identify data formats on the data bus. Format 0 + * is reserved, MEDIA_BUS_FMT_FIXED shall be used by host-client pairs, where + * the data format is fixed. Additionally, "2X8" means that one pixel is + * transferred in two 8-bit samples, "BE" or "LE" specify in which order those + * samples are transferred over the bus: "LE" means that the least significant + * bits are transferred first, "BE" means that the most significant bits are + * transferred first, and "PADHI" and "PADLO" define which bits - low or high, + * in the incomplete high byte, are filled with padding bits. + * + * The bus formats are grouped by type, bus_width, bits per component, samples + * per pixel and order of subsamples. Numerical values are sorted using generic + * numerical sort order (8 thus comes before 10). + * + * As their value can't change when a new bus format is inserted in the + * enumeration, the bus formats are explicitly given a numerical value. The next + * free values for each category are listed below, update them when inserting + * new pixel codes. + */ + +#define MEDIA_BUS_FMT_FIXED 0x0001 + +/* RGB - next is 0x1024 */ +#define MEDIA_BUS_FMT_RGB444_1X12 0x1016 +#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 +#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 +#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 +#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004 +#define MEDIA_BUS_FMT_RGB565_1X16 0x1017 +#define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005 +#define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006 +#define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 +#define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 +#define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RBG888_1X24 0x100e +#define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 +#define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 +#define MEDIA_BUS_FMT_BGR888_1X24 0x1013 +#define MEDIA_BUS_FMT_GBR888_1X24 0x1014 +#define MEDIA_BUS_FMT_RGB888_1X24 0x100a +#define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b +#define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c +#define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG 0x1011 +#define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 +#define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d +#define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f +#define MEDIA_BUS_FMT_RGB101010_1X30 0x1018 +#define MEDIA_BUS_FMT_RGB121212_1X36 0x1019 +#define MEDIA_BUS_FMT_RGB161616_1X48 0x101a +#define MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA 0x101b +#define MEDIA_BUS_FMT_SRGB888_3X8 0x101c +#define MEDIA_BUS_FMT_SBGR888_3X8 0x101d +#define MEDIA_BUS_FMT_SRBG888_3X8 0x101e +#define MEDIA_BUS_FMT_SRGB888_DUMMY_4X8 0x101f +#define MEDIA_BUS_FMT_SBGR888_DUMMY_4X8 0x1020 +#define MEDIA_BUS_FMT_SRBG888_DUMMY_4X8 0x1021 +#define MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG 0x1022 +#define MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA 0x1023 + +/* YUV (including grey) - next is 0x2026 */ +#define MEDIA_BUS_FMT_Y8_1X8 0x2001 +#define MEDIA_BUS_FMT_UV8_1X8 0x2015 +#define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 +#define MEDIA_BUS_FMT_VYUY8_1_5X8 0x2003 +#define MEDIA_BUS_FMT_YUYV8_1_5X8 0x2004 +#define MEDIA_BUS_FMT_YVYU8_1_5X8 0x2005 +#define MEDIA_BUS_FMT_UYVY8_2X8 0x2006 +#define MEDIA_BUS_FMT_VYUY8_2X8 0x2007 +#define MEDIA_BUS_FMT_YUYV8_2X8 0x2008 +#define MEDIA_BUS_FMT_YVYU8_2X8 0x2009 +#define MEDIA_BUS_FMT_Y10_1X10 0x200a +#define MEDIA_BUS_FMT_UYVY10_2X10 0x2018 +#define MEDIA_BUS_FMT_VYUY10_2X10 0x2019 +#define MEDIA_BUS_FMT_YUYV10_2X10 0x200b +#define MEDIA_BUS_FMT_YVYU10_2X10 0x200c +#define MEDIA_BUS_FMT_Y12_1X12 0x2013 +#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c +#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d +#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e +#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f +#define MEDIA_BUS_FMT_UYVY8_1X16 0x200f +#define MEDIA_BUS_FMT_VYUY8_1X16 0x2010 +#define MEDIA_BUS_FMT_YUYV8_1X16 0x2011 +#define MEDIA_BUS_FMT_YVYU8_1X16 0x2012 +#define MEDIA_BUS_FMT_YDYUYDYV8_1X16 0x2014 +#define MEDIA_BUS_FMT_UYVY10_1X20 0x201a +#define MEDIA_BUS_FMT_VYUY10_1X20 0x201b +#define MEDIA_BUS_FMT_YUYV10_1X20 0x200d +#define MEDIA_BUS_FMT_YVYU10_1X20 0x200e +#define MEDIA_BUS_FMT_VUY8_1X24 0x2024 +#define MEDIA_BUS_FMT_YUV8_1X24 0x2025 +#define MEDIA_BUS_FMT_UYYVYY8_0_5X24 0x2026 +#define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 +#define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 +#define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 +#define MEDIA_BUS_FMT_YVYU12_1X24 0x2023 +#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 +#define MEDIA_BUS_FMT_UYYVYY10_0_5X30 0x2027 +#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 +#define MEDIA_BUS_FMT_UYYVYY12_0_5X36 0x2028 +#define MEDIA_BUS_FMT_YUV12_1X36 0x2029 +#define MEDIA_BUS_FMT_YUV16_1X48 0x202a +#define MEDIA_BUS_FMT_UYYVYY16_0_5X48 0x202b + +/* Bayer - next is 0x3019 */ +#define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 +#define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013 +#define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002 +#define MEDIA_BUS_FMT_SRGGB8_1X8 0x3014 +#define MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 0x3015 +#define MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 0x3016 +#define MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 0x3017 +#define MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 0x3018 +#define MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 0x300b +#define MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 0x300c +#define MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 0x3009 +#define MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 0x300d +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE 0x3003 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE 0x3004 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE 0x3005 +#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE 0x3006 +#define MEDIA_BUS_FMT_SBGGR10_1X10 0x3007 +#define MEDIA_BUS_FMT_SGBRG10_1X10 0x300e +#define MEDIA_BUS_FMT_SGRBG10_1X10 0x300a +#define MEDIA_BUS_FMT_SRGGB10_1X10 0x300f +#define MEDIA_BUS_FMT_SBGGR12_1X12 0x3008 +#define MEDIA_BUS_FMT_SGBRG12_1X12 0x3010 +#define MEDIA_BUS_FMT_SGRBG12_1X12 0x3011 +#define MEDIA_BUS_FMT_SRGGB12_1X12 0x3012 + +/* JPEG compressed formats - next is 0x4002 */ +#define MEDIA_BUS_FMT_JPEG_1X8 0x4001 + +/* Vendor specific formats - next is 0x5002 */ + +/* S5C73M3 sensor specific interleaved UYVY and JPEG */ +#define MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8 0x5001 + +/* HSV - next is 0x6002 */ +#define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 + +/* Panel Mirror control */ +#define DRM_MODE_FLAG_XMIRROR (1<<28) +#define DRM_MODE_FLAG_YMIRROR (1<<29) +#define DRM_MODE_FLAG_XYMIRROR (DRM_MODE_FLAG_XMIRROR | DRM_MODE_FLAG_YMIRROR) + +#endif /* __LINUX_MEDIA_BUS_FORMAT_H */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/OtpLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/OtpLib.h new file mode 100644 index 0000000..4af1358 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/OtpLib.h @@ -0,0 +1,35 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef OTPLIB_H__ +#define OTPLIB_H__ + +VOID +OtpRead ( + IN UINT16 Offset, + IN UINT16 Length, + OUT UINT8 *Data + ); + +VOID +OtpReadCpuCode ( + OUT UINT16 *CpuCode + ); + +VOID +OtpReadId ( + OUT UINT8 Id[16] + ); + +VOID +OtpReadCpuVersion ( + OUT UINT8 *Version + ); + +#endif /* OTPLIB_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/PWMLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/PWMLib.h new file mode 100644 index 0000000..e4e0e8e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/PWMLib.h @@ -0,0 +1,423 @@ +/** @file + Rockchip PWM Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PWM_H__ +#define __PWM_H__ + +/******************************************PWM*******************************************/ +/* PWM0_CNT */ +#define PWM_PWM0_CNT_OFFSET (0x0U) +#define PWM_PWM0_CNT (0x0U) +#define PWM_PWM0_CNT_CNT_SHIFT (0U) +#define PWM_PWM0_CNT_CNT_MASK (0xFFFFFFFFU << PWM_PWM0_CNT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PWM0_PERIOD_HPR */ +#define PWM_PWM0_PERIOD_HPR_OFFSET (0x4U) +#define PWM_PWM0_PERIOD_HPR_PERIOD_HPR_SHIFT (0U) +#define PWM_PWM0_PERIOD_HPR_PERIOD_HPR_MASK (0xFFFFFFFFU << PWM_PWM0_PERIOD_HPR_PERIOD_HPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM0_DUTY_LPR */ +#define PWM_PWM0_DUTY_LPR_OFFSET (0x8U) +#define PWM_PWM0_DUTY_LPR_DUTY_LPR_SHIFT (0U) +#define PWM_PWM0_DUTY_LPR_DUTY_LPR_MASK (0xFFFFFFFFU << PWM_PWM0_DUTY_LPR_DUTY_LPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM0_CTRL */ +#define PWM_PWM0_CTRL_OFFSET (0xCU) +#define PWM_PWM0_CTRL_PWM_EN_SHIFT (0U) +#define PWM_PWM0_CTRL_PWM_EN_MASK (0x1U << PWM_PWM0_CTRL_PWM_EN_SHIFT) /* 0x00000001 */ +#define PWM_PWM0_CTRL_PWM_MODE_SHIFT (1U) +#define PWM_PWM0_CTRL_PWM_MODE_MASK (0x3U << PWM_PWM0_CTRL_PWM_MODE_SHIFT) /* 0x00000006 */ +#define PWM_PWM0_CTRL_DUTY_POL_SHIFT (3U) +#define PWM_PWM0_CTRL_DUTY_POL_MASK (0x1U << PWM_PWM0_CTRL_DUTY_POL_SHIFT) /* 0x00000008 */ +#define PWM_PWM0_CTRL_INACTIVE_POL_SHIFT (4U) +#define PWM_PWM0_CTRL_INACTIVE_POL_MASK (0x1U << PWM_PWM0_CTRL_INACTIVE_POL_SHIFT) /* 0x00000010 */ +#define PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT (5U) +#define PWM_PWM0_CTRL_OUTPUT_MODE_MASK (0x1U << PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT) /* 0x00000020 */ +#define PWM_PWM0_CTRL_CONLOCK_SHIFT (6U) +#define PWM_PWM0_CTRL_CONLOCK_MASK (0x1U << PWM_PWM0_CTRL_CONLOCK_SHIFT) /* 0x00000040 */ +#define PWM_PWM0_CTRL_CH_CNT_EN_SHIFT (7U) +#define PWM_PWM0_CTRL_CH_CNT_EN_MASK (0x1U << PWM_PWM0_CTRL_CH_CNT_EN_SHIFT) /* 0x00000080 */ +#define PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT (8U) +#define PWM_PWM0_CTRL_FORCE_CLK_EN_MASK (0x1U << PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT) /* 0x00000100 */ +#define PWM_PWM0_CTRL_CLK_SEL_SHIFT (9U) +#define PWM_PWM0_CTRL_CLK_SEL_MASK (0x1U << PWM_PWM0_CTRL_CLK_SEL_SHIFT) /* 0x00000200 */ +#define PWM_PWM0_CTRL_CLK_SRC_SEL_SHIFT (10U) +#define PWM_PWM0_CTRL_CLK_SRC_SEL_MASK (0x1U << PWM_PWM0_CTRL_CLK_SRC_SEL_SHIFT) /* 0x00000400 */ +#define PWM_PWM0_CTRL_PRESCALE_SHIFT (12U) +#define PWM_PWM0_CTRL_PRESCALE_MASK (0x7U << PWM_PWM0_CTRL_PRESCALE_SHIFT) /* 0x00007000 */ +#define PWM_PWM0_CTRL_SCALE_SHIFT (16U) +#define PWM_PWM0_CTRL_SCALE_MASK (0xFFU << PWM_PWM0_CTRL_SCALE_SHIFT) /* 0x00FF0000 */ +#define PWM_PWM0_CTRL_RPT_SHIFT (24U) +#define PWM_PWM0_CTRL_RPT_MASK (0xFFU << PWM_PWM0_CTRL_RPT_SHIFT) /* 0xFF000000 */ +/* PWM1_CNT */ +#define PWM_PWM1_CNT_OFFSET (0x10U) +#define PWM_PWM1_CNT (0x0U) +#define PWM_PWM1_CNT_CNT_SHIFT (0U) +#define PWM_PWM1_CNT_CNT_MASK (0xFFFFFFFFU << PWM_PWM1_CNT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PWM1_PERIOD_HPR */ +#define PWM_PWM1_PERIOD_HPR_OFFSET (0x14U) +#define PWM_PWM1_PERIOD_HPR_PERIOD_HPR_SHIFT (0U) +#define PWM_PWM1_PERIOD_HPR_PERIOD_HPR_MASK (0xFFFFFFFFU << PWM_PWM1_PERIOD_HPR_PERIOD_HPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM1_DUTY_LPR */ +#define PWM_PWM1_DUTY_LPR_OFFSET (0x18U) +#define PWM_PWM1_DUTY_LPR_DUTY_LPR_SHIFT (0U) +#define PWM_PWM1_DUTY_LPR_DUTY_LPR_MASK (0xFFFFFFFFU << PWM_PWM1_DUTY_LPR_DUTY_LPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM1_CTRL */ +#define PWM_PWM1_CTRL_OFFSET (0x1CU) +#define PWM_PWM1_CTRL_PWM_EN_SHIFT (0U) +#define PWM_PWM1_CTRL_PWM_EN_MASK (0x1U << PWM_PWM1_CTRL_PWM_EN_SHIFT) /* 0x00000001 */ +#define PWM_PWM1_CTRL_PWM_MODE_SHIFT (1U) +#define PWM_PWM1_CTRL_PWM_MODE_MASK (0x3U << PWM_PWM1_CTRL_PWM_MODE_SHIFT) /* 0x00000006 */ +#define PWM_PWM1_CTRL_DUTY_POL_SHIFT (3U) +#define PWM_PWM1_CTRL_DUTY_POL_MASK (0x1U << PWM_PWM1_CTRL_DUTY_POL_SHIFT) /* 0x00000008 */ +#define PWM_PWM1_CTRL_INACTIVE_POL_SHIFT (4U) +#define PWM_PWM1_CTRL_INACTIVE_POL_MASK (0x1U << PWM_PWM1_CTRL_INACTIVE_POL_SHIFT) /* 0x00000010 */ +#define PWM_PWM1_CTRL_OUTPUT_MODE_SHIFT (5U) +#define PWM_PWM1_CTRL_OUTPUT_MODE_MASK (0x1U << PWM_PWM1_CTRL_OUTPUT_MODE_SHIFT) /* 0x00000020 */ +#define PWM_PWM1_CTRL_CONLOCK_SHIFT (6U) +#define PWM_PWM1_CTRL_CONLOCK_MASK (0x1U << PWM_PWM1_CTRL_CONLOCK_SHIFT) /* 0x00000040 */ +#define PWM_PWM1_CTRL_CH_CNT_EN_SHIFT (7U) +#define PWM_PWM1_CTRL_CH_CNT_EN_MASK (0x1U << PWM_PWM1_CTRL_CH_CNT_EN_SHIFT) /* 0x00000080 */ +#define PWM_PWM1_CTRL_FORCE_CLK_EN_SHIFT (8U) +#define PWM_PWM1_CTRL_FORCE_CLK_EN_MASK (0x1U << PWM_PWM1_CTRL_FORCE_CLK_EN_SHIFT) /* 0x00000100 */ +#define PWM_PWM1_CTRL_CLK_SEL_SHIFT (9U) +#define PWM_PWM1_CTRL_CLK_SEL_MASK (0x1U << PWM_PWM1_CTRL_CLK_SEL_SHIFT) /* 0x00000200 */ +#define PWM_PWM1_CTRL_CLK_SRC_SEL_SHIFT (10U) +#define PWM_PWM1_CTRL_CLK_SRC_SEL_MASK (0x1U << PWM_PWM1_CTRL_CLK_SRC_SEL_SHIFT) /* 0x00000400 */ +#define PWM_PWM1_CTRL_PRESCALE_SHIFT (12U) +#define PWM_PWM1_CTRL_PRESCALE_MASK (0x7U << PWM_PWM1_CTRL_PRESCALE_SHIFT) /* 0x00007000 */ +#define PWM_PWM1_CTRL_SCALE_SHIFT (16U) +#define PWM_PWM1_CTRL_SCALE_MASK (0xFFU << PWM_PWM1_CTRL_SCALE_SHIFT) /* 0x00FF0000 */ +#define PWM_PWM1_CTRL_RPT_SHIFT (24U) +#define PWM_PWM1_CTRL_RPT_MASK (0xFFU << PWM_PWM1_CTRL_RPT_SHIFT) /* 0xFF000000 */ +/* PWM2_CNT */ +#define PWM_PWM2_CNT_OFFSET (0x20U) +#define PWM_PWM2_CNT (0x0U) +#define PWM_PWM2_CNT_CNT_SHIFT (0U) +#define PWM_PWM2_CNT_CNT_MASK (0xFFFFFFFFU << PWM_PWM2_CNT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PWM2_PERIOD_HPR */ +#define PWM_PWM2_PERIOD_HPR_OFFSET (0x24U) +#define PWM_PWM2_PERIOD_HPR_PERIOD_HPR_SHIFT (0U) +#define PWM_PWM2_PERIOD_HPR_PERIOD_HPR_MASK (0xFFFFFFFFU << PWM_PWM2_PERIOD_HPR_PERIOD_HPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM2_DUTY_LPR */ +#define PWM_PWM2_DUTY_LPR_OFFSET (0x28U) +#define PWM_PWM2_DUTY_LPR_DUTY_LPR_SHIFT (0U) +#define PWM_PWM2_DUTY_LPR_DUTY_LPR_MASK (0xFFFFFFFFU << PWM_PWM2_DUTY_LPR_DUTY_LPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM2_CTRL */ +#define PWM_PWM2_CTRL_OFFSET (0x2CU) +#define PWM_PWM2_CTRL_PWM_EN_SHIFT (0U) +#define PWM_PWM2_CTRL_PWM_EN_MASK (0x1U << PWM_PWM2_CTRL_PWM_EN_SHIFT) /* 0x00000001 */ +#define PWM_PWM2_CTRL_PWM_MODE_SHIFT (1U) +#define PWM_PWM2_CTRL_PWM_MODE_MASK (0x3U << PWM_PWM2_CTRL_PWM_MODE_SHIFT) /* 0x00000006 */ +#define PWM_PWM2_CTRL_DUTY_POL_SHIFT (3U) +#define PWM_PWM2_CTRL_DUTY_POL_MASK (0x1U << PWM_PWM2_CTRL_DUTY_POL_SHIFT) /* 0x00000008 */ +#define PWM_PWM2_CTRL_INACTIVE_POL_SHIFT (4U) +#define PWM_PWM2_CTRL_INACTIVE_POL_MASK (0x1U << PWM_PWM2_CTRL_INACTIVE_POL_SHIFT) /* 0x00000010 */ +#define PWM_PWM2_CTRL_OUTPUT_MODE_SHIFT (5U) +#define PWM_PWM2_CTRL_OUTPUT_MODE_MASK (0x1U << PWM_PWM2_CTRL_OUTPUT_MODE_SHIFT) /* 0x00000020 */ +#define PWM_PWM2_CTRL_CONLOCK_SHIFT (6U) +#define PWM_PWM2_CTRL_CONLOCK_MASK (0x1U << PWM_PWM2_CTRL_CONLOCK_SHIFT) /* 0x00000040 */ +#define PWM_PWM2_CTRL_CH_CNT_EN_SHIFT (7U) +#define PWM_PWM2_CTRL_CH_CNT_EN_MASK (0x1U << PWM_PWM2_CTRL_CH_CNT_EN_SHIFT) /* 0x00000080 */ +#define PWM_PWM2_CTRL_FORCE_CLK_EN_SHIFT (8U) +#define PWM_PWM2_CTRL_FORCE_CLK_EN_MASK (0x1U << PWM_PWM2_CTRL_FORCE_CLK_EN_SHIFT) /* 0x00000100 */ +#define PWM_PWM2_CTRL_CLK_SEL_SHIFT (9U) +#define PWM_PWM2_CTRL_CLK_SEL_MASK (0x1U << PWM_PWM2_CTRL_CLK_SEL_SHIFT) /* 0x00000200 */ +#define PWM_PWM2_CTRL_CLK_SRC_SEL_SHIFT (10U) +#define PWM_PWM2_CTRL_CLK_SRC_SEL_MASK (0x1U << PWM_PWM2_CTRL_CLK_SRC_SEL_SHIFT) /* 0x00000400 */ +#define PWM_PWM2_CTRL_PRESCALE_SHIFT (12U) +#define PWM_PWM2_CTRL_PRESCALE_MASK (0x7U << PWM_PWM2_CTRL_PRESCALE_SHIFT) /* 0x00007000 */ +#define PWM_PWM2_CTRL_SCALE_SHIFT (16U) +#define PWM_PWM2_CTRL_SCALE_MASK (0xFFU << PWM_PWM2_CTRL_SCALE_SHIFT) /* 0x00FF0000 */ +#define PWM_PWM2_CTRL_RPT_SHIFT (24U) +#define PWM_PWM2_CTRL_RPT_MASK (0xFFU << PWM_PWM2_CTRL_RPT_SHIFT) /* 0xFF000000 */ +/* PWM3_CNT */ +#define PWM_PWM3_CNT_OFFSET (0x30U) +#define PWM_PWM3_CNT (0x0U) +#define PWM_PWM3_CNT_CNT_SHIFT (0U) +#define PWM_PWM3_CNT_CNT_MASK (0xFFFFFFFFU << PWM_PWM3_CNT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PWM3_PERIOD_HPR */ +#define PWM_PWM3_PERIOD_HPR_OFFSET (0x34U) +#define PWM_PWM3_PERIOD_HPR_PERIOD_HPR_SHIFT (0U) +#define PWM_PWM3_PERIOD_HPR_PERIOD_HPR_MASK (0xFFFFFFFFU << PWM_PWM3_PERIOD_HPR_PERIOD_HPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM3_DUTY_LPR */ +#define PWM_PWM3_DUTY_LPR_OFFSET (0x38U) +#define PWM_PWM3_DUTY_LPR_DUTY_LPR_SHIFT (0U) +#define PWM_PWM3_DUTY_LPR_DUTY_LPR_MASK (0xFFFFFFFFU << PWM_PWM3_DUTY_LPR_DUTY_LPR_SHIFT) /* 0xFFFFFFFF */ +/* PWM3_CTRL */ +#define PWM_PWM3_CTRL_OFFSET (0x3CU) +#define PWM_PWM3_CTRL_PWM_EN_SHIFT (0U) +#define PWM_PWM3_CTRL_PWM_EN_MASK (0x1U << PWM_PWM3_CTRL_PWM_EN_SHIFT) /* 0x00000001 */ +#define PWM_PWM3_CTRL_PWM_MODE_SHIFT (1U) +#define PWM_PWM3_CTRL_PWM_MODE_MASK (0x3U << PWM_PWM3_CTRL_PWM_MODE_SHIFT) /* 0x00000006 */ +#define PWM_PWM3_CTRL_DUTY_POL_SHIFT (3U) +#define PWM_PWM3_CTRL_DUTY_POL_MASK (0x1U << PWM_PWM3_CTRL_DUTY_POL_SHIFT) /* 0x00000008 */ +#define PWM_PWM3_CTRL_INACTIVE_POL_SHIFT (4U) +#define PWM_PWM3_CTRL_INACTIVE_POL_MASK (0x1U << PWM_PWM3_CTRL_INACTIVE_POL_SHIFT) /* 0x00000010 */ +#define PWM_PWM3_CTRL_OUTPUT_MODE_SHIFT (5U) +#define PWM_PWM3_CTRL_OUTPUT_MODE_MASK (0x1U << PWM_PWM3_CTRL_OUTPUT_MODE_SHIFT) /* 0x00000020 */ +#define PWM_PWM3_CTRL_CONLOCK_SHIFT (6U) +#define PWM_PWM3_CTRL_CONLOCK_MASK (0x1U << PWM_PWM3_CTRL_CONLOCK_SHIFT) /* 0x00000040 */ +#define PWM_PWM3_CTRL_CH_CNT_EN_SHIFT (7U) +#define PWM_PWM3_CTRL_CH_CNT_EN_MASK (0x1U << PWM_PWM3_CTRL_CH_CNT_EN_SHIFT) /* 0x00000080 */ +#define PWM_PWM3_CTRL_FORCE_CLK_EN_SHIFT (8U) +#define PWM_PWM3_CTRL_FORCE_CLK_EN_MASK (0x1U << PWM_PWM3_CTRL_FORCE_CLK_EN_SHIFT) /* 0x00000100 */ +#define PWM_PWM3_CTRL_CLK_SEL_SHIFT (9U) +#define PWM_PWM3_CTRL_CLK_SEL_MASK (0x1U << PWM_PWM3_CTRL_CLK_SEL_SHIFT) /* 0x00000200 */ +#define PWM_PWM3_CTRL_CLK_SRC_SEL_SHIFT (10U) +#define PWM_PWM3_CTRL_CLK_SRC_SEL_MASK (0x1U << PWM_PWM3_CTRL_CLK_SRC_SEL_SHIFT) /* 0x00000400 */ +#define PWM_PWM3_CTRL_PRESCALE_SHIFT (12U) +#define PWM_PWM3_CTRL_PRESCALE_MASK (0x7U << PWM_PWM3_CTRL_PRESCALE_SHIFT) /* 0x00007000 */ +#define PWM_PWM3_CTRL_SCALE_SHIFT (16U) +#define PWM_PWM3_CTRL_SCALE_MASK (0xFFU << PWM_PWM3_CTRL_SCALE_SHIFT) /* 0x00FF0000 */ +#define PWM_PWM3_CTRL_RPT_SHIFT (24U) +#define PWM_PWM3_CTRL_RPT_MASK (0xFFU << PWM_PWM3_CTRL_RPT_SHIFT) /* 0xFF000000 */ +/* INTSTS */ +#define PWM_INTSTS_OFFSET (0x40U) +#define PWM_INTSTS_CH0_INTSTS_SHIFT (0U) +#define PWM_INTSTS_CH0_INTSTS_MASK (0x1U << PWM_INTSTS_CH0_INTSTS_SHIFT) /* 0x00000001 */ +#define PWM_INTSTS_CH1_INTSTS_SHIFT (1U) +#define PWM_INTSTS_CH1_INTSTS_MASK (0x1U << PWM_INTSTS_CH1_INTSTS_SHIFT) /* 0x00000002 */ +#define PWM_INTSTS_CH2_INTSTS_SHIFT (2U) +#define PWM_INTSTS_CH2_INTSTS_MASK (0x1U << PWM_INTSTS_CH2_INTSTS_SHIFT) /* 0x00000004 */ +#define PWM_INTSTS_CH3_INTSTS_SHIFT (3U) +#define PWM_INTSTS_CH3_INTSTS_MASK (0x1U << PWM_INTSTS_CH3_INTSTS_SHIFT) /* 0x00000008 */ +#define PWM_INTSTS_CH0_PWR_INTSTS_SHIFT (4U) +#define PWM_INTSTS_CH0_PWR_INTSTS_MASK (0x1U << PWM_INTSTS_CH0_PWR_INTSTS_SHIFT) /* 0x00000010 */ +#define PWM_INTSTS_CH1_PWR_INTSTS_SHIFT (5U) +#define PWM_INTSTS_CH1_PWR_INTSTS_MASK (0x1U << PWM_INTSTS_CH1_PWR_INTSTS_SHIFT) /* 0x00000020 */ +#define PWM_INTSTS_CH2_PWR_INTSTS_SHIFT (6U) +#define PWM_INTSTS_CH2_PWR_INTSTS_MASK (0x1U << PWM_INTSTS_CH2_PWR_INTSTS_SHIFT) /* 0x00000040 */ +#define PWM_INTSTS_CH3_PWR_INTSTS_SHIFT (7U) +#define PWM_INTSTS_CH3_PWR_INTSTS_MASK (0x1U << PWM_INTSTS_CH3_PWR_INTSTS_SHIFT) /* 0x00000080 */ +#define PWM_INTSTS_CH0_POL_SHIFT (8U) +#define PWM_INTSTS_CH0_POL_MASK (0x1U << PWM_INTSTS_CH0_POL_SHIFT) /* 0x00000100 */ +#define PWM_INTSTS_CH1_POL_SHIFT (9U) +#define PWM_INTSTS_CH1_POL_MASK (0x1U << PWM_INTSTS_CH1_POL_SHIFT) /* 0x00000200 */ +#define PWM_INTSTS_CH2_POL_SHIFT (10U) +#define PWM_INTSTS_CH2_POL_MASK (0x1U << PWM_INTSTS_CH2_POL_SHIFT) /* 0x00000400 */ +#define PWM_INTSTS_CH3_POL_SHIFT (11U) +#define PWM_INTSTS_CH3_POL_MASK (0x1U << PWM_INTSTS_CH3_POL_SHIFT) /* 0x00000800 */ +/* INT_EN */ +#define PWM_INT_EN_OFFSET (0x44U) +#define PWM_INT_EN_CH0_INT_EN_SHIFT (0U) +#define PWM_INT_EN_CH0_INT_EN_MASK (0x1U << PWM_INT_EN_CH0_INT_EN_SHIFT) /* 0x00000001 */ +#define PWM_INT_EN_CH1_INT_EN_SHIFT (1U) +#define PWM_INT_EN_CH1_INT_EN_MASK (0x1U << PWM_INT_EN_CH1_INT_EN_SHIFT) /* 0x00000002 */ +#define PWM_INT_EN_CH2_INT_EN_SHIFT (2U) +#define PWM_INT_EN_CH2_INT_EN_MASK (0x1U << PWM_INT_EN_CH2_INT_EN_SHIFT) /* 0x00000004 */ +#define PWM_INT_EN_CH3_INT_EN_SHIFT (3U) +#define PWM_INT_EN_CH3_INT_EN_MASK (0x1U << PWM_INT_EN_CH3_INT_EN_SHIFT) /* 0x00000008 */ +#define PWM_INT_EN_CH0_PWR_INT_EN_SHIFT (4U) +#define PWM_INT_EN_CH0_PWR_INT_EN_MASK (0x1U << PWM_INT_EN_CH0_PWR_INT_EN_SHIFT) /* 0x00000010 */ +#define PWM_INT_EN_CH1_PWR_INT_EN_SHIFT (5U) +#define PWM_INT_EN_CH1_PWR_INT_EN_MASK (0x1U << PWM_INT_EN_CH1_PWR_INT_EN_SHIFT) /* 0x00000020 */ +#define PWM_INT_EN_CH2_PWR_INT_EN_SHIFT (6U) +#define PWM_INT_EN_CH2_PWR_INT_EN_MASK (0x1U << PWM_INT_EN_CH2_PWR_INT_EN_SHIFT) /* 0x00000040 */ +#define PWM_INT_EN_CH3_PWR_INT_EN_SHIFT (7U) +#define PWM_INT_EN_CH3_PWR_INT_EN_MASK (0x1U << PWM_INT_EN_CH3_PWR_INT_EN_SHIFT) /* 0x00000080 */ +/* FIFO_CTRL */ +#define PWM_FIFO_CTRL_OFFSET (0x50U) +#define PWM_FIFO_CTRL_FIFO_MODE_SEL_SHIFT (0U) +#define PWM_FIFO_CTRL_FIFO_MODE_SEL_MASK (0x1U << PWM_FIFO_CTRL_FIFO_MODE_SEL_SHIFT) /* 0x00000001 */ +#define PWM_FIFO_CTRL_FULL_INT_EN_SHIFT (1U) +#define PWM_FIFO_CTRL_FULL_INT_EN_MASK (0x1U << PWM_FIFO_CTRL_FULL_INT_EN_SHIFT) /* 0x00000002 */ +#define PWM_FIFO_CTRL_OVERFLOW_INT_EN_SHIFT (2U) +#define PWM_FIFO_CTRL_OVERFLOW_INT_EN_MASK (0x1U << PWM_FIFO_CTRL_OVERFLOW_INT_EN_SHIFT) /* 0x00000004 */ +#define PWM_FIFO_CTRL_WATERMARK_INT_EN_SHIFT (3U) +#define PWM_FIFO_CTRL_WATERMARK_INT_EN_MASK (0x1U << PWM_FIFO_CTRL_WATERMARK_INT_EN_SHIFT) /* 0x00000008 */ +#define PWM_FIFO_CTRL_ALMOST_FULL_WATERMARK_SHIFT (4U) +#define PWM_FIFO_CTRL_ALMOST_FULL_WATERMARK_MASK (0x7U << PWM_FIFO_CTRL_ALMOST_FULL_WATERMARK_SHIFT) /* 0x00000070 */ +#define PWM_FIFO_CTRL_DMA_MODE_EN_SHIFT (8U) +#define PWM_FIFO_CTRL_DMA_MODE_EN_MASK (0x1U << PWM_FIFO_CTRL_DMA_MODE_EN_SHIFT) /* 0x00000100 */ +#define PWM_FIFO_CTRL_TIMEOUT_EN_SHIFT (9U) +#define PWM_FIFO_CTRL_TIMEOUT_EN_MASK (0x1U << PWM_FIFO_CTRL_TIMEOUT_EN_SHIFT) /* 0x00000200 */ +#define PWM_FIFO_CTRL_DMA_CH_SEL_EN_SHIFT (10U) +#define PWM_FIFO_CTRL_DMA_CH_SEL_EN_MASK (0x1U << PWM_FIFO_CTRL_DMA_CH_SEL_EN_SHIFT) /* 0x00000400 */ +#define PWM_FIFO_CTRL_DMA_CH_SEL_SHIFT (12U) +#define PWM_FIFO_CTRL_DMA_CH_SEL_MASK (0x3U << PWM_FIFO_CTRL_DMA_CH_SEL_SHIFT) /* 0x00003000 */ +/* FIFO_INTSTS */ +#define PWM_FIFO_INTSTS_OFFSET (0x54U) +#define PWM_FIFO_INTSTS_FIFO_FULL_INTSTS_SHIFT (0U) +#define PWM_FIFO_INTSTS_FIFO_FULL_INTSTS_MASK (0x1U << PWM_FIFO_INTSTS_FIFO_FULL_INTSTS_SHIFT) /* 0x00000001 */ +#define PWM_FIFO_INTSTS_FIFO_OVERFLOW_INTSTS_SHIFT (1U) +#define PWM_FIFO_INTSTS_FIFO_OVERFLOW_INTSTS_MASK (0x1U << PWM_FIFO_INTSTS_FIFO_OVERFLOW_INTSTS_SHIFT) /* 0x00000002 */ +#define PWM_FIFO_INTSTS_FIFO_WATERMARK_FULL_INTSTS_SHIFT (2U) +#define PWM_FIFO_INTSTS_FIFO_WATERMARK_FULL_INTSTS_MASK (0x1U << PWM_FIFO_INTSTS_FIFO_WATERMARK_FULL_INTSTS_SHIFT) /* 0x00000004 */ +#define PWM_FIFO_INTSTS_TIMIEOUT_INTSTS_SHIFT (3U) +#define PWM_FIFO_INTSTS_TIMIEOUT_INTSTS_MASK (0x1U << PWM_FIFO_INTSTS_TIMIEOUT_INTSTS_SHIFT) /* 0x00000008 */ +#define PWM_FIFO_INTSTS_FIFO_EMPTY_STATUS_SHIFT (4U) +#define PWM_FIFO_INTSTS_FIFO_EMPTY_STATUS_MASK (0x1U << PWM_FIFO_INTSTS_FIFO_EMPTY_STATUS_SHIFT) /* 0x00000010 */ +/* FIFO_TOUTTHR */ +#define PWM_FIFO_TOUTTHR_OFFSET (0x58U) +#define PWM_FIFO_TOUTTHR_TIMEOUT_THRESHOLD_SHIFT (0U) +#define PWM_FIFO_TOUTTHR_TIMEOUT_THRESHOLD_MASK (0xFFFFFU << PWM_FIFO_TOUTTHR_TIMEOUT_THRESHOLD_SHIFT) /* 0x000FFFFF */ +/* VERSION_ID */ +#define PWM_VERSION_ID_OFFSET (0x5CU) +#define PWM_VERSION_ID_SVN_VERSION_SHIFT (0U) +#define PWM_VERSION_ID_SVN_VERSION_MASK (0xFFFFU << PWM_VERSION_ID_SVN_VERSION_SHIFT) /* 0x0000FFFF */ +#define PWM_VERSION_ID_MINOR_VERSION_SHIFT (16U) +#define PWM_VERSION_ID_MINOR_VERSION_MASK (0xFFU << PWM_VERSION_ID_MINOR_VERSION_SHIFT) /* 0x00FF0000 */ +#define PWM_VERSION_ID_MAIN_VERSION_SHIFT (24U) +#define PWM_VERSION_ID_MAIN_VERSION_MASK (0xFFU << PWM_VERSION_ID_MAIN_VERSION_SHIFT) /* 0xFF000000 */ +/* FIFO */ +#define PWM_FIFO_OFFSET (0x60U) +#define PWM_FIFO (0x0U) +#define PWM_FIFO_CYCLE_CNT_SHIFT (0U) +#define PWM_FIFO_CYCLE_CNT_MASK (0x7FFFFFFFU << PWM_FIFO_CYCLE_CNT_SHIFT) /* 0x7FFFFFFF */ +#define PWM_FIFO_POL_SHIFT (31U) +#define PWM_FIFO_POL_MASK (0x1U << PWM_FIFO_POL_SHIFT) /* 0x80000000 */ +/* PWRMATCH_CTRL */ +#define PWM_PWRMATCH_CTRL_OFFSET (0x80U) +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_ENABLE_SHIFT (3U) +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_ENABLE_MASK (0x1U << PWM_PWRMATCH_CTRL_CH3_PWRKEY_ENABLE_SHIFT) /* 0x00000008 */ +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_POLARITY_SHIFT (7U) +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_POLARITY_MASK (0x1U << PWM_PWRMATCH_CTRL_CH3_PWRKEY_POLARITY_SHIFT) /* 0x00000080 */ +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_CAPTURE_CTRL_SHIFT (11U) +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_CAPTURE_CTRL_MASK (0x1U << PWM_PWRMATCH_CTRL_CH3_PWRKEY_CAPTURE_CTRL_SHIFT) /* 0x00000800 */ +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_INT_CTRL_SHIFT (15U) +#define PWM_PWRMATCH_CTRL_CH3_PWRKEY_INT_CTRL_MASK (0x1U << PWM_PWRMATCH_CTRL_CH3_PWRKEY_INT_CTRL_SHIFT) /* 0x00008000 */ +/* PWRMATCH_LPRE */ +#define PWM_PWRMATCH_LPRE_OFFSET (0x84U) +#define PWM_PWRMATCH_LPRE_CNT_MIN_SHIFT (0U) +#define PWM_PWRMATCH_LPRE_CNT_MIN_MASK (0xFFFFU << PWM_PWRMATCH_LPRE_CNT_MIN_SHIFT) /* 0x0000FFFF */ +#define PWM_PWRMATCH_LPRE_CNT_MAX_SHIFT (16U) +#define PWM_PWRMATCH_LPRE_CNT_MAX_MASK (0xFFFFU << PWM_PWRMATCH_LPRE_CNT_MAX_SHIFT) /* 0xFFFF0000 */ +/* PWRMATCH_HPRE */ +#define PWM_PWRMATCH_HPRE_OFFSET (0x88U) +#define PWM_PWRMATCH_HPRE_CNT_MIN_SHIFT (0U) +#define PWM_PWRMATCH_HPRE_CNT_MIN_MASK (0xFFFFU << PWM_PWRMATCH_HPRE_CNT_MIN_SHIFT) /* 0x0000FFFF */ +#define PWM_PWRMATCH_HPRE_CNT_MAX_SHIFT (16U) +#define PWM_PWRMATCH_HPRE_CNT_MAX_MASK (0xFFFFU << PWM_PWRMATCH_HPRE_CNT_MAX_SHIFT) /* 0xFFFF0000 */ +/* PWRMATCH_LD */ +#define PWM_PWRMATCH_LD_OFFSET (0x8CU) +#define PWM_PWRMATCH_LD_CNT_MIN_SHIFT (0U) +#define PWM_PWRMATCH_LD_CNT_MIN_MASK (0xFFFFU << PWM_PWRMATCH_LD_CNT_MIN_SHIFT) /* 0x0000FFFF */ +#define PWM_PWRMATCH_LD_CNT_MAX_SHIFT (16U) +#define PWM_PWRMATCH_LD_CNT_MAX_MASK (0xFFFFU << PWM_PWRMATCH_LD_CNT_MAX_SHIFT) /* 0xFFFF0000 */ +/* PWRMATCH_HD_ZERO */ +#define PWM_PWRMATCH_HD_ZERO_OFFSET (0x90U) +#define PWM_PWRMATCH_HD_ZERO_CNT_MIN_SHIFT (0U) +#define PWM_PWRMATCH_HD_ZERO_CNT_MIN_MASK (0xFFFFU << PWM_PWRMATCH_HD_ZERO_CNT_MIN_SHIFT) /* 0x0000FFFF */ +#define PWM_PWRMATCH_HD_ZERO_CNT_MAX_SHIFT (16U) +#define PWM_PWRMATCH_HD_ZERO_CNT_MAX_MASK (0xFFFFU << PWM_PWRMATCH_HD_ZERO_CNT_MAX_SHIFT) /* 0xFFFF0000 */ +/* PWRMATCH_HD_ONE */ +#define PWM_PWRMATCH_HD_ONE_OFFSET (0x94U) +#define PWM_PWRMATCH_HD_ONE_CNT_MIN_SHIFT (0U) +#define PWM_PWRMATCH_HD_ONE_CNT_MIN_MASK (0xFFFFU << PWM_PWRMATCH_HD_ONE_CNT_MIN_SHIFT) /* 0x0000FFFF */ +#define PWM_PWRMATCH_HD_ONE_CNT_MAX_SHIFT (16U) +#define PWM_PWRMATCH_HD_ONE_CNT_MAX_MASK (0xFFFFU << PWM_PWRMATCH_HD_ONE_CNT_MAX_SHIFT) /* 0xFFFF0000 */ +/* PWRMATCH_VALUE0 */ +#define PWM_PWRMATCH_VALUE0_OFFSET (0x98U) +#define PWM_PWRMATCH_VALUE0_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE0_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE0_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE1 */ +#define PWM_PWRMATCH_VALUE1_OFFSET (0x9CU) +#define PWM_PWRMATCH_VALUE1_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE1_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE1_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE2 */ +#define PWM_PWRMATCH_VALUE2_OFFSET (0xA0U) +#define PWM_PWRMATCH_VALUE2_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE2_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE2_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE3 */ +#define PWM_PWRMATCH_VALUE3_OFFSET (0xA4U) +#define PWM_PWRMATCH_VALUE3_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE3_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE3_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE4 */ +#define PWM_PWRMATCH_VALUE4_OFFSET (0xA8U) +#define PWM_PWRMATCH_VALUE4_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE4_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE4_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE5 */ +#define PWM_PWRMATCH_VALUE5_OFFSET (0xACU) +#define PWM_PWRMATCH_VALUE5_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE5_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE5_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE6 */ +#define PWM_PWRMATCH_VALUE6_OFFSET (0xB0U) +#define PWM_PWRMATCH_VALUE6_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE6_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE6_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE7 */ +#define PWM_PWRMATCH_VALUE7_OFFSET (0xB4U) +#define PWM_PWRMATCH_VALUE7_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE7_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE7_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE8 */ +#define PWM_PWRMATCH_VALUE8_OFFSET (0xB8U) +#define PWM_PWRMATCH_VALUE8_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE8_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE8_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWRMATCH_VALUE9 */ +#define PWM_PWRMATCH_VALUE9_OFFSET (0xBCU) +#define PWM_PWRMATCH_VALUE9_PWRKEY_MATCH_VALUE_SHIFT (0U) +#define PWM_PWRMATCH_VALUE9_PWRKEY_MATCH_VALUE_MASK (0xFFFFFFFFU << PWM_PWRMATCH_VALUE9_PWRKEY_MATCH_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* PWM3_PWRCAPTURE_VALUE */ +#define PWM_PWM3_PWRCAPTURE_VALUE_OFFSET (0xCCU) +#define PWM_PWM3_PWRCAPTURE_VALUE (0x0U) +#define PWM_PWM3_PWRCAPTURE_VALUE_PWRKEY_CAPTURE_VALUE_SHIFT (0U) +#define PWM_PWM3_PWRCAPTURE_VALUE_PWRKEY_CAPTURE_VALUE_MASK (0xFFFFFFFFU << PWM_PWM3_PWRCAPTURE_VALUE_PWRKEY_CAPTURE_VALUE_SHIFT) /* 0xFFFFFFFF */ +/* FILTER_CTRL */ +#define PWM_FILTER_CTRL_OFFSET (0xD0U) +#define PWM_FILTER_CTRL_CH0_INPUT_FILTER_ENABLE_SHIFT (0U) +#define PWM_FILTER_CTRL_CH0_INPUT_FILTER_ENABLE_MASK (0x1U << PWM_FILTER_CTRL_CH0_INPUT_FILTER_ENABLE_SHIFT) /* 0x00000001 */ +#define PWM_FILTER_CTRL_CH1_INPUT_FILTER_ENABLE_SHIFT (1U) +#define PWM_FILTER_CTRL_CH1_INPUT_FILTER_ENABLE_MASK (0x1U << PWM_FILTER_CTRL_CH1_INPUT_FILTER_ENABLE_SHIFT) /* 0x00000002 */ +#define PWM_FILTER_CTRL_CH2_INPUT_FILTER_ENABLE_SHIFT (2U) +#define PWM_FILTER_CTRL_CH2_INPUT_FILTER_ENABLE_MASK (0x1U << PWM_FILTER_CTRL_CH2_INPUT_FILTER_ENABLE_SHIFT) /* 0x00000004 */ +#define PWM_FILTER_CTRL_CH3_INPUT_FILTER_ENABLE_SHIFT (3U) +#define PWM_FILTER_CTRL_CH3_INPUT_FILTER_ENABLE_MASK (0x1U << PWM_FILTER_CTRL_CH3_INPUT_FILTER_ENABLE_SHIFT) /* 0x00000008 */ +#define PWM_FILTER_CTRL_FILTER_NUMBER_SHIFT (4U) +#define PWM_FILTER_CTRL_FILTER_NUMBER_MASK (0x1FFU << PWM_FILTER_CTRL_FILTER_NUMBER_SHIFT) /* 0x00001FF0 */ +#define PWM_FILTER_CTRL_CH0_AND_CH3_SWITCH_EN_SHIFT (16U) +#define PWM_FILTER_CTRL_CH0_AND_CH3_SWITCH_EN_MASK (0x1U << PWM_FILTER_CTRL_CH0_AND_CH3_SWITCH_EN_SHIFT) /* 0x00010000 */ +#define PWM_FILTER_CTRL_CH1_AND_CH3_SWITCH_EN_SHIFT (17U) +#define PWM_FILTER_CTRL_CH1_AND_CH3_SWITCH_EN_MASK (0x1U << PWM_FILTER_CTRL_CH1_AND_CH3_SWITCH_EN_SHIFT) /* 0x00020000 */ +#define PWM_FILTER_CTRL_CH2_AND_CH3_SWITCH_EN_SHIFT (18U) +#define PWM_FILTER_CTRL_CH2_AND_CH3_SWITCH_EN_MASK (0x1U << PWM_FILTER_CTRL_CH2_AND_CH3_SWITCH_EN_SHIFT) /* 0x00040000 */ + +#define RK3588_PWM0_BASE 0xfd8b0000 +#define RK3588_PWM1_BASE 0xfebd0000 +#define RK3588_PWM2_BASE 0xfebe0000 +#define RK3588_PWM3_BASE 0xfebf0000 +#define RK3588_PWM_SIZE 0x10000 + +enum PWM_CONTROLLER_ID { + PWM_CONTROLLER0, + PWM_CONTROLLER1, + PWM_CONTROLLER2, + PWM_CONTROLLER3 +}; + +enum PWM_CHANNEL_ID { + PWM_CHANNEL0, + PWM_CHANNEL1, + PWM_CHANNEL2, + PWM_CHANNEL3 +}; + +typedef struct { + UINT8 ControllerID; + UINT8 ChannelID; + UINT32 PeriodNs; + UINT32 DutyNs; + BOOLEAN Polarity; +} PWM_DATA; + +RETURN_STATUS +EFIAPI +RkPwmSetConfig ( + IN PWM_DATA *Data + ); + +RETURN_STATUS +EFIAPI +RkPwmEnable ( + IN PWM_DATA *Data + ); + +RETURN_STATUS +EFIAPI +RkPwmDisable ( + IN PWM_DATA *Data + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RK806.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RK806.h new file mode 100644 index 0000000..cf49bd4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RK806.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#ifndef __RK_806_H +#define __RK_806_H + +#include +#include "Soc.h" + +/* Not used or exisit register and configure */ +#define NA -1 +#define BIT(n) (1 << (n)) +/* rk806 buck*/ +#define RK806_BUCK_ON_VSEL(n) (0x1a + n - 1) +#define RK806_BUCK_SLP_VSEL(n) (0x24 + n - 1) +#define RK806_BUCK_CONFIG(n) (0x10 + n - 1) +#define RK806_BUCK_VSEL_MASK 0xff + +/* RK806 LDO */ +#define RK806_NLDO_ON_VSEL(n) (0x43 + n - 1) +#define RK806_NLDO_SLP_VSEL(n) (0x48 + n - 1) +#define RK806_NLDO_VSEL_MASK 0xff +#define RK806_PLDO_ON_VSEL(n) (0x4e + n - 1) +#define RK806_PLDO_SLP_VSEL(n) (0x54 + n - 1) +#define RK806_PLDO_VSEL_MASK 0xff + +/* RK806 ENABLE */ +#define RK806_POWER_EN(n) (0x00 + n) +#define RK806_NLDO_EN(n) (0x03 + n) +#define RK806_PLDO_EN(n) (0x04 + n) +#define RK806_RAMP_RATE_MASK1 0xc0 +#define RK806_RAMP_RATE_REG1(n) (0x10 + n) +#define RK806_RAMP_RATE_REG1_8 0xeb +#define RK806_RAMP_RATE_REG9_10 0xea + +#define RK806_RAMP_RATE_4LSB_PER_1CLK 0x00/* LDO 100mV/uS buck 50mV/us */ +#define RK806_RAMP_RATE_2LSB_PER_1CLK 0x01/* LDO 50mV/uS buck 25mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_1CLK 0x02/* LDO 25mV/uS buck 12.5mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_2CLK 0x03/* LDO 12.5mV/uS buck 6.25mV/us */ + +#define RK806_RAMP_RATE_1LSB_PER_4CLK 0x04/* LDO 6.28/2mV/uS buck 3.125mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_8CLK 0x05/* LDO 3.12mV/uS buck 1.56mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_13CLK 0x06/* LDO 1.9mV/uS buck 961mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_32CLK 0x07/* LDO 0.78mV/uS buck 0.39mV/us */ + +#define RK806_PLDO0_2_MSK(pldo) (BIT(pldo + 5)) +#define RK806_PLDO0_2_SET(pldo) (BIT(pldo + 1) | RK806_PLDO0_2_MSK(pldo)) +#define RK806_PLDO0_2_CLR(pldo) RK806_PLDO0_2_MSK(pldo) + +#define RK806_CHIP_NAME 0x5A +#define RK806_CHIP_VER 0x5B + +#define RK806_CMD_READ 0 +#define RK806_CMD_WRITE BIT(7) +#define RK806_CMD_CRC_EN BIT(6) +#define RK806_CMD_CRC_DIS 0 +#define RK806_CMD_LEN_MSK 0x0f +#define RK806_REG_H 0x00 + +#define RK806_SYS_CFG1 0x5f +#define RK806_SYS_CFG3 0x72 +#define RK806_PWRON_KEY 0x76 +#define RK806_INT_STS0 0x77 +#define RK806_INT_MSK0 0x78 +#define RK806_INT_STS1 0x79 +#define RK806_INT_MSK1 0x7A +#define RK806_GPIO_INT_CONFIG 0x7B +#define RK806_IRQ_PWRON_FALL_MSK BIT(0) +#define RK806_IRQ_PWRON_RISE_MSK BIT(1) +#define RK806_DEV_OFF BIT(0) +#define RK806_RST_MODE1 0x01 +#define RK806_RST_MODE2 0x02 +#define VERSION_AB 0x01 + +struct regulator_init_data { + const char *supply_regulator; /* or NULL for system supply */ + INT32 reg_id; + INT32 init_voltage_mv; +}; + +struct rk8xx_reg_info { + UINT32 min_uv; + UINT32 step_uv; + UINT8 vsel_reg; + UINT8 vsel_sleep_reg; + UINT8 config_reg; + UINT8 vsel_mask; + UINT8 min_sel; + /* only for buck now */ + UINT8 max_sel; + UINT8 range_num; +}; + +#define RK8XX_DESC_COM(_name, _reg_info, _ops) \ +{ \ + .reg_info = (_reg_info), \ + .name = (_reg_id), \ + .ops = _ops, \ +} + +#define RK8XX_VOLTAGE_INIT(_id, _voltage) \ +{ \ + .reg_id = (_id),\ + .init_voltage_mv = (_voltage),\ +} + +/****************************************** +8 -12: MASTER, SLAVE +4 -7: BUCK, NLDO, PLDO +0 -3: num +******************************************/ +#define MASTER (0x0 << 8) +#define SLAVER (0x1 << 8) +#define BUCK (0x0 << 4) +#define NLDO (0x1 << 4) +#define PLDO (0x2 << 4) + +enum master_num { + MASTER_BUCK1 = (MASTER | BUCK | 0), + MASTER_BUCK2 = (MASTER | BUCK | 1), + MASTER_BUCK3 = (MASTER | BUCK | 2), + MASTER_BUCK4 = (MASTER | BUCK | 3), + MASTER_BUCK5 = (MASTER | BUCK | 4), + MASTER_BUCK6 = (MASTER | BUCK | 5), + MASTER_BUCK7 = (MASTER | BUCK | 6), + MASTER_BUCK8 = (MASTER | BUCK | 7), + MASTER_BUCK9 = (MASTER | BUCK | 8), + MASTER_BUCK10 = (MASTER | BUCK | 9), + + MASTER_NLDO1 = (MASTER | NLDO | 0), + MASTER_NLDO2 = (MASTER | NLDO | 1), + MASTER_NLDO3 = (MASTER | NLDO | 2), + MASTER_NLDO4 = (MASTER | NLDO | 3), + MASTER_NLDO5 = (MASTER | NLDO | 4), + + MASTER_PLDO1 = (MASTER | PLDO | 0), + MASTER_PLDO2 = (MASTER | PLDO | 1), + MASTER_PLDO3 = (MASTER | PLDO | 2), + MASTER_PLDO4 = (MASTER | PLDO | 3), + MASTER_PLDO5 = (MASTER | PLDO | 4), + MASTER_PLDO6 = (MASTER | PLDO | 5), +}; + +enum slaver_num { + SLAVER_BUCK1 = (SLAVER | BUCK | 0), + SLAVER_BUCK2 = (SLAVER | BUCK | 1), + SLAVER_BUCK3 = (SLAVER | BUCK | 2), + SLAVER_BUCK4 = (SLAVER | BUCK | 3), + SLAVER_BUCK5 = (SLAVER | BUCK | 4), + SLAVER_BUCK6 = (SLAVER | BUCK | 5), + SLAVER_BUCK7 = (SLAVER | BUCK | 6), + SLAVER_BUCK8 = (SLAVER | BUCK | 7), + SLAVER_BUCK9 = (SLAVER | BUCK | 8), + SLAVER_BUCK10 = (SLAVER | BUCK | 9), + + SLAVER_NLDO1 = (SLAVER | NLDO | 0), + SLAVER_NLDO2 = (SLAVER | NLDO | 1), + SLAVER_NLDO3 = (SLAVER | NLDO | 2), + SLAVER_NLDO4 = (SLAVER | NLDO | 3), + SLAVER_NLDO5 = (SLAVER | NLDO | 4), + + SLAVER_PLDO1 = (SLAVER | PLDO | 0), + SLAVER_PLDO2 = (SLAVER | PLDO | 1), + SLAVER_PLDO3 = (SLAVER | PLDO | 2), + SLAVER_PLDO4 = (SLAVER | PLDO | 3), + SLAVER_PLDO5 = (SLAVER | PLDO | 4), + SLAVER_PLDO6 = (SLAVER | PLDO | 5), +}; + +extern RETURN_STATUS RK806Init(void); +extern void RK806RegulatorInit(struct regulator_init_data init_data); + +#endif \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkAtagsLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkAtagsLib.h new file mode 100644 index 0000000..a333219 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkAtagsLib.h @@ -0,0 +1,208 @@ +/** @file + * + * Rockchip ATAGS library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef RKATAGSLIB_H__ +#define RKATAGSLIB_H__ + +/* + These Atags get populated by earlier boot stages (U-Boot, ATF). + Some may be unavailable depending on the platform. + + It's also possible to write new/existing tags, but we won't support that + since there are more appropriate ways to pass configuration data around + from the UEFI. +*/ + +typedef enum { + RkAtagSerialMuxM0 = 0, + RkAtagSerialMuxM1 = 1, + RkAtagSerialMuxM2 = 2 +} RKATAG_SERIAL_MUX_MODE; + +typedef enum { + RkAtagBootDevTypeUnknown = 0, + RkAtagBootDevTypeNand = BIT0, + RkAtagBootDevTypeEmmc = BIT1, + RkAtagBootDevTypeSd0 = BIT2, + RkAtagBootDevTypeSd1 = BIT3, + RkAtagBootDevTypeSpiNor = BIT4, + RkAtagBootDevTypeSpiNand = BIT5, + RkAtagBootDevTypeRam = BIT6, + RkAtagBootDevTypeMtdBlkNand = BIT7, + RkAtagBootDevTypeMtdBlkSpiNand = BIT8, + RkAtagBootDevTypeMtdBlkSpiNor = BIT9, + RkAtagBootDevTypeSata = BIT10, + RkAtagBootDevTypePcie = BIT11 +} RKATAG_BOOTDEV_TYPE; + +typedef enum { + RkAtagBootDevSdCardUnknown = 0, + RkAtagBootDevSdCardUpdate = 1 +} RKATAG_BOOTDEV_SDCARD_UPDATE; + +typedef enum { + RkAtagDdrMemExtTop = 1 +} RKATAG_DDR_MEM_FLAG; + +typedef enum { + RkAtagPubKeyFuseProgrammed = 0x4B415352 +} RKATAG_PUB_KEY_FLAG; + +typedef enum { + RkAtagSocInfoFlagTdbt = BIT0 +} RKATAG_SOC_INFO_FLAG; + +#define BOOT1_PARAM2_BOOT_CPU_HWID_MASK 0x0000001F + +#pragma pack(1) + +typedef struct { + UINT32 Version; + UINT32 Enable; + UINT64 Address; + UINT32 BaudRate; + RKATAG_SERIAL_MUX_MODE MuxMode; + UINT32 Id; + UINT32 Reserved[2]; +} RKATAG_SERIAL; + +typedef struct { + UINT32 Version; + RKATAG_BOOTDEV_TYPE DevType; + UINT32 DevNum; + UINT32 Mode; + RKATAG_BOOTDEV_SDCARD_UPDATE SdUpdate; + UINT32 Reserved[6]; +} RKATAG_BOOTDEV; + +typedef struct { + UINT32 Count; + UINT32 Version; + UINT64 Bank[20]; + RKATAG_DDR_MEM_FLAG Flags; + UINT32 Data[2]; +} RKATAG_DDR_MEM; + +typedef struct { + UINT32 Version; + struct { + CHAR8 Name[8]; + UINT64 PhyAddr; + UINT32 Size; + UINT32 Flags; + } TeeMem; + + struct { + CHAR8 Name[8]; + UINT64 PhyAddr; + UINT32 Size; + UINT32 Flags; + } DrmMem; + + UINT32 Reserved[15]; +} RKATAG_TOS_MEM; + +typedef struct { + UINT32 Version; + UINT32 Count; + UINT32 Reserved[4]; + + struct { + CHAR8 Name[16]; + UINT64 Start; + UINT64 Size; + } Partition[6]; + + UINT32 Reserved1[3]; +} RKATAG_RAM_PARTITION; + +typedef struct { + UINT32 Version; + UINT64 PhyAddr; + UINT32 Size; + UINT32 Flags; + UINT32 Reserved[2]; +} RKATAG_ATF_MEM; + +typedef struct { + UINT32 Version; + UINT32 Len; + + struct { + UINT32 RsaN[64]; + UINT32 RsaE[64]; + UINT32 RsaC[64]; + } Data; + + UINT32 Flags; + UINT32 Reserved[5]; +} RKATAG_PUB_KEY; + +typedef struct { + UINT32 Version; + UINT32 HexName; + RKATAG_SOC_INFO_FLAG Flags; + UINT32 Reserved[6]; +} RKATAG_SOC_INFO; + +typedef struct { + UINT32 Version; + UINT32 Param[8]; + UINT32 Reserved[4]; +} RKATAG_BOOT1_PARAM; + +#pragma pack() + +RKATAG_SERIAL * +RkAtagsGetSerial ( + VOID + ); + +RKATAG_BOOTDEV * +RkAtagsGetBootDev ( + VOID + ); + +RKATAG_DDR_MEM * +RkAtagsGetDdrMem ( + VOID + ); + +RKATAG_TOS_MEM * +RkAtagsGetTosMem ( + VOID + ); + +RKATAG_RAM_PARTITION * +RkAtagsGetRamPartition ( + VOID + ); + +RKATAG_ATF_MEM * +RkAtagsGetAtfMem ( + VOID + ); + +RKATAG_PUB_KEY * +RkAtagsGetPubKey ( + VOID + ); + +RKATAG_SOC_INFO * +RkAtagsGetSocInfo ( + VOID + ); + +RKATAG_BOOT1_PARAM * +RkAtagsGetBoot1Param ( + VOID + ); + +#endif /* RKATAGSLIB_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkSdmmcPlatformLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkSdmmcPlatformLib.h new file mode 100644 index 0000000..606e522 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RkSdmmcPlatformLib.h @@ -0,0 +1,33 @@ +/** @file + * + * RkSdmmcDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +typedef enum { + RkSdmmcCardPresenceUnsupported = 0, + RkSdmmcCardPresent, + RkSdmmcCardNotPresent +} RKSDMMC_CARD_PRESENCE_STATE; + +EFI_STATUS +EFIAPI +RkSdmmcSetClockRate ( + IN UINTN Frequency + ); + +VOID +EFIAPI +RkSdmmcSetIoMux ( + VOID + ); + +RKSDMMC_CARD_PRESENCE_STATE +EFIAPI +RkSdmmcGetCardPresenceState ( + VOID + ); diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipDisplayLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipDisplayLib.h new file mode 100644 index 0000000..9f9c875 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipDisplayLib.h @@ -0,0 +1,285 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __ROCKCHIP_DISPLAY_H__ +#define __ROCKCHIP_DISPLAY_H__ + +#include +#include +#include + +#define LIST_FOR_EACH_ENTRY(Pos, Head, Member) \ + for (Pos = BASE_CR((Head)->ForwardLink, typeof(*Pos), Member); \ + &Pos->Member != (Head); \ + Pos = BASE_CR(Pos->Member.ForwardLink, typeof(*Pos), Member)) + +#define __ROUND_MASK(x, y) ((__typeof__(x))((y)-1)) +#define ROUNDUP(x, y) ((((x)-1) | __ROUND_MASK(x, y))+1) +#define ROUNDDOWN(x, y) ((x) & ~__ROUND_MASK(x, y)) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +#define INLINE static inline + +#define EDID_SIZE 128 + +typedef enum { + ROCKCHIP_DISPLAY_FULLSCREEN, + ROCKCHIP_DISPLAY_CENTER, +} LOGO_DISPLAY_MODE; + +typedef enum { + ROCKCHIP_FMT_ARGB8888 = 0, + ROCKCHIP_FMT_RGB888, + ROCKCHIP_FMT_RGB565, + ROCKCHIP_FMT_YUV420SP = 4, + ROCKCHIP_FMT_YUV422SP, + ROCKCHIP_FMT_YUV444SP, +} DATA_FORMAT; + +#define ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE BIT(0) +#define ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE BIT(1) +#define ROCKCHIP_OUTPUT_DATA_SWAP BIT(2) +#define ROCKCHIP_OUTPUT_MIPI_DS_MODE BIT(3) + +#define ROCKCHIP_DSC_PPS_SIZE_BYTE 88 + +/* + * display output interface supported by rockchip lcdc + */ +#define ROCKCHIP_OUT_MODE_P888 0 +#define ROCKCHIP_OUT_MODE_BT1120 0 +#define ROCKCHIP_OUT_MODE_P666 1 +#define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_BT656 5 +#define ROCKCHIP_OUT_MODE_S888 8 +#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 +#define ROCKCHIP_OUT_MODE_YUV420 14 +/* for use special outface */ +#define ROCKCHIP_OUT_MODE_AAAA 15 + +#define VOP_OUTPUT_IF_RGB BIT(0) +#define VOP_OUTPUT_IF_BT1120 BIT(1) +#define VOP_OUTPUT_IF_BT656 BIT(2) +#define VOP_OUTPUT_IF_LVDS0 BIT(3) +#define VOP_OUTPUT_IF_LVDS1 BIT(4) +#define VOP_OUTPUT_IF_MIPI0 BIT(5) +#define VOP_OUTPUT_IF_MIPI1 BIT(6) +#define VOP_OUTPUT_IF_eDP0 BIT(7) +#define VOP_OUTPUT_IF_eDP1 BIT(8) +#define VOP_OUTPUT_IF_DP0 BIT(9) +#define VOP_OUTPUT_IF_DP1 BIT(10) +#define VOP_OUTPUT_IF_HDMI0 BIT(11) +#define VOP_OUTPUT_IF_HDMI1 BIT(12) + +typedef struct { + UINT32 Mode; + UINT32 Offset; + UINT32 Width; + UINT32 Height; + UINT32 Bpp; + CHAR8 *Memory; + BOOLEAN YMirror; +} LOGO_INFO; + +typedef struct { + UINT32 Width; + UINT32 Height; +} VOP_RECT; + +struct rockchip_dsc_sink_cap { + /** + * @slice_width: the number of pixel columns that comprise the slice width + * @slice_height: the number of pixel rows that comprise the slice height + * @block_pred: Does block prediction + * @native_420: Does sink support DSC with 4:2:0 compression + * @bpc_supported: compressed bpc supported by sink : 10, 12 or 16 bpc + * @version_major: DSC major version + * @version_minor: DSC minor version + * @target_bits_per_pixel_x16: bits num after compress and multiply 16 + */ + UINT16 slice_width; + UINT16 slice_height; + BOOLEAN block_pred; + BOOLEAN native_420; + UINT8 bpc_supported; + UINT8 version_major; + UINT8 version_minor; + UINT16 target_bits_per_pixel_x16; +}; + +typedef struct { + UINT32 LeftMargin; + UINT32 RightMargin; + UINT32 TopMargin; + UINT32 BottomMargin; +} OVER_SCAN; + +typedef struct { + /* Proposed mode values */ + UINT32 Clock; /* in kHz */ + UINT32 HDisplay; + UINT32 HSyncStart; + UINT32 HSyncEnd; + UINT32 HTotal; + UINT32 VDisplay; + UINT32 VSyncStart; + UINT32 VSyncEnd; + UINT32 VTotal; + UINT32 VRefresh; + UINT32 VScan; + UINT32 Flags; + UINT32 PictureAspectRatio; + UINT32 HSkew; + UINT32 Type; + /* Actual mode we give to hw */ + UINT32 CrtcClock; /* in KHz */ + UINT32 CrtcHDisplay; + UINT32 CrtcHBlankStart; + UINT32 CrtcHBblankEnd; + UINT32 CrtcHSyncStart; + UINT32 CrtcHSyncEnd; + UINT32 CrtcHTotal; + UINT32 CrtcHSkew; + UINT32 CrtcVDisplay; + UINT32 CrtcVBlankStart; + UINT32 CrtcVBlankEnd; + UINT32 CrtcVSyncStart; + UINT32 CrtcVSyncEnd; + UINT32 CrtcVTotal; + BOOLEAN Invalid; +} DRM_DISPLAY_MODE; + +typedef struct { + UINT16 Brightness; + UINT16 Contrast; + UINT16 Saturation; + UINT16 Hue; +} BASE_BCSH_INFO; + +typedef struct { + INT8 DispHeadFlag[6]; + /* struct base2_screen_info screen_info[4]; --- todo */ + BASE_BCSH_INFO BCSHInfo; + /* struct base_overscan overscan_info; --- todo */ + /* struct base2_gamma_lut_data gamma_lut_data; --- todo */ + /* struct base2_cubic_lut_data cubic_lut_data; --- todo */ + /* struct framebuffer_info framebuffer_info; --- todo */ + UINT32 Reserved[244]; + UINT32 CRC; +} BASE2_DISP_INFO; + +typedef struct { + VOID *Connector; + OVER_SCAN OverScan; + DRM_DISPLAY_MODE DisplayMode; + BASE2_DISP_INFO *DispInfo; /* disp_info from baseparameter 2.0 */ + UINT8 EDID[EDID_SIZE * 4]; + UINT32 BusFormat; + UINT32 OutputMode; + UINT32 Type; + UINT32 OutputInterface; + UINT32 OutputFlags; + UINT32 ColorSpace; + UINT32 BPC; + + /** + * @hold_mode: enabled when it's: + * (1) mcu hold mode + * (2) mipi dsi cmd mode + * (3) edp psr mode + */ + BOOLEAN hold_mode; +} CONNECTOR_STATE; + +typedef struct { + VOID *Crtc; + VOID *Private; + UINT32 CrtcID; + UINT32 Format; + UINT32 YMirror; + UINT32 RBSwap; + UINT32 XVirtual; + UINT32 SrcX; + UINT32 SrcY; + UINT32 SrcW; + UINT32 SrcH; + UINT32 CrtcX; + UINT32 CrtcY; + UINT32 CrtcW; + UINT32 CrtcH; + UINT32 Feature; + UINT32 DMAAddress; + BOOLEAN YUVOverlay; + VOP_RECT MaxOutput; + + UINT32 DclkCoreDiv; + UINT32 DclkOutDiv; + + UINT8 dsc_id; + UINT8 dsc_enable; + UINT8 dsc_slice_num; + UINT8 dsc_pixel_num; + UINT64 dsc_txp_clk_rate; + UINT64 dsc_pxl_clk_rate; + UINT64 dsc_cds_clk_rate; + struct drm_dsc_picture_parameter_set pps; + struct rockchip_dsc_sink_cap dsc_sink_cap; +} CRTC_STATE; + +typedef struct { + LIST_ENTRY ListHead; + CRTC_STATE CrtcState; + CONNECTOR_STATE ConnectorState; + + UINT32 ModeNumber; + INT32 VpsConfigModeID; + + VOID *MemoryBase; + UINT32 MemorySize; + + BOOLEAN IsInit; + BOOLEAN IsEnable; + + BOOLEAN IsForceOutput; + UINT32 ForceOutputFormat; +} DISPLAY_STATE; + +typedef struct { + UINT32 Resolution; + UINT32 Sync; + UINT32 BackPorch; + UINT32 FrontPorch; +} SCAN_TIMINGS; + +typedef struct { + UINT32 CrtcId; + UINT32 OscFreq; + SCAN_TIMINGS Horizontal; + SCAN_TIMINGS Vertical; + UINT32 HsyncActive; + UINT32 VsyncActive; + UINT32 DenActive; + UINT32 ClkActive; + UINT32 VpsConfigModeID; +} DISPLAY_MODE; + +EFIAPI +EFI_STATUS +DisplaySetCrtcInfo ( + OUT DRM_DISPLAY_MODE *Mode, + IN UINT32 AdjustFlags + ); + +UINT32 +EFIAPI +DrmModeVRefresh ( + DRM_DISPLAY_MODE *Mode + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipPlatformLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipPlatformLib.h new file mode 100644 index 0000000..9b93e42 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/RockchipPlatformLib.h @@ -0,0 +1,155 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Inc. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __PALTFORM_LIB_H__ +#define __PALTFORM_LIB_H__ + +#include + +VOID +EFIAPI +SdmmcIoMux ( + VOID + ); + +VOID +EFIAPI +SdhciEmmcIoMux ( + VOID + ); + +VOID +EFIAPI +EnableBacklight ( + IN BOOLEAN en + ); + +VOID +EFIAPI +EnablePWM ( + IN BOOLEAN en + ); + +VOID +EFIAPI +GmacIomux ( + IN UINT32 Id + ); + +VOID +EFIAPI +GmacIoPhyReset ( + IN UINT32 Id, + IN BOOLEAN Enable + ); + +VOID +EFIAPI +Rk806SpiIomux ( + VOID + ); + +VOID +EFIAPI +Rk806Configure ( + VOID + ); + +VOID +EFIAPI +SetCPULittleVoltage ( + IN UINT32 Microvolts + ); + +VOID +EFIAPI +NorFspiIomux ( + VOID + ); + +VOID +EFIAPI +NorFspiEnableClock ( + UINT32 *CruBase + ); + +VOID +EFIAPI +I2cIomux ( + UINT32 id + ); + +VOID +EFIAPI +UsbPortPowerEnable ( + VOID + ); + +VOID +EFIAPI +Usb2PhyResume ( + VOID + ); + +VOID +EFIAPI +PcieIoInit ( + UINT32 Segment + ); + +VOID +EFIAPI +PciePowerEn ( + UINT32 Segment, + BOOLEAN Enable + ); + +VOID +EFIAPI +PciePeReset ( + UINT32 Segment, + BOOLEAN Enable + ); + +VOID +EFIAPI +PwmFanIoSetup ( + VOID + ); + +VOID +EFIAPI +PwmFanSetSpeed ( + IN UINT32 Percentage + ); + +VOID +EFIAPI +PlatformInitLeds ( + VOID + ); + +VOID +EFIAPI +PlatformSetStatusLed ( + IN BOOLEAN Enable + ); + +VOID +EFIAPI +PlatformEarlyInit ( + VOID + ); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SdramLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SdramLib.h new file mode 100644 index 0000000..7faf26c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SdramLib.h @@ -0,0 +1,17 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef SDRAMLIB_H__ +#define SDRAMLIB_H__ + +UINT64 +SdramGetMemorySize ( + VOID + ); + +#endif /* SDRAMLIB_H__ */ \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Snor.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Snor.h new file mode 100644 index 0000000..930feab --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Snor.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#ifndef _HAL_SFC_NOR_H_ +#define _HAL_SFC_NOR_H_ + +/***************************** Structure Definition **************************/ + +#define SPI_NOR_MAX_CMD_SIZE 8 +#define SNOR_SPEED_MAX 133000000 +#define SNOR_SPEED_DEFAULT 80000000 + +#define SNOR_PROTO_STR(a, b, c) (((a) << 8) | ((b) << 4) | (c)) + +#define SNOR_GET_PROTOCOL_ADDR_BITS(proto) (((proto) >> 4) & 0xf) +#define SNOR_GET_PROTOCOL_DATA_BITS(proto) ((proto) & 0xf) + +enum SPI_NOR_PROTOCOL { + SNOR_PROTO_1_1_1 = SNOR_PROTO_STR(1, 1, 1), + SNOR_PROTO_1_1_2 = SNOR_PROTO_STR(1, 1, 2), + SNOR_PROTO_1_1_4 = SNOR_PROTO_STR(1, 1, 4), + SNOR_PROTO_1_1_8 = SNOR_PROTO_STR(1, 1, 8), + SNOR_PROTO_1_2_2 = SNOR_PROTO_STR(1, 2, 2), + SNOR_PROTO_1_4_4 = SNOR_PROTO_STR(1, 4, 4), + SNOR_PROTO_1_8_8 = SNOR_PROTO_STR(1, 8, 8), + SNOR_PROTO_2_2_2 = SNOR_PROTO_STR(2, 2, 2), + SNOR_PROTO_4_4_4 = SNOR_PROTO_STR(4, 4, 4), + SNOR_PROTO_8_8_8 = SNOR_PROTO_STR(8, 8, 8), +}; + +/* Flash opcodes. */ +#define SPINOR_OP_WREN 0x06 /**< Write enable */ +#define SPINOR_OP_RDSR 0x05 /**< Read status register */ +#define SPINOR_OP_WRSR 0x01 /**< Write status register 1 byte */ +#define SPINOR_OP_RDSR1 0x35 /**< Read status register 1 */ +#define SPINOR_OP_WRSR1 0x31 /**< Write status register 1 */ +#define SPINOR_OP_RDSR2 0x15 /**< Read status register 2 */ +#define SPINOR_OP_WRSR2 0x3e /**< Write status register 2 */ +#define SPINOR_OP_READ 0x03 /**< Read data bytes (low frequency) */ +#define SPINOR_OP_READ_FAST 0x0b /**< Read data bytes (high frequency) */ +#define SPINOR_OP_READ_1_1_2 0x3b /**< Read data bytes (Dual Output SPI) */ +#define SPINOR_OP_READ_1_2_2 0xbb /**< Read data bytes (Dual I/O SPI) */ +#define SPINOR_OP_READ_1_1_4 0x6b /**< Read data bytes (Quad Output SPI) */ +#define SPINOR_OP_READ_1_4_4 0xeb /**< Read data bytes (Quad I/O SPI) */ +#define SPINOR_OP_READ_EC 0xec /**< Read data bytes (Quad I/O SPI) 4 byte address */ +#define SPINOR_OP_PP 0x02 /**< Page program (up to 256 bytes) */ +#define SPINOR_OP_PP_1_1_4 0x32 /**< Quad page program */ +#define SPINOR_OP_PP_1_4_4 0x38 /**< Quad page program */ +#define SPINOR_OP_BE_4K 0x20 /**< Erase 4KiB block */ +#define SPINOR_OP_BE_4K_PMC 0xd7 /**< Erase 4KiB block on PMC chips */ +#define SPINOR_OP_BE_32K 0x52 /**< Erase 32KiB block */ +#define SPINOR_OP_CHIP_ERASE 0xc7 /**< Erase whole flash chip */ +#define SPINOR_OP_SE 0xd8 /**< Sector erase (usually 64KiB) */ +#define SPINOR_OP_RDID 0x9f /**< Read JEDEC ID */ +#define SPINOR_OP_RDSFDP 0x5a /**< Read SFDP */ +#define SPINOR_OP_RDCR 0x15 /**< Read configuration register */ +#define SPINOR_OP_WRCR 0x11 /**< Write configuration register */ +#define SPINOR_OP_RDFSR 0x70 /**< Read flag status register */ +#define SPINOR_OP_CLFSR 0x50 /**< Clear flag status register */ +#define SPINOR_OP_RDEAR 0xc8 /**< Read Extended Address Register */ +#define SPINOR_OP_WREAR 0xc5 /**< Write Extended Address Register */ +#define SPINOR_OP_READ_UUID 0x4b /**< Read SPI Nor UUID */ +#define SPINOR_OP_READ_SFDP 0x5A /**< Read SPI Nor SFDP */ + +struct SPI_NOR { + struct HAL_FSPI_HOST *spi; + const struct FLASH_INFO *info; + UINT32 pageSize; + UINT8 addrWidth; + UINT8 eraseOpcodeSec; + UINT8 eraseOpcodeBlk; + UINT8 readOpcode; + UINT8 readDummy; + UINT8 programOpcode; + + enum SPI_NOR_PROTOCOL readProto; + enum SPI_NOR_PROTOCOL writeProto; + UINT8 cmdBuf[SPI_NOR_MAX_CMD_SIZE]; + + UINT32 size; + UINT32 sectorSize; + UINT32 eraseSize; +}; + +typedef enum { + ERASE_SECTOR = 0, + ERASE_BLOCK64K, + ERASE_CHIP +} NOR_ERASE_TYPE; + +RETURN_STATUS HAL_SNOR_Init(struct SPI_NOR *nor); +RETURN_STATUS HAL_SNOR_DeInit(struct SPI_NOR *nor); +UINT32 HAL_SNOR_GetCapacity(struct SPI_NOR *nor); +RETURN_STATUS HAL_SNOR_ReadID(struct SPI_NOR *nor, UINT8 *data); +RETURN_STATUS HAL_SNOR_ReadData(struct SPI_NOR *nor, UINT32 from, void *buf, UINT32 len); +RETURN_STATUS HAL_SNOR_ProgData(struct SPI_NOR *nor, UINT32 to, void *buf, UINT32 len); +RETURN_STATUS HAL_SNOR_Read(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData); +RETURN_STATUS HAL_SNOR_Write(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData); +RETURN_STATUS HAL_SNOR_OverWrite(struct SPI_NOR *nor, UINT32 sec, UINT32 nSec, void *pData); +RETURN_STATUS HAL_SNOR_Erase(struct SPI_NOR *nor, UINT32 addr, NOR_ERASE_TYPE EraseType); +BOOLEAN HAL_SNOR_IsFlashSupported(UINT8 *flashId); +RETURN_STATUS HAL_SNOR_ReadUUID(struct SPI_NOR *nor, void *buf); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiLib.h new file mode 100644 index 0000000..216d4db --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiLib.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#ifndef __RK_SPI_H +#define __RK_SPI_H + +#define HAL_SPI_MASTER_MAX_SCLK_OUT 50000000 /**< Max io clock in master mode */ +#define HAL_SPI_SLAVE_MAX_SCLK_OUT 20000000 /**< Max io in clock in slave mode */ + +#define CR0_DATA_FRAME_SIZE_4BIT (0x00 << SPI_CTRLR0_DFS_SHIFT) +#define CR0_DATA_FRAME_SIZE_8BIT (0x01 << SPI_CTRLR0_DFS_SHIFT) +#define CR0_DATA_FRAME_SIZE_16BIT (0x02 << SPI_CTRLR0_DFS_SHIFT) + +/* serial clock toggles in middle of first data bit */ +#define CR0_PHASE_1EDGE (0x00 << SPI_CTRLR0_SCPH_SHIFT) +/* serial clock toggles at start of first data bit */ +#define CR0_PHASE_2EDGE (0x01 << SPI_CTRLR0_SCPH_SHIFT) + +#define CR0_POLARITY_LOW (0x00 << SPI_CTRLR0_SCPOL_SHIFT) +#define CR0_POLARITY_HIGH (0x01 << SPI_CTRLR0_SCPOL_SHIFT) + +/* + * The period between ss_n active and + * sclk_out active is half sclk_out cycles + */ +#define CR0_SSD_HALF (0x00 << SPI_CTRLR0_SSD_SHIFT) +/* + * The period between ss_n active and + * sclk_out active is one sclk_out cycle + */ +#define CR0_SSD_ONE (0x01 << SPI_CTRLR0_SSD_SHIFT) + +#define CR0_EM_LITTLE (0x0 << SPI_CTRLR0_EM_SHIFT) +#define CR0_EM_BIG (0x1 << SPI_CTRLR0_EM_SHIFT) + +#define CR0_FIRSTBIT_MSB (0x0 << SPI_CTRLR0_FBM_SHIFT) +#define CR0_FIRSTBIT_LSB (0x1 << SPI_CTRLR0_FBM_SHIFT) + +#define CR0_BHT_16BIT (0x0 << SPI_CTRLR0_BHT_SHIFT) +#define CR0_BHT_8BIT (0x1 << SPI_CTRLR0_BHT_SHIFT) + +#define CR0_XFM_TR (0x00 << SPI_CTRLR0_XFM_SHIFT) +#define CR0_XFM_TO (0x01 << SPI_CTRLR0_XFM_SHIFT) +#define CR0_XFM_RO (0x02 << SPI_CTRLR0_XFM_SHIFT) + +#define CR0_OPM_MASTER (0x00 << SPI_CTRLR0_OPM_SHIFT) +#define CR0_OPM_SLAVE (0x01 << SPI_CTRLR0_OPM_SHIFT) + +#define CR0_CSM(nCycles) (((nCycles) << SPI_CTRLR0_CSM_SHIFT) & SPI_CTRLR0_CSM_MASK) +#define CR0_CSM_0CYCLE CR0_CSM(0) +#define CR0_CSM_1CYCLE CR0_CSM(1) +#define CR0_CSM_2CYCLES CR0_CSM(2) +#define CR0_CSM_3CYCLES CR0_CSM(3) + +/***************************** Structure Definition **************************/ + +/** @brief SPI Type definition */ +typedef enum { + SSI_MOTO_SPI = 0, + SSI_TI_SSP, + SSI_NS_MICROWIRE +} eSPI_SSIType; + +/** @brief SPI Transfer type definition */ +typedef enum { + SPI_POLL = 0, + SPI_IT, + SPI_DMA +} eSPI_TransferType; + +/** @brief SPI Configuration Structure definition */ +struct SPI_CONFIG { + UINT32 opMode; /**< Specifies the SPI operating mode, master or slave. */ + UINT32 xfmMode; /**< Specifies the SPI bidirectional mode state, tx only, rx only or trx mode. */ + UINT32 nBytes; /**< Specifies the SPI data size. */ + UINT32 clkPolarity; /**< Specifies the serial clock steady state. */ + UINT32 clkPhase; /**< Specifies the clock active edge for the bit capture. */ + UINT32 firstBit; /**< Specifies whether data transfers start from MSB or LSB bit. */ + UINT32 endianMode; /**< Specifies whether data transfers start from little or big endian. */ + UINT32 apbTransform; /**< Specifies apb transform type. */ + UINT32 ssd; /**< Specifies period between ss_n active and sclk_out. */ + UINT32 speed; /**< Specifies the Baud Rate prescaler value which will be + used to configure the transmit and receive SCK clock. */ + UINT32 ssiType; /**< Specifies if the TI mode is enabled or not.*/ + UINT32 csm; /**< Specifies Motorola SPI Master SS_N high cycles for each frame data is transfer. */ +}; + +/* We have 2 DMA channels per SPI, one for RX and one for TX */ +struct HAL_SPI_DMA_INFO { + UINT8 channel; + UINT8 direction; + UINT32 addr; +}; + +struct HAL_SPI_DEV { + const UINT32 base; + const UINT32 clkId; + const UINT32 clkGateID; + const UINT32 pclkGateID; + const UINT8 irqNum; + const UINT8 isSlave; + const struct HAL_SPI_DMA_INFO txDma; + const struct HAL_SPI_DMA_INFO rxDma; +}; + +/** @brief SPI handle Structure definition */ +struct SPI_HANDLE { + struct SPI_REG *pReg; /**< Specifies SPI registers base address. */ + UINT32 maxFreq; /**< Specifies SPI clock frequency. */ + struct SPI_CONFIG config; /**< Specifies SPI communication parameters. */ + const UINT8 *pTxBuffer; /**< Specifies pointer to SPI Tx transfer Buffer. */ + const UINT8 *pTxBufferEnd; /**< Specifies pointer to SPI Tx End transfer Buffer. */ + UINT8 *pRxBuffer; /**< Specifies pointer to SPI Rx transfer Buffer. */ + UINT8 *pRxBufferEnd; /**< Specifies pointer to SPI Rx End transfer Buffer. */ + UINT32 len; /**< Specifies the transfer length . */ + eSPI_TransferType type; /**< Specifies the transfer type: POLL/IT/DMA. */ + UINT32 dmaBurstSize; /**< Specifies Dma Burst size */ +}; + + +RETURN_STATUS SPI_Init(struct SPI_HANDLE *pSPI, UINT32 base); +RETURN_STATUS SPI_DeInit(struct SPI_HANDLE *pSPI); +RETURN_STATUS SPI_FlushFifo(struct SPI_HANDLE *pSPI); +RETURN_STATUS SPI_SetCS(struct SPI_HANDLE *pSPI, UINT8 select, UINT8 enable); +RETURN_STATUS SPI_PioTransfer(struct SPI_HANDLE *pSPI); +RETURN_STATUS SPI_Stop(struct SPI_HANDLE *pSPI); +RETURN_STATUS SPI_Configure(struct SPI_HANDLE *pSPI, const UINT8 *pTxData, + UINT8 *pRxData, UINT32 Size); +UINT32 SPI_CalculateTimeout(struct SPI_HANDLE *pSPI); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiMem.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiMem.h new file mode 100644 index 0000000..67fa26f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/SpiMem.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#ifndef _HAL_SPI_MEM_H_ +#define _HAL_SPI_MEM_H_ + +#define BIT(nr) (1UL << (nr)) +/** SPI Memory host mode */ +#define HAL_SPI_CPHA BIT(0) /**< clock phase */ +#define HAL_SPI_CPOL BIT(1) /**< clock polarity */ +#define HAL_SPI_MODE_0 (0 | 0) /**< (original MicroWire) */ +#define HAL_SPI_MODE_1 (0 | HAL_SPI_CPHA) +#define HAL_SPI_MODE_2 (HAL_SPI_CPOL | 0) +#define HAL_SPI_MODE_3 (HAL_SPI_CPOL | HAL_SPI_CPHA) +#define HAL_SPI_CS_HIGH BIT(2) /**< CS active high */ +#define HAL_SPI_LSB_FIRST BIT(3) /**< per-word bits-on-wire */ +#define HAL_SPI_3WIRE BIT(4) /**< SI/SO signals shared */ +#define HAL_SPI_LOOP BIT(5) /**< loopback mode */ +#define HAL_SPI_SLAVE BIT(6) /**< slave mode */ +#define HAL_SPI_PREAMBLE BIT(7) /**< Skip preamble bytes */ +#define HAL_SPI_TX_BYTE BIT(8) /**< transmit with 1 wire byte */ +#define HAL_SPI_TX_DUAL BIT(9) /**< transmit with 2 wires */ +#define HAL_SPI_TX_QUAD BIT(10) /**< transmit with 4 wires */ +#define HAL_SPI_RX_SLOW BIT(11) /**< receive with 1 wire slow */ +#define HAL_SPI_RX_DUAL BIT(12) /**< receive with 2 wires */ +#define HAL_SPI_RX_QUAD BIT(13) /**< receive with 4 wires */ +#define HAL_SPI_XIP BIT(14) /**< support spi flash xip mode */ + +/** SPI Memory host xfer flags */ +#define HAL_SPI_XFER_BEGIN BIT(0) /**< Assert CS before transfer */ +#define HAL_SPI_XFER_END BIT(1) /**< Deassert CS after transfer */ +#define HAL_SPI_XFER_ONCE (HAL_SPI_XFER_BEGIN | HAL_SPI_XFER_END) + +#define JEDEC_MFR(id) (((id) >> 16) & 0xff) + +#define HAL_SPI_MEM_OP_FORMAT(__cmd, __addr, __dummy, __data) \ + { \ + .cmd = __cmd, \ + .addr = __addr, \ + .dummy = __dummy, \ + .data = __data, \ + } + +#define HAL_SPI_MEM_OP_CMD(__opcode, __buswidth) \ + { \ + .buswidth = __buswidth, \ + .opcode = __opcode, \ + } + +#define HAL_SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \ + { \ + .nbytes = __nbytes, \ + .val = __val, \ + .buswidth = __buswidth, \ + } + +#define HAL_SPI_MEM_OP_NO_ADDR \ + { \ + .nbytes = 0, \ + .val = 0, \ + .buswidth = 0, \ + } + +#define HAL_SPI_MEM_OP_DUMMY(__nbytes, __buswidth) \ + { \ + .a2dIdle = 0, \ + .nbytes = __nbytes, \ + .buswidth = __buswidth, \ + } + +#define HAL_SPI_MEM_OP_NO_DUMMY \ + { \ + .a2dIdle = 0, \ + .nbytes = 0, \ + .buswidth = 0, \ + } + +#define HAL_SPI_MEM_OP_DATA_IN(__nbytes, __buf, __buswidth) \ + { \ + .dir = HAL_SPI_MEM_DATA_IN, \ + .nbytes = __nbytes, \ + .buf.in = __buf, \ + .buswidth = __buswidth, \ + } + +#define HAL_SPI_MEM_OP_DATA_OUT(__nbytes, __buf, __buswidth) \ + { \ + .dir = HAL_SPI_MEM_DATA_OUT, \ + .nbytes = __nbytes, \ + .buf.out = __buf, \ + .buswidth = __buswidth, \ + } + +#define HAL_SPI_MEM_OP_NO_DATA \ + { \ + .dir = HAL_SPI_MEM_DATA_IN, \ + .nbytes = 0, \ + .buf.out = NULL, \ + .buswidth = 0, \ + } + +/* Max len case: cmd(1) + addr(4) + dummy(4) */ +#define HAL_SPI_OP_LEN_MAX 0x10 + +/***************************** Structure Definition **************************/ + +enum SPI_MEM_DATA_DIR { + HAL_SPI_MEM_DATA_IN, + HAL_SPI_MEM_DATA_OUT, +}; + +struct HAL_SPI_MEM_OP { + struct { + uint8_t buswidth; + uint8_t opcode; + } cmd; + + struct { + uint8_t nbytes; + uint8_t buswidth; + uint32_t val; + } addr; + + struct { + uint8_t a2dIdle; + uint8_t nbytes; + uint8_t buswidth; + } dummy; + + struct { + uint8_t buswidth; + enum SPI_MEM_DATA_DIR dir; + unsigned int nbytes; + /**< buf.{in,out} must be DMA-able. */ + union { + void *in; + const void *out; + } buf; + } data; +}; + +#define HAL_SPI_MEM_OP(__cmd, __addr, __dummy, __data) \ + { \ + .cmd = __cmd, \ + .addr = __addr, \ + .dummy = __dummy, \ + .data = __data, \ + } + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Vop2Regs.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Vop2Regs.h new file mode 100644 index 0000000..dace873 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/Vop2Regs.h @@ -0,0 +1,701 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __VOP2_REGS_H__ +#define __VOP2_REGS_H__ + +/* System registers definition */ +#define RK3568_REG_CFG_DONE 0x000 +#define CFG_DONE_EN BIT(15) + +#define RK3568_VERSION_INFO 0x004 +#define EN_MASK 1 +#define ALL_MASK 0xFFFFFFFF + +#define RK3568_AUTO_GATING_CTRL 0x008 + +#define RK3568_SYS_AXI_LUT_CTRL 0x024 +#define LUT_DMA_EN_SHIFT 0 + +#define RK3568_DSP_IF_EN 0x028 +#define RGB_EN_SHIFT 0 +#define RK3588_DP0_EN_SHIFT 0 +#define RK3588_DP1_EN_SHIFT 1 +#define RK3588_RGB_EN_SHIFT 8 +#define HDMI0_EN_SHIFT 1 +#define EDP0_EN_SHIFT 3 +#define RK3588_EDP0_EN_SHIFT 2 +#define RK3588_HDMI0_EN_SHIFT 3 +#define MIPI0_EN_SHIFT 4 +#define RK3588_EDP1_EN_SHIFT 4 +#define RK3588_HDMI1_EN_SHIFT 5 +#define RK3588_MIPI0_EN_SHIFT 6 +#define MIPI1_EN_SHIFT 20 +#define RK3588_MIPI1_EN_SHIFT 7 +#define LVDS0_EN_SHIFT 5 +#define LVDS1_EN_SHIFT 24 +#define BT1120_EN_SHIFT 6 +#define BT656_EN_SHIFT 7 +#define IF_MUX_MASK 3 +#define RGB_MUX_SHIFT 8 +#define HDMI0_MUX_SHIFT 10 +#define RK3588_DP0_MUX_SHIFT 12 +#define RK3588_DP1_MUX_SHIFT 14 +#define EDP0_MUX_SHIFT 14 +#define RK3588_HDMI_EDP0_MUX_SHIFT 16 +#define RK3588_HDMI_EDP1_MUX_SHIFT 18 +#define MIPI0_MUX_SHIFT 16 +#define RK3588_MIPI0_MUX_SHIFT 20 +#define MIPI1_MUX_SHIFT 21 +#define LVDS0_MUX_SHIFT 18 +#define LVDS1_MUX_SHIFT 25 + +#define RK3568_DSP_IF_CTRL 0x02C +#define LVDS_DUAL_EN_SHIFT 0 +#define RK3588_BT656_UV_SWAP_SHIFT 0 +#define LVDS_DUAL_LEFT_RIGHT_EN_SHIFT 1 +#define RK3588_BT656_YC_SWAP_SHIFT 1 +#define LVDS_DUAL_SWAP_EN_SHIFT 2 +#define BT656_UV_SWAP 4 +#define RK3588_BT1120_UV_SWAP_SHIFT 4 +#define BT656_YC_SWAP 5 +#define RK3588_BT1120_YC_SWAP_SHIFT 5 +#define BT656_DCLK_POL 6 +#define RK3588_HDMI_DUAL_EN_SHIFT 8 +#define RK3588_EDP_DUAL_EN_SHIFT 8 +#define RK3588_DP_DUAL_EN_SHIFT 9 +#define RK3568_MIPI_DUAL_EN_SHIFT 10 +#define RK3588_MIPI_DSI0_MODE_SEL_SHIFT 11 +#define RK3588_MIPI_DSI1_MODE_SEL_SHIFT 12 + +#define RK3568_DSP_IF_POL 0x030 +#define IF_CTRL_REG_DONE_IMD_MASK 1 +#define IF_CTRL_REG_DONE_IMD_SHIFT 28 +#define IF_CRTL_MIPI_DCLK_POL_SHIT 19 +#define IF_CRTL_EDP_DCLK_POL_SHIT 15 +#define IF_CRTL_HDMI_DCLK_POL_SHIT 7 +#define IF_CRTL_HDMI_PIN_POL_MASK 0x7 +#define IF_CRTL_HDMI_PIN_POL_SHIT 4 + +#define RK3588_DP0_PIN_POL_SHIFT 8 +#define RK3588_DP1_PIN_POL_SHIFT 12 +#define RK3588_IF_PIN_POL_MASK 0x7 + +#define IF_CRTL_RGB_LVDS_DCLK_POL_SHIT 3 + +#define HDMI_EDP0_DCLK_DIV_SHIFT 16 +#define HDMI_EDP0_PIXCLK_DIV_SHIFT 18 +#define HDMI_EDP1_DCLK_DIV_SHIFT 20 +#define HDMI_EDP1_PIXCLK_DIV_SHIFT 22 +#define MIPI0_PIXCLK_DIV_SHIFT 24 +#define MIPI1_PIXCLK_DIV_SHIFT 26 + +#define RK3568_SYS_OTP_WIN_EN 0x50 +#define OTP_WIN_EN_SHIFT 0 +#define RK3568_SYS_LUT_PORT_SEL 0x58 +#define GAMMA_PORT_SEL_MASK 0x3 +#define GAMMA_PORT_SEL_SHIFT 0 +#define RK3568_MIPI_DUAL_EN_SHIFT 10 + +#define RK3568_SYS_PD_CTRL 0x034 +#define RK3568_VP0_LINE_FLAG 0x70 +#define RK3568_VP1_LINE_FLAG 0x74 +#define RK3568_VP2_LINE_FLAG 0x78 +#define RK3568_SYS0_INT_EN 0x80 +#define RK3568_SYS0_INT_CLR 0x84 +#define RK3568_SYS0_INT_STATUS 0x88 +#define RK3568_SYS1_INT_EN 0x90 +#define RK3568_SYS1_INT_CLR 0x94 +#define RK3568_SYS1_INT_STATUS 0x98 +#define RK3568_VP0_INT_EN 0xA0 +#define RK3568_VP0_INT_CLR 0xA4 +#define RK3568_VP0_INT_STATUS 0xA8 +#define RK3568_VP1_INT_EN 0xB0 +#define RK3568_VP1_INT_CLR 0xB4 +#define RK3568_VP1_INT_STATUS 0xB8 +#define RK3568_VP2_INT_EN 0xC0 +#define RK3568_VP2_INT_CLR 0xC4 +#define RK3568_VP2_INT_STATUS 0xC8 +#define RK3588_CLUSTER0_PD_EN_SHIFT 0 +#define RK3588_CLUSTER1_PD_EN_SHIFT 1 +#define RK3588_CLUSTER2_PD_EN_SHIFT 2 +#define RK3588_CLUSTER3_PD_EN_SHIFT 3 +#define RK3588_DSC_8K_PD_EN_SHIFT 5 +#define RK3588_DSC_4K_PD_EN_SHIFT 6 +#define RK3588_ESMART_PD_EN_SHIFT 7 + +#define RK3568_SYS_STATUS0 0x60 +#define RK3588_CLUSTER0_PD_STATUS_SHIFT 8 +#define RK3588_CLUSTER1_PD_STATUS_SHIFT 9 +#define RK3588_CLUSTER2_PD_STATUS_SHIFT 10 +#define RK3588_CLUSTER3_PD_STATUS_SHIFT 11 +#define RK3588_DSC_8K_PD_STATUS_SHIFT 13 +#define RK3588_DSC_4K_PD_STATUS_SHIFT 14 +#define RK3588_ESMART_PD_STATUS_SHIFT 15 + + +/* Overlay registers definition */ +#define RK3568_OVL_CTRL 0x600 +#define OVL_PORT_MUX_REG_DONE_IMD_SHIFT 28 +#define RK3568_OVL_LAYER_SEL 0x604 +#define LAYER_SEL_MASK 0xF + +#define RK3568_OVL_PORT_SEL 0x608 +#define PORT_MUX_MASK 0xF +#define PORT_MUX_SHIFT 0 +#define LAYER_SEL_PORT_MASK 0x3 +#define LAYER_SEL_PORT_SHIFT 16 + +#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL 0x610 +#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL 0x614 +#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL 0x618 +#define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL 0x61C +#define RK3568_MIX0_SRC_COLOR_CTRL 0x650 +#define RK3568_MIX0_DST_COLOR_CTRL 0x654 +#define RK3568_MIX0_SRC_ALPHA_CTRL 0x658 +#define RK3568_MIX0_DST_ALPHA_CTRL 0x65C +#define RK3568_HDR0_SRC_COLOR_CTRL 0x6C0 +#define RK3568_HDR0_DST_COLOR_CTRL 0x6C4 +#define RK3568_HDR0_SRC_ALPHA_CTRL 0x6C8 +#define RK3568_HDR0_DST_ALPHA_CTRL 0x6CC +#define RK3568_VP0_BG_MIX_CTRL 0x6E0 +#define BG_MIX_CTRL_MASK 0xff +#define BG_MIX_CTRL_SHIFT 24 +#define RK3568_VP1_BG_MIX_CTRL 0x6E4 +#define RK3568_VP2_BG_MIX_CTRL 0x6E8 +#define RK3568_CLUSTER_DLY_NUM 0x6F0 +#define RK3568_SMART_DLY_NUM 0x6F8 + +/* Video Port registers definition */ +#define RK3568_VP0_DSP_CTRL 0xC00 +#define OUT_MODE_MASK 0xF +#define OUT_MODE_SHIFT 0 +#define DATA_SWAP_MASK 0x1F +#define DATA_SWAP_SHIFT 8 +#define DSP_BG_SWAP 0x1 +#define DSP_RB_SWAP 0x2 +#define DSP_RG_SWAP 0x4 +#define DSP_DELTA_SWAP 0x8 +#define CORE_DCLK_DIV_EN_SHIFT 4 +#define P2I_EN_SHIFT 5 +#define DSP_FILED_POL 6 +#define INTERLACE_EN_SHIFT 7 +#define POST_DSP_OUT_R2Y_SHIFT 15 +#define PRE_DITHER_DOWN_EN_SHIFT 16 +#define DITHER_DOWN_EN_SHIFT 17 +#define DSP_LUT_EN_SHIFT 28 + +#define STANDBY_EN_SHIFT 31 + +#define RK3568_VP0_MIPI_CTRL 0xC04 +#define DCLK_DIV2_SHIFT 4 +#define DCLK_DIV2_MASK 0x3 +#define MIPI_DUAL_EN_SHIFT 20 +#define MIPI_DUAL_SWAP_EN_SHIFT 21 +#define EDPI_TE_EN 28 +#define EDPI_WMS_HOLD_EN 30 +#define EDPI_WMS_FS 31 + +#define RK3568_VP0_COLOR_BAR_CTRL 0xC08 +#define RK3568_VP0_3D_LUT_CTRL 0xC10 +#define VP0_3D_LUT_EN_SHIFT 0 +#define VP0_3D_LUT_UPDATE_SHIFT 2 + +#define RK3588_VP0_CLK_CTRL 0xC0C +#define DCLK_CORE_DIV_SHIFT 0 +#define DCLK_OUT_DIV_SHIFT 2 + +#define RK3568_VP0_3D_LUT_MST 0xC20 + +#define RK3568_VP0_DSP_BG 0xC2C +#define RK3568_VP0_PRE_SCAN_HTIMING 0xC30 +#define RK3568_VP0_POST_DSP_HACT_INFO 0xC34 +#define RK3568_VP0_POST_DSP_VACT_INFO 0xC38 +#define RK3568_VP0_POST_SCL_FACTOR_YRGB 0xC3C +#define RK3568_VP0_POST_SCL_CTRL 0xC40 +#define RK3568_VP0_POST_DSP_VACT_INFO_F1 0xC44 +#define RK3568_VP0_DSP_HTOTAL_HS_END 0xC48 +#define RK3568_VP0_DSP_HACT_ST_END 0xC4C +#define RK3568_VP0_DSP_VTOTAL_VS_END 0xC50 +#define RK3568_VP0_DSP_VACT_ST_END 0xC54 +#define RK3568_VP0_DSP_VS_ST_END_F1 0xC58 +#define RK3568_VP0_DSP_VACT_ST_END_F1 0xC5C + +#define RK3568_VP0_BCSH_CTRL 0xC60 +#define BCSH_CTRL_Y2R_SHIFT 0 +#define BCSH_CTRL_Y2R_MASK 0x1 +#define BCSH_CTRL_Y2R_CSC_MODE_SHIFT 2 +#define BCSH_CTRL_Y2R_CSC_MODE_MASK 0x3 +#define BCSH_CTRL_R2Y_SHIFT 4 +#define BCSH_CTRL_R2Y_MASK 0x1 +#define BCSH_CTRL_R2Y_CSC_MODE_SHIFT 6 +#define BCSH_CTRL_R2Y_CSC_MODE_MASK 0x3 + +#define RK3568_VP0_BCSH_BCS 0xC64 +#define BCSH_BRIGHTNESS_SHIFT 0 +#define BCSH_BRIGHTNESS_MASK 0xFF +#define BCSH_CONTRAST_SHIFT 8 +#define BCSH_CONTRAST_MASK 0x1FF +#define BCSH_SATURATION_SHIFT 20 +#define BCSH_SATURATION_MASK 0x3FF +#define BCSH_OUT_MODE_SHIFT 30 +#define BCSH_OUT_MODE_MASK 0x3 + +#define RK3568_VP0_BCSH_H 0xC68 +#define BCSH_SIN_HUE_SHIFT 0 +#define BCSH_SIN_HUE_MASK 0x1FF +#define BCSH_COS_HUE_SHIFT 16 +#define BCSH_COS_HUE_MASK 0x1FF + +#define RK3568_VP0_BCSH_COLOR 0xC6C +#define BCSH_EN_SHIFT 31 +#define BCSH_EN_MASK 1 + +#define RK3568_VP1_DSP_CTRL 0xD00 +#define RK3568_VP1_MIPI_CTRL 0xD04 +#define RK3568_VP1_COLOR_BAR_CTRL 0xD08 +#define RK3568_VP1_PRE_SCAN_HTIMING 0xD30 +#define RK3568_VP1_POST_DSP_HACT_INFO 0xD34 +#define RK3568_VP1_POST_DSP_VACT_INFO 0xD38 +#define RK3568_VP1_POST_SCL_FACTOR_YRGB 0xD3C +#define RK3568_VP1_POST_SCL_CTRL 0xD40 +#define RK3568_VP1_DSP_HACT_INFO 0xD34 +#define RK3568_VP1_DSP_VACT_INFO 0xD38 +#define RK3568_VP1_POST_DSP_VACT_INFO_F1 0xD44 +#define RK3568_VP1_DSP_HTOTAL_HS_END 0xD48 +#define RK3568_VP1_DSP_HACT_ST_END 0xD4C +#define RK3568_VP1_DSP_VTOTAL_VS_END 0xD50 +#define RK3568_VP1_DSP_VACT_ST_END 0xD54 +#define RK3568_VP1_DSP_VS_ST_END_F1 0xD58 +#define RK3568_VP1_DSP_VACT_ST_END_F1 0xD5C + +#define RK3568_VP2_DSP_CTRL 0xE00 +#define RK3568_VP2_MIPI_CTRL 0xE04 +#define RK3568_VP2_COLOR_BAR_CTRL 0xE08 +#define RK3568_VP2_PRE_SCAN_HTIMING 0xE30 +#define RK3568_VP2_POST_DSP_HACT_INFO 0xE34 +#define RK3568_VP2_POST_DSP_VACT_INFO 0xE38 +#define RK3568_VP2_POST_SCL_FACTOR_YRGB 0xE3C +#define RK3568_VP2_POST_SCL_CTRL 0xE40 +#define RK3568_VP2_DSP_HACT_INFO 0xE34 +#define RK3568_VP2_DSP_VACT_INFO 0xE38 +#define RK3568_VP2_POST_DSP_VACT_INFO_F1 0xE44 +#define RK3568_VP2_DSP_HTOTAL_HS_END 0xE48 +#define RK3568_VP2_DSP_HACT_ST_END 0xE4C +#define RK3568_VP2_DSP_VTOTAL_VS_END 0xE50 +#define RK3568_VP2_DSP_VACT_ST_END 0xE54 +#define RK3568_VP2_DSP_VS_ST_END_F1 0xE58 +#define RK3568_VP2_DSP_VACT_ST_END_F1 0xE5C + +/* Cluster0 register definition */ +#define RK3568_CLUSTER0_WIN0_CTRL0 0x1000 +#define CLUSTER_YUV2RGB_EN_SHIFT 8 +#define CLUSTER_RGB2YUV_EN_SHIFT 9 +#define CLUSTER_CSC_MODE_SHIFT 10 +#define CLUSTER_YRGB_XSCL_MODE_SHIFT 12 +#define CLUSTER_YRGB_YSCL_MODE_SHIFT 14 +#define RK3568_CLUSTER0_WIN0_CTRL1 0x1004 +#define CLUSTER_YRGB_GT2_SHIFT 28 +#define CLUSTER_YRGB_GT4_SHIFT 29 +#define RK3568_CLUSTER0_WIN0_YRGB_MST 0x1010 +#define RK3568_CLUSTER0_WIN0_CBR_MST 0x1014 +#define RK3568_CLUSTER0_WIN0_VIR 0x1018 +#define RK3568_CLUSTER0_WIN0_ACT_INFO 0x1020 +#define RK3568_CLUSTER0_WIN0_DSP_INFO 0x1024 +#define RK3568_CLUSTER0_WIN0_DSP_ST 0x1028 +#define RK3568_CLUSTER0_WIN0_SCL_FACTOR_YRGB 0x1030 +#define RK3568_CLUSTER0_WIN0_AFBCD_ROTATE_MODE 0x1054 +#define RK3568_CLUSTER0_WIN0_AFBCD_HDR_PTR 0x1058 +#define RK3568_CLUSTER0_WIN0_AFBCD_VIR_WIDTH 0x105C +#define RK3568_CLUSTER0_WIN0_AFBCD_PIC_SIZE 0x1060 +#define RK3568_CLUSTER0_WIN0_AFBCD_PIC_OFFSET 0x1064 +#define RK3568_CLUSTER0_WIN0_AFBCD_DSP_OFFSET 0x1068 +#define RK3568_CLUSTER0_WIN0_AFBCD_CTRL 0x106C + +#define RK3568_CLUSTER0_WIN1_CTRL0 0x1080 +#define RK3568_CLUSTER0_WIN1_CTRL1 0x1084 +#define RK3568_CLUSTER0_WIN1_YRGB_MST 0x1090 +#define RK3568_CLUSTER0_WIN1_CBR_MST 0x1094 +#define RK3568_CLUSTER0_WIN1_VIR 0x1098 +#define RK3568_CLUSTER0_WIN1_ACT_INFO 0x10A0 +#define RK3568_CLUSTER0_WIN1_DSP_INFO 0x10A4 +#define RK3568_CLUSTER0_WIN1_DSP_ST 0x10A8 +#define RK3568_CLUSTER0_WIN1_SCL_FACTOR_YRGB 0x10B0 +#define RK3568_CLUSTER0_WIN1_AFBCD_ROTATE_MODE 0x10D4 +#define RK3568_CLUSTER0_WIN1_AFBCD_HDR_PTR 0x10D8 +#define RK3568_CLUSTER0_WIN1_AFBCD_VIR_WIDTH 0x10DC +#define RK3568_CLUSTER0_WIN1_AFBCD_PIC_SIZE 0x10E0 +#define RK3568_CLUSTER0_WIN1_AFBCD_PIC_OFFSET 0x10E4 +#define RK3568_CLUSTER0_WIN1_AFBCD_DSP_OFFSET 0x10E8 +#define RK3568_CLUSTER0_WIN1_AFBCD_CTRL 0x10EC + +#define RK3568_CLUSTER0_CTRL 0x1100 +#define CLUSTER_EN_SHIFT 0 + +#define RK3568_CLUSTER1_WIN0_CTRL0 0x1200 +#define RK3568_CLUSTER1_WIN0_CTRL1 0x1204 +#define RK3568_CLUSTER1_WIN0_YRGB_MST 0x1210 +#define RK3568_CLUSTER1_WIN0_CBR_MST 0x1214 +#define RK3568_CLUSTER1_WIN0_VIR 0x1218 +#define RK3568_CLUSTER1_WIN0_ACT_INFO 0x1220 +#define RK3568_CLUSTER1_WIN0_DSP_INFO 0x1224 +#define RK3568_CLUSTER1_WIN0_DSP_ST 0x1228 +#define RK3568_CLUSTER1_WIN0_SCL_FACTOR_YRGB 0x1230 +#define RK3568_CLUSTER1_WIN0_AFBCD_ROTATE_MODE 0x1254 +#define RK3568_CLUSTER1_WIN0_AFBCD_HDR_PTR 0x1258 +#define RK3568_CLUSTER1_WIN0_AFBCD_VIR_WIDTH 0x125C +#define RK3568_CLUSTER1_WIN0_AFBCD_PIC_SIZE 0x1260 +#define RK3568_CLUSTER1_WIN0_AFBCD_PIC_OFFSET 0x1264 +#define RK3568_CLUSTER1_WIN0_AFBCD_DSP_OFFSET 0x1268 +#define RK3568_CLUSTER1_WIN0_AFBCD_CTRL 0x126C + +#define RK3568_CLUSTER1_WIN1_CTRL0 0x1280 +#define RK3568_CLUSTER1_WIN1_CTRL1 0x1284 +#define RK3568_CLUSTER1_WIN1_YRGB_MST 0x1290 +#define RK3568_CLUSTER1_WIN1_CBR_MST 0x1294 +#define RK3568_CLUSTER1_WIN1_VIR 0x1298 +#define RK3568_CLUSTER1_WIN1_ACT_INFO 0x12A0 +#define RK3568_CLUSTER1_WIN1_DSP_INFO 0x12A4 +#define RK3568_CLUSTER1_WIN1_DSP_ST 0x12A8 +#define RK3568_CLUSTER1_WIN1_SCL_FACTOR_YRGB 0x12B0 +#define RK3568_CLUSTER1_WIN1_AFBCD_ROTATE_MODE 0x12D4 +#define RK3568_CLUSTER1_WIN1_AFBCD_HDR_PTR 0x12D8 +#define RK3568_CLUSTER1_WIN1_AFBCD_VIR_WIDTH 0x12DC +#define RK3568_CLUSTER1_WIN1_AFBCD_PIC_SIZE 0x12E0 +#define RK3568_CLUSTER1_WIN1_AFBCD_PIC_OFFSET 0x12E4 +#define RK3568_CLUSTER1_WIN1_AFBCD_DSP_OFFSET 0x12E8 +#define RK3568_CLUSTER1_WIN1_AFBCD_CTRL 0x12EC + +#define RK3568_CLUSTER1_CTRL 0x1300 + +/* Esmart register definition */ +#define RK3568_ESMART0_CTRL0 0x1800 +#define RGB2YUV_EN_SHIFT 1 +#define CSC_MODE_SHIFT 2 +#define CSC_MODE_MASK 0x3 + +#define RK3568_ESMART0_CTRL1 0x1804 +#define YMIRROR_EN_SHIFT 31 +#define RK3568_ESMART0_REGION0_CTRL 0x1810 +#define REGION0_RB_SWAP_SHIFT 14 +#define WIN_EN_SHIFT 0 +#define WIN_FORMAT_MASK 0x1f +#define WIN_FORMAT_SHIFT 1 + +#define RK3568_ESMART0_REGION0_YRGB_MST 0x1814 +#define RK3568_ESMART0_REGION0_CBR_MST 0x1818 +#define RK3568_ESMART0_REGION0_VIR 0x181C +#define RK3568_ESMART0_REGION0_ACT_INFO 0x1820 +#define RK3568_ESMART0_REGION0_DSP_INFO 0x1824 +#define RK3568_ESMART0_REGION0_DSP_ST 0x1828 +#define RK3568_ESMART0_REGION0_SCL_CTRL 0x1830 +#define YRGB_XSCL_MODE_MASK 0x3 +#define YRGB_XSCL_MODE_SHIFT 0 +#define YRGB_XSCL_FILTER_MODE_MASK 0x3 +#define YRGB_XSCL_FILTER_MODE_SHIFT 2 +#define YRGB_YSCL_MODE_MASK 0x3 +#define YRGB_YSCL_MODE_SHIFT 4 +#define YRGB_YSCL_FILTER_MODE_MASK 0x3 +#define YRGB_YSCL_FILTER_MODE_SHIFT 6 + +#define RK3568_ESMART0_REGION0_SCL_FACTOR_YRGB 0x1834 +#define RK3568_ESMART0_REGION0_SCL_FACTOR_CBR 0x1838 +#define RK3568_ESMART0_REGION0_SCL_OFFSET 0x183C +#define RK3568_ESMART0_REGION1_CTRL 0x1840 +#define YRGB_GT2_MASK 0x1 +#define YRGB_GT2_SHIFT 8 +#define YRGB_GT4_MASK 0x1 +#define YRGB_GT4_SHIFT 9 + +#define RK3568_ESMART0_REGION1_YRGB_MST 0x1844 +#define RK3568_ESMART0_REGION1_CBR_MST 0x1848 +#define RK3568_ESMART0_REGION1_VIR 0x184C +#define RK3568_ESMART0_REGION1_ACT_INFO 0x1850 +#define RK3568_ESMART0_REGION1_DSP_INFO 0x1854 +#define RK3568_ESMART0_REGION1_DSP_ST 0x1858 +#define RK3568_ESMART0_REGION1_SCL_CTRL 0x1860 +#define RK3568_ESMART0_REGION1_SCL_FACTOR_YRGB 0x1864 +#define RK3568_ESMART0_REGION1_SCL_FACTOR_CBR 0x1868 +#define RK3568_ESMART0_REGION1_SCL_OFFSET 0x186C +#define RK3568_ESMART0_REGION2_CTRL 0x1870 +#define RK3568_ESMART0_REGION2_YRGB_MST 0x1874 +#define RK3568_ESMART0_REGION2_CBR_MST 0x1878 +#define RK3568_ESMART0_REGION2_VIR 0x187C +#define RK3568_ESMART0_REGION2_ACT_INFO 0x1880 +#define RK3568_ESMART0_REGION2_DSP_INFO 0x1884 +#define RK3568_ESMART0_REGION2_DSP_ST 0x1888 +#define RK3568_ESMART0_REGION2_SCL_CTRL 0x1890 +#define RK3568_ESMART0_REGION2_SCL_FACTOR_YRGB 0x1894 +#define RK3568_ESMART0_REGION2_SCL_FACTOR_CBR 0x1898 +#define RK3568_ESMART0_REGION2_SCL_OFFSET 0x189C +#define RK3568_ESMART0_REGION3_CTRL 0x18A0 +#define RK3568_ESMART0_REGION3_YRGB_MST 0x18A4 +#define RK3568_ESMART0_REGION3_CBR_MST 0x18A8 +#define RK3568_ESMART0_REGION3_VIR 0x18AC +#define RK3568_ESMART0_REGION3_ACT_INFO 0x18B0 +#define RK3568_ESMART0_REGION3_DSP_INFO 0x18B4 +#define RK3568_ESMART0_REGION3_DSP_ST 0x18B8 +#define RK3568_ESMART0_REGION3_SCL_CTRL 0x18C0 +#define RK3568_ESMART0_REGION3_SCL_FACTOR_YRGB 0x18C4 +#define RK3568_ESMART0_REGION3_SCL_FACTOR_CBR 0x18C8 +#define RK3568_ESMART0_REGION3_SCL_OFFSET 0x18CC + +#define RK3568_ESMART1_CTRL0 0x1A00 +#define RK3568_ESMART1_CTRL1 0x1A04 +#define RK3568_ESMART1_REGION0_CTRL 0x1A10 +#define RK3568_ESMART1_REGION0_YRGB_MST 0x1A14 +#define RK3568_ESMART1_REGION0_CBR_MST 0x1A18 +#define RK3568_ESMART1_REGION0_VIR 0x1A1C +#define RK3568_ESMART1_REGION0_ACT_INFO 0x1A20 +#define RK3568_ESMART1_REGION0_DSP_INFO 0x1A24 +#define RK3568_ESMART1_REGION0_DSP_ST 0x1A28 +#define RK3568_ESMART1_REGION0_SCL_CTRL 0x1A30 +#define RK3568_ESMART1_REGION0_SCL_FACTOR_YRGB 0x1A34 +#define RK3568_ESMART1_REGION0_SCL_FACTOR_CBR 0x1A38 +#define RK3568_ESMART1_REGION0_SCL_OFFSET 0x1A3C +#define RK3568_ESMART1_REGION1_CTRL 0x1A40 +#define RK3568_ESMART1_REGION1_YRGB_MST 0x1A44 +#define RK3568_ESMART1_REGION1_CBR_MST 0x1A48 +#define RK3568_ESMART1_REGION1_VIR 0x1A4C +#define RK3568_ESMART1_REGION1_ACT_INFO 0x1A50 +#define RK3568_ESMART1_REGION1_DSP_INFO 0x1A54 +#define RK3568_ESMART1_REGION1_DSP_ST 0x1A58 +#define RK3568_ESMART1_REGION1_SCL_CTRL 0x1A60 +#define RK3568_ESMART1_REGION1_SCL_FACTOR_YRGB 0x1A64 +#define RK3568_ESMART1_REGION1_SCL_FACTOR_CBR 0x1A68 +#define RK3568_ESMART1_REGION1_SCL_OFFSET 0x1A6C +#define RK3568_ESMART1_REGION2_CTRL 0x1A70 +#define RK3568_ESMART1_REGION2_YRGB_MST 0x1A74 +#define RK3568_ESMART1_REGION2_CBR_MST 0x1A78 +#define RK3568_ESMART1_REGION2_VIR 0x1A7C +#define RK3568_ESMART1_REGION2_ACT_INFO 0x1A80 +#define RK3568_ESMART1_REGION2_DSP_INFO 0x1A84 +#define RK3568_ESMART1_REGION2_DSP_ST 0x1A88 +#define RK3568_ESMART1_REGION2_SCL_CTRL 0x1A90 +#define RK3568_ESMART1_REGION2_SCL_FACTOR_YRGB 0x1A94 +#define RK3568_ESMART1_REGION2_SCL_FACTOR_CBR 0x1A98 +#define RK3568_ESMART1_REGION2_SCL_OFFSET 0x1A9C +#define RK3568_ESMART1_REGION3_CTRL 0x1AA0 +#define RK3568_ESMART1_REGION3_YRGB_MST 0x1AA4 +#define RK3568_ESMART1_REGION3_CBR_MST 0x1AA8 +#define RK3568_ESMART1_REGION3_VIR 0x1AAC +#define RK3568_ESMART1_REGION3_ACT_INFO 0x1AB0 +#define RK3568_ESMART1_REGION3_DSP_INFO 0x1AB4 +#define RK3568_ESMART1_REGION3_DSP_ST 0x1AB8 +#define RK3568_ESMART1_REGION3_SCL_CTRL 0x1AC0 +#define RK3568_ESMART1_REGION3_SCL_FACTOR_YRGB 0x1AC4 +#define RK3568_ESMART1_REGION3_SCL_FACTOR_CBR 0x1AC8 +#define RK3568_ESMART1_REGION3_SCL_OFFSET 0x1ACC + +#define RK3568_SMART0_CTRL0 0x1C00 +#define RK3568_SMART0_CTRL1 0x1C04 +#define RK3568_SMART0_REGION0_CTRL 0x1C10 +#define RK3568_SMART0_REGION0_YRGB_MST 0x1C14 +#define RK3568_SMART0_REGION0_CBR_MST 0x1C18 +#define RK3568_SMART0_REGION0_VIR 0x1C1C +#define RK3568_SMART0_REGION0_ACT_INFO 0x1C20 +#define RK3568_SMART0_REGION0_DSP_INFO 0x1C24 +#define RK3568_SMART0_REGION0_DSP_ST 0x1C28 +#define RK3568_SMART0_REGION0_SCL_CTRL 0x1C30 +#define RK3568_SMART0_REGION0_SCL_FACTOR_YRGB 0x1C34 +#define RK3568_SMART0_REGION0_SCL_FACTOR_CBR 0x1C38 +#define RK3568_SMART0_REGION0_SCL_OFFSET 0x1C3C +#define RK3568_SMART0_REGION1_CTRL 0x1C40 +#define RK3568_SMART0_REGION1_YRGB_MST 0x1C44 +#define RK3568_SMART0_REGION1_CBR_MST 0x1C48 +#define RK3568_SMART0_REGION1_VIR 0x1C4C +#define RK3568_SMART0_REGION1_ACT_INFO 0x1C50 +#define RK3568_SMART0_REGION1_DSP_INFO 0x1C54 +#define RK3568_SMART0_REGION1_DSP_ST 0x1C58 +#define RK3568_SMART0_REGION1_SCL_CTRL 0x1C60 +#define RK3568_SMART0_REGION1_SCL_FACTOR_YRGB 0x1C64 +#define RK3568_SMART0_REGION1_SCL_FACTOR_CBR 0x1C68 +#define RK3568_SMART0_REGION1_SCL_OFFSET 0x1C6C +#define RK3568_SMART0_REGION2_CTRL 0x1C70 +#define RK3568_SMART0_REGION2_YRGB_MST 0x1C74 +#define RK3568_SMART0_REGION2_CBR_MST 0x1C78 +#define RK3568_SMART0_REGION2_VIR 0x1C7C +#define RK3568_SMART0_REGION2_ACT_INFO 0x1C80 +#define RK3568_SMART0_REGION2_DSP_INFO 0x1C84 +#define RK3568_SMART0_REGION2_DSP_ST 0x1C88 +#define RK3568_SMART0_REGION2_SCL_CTRL 0x1C90 +#define RK3568_SMART0_REGION2_SCL_FACTOR_YRGB 0x1C94 +#define RK3568_SMART0_REGION2_SCL_FACTOR_CBR 0x1C98 +#define RK3568_SMART0_REGION2_SCL_OFFSET 0x1C9C +#define RK3568_SMART0_REGION3_CTRL 0x1CA0 +#define RK3568_SMART0_REGION3_YRGB_MST 0x1CA4 +#define RK3568_SMART0_REGION3_CBR_MST 0x1CA8 +#define RK3568_SMART0_REGION3_VIR 0x1CAC +#define RK3568_SMART0_REGION3_ACT_INFO 0x1CB0 +#define RK3568_SMART0_REGION3_DSP_INFO 0x1CB4 +#define RK3568_SMART0_REGION3_DSP_ST 0x1CB8 +#define RK3568_SMART0_REGION3_SCL_CTRL 0x1CC0 +#define RK3568_SMART0_REGION3_SCL_FACTOR_YRGB 0x1CC4 +#define RK3568_SMART0_REGION3_SCL_FACTOR_CBR 0x1CC8 +#define RK3568_SMART0_REGION3_SCL_OFFSET 0x1CCC + +#define RK3568_SMART1_CTRL0 0x1E00 +#define RK3568_SMART1_CTRL1 0x1E04 +#define RK3568_SMART1_REGION0_CTRL 0x1E10 +#define RK3568_SMART1_REGION0_YRGB_MST 0x1E14 +#define RK3568_SMART1_REGION0_CBR_MST 0x1E18 +#define RK3568_SMART1_REGION0_VIR 0x1E1C +#define RK3568_SMART1_REGION0_ACT_INFO 0x1E20 +#define RK3568_SMART1_REGION0_DSP_INFO 0x1E24 +#define RK3568_SMART1_REGION0_DSP_ST 0x1E28 +#define RK3568_SMART1_REGION0_SCL_CTRL 0x1E30 +#define RK3568_SMART1_REGION0_SCL_FACTOR_YRGB 0x1E34 +#define RK3568_SMART1_REGION0_SCL_FACTOR_CBR 0x1E38 +#define RK3568_SMART1_REGION0_SCL_OFFSET 0x1E3C +#define RK3568_SMART1_REGION1_CTRL 0x1E40 +#define RK3568_SMART1_REGION1_YRGB_MST 0x1E44 +#define RK3568_SMART1_REGION1_CBR_MST 0x1E48 +#define RK3568_SMART1_REGION1_VIR 0x1E4C +#define RK3568_SMART1_REGION1_ACT_INFO 0x1E50 +#define RK3568_SMART1_REGION1_DSP_INFO 0x1E54 +#define RK3568_SMART1_REGION1_DSP_ST 0x1E58 +#define RK3568_SMART1_REGION1_SCL_CTRL 0x1E60 +#define RK3568_SMART1_REGION1_SCL_FACTOR_YRGB 0x1E64 +#define RK3568_SMART1_REGION1_SCL_FACTOR_CBR 0x1E68 +#define RK3568_SMART1_REGION1_SCL_OFFSET 0x1E6C +#define RK3568_SMART1_REGION2_CTRL 0x1E70 +#define RK3568_SMART1_REGION2_YRGB_MST 0x1E74 +#define RK3568_SMART1_REGION2_CBR_MST 0x1E78 +#define RK3568_SMART1_REGION2_VIR 0x1E7C +#define RK3568_SMART1_REGION2_ACT_INFO 0x1E80 +#define RK3568_SMART1_REGION2_DSP_INFO 0x1E84 +#define RK3568_SMART1_REGION2_DSP_ST 0x1E88 +#define RK3568_SMART1_REGION2_SCL_CTRL 0x1E90 +#define RK3568_SMART1_REGION2_SCL_FACTOR_YRGB 0x1E94 +#define RK3568_SMART1_REGION2_SCL_FACTOR_CBR 0x1E98 +#define RK3568_SMART1_REGION2_SCL_OFFSET 0x1E9C +#define RK3568_SMART1_REGION3_CTRL 0x1EA0 +#define RK3568_SMART1_REGION3_YRGB_MST 0x1EA4 +#define RK3568_SMART1_REGION3_CBR_MST 0x1EA8 +#define RK3568_SMART1_REGION3_VIR 0x1EAC +#define RK3568_SMART1_REGION3_ACT_INFO 0x1EB0 +#define RK3568_SMART1_REGION3_DSP_INFO 0x1EB4 +#define RK3568_SMART1_REGION3_DSP_ST 0x1EB8 +#define RK3568_SMART1_REGION3_SCL_CTRL 0x1EC0 +#define RK3568_SMART1_REGION3_SCL_FACTOR_YRGB 0x1EC4 +#define RK3568_SMART1_REGION3_SCL_FACTOR_CBR 0x1EC8 +#define RK3568_SMART1_REGION3_SCL_OFFSET 0x1ECC + +/* DSC 8K/4K register definition */ +#define RK3588_DSC_8K_PPS0_3 0x4000 +#define RK3588_DSC_8K_CTRL0 0x40A0 +#define DSC_EN_SHIFT 0 +#define DSC_RBIT_SHIFT 2 +#define DSC_RBYT_SHIFT 3 +#define DSC_FLAL_SHIFT 4 +#define DSC_MER_SHIFT 5 +#define DSC_EPB_SHIFT 6 +#define DSC_EPL_SHIFT 7 +#define DSC_NSLC_MASK 0x7 +#define DSC_NSLC_SHIFT 16 +#define DSC_SBO_SHIFT 28 +#define DSC_IFEP_SHIFT 29 +#define DSC_PPS_UPD_SHIFT 31 +#define DSC_CTRL0_DEF_CON ((1 << DSC_EN_SHIFT) | (1 << DSC_RBIT_SHIFT) | (0 << DSC_RBYT_SHIFT) | \ + (1 << DSC_FLAL_SHIFT) | (1 << DSC_MER_SHIFT) | (0 << DSC_EPB_SHIFT) | \ + (1 << DSC_EPL_SHIFT) | (1 << DSC_SBO_SHIFT)) + +#define RK3568_MAX_REG 0x1ED0 +#define RK3588_VOP2_REG_BASE 0xFDD90000 + +#define RK3568_SYS_CTRL_LINE_FLAG0 0x70 +#define LINE_FLAG_NUM_MASK 0x1FFF +#define RK3568_DSP_LINE_FLAG_NUM0_SHIFT 0 +#define RK3568_DSP_LINE_FLAG_NUM1_SHIFT 16 + +/* DSC CTRL registers definition */ +#define RK3588_DSC_8K_SYS_CTRL 0x200 +#define DSC_PORT_SEL_MASK 0x3 +#define DSC_PORT_SEL_SHIFT 0 +#define DSC_MAN_MODE_MASK 0x1 +#define DSC_MAN_MODE_SHIFT 2 +#define DSC_INTERFACE_MODE_MASK 0x3 +#define DSC_INTERFACE_MODE_SHIFT 4 +#define DSC_PIXEL_NUM_MASK 0x3 +#define DSC_PIXEL_NUM_SHIFT 6 +#define DSC_PXL_CLK_DIV_MASK 0x1 +#define DSC_PXL_CLK_DIV_SHIFT 8 +#define DSC_CDS_CLK_DIV_MASK 0x3 +#define DSC_CDS_CLK_DIV_SHIFT 12 +#define DSC_TXP_CLK_DIV_MASK 0x3 +#define DSC_TXP_CLK_DIV_SHIFT 14 +#define DSC_INIT_DLY_MODE_MASK 0x1 +#define DSC_INIT_DLY_MODE_SHIFT 16 +#define DSC_SCAN_EN_SHIFT 17 +#define DSC_HALT_EN_SHIFT 18 + +#define RK3588_DSC_8K_RST 0x204 +#define RST_DEASSERT_MASK 0x1 +#define RST_DEASSERT_SHIFT 0 + +#define RK3588_DSC_8K_CFG_DONE 0x208 +#define DSC_CFG_DONE_SHIFT 0 + +#define RK3588_DSC_8K_INIT_DLY 0x20C +#define DSC_INIT_DLY_NUM_MASK 0xffff +#define DSC_INIT_DLY_NUM_SHIFT 0 +#define SCAN_TIMING_PARA_IMD_EN_SHIFT 16 + +#define RK3588_DSC_8K_HTOTAL_HS_END 0x210 +#define DSC_HTOTAL_PW_MASK 0xffffffff +#define DSC_HTOTAL_PW_SHIFT 0 + +#define RK3588_DSC_8K_HACT_ST_END 0x214 +#define DSC_HACT_ST_END_MASK 0xffffffff +#define DSC_HACT_ST_END_SHIFT 0 + +#define RK3588_DSC_8K_VTOTAL_VS_END 0x218 +#define DSC_VTOTAL_PW_MASK 0xffffffff +#define DSC_VTOTAL_PW_SHIFT 0 + +#define RK3588_DSC_8K_VACT_ST_END 0x21C +#define DSC_VACT_ST_END_MASK 0xffffffff +#define DSC_VACT_ST_END_SHIFT 0 + +#define RK3588_DSC_8K_STATUS 0x220 + +#define RK3588_VOP_GRF_BASE 0xFD5A4000 +#define RK3588_GRF_VOP_CON2 0x0008 +#define RK3588_GRF_EDP0_ENABLE_SHIFT 0 +#define RK3588_GRF_HDMITX0_ENABLE_SHIFT 1 +#define RK3588_GRF_EDP1_ENABLE_SHIFT 3 +#define RK3588_GRF_HDMITX1_ENABLE_SHIFT 4 + +#define RK3588_VO0_GRF_BASE 0xFD5A6000 + +#define RK3588_VO1_GRF_BASE 0xFD5A8000 +#define RK3588_GRF_VO1_CON0 0x0000 +#define HDMI_SYNC_POL_MASK 0x3 +#define HDMI0_SYNC_POL_SHIFT 5 +#define HDMI1_SYNC_POL_SHIFT 7 + +#define RK3588_PMU_BISR_CON3 0x20C +#define RK3588_PD_CLUSTER0_REPAIR_EN_SHIFT 9 +#define RK3588_PD_CLUSTER1_REPAIR_EN_SHIFT 10 +#define RK3588_PD_CLUSTER2_REPAIR_EN_SHIFT 11 +#define RK3588_PD_CLUSTER3_REPAIR_EN_SHIFT 12 +#define RK3588_PD_DSC_8K_REPAIR_EN_SHIFT 13 +#define RK3588_PD_DSC_4K_REPAIR_EN_SHIFT 14 +#define RK3588_PD_ESMART_REPAIR_EN_SHIFT 15 + +#define RK3588_PMU_BISR_STATUS5 0x294 +#define RK3588_PD_CLUSTER0_PWR_STAT_SHIFI 9 +#define RK3588_PD_CLUSTER1_PWR_STAT_SHIFI 10 +#define RK3588_PD_CLUSTER2_PWR_STAT_SHIFI 11 +#define RK3588_PD_CLUSTER3_PWR_STAT_SHIFI 12 +#define RK3588_PD_DSC_8K_PWR_STAT_SHIFI 13 +#define RK3588_PD_DSC_4K_PWR_STAT_SHIFI 14 +#define RK3588_PD_ESMART_PWR_STAT_SHIFI 15 + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dp_helper.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dp_helper.h new file mode 100644 index 0000000..e28b3cf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dp_helper.h @@ -0,0 +1,1227 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright © 2008 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _DRM_DP_HELPER_H_ +#define _DRM_DP_HELPER_H_ + +/* + * Unless otherwise noted, all values are from the DP 1.1a spec. Note that + * DP and DPCD versions are independent. Differences from 1.0 are not noted, + * 1.0 devices basically don't exist in the wild. + * + * Abbreviations, in chronological order: + * + * eDP: Embedded DisplayPort version 1 + * DPI: DisplayPort Interoperability Guideline v1.1a + * 1.2: DisplayPort 1.2 + * MST: Multistream Transport - part of DP 1.2a + * + * 1.2 formally includes both eDP and DPI definitions. + */ + +/* MSA (Main Stream Attribute) MISC bits (as MISC1<<8|MISC0) */ +#define DP_MSA_MISC_SYNC_CLOCK (1 << 0) +#define DP_MSA_MISC_INTERLACE_VTOTAL_EVEN (1 << 8) +#define DP_MSA_MISC_STEREO_NO_3D (0 << 9) +#define DP_MSA_MISC_STEREO_PROG_RIGHT_EYE (1 << 9) +#define DP_MSA_MISC_STEREO_PROG_LEFT_EYE (3 << 9) +/* bits per component for non-RAW */ +#define DP_MSA_MISC_6_BPC (0 << 5) +#define DP_MSA_MISC_8_BPC (1 << 5) +#define DP_MSA_MISC_10_BPC (2 << 5) +#define DP_MSA_MISC_12_BPC (3 << 5) +#define DP_MSA_MISC_16_BPC (4 << 5) +/* bits per component for RAW */ +#define DP_MSA_MISC_RAW_6_BPC (1 << 5) +#define DP_MSA_MISC_RAW_7_BPC (2 << 5) +#define DP_MSA_MISC_RAW_8_BPC (3 << 5) +#define DP_MSA_MISC_RAW_10_BPC (4 << 5) +#define DP_MSA_MISC_RAW_12_BPC (5 << 5) +#define DP_MSA_MISC_RAW_14_BPC (6 << 5) +#define DP_MSA_MISC_RAW_16_BPC (7 << 5) +/* pixel encoding/colorimetry format */ +#define _DP_MSA_MISC_COLOR(misc1_7, misc0_21, misc0_3, misc0_4) \ + ((misc1_7) << 15 | (misc0_4) << 4 | (misc0_3) << 3 | ((misc0_21) << 1)) +#define DP_MSA_MISC_COLOR_RGB _DP_MSA_MISC_COLOR(0, 0, 0, 0) +#define DP_MSA_MISC_COLOR_CEA_RGB _DP_MSA_MISC_COLOR(0, 0, 1, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FIXED _DP_MSA_MISC_COLOR(0, 3, 0, 0) +#define DP_MSA_MISC_COLOR_RGB_WIDE_FLOAT _DP_MSA_MISC_COLOR(0, 3, 0, 1) +#define DP_MSA_MISC_COLOR_Y_ONLY _DP_MSA_MISC_COLOR(1, 0, 0, 0) +#define DP_MSA_MISC_COLOR_RAW _DP_MSA_MISC_COLOR(1, 1, 0, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 1, 1) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 1, 0) +#define DP_MSA_MISC_COLOR_YCBCR_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 1, 1) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT601 _DP_MSA_MISC_COLOR(0, 1, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_422_BT709 _DP_MSA_MISC_COLOR(0, 1, 0, 1) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT601 _DP_MSA_MISC_COLOR(0, 2, 0, 0) +#define DP_MSA_MISC_COLOR_XVYCC_444_BT709 _DP_MSA_MISC_COLOR(0, 2, 0, 1) +#define DP_MSA_MISC_COLOR_OPRGB _DP_MSA_MISC_COLOR(0, 0, 1, 1) +#define DP_MSA_MISC_COLOR_DCI_P3 _DP_MSA_MISC_COLOR(0, 3, 1, 0) +#define DP_MSA_MISC_COLOR_COLOR_PROFILE _DP_MSA_MISC_COLOR(0, 3, 1, 1) +#define DP_MSA_MISC_COLOR_VSC_SDP (1 << 14) + +#define DP_AUX_MAX_PAYLOAD_BYTES 16 + +#define DP_AUX_I2C_WRITE 0x0 +#define DP_AUX_I2C_READ 0x1 +#define DP_AUX_I2C_WRITE_STATUS_UPDATE 0x2 +#define DP_AUX_I2C_MOT 0x4 +#define DP_AUX_NATIVE_WRITE 0x8 +#define DP_AUX_NATIVE_READ 0x9 + +#define DP_AUX_NATIVE_REPLY_ACK (0x0 << 0) +#define DP_AUX_NATIVE_REPLY_NACK (0x1 << 0) +#define DP_AUX_NATIVE_REPLY_DEFER (0x2 << 0) +#define DP_AUX_NATIVE_REPLY_MASK (0x3 << 0) + +#define DP_AUX_I2C_REPLY_ACK (0x0 << 2) +#define DP_AUX_I2C_REPLY_NACK (0x1 << 2) +#define DP_AUX_I2C_REPLY_DEFER (0x2 << 2) +#define DP_AUX_I2C_REPLY_MASK (0x3 << 2) + +/* AUX CH addresses */ +/* DPCD */ +#define DP_DPCD_REV 0x000 +# define DP_DPCD_REV_10 0x10 +# define DP_DPCD_REV_11 0x11 +# define DP_DPCD_REV_12 0x12 +# define DP_DPCD_REV_13 0x13 +# define DP_DPCD_REV_14 0x14 + +#define DP_MAX_LINK_RATE 0x001 + +#define DP_MAX_LANE_COUNT 0x002 +# define DP_MAX_LANE_COUNT_MASK 0x1f +# define DP_TPS3_SUPPORTED (1 << 6) /* 1.2 */ +# define DP_ENHANCED_FRAME_CAP (1 << 7) + +#define DP_MAX_DOWNSPREAD 0x003 +# define DP_MAX_DOWNSPREAD_0_5 (1 << 0) +# define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6) +# define DP_TPS4_SUPPORTED (1 << 7) + +#define DP_NORP 0x004 + +#define DP_DOWNSTREAMPORT_PRESENT 0x005 +# define DP_DWN_STRM_PORT_PRESENT (1 << 0) +# define DP_DWN_STRM_PORT_TYPE_MASK 0x06 +# define DP_DWN_STRM_PORT_TYPE_DP (0 << 1) +# define DP_DWN_STRM_PORT_TYPE_ANALOG (1 << 1) +# define DP_DWN_STRM_PORT_TYPE_TMDS (2 << 1) +# define DP_DWN_STRM_PORT_TYPE_OTHER (3 << 1) +# define DP_FORMAT_CONVERSION (1 << 3) +# define DP_DETAILED_CAP_INFO_AVAILABLE (1 << 4) /* DPI */ + +#define DP_MAIN_LINK_CHANNEL_CODING 0x006 +# define DP_CAP_ANSI_8B10B (1 << 0) + +#define DP_DOWN_STREAM_PORT_COUNT 0x007 +# define DP_PORT_COUNT_MASK 0x0f +# define DP_MSA_TIMING_PAR_IGNORED (1 << 6) /* eDP */ +# define DP_OUI_SUPPORT (1 << 7) + +#define DP_RECEIVE_PORT_0_CAP_0 0x008 +# define DP_LOCAL_EDID_PRESENT (1 << 1) +# define DP_ASSOCIATED_TO_PRECEDING_PORT (1 << 2) + +#define DP_RECEIVE_PORT_0_BUFFER_SIZE 0x009 + +#define DP_RECEIVE_PORT_1_CAP_0 0x00a +#define DP_RECEIVE_PORT_1_BUFFER_SIZE 0x00b + +#define DP_I2C_SPEED_CAP 0x00c /* DPI */ +# define DP_I2C_SPEED_1K 0x01 +# define DP_I2C_SPEED_5K 0x02 +# define DP_I2C_SPEED_10K 0x04 +# define DP_I2C_SPEED_100K 0x08 +# define DP_I2C_SPEED_400K 0x10 +# define DP_I2C_SPEED_1M 0x20 + +#define DP_EDP_CONFIGURATION_CAP 0x00d /* XXX 1.2? */ +# define DP_ALTERNATE_SCRAMBLER_RESET_CAP (1 << 0) +# define DP_FRAMING_CHANGE_CAP (1 << 1) +# define DP_DPCD_DISPLAY_CONTROL_CAPABLE (1 << 3) /* edp v1.2 or higher */ + +#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +# define DP_TRAINING_AUX_RD_MASK 0x7F /* XXX 1.2? */ +# define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */ + +#define DP_ADAPTER_CAP 0x00f /* 1.2 */ +# define DP_FORCE_LOAD_SENSE_CAP (1 << 0) +# define DP_ALTERNATE_I2C_PATTERN_CAP (1 << 1) + +#define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */ +# define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */ + +/* Multiple stream transport */ +#define DP_FAUX_CAP 0x020 /* 1.2 */ +# define DP_FAUX_CAP_1 (1 << 0) + +#define DP_MSTM_CAP 0x021 /* 1.2 */ +# define DP_MST_CAP (1 << 0) + +#define DP_NUMBER_OF_AUDIO_ENDPOINTS 0x022 /* 1.2 */ + +/* AV_SYNC_DATA_BLOCK 1.2 */ +#define DP_AV_GRANULARITY 0x023 +# define DP_AG_FACTOR_MASK (0xf << 0) +# define DP_AG_FACTOR_3MS (0 << 0) +# define DP_AG_FACTOR_2MS (1 << 0) +# define DP_AG_FACTOR_1MS (2 << 0) +# define DP_AG_FACTOR_500US (3 << 0) +# define DP_AG_FACTOR_200US (4 << 0) +# define DP_AG_FACTOR_100US (5 << 0) +# define DP_AG_FACTOR_10US (6 << 0) +# define DP_AG_FACTOR_1US (7 << 0) +# define DP_VG_FACTOR_MASK (0xf << 4) +# define DP_VG_FACTOR_3MS (0 << 4) +# define DP_VG_FACTOR_2MS (1 << 4) +# define DP_VG_FACTOR_1MS (2 << 4) +# define DP_VG_FACTOR_500US (3 << 4) +# define DP_VG_FACTOR_200US (4 << 4) +# define DP_VG_FACTOR_100US (5 << 4) + +#define DP_AUD_DEC_LAT0 0x024 +#define DP_AUD_DEC_LAT1 0x025 + +#define DP_AUD_PP_LAT0 0x026 +#define DP_AUD_PP_LAT1 0x027 + +#define DP_VID_INTER_LAT 0x028 + +#define DP_VID_PROG_LAT 0x029 + +#define DP_REP_LAT 0x02a + +#define DP_AUD_DEL_INS0 0x02b +#define DP_AUD_DEL_INS1 0x02c +#define DP_AUD_DEL_INS2 0x02d +/* End of AV_SYNC_DATA_BLOCK */ + +#define DP_RECEIVER_ALPM_CAP 0x02e /* eDP 1.4 */ +# define DP_ALPM_CAP (1 << 0) + +#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CAP 0x02f /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_CAP (1 << 0) + +#define DP_GUID 0x030 /* 1.2 */ + +#define DP_DSC_SUPPORT 0x060 /* DP 1.4 */ +# define DP_DSC_DECOMPRESSION_IS_SUPPORTED (1 << 0) + +#define DP_DSC_REV 0x061 +# define DP_DSC_MAJOR_MASK (0xf << 0) +# define DP_DSC_MINOR_MASK (0xf << 4) +# define DP_DSC_MAJOR_SHIFT 0 +# define DP_DSC_MINOR_SHIFT 4 + +#define DP_DSC_RC_BUF_BLK_SIZE 0x062 +# define DP_DSC_RC_BUF_BLK_SIZE_1 0x0 +# define DP_DSC_RC_BUF_BLK_SIZE_4 0x1 +# define DP_DSC_RC_BUF_BLK_SIZE_16 0x2 +# define DP_DSC_RC_BUF_BLK_SIZE_64 0x3 + +#define DP_DSC_RC_BUF_SIZE 0x063 + +#define DP_DSC_SLICE_CAP_1 0x064 +# define DP_DSC_1_PER_DP_DSC_SINK (1 << 0) +# define DP_DSC_2_PER_DP_DSC_SINK (1 << 1) +# define DP_DSC_4_PER_DP_DSC_SINK (1 << 3) +# define DP_DSC_6_PER_DP_DSC_SINK (1 << 4) +# define DP_DSC_8_PER_DP_DSC_SINK (1 << 5) +# define DP_DSC_10_PER_DP_DSC_SINK (1 << 6) +# define DP_DSC_12_PER_DP_DSC_SINK (1 << 7) + +#define DP_DSC_LINE_BUF_BIT_DEPTH 0x065 +# define DP_DSC_LINE_BUF_BIT_DEPTH_MASK (0xf << 0) +# define DP_DSC_LINE_BUF_BIT_DEPTH_9 0x0 +# define DP_DSC_LINE_BUF_BIT_DEPTH_10 0x1 +# define DP_DSC_LINE_BUF_BIT_DEPTH_11 0x2 +# define DP_DSC_LINE_BUF_BIT_DEPTH_12 0x3 +# define DP_DSC_LINE_BUF_BIT_DEPTH_13 0x4 +# define DP_DSC_LINE_BUF_BIT_DEPTH_14 0x5 +# define DP_DSC_LINE_BUF_BIT_DEPTH_15 0x6 +# define DP_DSC_LINE_BUF_BIT_DEPTH_16 0x7 +# define DP_DSC_LINE_BUF_BIT_DEPTH_8 0x8 + +#define DP_DSC_BLK_PREDICTION_SUPPORT 0x066 +# define DP_DSC_BLK_PREDICTION_IS_SUPPORTED (1 << 0) + +#define DP_DSC_MAX_BITS_PER_PIXEL_LOW 0x067 /* eDP 1.4 */ + +#define DP_DSC_MAX_BITS_PER_PIXEL_HI 0x068 /* eDP 1.4 */ + +#define DP_DSC_DEC_COLOR_FORMAT_CAP 0x069 +# define DP_DSC_RGB (1 << 0) +# define DP_DSC_YCbCr444 (1 << 1) +# define DP_DSC_YCbCr422_Simple (1 << 2) +# define DP_DSC_YCbCr422_Native (1 << 3) +# define DP_DSC_YCbCr420_Native (1 << 4) + +#define DP_DSC_DEC_COLOR_DEPTH_CAP 0x06A +# define DP_DSC_8_BPC (1 << 1) +# define DP_DSC_10_BPC (1 << 2) +# define DP_DSC_12_BPC (1 << 3) + +#define DP_DSC_PEAK_THROUGHPUT 0x06B +# define DP_DSC_THROUGHPUT_MODE_0_MASK (0xf << 0) +# define DP_DSC_THROUGHPUT_MODE_0_SHIFT 0 +# define DP_DSC_THROUGHPUT_MODE_0_340 (1 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_400 (2 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_450 (3 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_500 (4 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_550 (5 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_600 (6 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_650 (7 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_700 (8 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_750 (9 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_800 (10 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_850 (11 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_900 (12 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_950 (13 << 0) +# define DP_DSC_THROUGHPUT_MODE_0_1000 (14 << 0) +# define DP_DSC_THROUGHPUT_MODE_1_MASK (0xf << 4) +# define DP_DSC_THROUGHPUT_MODE_1_SHIFT 4 +# define DP_DSC_THROUGHPUT_MODE_1_340 (1 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_400 (2 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_450 (3 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_500 (4 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_550 (5 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_600 (6 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_650 (7 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_700 (8 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_750 (9 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_800 (10 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_850 (11 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_900 (12 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_950 (13 << 4) +# define DP_DSC_THROUGHPUT_MODE_1_1000 (14 << 4) + +#define DP_DSC_MAX_SLICE_WIDTH 0x06C + +#define DP_DSC_SLICE_CAP_2 0x06D +# define DP_DSC_16_PER_DP_DSC_SINK (1 << 0) +# define DP_DSC_20_PER_DP_DSC_SINK (1 << 1) +# define DP_DSC_24_PER_DP_DSC_SINK (1 << 2) + +#define DP_DSC_BITS_PER_PIXEL_INC 0x06F +# define DP_DSC_BITS_PER_PIXEL_1_16 0x0 +# define DP_DSC_BITS_PER_PIXEL_1_8 0x1 +# define DP_DSC_BITS_PER_PIXEL_1_4 0x2 +# define DP_DSC_BITS_PER_PIXEL_1_2 0x3 +# define DP_DSC_BITS_PER_PIXEL_1 0x4 + +#define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */ +# define DP_PSR_IS_SUPPORTED 1 +# define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */ +# define DP_PSR2_WITH_Y_COORD_IS_SUPPORTED 3 /* eDP 1.4a */ + +#define DP_PSR_CAPS 0x071 /* XXX 1.2? */ +# define DP_PSR_NO_TRAIN_ON_EXIT 1 +# define DP_PSR_SETUP_TIME_330 (0 << 1) +# define DP_PSR_SETUP_TIME_275 (1 << 1) +# define DP_PSR_SETUP_TIME_220 (2 << 1) +# define DP_PSR_SETUP_TIME_165 (3 << 1) +# define DP_PSR_SETUP_TIME_110 (4 << 1) +# define DP_PSR_SETUP_TIME_55 (5 << 1) +# define DP_PSR_SETUP_TIME_0 (6 << 1) +# define DP_PSR_SETUP_TIME_MASK (7 << 1) +# define DP_PSR_SETUP_TIME_SHIFT 1 +# define DP_PSR2_SU_Y_COORDINATE_REQUIRED (1 << 4) /* eDP 1.4a */ +# define DP_PSR2_SU_GRANULARITY_REQUIRED (1 << 5) /* eDP 1.4b */ +/* + * 0x80-0x8f describe downstream port capabilities, but there are two layouts + * based on whether DP_DETAILED_CAP_INFO_AVAILABLE was set. If it was not, + * each port's descriptor is one byte wide. If it was set, each port's is + * four bytes wide, starting with the one byte from the base info. As of + * DP interop v1.1a only VGA defines additional detail. + */ + +/* offset 0 */ +#define DP_DOWNSTREAM_PORT_0 0x80 +# define DP_DS_PORT_TYPE_MASK (7 << 0) +# define DP_DS_PORT_TYPE_DP 0 +# define DP_DS_PORT_TYPE_VGA 1 +# define DP_DS_PORT_TYPE_DVI 2 +# define DP_DS_PORT_TYPE_HDMI 3 +# define DP_DS_PORT_TYPE_NON_EDID 4 +# define DP_DS_PORT_TYPE_DP_DUALMODE 5 +# define DP_DS_PORT_TYPE_WIRELESS 6 +# define DP_DS_PORT_HPD (1 << 3) +/* offset 1 for VGA is maximum megapixels per second / 8 */ +/* offset 2 */ +# define DP_DS_MAX_BPC_MASK (3 << 0) +# define DP_DS_8BPC 0 +# define DP_DS_10BPC 1 +# define DP_DS_12BPC 2 +# define DP_DS_16BPC 3 + +/* DP Forward error Correction Registers */ +#define DP_FEC_CAPABILITY 0x090 /* 1.4 */ +# define DP_FEC_CAPABLE (1 << 0) +# define DP_FEC_UNCORR_BLK_ERROR_COUNT_CAP (1 << 1) +# define DP_FEC_CORR_BLK_ERROR_COUNT_CAP (1 << 2) +# define DP_FEC_BIT_ERROR_COUNT_CAP (1 << 3) + +/* link configuration */ +#define DP_LINK_BW_SET 0x100 +# define DP_LINK_RATE_TABLE 0x00 /* eDP 1.4 */ +# define DP_LINK_BW_1_62 0x06 +# define DP_LINK_BW_2_7 0x0a +# define DP_LINK_BW_5_4 0x14 /* 1.2 */ +# define DP_LINK_BW_8_1 0x1e /* 1.4 */ + +#define DP_LANE_COUNT_SET 0x101 +# define DP_LANE_COUNT_MASK 0x0f +# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) + +#define DP_TRAINING_PATTERN_SET 0x102 +# define DP_TRAINING_PATTERN_DISABLE 0 +# define DP_TRAINING_PATTERN_1 1 +# define DP_TRAINING_PATTERN_2 2 +# define DP_TRAINING_PATTERN_3 3 /* 1.2 */ +# define DP_TRAINING_PATTERN_4 7 /* 1.4 */ +# define DP_TRAINING_PATTERN_MASK 0x3 +# define DP_TRAINING_PATTERN_MASK_1_4 0xf + +/* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ +# define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) +# define DP_LINK_QUAL_PATTERN_11_D10_2 (1 << 2) +# define DP_LINK_QUAL_PATTERN_11_ERROR_RATE (2 << 2) +# define DP_LINK_QUAL_PATTERN_11_PRBS7 (3 << 2) +# define DP_LINK_QUAL_PATTERN_11_MASK (3 << 2) + +# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) +# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) + +# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) +# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) +# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) +# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) + +#define DP_TRAINING_LANE0_SET 0x103 +#define DP_TRAINING_LANE1_SET 0x104 +#define DP_TRAINING_LANE2_SET 0x105 +#define DP_TRAINING_LANE3_SET 0x106 + +# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 +# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 +# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0) + +# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3) + +# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 +# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + +#define DP_DOWNSPREAD_CTRL 0x107 +# define DP_SPREAD_AMP_0_5 (1 << 4) +# define DP_MSA_TIMING_PAR_IGNORE_EN (1 << 7) /* eDP */ + +#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 +# define DP_SET_ANSI_8B10B (1 << 0) + +#define DP_I2C_SPEED_CONTROL_STATUS 0x109 /* DPI */ +/* bitmask as for DP_I2C_SPEED_CAP */ + +#define DP_EDP_CONFIGURATION_SET 0x10a /* XXX 1.2? */ +# define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE (1 << 0) +# define DP_FRAMING_CHANGE_ENABLE (1 << 1) +# define DP_PANEL_SELF_TEST_ENABLE (1 << 7) + +#define DP_LINK_QUAL_LANE0_SET 0x10b /* DPCD >= 1.2 */ +#define DP_LINK_QUAL_LANE1_SET 0x10c +#define DP_LINK_QUAL_LANE2_SET 0x10d +#define DP_LINK_QUAL_LANE3_SET 0x10e +# define DP_LINK_QUAL_PATTERN_DISABLE 0 +# define DP_LINK_QUAL_PATTERN_D10_2 1 +# define DP_LINK_QUAL_PATTERN_ERROR_RATE 2 +# define DP_LINK_QUAL_PATTERN_PRBS7 3 +# define DP_LINK_QUAL_PATTERN_80BIT_CUSTOM 4 +# define DP_LINK_QUAL_PATTERN_HBR2_EYE 5 +# define DP_LINK_QUAL_PATTERN_MASK 7 + +#define DP_TRAINING_LANE0_1_SET2 0x10f +#define DP_TRAINING_LANE2_3_SET2 0x110 +# define DP_LANE02_POST_CURSOR2_SET_MASK (3 << 0) +# define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2) +# define DP_LANE13_POST_CURSOR2_SET_MASK (3 << 4) +# define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6) + +#define DP_MSTM_CTRL 0x111 /* 1.2 */ +# define DP_MST_EN (1 << 0) +# define DP_UP_REQ_EN (1 << 1) +# define DP_UPSTREAM_IS_SRC (1 << 2) + +#define DP_AUDIO_DELAY0 0x112 /* 1.2 */ +#define DP_AUDIO_DELAY1 0x113 +#define DP_AUDIO_DELAY2 0x114 + +#define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ +# define DP_LINK_RATE_SET_SHIFT 0 +# define DP_LINK_RATE_SET_MASK (7 << 0) + +#define DP_RECEIVER_ALPM_CONFIG 0x116 /* eDP 1.4 */ +# define DP_ALPM_ENABLE (1 << 0) +# define DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE (1 << 1) + +#define DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF 0x117 /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_ENABLE (1 << 0) +# define DP_IRQ_HPD_ENABLE (1 << 1) + +#define DP_UPSTREAM_DEVICE_DP_PWR_NEED 0x118 /* 1.2 */ +# define DP_PWR_NOT_NEEDED (1 << 0) + +#define DP_FEC_CONFIGURATION 0x120 /* 1.4 */ +# define DP_FEC_READY (1 << 0) +# define DP_FEC_ERR_COUNT_SEL_MASK (7 << 1) +# define DP_FEC_ERR_COUNT_DIS (0 << 1) +# define DP_FEC_UNCORR_BLK_ERROR_COUNT (1 << 1) +# define DP_FEC_CORR_BLK_ERROR_COUNT (2 << 1) +# define DP_FEC_BIT_ERROR_COUNT (3 << 1) +# define DP_FEC_LANE_SELECT_MASK (3 << 4) +# define DP_FEC_LANE_0_SELECT (0 << 4) +# define DP_FEC_LANE_1_SELECT (1 << 4) +# define DP_FEC_LANE_2_SELECT (2 << 4) +# define DP_FEC_LANE_3_SELECT (3 << 4) + +#define DP_AUX_FRAME_SYNC_VALUE 0x15c /* eDP 1.4 */ +# define DP_AUX_FRAME_SYNC_VALID (1 << 0) + +#define DP_DSC_ENABLE 0x160 /* DP 1.4 */ + +#define DP_PSR_EN_CFG 0x170 /* XXX 1.2? */ +# define DP_PSR_ENABLE (1 << 0) +# define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) +# define DP_PSR_CRC_VERIFICATION (1 << 2) +# define DP_PSR_FRAME_CAPTURE (1 << 3) +# define DP_PSR_SELECTIVE_UPDATE (1 << 4) +# define DP_PSR_IRQ_HPD_WITH_CRC_ERRORS (1 << 5) +# define DP_PSR_ENABLE_PSR2 (1 << 6) /* eDP 1.4a */ + +#define DP_ADAPTER_CTRL 0x1a0 +# define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) + +#define DP_BRANCH_DEVICE_CTRL 0x1a1 +# define DP_BRANCH_DEVICE_IRQ_HPD (1 << 0) + +#define DP_PAYLOAD_ALLOCATE_SET 0x1c0 +#define DP_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x1c1 +#define DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x1c2 + +#define DP_SINK_COUNT 0x200 +/* prior to 1.2 bit 7 was reserved mbz */ +# define DP_GET_SINK_COUNT(x) ((((x) & 0x80) >> 1) | ((x) & 0x3f)) +# define DP_SINK_CP_READY (1 << 6) + +#define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201 +# define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0) +# define DP_AUTOMATED_TEST_REQUEST (1 << 1) +# define DP_CP_IRQ (1 << 2) +# define DP_MCCS_IRQ (1 << 3) +# define DP_DOWN_REP_MSG_RDY (1 << 4) /* 1.2 MST */ +# define DP_UP_REQ_MSG_RDY (1 << 5) /* 1.2 MST */ +# define DP_SINK_SPECIFIC_IRQ (1 << 6) + +#define DP_LANE0_1_STATUS 0x202 +#define DP_LANE2_3_STATUS 0x203 +# define DP_LANE_CR_DONE (1 << 0) +# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) +# define DP_LANE_SYMBOL_LOCKED (1 << 2) + +#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \ + DP_LANE_CHANNEL_EQ_DONE | \ + DP_LANE_SYMBOL_LOCKED) + +#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 + +#define DP_INTERLANE_ALIGN_DONE (1 << 0) +#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) +#define DP_LINK_STATUS_UPDATED (1 << 7) + +#define DP_SINK_STATUS 0x205 + +#define DP_RECEIVE_PORT_0_STATUS (1 << 0) +#define DP_RECEIVE_PORT_1_STATUS (1 << 1) + +#define DP_ADJUST_REQUEST_LANE0_1 0x206 +#define DP_ADJUST_REQUEST_LANE2_3 0x207 +# define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 +# define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 +# define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c +# define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 +# define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 +# define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 +# define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 +# define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 + +#define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c + +#define DP_TEST_REQUEST 0x218 +# define DP_TEST_LINK_TRAINING (1 << 0) +# define DP_TEST_LINK_VIDEO_PATTERN (1 << 1) +# define DP_TEST_LINK_EDID_READ (1 << 2) +# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ +# define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ + +#define DP_TEST_LINK_RATE 0x219 +# define DP_LINK_RATE_162 (0x6) +# define DP_LINK_RATE_27 (0xa) + +#define DP_TEST_LANE_COUNT 0x220 + +#define DP_TEST_PATTERN 0x221 +# define DP_NO_TEST_PATTERN 0x0 +# define DP_COLOR_RAMP 0x1 +# define DP_BLACK_AND_WHITE_VERTICAL_LINES 0x2 +# define DP_COLOR_SQUARE 0x3 + +#define DP_TEST_H_TOTAL_HI 0x222 +#define DP_TEST_H_TOTAL_LO 0x223 + +#define DP_TEST_V_TOTAL_HI 0x224 +#define DP_TEST_V_TOTAL_LO 0x225 + +#define DP_TEST_H_START_HI 0x226 +#define DP_TEST_H_START_LO 0x227 + +#define DP_TEST_V_START_HI 0x228 +#define DP_TEST_V_START_LO 0x229 + +#define DP_TEST_HSYNC_HI 0x22A +# define DP_TEST_HSYNC_POLARITY (1 << 7) +# define DP_TEST_HSYNC_WIDTH_HI_MASK (127 << 0) +#define DP_TEST_HSYNC_WIDTH_LO 0x22B + +#define DP_TEST_VSYNC_HI 0x22C +# define DP_TEST_VSYNC_POLARITY (1 << 7) +# define DP_TEST_VSYNC_WIDTH_HI_MASK (127 << 0) +#define DP_TEST_VSYNC_WIDTH_LO 0x22D + +#define DP_TEST_H_WIDTH_HI 0x22E +#define DP_TEST_H_WIDTH_LO 0x22F + +#define DP_TEST_V_HEIGHT_HI 0x230 +#define DP_TEST_V_HEIGHT_LO 0x231 + +#define DP_TEST_MISC0 0x232 +# define DP_TEST_SYNC_CLOCK (1 << 0) +# define DP_TEST_COLOR_FORMAT_MASK (3 << 1) +# define DP_TEST_COLOR_FORMAT_SHIFT 1 +# define DP_COLOR_FORMAT_RGB (0 << 1) +# define DP_COLOR_FORMAT_YCbCr422 (1 << 1) +# define DP_COLOR_FORMAT_YCbCr444 (2 << 1) +# define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3) +# define DP_TEST_YCBCR_COEFFICIENTS (1 << 4) +# define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4) +# define DP_YCBCR_COEFFICIENTS_ITU709 (1 << 4) +# define DP_TEST_BIT_DEPTH_MASK (7 << 5) +# define DP_TEST_BIT_DEPTH_SHIFT 5 +# define DP_TEST_BIT_DEPTH_6 (0 << 5) +# define DP_TEST_BIT_DEPTH_8 (1 << 5) +# define DP_TEST_BIT_DEPTH_10 (2 << 5) +# define DP_TEST_BIT_DEPTH_12 (3 << 5) +# define DP_TEST_BIT_DEPTH_16 (4 << 5) + +#define DP_TEST_MISC1 0x233 +# define DP_TEST_REFRESH_DENOMINATOR (1 << 0) +# define DP_TEST_INTERLACED (1 << 1) + +#define DP_TEST_REFRESH_RATE_NUMERATOR 0x234 + +#define DP_TEST_MISC0 0x232 + +#define DP_TEST_CRC_R_CR 0x240 +#define DP_TEST_CRC_G_Y 0x242 +#define DP_TEST_CRC_B_CB 0x244 + +#define DP_TEST_SINK_MISC 0x246 +# define DP_TEST_CRC_SUPPORTED (1 << 5) +# define DP_TEST_COUNT_MASK 0xf + +#define DP_TEST_PHY_PATTERN 0x248 +# define DP_TEST_PHY_PATTERN_NONE 0x0 +# define DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING 0x1 +# define DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT 0x2 +# define DP_TEST_PHY_PATTERN_PRBS7 0x3 +# define DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN 0x4 +# define DP_TEST_PHY_PATTERN_CP2520_PATTERN_1 0x5 +# define DP_TEST_PHY_PATTERN_CP2520_PATTERN_2 0x6 +# define DP_TEST_PHY_PATTERN_CP2520_PATTERN_3 0x7 +#define DP_TEST_80BIT_CUSTOM_PATTERN_7_0 0x250 +#define DP_TEST_80BIT_CUSTOM_PATTERN_15_8 0x251 +#define DP_TEST_80BIT_CUSTOM_PATTERN_23_16 0x252 +#define DP_TEST_80BIT_CUSTOM_PATTERN_31_24 0x253 +#define DP_TEST_80BIT_CUSTOM_PATTERN_39_32 0x254 +#define DP_TEST_80BIT_CUSTOM_PATTERN_47_40 0x255 +#define DP_TEST_80BIT_CUSTOM_PATTERN_55_48 0x256 +#define DP_TEST_80BIT_CUSTOM_PATTERN_63_56 0x257 +#define DP_TEST_80BIT_CUSTOM_PATTERN_71_64 0x258 +#define DP_TEST_80BIT_CUSTOM_PATTERN_79_72 0x259 + +#define DP_TEST_RESPONSE 0x260 +# define DP_TEST_ACK (1 << 0) +# define DP_TEST_NAK (1 << 1) +# define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) + +#define DP_TEST_EDID_CHECKSUM 0x261 + +#define DP_TEST_SINK 0x270 +# define DP_TEST_SINK_START (1 << 0) + +#define DP_FEC_STATUS 0x280 /* 1.4 */ +# define DP_FEC_DECODE_EN_DETECTED (1 << 0) +# define DP_FEC_DECODE_DIS_DETECTED (1 << 1) + +#define DP_FEC_ERROR_COUNT_LSB 0x0281 /* 1.4 */ + +#define DP_FEC_ERROR_COUNT_MSB 0x0282 /* 1.4 */ +# define DP_FEC_ERROR_COUNT_MASK 0x7F +# define DP_FEC_ERR_COUNT_VALID (1 << 7) + +#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */ +# define DP_PAYLOAD_TABLE_UPDATED (1 << 0) +# define DP_PAYLOAD_ACT_HANDLED (1 << 1) + +#define DP_VC_PAYLOAD_ID_SLOT_1 0x2c1 /* 1.2 MST */ +/* up to ID_SLOT_63 at 0x2ff */ + +#define DP_SOURCE_OUI 0x300 +#define DP_SINK_OUI 0x400 +#define DP_BRANCH_OUI 0x500 +#define DP_BRANCH_ID 0x503 +#define DP_BRANCH_REVISION_START 0x509 +#define DP_BRANCH_HW_REV 0x509 +#define DP_BRANCH_SW_REV 0x50A + +#define DP_SET_POWER 0x600 +# define DP_SET_POWER_D0 0x1 +# define DP_SET_POWER_D3 0x2 +# define DP_SET_POWER_MASK 0x3 +# define DP_SET_POWER_D3_AUX_ON 0x5 + +#define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ +# define DP_EDP_11 0x00 +# define DP_EDP_12 0x01 +# define DP_EDP_13 0x02 +# define DP_EDP_14 0x03 + +#define DP_EDP_GENERAL_CAP_1 0x701 +# define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0) +# define DP_EDP_BACKLIGHT_PIN_ENABLE_CAP (1 << 1) +# define DP_EDP_BACKLIGHT_AUX_ENABLE_CAP (1 << 2) +# define DP_EDP_PANEL_SELF_TEST_PIN_ENABLE_CAP (1 << 3) +# define DP_EDP_PANEL_SELF_TEST_AUX_ENABLE_CAP (1 << 4) +# define DP_EDP_FRC_ENABLE_CAP (1 << 5) +# define DP_EDP_COLOR_ENGINE_CAP (1 << 6) +# define DP_EDP_SET_POWER_CAP (1 << 7) + +#define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP 0x702 +# define DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP (1 << 0) +# define DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP (1 << 1) +# define DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT (1 << 2) +# define DP_EDP_BACKLIGHT_AUX_PWM_PRODUCT_CAP (1 << 3) +# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_CAP (1 << 4) +# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP (1 << 5) +# define DP_EDP_DYNAMIC_BACKLIGHT_CAP (1 << 6) +# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_CAP (1 << 7) + +#define DP_EDP_GENERAL_CAP_2 0x703 +# define DP_EDP_OVERDRIVE_ENGINE_ENABLED (1 << 0) + +#define DP_EDP_GENERAL_CAP_3 0x704 /* eDP 1.4 */ +# define DP_EDP_X_REGION_CAP_MASK (0xf << 0) +# define DP_EDP_X_REGION_CAP_SHIFT 0 +# define DP_EDP_Y_REGION_CAP_MASK (0xf << 4) +# define DP_EDP_Y_REGION_CAP_SHIFT 4 + +#define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720 +# define DP_EDP_BACKLIGHT_ENABLE (1 << 0) +# define DP_EDP_BLACK_VIDEO_ENABLE (1 << 1) +# define DP_EDP_FRC_ENABLE (1 << 2) +# define DP_EDP_COLOR_ENGINE_ENABLE (1 << 3) +# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_ENABLE (1 << 7) + +#define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721 +# define DP_EDP_BACKLIGHT_CONTROL_MODE_MASK (3 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PWM (0 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET (1 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD (2 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT (3 << 0) +# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_ENABLE (1 << 2) +# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE (1 << 3) +# define DP_EDP_DYNAMIC_BACKLIGHT_ENABLE (1 << 4) +# define DP_EDP_REGIONAL_BACKLIGHT_ENABLE (1 << 5) +# define DP_EDP_UPDATE_REGION_BRIGHTNESS (1 << 6) /* eDP 1.4 */ + +#define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB 0x722 +#define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB 0x723 + +#define DP_EDP_PWMGEN_BIT_COUNT 0x724 +#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MIN 0x725 +#define DP_EDP_PWMGEN_BIT_COUNT_CAP_MAX 0x726 +# define DP_EDP_PWMGEN_BIT_COUNT_MASK (0x1f << 0) + +#define DP_EDP_BACKLIGHT_CONTROL_STATUS 0x727 + +#define DP_EDP_BACKLIGHT_FREQ_SET 0x728 +# define DP_EDP_BACKLIGHT_FREQ_BASE_KHZ 27000 + +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MSB 0x72a +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_MID 0x72b +#define DP_EDP_BACKLIGHT_FREQ_CAP_MIN_LSB 0x72c + +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MSB 0x72d +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_MID 0x72e +#define DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB 0x72f + +#define DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET 0x732 +#define DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET 0x733 + +#define DP_EDP_REGIONAL_BACKLIGHT_BASE 0x740 /* eDP 1.4 */ +#define DP_EDP_REGIONAL_BACKLIGHT_0 0x741 /* eDP 1.4 */ + +#define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400 /* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ + +#define DP_SINK_COUNT_ESI 0x2002 /* 1.2 */ +/* 0-5 sink count */ +# define DP_SINK_COUNT_CP_READY (1 << 6) + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ +# define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) +# define DP_LOCK_ACQUISITION_REQUEST (1 << 1) +# define DP_CEC_IRQ (1 << 2) + +#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 /* 1.2 */ + +#define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */ +# define DP_PSR_LINK_CRC_ERROR (1 << 0) +# define DP_PSR_RFB_STORAGE_ERROR (1 << 1) +# define DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR (1 << 2) /* eDP 1.4 */ + +#define DP_PSR_ESI 0x2007 /* XXX 1.2? */ +# define DP_PSR_CAPS_CHANGE (1 << 0) + +#define DP_PSR_STATUS 0x2008 /* XXX 1.2? */ +# define DP_PSR_SINK_INACTIVE 0 +# define DP_PSR_SINK_ACTIVE_SRC_SYNCED 1 +# define DP_PSR_SINK_ACTIVE_RFB 2 +# define DP_PSR_SINK_ACTIVE_SINK_SYNCED 3 +# define DP_PSR_SINK_ACTIVE_RESYNC 4 +# define DP_PSR_SINK_INTERNAL_ERROR 7 +# define DP_PSR_SINK_STATE_MASK 0x07 + +#define DP_SYNCHRONIZATION_LATENCY_IN_SINK 0x2009 /* edp 1.4 */ +# define DP_MAX_RESYNC_FRAME_COUNT_MASK (0xf << 0) +# define DP_MAX_RESYNC_FRAME_COUNT_SHIFT 0 +# define DP_LAST_ACTUAL_SYNCHRONIZATION_LATENCY_MASK (0xf << 4) +# define DP_LAST_ACTUAL_SYNCHRONIZATION_LATENCY_SHIFT 4 + +#define DP_LAST_RECEIVED_PSR_SDP 0x200a /* eDP 1.2 */ +# define DP_PSR_STATE_BIT (1 << 0) /* eDP 1.2 */ +# define DP_UPDATE_RFB_BIT (1 << 1) /* eDP 1.2 */ +# define DP_CRC_VALID_BIT (1 << 2) /* eDP 1.2 */ +# define DP_SU_VALID (1 << 3) /* eDP 1.4 */ +# define DP_FIRST_SCAN_LINE_SU_REGION (1 << 4) /* eDP 1.4 */ +# define DP_LAST_SCAN_LINE_SU_REGION (1 << 5) /* eDP 1.4 */ +# define DP_Y_COORDINATE_VALID (1 << 6) /* eDP 1.4a */ + +#define DP_RECEIVER_ALPM_STATUS 0x200b /* eDP 1.4 */ +# define DP_ALPM_LOCK_TIMEOUT_ERROR (1 << 0) + +#define DP_LANE0_1_STATUS_ESI 0x200c /* status same as 0x202 */ +#define DP_LANE2_3_STATUS_ESI 0x200d /* status same as 0x203 */ +#define DP_LANE_ALIGN_STATUS_UPDATED_ESI 0x200e /* status same as 0x204 */ +#define DP_SINK_STATUS_ESI 0x200f /* status same as 0x205 */ + +#define DP_DP13_DPCD_REV 0x2200 +#define DP_DP13_MAX_LINK_RATE 0x2201 + +#define DP_DPRX_FEATURE_ENUMERATION_LIST 0x2210 /* DP 1.3 */ +# define DP_GTC_CAP (1 << 0) /* DP 1.3 */ +# define DP_SST_SPLIT_SDP_CAP (1 << 1) /* DP 1.4 */ +# define DP_AV_SYNC_CAP (1 << 2) /* DP 1.3 */ +# define DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED (1 << 3) /* DP 1.3 */ +# define DP_VSC_EXT_VESA_SDP_SUPPORTED (1 << 4) /* DP 1.4 */ +# define DP_VSC_EXT_VESA_SDP_CHAINING_SUPPORTED (1 << 5) /* DP 1.4 */ +# define DP_VSC_EXT_CEA_SDP_SUPPORTED (1 << 6) /* DP 1.4 */ +# define DP_VSC_EXT_CEA_SDP_CHAINING_SUPPORTED (1 << 7) /* DP 1.4 */ + +/* HDMI CEC tunneling over AUX DP 1.3 section 5.3.3.3.1 DPCD 1.4+ */ +#define DP_CEC_TUNNELING_CAPABILITY 0x3000 +# define DP_CEC_TUNNELING_CAPABLE (1 << 0) +# define DP_CEC_SNOOPING_CAPABLE (1 << 1) +# define DP_CEC_MULTIPLE_LA_CAPABLE (1 << 2) + +#define DP_CEC_TUNNELING_CONTROL 0x3001 +# define DP_CEC_TUNNELING_ENABLE (1 << 0) +# define DP_CEC_SNOOPING_ENABLE (1 << 1) + +#define DP_CEC_RX_MESSAGE_INFO 0x3002 +# define DP_CEC_RX_MESSAGE_LEN_MASK (0xf << 0) +# define DP_CEC_RX_MESSAGE_LEN_SHIFT 0 +# define DP_CEC_RX_MESSAGE_HPD_STATE (1 << 4) +# define DP_CEC_RX_MESSAGE_HPD_LOST (1 << 5) +# define DP_CEC_RX_MESSAGE_ACKED (1 << 6) +# define DP_CEC_RX_MESSAGE_ENDED (1 << 7) + +#define DP_CEC_TX_MESSAGE_INFO 0x3003 +# define DP_CEC_TX_MESSAGE_LEN_MASK (0xf << 0) +# define DP_CEC_TX_MESSAGE_LEN_SHIFT 0 +# define DP_CEC_TX_RETRY_COUNT_MASK (0x7 << 4) +# define DP_CEC_TX_RETRY_COUNT_SHIFT 4 +# define DP_CEC_TX_MESSAGE_SEND (1 << 7) + +#define DP_CEC_TUNNELING_IRQ_FLAGS 0x3004 +# define DP_CEC_RX_MESSAGE_INFO_VALID (1 << 0) +# define DP_CEC_RX_MESSAGE_OVERFLOW (1 << 1) +# define DP_CEC_TX_MESSAGE_SENT (1 << 4) +# define DP_CEC_TX_LINE_ERROR (1 << 5) +# define DP_CEC_TX_ADDRESS_NACK_ERROR (1 << 6) +# define DP_CEC_TX_DATA_NACK_ERROR (1 << 7) + +#define DP_CEC_LOGICAL_ADDRESS_MASK 0x300E /* 0x300F word */ +# define DP_CEC_LOGICAL_ADDRESS_0 (1 << 0) +# define DP_CEC_LOGICAL_ADDRESS_1 (1 << 1) +# define DP_CEC_LOGICAL_ADDRESS_2 (1 << 2) +# define DP_CEC_LOGICAL_ADDRESS_3 (1 << 3) +# define DP_CEC_LOGICAL_ADDRESS_4 (1 << 4) +# define DP_CEC_LOGICAL_ADDRESS_5 (1 << 5) +# define DP_CEC_LOGICAL_ADDRESS_6 (1 << 6) +# define DP_CEC_LOGICAL_ADDRESS_7 (1 << 7) +#define DP_CEC_LOGICAL_ADDRESS_MASK_2 0x300F /* 0x300E word */ +# define DP_CEC_LOGICAL_ADDRESS_8 (1 << 0) +# define DP_CEC_LOGICAL_ADDRESS_9 (1 << 1) +# define DP_CEC_LOGICAL_ADDRESS_10 (1 << 2) +# define DP_CEC_LOGICAL_ADDRESS_11 (1 << 3) +# define DP_CEC_LOGICAL_ADDRESS_12 (1 << 4) +# define DP_CEC_LOGICAL_ADDRESS_13 (1 << 5) +# define DP_CEC_LOGICAL_ADDRESS_14 (1 << 6) +# define DP_CEC_LOGICAL_ADDRESS_15 (1 << 7) + +#define DP_CEC_RX_MESSAGE_BUFFER 0x3010 +#define DP_CEC_TX_MESSAGE_BUFFER 0x3020 +#define DP_CEC_MESSAGE_BUFFER_LENGTH 0x10 + +#define DP_AUX_HDCP_BKSV 0x68000 +#define DP_AUX_HDCP_RI_PRIME 0x68005 +#define DP_AUX_HDCP_AKSV 0x68007 +#define DP_AUX_HDCP_AN 0x6800C +#define DP_AUX_HDCP_V_PRIME(h) (0x68014 + (h) * 4) +#define DP_AUX_HDCP_BCAPS 0x68028 +# define DP_BCAPS_REPEATER_PRESENT BIT(1) +# define DP_BCAPS_HDCP_CAPABLE BIT(0) +#define DP_AUX_HDCP_BSTATUS 0x68029 +# define DP_BSTATUS_REAUTH_REQ BIT(3) +# define DP_BSTATUS_LINK_FAILURE BIT(2) +# define DP_BSTATUS_R0_PRIME_READY BIT(1) +# define DP_BSTATUS_READY BIT(0) +#define DP_AUX_HDCP_BINFO 0x6802A +#define DP_AUX_HDCP_KSV_FIFO 0x6802C +#define DP_AUX_HDCP_AINFO 0x6803B + +/* DP 1.2 Sideband message defines */ +/* peer device type - DP 1.2a Table 2-92 */ +#define DP_PEER_DEVICE_NONE 0x0 +#define DP_PEER_DEVICE_SOURCE_OR_SST 0x1 +#define DP_PEER_DEVICE_MST_BRANCHING 0x2 +#define DP_PEER_DEVICE_SST_SINK 0x3 +#define DP_PEER_DEVICE_DP_LEGACY_CONV 0x4 + +/* DP 1.2 MST sideband request names DP 1.2a Table 2-80 */ +#define DP_LINK_ADDRESS 0x01 +#define DP_CONNECTION_STATUS_NOTIFY 0x02 +#define DP_ENUM_PATH_RESOURCES 0x10 +#define DP_ALLOCATE_PAYLOAD 0x11 +#define DP_QUERY_PAYLOAD 0x12 +#define DP_RESOURCE_STATUS_NOTIFY 0x13 +#define DP_CLEAR_PAYLOAD_ID_TABLE 0x14 +#define DP_REMOTE_DPCD_READ 0x20 +#define DP_REMOTE_DPCD_WRITE 0x21 +#define DP_REMOTE_I2C_READ 0x22 +#define DP_REMOTE_I2C_WRITE 0x23 +#define DP_POWER_UP_PHY 0x24 +#define DP_POWER_DOWN_PHY 0x25 +#define DP_SINK_EVENT_NOTIFY 0x30 +#define DP_QUERY_STREAM_ENC_STATUS 0x38 + +/* DP 1.2 MST sideband nak reasons - table 2.84 */ +#define DP_NAK_WRITE_FAILURE 0x01 +#define DP_NAK_INVALID_READ 0x02 +#define DP_NAK_CRC_FAILURE 0x03 +#define DP_NAK_BAD_PARAM 0x04 +#define DP_NAK_DEFER 0x05 +#define DP_NAK_LINK_FAILURE 0x06 +#define DP_NAK_NO_RESOURCES 0x07 +#define DP_NAK_DPCD_FAIL 0x08 +#define DP_NAK_I2C_NAK 0x09 +#define DP_NAK_ALLOCATE_FAIL 0x0a + +#define MODE_I2C_START 1 +#define MODE_I2C_WRITE 2 +#define MODE_I2C_READ 4 +#define MODE_I2C_STOP 8 + +/* DP 1.2 MST PORTs - Section 2.5.1 v1.2a spec */ +#define DP_MST_PHYSICAL_PORT_0 0 +#define DP_MST_LOGICAL_PORT_0 8 + +#define DP_LINK_STATUS_SIZE 6 +bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count); +bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count); +u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); +u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane); + +#define DP_BRANCH_OUI_HEADER_SIZE 0xc +#define DP_RECEIVER_CAP_SIZE 0xf +#define EDP_PSR_RECEIVER_CAP_SIZE 2 +#define EDP_DISPLAY_CTL_CAP_SIZE 3 + +void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]); +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]); + +u8 drm_dp_link_rate_to_bw_code(int link_rate); +int drm_dp_bw_code_to_link_rate(u8 link_bw); + +#define DP_SDP_AUDIO_TIMESTAMP 0x01 +#define DP_SDP_AUDIO_STREAM 0x02 +#define DP_SDP_EXTENSION 0x04 /* DP 1.1 */ +#define DP_SDP_AUDIO_COPYMANAGEMENT 0x05 /* DP 1.2 */ +#define DP_SDP_ISRC 0x06 /* DP 1.2 */ +#define DP_SDP_VSC 0x07 /* DP 1.2 */ +#define DP_SDP_CAMERA_GENERIC(i) (0x08 + (i)) /* 0-7, DP 1.3 */ +#define DP_SDP_PPS 0x10 /* DP 1.4 */ +#define DP_SDP_VSC_EXT_VESA 0x20 /* DP 1.4 */ +#define DP_SDP_VSC_EXT_CEA 0x21 /* DP 1.4 */ +/* 0x80+ CEA-861 infoframe types */ + +#pragma pack(1) +struct dp_sdp_header { + u8 HB0; /* Secondary Data Packet ID */ + u8 HB1; /* Secondary Data Packet Type */ + u8 HB2; /* Secondary Data Packet Specific header, Byte 0 */ + u8 HB3; /* Secondary Data packet Specific header, Byte 1 */ +}; +#pragma pack() + +#define EDP_SDP_HEADER_REVISION_MASK 0x1F +#define EDP_SDP_HEADER_VALID_PAYLOAD_BYTES 0x1F +#define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F + +#pragma pack(1) +struct edp_vsc_psr { + struct dp_sdp_header sdp_header; + u8 DB0; /* Stereo Interface */ + u8 DB1; /* 0 - PSR State; 1 - Update RFB; 2 - CRC Valid */ + u8 DB2; /* CRC value bits 7:0 of the R or Cr component */ + u8 DB3; /* CRC value bits 15:8 of the R or Cr component */ + u8 DB4; /* CRC value bits 7:0 of the G or Y component */ + u8 DB5; /* CRC value bits 15:8 of the G or Y component */ + u8 DB6; /* CRC value bits 7:0 of the B or Cb component */ + u8 DB7; /* CRC value bits 15:8 of the B or Cb component */ + u8 DB8_31[24]; /* Reserved */ +}; +#pragma pack() + +#define EDP_VSC_PSR_STATE_ACTIVE (1 << 0) +#define EDP_VSC_PSR_UPDATE_RFB (1 << 1) +#define EDP_VSC_PSR_CRC_VALUES_VALID (1 << 2) + +enum dp_pixelformat { + DP_PIXELFORMAT_RGB = 0, + DP_PIXELFORMAT_YUV444 = 0x1, + DP_PIXELFORMAT_YUV422 = 0x2, + DP_PIXELFORMAT_YUV420 = 0x3, + DP_PIXELFORMAT_Y_ONLY = 0x4, + DP_PIXELFORMAT_RAW = 0x5, + DP_PIXELFORMAT_RESERVED = 0x6, +}; + +enum dp_colorimetry { + DP_COLORIMETRY_DEFAULT = 0, + DP_COLORIMETRY_RGB_WIDE_FIXED = 0x1, + DP_COLORIMETRY_BT709_YCC = 0x1, + DP_COLORIMETRY_RGB_WIDE_FLOAT = 0x2, + DP_COLORIMETRY_XVYCC_601 = 0x2, + DP_COLORIMETRY_OPRGB = 0x3, + DP_COLORIMETRY_XVYCC_709 = 0x3, + DP_COLORIMETRY_DCI_P3_RGB = 0x4, + DP_COLORIMETRY_SYCC_601 = 0x4, + DP_COLORIMETRY_RGB_CUSTOM = 0x5, + DP_COLORIMETRY_OPYCC_601 = 0x5, + DP_COLORIMETRY_BT2020_RGB = 0x6, + DP_COLORIMETRY_BT2020_CYCC = 0x6, + DP_COLORIMETRY_BT2020_YCC = 0x7, +}; + +enum dp_dynamic_range { + DP_DYNAMIC_RANGE_VESA = 0, + DP_DYNAMIC_RANGE_CTA = 1, +}; + +enum dp_content_type { + DP_CONTENT_TYPE_NOT_DEFINED = 0x00, + DP_CONTENT_TYPE_GRAPHICS = 0x01, + DP_CONTENT_TYPE_PHOTO = 0x02, + DP_CONTENT_TYPE_VIDEO = 0x03, + DP_CONTENT_TYPE_GAME = 0x04, +}; + +struct drm_dp_vsc_sdp { + unsigned char sdp_type; + unsigned char revision; + unsigned char length; + enum dp_pixelformat pixelformat; + enum dp_colorimetry colorimetry; + int bpc; + enum dp_dynamic_range dynamic_range; + enum dp_content_type content_type; +}; + +static inline int +drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]); +} + +static inline u8 +drm_dp_max_lane_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; +} + +static inline bool +drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); +} + +static inline bool +drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x12 && + dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED; +} + +static inline bool +drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x14 && + dpcd[DP_MAX_DOWNSPREAD] & DP_TPS4_SUPPORTED; +} + +static inline u8 +drm_dp_training_pattern_mask(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return (dpcd[DP_DPCD_REV] >= 0x14) ? DP_TRAINING_PATTERN_MASK_1_4 : + DP_TRAINING_PATTERN_MASK; +} + +static inline bool +drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT; +} + +static inline bool +drm_dp_channel_coding_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_8B10B; +} + +struct drm_dp_aux_msg { + unsigned int address; + u8 request; + u8 reply; + void *buffer; + size_t size; +}; + +struct drm_dp_aux { + const char *name; + ssize_t (*transfer)(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg); + unsigned int i2c_nack_count; + unsigned int i2c_defer_count; +}; + +ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size); +ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size); + +/** + * drm_dp_dpcd_readb() - read a single byte from the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to read + * @valuep: location where the value of the register will be stored + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. + */ +static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, + unsigned int offset, u8 *valuep) +{ + return drm_dp_dpcd_read(aux, offset, valuep, 1); +} + +/** + * drm_dp_dpcd_writeb() - write a single byte to the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to write + * @value: value to write to the register + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. + */ +static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux, + unsigned int offset, u8 value) +{ + return drm_dp_dpcd_write(aux, offset, &value, 1); +} + +int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]); + +int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, + u8 status[DP_LINK_STATUS_SIZE]); + +#endif /* _DRM_DP_HELPER_H_ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dsc.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dsc.h new file mode 100644 index 0000000..3cb6eb9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_dsc.h @@ -0,0 +1,613 @@ +/* SPDX-License-Identifier: MIT + * Copyright (C) 2018 Intel Corp. + * + * Authors: + * Manasi Navare + */ + +#ifndef DRM_DSC_H_ +#define DRM_DSC_H_ + +#include + +/* VESA Display Stream Compression DSC 1.2 constants */ +#define DSC_NUM_BUF_RANGES 15 +#define DSC_MUX_WORD_SIZE_8_10_BPC 48 +#define DSC_MUX_WORD_SIZE_12_BPC 64 +#define DSC_RC_PIXELS_PER_GROUP 3 +#define DSC_SCALE_DECREMENT_INTERVAL_MAX 4095 +#define DSC_RANGE_BPG_OFFSET_MASK 0x3f + +/* DSC Rate Control Constants */ +#define DSC_RC_MODEL_SIZE_CONST 8192 +#define DSC_RC_EDGE_FACTOR_CONST 6 +#define DSC_RC_TGT_OFFSET_HI_CONST 3 +#define DSC_RC_TGT_OFFSET_LO_CONST 3 + +/* DSC PPS constants and macros */ +#define DSC_PPS_VERSION_MAJOR_SHIFT 4 +#define DSC_PPS_BPC_SHIFT 4 +#define DSC_PPS_MSB_SHIFT 8 +#define DSC_PPS_LSB_MASK (0xFF << 0) +#define DSC_PPS_BPP_HIGH_MASK (0x3 << 8) +#define DSC_PPS_VBR_EN_SHIFT 2 +#define DSC_PPS_SIMPLE422_SHIFT 3 +#define DSC_PPS_CONVERT_RGB_SHIFT 4 +#define DSC_PPS_BLOCK_PRED_EN_SHIFT 5 +#define DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK (0x3 << 8) +#define DSC_PPS_SCALE_DEC_INT_HIGH_MASK (0xF << 8) +#define DSC_PPS_RC_TGT_OFFSET_HI_SHIFT 4 +#define DSC_PPS_RC_RANGE_MINQP_SHIFT 11 +#define DSC_PPS_RC_RANGE_MAXQP_SHIFT 6 +#define DSC_PPS_NATIVE_420_SHIFT 1 +#define DSC_1_2_MAX_LINEBUF_DEPTH_BITS 16 +#define DSC_1_2_MAX_LINEBUF_DEPTH_VAL 0 +#define DSC_1_1_MAX_LINEBUF_DEPTH_BITS 13 + +/** + * struct drm_dsc_rc_range_parameters - DSC Rate Control range parameters + * + * This defines different rate control parameters used by the DSC engine + * to compress the frame. + */ +struct drm_dsc_rc_range_parameters { + /** + * @range_min_qp: Min Quantization Parameters allowed for this range + */ + u8 range_min_qp; + /** + * @range_max_qp: Max Quantization Parameters allowed for this range + */ + u8 range_max_qp; + /** + * @range_bpg_offset: + * Bits/group offset to apply to target for this group + */ + u8 range_bpg_offset; +}; + +/** + * struct drm_dsc_config - Parameters required to configure DSC + * + * Driver populates this structure with all the parameters required + * to configure the display stream compression on the source. + */ +struct drm_dsc_config { + /** + * @line_buf_depth: + * Bits per component for previous reconstructed line buffer + */ + u8 line_buf_depth; + /** + * @bits_per_component: Bits per component to code (8/10/12) + */ + u8 bits_per_component; + /** + * @convert_rgb: + * Flag to indicate if RGB - YCoCg conversion is needed + * True if RGB input, False if YCoCg input + */ + bool convert_rgb; + /** + * @slice_count: Number of slices per line used by the DSC encoder + */ + u8 slice_count; + /** + * @slice_width: Width of each slice in pixels + */ + u16 slice_width; + /** + * @slice_height: Slice height in pixels + */ + u16 slice_height; + /** + * @simple_422: True if simple 4_2_2 mode is enabled else False + */ + bool simple_422; + /** + * @pic_width: Width of the input display frame in pixels + */ + u16 pic_width; + /** + * @pic_height: Vertical height of the input display frame + */ + u16 pic_height; + /** + * @rc_tgt_offset_high: + * Offset to bits/group used by RC to determine QP adjustment + */ + u8 rc_tgt_offset_high; + /** + * @rc_tgt_offset_low: + * Offset to bits/group used by RC to determine QP adjustment + */ + u8 rc_tgt_offset_low; + /** + * @bits_per_pixel: + * Target bits per pixel with 4 fractional bits, bits_per_pixel << 4 + */ + u16 bits_per_pixel; + /** + * @rc_edge_factor: + * Factor to determine if an edge is present based on the bits produced + */ + u8 rc_edge_factor; + /** + * @rc_quant_incr_limit1: + * Slow down incrementing once the range reaches this value + */ + u8 rc_quant_incr_limit1; + /** + * @rc_quant_incr_limit0: + * Slow down incrementing once the range reaches this value + */ + u8 rc_quant_incr_limit0; + /** + * @initial_xmit_delay: + * Number of pixels to delay the initial transmission + */ + u16 initial_xmit_delay; + /** + * @initial_dec_delay: + * Initial decoder delay, number of pixel times that the decoder + * accumulates data in its rate buffer before starting to decode + * and output pixels. + */ + u16 initial_dec_delay; + /** + * @block_pred_enable: + * True if block prediction is used to code any groups within the + * picture. False if BP not used + */ + bool block_pred_enable; + /** + * @first_line_bpg_offset: + * Number of additional bits allocated for each group on the first + * line of slice. + */ + u8 first_line_bpg_offset; + /** + * @initial_offset: Value to use for RC model offset at slice start + */ + u16 initial_offset; + /** + * @rc_buf_thresh: Thresholds defining each of the buffer ranges + */ + u16 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1]; + /** + * @rc_range_params: + * Parameters for each of the RC ranges defined in + * &struct drm_dsc_rc_range_parameters + */ + struct drm_dsc_rc_range_parameters rc_range_params[DSC_NUM_BUF_RANGES]; + /** + * @rc_model_size: Total size of RC model + */ + u16 rc_model_size; + /** + * @flatness_min_qp: Minimum QP where flatness information is sent + */ + u8 flatness_min_qp; + /** + * @flatness_max_qp: Maximum QP where flatness information is sent + */ + u8 flatness_max_qp; + /** + * @initial_scale_value: Initial value for the scale factor + */ + u8 initial_scale_value; + /** + * @scale_decrement_interval: + * Specifies number of group times between decrementing the scale factor + * at beginning of a slice. + */ + u16 scale_decrement_interval; + /** + * @scale_increment_interval: + * Number of group times between incrementing the scale factor value + * used at the beginning of a slice. + */ + u16 scale_increment_interval; + /** + * @nfl_bpg_offset: Non first line BPG offset to be used + */ + u16 nfl_bpg_offset; + /** + * @slice_bpg_offset: BPG offset used to enforce slice bit + */ + u16 slice_bpg_offset; + /** + * @final_offset: Final RC linear transformation offset value + */ + u16 final_offset; + /** + * @vbr_enable: True if VBR mode is enabled, false if disabled + */ + bool vbr_enable; + /** + * @mux_word_size: Mux word size (in bits) for SSM mode + */ + u8 mux_word_size; + /** + * @slice_chunk_size: + * The (max) size in bytes of the "chunks" that are used in slice + * multiplexing. + */ + u16 slice_chunk_size; + /** + * @rc_bits: Rate control buffer size in bits + */ + u16 rc_bits; + /** + * @dsc_version_minor: DSC minor version + */ + u8 dsc_version_minor; + /** + * @dsc_version_major: DSC major version + */ + u8 dsc_version_major; + /** + * @native_422: True if Native 4:2:2 supported, else false + */ + bool native_422; + /** + * @native_420: True if Native 4:2:0 supported else false. + */ + bool native_420; + /** + * @second_line_bpg_offset: + * Additional bits/grp for seconnd line of slice for native 4:2:0 + */ + u8 second_line_bpg_offset; + /** + * @nsl_bpg_offset: + * Num of bits deallocated for each grp that is not in second line of + * slice + */ + u16 nsl_bpg_offset; + /** + * @second_line_offset_adj: + * Offset adjustment for second line in Native 4:2:0 mode + */ + u16 second_line_offset_adj; +}; + +/** + * struct picture_parameter_set - Represents 128 bytes of Picture Parameter Set + * + * The VESA DSC standard defines picture parameter set (PPS) which display + * stream compression encoders must communicate to decoders. + * The PPS is encapsulated in 128 bytes (PPS 0 through PPS 127). The fields in + * this structure are as per Table 4.1 in Vesa DSC specification v1.1/v1.2. + * The PPS fields that span over more than a byte should be stored in Big Endian + * format. + */ +#pragma pack(1) +struct drm_dsc_picture_parameter_set { + /** + * @dsc_version: + * PPS0[3:0] - dsc_version_minor: Contains Minor version of DSC + * PPS0[7:4] - dsc_version_major: Contains major version of DSC + */ + u8 dsc_version; + /** + * @pps_identifier: + * PPS1[7:0] - Application specific identifier that can be + * used to differentiate between different PPS tables. + */ + u8 pps_identifier; + /** + * @pps_reserved: + * PPS2[7:0]- RESERVED Byte + */ + u8 pps_reserved; + /** + * @pps_3: + * PPS3[3:0] - linebuf_depth: Contains linebuffer bit depth used to + * generate the bitstream. (0x0 - 16 bits for DSC 1.2, 0x8 - 8 bits, + * 0xA - 10 bits, 0xB - 11 bits, 0xC - 12 bits, 0xD - 13 bits, + * 0xE - 14 bits for DSC1.2, 0xF - 14 bits for DSC 1.2. + * PPS3[7:4] - bits_per_component: Bits per component for the original + * pixels of the encoded picture. + * 0x0 = 16bpc (allowed only when dsc_version_minor = 0x2) + * 0x8 = 8bpc, 0xA = 10bpc, 0xC = 12bpc, 0xE = 14bpc (also + * allowed only when dsc_minor_version = 0x2) + */ + u8 pps_3; + /** + * @pps_4: + * PPS4[1:0] -These are the most significant 2 bits of + * compressed BPP bits_per_pixel[9:0] syntax element. + * PPS4[2] - vbr_enable: 0 = VBR disabled, 1 = VBR enabled + * PPS4[3] - simple_422: Indicates if decoder drops samples to + * reconstruct the 4:2:2 picture. + * PPS4[4] - Convert_rgb: Indicates if DSC color space conversion is + * active. + * PPS4[5] - blobk_pred_enable: Indicates if BP is used to code any + * groups in picture + * PPS4[7:6] - Reserved bits + */ + u8 pps_4; + /** + * @bits_per_pixel_low: + * PPS5[7:0] - This indicates the lower significant 8 bits of + * the compressed BPP bits_per_pixel[9:0] element. + */ + u8 bits_per_pixel_low; + /** + * @pic_height: + * PPS6[7:0], PPS7[7:0] -pic_height: Specifies the number of pixel rows + * within the raster. + */ + __be16 pic_height; + /** + * @pic_width: + * PPS8[7:0], PPS9[7:0] - pic_width: Number of pixel columns within + * the raster. + */ + __be16 pic_width; + /** + * @slice_height: + * PPS10[7:0], PPS11[7:0] - Slice height in units of pixels. + */ + __be16 slice_height; + /** + * @slice_width: + * PPS12[7:0], PPS13[7:0] - Slice width in terms of pixels. + */ + __be16 slice_width; + /** + * @chunk_size: + * PPS14[7:0], PPS15[7:0] - Size in units of bytes of the chunks + * that are used for slice multiplexing. + */ + __be16 chunk_size; + /** + * @initial_xmit_delay_high: + * PPS16[1:0] - Most Significant two bits of initial transmission delay. + * It specifies the number of pixel times that the encoder waits before + * transmitting data from its rate buffer. + * PPS16[7:2] - Reserved + */ + u8 initial_xmit_delay_high; + /** + * @initial_xmit_delay_low: + * PPS17[7:0] - Least significant 8 bits of initial transmission delay. + */ + u8 initial_xmit_delay_low; + /** + * @initial_dec_delay: + * + * PPS18[7:0], PPS19[7:0] - Initial decoding delay which is the number + * of pixel times that the decoder accumulates data in its rate buffer + * before starting to decode and output pixels. + */ + __be16 initial_dec_delay; + /** + * @pps20_reserved: + * + * PPS20[7:0] - Reserved + */ + u8 pps20_reserved; + /** + * @initial_scale_value: + * PPS21[5:0] - Initial rcXformScale factor used at beginning + * of a slice. + * PPS21[7:6] - Reserved + */ + u8 initial_scale_value; + /** + * @scale_increment_interval: + * PPS22[7:0], PPS23[7:0] - Number of group times between incrementing + * the rcXformScale factor at end of a slice. + */ + __be16 scale_increment_interval; + /** + * @scale_decrement_interval_high: + * PPS24[3:0] - Higher 4 bits indicating number of group times between + * decrementing the rcXformScale factor at beginning of a slice. + * PPS24[7:4] - Reserved + */ + u8 scale_decrement_interval_high; + /** + * @scale_decrement_interval_low: + * PPS25[7:0] - Lower 8 bits of scale decrement interval + */ + u8 scale_decrement_interval_low; + /** + * @pps26_reserved: + * PPS26[7:0] + */ + u8 pps26_reserved; + /** + * @first_line_bpg_offset: + * PPS27[4:0] - Number of additional bits that are allocated + * for each group on first line of a slice. + * PPS27[7:5] - Reserved + */ + u8 first_line_bpg_offset; + /** + * @nfl_bpg_offset: + * PPS28[7:0], PPS29[7:0] - Number of bits including frac bits + * deallocated for each group for groups after the first line of slice. + */ + __be16 nfl_bpg_offset; + /** + * @slice_bpg_offset: + * PPS30, PPS31[7:0] - Number of bits that are deallocated for each + * group to enforce the slice constraint. + */ + __be16 slice_bpg_offset; + /** + * @initial_offset: + * PPS32,33[7:0] - Initial value for rcXformOffset + */ + __be16 initial_offset; + /** + * @final_offset: + * PPS34,35[7:0] - Maximum end-of-slice value for rcXformOffset + */ + __be16 final_offset; + /** + * @flatness_min_qp: + * PPS36[4:0] - Minimum QP at which flatness is signaled and + * flatness QP adjustment is made. + * PPS36[7:5] - Reserved + */ + u8 flatness_min_qp; + /** + * @flatness_max_qp: + * PPS37[4:0] - Max QP at which flatness is signalled and + * the flatness adjustment is made. + * PPS37[7:5] - Reserved + */ + u8 flatness_max_qp; + /** + * @rc_model_size: + * PPS38,39[7:0] - Number of bits within RC Model. + */ + __be16 rc_model_size; + /** + * @rc_edge_factor: + * PPS40[3:0] - Ratio of current activity vs, previous + * activity to determine presence of edge. + * PPS40[7:4] - Reserved + */ + u8 rc_edge_factor; + /** + * @rc_quant_incr_limit0: + * PPS41[4:0] - QP threshold used in short term RC + * PPS41[7:5] - Reserved + */ + u8 rc_quant_incr_limit0; + /** + * @rc_quant_incr_limit1: + * PPS42[4:0] - QP threshold used in short term RC + * PPS42[7:5] - Reserved + */ + u8 rc_quant_incr_limit1; + /** + * @rc_tgt_offset: + * PPS43[3:0] - Lower end of the variability range around the target + * bits per group that is allowed by short term RC. + * PPS43[7:4]- Upper end of the variability range around the target + * bits per group that i allowed by short term rc. + */ + u8 rc_tgt_offset; + /** + * @rc_buf_thresh: + * PPS44[7:0] - PPS57[7:0] - Specifies the thresholds in RC model for + * the 15 ranges defined by 14 thresholds. + */ + u8 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1]; + /** + * @rc_range_parameters: + * PPS58[7:0] - PPS87[7:0] + * Parameters that correspond to each of the 15 ranges. + */ + __be16 rc_range_parameters[DSC_NUM_BUF_RANGES]; + /** + * @native_422_420: + * PPS88[0] - 0 = Native 4:2:2 not used + * 1 = Native 4:2:2 used + * PPS88[1] - 0 = Native 4:2:0 not use + * 1 = Native 4:2:0 used + * PPS88[7:2] - Reserved 6 bits + */ + u8 native_422_420; + /** + * @second_line_bpg_offset: + * PPS89[4:0] - Additional bits/group budget for the + * second line of a slice in Native 4:2:0 mode. + * Set to 0 if DSC minor version is 1 or native420 is 0. + * PPS89[7:5] - Reserved + */ + u8 second_line_bpg_offset; + /** + * @nsl_bpg_offset: + * PPS90[7:0], PPS91[7:0] - Number of bits that are deallocated + * for each group that is not in the second line of a slice. + */ + __be16 nsl_bpg_offset; + /** + * @second_line_offset_adj: + * PPS92[7:0], PPS93[7:0] - Used as offset adjustment for the second + * line in Native 4:2:0 mode. + */ + __be16 second_line_offset_adj; + /** + * @pps_long_94_reserved: + * PPS 94, 95, 96, 97 - Reserved + */ + u32 pps_long_94_reserved; + /** + * @pps_long_98_reserved: + * PPS 98, 99, 100, 101 - Reserved + */ + u32 pps_long_98_reserved; + /** + * @pps_long_102_reserved: + * PPS 102, 103, 104, 105 - Reserved + */ + u32 pps_long_102_reserved; + /** + * @pps_long_106_reserved: + * PPS 106, 107, 108, 109 - reserved + */ + u32 pps_long_106_reserved; + /** + * @pps_long_110_reserved: + * PPS 110, 111, 112, 113 - reserved + */ + u32 pps_long_110_reserved; + /** + * @pps_long_114_reserved: + * PPS 114 - 117 - reserved + */ + u32 pps_long_114_reserved; + /** + * @pps_long_118_reserved: + * PPS 118 - 121 - reserved + */ + u32 pps_long_118_reserved; + /** + * @pps_long_122_reserved: + * PPS 122- 125 - reserved + */ + u32 pps_long_122_reserved; + /** + * @pps_short_126_reserved: + * PPS 126, 127 - reserved + */ + __be16 pps_short_126_reserved; +}; +#pragma pack() + +/** + * struct drm_dsc_pps_infoframe - DSC infoframe carrying the Picture Parameter + * Set Metadata + * + * This structure represents the DSC PPS infoframe required to send the Picture + * Parameter Set metadata required before enabling VESA Display Stream + * Compression. This is based on the DP Secondary Data Packet structure and + * comprises of SDP Header as defined &struct dp_sdp_header in drm_dp_helper.h + * and PPS payload defined in &struct drm_dsc_picture_parameter_set. + * + * @pps_header: Header for PPS as per DP SDP header format of type + * &struct dp_sdp_header + * @pps_payload: PPS payload fields as per DSC specification Table 4-1 + * as represented in &struct drm_dsc_picture_parameter_set + */ +#pragma pack(1) +struct drm_dsc_pps_infoframe { + struct dp_sdp_header pps_header; + struct drm_dsc_picture_parameter_set pps_payload; +}; +#pragma pack() + +void drm_dsc_dp_pps_header_init(struct dp_sdp_header *pps_header); +void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_sdp, + const struct drm_dsc_config *dsc_cfg); +int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg); + +#endif /* _DRM_DSC_H_ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_mipi_dsi.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_mipi_dsi.h new file mode 100644 index 0000000..05f0749 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/drm_mipi_dsi.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda + */ + +#ifndef __DRM_MIPI_DSI_H__ +#define __DRM_MIPI_DSI_H__ + +#include +#include + +struct mipi_dsi_host; +struct mipi_dsi_device; + +/* request ACK from peripheral */ +#define MIPI_DSI_MSG_REQ_ACK BIT(0) +/* use Low Power Mode to transmit message */ +#define MIPI_DSI_MSG_USE_LPM BIT(1) + +/** + * struct mipi_dsi_msg - read/write DSI buffer + * @channel: virtual channel id + * @type: payload data type + * @flags: flags controlling this message transmission + * @tx_len: length of @tx_buf + * @tx_buf: data to be written + * @rx_len: length of @rx_buf + * @rx_buf: data to be read, or NULL + */ +struct mipi_dsi_msg { + u8 channel; + u8 type; + u16 flags; + + size_t tx_len; + const void *tx_buf; + + size_t rx_len; + void *rx_buf; +}; + +bool mipi_dsi_packet_format_is_short(u8 type); +bool mipi_dsi_packet_format_is_long(u8 type); + +/** + * struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format + * @size: size (in bytes) of the packet + * @header: the four bytes that make up the header (Data ID, Word Count or + * Packet Data, and ECC) + * @payload_length: number of bytes in the payload + * @payload: a pointer to a buffer containing the payload, if any + */ +struct mipi_dsi_packet { + size_t size; + u8 header[4]; + size_t payload_length; + const u8 *payload; +}; + +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg); + +/** + * struct mipi_dsi_host_ops - DSI bus operations + * @attach: attach DSI device to DSI host + * @detach: detach DSI device from DSI host + * @transfer: transmit a DSI packet + * + * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg + * structures. This structure contains information about the type of packet + * being transmitted as well as the transmit and receive buffers. When an + * error is encountered during transmission, this function will return a + * negative error code. On success it shall return the number of bytes + * transmitted for write packets or the number of bytes received for read + * packets. + * + * Note that typically DSI packet transmission is atomic, so the .transfer() + * function will seldomly return anything other than the number of bytes + * contained in the transmit buffer on success. + */ +struct mipi_dsi_host_ops { + int (*attach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + int (*detach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + ssize_t (*transfer)(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg); +}; + +/** + * struct mipi_dsi_host - DSI host device + * @dev: driver model device node for this DSI host + * @ops: DSI host operations + * @list: list management + */ +struct mipi_dsi_host { + struct udevice *dev; + const struct mipi_dsi_host_ops *ops; +}; + +/* DSI mode flags */ + +/* video mode */ +#define MIPI_DSI_MODE_VIDEO BIT(0) +/* video burst mode */ +#define MIPI_DSI_MODE_VIDEO_BURST BIT(1) +/* video pulse mode */ +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) +/* enable auto vertical count mode */ +#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) +/* enable hsync-end packets in vsync-pulse and v-porch area */ +#define MIPI_DSI_MODE_VIDEO_HSE BIT(4) +/* disable hfront-porch area */ +#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) +/* disable hback-porch area */ +#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) +/* disable hsync-active area */ +#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) +/* flush display FIFO on vsync pulse */ +#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) +/* disable EoT packets in HS mode */ +#define MIPI_DSI_MODE_EOT_PACKET BIT(9) +/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ +#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) +/* transmit data in low power */ +#define MIPI_DSI_MODE_LPM BIT(11) + +enum mipi_dsi_pixel_format { + MIPI_DSI_FMT_RGB888, + MIPI_DSI_FMT_RGB666, + MIPI_DSI_FMT_RGB666_PACKED, + MIPI_DSI_FMT_RGB565, +}; + +#define DSI_DEV_NAME_SIZE 20 + +/** + * struct mipi_dsi_device - DSI peripheral device + * @host: DSI host for this peripheral + * @dev: driver model device node for this peripheral + * @name: DSI peripheral chip type + * @channel: virtual channel assigned to the peripheral + * @format: pixel format for video mode + * @lanes: number of active data lanes + * @mode_flags: DSI operation mode related flags + * @hs_rate: maximum lane frequency for high speed mode in hertz, this should + * be set to the real limits of the hardware, zero is only accepted for + * legacy drivers + * @lp_rate: maximum lane frequency for low power mode in hertz, this should + * be set to the real limits of the hardware, zero is only accepted for + * legacy drivers + */ +struct mipi_dsi_device { + struct mipi_dsi_host *host; + struct udevice *dev; + + char name[DSI_DEV_NAME_SIZE]; + unsigned int channel; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; + unsigned long hs_rate; + unsigned long lp_rate; +}; + +/** + * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any + * given pixel format defined by the MIPI DSI + * specification + * @fmt: MIPI DSI pixel format + * + * Returns: The number of bits per pixel of the given pixel format. + */ +static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB888: + case MIPI_DSI_FMT_RGB666: + return 24; + + case MIPI_DSI_FMT_RGB666_PACKED: + return 18; + + case MIPI_DSI_FMT_RGB565: + return 16; + } + + return -EINVAL; +} + +int mipi_dsi_attach(struct mipi_dsi_device *dsi); +int mipi_dsi_detach(struct mipi_dsi_device *dsi); +int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi); +int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi); +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value); + +ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable); +ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, + const struct drm_dsc_picture_parameter_set *pps); + +ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size); +ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, + size_t num_params, void *data, size_t size); + +/** + * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode + * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking + * information only + * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both + * V-Blanking and H-Blanking information + */ +enum mipi_dsi_dcs_tear_mode { + MIPI_DSI_DCS_TEAR_MODE_VBLANK, + MIPI_DSI_DCS_TEAR_MODE_VHBLANK, +}; + +#define MIPI_DSI_DCS_POWER_MODE_DISPLAY BIT(2) +#define MIPI_DSI_DCS_POWER_MODE_NORMAL BIT(3) +#define MIPI_DSI_DCS_POWER_MODE_SLEEP BIT(4) +#define MIPI_DSI_DCS_POWER_MODE_PARTIAL BIT(5) +#define MIPI_DSI_DCS_POWER_MODE_IDLE BIT(6) + +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len); +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode); +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format); +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end); +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode); +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format); +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); +int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, + u16 brightness); +int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, + u16 *brightness); + +#endif /* __DRM_MIPI_DSI__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/errno.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/errno.h new file mode 100644 index 0000000..3767df3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/errno.h @@ -0,0 +1,168 @@ +#ifndef _LINUX_ERRNO_H +#define _LINUX_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ + +#define ENOSYS 38 /* Invalid system call number */ + +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + +#define ERFKILL 132 /* Operation not possible due to RF-kill */ + +#define EHWPOISON 133 /* Memory page has hardware error */ + +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 /* restart if no handler.. */ +#define ENOIOCTLCMD 515 /* No ioctl command */ +#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */ +#define EPROBE_DEFER 517 /* Driver requests probe retry */ +#define EOPENSTALE 518 /* open found a stale dentry */ + +/* Defined for the NFSv3 protocol */ +#define EBADHANDLE 521 /* Illegal NFS file handle */ +#define ENOTSYNC 522 /* Update synchronization mismatch */ +#define EBADCOOKIE 523 /* Cookie is stale */ +#define ENOTSUPP 524 /* Operation is not supported */ +#define ETOOSMALL 525 /* Buffer or request is too small */ +#define ESERVERFAULT 526 /* An untranslatable error occurred */ +#define EBADTYPE 527 /* Type not supported by server */ +#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ +#define EIOCBQUEUED 529 /* iocb queued, will get completion event */ +#define ERECALLCONFLICT 530 /* conflict with recalled state */ + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/mipi_display.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/mipi_display.h new file mode 100644 index 0000000..3542d1c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/mipi_display.h @@ -0,0 +1,143 @@ +/* + * Defines for Mobile Industry Processor Interface (MIPI(R)) + * Display Working Group standards: DSI, DCS, DBI, DPI + * + * Copyright (C) 2010 Guennadi Liakhovetski + * Copyright (C) 2006 Nokia Corporation + * Author: Imre Deak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef MIPI_DISPLAY_H +#define MIPI_DISPLAY_H + +/* MIPI DSI Processor-to-Peripheral transaction types */ +enum { + MIPI_DSI_V_SYNC_START = 0x01, + MIPI_DSI_V_SYNC_END = 0x11, + MIPI_DSI_H_SYNC_START = 0x21, + MIPI_DSI_H_SYNC_END = 0x31, + + MIPI_DSI_COMPRESSION_MODE = 0x07, + + MIPI_DSI_COLOR_MODE_OFF = 0x02, + MIPI_DSI_COLOR_MODE_ON = 0x12, + MIPI_DSI_SHUTDOWN_PERIPHERAL = 0x22, + MIPI_DSI_TURN_ON_PERIPHERAL = 0x32, + + MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 0x03, + MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 0x13, + MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 0x23, + + MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 0x04, + MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 0x14, + MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 0x24, + + MIPI_DSI_DCS_SHORT_WRITE = 0x05, + MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15, + + MIPI_DSI_DCS_READ = 0x06, + + MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37, + + MIPI_DSI_END_OF_TRANSMISSION = 0x08, + + MIPI_DSI_NULL_PACKET = 0x09, + MIPI_DSI_BLANKING_PACKET = 0x19, + MIPI_DSI_GENERIC_LONG_WRITE = 0x29, + MIPI_DSI_DCS_LONG_WRITE = 0x39, + + MIPI_DSI_PICTURE_PARAMETER_SET = 0x0a, + MIPI_DSI_COMPRESSED_PIXEL_STREAM = 0x0b, + + MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 0x0c, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 0x1c, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 0x2c, + + MIPI_DSI_PACKED_PIXEL_STREAM_30 = 0x0d, + MIPI_DSI_PACKED_PIXEL_STREAM_36 = 0x1d, + MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 0x3d, + + MIPI_DSI_PACKED_PIXEL_STREAM_16 = 0x0e, + MIPI_DSI_PACKED_PIXEL_STREAM_18 = 0x1e, + MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 0x2e, + MIPI_DSI_PACKED_PIXEL_STREAM_24 = 0x3e, +}; + +/* MIPI DSI Peripheral-to-Processor transaction types */ +enum { + MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT = 0x02, + MIPI_DSI_RX_END_OF_TRANSMISSION = 0x08, + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE = 0x11, + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE = 0x12, + MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE = 0x1a, + MIPI_DSI_RX_DCS_LONG_READ_RESPONSE = 0x1c, + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE = 0x21, + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE = 0x22, +}; + +/* MIPI DCS commands */ +enum { + MIPI_DCS_NOP = 0x00, + MIPI_DCS_SOFT_RESET = 0x01, + MIPI_DCS_GET_DISPLAY_ID = 0x04, + MIPI_DCS_GET_RED_CHANNEL = 0x06, + MIPI_DCS_GET_GREEN_CHANNEL = 0x07, + MIPI_DCS_GET_BLUE_CHANNEL = 0x08, + MIPI_DCS_GET_DISPLAY_STATUS = 0x09, + MIPI_DCS_GET_POWER_MODE = 0x0A, + MIPI_DCS_GET_ADDRESS_MODE = 0x0B, + MIPI_DCS_GET_PIXEL_FORMAT = 0x0C, + MIPI_DCS_GET_DISPLAY_MODE = 0x0D, + MIPI_DCS_GET_SIGNAL_MODE = 0x0E, + MIPI_DCS_GET_DIAGNOSTIC_RESULT = 0x0F, + MIPI_DCS_ENTER_SLEEP_MODE = 0x10, + MIPI_DCS_EXIT_SLEEP_MODE = 0x11, + MIPI_DCS_ENTER_PARTIAL_MODE = 0x12, + MIPI_DCS_ENTER_NORMAL_MODE = 0x13, + MIPI_DCS_EXIT_INVERT_MODE = 0x20, + MIPI_DCS_ENTER_INVERT_MODE = 0x21, + MIPI_DCS_SET_GAMMA_CURVE = 0x26, + MIPI_DCS_SET_DISPLAY_OFF = 0x28, + MIPI_DCS_SET_DISPLAY_ON = 0x29, + MIPI_DCS_SET_COLUMN_ADDRESS = 0x2A, + MIPI_DCS_SET_PAGE_ADDRESS = 0x2B, + MIPI_DCS_WRITE_MEMORY_START = 0x2C, + MIPI_DCS_WRITE_LUT = 0x2D, + MIPI_DCS_READ_MEMORY_START = 0x2E, + MIPI_DCS_SET_PARTIAL_AREA = 0x30, + MIPI_DCS_SET_SCROLL_AREA = 0x33, + MIPI_DCS_SET_TEAR_OFF = 0x34, + MIPI_DCS_SET_TEAR_ON = 0x35, + MIPI_DCS_SET_ADDRESS_MODE = 0x36, + MIPI_DCS_SET_SCROLL_START = 0x37, + MIPI_DCS_EXIT_IDLE_MODE = 0x38, + MIPI_DCS_ENTER_IDLE_MODE = 0x39, + MIPI_DCS_SET_PIXEL_FORMAT = 0x3A, + MIPI_DCS_WRITE_MEMORY_CONTINUE = 0x3C, + MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E, + MIPI_DCS_SET_TEAR_SCANLINE = 0x44, + MIPI_DCS_GET_SCANLINE = 0x45, + MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 0x51, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 0x52, /* MIPI DCS 1.3 */ + MIPI_DCS_WRITE_CONTROL_DISPLAY = 0x53, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_CONTROL_DISPLAY = 0x54, /* MIPI DCS 1.3 */ + MIPI_DCS_WRITE_POWER_SAVE = 0x55, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_POWER_SAVE = 0x56, /* MIPI DCS 1.3 */ + MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 0x5E, /* MIPI DCS 1.3 */ + MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F, /* MIPI DCS 1.3 */ + MIPI_DCS_READ_DDB_START = 0xA1, + MIPI_DCS_READ_DDB_CONTINUE = 0xA8, +}; + +/* MIPI DCS pixel formats */ +#define MIPI_DCS_PIXEL_FMT_24BIT 7 +#define MIPI_DCS_PIXEL_FMT_18BIT 6 +#define MIPI_DCS_PIXEL_FMT_16BIT 5 +#define MIPI_DCS_PIXEL_FMT_12BIT 3 +#define MIPI_DCS_PIXEL_FMT_8BIT 2 +#define MIPI_DCS_PIXEL_FMT_3BIT 1 + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/uboot-env.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/uboot-env.h new file mode 100644 index 0000000..47e2c24 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Library/uboot-env.h @@ -0,0 +1,222 @@ +#ifndef _UBOOT_ENV_H +#define _UBOOT_ENV_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __maybe_unused + +typedef UINT8 u8; +typedef UINT16 u16; +typedef UINT32 u32; +typedef UINT64 u64; +typedef unsigned int uint; +typedef UINTN ulong; +typedef INTN ssize_t; +typedef UINTN size_t; +typedef BOOLEAN bool; +typedef UINT16 __be16; + +#define true TRUE +#define false FALSE + +#define udelay(x) MicroSecondDelay (x) +#define mdelay(x) MicroSecondDelay (x * 1000) + +#define dev_err(dev, args...) DEBUG ((DEBUG_ERROR, args)) +#define dev_info(dev, args...) DEBUG ((DEBUG_INFO, args)) +#define dev_dbg(dev, args...) DEBUG ((DEBUG_INFO, args)) +#define printf(args...) DEBUG ((DEBUG_INFO, args)) +#define debug(args...) DEBUG ((DEBUG_INFO, args)) +#define WARN(x, args...) DEBUG ((DEBUG_WARN, args)) + +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) + +#define BIT(x) (1 << (x)) + +#define BITS_PER_LONG (sizeof(UINTN) * 8) +#define GENMASK(h, l) \ + (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define FIELD_PREP(_mask, _val) \ + ({ \ + ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + }) + +#define FIELD_GET(_mask, _reg) \ + ({ \ + (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + }) + +#define fls(x) HighBitSet32(x) + +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +#define min_t(type, a, b) min(((type) a), ((type) b)) +#define max_t(type, a, b) max(((type) a), ((type) b)) + +#define do_div(n,base) ({ \ + uint32_t __base = (base); \ + uint32_t __rem; \ + __rem = ((uint64_t)(n)) % __base; \ + (n) = ((uint64_t)(n)) / __base; \ + __rem; \ + }) + +#define DIV_ROUND_CLOSEST(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) + +#define writel(val, addr) MmioWrite32(addr, val) +#define readl(addr) MmioRead32(addr) + +// +// TODO: Actually check for timeout below... +// +#define readx_poll_timeout(op, addr, val, cond, timeout_us) \ +({ \ + for (;;) { \ + (val) = op(addr); \ + if (cond) \ + break; \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +#define readl_poll_timeout(addr, val, cond, timeout_us) \ + readx_poll_timeout(readl, addr, val, cond, timeout_us) + +#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, \ + timeout_ms) \ +({ \ + int __ret; \ + for (;;) { \ + __ret = regmap_read((map), (addr), &(val)); \ + if (__ret) \ + break; \ + if (cond) \ + break; \ + if ((sleep_us)) \ + udelay((sleep_us)); \ + } \ + __ret ?: ((cond) ? 0 : -ETIMEDOUT); \ +}) + +static inline int regmap_write(UINTN map, uint offset, uint val) +{ + MmioWrite32 (map + offset, val); + return 0; +} + +static inline int regmap_read(UINTN map, uint offset, uint *valp) +{ + *valp = MmioRead32 (map + offset); + return 0; +} + +static inline int regmap_update_bits(UINTN map, uint offset, uint mask, uint val) +{ + uint reg; + int ret; + + ret = regmap_read(map, offset, ®); + if (ret) + return ret; + + reg &= ~mask; + + return regmap_write(map, offset, reg | (val & mask)); +} + +struct reset_ctl { + unsigned int offset; + unsigned int bit; +}; + +static inline void reset(const struct reset_ctl *ctl, bool en) +{ + u32 val; + val = (en << ctl->bit) | ((1 << ctl->bit) << 16); + regmap_write(CRU_BASE, ctl->offset, val); +} + +#define reset_assert(ctl) reset(ctl, true) +#define reset_deassert(ctl) reset(ctl, false) + +static inline u32 __get_unaligned_le32(const u8 *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_le32((const u8 *)p); +} + +static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) +{ + *remainder = dividend % divisor; + return dividend / divisor; +} + +static inline u64 div_u64(u64 dividend, u32 divisor) +{ + u32 remainder; + return div_u64_rem(dividend, divisor, &remainder); +} + +#define div64_ul(x, y) div_u64((x), (y)) + +#define abs(x) ({ \ + long ret; \ + if (sizeof(x) == sizeof(long)) { \ + long __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } else { \ + int __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } \ + ret; \ + }) + +#define uswap_16(x) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) + +#define cpu_to_be16(x) uswap_16(x) +#define be16_to_cpu(x) uswap_16(x) + +#define memcpy(dest, source, count) CopyMem(dest,source, (UINTN)(count)) +#define memset(dest, ch, count) SetMem(dest, (UINTN)(count),(UINT8)(ch)) +#define memchr(buf, ch, count) ScanMem8(buf, (UINTN)(count),(UINT8)ch) +#define memcmp(buf1, buf2, count) (int)(CompareMem(buf1, buf2, (UINTN)(count))) +#define memmove(dest, source, count) CopyMem(dest, source, (UINTN)(count)) +#define strlen(str) (size_t)(AsciiStrLen(str)) +#define strnlen(str, count) (size_t)(AsciiStrnLenS(str, count)) +#define strncpy(strDest, strSource, count) AsciiStrnCpyS(strDest, MAX_STRING_SIZE, strSource, (UINTN)count) +#define strcat(strDest, strSource) AsciiStrCatS(strDest, MAX_STRING_SIZE, strSource) +#define strcmp(string1, string2, count) (int)(AsciiStrCmp(string1, string2)) +#define strncmp(string1, string2, count) (int)(AsciiStrnCmp(string1, string2, (UINTN)(count))) + +#define malloc(sz) AllocatePool(sz) +#define calloc(num, sz) AllocateZeroPool((num) * (sz)); +#define free(buf) FreePool(buf) + +#endif // _UBOOT_ENV_H diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/DpPhy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/DpPhy.h new file mode 100644 index 0000000..62bac0c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/DpPhy.h @@ -0,0 +1,64 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef _DP_PHY_PROTOCOL_H_ +#define _DP_PHY_PROTOCOL_H_ + +#define DP_PHY_PROTOCOL_GUID \ + { 0xb4bcf881, 0xc8b3, 0x46d7, { 0xaf, 0xbe, 0x5a, 0x2d, 0x94, 0x9d, 0x93, 0xc3 } } + +typedef struct _DP_PHY_PROTOCOL DP_PHY_PROTOCOL; + +#define DP_PHY_MAX_LANES 4 + +typedef struct { + UINT32 LinkRate; + UINT32 LaneCount; + UINT32 LaneVoltageSwingLevels[DP_PHY_MAX_LANES]; + UINT32 LanePreEmphasisLevels[DP_PHY_MAX_LANES]; + BOOLEAN EnableSpreadSpectrum; + BOOLEAN SetLinkRateAndSpreadSpectrum; + BOOLEAN SetLaneCount; + BOOLEAN SetVoltageSwingAndPreEmphasisLevels; +} DP_PHY_CONFIGURATION; + +typedef struct { + UINT32 BusWidth; + UINT32 MaximumLinkRate; +} DP_PHY_CAPABILITIES; + +typedef +EFI_STATUS +(EFIAPI *DP_PHY_POWER_ON) ( + IN DP_PHY_PROTOCOL *This + ); + +typedef +EFI_STATUS +(EFIAPI *DP_PHY_POWER_OFF) ( + IN DP_PHY_PROTOCOL *This + ); + +typedef +EFI_STATUS +(EFIAPI *DP_PHY_CONFIGURE) ( + IN DP_PHY_PROTOCOL *This, + IN DP_PHY_CONFIGURATION *Config + ); + +struct _DP_PHY_PROTOCOL { + DP_PHY_POWER_ON PowerOn; + DP_PHY_POWER_OFF PowerOff; + DP_PHY_CONFIGURE Configure; + DP_PHY_CAPABILITIES Capabilities; + UINT32 Id; +}; + +extern EFI_GUID gDpPhyProtocolGuid; + +#endif // _DP_PHY_PROTOCOL_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2c.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2c.h new file mode 100644 index 0000000..ebaad29 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2c.h @@ -0,0 +1,32 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Inc. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef _RK_I2C_H__ +#define _RK_I2C_H__ + +/* + * I2C_FLAG_NORESTART is not part of PI spec, it allows to continue + * transmission without repeated start operation. + */ +#define I2C_FLAG_NORESTART 0x00000002 + +/* + * Helper macros for maintaining multiple I2C buses + * and devices defined via EFI_I2C_DEVICE. + */ +#define I2C_DEVICE_ADDRESS(Index) ((Index) & MAX_UINT16) +#define I2C_DEVICE_BUS(Index) ((Index) >> 16) +#define I2C_DEVICE_INDEX(Bus, Address) (((Address) & MAX_UINT16) | (Bus) << 16) + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2cDemo.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2cDemo.h new file mode 100644 index 0000000..7515d49 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/I2cDemo.h @@ -0,0 +1,32 @@ +/******************************************************************************** +Copyright (C) 2016 Marvell International Ltd. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +*******************************************************************************/ + +#ifndef __ROCKCHIP_I2CDEMO_H__ +#define __ROCKCHIP_I2CDEMO_H__ + +#define ROCKCHIP_I2CDEMO_PROTOCOL_GUID { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }} + +typedef struct _ROCKCHIP_I2CDEMO_PROTOCOL ROCKCHIP_I2CDEMO_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EFI_I2CDEMO_TRANSFER) ( + IN CONST ROCKCHIP_I2CDEMO_PROTOCOL *This, + IN UINT8 *RegAddress, + IN UINT16 RegAddressLength, + IN UINT8 *Buffer, + IN UINT16 Length +); + +struct _ROCKCHIP_I2CDEMO_PROTOCOL { + EFI_I2CDEMO_TRANSFER Read; + EFI_I2CDEMO_TRANSFER Write; + UINT32 Identifier; +}; + +extern EFI_GUID gRockchipI2cDemoProtocolGuid; +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/NorFlashProtocol.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/NorFlashProtocol.h new file mode 100644 index 0000000..7344e1b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/NorFlashProtocol.h @@ -0,0 +1,69 @@ +/** @file +* +* Copyright (c) 2022, Rockchip Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + + +#ifndef _UNI_NOR_FLASH_PROTOCOL_H_ +#define _UNI_NOR_FLASH_PROTOCOL_H_ + +#define UNI_NOR_FLASH_PROTOCOL_GUID \ + {0x86F305EA, 0xDFAC, 0x4A6B, {0x92, 0x77, 0x47, 0x31, 0x2E, 0xCE, 0x42, 0xA}} + +typedef struct _UNI_NOR_FLASH_PROTOCOL UNI_NOR_FLASH_PROTOCOL; + +typedef +UINT32 +(EFIAPI *UNI_FLASH_GET_SIZE_INTERFACE) ( + IN UNI_NOR_FLASH_PROTOCOL *This + ); + +typedef +EFI_STATUS +(EFIAPI *UNI_FLASH_ERASE_INTERFACE) ( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT32 Length + ); + +typedef +EFI_STATUS +(EFIAPI *UNI_FLASH_WRITE_INTERFACE) ( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT8 *Buffer, + UINT32 ulLength + ); + +typedef +EFI_STATUS +(EFIAPI *UNI_FLASH_READ_INTERFACE) ( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN OUT UINT8 *Buffer, + IN UINT32 ulLen + ); + +typedef +EFI_STATUS +(EFIAPI *UNI_FLASH_UPDATE_INTERFACE) ( + IN UNI_NOR_FLASH_PROTOCOL *This, + IN UINT32 Offset, + IN UINT8 *Buffer, + UINT32 ulLength + ); + +struct _UNI_NOR_FLASH_PROTOCOL { + UNI_FLASH_GET_SIZE_INTERFACE GetSize; + UNI_FLASH_ERASE_INTERFACE Erase; + UNI_FLASH_WRITE_INTERFACE Write; + UNI_FLASH_READ_INTERFACE Read; + UNI_FLASH_UPDATE_INTERFACE Update; +}; + +extern EFI_GUID gUniNorFlashProtocolGuid; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/OhciDeviceProtocol.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/OhciDeviceProtocol.h new file mode 100644 index 0000000..ba62bc7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/OhciDeviceProtocol.h @@ -0,0 +1,23 @@ +/** @file + + Copyright (c) 2023, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _OHCI_DEVICE_PROTOCOL_H_ +#define _OHCI_DEVICE_PROTOCOL_H_ + +#include + +#define OHCI_DEVICE_PROTOCOL_GUID \ + {0x54bce5e6, 0xbaae, 0x488a, {0x82, 0x67, 0xc0, 0x85, 0x7f, 0xb4, 0xe8, 0x05}} + +typedef struct { + UINT32 BaseAddress; +} OHCI_DEVICE_PROTOCOL; + +extern EFI_GUID gOhciDeviceProtocolGuid; + +#endif // _OHCI_DEVICE_PROTOCOL_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Pca9555.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Pca9555.h new file mode 100644 index 0000000..141218c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Pca9555.h @@ -0,0 +1,28 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * Copyright (c) 2023, Shimrra Shai + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __PCA9555_H__ +#define __PCA9555_H__ + +#include + +#include + +#define PCA95XX_PROTOCOL_GUID \ + { 0x7e91391b, 0xa23c, 0x4a51, { 0x9d, 0xf7, 0xf6, 0x74, 0xef, 0x1d, 0x51, 0x1b } } + +typedef struct _PCA95XX_PROTOCOL PCA95XX_PROTOCOL; + +struct _PCA95XX_PROTOCOL { + EMBEDDED_GPIO GpioProtocol; +}; + +extern EFI_GUID gPca95xxProtocolGuid; + +#endif // __PCA9555_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Rk860xRegulator.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Rk860xRegulator.h new file mode 100644 index 0000000..5894410 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/Rk860xRegulator.h @@ -0,0 +1,74 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __RK860X_REGULATOR_H__ +#define __RK860X_REGULATOR_H__ + +#define RK860X_REGULATOR_PROTOCOL_GUID { 0xb9ef9018, 0x2096, 0x4bf5, { 0x94, 0xb2, 0x70, 0x32, 0xb9, 0xa9, 0xa4, 0x29 }} + +typedef struct _RK860X_REGULATOR_PROTOCOL RK860X_REGULATOR_PROTOCOL; + +typedef struct { + UINT32 Min; + UINT32 Max; +} VOLTAGE_RANGE; + +typedef +EFI_STATUS +(EFIAPI *EFI_RK860X_REGULATOR_GET_VOLTAGE) ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT UINT32 *Voltage, + IN BOOLEAN Suspend +); + +typedef +EFI_STATUS +(EFIAPI *EFI_RK860X_REGULATOR_SET_VOLTAGE) ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN UINT32 Voltage, + IN BOOLEAN Suspend +); + +typedef +EFI_STATUS +(EFIAPI *EFI_RK860X_REGULATOR_GET_ENABLE) ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT BOOLEAN *Enable, + IN BOOLEAN Suspend +); + +typedef +EFI_STATUS +(EFIAPI *EFI_RK860X_REGULATOR_SET_ENABLE) ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + IN BOOLEAN Enable, + IN BOOLEAN Suspend +); + +typedef +EFI_STATUS +(EFIAPI *EFI_RK860X_REGULATOR_GET_VOLTAGE_LIMIT) ( + IN CONST RK860X_REGULATOR_PROTOCOL *This, + OUT UINT32 *Voltage, + IN BOOLEAN PlatformPreferredLimit +); + +struct _RK860X_REGULATOR_PROTOCOL { + EFI_RK860X_REGULATOR_GET_VOLTAGE GetVoltage; + EFI_RK860X_REGULATOR_SET_VOLTAGE SetVoltage; + EFI_RK860X_REGULATOR_GET_ENABLE GetEnable; + EFI_RK860X_REGULATOR_SET_ENABLE SetEnable; + VOLTAGE_RANGE SupportedVoltageRange; + VOLTAGE_RANGE PreferredVoltageRange; + UINT8 Tag; + UINT32 Identifier; +}; + +extern EFI_GUID gRk860xRegulatorProtocolGuid; + +#endif // __RK860X_REGULATOR_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipConnectorProtocol.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipConnectorProtocol.h new file mode 100644 index 0000000..6c5bd5f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipConnectorProtocol.h @@ -0,0 +1,107 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _ROCKCHIP_CONNECTOR_PROTOCOL_H_ +#define _ROCKCHIP_CONNECTOR_PROTOCOL_H_ + +#include + +#define RK_CONNECTOR_PROTOCOL_GUID \ + {0x50439CB6, 0x9B85, 0x11EC, {0x95, 0x73, 0xF4, 0x2A, 0x7D, 0xCB, 0x92, 0x5D}} + +typedef struct _ROCKCHIP_CONNECTOR_PROTOCOL ROCKCHIP_CONNECTOR_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_PREINIT) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_INIT) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_DEINIT) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_DETECT) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_GET_TIMING) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_GET_EDID) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_PREPARE) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_ENABLE) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_DISABLE) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CONNECTOR_UNPREPARE) ( + IN ROCKCHIP_CONNECTOR_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +struct _ROCKCHIP_CONNECTOR_PROTOCOL { + VOID *Private; + ROCKCHIP_CONNECTOR_PREINIT Preinit; + ROCKCHIP_CONNECTOR_INIT Init; + ROCKCHIP_CONNECTOR_DEINIT Deinit; + ROCKCHIP_CONNECTOR_DETECT Detect; + ROCKCHIP_CONNECTOR_GET_TIMING GetTiming; + ROCKCHIP_CONNECTOR_GET_EDID GetEdid; + ROCKCHIP_CONNECTOR_PREPARE Prepare; + ROCKCHIP_CONNECTOR_ENABLE Enable; + ROCKCHIP_CONNECTOR_DISABLE Disable; + ROCKCHIP_CONNECTOR_UNPREPARE Unprepare; +}; + +extern EFI_GUID gRockchipConnectorProtocolGuid; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipCrtcProtocol.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipCrtcProtocol.h new file mode 100644 index 0000000..0ad4f34 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipCrtcProtocol.h @@ -0,0 +1,105 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _ROCKCHIP_CRTC_PROTOCOL_H_ +#define _ROCKCHIP_CRTC_PROTOCOL_H_ + +#include + +#define ROCKCHIP_CRTC_PROTOCOL_GUID \ + {0xC128406A, 0x99D9, 0x11EC, {0x99, 0x27, 0xF4, 0x2A, 0x7D, 0xCB, 0x92, 0x5D}} + +typedef struct _ROCKCHIP_CRTC_PROTOCOL ROCKCHIP_CRTC_PROTOCOL; + +typedef struct { + BOOLEAN Enable; + UINT8 BgOvlDly; + UINT32 PlaneMask; + UINT32 PrimaryPlane; + INT32 OutputType; + INT32 CursorPlane; +} VPS_CONFIG; + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_PREINIT) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_INIT) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_DEINIT) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_SET_PLANE) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_PREPARE) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_ENABLE) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_DISABLE) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_CRTC_UNPREPARE) ( + IN ROCKCHIP_CRTC_PROTOCOL *This, + IN OUT DISPLAY_STATE *DisplayState + ); + +struct _ROCKCHIP_CRTC_PROTOCOL { + VOID *Private; + ROCKCHIP_CRTC_PREINIT Preinit; + ROCKCHIP_CRTC_INIT Init; + ROCKCHIP_CRTC_DEINIT Deinit; + ROCKCHIP_CRTC_SET_PLANE SetPlane; + ROCKCHIP_CRTC_PREPARE Prepare; + ROCKCHIP_CRTC_ENABLE Enable; + ROCKCHIP_CRTC_DISABLE Disable; + ROCKCHIP_CRTC_UNPREPARE Unprepare; + DRM_DISPLAY_MODE ActiveMode; + VPS_CONFIG Vps[4]; + BOOLEAN HdmiHpd; + BOOLEAN Active; + BOOLEAN AssignPlane; +}; + +extern EFI_GUID gRockchipCrtcProtocolGuid; + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipDsiPanel.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipDsiPanel.h new file mode 100644 index 0000000..fe705d2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipDsiPanel.h @@ -0,0 +1,50 @@ +/** @file +* +* Copyright (c) 2024, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef _ROCKCHIP_DSI_PANEL_PROTOCOL_H_ +#define _ROCKCHIP_DSI_PANEL_PROTOCOL_H_ + +#include +#include + +#define ROCKCHIP_DSI_PANEL_PROTOCOL_GUID \ + { 0xb4bcf881, 0xc8b3, 0x46d7, { 0xaf, 0xbe, 0x5a, 0x2d, 0x94, 0x9d, 0x93, 0xc3 } } + +typedef struct _ROCKCHIP_DSI_PANEL_PROTOCOL ROCKCHIP_DSI_PANEL_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *ROCKCHIP_DSI_PANEL_PREPARE)( + IN ROCKCHIP_DSI_PANEL_PROTOCOL *This + ); + +struct _ROCKCHIP_DSI_PANEL_PROTOCOL { + UINT32 DsiId; + UINT32 DsiLaneRate; + UINT32 DsiLanes; + UINT32 DsiFlags; + UINT32 DsiFormat; + BOOLEAN DscEnable; + BOOLEAN CPhyEnable; + BOOLEAN ScramblingEnable; + UINT32 SliceWidth; + UINT32 SliceHeight; + UINT32 VersionMajor; + UINT32 VersionMinor; + + UINT8 *InitSequence; + UINT32 InitSequenceLength; + + DISPLAY_MODE NativeMode; + + ROCKCHIP_DSI_PANEL_PREPARE Prepare; +}; + +extern EFI_GUID gRockchipDsiPanelProtocolGuid; + +#endif // _ROCKCHIP_DSI_PANEL_PROTOCOL_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipI2cMasterProtocol.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipI2cMasterProtocol.h new file mode 100644 index 0000000..d530242 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Include/Protocol/RockchipI2cMasterProtocol.h @@ -0,0 +1,23 @@ +/** @file + + Copyright (c) 2023, Mario Bălănică + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _ROCKCHIP_I2C_MASTER_PROTOCOL_H_ +#define _ROCKCHIP_I2C_MASTER_PROTOCOL_H_ + +#include + +#define ROCKCHIP_I2C_MASTER_PROTOCOL_GUID \ + { 0x7b4af789, 0x43d2, 0x44a5, { 0xa0, 0xb3, 0x3f, 0xa5, 0xde, 0xd7, 0xa1, 0x27 } } + +typedef struct { + UINT8 Bus; +} ROCKCHIP_I2C_MASTER_PROTOCOL; + +extern EFI_GUID gRockchipI2cMasterProtocolGuid; + +#endif // _ROCKCHIP_I2C_MASTER_PROTOCOL_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.c new file mode 100644 index 0000000..56ab462 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.c @@ -0,0 +1,1460 @@ +/** @file + * + * Read-only non-volatile variable service library for early SEC phase. + * Based on FaultTolerantWritePei and VariablePei, without using any HOBs. + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
    + * Copyright (c) Microsoft Corporation.
    + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "Variable.h" + +STATIC FAULT_TOLERANT_WRITE_LAST_WRITE_DATA mFtwLastWriteData; +STATIC BOOLEAN mFtwLastWriteDataInitialized; + +// Also fits VARIABLE_HEADER +STATIC AUTHENTICATED_VARIABLE_HEADER mVariableHeaderFtw; +STATIC BOOLEAN mVariableHeaderFtwMerged; + +STATIC VARIABLE_INDEX_TABLE mVariableIndexTable; + +/** + Get the last Write Header pointer. + The last write header is the header whose 'complete' state hasn't been set. + After all, this header may be a EMPTY header entry for next Allocate. + + + @param FtwWorkSpaceHeader Pointer of the working block header + @param FtwWorkSpaceSize Size of the work space + @param FtwWriteHeader Pointer to retrieve the last write header + + @retval EFI_SUCCESS Get the last write record successfully + @retval EFI_ABORTED The FTW work space is damaged + +**/ +EFI_STATUS +FtwGetLastWriteHeader ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader, + IN UINTN FtwWorkSpaceSize, + OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader + ) +{ + UINTN Offset; + EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader; + + *FtwWriteHeader = NULL; + FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)(FtwWorkSpaceHeader + 1); + Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER); + + while (FtwHeader->Complete == FTW_VALID_STATE) { + Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); + // + // If Offset exceed the FTW work space boudary, return error. + // + if (Offset >= FtwWorkSpaceSize) { + *FtwWriteHeader = FtwHeader; + return EFI_ABORTED; + } + + FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *)((UINT8 *)FtwWorkSpaceHeader + Offset); + } + + // + // Last write header is found + // + *FtwWriteHeader = FtwHeader; + + return EFI_SUCCESS; +} + +/** + Get the last Write Record pointer. The last write Record is the Record + whose DestinationCompleted state hasn't been set. After all, this Record + may be a EMPTY record entry for next write. + + + @param FtwWriteHeader Pointer to the write record header + @param FtwWriteRecord Pointer to retrieve the last write record + + @retval EFI_SUCCESS Get the last write record successfully + @retval EFI_ABORTED The FTW work space is damaged + +**/ +EFI_STATUS +FtwGetLastWriteRecord ( + IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader, + OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord + ) +{ + UINTN Index; + EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord; + + *FtwWriteRecord = NULL; + FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)(FtwWriteHeader + 1); + + // + // Try to find the last write record "that has not completed" + // + for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) { + if (FtwRecord->DestinationComplete != FTW_VALID_STATE) { + // + // The last write record is found + // + *FtwWriteRecord = FtwRecord; + return EFI_SUCCESS; + } + + FtwRecord++; + + if (FtwWriteHeader->PrivateDataSize != 0) { + FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord + (UINTN)FtwWriteHeader->PrivateDataSize); + } + } + + // + // if Index == NumberOfWrites, then + // the last record has been written successfully, + // but the Header->Complete Flag has not been set. + // also return the last record. + // + if (Index == FtwWriteHeader->NumberOfWrites) { + *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *)((UINTN)FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize)); + return EFI_SUCCESS; + } + + return EFI_ABORTED; +} + +/** + Check to see if it is a valid work space. + + + @param WorkingHeader Pointer of working block header + @param WorkingLength Working block length + + @retval TRUE The work space is valid. + @retval FALSE The work space is invalid. + +**/ +BOOLEAN +IsValidWorkSpace ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader, + IN UINTN WorkingLength + ) +{ + UINT8 Data; + + if (WorkingHeader == NULL) { + return FALSE; + } + + if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) { + DEBUG ((DEBUG_ERROR, "FtwPei: Work block header valid bit check error\n")); + return FALSE; + } + + if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) { + DEBUG ((DEBUG_ERROR, "FtwPei: Work block header WriteQueueSize check error\n")); + return FALSE; + } + + // + // Check signature with gEdkiiWorkingBlockSignatureGuid + // + if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) { + DEBUG ((DEBUG_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n")); + // + // To be compatible with old signature gEfiSystemNvDataFvGuid. + // + if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) { + return FALSE; + } else { + Data = *(UINT8 *)(WorkingHeader + 1); + if (Data != 0xff) { + DEBUG ((DEBUG_ERROR, "FtwPei: Old format FTW structure can't be handled\n")); + ASSERT (FALSE); + return FALSE; + } + } + } + + return TRUE; +} + +/** + Main entry for Fault Tolerant Write PEIM. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Pointer to PEI Services table. + + @retval EFI_SUCCESS If the interface could be successfully installed + @retval Others Returned from PeiServicesInstallPpi() + +**/ +EFI_STATUS +EFIAPI +FaultTolerantWriteInitialize ( + VOID + ) +{ + EFI_STATUS Status; + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkingBlockHeader; + EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader; + EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord; + EFI_PHYSICAL_ADDRESS WorkSpaceAddress; + UINTN WorkSpaceLength; + EFI_PHYSICAL_ADDRESS SpareAreaAddress; + UINTN SpareAreaLength; + EFI_PHYSICAL_ADDRESS WorkSpaceInSpareArea; + + if (mFtwLastWriteDataInitialized) { + return EFI_SUCCESS; + } + + FtwWorkingBlockHeader = NULL; + FtwLastWriteHeader = NULL; + FtwLastWriteRecord = NULL; + + WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFlashNvStorageFtwWorkingBase64); + if (WorkSpaceAddress == 0) { + WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdFlashNvStorageFtwWorkingBase); + } + + WorkSpaceLength = (UINTN)PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + + SpareAreaAddress = (EFI_PHYSICAL_ADDRESS)PcdGet64 (PcdFlashNvStorageFtwSpareBase64); + if (SpareAreaAddress == 0) { + SpareAreaAddress = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdFlashNvStorageFtwSpareBase); + } + + SpareAreaLength = (UINTN)PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + // + // The address of FTW working base and spare base must not be 0. + // + ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0)); + + FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceAddress; + if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) { + Status = FtwGetLastWriteHeader ( + FtwWorkingBlockHeader, + WorkSpaceLength, + &FtwLastWriteHeader + ); + if (!EFI_ERROR (Status)) { + Status = FtwGetLastWriteRecord ( + FtwLastWriteHeader, + &FtwLastWriteRecord + ); + } + + if (!EFI_ERROR (Status)) { + ASSERT (FtwLastWriteRecord != NULL); + if ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE)) { + // + // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set. + // It means the target buffer has been backed up in spare block, then target block has been erased, + // but the target buffer has not been writen in target block from spare block, we need to build + // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data. + // + mFtwLastWriteData.TargetAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((INT64)SpareAreaAddress + FtwLastWriteRecord->RelativeOffset); + mFtwLastWriteData.SpareAddress = SpareAreaAddress; + mFtwLastWriteData.Length = SpareAreaLength; + DEBUG (( + DEBUG_INFO, + "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n", + (UINTN)mFtwLastWriteData.TargetAddress, + (UINTN)mFtwLastWriteData.SpareAddress, + (UINTN)mFtwLastWriteData.Length + )); + } + } + } else { + FtwWorkingBlockHeader = NULL; + // + // If the working block workspace is not valid, try to find workspace in the spare block. + // + WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength; + while (WorkSpaceInSpareArea >= SpareAreaAddress) { + if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *)(UINTN)WorkSpaceInSpareArea)) { + // + // Found the workspace. + // + DEBUG ((DEBUG_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN)WorkSpaceInSpareArea)); + FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *)(UINTN)WorkSpaceInSpareArea; + break; + } + + WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID); + } + + if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) { + // + // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it. + // + mFtwLastWriteData.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress); + mFtwLastWriteData.SpareAddress = SpareAreaAddress; + mFtwLastWriteData.Length = SpareAreaLength; + DEBUG (( + DEBUG_INFO, + "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n", + (UINTN)mFtwLastWriteData.TargetAddress, + (UINTN)mFtwLastWriteData.SpareAddress, + (UINTN)mFtwLastWriteData.Length + )); + } else { + // + // Both are invalid. + // + DEBUG ((DEBUG_ERROR, "FtwPei: Both working and spare block are invalid.\n")); + } + } + + mFtwLastWriteDataInitialized = TRUE; + + return EFI_SUCCESS; +} + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The start of variable store + // + return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1); +} + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size); +} + +/** + This code checks if variable header is valid or not. + + @param Variable Pointer to the Variable Header. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +{ + if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) { + return FALSE; + } + + return TRUE; +} + +/** + This code gets the size of variable header. + + @param AuthFlag Authenticated variable flag. + + @return Size of variable header in bytes in type UINTN. + +**/ +UINTN +GetVariableHeaderSize ( + IN BOOLEAN AuthFlag + ) +{ + UINTN Value; + + if (AuthFlag) { + Value = sizeof (AUTHENTICATED_VARIABLE_HEADER); + } else { + Value = sizeof (VARIABLE_HEADER); + } + + return Value; +} + +/** + This code gets the size of name of variable. + + @param Variable Pointer to the Variable Header. + @param AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + if ((AuthVariable->State == (UINT8)(-1)) || + (AuthVariable->DataSize == (UINT32)(-1)) || + (AuthVariable->NameSize == (UINT32)(-1)) || + (AuthVariable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)AuthVariable->NameSize; + } else { + if ((Variable->State == (UINT8)(-1)) || + (Variable->DataSize == (UINT32)(-1)) || + (Variable->NameSize == (UINT32)(-1)) || + (Variable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)Variable->NameSize; + } +} + +/** + This code gets the size of data of variable. + + @param Variable Pointer to the Variable Header. + @param AuthFlag Authenticated variable flag. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + if ((AuthVariable->State == (UINT8)(-1)) || + (AuthVariable->DataSize == (UINT32)(-1)) || + (AuthVariable->NameSize == (UINT32)(-1)) || + (AuthVariable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)AuthVariable->DataSize; + } else { + if ((Variable->State == (UINT8)(-1)) || + (Variable->DataSize == (UINT32)(-1)) || + (Variable->NameSize == (UINT32)(-1)) || + (Variable->Attributes == (UINT32)(-1))) + { + return 0; + } + + return (UINTN)Variable->DataSize; + } +} + +/** + This code gets the pointer to the variable name. + + @param Variable Pointer to the Variable Header. + @param AuthFlag Authenticated variable flag. + + @return A CHAR16* pointer to Variable Name. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag)); +} + +/** + This code gets the pointer to the variable guid. + + @param Variable Pointer to the Variable Header. + @param AuthFlag Authenticated variable flag. + + @return A EFI_GUID* pointer to Vendor Guid. + +**/ +EFI_GUID * +GetVendorGuidPtr ( + IN VARIABLE_HEADER *Variable, + IN BOOLEAN AuthFlag + ) +{ + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; + + AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable; + if (AuthFlag) { + return &AuthVariable->VendorGuid; + } else { + return &Variable->VendorGuid; + } +} + +/** + This code gets the pointer to the variable data. + + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to the Variable Header that has consecutive content. + @param AuthFlag Authenticated variable flag. + + @return A UINT8* pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN BOOLEAN AuthFlag + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment + // + Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag); + Value += NameSizeOfVariable (VariableHeader, AuthFlag); + Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag)); + + return (UINT8 *)Value; +} + +/** + This code gets the pointer to the next variable header. + + @param StoreInfo Pointer to variable store info structure. + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to the Variable Header that has consecutive content. + + @return A VARIABLE_HEADER* pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN Value; + + Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag); + Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag); + Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag)); + // + // Be careful about pad size for alignment + // + Value = HEADER_ALIGN (Value); + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) { + // + // Next variable is in spare block. + // + Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress); + } + } + + return (VARIABLE_HEADER *)Value; +} + +/** + Get variable store status. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store is raw + @retval EfiValid Variable store is valid + @retval EfiInvalid Variable store is invalid + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) && + (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) && + (VarStoreHeader->State == VARIABLE_STORE_HEALTHY) + ) + { + return EfiValid; + } + + if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) && + (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) && + (VarStoreHeader->Size == 0xffffffff) && + (VarStoreHeader->Format == 0xff) && + (VarStoreHeader->State == 0xff) + ) + { + return EfiRaw; + } else { + return EfiInvalid; + } +} + +/** + Compare two variable names, one of them may be inconsecutive. + + @param StoreInfo Pointer to variable store info structure. + @param Name1 Pointer to one variable name. + @param Name2 Pointer to another variable name. + @param NameSize Variable name size. + + @retval TRUE Name1 and Name2 are identical. + @retval FALSE Name1 and Name2 are not identical. + +**/ +BOOLEAN +CompareVariableName ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN CONST CHAR16 *Name1, + IN CONST CHAR16 *Name2, + IN UINTN NameSize + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialNameSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) { + // + // Name1 is inconsecutive. + // + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + + return FALSE; + } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) { + // + // Name2 is inconsecutive. + // + PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + + return FALSE; + } + } + + // + // Both Name1 and Name2 are consecutive. + // + if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) { + return TRUE; + } + + return FALSE; +} + +/** + This function compares a variable with variable entries in database. + + @param StoreInfo Pointer to variable store info structure. + @param Variable Pointer to the variable in our database + @param VariableHeader Pointer to the Variable Header that has consecutive content. + @param VariableName Name of the variable to compare to 'Variable' + @param VendorGuid GUID of the variable to compare to 'Variable' + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Found match variable + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +CompareWithValidVariable ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + VOID *Point; + EFI_GUID *TempVendorGuid; + + TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag); + + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } else { + // + // Don't use CompareGuid function here for performance reasons. + // Instead we compare the GUID a UINT32 at a time and branch + // on the first failed comparison. + // + if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) && + (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) && + (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) && + (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3]) + ) + { + ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0); + Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag); + if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Return the variable store header and the store info based on the Index. + + @param Type The type of the variable store. + @param StoreInfo Return the store info. + + @return Pointer to the variable store header. +**/ +VARIABLE_STORE_HEADER * +GetVariableStore ( + IN VARIABLE_STORE_TYPE Type, + OUT VARIABLE_STORE_INFO *StoreInfo + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT32 NvStorageSize; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + UINT32 BackUpOffset; + + StoreInfo->IndexTable = NULL; + StoreInfo->FtwLastWriteData = NULL; + StoreInfo->AuthFlag = FALSE; + VariableStoreHeader = NULL; + switch (Type) { + case VariableStoreTypeHob: + // + // Unsupported + // + break; + + case VariableStoreTypeNv: + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { + // + // Emulated non-volatile variable mode is not enabled. + // + + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); + NvStorageBase = (EFI_PHYSICAL_ADDRESS)(PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? + PcdGet64 (PcdFlashNvStorageVariableBase64) : + PcdGet32 (PcdFlashNvStorageVariableBase) + ); + ASSERT (NvStorageBase != 0); + + // + // First let FvHeader point to NV storage base. + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase; + + // + // Check the FTW last write data hob. + // + BackUpOffset = 0; + FaultTolerantWriteInitialize (); + if (mFtwLastWriteDataInitialized) { + FtwLastWriteData = &mFtwLastWriteData; + if (FtwLastWriteData->TargetAddress == NvStorageBase) { + // + // Let FvHeader point to spare block. + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FtwLastWriteData->SpareAddress; + DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress)); + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { + StoreInfo->FtwLastWriteData = FtwLastWriteData; + // + // Flash NV storage from the offset is backed up in spare block. + // + BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase); + DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress)); + // + // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base. + // + } + } + + // + // Check if the Firmware Volume is not corrupted + // + if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { + DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n")); + break; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength); + + StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)); + + StoreInfo->IndexTable = &mVariableIndexTable; + if (StoreInfo->IndexTable->StartPtr == NULL) { + // + // If it's the first time to access variable region in flash, create a guid hob to record + // VAR_ADDED type variable info. + // Note that as the resource of PEI phase is limited, only store the limited number of + // VAR_ADDED type variables to reduce access time. + // + StoreInfo->IndexTable->Length = 0; + StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); + StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); + StoreInfo->IndexTable->GoneThrough = 0; + } + } + + break; + + default: + ASSERT (FALSE); + break; + } + + StoreInfo->VariableStoreHeader = VariableStoreHeader; + return VariableStoreHeader; +} + +/** + Get variable header that has consecutive content. + + @param StoreInfo Pointer to variable store info structure. + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +GetVariableHeader ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + OUT VARIABLE_HEADER **VariableHeader + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialHeaderSize; + + if (Variable == NULL) { + return FALSE; + } + + // + // First assume variable header pointed by Variable is consecutive. + // + *VariableHeader = Variable; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)Variable > (UINTN)SpareAddress) && + (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader))) + { + // + // Reach the end of variable store. + // + return FALSE; + } + + if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) { + // + // Variable header pointed by Variable is inconsecutive, + // create a guid hob to combine the two partial variable header content together. + // + *VariableHeader = (VARIABLE_HEADER *)&mVariableHeaderFtw; + if (mVariableHeaderFtwMerged != TRUE) { + PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable; + // + // Partial content is in NV storage. + // + CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize); + // + // Another partial content is in spare block. + // + CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize); + + mVariableHeaderFtwMerged = TRUE; + } + } + } else { + if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) { + // + // Reach the end of variable store. + // + return FALSE; + } + } + + return IsValidVariableHeader (*VariableHeader); +} + +/** + Get variable name or data to output buffer. + + @param StoreInfo Pointer to variable store info structure. + @param NameOrData Pointer to the variable name/data that may be inconsecutive. + @param Size Variable name/data size. + @param Buffer Pointer to output buffer to hold the variable name/data. + +**/ +VOID +GetVariableNameOrData ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN UINT8 *NameOrData, + IN UINTN Size, + OUT UINT8 *Buffer + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) { + // + // Variable name/data is inconsecutive. + // + PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData; + // + // Partial content is in NV storage. + // + CopyMem (Buffer, NameOrData, PartialSize); + // + // Another partial content is in spare block. + // + CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize); + return; + } + } + + // + // Variable name/data is consecutive. + // + CopyMem (Buffer, NameOrData, Size); +} + +/** + Find the variable in the specified variable store. + + @param StoreInfo Pointer to the store info structure. + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found + @retval EFI_INVALID_PARAMETER Invalid variable name + +**/ +EFI_STATUS +FindVariableEx ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *LastVariable; + VARIABLE_HEADER *MaxIndex; + UINTN Index; + UINTN Offset; + BOOLEAN StopRecord; + VARIABLE_HEADER *InDeletedVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_INDEX_TABLE *IndexTable; + VARIABLE_HEADER *VariableHeader; + + VariableStoreHeader = StoreInfo->VariableStoreHeader; + + if (VariableStoreHeader == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { + return EFI_UNSUPPORTED; + } + + if (~VariableStoreHeader->Size == 0) { + return EFI_NOT_FOUND; + } + + IndexTable = StoreInfo->IndexTable; + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); + + InDeletedVariable = NULL; + + // + // No Variable Address equals zero, so 0 as initial value is safe. + // + MaxIndex = NULL; + VariableHeader = NULL; + + if (IndexTable != NULL) { + // + // traverse the variable index table to look for varible. + // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables. + // + for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) { + ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0])); + Offset += IndexTable->Index[Index]; + MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset); + GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader); + if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + return EFI_SUCCESS; + } + } + } + + if (IndexTable->GoneThrough != 0) { + // + // If the table has all the existing variables indexed, return. + // + PtrTrack->CurrPtr = InDeletedVariable; + return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; + } + } + + if (MaxIndex != NULL) { + // + // HOB exists but the variable cannot be found in HOB + // If not found in HOB, then let's start from the MaxIndex we've found. + // + Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader); + LastVariable = MaxIndex; + } else { + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable = PtrTrack->StartPtr; + LastVariable = PtrTrack->StartPtr; + } + + // + // Find the variable by walk through variable store + // + StopRecord = FALSE; + while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) { + if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) { + // + // Record Variable in VariableIndex HOB + // + if ((IndexTable != NULL) && !StopRecord) { + Offset = (UINTN)Variable - (UINTN)LastVariable; + if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) { + // + // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16), + // or the record buffer is full. + // + StopRecord = TRUE; + } else { + IndexTable->Index[IndexTable->Length++] = (UINT16)Offset; + LastVariable = Variable; + } + } + + if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = PtrTrack->CurrPtr; + } else { + return EFI_SUCCESS; + } + } + } + + Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader); + } + + // + // If gone through the VariableStore, that means we never find in Firmware any more. + // + if ((IndexTable != NULL) && !StopRecord) { + IndexTable->GoneThrough = 1; + } + + PtrTrack->CurrPtr = InDeletedVariable; + + return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; +} + +/** + Find the variable in HOB and Non-Volatile variable storages. + + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + @param StoreInfo Return the store info. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found + @retval EFI_INVALID_PARAMETER Invalid variable name +**/ +EFI_STATUS +FindVariable ( + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + OUT VARIABLE_STORE_INFO *StoreInfo + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_TYPE Type; + + if ((VariableName[0] != 0) && (VendorGuid == NULL)) { + return EFI_INVALID_PARAMETER; + } + + for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) { + GetVariableStore (Type, StoreInfo); + Status = FindVariableEx ( + StoreInfo, + VariableName, + VendorGuid, + PtrTrack + ); + if (!EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_NOT_FOUND; +} + +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + May be NULL with a zero DataSize in order to determine the size of the buffer needed. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable was be found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +BaseGetVariable ( + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + VARIABLE_STORE_INFO StoreInfo; + VARIABLE_HEADER *VariableHeader; + + if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (VariableName[0] == 0) { + return EFI_NOT_FOUND; + } + + VariableHeader = NULL; + + // + // Find existing variable + // + Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); + + // + // Get data size + // + VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag); + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + if (Attributes != NULL) { + *Attributes = VariableHeader->Attributes; + } + + *DataSize = VarDataSize; + + return Status; +} + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + On return, the size of the variable name buffer. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +BaseGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ) +{ + VARIABLE_STORE_TYPE Type; + VARIABLE_POINTER_TRACK Variable; + VARIABLE_POINTER_TRACK VariableInHob; + VARIABLE_POINTER_TRACK VariablePtrTrack; + UINTN VarNameSize; + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; + VARIABLE_HEADER *VariableHeader; + VARIABLE_STORE_INFO StoreInfo; + VARIABLE_STORE_INFO StoreInfoForNv; + VARIABLE_STORE_INFO StoreInfoForHob; + + if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + VariableHeader = NULL; + + Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); + if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); + } + + VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob); + VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv); + + while (TRUE) { + // + // Switch from HOB to Non-Volatile. + // + while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) { + // + // Find current storage index + // + for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) { + if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { + break; + } + } + + ASSERT (Type < VariableStoreTypeMax); + // + // Switch to next storage + // + for (Type++; Type < VariableStoreTypeMax; Type++) { + if (VariableStoreHeader[Type] != NULL) { + break; + } + } + + // + // Capture the case that + // 1. current storage is the last one, or + // 2. no further storage + // + if (Type == VariableStoreTypeMax) { + return EFI_NOT_FOUND; + } + + Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); + Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); + Variable.CurrPtr = Variable.StartPtr; + GetVariableStore (Type, &StoreInfo); + } + + if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + // + // If it is a IN_DELETED_TRANSITION variable, + // and there is also a same ADDED one at the same time, + // don't return it. + // + Status = FindVariableEx ( + &StoreInfo, + GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), + GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), + &VariablePtrTrack + ); + if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) { + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); + continue; + } + } + + // + // Don't return NV variable when HOB overrides it + // + if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && + (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) + ) + { + Status = FindVariableEx ( + &StoreInfoForHob, + GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), + GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), + &VariableInHob + ); + if (!EFI_ERROR (Status)) { + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); + continue; + } + } + + VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag); + ASSERT (VarNameSize != 0); + + if (VarNameSize <= *VariableNameSize) { + GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName); + + CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID)); + + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + // + // Variable is found + // + return Status; + } else { + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.inf new file mode 100644 index 0000000..f27a0fc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.inf @@ -0,0 +1,51 @@ +#/** @file +# +# Read-only non-volatile variable service library for early SEC phase. +# Based on FaultTolerantWritePei and VariablePei, without using any HOBs or PPIs. +# +# Copyright (c) 2024, Mario Bălănică +# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
    +# Copyright (c) Microsoft Corporation.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = BaseVariableLib + FILE_GUID = 0a9a1145-e20f-4d69-be68-eb13b3c3e4a3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseVariableLib + +[Sources] + BaseVariableLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + PcdLib + +[Guids] + gEdkiiWorkingBlockSignatureGuid ## SOMETIMES_CONSUMES ## GUID + gEfiAuthenticatedVariableGuid ## SOMETIMES_CONSUMES ## GUID + gEfiVariableGuid ## SOMETIMES_CONSUMES ## GUID + gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/Variable.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/Variable.h new file mode 100644 index 0000000..0d725ba --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/BaseVariableLib/Variable.h @@ -0,0 +1,45 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
    + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef _BASE_VARIABLE_H_ +#define _BASE_VARIABLE_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef enum { + VariableStoreTypeHob, + VariableStoreTypeNv, + VariableStoreTypeMax +} VARIABLE_STORE_TYPE; + +typedef struct { + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_INDEX_TABLE *IndexTable; + // + // If it is not NULL, it means there may be an inconsecutive variable whose + // partial content is still in NV storage, but another partial content is backed up + // in spare block. + // + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + BOOLEAN AuthFlag; +} VARIABLE_STORE_INFO; + +#endif // _BASE_VARIABLE_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.c new file mode 100644 index 0000000..4dcd6da --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.c @@ -0,0 +1,1048 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "Include/Library/CruLib.h" +#include +#include +#include +#include + +/** @addtogroup RK_HAL_Driver + * @{ + */ + +/** @addtogroup CRU + * @{ + */ + +/** @defgroup CRU_How_To_Use How To Use + * @{ + + The CRU driver can be used as follows: + + - Invoke cru functions to set clk rate, enable or disable clk, reset clk in each device. + - The gate and soft reset id is include register offset and shift information: + + con_offset: id /16 + shift: id %16 + + - The mux and div id is include register offset, shift, mask information: + + [15:0]: con + [23:16]: shift + [31:24]: width + + - CRU driver is just responsible for passing simple command data, And + the usecount is the user's responsibility. Protection the usecount at the driver layer. + - More details refer to APIs' descriptions as below. + + @} */ + +/** @defgroup CRU_Private_Definition Private Definition + * @{ + */ +/********************* Private MACRO Definition ******************************/ +#define PWRDOWN_SHIT 13 +#define PWRDOWN_MASK 1 << PWRDOWN_SHIT +#define PLL_POSTDIV1_SHIFT 12 +#define PLL_POSTDIV1_MASK 0x7 << PLL_POSTDIV1_SHIFT +#define PLL_FBDIV_SHIFT 0 +#define PLL_FBDIV_MASK 0xfff << PLL_FBDIV_SHIFT +#define PLL_POSTDIV2_SHIFT 6 +#define PLL_POSTDIV2_MASK 0x7 << PLL_POSTDIV2_SHIFT +#define PLL_REFDIV_SHIFT 0 +#define PLL_REFDIV_MASK 0x3f << PLL_REFDIV_SHIFT +#define PLL_DSMPD_SHIFT 12 +#define PLL_DSMPD_MASK 1 << PLL_DSMPD_SHIFT +#define PLL_FRAC_SHIFT 0 +#define PLL_FRAC_MASK 0xffffff << PLL_FRAC_SHIFT + +#define PLLCON0_M_SHIFT 0 +#define PLLCON0_M_MASK 0x3ff << PLLCON0_M_SHIFT +#define PLLCON1_P_SHIFT 0 +#define PLLCON1_P_MASK 0x3f << PLLCON1_P_SHIFT +#define PLLCON1_S_SHIFT 6 +#define PLLCON1_S_MASK 0x7 << PLLCON1_S_SHIFT +#define PLLCON2_K_SHIFT 0 +#define PLLCON2_K_MASK 0xffff << PLLCON2_K_SHIFT +#define PLLCON1_PWRDOWN BIT(13) +#define PLLCON6_LOCK_STATUS BIT(15) + +#define MIN_FOUTVCO_FREQ (800 * MHZ) +#define MAX_FOUTVCO_FREQ (2000 * MHZ) +#define MIN_FOUT_FREQ (24 * MHZ) +#define MAX_FOUT_FREQ (1600 * MHZ) + +#define RK3588_VCO_MIN_HZ (2250UL * MHZ) +#define RK3588_VCO_MAX_HZ (4500UL * MHZ) +#define RK3588_FOUT_MIN_HZ (37UL * MHZ) +#define RK3588_FOUT_MAX_HZ (4500UL * MHZ) + +#define EXPONENT_OF_FRAC_PLL 24 +#define RK_PLL_MODE_SLOW 0 +#define RK_PLL_MODE_NORMAL 1 +#define RK_PLL_MODE_DEEP 2 +#define PLL_GET_PLLMODE(val, shift, mask) (((uint32_t)(val) & mask) >> shift) + +#define PLL_GET_FBDIV(x) (((uint32_t)(x) & (PLL_FBDIV_MASK)) >> PLL_FBDIV_SHIFT) +#define PLL_GET_REFDIV(x) \ + (((uint32_t)(x) & (PLL_REFDIV_MASK)) >> PLL_REFDIV_SHIFT) +#define PLL_GET_POSTDIV1(x) \ + (((uint32_t)(x) & (PLL_POSTDIV1_MASK)) >> PLL_POSTDIV1_SHIFT) +#define PLL_GET_POSTDIV2(x) \ + (((uint32_t)(x) & (PLL_POSTDIV2_MASK)) >> PLL_POSTDIV2_SHIFT) +#define PLL_GET_DSMPD(x) (((uint32_t)(x) & (PLL_DSMPD_MASK)) >> PLL_DSMPD_SHIFT) +#define PLL_GET_FRAC(x) (((uint32_t)(x) & (PLL_FRAC_MASK)) >> PLL_FRAC_SHIFT) + +#define CRU_PLL_ROUND_UP_TO_KHZ(x) (HAL_DIV_ROUND_UP((x), KHZ) * KHZ) + +/********************* Private Structure Definition **************************/ +static struct PLL_CONFIG g_rockchipAutoTable; + +/********************* Private Variable Definition ***************************/ + +/********************* Private Function Definition ***************************/ + +/** Calculate the greatest common divisor */ +static uint32_t CRU_Gcd(uint32_t m, uint32_t n) +{ + int t; + + while (m > 0) { + if (n > m) { + t = m; + m = n; + n = t; + } + m -= n; + } + + return n; +} + +/** + * @brief Rockchip pll clk set postdiv. + * @param foutHz: output freq + * @param *postDiv1: pll postDiv1 + * @param *postDiv2: pll postDiv2 + * @param *foutVco: pll vco + * @return HAL_Status. + * How to calculate the PLL: + * Formulas also embedded within the fractional PLL Verilog model: + * If DSMPD = 1 (DSM is disabled, "integer mode") + * FOUTVCO = FREF / REFDIV * FBDIV + * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 + * Where: + * FOUTVCO = fractional PLL non-divided output frequency + * FOUTPOSTDIV = fractional PLL divided output frequency + * (output of second post divider) + */ +static HAL_Status CRU_PllSetPostDiv(uint32_t foutHz, uint32_t *postDiv1, + uint32_t *postDiv2, uint32_t *foutVco) +{ + uint32_t freq; + + if (foutHz < MIN_FOUTVCO_FREQ) { + for (*postDiv1 = 1; *postDiv1 <= 7; (*postDiv1)++) { + for (*postDiv2 = 1; *postDiv2 <= 7; (*postDiv2)++) { + freq = foutHz * (*postDiv1) * (*postDiv2); + if (freq >= MIN_FOUTVCO_FREQ && freq <= MAX_FOUTVCO_FREQ) { + *foutVco = freq; + + return HAL_OK; + } + } + } + + return HAL_ERROR; + } else { + *postDiv1 = 1; + *postDiv2 = 1; + + return HAL_OK; + } +} + +/** + * @brief Get pll parameter by auto. + * @param finHz: pll intput freq + * @param foutHz: pll output freq + * @return struct PLL_CONFIG. + * How to calculate the PLL: + * Formulas also embedded within the fractional PLL Verilog model: + * If DSMPD = 1 (DSM is disabled, "integer mode") + * FOUTVCO = FREF / REFDIV * FBDIV + * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 + * Where: + * FOUTVCO = fractional PLL non-divided output frequency + * FOUTPOSTDIV = fractional PLL divided output frequency + * (output of second post divider) + * FREF = fractional PLL input reference frequency, (the OSC_HZ 24MHz input) + * REFDIV = fractional PLL input reference clock divider + * FBDIV = Integer value programmed into feedback divide + */ +static const struct PLL_CONFIG *CRU_PllSetByAuto(uint32_t finHz, + uint32_t foutHz) +{ + struct PLL_CONFIG *rateTable = &g_rockchipAutoTable; + uint32_t foutVco = foutHz; + uint64_t fin64, frac64; + uint32_t postDiv1, postDiv2; + uint32_t clkGcd = 0; + HAL_Status error; + + if (finHz == 0 || foutHz == 0 || foutHz == finHz) { + return NULL; + } + + error = CRU_PllSetPostDiv(foutHz, &postDiv1, &postDiv2, &foutVco); + if (error) { + return NULL; + } + rateTable->postDiv1 = postDiv1; + rateTable->postDiv2 = postDiv2; + rateTable->dsmpd = 1; + + if (finHz / MHZ * MHZ == finHz && foutHz / MHZ * MHZ == foutHz) { + finHz /= MHZ; + foutVco /= MHZ; + clkGcd = CRU_Gcd(finHz, foutVco); + rateTable->refDiv = finHz / clkGcd; + rateTable->fbDiv = foutVco / clkGcd; + + rateTable->frac = 0; + } else if (finHz / MHZ * MHZ != finHz) { + clkGcd = foutHz / finHz; + rateTable->fbDiv = clkGcd; + rateTable->refDiv = 1; + rateTable->postDiv1 = 1; + rateTable->postDiv2 = 1; + + fin64 = foutHz * rateTable->refDiv; + fin64 = HAL_DivU64(fin64 << EXPONENT_OF_FRAC_PLL, finHz); + frac64 = rateTable->fbDiv; + frac64 = rateTable->fbDiv << EXPONENT_OF_FRAC_PLL; + frac64 = fin64 - frac64; + rateTable->frac = frac64; + if (rateTable->frac > 0) { + rateTable->dsmpd = 0; + } + } else { + clkGcd = CRU_Gcd(finHz / MHZ, foutVco / MHZ); + rateTable->refDiv = finHz / MHZ / clkGcd; + rateTable->fbDiv = foutVco / MHZ / clkGcd; + rateTable->frac = 0; + + frac64 = (foutVco % MHZ); + fin64 = finHz; + frac64 = frac64 * rateTable->refDiv; + frac64 = HAL_DivU64(frac64 << EXPONENT_OF_FRAC_PLL, fin64); + rateTable->frac = frac64; + if (rateTable->frac > 0) { + rateTable->dsmpd = 0; + } + } + + return rateTable; +} + +/** + * @brief Get pll parameter by rateTable. + * @param *pSetup: struct PLL_SETUP struct, Contains PLL register parameters + * @param rate: pll target rate. + * @return struct PLL_CONFIG. + * How to calculate the PLL: + * Look up the rateTable to get the PLL config parameter + */ +static const struct PLL_CONFIG *CRU_PllGetSettings(struct PLL_SETUP *pSetup, + uint32_t rate) +{ + const struct PLL_CONFIG *rateTable = pSetup->rateTable; + + if (rateTable == NULL) { + return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate); + } + + while (rateTable->rate) { + if (rateTable->rate == rate) { + break; + } + rateTable++; + } + if (rateTable->rate != rate) { + return CRU_PllSetByAuto(PLL_INPUT_OSC_RATE, rate); + } else { + return rateTable; + } +} + +static const struct PLL_CONFIG *CRU_PllV1SetByAuto(uint32_t fin_hz, + uint32_t fout_hz) +{ + struct PLL_CONFIG *rate_table = &g_rockchipAutoTable; + uint32_t p, m, s; + uint64_t fvco, fref, fout, ffrac; + + if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) + return NULL; + + if (fout_hz > RK3588_FOUT_MAX_HZ || fout_hz < RK3588_FOUT_MIN_HZ) + return NULL; + + for (s = 0; s <= 6; s++) { + fvco = fout_hz << s; + if (fvco < RK3588_VCO_MIN_HZ || + fvco > RK3588_VCO_MAX_HZ) + continue; + for (p = 1; p <= 4; p++) { + for (m = 64; m <= 1023; m++) { + if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) { + rate_table->p = p; + rate_table->m = m; + rate_table->s = s; + fref = fin_hz / p; + ffrac = fvco - (m * fref); + fout = ffrac * 65536; + rate_table->k = fout / fref; + return rate_table; + } + } + } + } + + DEBUG((DEBUG_ERROR, "%a: CANNOT FIND Fout by auto,fout = %lu\n", __func__, fout_hz)); + return NULL; +} + +/** + * @brief Get pll parameter by rateTable. (RK3588) + * @param *pSetup: struct PLL_SETUP struct, Contains PLL register parameters + * @param rate: pll target rate. + * @return struct PLL_CONFIG. + * How to calculate the PLL: + * Look up the rateTable to get the PLL config parameter + */ +static const struct PLL_CONFIG *CRU_PllV1GetSettings(struct PLL_SETUP *pSetup, + uint32_t rate) +{ + const struct PLL_CONFIG *rateTable = pSetup->rateTable; + + if (rateTable == NULL) { + return CRU_PllV1SetByAuto(PLL_INPUT_OSC_RATE, rate); + } + + while (rateTable->rate) { + if (rateTable->rate == rate) { + break; + } + rateTable++; + } + if (rateTable->rate != rate) { + return CRU_PllV1SetByAuto(PLL_INPUT_OSC_RATE, rate); + } else { + return rateTable; + } +} + +/** @} */ +/********************* Public Function Definition ****************************/ + +/** @defgroup CRU_Exported_Functions_Group5 Other Functions + * @attention these APIs allow direct use in the HAL layer. + * @{ + */ + +/** + * @brief Get pll freq. + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @return pll rate. + * How to calculate the PLL: + * Formulas also embedded within the fractional PLL Verilog model: + * If DSMPD = 1 (DSM is disabled, "integer mode") + * FOUTVCO = FREF / REFDIV * FBDIV + * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2 + * If DSMPD = 0 (DSM is enabled, "fractional mode") + * FOUTVCO = (FREF / REFDIV) * (FBDIV + FRAC / (2^24)) + * FOUTPOSTDIV = FOUTVCO / (POSTDIV1*POSTDIV2) + * FOUT = FOUTVCO / POSTDIV1 / POSTDIV2 + */ +uint32_t HAL_CRU_GetPllFreq(struct PLL_SETUP *pSetup) +{ + uint32_t refDiv, fbDiv, postdDv1, postDiv2, frac, dsmpd; + uint32_t mode = 0, rate = PLL_INPUT_OSC_RATE; + + mode = PLL_GET_PLLMODE(READ_REG(*(pSetup->modeOffset)), pSetup->modeShift, + pSetup->modeMask); + + switch (mode) { + case RK_PLL_MODE_SLOW: + rate = PLL_INPUT_OSC_RATE; + break; + case RK_PLL_MODE_NORMAL: + postdDv1 = PLL_GET_POSTDIV1(READ_REG(*(pSetup->conOffset0))); + fbDiv = PLL_GET_FBDIV(READ_REG(*(pSetup->conOffset0))); + postDiv2 = PLL_GET_POSTDIV2(READ_REG(*(pSetup->conOffset1))); + refDiv = PLL_GET_REFDIV(READ_REG(*(pSetup->conOffset1))); + dsmpd = PLL_GET_DSMPD(READ_REG(*(pSetup->conOffset1))); + frac = PLL_GET_FRAC(READ_REG(*(pSetup->conOffset2))); + rate = (rate / refDiv) * fbDiv; + if (dsmpd == 0) { + uint64_t fracRate = PLL_INPUT_OSC_RATE; + + fracRate *= frac; + fracRate = fracRate >> EXPONENT_OF_FRAC_PLL; + fracRate = fracRate / refDiv; + rate += fracRate; + } + rate = rate / (postdDv1 * postDiv2); + rate = CRU_PLL_ROUND_UP_TO_KHZ(rate); + break; + case RK_PLL_MODE_DEEP: + default: + rate = 32768; + break; + } + + return rate; +} + +/** + * @brief Set pll freq. + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @param rate: pll set rate + * @return HAL_Status. + * How to calculate the PLL: + * Force PLL into slow mode + * Pll Power down + * Pll Config fbDiv, refDiv, postdDv1, postDiv2, dsmpd, frac + * Pll Power up + * Waiting for pll lock + * Force PLL into normal mode + */ +HAL_Status HAL_CRU_SetPllFreq(struct PLL_SETUP *pSetup, uint32_t rate) +{ + const struct PLL_CONFIG *pConfig; + int delay = 2400; + + if (rate == HAL_CRU_GetPllFreq(pSetup)) { + return HAL_OK; + } else if (rate < MIN_FOUT_FREQ) { + return HAL_INVAL; + } else if (rate > MAX_FOUT_FREQ) { + return HAL_INVAL; + } + + pConfig = CRU_PllGetSettings(pSetup, rate); + if (!pConfig) { + return HAL_ERROR; + } + + /* Force PLL into slow mode to ensure output stable clock */ + WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift); + + /* Pll Power down */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIT); + + /* Pll Config */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_POSTDIV2_MASK, pConfig->postDiv2 << PLL_POSTDIV2_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_REFDIV_MASK, pConfig->refDiv << PLL_REFDIV_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_POSTDIV1_MASK, pConfig->postDiv1 << PLL_POSTDIV1_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLL_FBDIV_MASK, pConfig->fbDiv << PLL_FBDIV_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLL_DSMPD_MASK, pConfig->dsmpd << PLL_DSMPD_SHIFT); + + if (pConfig->frac) { + WRITE_REG(*(pSetup->conOffset2), (READ_REG(*(pSetup->conOffset2)) & 0xff000000) | pConfig->frac); + } + + /* Pll Power up */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIT); + + /* Waiting for pll lock */ + while (delay > 0) { + if (pSetup->stat0) { + if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) { + break; + } + } else { + if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) { + break; + } + } + HAL_CPUDelayUs(1000); + delay--; + } + if (delay == 0) { + return HAL_TIMEOUT; + } + + /* Force PLL into normal mode */ + WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift); + + return HAL_OK; +} + +/** + * @brief Get pll v1 freq(RK3588). + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @return pll rate. + * How to calculate the PLL: + * Formulas also embedded within the fractional PLL Verilog model: + * If K = 0 (DSM is disabled, "integer mode") + * FOUTVCO = FREF / P * M + * FOUT = FOUTVCO / 2^S + * If K > 0 (DSM is enabled, "fractional mode") + * FOUTVCO = (FREF / P) * (M + K / 65536) + * FOUT = FOUTVCO / 2^S + */ +uint32_t HAL_CRU_GetPllV1Freq(struct PLL_SETUP *pSetup) +{ + uint32_t m, p, s, k; + uint64_t rate = PLL_INPUT_OSC_RATE; + uint32_t mode = 0; + + if (pSetup->modeMask) + mode = PLL_GET_PLLMODE(READ_REG(*(pSetup->modeOffset)), pSetup->modeShift, + pSetup->modeMask); + else + mode = RK_PLL_MODE_NORMAL; + + switch (mode) { + case RK_PLL_MODE_SLOW: + rate = PLL_INPUT_OSC_RATE; + break; + case RK_PLL_MODE_NORMAL: + m = (READ_REG(*(pSetup->conOffset0)) & PLLCON0_M_MASK) >> PLLCON0_M_SHIFT; + p = (READ_REG(*(pSetup->conOffset1)) & PLLCON1_P_MASK) >> PLLCON1_P_SHIFT; + s = (READ_REG(*(pSetup->conOffset1)) & PLLCON1_S_MASK) >> PLLCON1_S_SHIFT; + k = (READ_REG(*(pSetup->conOffset2)) & PLLCON2_K_MASK) >> PLLCON2_K_SHIFT; + + rate *= m; + rate = rate / p; + if (k) { + /* fractional mode */ + uint64_t frac = PLL_INPUT_OSC_RATE / p; + + frac *= k; + frac = frac / 65536; + rate += frac; + } + rate = rate >> s; + + break; + case RK_PLL_MODE_DEEP: + default: + rate = 32768; + break; + } + + return rate; +} + +/** + * @brief Set pll v1 freq(RK3588). + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @param rate: pll set rate + * @return HAL_Status. + * How to calculate the PLL: + * Force PLL into slow mode + * Pll Power down + * Pll Config M, P, S, K + * Pll Power up + * Waiting for pll lock + * Force PLL into normal mode + */ +HAL_Status HAL_CRU_SetPllV1Freq(struct PLL_SETUP *pSetup, uint32_t rate) +{ + const struct PLL_CONFIG *pConfig; + int delay = 24000000; + + if (rate == HAL_CRU_GetPllV1Freq(pSetup)) { + return HAL_OK; + } else if (rate < RK3588_FOUT_MIN_HZ) { + return HAL_INVAL; + } else if (rate > RK3588_FOUT_MAX_HZ) { + return HAL_INVAL; + } + + pConfig = CRU_PllV1GetSettings(pSetup, rate); + if (!pConfig) { + return HAL_ERROR; + } + + /* Force PLL into slow mode to ensure output stable clock */ + if (pSetup->modeMask) + WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_SLOW << pSetup->modeShift); + + /* Pll Power down */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIT); + + /* Pll Config */ + WRITE_REG_MASK_WE(*(pSetup->conOffset0), PLLCON0_M_MASK, pConfig->m << PLLCON0_M_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLLCON1_P_MASK, pConfig->p << PLLCON1_P_SHIFT); + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PLLCON1_S_MASK, pConfig->s << PLLCON1_S_SHIFT); + if (pConfig->k) + WRITE_REG_MASK_WE(*(pSetup->conOffset2), PLLCON2_K_MASK, pConfig->k << PLLCON2_K_SHIFT); + + /* Pll Power up */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIT); + + /* Waiting for pll lock */ + while (delay > 0) { + if (READ_REG(*(pSetup->conOffset6)) & (1 << pSetup->lockShift)) { + break; + } + delay--; + } + if (delay == 0) { + return HAL_TIMEOUT; + } + + /* Force PLL into normal mode */ + if (pSetup->modeMask) + WRITE_REG_MASK_WE(*(pSetup->modeOffset), pSetup->modeMask, RK_PLL_MODE_NORMAL << pSetup->modeShift); + + return HAL_OK; +} + +/** + * @brief Set pll power up. + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @return HAL_Status. + */ +HAL_Status HAL_CRU_SetPllPowerUp(struct PLL_SETUP *pSetup) +{ + int delay = 2400; + + /* Pll Power up */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 0 << PWRDOWN_SHIT); + + /* Waiting for pll lock */ + while (delay > 0) { + if (pSetup->stat0) { + if (READ_REG(*(pSetup->stat0)) & (1 << pSetup->lockShift)) { + break; + } + } else { + if (READ_REG(*(pSetup->conOffset1)) & (1 << pSetup->lockShift)) { + break; + } + } + HAL_CPUDelayUs(1000); + delay--; + } + if (delay == 0) { + return HAL_TIMEOUT; + } + + return HAL_OK; +} + +/** + * @brief Set pll power down. + * @param *pSetup: struct PLL_SETUP struct,Contains PLL register parameters + * @return HAL_Status. + */ +HAL_Status HAL_CRU_SetPllPowerDown(struct PLL_SETUP *pSetup) +{ + /* Pll Power down */ + WRITE_REG_MASK_WE(*(pSetup->conOffset1), PWRDOWN_MASK, 1 << PWRDOWN_SHIT); + + return HAL_OK; +} + +/** + * @brief IP Clock is Enabled API + * @param clk: clk gate id + * @return HAL_Check + */ +HAL_Check HAL_CRU_ClkIsEnabled(uint32_t clockId) +{ + CRU_CLOCK *clk; + uint32_t index, shift, address; + HAL_Check ret; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL) { + ASSERT (FALSE); + return HAL_FALSE; + } else if ((clk->flags & CLOCK_SUPPORT_GATE) == 0) { + return HAL_TRUE; + } + + index = CLK_GATE_GET_REG_OFFSET(clk->gate); + shift = CLK_GATE_GET_BITS_SHIFT(clk->gate); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->gateOffset, index); + + ret = (HAL_Check)(!((MmioRead32(address) & (1 << shift)) >> shift)); + + return ret; +} + +/** + * @brief IP Clock Enable API + * @param clk: clk gate id + * @return NONE + */ +HAL_Status HAL_CRU_ClkEnable(uint32_t clockId) +{ + CRU_CLOCK *clk; + uint32_t index, shift, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_GATE) == 0) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_GATE_GET_REG_OFFSET(clk->gate); + shift = CLK_GATE_GET_BITS_SHIFT(clk->gate); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->gateOffset, index); + + MmioWrite32(address, VAL_MASK_WE(1U << shift, 0U << shift)); + + return HAL_OK; +} + +/** + * @brief IP Clock Disabled API + * @param clk: clk gate id + * @return NONE + */ +HAL_Status HAL_CRU_ClkDisable(uint32_t clockId) +{ + CRU_CLOCK *clk; + uint32_t index, shift, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_GATE) == 0) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_GATE_GET_REG_OFFSET(clk->gate); + shift = CLK_GATE_GET_BITS_SHIFT(clk->gate); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->gateOffset, index); + + MmioWrite32(address, VAL_MASK_WE(1U << shift, 1U << shift)); + + return HAL_OK; +} + +/** + * @brief IP Clock set div API + * @param clockId: div id(Contains div offset, shift, mask information) + * @param divValue: div value + * @return NONE + */ +HAL_Status HAL_CRU_ClkSetDiv(uint32_t clockId, uint32_t divValue) +{ + CRU_CLOCK *clk; + uint32_t shift, mask, index, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_DIV) == 0) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_DIV_GET_REG_OFFSET(clk->div); + shift = CLK_DIV_GET_BITS_SHIFT(clk->div); + HAL_ASSERT(shift < 16); + mask = CLK_DIV_GET_MASK(clk->div); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->divOffset, index); + + if (divValue > mask) { + divValue = mask; + } + + MmioWrite32(address, VAL_MASK_WE(mask, (divValue - 1U) << shift)); + + return HAL_OK; +} + +/** + * @brief IP Clock get div API + * @param clockId: div id(Contains div offset, shift, mask information) + * @return div value + */ +uint32_t HAL_CRU_ClkGetDiv(uint32_t clockId) +{ + CRU_CLOCK *clk; + uint32_t shift, mask, index, divValue, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_DIV) == 0) { + ASSERT (clk != NULL); + return 1; + } + + index = CLK_DIV_GET_REG_OFFSET(clk->div); + shift = CLK_DIV_GET_BITS_SHIFT(clk->div); + HAL_ASSERT(shift < 16); + mask = CLK_DIV_GET_MASK(clk->div); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->divOffset, index); + + divValue = ((MmioRead32(address) & mask) >> shift) + 1; + + return divValue; +} + +/** + * @brief IP Clock set mux API + * @param clockId: mux id(Contains mux offset, shift, mask information) + * @param muxValue: mux value + * @return NONE + */ +HAL_SECTION_SRAM_CODE +HAL_Status HAL_CRU_ClkSetMux(uint32_t clockId, uint32_t muxValue) +{ + CRU_CLOCK *clk; + uint32_t shift, mask, index, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_MUX) == 0) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_MUX_GET_REG_OFFSET(clk->mux); + shift = CLK_MUX_GET_BITS_SHIFT(clk->mux); + HAL_ASSERT(shift < 16); + mask = CLK_MUX_GET_MASK(clk->mux); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->muxOffset, index); + + MmioWrite32(address, VAL_MASK_WE(mask, muxValue << shift)); + + return HAL_OK; +} + +/** + * @brief IP Clock get mux API + * @param clockId: mux id(Contains mux offset, shift, mask information) + * @return mux value + */ +HAL_SECTION_SRAM_CODE +uint32_t HAL_CRU_ClkGetMux(uint32_t clockId) +{ + CRU_CLOCK *clk; + uint32_t shift, mask, index, muxValue, address; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL || (clk->flags & CLOCK_SUPPORT_MUX) == 0) { + ASSERT (FALSE); + return 0; + } + + index = CLK_MUX_GET_REG_OFFSET(clk->mux); + shift = CLK_MUX_GET_BITS_SHIFT(clk->mux); + HAL_ASSERT(shift < 16); + mask = CLK_MUX_GET_MASK(clk->mux); + address = CRU_CON_REG_ADDRESS(clk->regBase, clk->muxOffset, index); + + muxValue = ((MmioRead32(address) & mask) >> shift); + + return muxValue; +} + +/** + * @brief Get frac div config. + * @param rateOut: clk out rate. + * @param rate: clk src rate. + * @param numerator: the returned numerator. + * @param denominator: the returned denominator. + * @return HAL_Status. + */ +HAL_Status HAL_CRU_FracdivGetConfig(uint32_t rateOut, uint32_t rate, + uint32_t *numerator, + uint32_t *denominator) +{ + uint32_t gcdVal; + + gcdVal = CRU_Gcd(rate, rateOut); + if (!gcdVal) { + return HAL_ERROR; + } + + *numerator = rateOut / gcdVal; + *denominator = rate / gcdVal; + + if (*numerator < 4) { + *numerator *= 4; + *denominator *= 4; + } + if (*numerator > 0xffff || *denominator > 0xffff) { + return HAL_INVAL; + } + + return HAL_OK; +} + +/** + * @brief Get Np5 best div. + * @param clockId: clk id. + * @param rate: clk rate. + * @param pRate: clk parent rate + * @param bestdiv: the returned bestdiv. + * @return HAL_Status. + */ +HAL_Status HAL_CRU_ClkNp5BestDiv(uint32_t clockId, uint32_t rate, uint32_t pRate, uint32_t *bestdiv) +{ + CRU_CLOCK *clk; + uint32_t maxDiv; + uint32_t i; + + clk = HAL_CRU_ClkGetById(clockId); + if (clk == NULL) { + return HAL_ERROR; + } + + maxDiv = CLK_DIV_GET_MASK(clk->div); + + for (i = 0; i < maxDiv; i++) { + if (((pRate * 2) == (rate * (i * 2 + 3)))) { + *bestdiv = i; + + return HAL_OK; + } + } + + return HAL_ERROR; +} + +/** + * @brief vop dclk enable. + * @param gateId: gate id + * @return HAL_Status. + * @attention these APIs allow direct use in the HAL layer. + */ +__WEAK HAL_Status HAL_CRU_VopDclkEnable(uint32_t gateId) +{ + HAL_CRU_ClkEnable(gateId); + + return HAL_OK; +} + +/** + * @brief vop dclk disable. + * @param gateId: gate id + * @return HAL_Status. + * @attention these APIs allow direct use in the HAL layer. + */ +__WEAK HAL_Status HAL_CRU_VopDclkDisable(uint32_t gateId) +{ + HAL_CRU_ClkDisable(gateId); + + return HAL_OK; +} + +/** + * @brief assert CRU global software reset. + * @param type: global software reset type. + * @return HAL_INVAL if the SoC does not support. + */ +HAL_Status HAL_CRU_SetGlbSrst(eCRU_GlbSrstType type) +{ +#ifdef CRU_GLB_SRST_FST_VALUE_OFFSET + if (type == GLB_SRST_FST) { + CRU->GLB_SRST_FST_VALUE = GLB_SRST_FST; + } +#endif +#ifdef CRU_GLB_SRST_SND_VALUE_OFFSET + if (type == GLB_SRST_SND) { + CRU->GLB_SRST_SND_VALUE = GLB_SRST_SND; + } +#endif + + return HAL_INVAL; +} + +/** + * @brief IP Clock is reset API + * @param clk: clk reset id + * @return HAL_Check + */ +HAL_Check HAL_CRU_RstIsAsserted(uint32_t resetId) +{ + CRU_RESET *rst; + uint32_t index, shift, address; + HAL_Check ret; + + rst = HAL_CRU_RstGetById(resetId); + if (rst == NULL) { + ASSERT (FALSE); + return HAL_FALSE; + } + + index = CLK_RESET_GET_REG_OFFSET(rst->srst); + shift = CLK_RESET_GET_BITS_SHIFT(rst->srst); + HAL_ASSERT(shift < 16); + address = CRU_CON_REG_ADDRESS(rst->regBase, rst->srstOffset, index); + + ret = (HAL_Check)((MmioRead32(address) & (1 << shift)) >> shift); + + return ret; +} + +/** + * @brief IP Clock Reset Assert API + * @param clk: clk reset id + * @return NONE + */ +HAL_Status HAL_CRU_RstAssert(uint32_t resetId) +{ + CRU_RESET *rst; + uint32_t index, shift, address; + + rst = HAL_CRU_RstGetById(resetId); + if (rst == NULL) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_RESET_GET_REG_OFFSET(rst->srst); + shift = CLK_RESET_GET_BITS_SHIFT(rst->srst); + HAL_ASSERT(shift < 16); + address = CRU_CON_REG_ADDRESS(rst->regBase, rst->srstOffset, index); + + MmioWrite32(address, VAL_MASK_WE(1U << shift, 1U << shift)); + + return HAL_OK; +} + +/** + * @brief IP Clock Reset Deassert API + * @param clk: clk reset id + * @return NONE + */ +HAL_Status HAL_CRU_RstDeassert(uint32_t resetId) +{ + CRU_RESET *rst; + uint32_t index, shift, address; + + rst = HAL_CRU_RstGetById(resetId); + if (rst == NULL) { + ASSERT (FALSE); + return HAL_ERROR; + } + + index = CLK_RESET_GET_REG_OFFSET(rst->srst); + shift = CLK_RESET_GET_BITS_SHIFT(rst->srst); + HAL_ASSERT(shift < 16); + address = CRU_CON_REG_ADDRESS(rst->regBase, rst->srstOffset, index); + + MmioWrite32(address, VAL_MASK_WE(1U << shift, 0U << shift)); + + return HAL_OK; +} + +/** @} */ + +/** @} */ + +/** @} */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.inf new file mode 100644 index 0000000..2c07344 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/CruLib/CruLib.inf @@ -0,0 +1,39 @@ +#/** @file +# +# Copyright (c) 2017, Rockchip Inc. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CruLib + FILE_GUID = e4457c4c-2cca-11ec-95b4-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CruLib + +[Sources.common] + CruLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + DebugLib + IoLib + RockchipPlatformLib + +[BuildOptions] + +[Pcd] + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.c new file mode 100644 index 0000000..cd58702 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.c @@ -0,0 +1,1311 @@ +/** @file + Rockchip eDP Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +# define DP_MAX_LINK_RATE 0x001 +# define DP_MAX_LANE_COUNT 0x002 + +#define DP_LANE0_1_STATUS 0x202 +#define DP_LANE2_3_STATUS 0x203 +# define DP_LANE_CR_DONE (1 << 0) +# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) +# define DP_LANE_SYMBOL_LOCKED (1 << 2) + +#define DP_TRAINING_LANE0_SET 0x103 +#define DP_TRAINING_LANE1_SET 0x104 +#define DP_TRAINING_LANE2_SET 0x105 +#define DP_TRAINING_LANE3_SET 0x106 + +#define DP_LINK_BW_SET 0x100 +# define DP_LINK_BW_1_62 0x06 +# define DP_LINK_BW_2_7 0x0a +# define DP_LINK_BW_5_4 0x14 /* 1.2 */ +# define DP_LINK_BW_8_1 0x1e /* 1.4 */ + +#define DP_ADJUST_REQUEST_LANE0_1 0x206 +#define DP_ADJUST_REQUEST_LANE2_3 0x207 + +#define DP_DOWNSPREAD_CTRL 0x107 +# define DP_SPREAD_AMP_0_5 (1 << 4) +#define DP_MAX_DOWNSPREAD 0x003 +# define DP_MAX_DOWNSPREAD_0_5 (1 << 0) + +#define DP_SET_ANSI_8B10B (1 << 0) + +#define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 +# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 +# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0) +# define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0) + +#define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3) +# define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3) + +#define DP_TRAINING_PATTERN_SET 0x102 +# define DP_TRAINING_PATTERN_DISABLE 0 +# define DP_TRAINING_PATTERN_1 1 +# define DP_TRAINING_PATTERN_2 2 +# define DP_TRAINING_PATTERN_3 3 /* 1.2 */ +# define DP_TRAINING_PATTERN_4 7 /* 1.4 */ +# define DP_TRAINING_PATTERN_MASK 0x3 +# define DP_TRAINING_PATTERN_MASK_1_4 0xf +# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + +#define DP_LINK_SCRAMBLING_DISABLE (1 << 5) + +#define DP_LANE_COUNT_SET 0x101 +# define DP_LANE_COUNT_MASK 0x0f +# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) + +#define DP_INTERLANE_ALIGN_DONE (1 << 0) +#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) +#define DP_LINK_STATUS_UPDATED (1 << 7) +#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | DP_LANE_CHANNEL_EQ_DONE | DP_LANE_SYMBOL_LOCKED) +#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 + +#define EIO 5 /* I/O error */ +#define ENODEV 19 /* No such device */ + +/* DRM-DP-HELPER */ +STATIC +VOID +DrmDpLinkTrainClockRecoveryDelay ( + CONST UINT8 Dpcd[DP_RECEIVER_CAP_SIZE] + ) +{ + INT32 RdInterval = Dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + + if (RdInterval > 4) + DEBUG ((DEBUG_WARN, "AUX interval %d, out of range (max 4)\n", RdInterval)); + + if (RdInterval == 0 || Dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) + NanoSecondDelay(100000); + else + MicroSecondDelay (RdInterval * 4); +} + +STATIC +VOID +DrmDpLinkTrainChannelEqDelay ( + CONST UINT8 Dpcd[DP_RECEIVER_CAP_SIZE] + ) +{ + INT32 RdInterval = Dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + + if (RdInterval > 4) + DEBUG ((DEBUG_WARN, "AUX interval %d, out of range (max 4)\n", RdInterval)); + + if (RdInterval == 0) + NanoSecondDelay(400000); + else + MicroSecondDelay (RdInterval * 4); +} + +STATIC +INT32 +DrmDpBwCodeToLinkRate ( + UINT8 LinkBw + ) +{ + switch(LinkBw) { + default: + DEBUG ((DEBUG_WARN, "Unknown DP link BW code %x, using 162000\n", LinkBw)); + case DP_LINK_BW_1_62: + return 162000; + case DP_LINK_BW_2_7: + return 270000; + case DP_LINK_BW_5_4: + return 540000; + case DP_LINK_BW_8_1: + return 810000; + } +} + +VOID +AnalogixDpEnableScramble ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT8 Data; + + if (Enable) { + AnalogixDpEnableScrambling(Dp); + + AnalogixDpReadByteFromDpcd(Dp, DP_TRAINING_PATTERN_SET, + &Data); + AnalogixDpWriteByteToDpcd(Dp, + DP_TRAINING_PATTERN_SET, + (UINT8)(Data & ~DP_LINK_SCRAMBLING_DISABLE)); + } else { + AnalogixDpDisableScrambling(Dp); + + AnalogixDpReadByteFromDpcd(Dp, DP_TRAINING_PATTERN_SET, + &Data); + AnalogixDpWriteByteToDpcd(Dp, + DP_TRAINING_PATTERN_SET, + (UINT8)(Data | DP_LINK_SCRAMBLING_DISABLE)); + } +} + +BOOLEAN +AnalogixDpGetPllLockStatus ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + UINTN i; + + for(i = 0; i < 20; i++) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_DEBUG_CTL); + MicroSecondDelay (20); + } + + if (Reg & PLL_LOCK) { + return PLL_LOCKED; + } else { + DEBUG ((DEBUG_WARN, "Pll unlocked \n")); + return PLL_UNLOCKED; + } +} + +VOID +AnalogixDpEnableRxToEnhancedMode ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT8 Data; + + AnalogixDpReadByteFromDpcd(Dp, DP_LANE_COUNT_SET, &Data); + + if (Enable) + AnalogixDpWriteByteToDpcd(Dp, DP_LANE_COUNT_SET, + DP_LANE_COUNT_ENHANCED_FRAME_EN | DPCD_LANE_COUNT_SET(Data)); + else + AnalogixDpWriteByteToDpcd(Dp, DP_LANE_COUNT_SET, + DPCD_LANE_COUNT_SET(Data)); +} + +VOID +AnalogixDpEnableEnhancedMode ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT32 Reg; + + if (Enable) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_4); + Reg |= ENHANCED; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_4,Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_4); + Reg &= ~ENHANCED; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_4,Reg); + } +} + +VOID +AnalogixDpInitVideo ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_1, Reg); + + Reg = 0x0; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_1, Reg); + + Reg = CHA_CRI(4) | CHA_CTRL; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_2, Reg); + + Reg = 0x0; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_3, Reg); + + Reg = VID_HRES_TH(2) | VID_VRES_TH(0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_8, Reg); +} + +VOID +AnalogixDpResetMacro ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_PHY_TEST); + Reg |= MACRO_RST; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PHY_TEST, Reg); + + /* 10 us is the minimum reset time. */ + NanoSecondDelay (20000); + + Reg &= ~MACRO_RST; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PHY_TEST, Reg); +} + +STATIC +VOID +AnalogixDpGetMaxRxBandwidth ( + OUT struct AnalogixDpDevice *Dp, + IN UINT8 *Bandwidth + ) +{ + UINT8 Data; + /* + * For DP rev.1.1, Maximum link rate of Main Link Lanes + * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps + * For DP rev.1.2, Maximum link rate of Main Link Lanes + * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps + */ + AnalogixDpReadByteFromDpcd(Dp, DP_MAX_LINK_RATE, &Data); + *Bandwidth = Data; +} + +STATIC +VOID +AnalogixDpGetMaxRxLaneCount ( + OUT struct AnalogixDpDevice *Dp, + IN UINT8 *LaneCount + ) +{ + UINT8 Data; + + /* + * For DP rev.1.1, Maximum number of Main Link Lanes + * 0x01 = 1 Lane, 0x02 = 2 Lanes, 0x04 = 4 Lanes + */ + AnalogixDpReadByteFromDpcd(Dp, DP_MAX_LANE_COUNT, &Data); + *LaneCount = DPCD_MAX_LANE_COUNT(Data); +} + +UINTN +AnalogixDpInitTraining ( + OUT struct AnalogixDpDevice *Dp, + enum LinkLaneCountType MaxLane, + INT32 MaxRate + ) +{ + UINT8 Dpcd; + + /* + * MACRO_RST must be applied after the PLL_LOCCK to avoid + * the DP inter pair skew issue for at least 10us + * */ + AnalogixDpResetMacro(Dp); + + /* Initailze by reading RX's DPCD */ + AnalogixDpGetMaxRxBandwidth(Dp, &Dp->LinkTrain.LinkRate); + AnalogixDpGetMaxRxLaneCount(Dp, &Dp->LinkTrain.LaneCount); + + if ((Dp->LinkTrain.LinkRate != DP_LINK_BW_1_62) && + (Dp->LinkTrain.LinkRate != DP_LINK_BW_2_7) && + (Dp->LinkTrain.LinkRate != DP_LINK_BW_5_4) ) { + DEBUG ((DEBUG_WARN, "faiied to get Rx Max Link Rate 0x%2x \n", + Dp->LinkTrain.LinkRate)); + return -ENODEV; + } + + if (Dp->LinkTrain.LaneCount == 0) { + DEBUG ((DEBUG_WARN, "faiied to get Rx Max Lane count\n")); + return -ENODEV; + } + + /* Setup TX Lane count & rate */ + if (Dp->LinkTrain.LaneCount > MaxLane) + Dp->LinkTrain.LaneCount = MaxLane; + if (Dp->LinkTrain.LinkRate > MaxRate) + Dp->LinkTrain.LinkRate = MaxRate; + + AnalogixDpReadByteFromDpcd(Dp, DP_MAX_DOWNSPREAD, &Dpcd); + Dp->LinkTrain.SSC = !!(Dpcd & DP_MAX_DOWNSPREAD_0_5); + + /* All DP analog module power up */ + AnalogixDpSetAnalogPowerDown(Dp, POWER_ALL, 0); + + return 0; +} + +BOOLEAN +AnalogixDpSscSupportes ( + OUT struct AnalogixDpDevice *Dp + ) +{ + // Todo + return Dp->LinkTrain.SSC; +} + +UINTN +AnalogixDpSetLinkBandwidth ( + OUT struct AnalogixDpDevice *Dp, + UINT32 BwType + ) +{ + UINTN i; + UINT32 Reg; + OUT struct PhyConfigureOptsDp OPTS_DP; + OUT struct RockchipHdptxPhy Hdptx; + Dp->Id = Hdptx.Id = PcdGet32(PcdEdpId); + + OPTS_DP.LANES = Dp->LinkTrain.LaneCount; + OPTS_DP.LINKRATE = DrmDpBwCodeToLinkRate(Dp->LinkTrain.LinkRate) / 100; + OPTS_DP.SSC = AnalogixDpSscSupportes(Dp); + OPTS_DP.SETLANES = FALSE; + OPTS_DP.SETRATE = TRUE; + OPTS_DP.SETVOLTAGES = FALSE; + + RockchipHdptxPhyConfigure(&Hdptx, &OPTS_DP); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_LINK_BW_SET, BwType); + + Reg = AnalogixDpGetPllLockStatus(Dp); + for (i = 0; i < 20; i++) { + if (Reg != PLL_LOCKED) + MicroSecondDelay (10); + else + break; + } + + return 0; +} + +UINTN +AnalogixDpSetLaneCount ( + OUT struct AnalogixDpDevice *Dp, + UINT32 Count + ) +{ + UINTN Reg ; + OUT struct PhyConfigureOptsDp OPTS_DP; + OUT struct RockchipHdptxPhy Hdptx; + Dp->Id = Hdptx.Id = PcdGet32(PcdEdpId); + + Reg = Count; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_LANE_COUNT_SET, Reg); + + OPTS_DP.LANES = Dp->LinkTrain.LaneCount; + OPTS_DP.LINKRATE = DrmDpBwCodeToLinkRate(Dp->LinkTrain.LinkRate) / 100; + OPTS_DP.SSC = AnalogixDpSscSupportes(Dp); + OPTS_DP.SETLANES = TRUE; + OPTS_DP.SETRATE = FALSE; + OPTS_DP.SETVOLTAGES = FALSE; + RockchipHdptxPhyConfigure(&Hdptx, &OPTS_DP); + + return 0 ; +} + +STATIC +INT32 +AnalogixDpLinkStart ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT8 Buf[4]; + INT32 Lane, LaneCount, Retval; + + LaneCount = Dp->LinkTrain.LaneCount; + Dp->LinkTrain.LtState = CLOCK_RECOVERY; + Dp->LinkTrain.EqLoop = 0; + + for (Lane = 0; Lane < LaneCount; Lane++) + Dp->LinkTrain.CrLoop[Lane] = 0; + + /* Set link rate and count as you want to establish*/ + AnalogixDpSetLinkBandwidth(Dp, Dp->LinkTrain.LinkRate); + AnalogixDpSetLaneCount(Dp, Dp->LinkTrain.LaneCount); + + /* Setup RX configuration */ + Buf[0] = Dp->LinkTrain.LinkRate; + Buf[1] = Dp->LinkTrain.LaneCount; + Retval = AnalogixDpWriteBytesToDpcd(Dp, DP_LINK_BW_SET, 2, Buf); + if (Retval) + return Retval; + + /* Spread AMP if required, Enable 8b/10b coding */ + Buf[0] = AnalogixDpSscSupportes(Dp) ? DP_SPREAD_AMP_0_5 : 0; + Buf[1] = DP_SET_ANSI_8B10B; + Retval = AnalogixDpWriteBytesToDpcd(Dp, DP_DOWNSPREAD_CTRL, + 2, Buf); + if (Retval < 0) + return Retval; + + /* Set TX voltage-swing and pre-emphasis to minimum */ + for (Lane = 0; Lane < LaneCount; Lane++) + Dp->LinkTrain.TrainingLane[Lane] = + DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | + DP_TRAIN_PRE_EMPH_LEVEL_0; + AnalogixDpSetLaneLinkTraining(Dp); + + /* Set training pattern 1 */ + AnalogixDpSetTrainingPattern(Dp, TRAINING_PTN1); + + /* Set RX training pattern */ + Retval = AnalogixDpWriteByteToDpcd(Dp, + DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); + if (Retval) + return Retval; + + for (Lane = 0; Lane < LaneCount; Lane++) + Buf[Lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | + DP_TRAIN_VOLTAGE_SWING_LEVEL_0; + + Retval = AnalogixDpWriteBytesToDpcd(Dp, DP_TRAINING_LANE0_SET, + LaneCount, Buf); + + return Retval; +} + +STATIC +UINT8 +AnalogixDpGetAdjustRequestVoltage ( + UINT8 AdjustRequest[2], + UINTN Lane) +{ + UINTN Shift = (Lane & 1) * 4; + UINT8 LinkValue = AdjustRequest[Lane >> 1]; + + return (LinkValue >> Shift) & 0x3; +} + +STATIC +UINT8 +AnalogixDpGetAdjustRequestPreEmphasis ( + UINT8 AdjustRequest[2], + UINTN Lane + ) +{ + UINTN shift = (Lane & 1) * 4; + UINT8 link_value = AdjustRequest[Lane >> 1]; + + return ((link_value >> shift) & 0xc) >> 2; +} + +STATIC +VOID +AnalogixDpTrainingPatternDis ( + OUT struct AnalogixDpDevice *Dp + ) +{ + AnalogixDpSetTrainingPattern(Dp, DP_NONE); + + AnalogixDpWriteByteToDpcd(Dp, DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); +} + +STATIC +INT32 +AnalogixDpIsEnhancedModeAvailable ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT8 Data; + INT32 Retval; + + AnalogixDpReadByteFromDpcd(Dp, DP_MAX_LANE_COUNT, &Data); + Retval = DPCD_ENHANCED_FRAME_CAP(Data); + + return Retval; +} + +STATIC +VOID +AnalogixDpSetEnhancedMode ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT8 Data; + + Data = AnalogixDpIsEnhancedModeAvailable(Dp); + AnalogixDpEnableRxToEnhancedMode(Dp, Data); + AnalogixDpEnableEnhancedMode(Dp, Data); +} + +STATIC +VOID +AnalogixDpReduceLinkRate ( + OUT struct AnalogixDpDevice *Dp + ) +{ + AnalogixDpTrainingPatternDis(Dp); + AnalogixDpSetEnhancedMode(Dp); + Dp->LinkTrain.LtState = FAILED; +} + +STATIC +VOID +AnalogixDpGetAdjustTrainingLane ( + OUT struct AnalogixDpDevice *Dp, + UINT8 AdjustRequest[2]) +{ + UINTN Lane , LaneCount; + UINT8 VoltageSwing, PreEmphasis, TrainingLane; + LaneCount = Dp->LinkTrain.LaneCount; + + for (Lane = 0; Lane < LaneCount; Lane++) { + VoltageSwing = AnalogixDpGetAdjustRequestVoltage( + AdjustRequest, Lane + ); + PreEmphasis = AnalogixDpGetAdjustRequestPreEmphasis( + AdjustRequest, Lane + ); + TrainingLane = DPCD_VOLTAGE_SWING_SET(VoltageSwing) | + DPCD_PRE_EMPHASIS_SET(PreEmphasis); + if (VoltageSwing == VOLTAGE_LEVEL_3) + TrainingLane |= DP_TRAIN_MAX_SWING_REACHED; + if (PreEmphasis == PRE_EMPHASIS_LEVEL_3) + TrainingLane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + + Dp->LinkTrain.TrainingLane[Lane] = TrainingLane; + } +} + +VOID +AnalogixDpSetLaneLinkTraining ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT8 Lane; + OUT struct PhyConfigureOptsDp OPTS_DP; + OUT struct RockchipHdptxPhy Hdptx; + Dp->Id = Hdptx.Id = PcdGet32(PcdEdpId); + + for (Lane = 0; Lane < Dp->LinkTrain.LaneCount; Lane++) { + UINT8 TrainingLane = Dp->LinkTrain.TrainingLane[Lane]; + UINT8 VS, PE; + + AnalogixDpRegWrite(Dp, + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * Lane, + Dp->LinkTrain.TrainingLane[Lane]); + + VS = (TrainingLane & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + PE = (TrainingLane & DP_TRAIN_PRE_EMPHASIS_MASK) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + OPTS_DP.VOLTAGE[Lane] = VS; + OPTS_DP.PRE[Lane] = PE; + } + + OPTS_DP.LANES = Dp->LinkTrain.LaneCount; + OPTS_DP.LINKRATE = DrmDpBwCodeToLinkRate(Dp->LinkTrain.LinkRate) / 100; + OPTS_DP.SETLANES = FALSE; + OPTS_DP.SETRATE = FALSE; + OPTS_DP.SETVOLTAGES = TRUE; + RockchipHdptxPhyConfigure(&Hdptx, &OPTS_DP); +} + +STATIC +UINT8 +AnalogixDpGetLaneStatus ( + UINT8 LinkStatus[2], + INT32 Lane + ) +{ + INT32 Shift = (Lane & 1) * 4; + UINT8 LinkValue = LinkStatus[Lane >> 1]; + + return (LinkValue >> Shift) & 0xf; +} + +STATIC +INT32 +AnalogixDpClockRecoveryOk ( + UINT8 LinkStatus[2], + INT32 LaneCount + ) +{ + INT32 Lane; + UINT8 LaneStatus; + + for (Lane = 0; Lane < LaneCount; Lane++) { + LaneStatus = AnalogixDpGetLaneStatus(LinkStatus, Lane); + if ((LaneStatus & DP_LANE_CR_DONE) == 0) + return -EINVAL; + } + return 0; +} + +BOOLEAN +AnalogixDpTps3Supported ( + OUT struct AnalogixDpDevice *Dp + ) +{ + BOOLEAN SourceTps3Supported, SinkTps3Supported; + UINT8 Dpcd = 0; + + SourceTps3Supported = + Dp->VideoInfo.MaxLinkRate == DP_LINK_BW_5_4; + + AnalogixDpReadByteFromDpcd(Dp, DP_MAX_LANE_COUNT, &Dpcd); + SinkTps3Supported = Dpcd & DP_TPS3_SUPPORTED; + + return SourceTps3Supported && SinkTps3Supported; +} + +STATIC +INT32 +AnalogixDpProcessClockRecovery ( + OUT struct AnalogixDpDevice *Dp + ) +{ + INT32 Lane, LaneCount, Retval; + UINT8 VoltageSwing, PreEmphasis, TrainingLane; + UINT8 LinkStatus[2], AdjustRequest[2]; + UINT8 TrainingPattern = TRAINING_PTN2; + + DrmDpLinkTrainClockRecoveryDelay(Dp->Dpcd); + + LaneCount = Dp->LinkTrain.LaneCount; + + Retval = AnalogixDpReadBytesFromDpcd(Dp, + DP_LANE0_1_STATUS, 2, LinkStatus); + if (Retval) + return Retval; + + if (AnalogixDpClockRecoveryOk(LinkStatus, LaneCount) == 0) { + if (AnalogixDpTps3Supported(Dp)) + TrainingPattern = TRAINING_PTN3; + + /* set training pattern for EQ*/ + AnalogixDpSetTrainingPattern(Dp, TrainingPattern); + + Retval = AnalogixDpWriteByteToDpcd(Dp, + DP_TRAINING_PATTERN_SET, + (TrainingPattern == TRAINING_PTN3 ? + DP_TRAINING_PATTERN_3 : DP_TRAINING_PATTERN_2)); + if (Retval) + return Retval; + + DEBUG ((DEBUG_WARN, "Link Training Clock Recovery success\n")); + Dp->LinkTrain.LtState = EQUALIZER_TRAINING; + + return 0; + } else { + Retval = AnalogixDpReadBytesFromDpcd(Dp, + DP_ADJUST_REQUEST_LANE0_1, 2, AdjustRequest); + if (Retval) + return Retval; + + for (Lane = 0; Lane < LaneCount; Lane++) { + TrainingLane = AnalogixDpGetLaneLinkTraining( + Dp, Lane); + VoltageSwing = AnalogixDpGetAdjustRequestVoltage( + AdjustRequest, Lane); + PreEmphasis = AnalogixDpGetAdjustRequestPreEmphasis( + AdjustRequest, Lane); + + if (DPCD_VOLTAGE_SWING_GET(TrainingLane) == + VoltageSwing && + DPCD_PRE_EMPHASIS_GET(TrainingLane) == + PreEmphasis) + Dp->LinkTrain.CrLoop[Lane]++; + + if (Dp->LinkTrain.CrLoop[Lane] == MAX_CR_LOOP || + VoltageSwing == VOLTAGE_LEVEL_3 || + PreEmphasis == PRE_EMPHASIS_LEVEL_3) { + DEBUG ((DEBUG_ERROR, "CR Max reached (%d,%d)\n", + Dp->LinkTrain.CrLoop[Lane], + VoltageSwing, PreEmphasis)); + AnalogixDpReduceLinkRate(Dp); + return -EIO; + } + } + } + + AnalogixDpGetAdjustTrainingLane(Dp, AdjustRequest); + AnalogixDpSetLaneLinkTraining(Dp); + + Retval = AnalogixDpWriteBytesToDpcd(Dp, + DP_TRAINING_LANE0_SET, LaneCount, + Dp->LinkTrain.TrainingLane); + if (Retval) + return Retval; + + return Retval; +} + +STATIC +INT32 +AnalogixDpChannelEqOk ( + UINT8 LinkStatus[2], + UINT8 LinkAlign, + INT32 LaneCount + ) +{ + INT32 Lane; + UINT8 LaneStatus; + + if ((LinkAlign & DP_INTERLANE_ALIGN_DONE) == 0) + return -EINVAL; + + for (Lane = 0; Lane < LaneCount; Lane++) { + LaneStatus = AnalogixDpGetLaneStatus(LinkStatus, Lane); + LaneStatus &= DP_CHANNEL_EQ_BITS; + if (LaneStatus != DP_CHANNEL_EQ_BITS) + return -EINVAL; + } + + return 0; +} + +STATIC +INT32 +AnalogixDpProcessEqualizerTraining ( + OUT struct AnalogixDpDevice *Dp + ) +{ + INT32 LaneCount, Retval; + UINT32 Reg; + UINT8 LinkAlign; + UINT8 LinkStatus[2], AdjustRequest[2]; + + DrmDpLinkTrainChannelEqDelay(Dp->Dpcd); + + LaneCount = Dp->LinkTrain.LaneCount; + + Retval = AnalogixDpReadBytesFromDpcd(Dp, + DP_LANE0_1_STATUS, 2, LinkStatus); + if (Retval) + return Retval; + + if (AnalogixDpClockRecoveryOk(LinkStatus, LaneCount)) { + DEBUG ((DEBUG_WARN, "AnalogixDpReduceLinkRate \n")); + AnalogixDpReduceLinkRate(Dp); + //Todo + //return -EIO; + } + + Retval = AnalogixDpReadBytesFromDpcd(Dp, + DP_ADJUST_REQUEST_LANE0_1, 2, AdjustRequest); + if (Retval) + return Retval; + + Retval = AnalogixDpReadByteFromDpcd(Dp, + DP_LANE_ALIGN_STATUS_UPDATED, &LinkAlign); + if (Retval) + return Retval; + + /* Training pattern set to normal */ + AnalogixDpTrainingPatternDis(Dp); + if (!AnalogixDpChannelEqOk(LinkStatus, LinkAlign, LaneCount)) { + + DEBUG ((DEBUG_WARN, "Link Training success\n")); + + AnalogixDpGetLinkBandwidth(Dp, &Reg); + Dp->LinkTrain.LinkRate = Reg; + AnalogixDpGetLaneCount(Dp, &Reg); + Dp->LinkTrain.LaneCount = Reg; + + DEBUG ((DEBUG_WARN, "Final link rate = 0x%.2x, Lane count = 0x%.2x\n", + Dp->LinkTrain.LinkRate, Dp->LinkTrain.LaneCount)); + + /* Set enhanced mode if available */ + AnalogixDpSetEnhancedMode(Dp); + Dp->LinkTrain.LtState = FINISHED; + + return 0; + } + + /* not all locked */ + Dp->LinkTrain.EqLoop++; + if (Dp->LinkTrain.EqLoop > MAX_EQ_LOOP) { + DEBUG ((DEBUG_WARN, "EQ Max loop\n")); + AnalogixDpReduceLinkRate(Dp); + return -EIO; + } + + Retval = AnalogixDpReadBytesFromDpcd(Dp, + DP_ADJUST_REQUEST_LANE0_1, 2, AdjustRequest); + if (Retval) + return Retval; + + AnalogixDpGetAdjustTrainingLane(Dp, AdjustRequest); + AnalogixDpSetLaneLinkTraining(Dp); + + Retval = AnalogixDpWriteBytesToDpcd(Dp, DP_TRAINING_LANE0_SET, + LaneCount, Dp->LinkTrain.TrainingLane); + + return Retval; +} + +STATIC +INT32 +AnalogixDpSwLinkTraining ( + OUT struct AnalogixDpDevice *Dp + ) +{ + INT32 Retval = 0, TrainingFinished = 0; + + Dp->LinkTrain.LtState = START; + + while (!Retval && !TrainingFinished) { + switch (Dp->LinkTrain.LtState) { + case START: + Retval = AnalogixDpLinkStart(Dp); + if (Retval) + DEBUG ((DEBUG_WARN, "LT link start failed!\n")); + break; + case CLOCK_RECOVERY: + Retval = AnalogixDpProcessClockRecovery(Dp); + if (Retval) + DEBUG ((DEBUG_WARN, "LT CR failed!\n")); + case EQUALIZER_TRAINING: + Retval = AnalogixDpProcessEqualizerTraining(Dp); + if (Retval) + DEBUG ((DEBUG_WARN, "LT EQ failed!\n")); + case FINISHED: + TrainingFinished = 1; + break; + case FAILED: + return -EIO; + } + } + + return Retval; +} + +INT32 +AnalogixDpSetLinkTrain ( + OUT struct AnalogixDpDevice *Dp, + UINT32 Count, + UINT32 BwType + ) +{ + INT32 i, Ret; + + for (i = 0; i < 5; i++) { + Ret = AnalogixDpInitTraining(Dp, Count, BwType); + if (Ret < 0) { + DEBUG ((DEBUG_WARN, "faiied to init training\n")); + return Ret; + } + + Ret = AnalogixDpSwLinkTraining(Dp); + if (!Ret) + break; + } + + return Ret; +} + +VOID +AnalogixDpConfigVideoSlaveMode ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_FUNC_EN_1); + Reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N); + Reg |= MASTER_VID_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_1, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_10); + Reg &= ~INTERACE_SCAN_CFG; + Reg |= (Dp->VideoInfo.Interlaced << 2); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_10, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_10); + Reg &= ~VSYNC_POLARITY_CFG; + Reg |= (Dp->VideoInfo.VSyncPolarity << 1); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_10, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_10); + Reg &= ~HSYNC_POLARITY_CFG; + Reg |= (Dp->VideoInfo.HSyncPolarity << 0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_10, Reg); + + Reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SOC_GENERAL_CTL, Reg); +} + +VOID +AnalogixDpSetVideoColorFormat ( + OUT struct AnalogixDpDevice *Dp + ) +{ + //Todo + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_2, 0x10); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_3, 0x00); +} + +VOID +AnalogixDpSetVideoCrMn ( + OUT struct AnalogixDpDevice *Dp, + enum ClockRecoveryMValueType Type, + UINT32 MValue, + UINT32 NValue + ) +{ + UINT32 Reg; + + if (Type == REGISTER_M) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_4); + Reg |= FIX_M_VID; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_4, Reg); + Reg = MValue & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_M_VID_0, Reg); + Reg = (MValue >> 8) & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_M_VID_1, Reg); + Reg = (MValue >> 16) & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_M_VID_2, Reg); + + Reg = NValue & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_0, Reg); + Reg = (NValue >> 8) & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_1, Reg); + Reg = (NValue >> 16) & 0xff; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_2, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_4); + Reg &= ~FIX_M_VID; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_4, Reg); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_0, 0x00); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_1, 0x80); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_N_VID_2, 0x00); + } +} + +VOID +AnalogixDpSetVideoTimingMode ( + OUT struct AnalogixDpDevice *Dp, + UINT32 Type + ) +{ + UINT32 Reg; + + if (Type == VIDEO_TIMING_FROM_CAPTURE) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_10); + Reg &= ~FORMAT_SEL; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_10, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_10); + Reg |= FORMAT_SEL; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_10, Reg); + } +} + +STATIC +INT32 +AnalogixDpConfigVideo ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg ,Ret; + UINT32 TimeoutLoop, DoneCount; + + AnalogixDpConfigVideoSlaveMode(Dp); + AnalogixDpSetVideoColorFormat(Dp); + + Reg = AnalogixDpGetPllLockStatus(Dp); + if (Reg != PLL_LOCKED ) { + DEBUG ((DEBUG_WARN, "PLL is not locked yet. \n")); + Ret = AnalogixDpRegRead(Dp, ANALOGIX_DP_DEBUG_CTL); + DEBUG ((DEBUG_WARN, "PLL Dp debug ctl ret 0x%.8x\n", Ret)); + } + + for (;;) { + TimeoutLoop++; + if (AnalogixDpIsSlaveVideoStreamClockOn(Dp) == 0) + break; + if (TimeoutLoop > DP_TIMEOUT_LOOP_COUNT) { + DEBUG ((DEBUG_WARN, "Timeout of video streamclk ok\n")); + return -ETIMEDOUT; + } + + NanoSecondDelay(2000); + } + + /* Set to use the Register calculated M/N video */ + AnalogixDpSetVideoCrMn(Dp, CALCULATED_M, 0, 0); + + /* For video bist Video timing must be generated register */ + AnalogixDpSetVideoTimingMode(Dp, VIDEO_TIMING_FROM_CAPTURE); + + /* Disable video mute */ + AnalogixDpEnableVideoMute(Dp, 0); + + /* Configure video slave mode */ + AnalogixDpEnableVideoMaster(Dp, 0); + + /* Enable video input */ + AnalogixDpStartVideo(Dp); + + TimeoutLoop = 0; + + for (;;) { + TimeoutLoop++; + if (AnalogixDpIsVideoStreamOn(Dp) == 0) { + DoneCount++; + if (DoneCount > 10) + break; + } else if (DoneCount) + DoneCount = 0; + + if (TimeoutLoop > DP_TIMEOUT_LOOP_COUNT) { + DEBUG ((DEBUG_ERROR, "Timeout of video streamclk ok\n")); + return -ETIMEDOUT; + } + + NanoSecondDelay(1001000); + } + + return 0; +} + +EFI_STATUS +AnalogixDpConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + struct RockchipHdptxPhy Hdptx; + struct AnalogixDpDevice *Dp; + Dp = AllocateZeroPool(sizeof (*Dp)); + + ConnectorState->Type = DRM_MODE_CONNECTOR_eDP; + ConnectorState->OutputInterface = VOP_OUTPUT_IF_eDP1; + Dp->Id = Hdptx.Id = PcdGet32(PcdEdpId); + + if (Dp->Id) + ConnectorState->OutputInterface = VOP_OUTPUT_IF_eDP1; + else + ConnectorState->OutputInterface = VOP_OUTPUT_IF_eDP0; + + if (ConnectorState->OutputInterface == VOP_OUTPUT_IF_eDP0) { + MmioWrite32(0xFD5A8000, 0xFFFF0001); + } else { + MmioWrite32(0xFD5A8004, 0xFFFF0001); + } + + RockchipHdptxPhyInit(&Hdptx); + MicroSecondDelay (10); + EnableBacklight(TRUE); + EnablePWM(TRUE); + AnalogixDpReset(Dp); + AnalogixDpSwreset(Dp); + AnalogixDpInitAnalogParam(Dp); + AnalogixDpInitInterrupt(Dp); + /* SW defined function Normal operation */ + AnalogixDpEnableSwFunction(Dp); + AnalogixDpConfigInterrupt(Dp); + AnalogixDpInitAnalogFunc(Dp); + AnalogixDpInitHpd(Dp); + AnalogixDpInitAux(Dp); + + return 0; +}; + +STATIC +INT32 +AnalogixDpLinkPowerUp ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT8 Value; + INTN Ret; + + if (Dp->Dpcd[DP_DPCD_REV] < 0x11) + return 0; + + Ret = AnalogixDpReadByteFromDpcd(Dp, DP_SET_POWER, &Value); + if (Ret < 0) + return Ret; + + Value &= ~DP_SET_POWER_MASK; + Value |= DP_SET_POWER_D0; + + Ret = AnalogixDpWriteByteToDpcd(Dp, DP_SET_POWER, Value); + if (Ret < 0) + return Ret; + + MicroSecondDelay (1); + return 0; +}; + +EFI_STATUS +AnalogixDpConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + + ConnectorState->OutputMode = ROCKCHIP_OUT_MODE_AAAA; + ConnectorState->ColorSpace = V4L2_COLORSPACE_DEFAULT; + + return 0; +}; + +EFI_STATUS +AnalogixDpConnectorGetEdid ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +EFI_STATUS +AnalogixDpConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + struct AnalogixDpDevice *Dp; + Dp = AllocatePool(sizeof (*Dp)); + struct VideoInfo *Video = &Dp->VideoInfo; + UINTN Ret; + + switch (ConnectorState->BPC) { + case 12: + Video->ColorDepth = COLOR_12; + break; + case 10: + Video->ColorDepth = COLOR_10; + break; + case 6: + Video->ColorDepth = COLOR_6; + break; + case 8: + Video->ColorDepth = COLOR_8; + break; + default: + Video->ColorDepth = COLOR_8; + break; + } + + Dp->VideoInfo.MaxLinkRate = DP_LINK_BW_5_4; + Dp->VideoInfo.MaxLaneCount = LANE_COUNT4; + Dp->LinkTrain.SSC = TRUE; + Dp->Id = PcdGet32(PcdEdpId); + + Ret = AnalogixDpReadBytesFromDpcd(Dp, DP_DPCD_REV, + DP_RECEIVER_CAP_SIZE, Dp->Dpcd); + if (Ret) { + DEBUG ((DEBUG_WARN, "Falied to read dpcd cap \n")); + return Ret; + } + + Ret = AnalogixDpLinkPowerUp(Dp); + if (Ret) { + DEBUG ((DEBUG_WARN, "Falied to link power up \n")); + return Ret; + } + + Ret = AnalogixDpSetLinkTrain(Dp, Dp->VideoInfo.MaxLaneCount, + Dp->VideoInfo.MaxLinkRate); + if (Ret) { + DEBUG ((DEBUG_WARN, "Unable to do link train !!! \n")); + return Ret; + } + + AnalogixDpEnableScramble(Dp, 1); + AnalogixDpEnableRxToEnhancedMode(Dp, 1); + AnalogixDpEnableEnhancedMode(Dp, 1); + + AnalogixDpInitVideo(Dp); + AnalogixDpSetVideoFormat(Dp, &ConnectorState->DisplayMode); + AnalogixDpConfigVideo(Dp); + +#if REG_DUMP + DumpDpRegisters(Dp); + DumpHdptxPhyRegisters(Dp); +#endif + FreePool(Dp); + return 0; +}; + +EFI_STATUS +AnalogixDpConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +EFI_STATUS +AnalogixDpConnectorDetect ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +ROCKCHIP_CONNECTOR_PROTOCOL mDp = { + NULL, + AnalogixDpConnectorPreInit, + AnalogixDpConnectorInit, + NULL, + AnalogixDpConnectorDetect, + NULL, + AnalogixDpConnectorGetEdid, + NULL, + AnalogixDpConnectorEnable, + AnalogixDpConnectorDisable, + NULL +}; + +EFI_STATUS +EFIAPI +AnalogixDpInitDp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipConnectorProtocolGuid, + &mDp, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf new file mode 100644 index 0000000..a1be628 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf @@ -0,0 +1,63 @@ +#/** @file +# +# Component description file for analogix dp module +# +# Copyright (c) 2017, Rockchip Inc. All rights reserved.
    +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AnalogixDpLib + FILE_GUID = 10142bcc-7b5c-11ec-b45f-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = AnalogixDpInitDp + +[Sources.common] + AnalogixDpLib.c + AnalogixDpReg.c + PhyRockchipSamsungHdptx.c + +[LibraryClasses] + TimerLib + DebugLib + IoLib + BaseLib + BaseMemoryLib + RockchipDisplayLib + MemoryAllocationLib + PWMLib + RockchipPlatformLib + UefiLib + UefiDriverEntryPoint + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[BuildOptions] + +[Pcd] + gRockchipTokenSpaceGuid.PcdLcdPixelFormat + gRockchipTokenSpaceGuid.PcdEdpId + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution + +[Protocols] + gRockchipConnectorProtocolGuid + +[Depex] + TRUE + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpReg.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpReg.c new file mode 100644 index 0000000..92c6341 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/AnalogixDpReg.c @@ -0,0 +1,1233 @@ +/** @file + Rockchip eDP Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#define COMMON_INT_MASK_1 0 +#define COMMON_INT_MASK_2 0 +#define COMMON_INT_MASK_3 0 +#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) +#define INT_STA_MASK INT_HPD + +VOID +AnalogixDpRegWrite ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 Offset, + IN UINT32 Value + ) +{ + UINT32 BASE; + + if (!Dp->Id) + BASE = ANALOGIX_DP0_REG_BASE; + else + BASE = ANALOGIX_DP1_REG_BASE; + + MmioWrite32(BASE + Offset, Value); +} + +UINT32 +AnalogixDpRegRead ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 Offset + ) +{ + UINT32 Reg; + UINT32 BASE; + + if (!Dp->Id) + BASE = ANALOGIX_DP0_REG_BASE; + else + BASE = ANALOGIX_DP1_REG_BASE; + + Reg = MmioRead32(BASE + Offset); + return Reg; +} + +VOID +AnalogixDpStopVideo ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_1); + Reg &= ~VIDEO_EN; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_1, Reg); +} + +VOID +AnalogixDpSetLaneMap ( + OUT struct AnalogixDpDevice *Dp + ) +{ + //Todo + AnalogixDpRegWrite(Dp, ANALOGIX_DP_LANE_MAP, 0xE4); +} + + +VOID +AnalogixDpEnableVideoMute ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_1); + if (Enable) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_1); + Reg |= HDCP_VIDEO_MUTE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_1,Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_1); + Reg &= ~HDCP_VIDEO_MUTE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_1,Reg); + } +} + +VOID +AnalogixDpLaneSwap ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + //Todo + UINT32 Reg; + + if (Enable) + Reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | + LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; + else + Reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | + LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_LANE_MAP, Reg); +} + +VOID +AnalogixDpReset ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + AnalogixDpStopVideo(Dp); + AnalogixDpEnableVideoMute(Dp, 0); + + Reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | + AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | + HDCP_FUNC_EN_N | SW_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_1, Reg); + + Reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | + SERDES_FIFO_FUNC_EN_N | + LS_CLK_DOMAIN_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_2, Reg); + + NanoSecondDelay (30000); + + AnalogixDpSetLaneMap(Dp); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_1, 0x0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_2, 0x40); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_3, 0x0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_4, 0x0); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PKT_SEND_CTL, 0x0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_HDCP_CTL, 0x0); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_HPD_DEGLITCH_L, 0x5e); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_HPD_DEGLITCH_H, 0x1a); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_LINK_DEBUG_CTL, 0x10); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PHY_TEST, 0x0); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_FIFO_THRD, 0x0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUDIO_MARGIN, 0x20); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_M_VID_GEN_FILTER_TH, 0x4); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_M_AUD_GEN_FILTER_TH, 0x2); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SOC_GENERAL_CTL, 0x00000101); +} + +VOID +AnalogixDpSwreset ( + OUT struct AnalogixDpDevice *Dp + ) +{ + /* SW_RESET */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TX_SW_RESET,RESET_DP_TX); +} + +VOID +AnalogixDpInitAnalogParam ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = TX_TERMINAL_CTRL_50_OHM; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ANALOG_CTL_1, Reg); + + Reg = SEL_24M | TX_DVDD_BIT_1_0625V; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ANALOG_CTL_2, Reg); + + Reg = REF_CLK_24M; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_REG_1, Reg); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_REG_2, 0x99); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_REG_3, 0x40); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_REG_4, 0x58); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_REG_5, 0x22); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BIAS, 0x44); + + Reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ANALOG_CTL_3, Reg); + + Reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | + TX_CUR1_2X | TX_CUR_16_MA; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_FILTER_CTL_1, Reg); + + Reg = CH3_AMP_400_MV | CH2_AMP_400_MV | + CH1_AMP_400_MV | CH0_AMP_400_MV; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TX_AMP_TUNING_CTL, Reg); + + MicroSecondDelay (10); +} + +VOID +AnalogixDpInitInterrupt ( + OUT struct AnalogixDpDevice *Dp + ) +{ + /* Set interrupt pin assertion polarity as high */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_CTL,INT_POL1 | INT_POL0); + + /* Clear pending Regisers */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_1, 0xff); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_2, 0x4f); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_3, 0xe0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_4, 0xe7); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA_MASK, 0x63); + + /* 0:mask,1: unmask */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_1, 0x00); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_2, 0x00); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_3, 0x00); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_4, 0x00); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA_MASK, 0x00); +} + +VOID +AnalogixDpEnableSwFunction ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_FUNC_EN_1); + Reg &= ~SW_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_1, Reg); +} + +VOID +AnalogixDpConfigInterrupt ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + /* 0: mask, 1: unmask */ + Reg = COMMON_INT_MASK_1; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_1, Reg); + Reg = COMMON_INT_MASK_2; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_2, Reg); + + Reg = COMMON_INT_MASK_3; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_3, Reg); + + Reg = COMMON_INT_MASK_4; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_MASK_4, Reg); + Reg = INT_STA_MASK; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA_MASK, Reg); + +} + +VOID +AnalogixDpSetAnalogPowerDown ( + OUT struct AnalogixDpDevice *Dp, + enum AnalogPowerBlock Block, + BOOLEAN Enable + ) +{ + UINT32 Reg; + UINT32 PhyPdAddr = ANALOGIX_DP_PD; + //Todo + switch (Block) { + case AUX_BLOCK: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= AUX_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~AUX_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case CH0_BLOCK: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= CH0_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~CH0_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case CH1_BLOCK: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= CH1_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~CH1_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case CH2_BLOCK: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= CH2_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~CH2_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case CH3_BLOCK: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= CH3_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~CH3_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case ANALOG_TOTAL: + if (Enable) { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg |= DP_PHY_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, PhyPdAddr); + Reg &= ~DP_PHY_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } + break; + case POWER_ALL: + if (Enable) { + Reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | + CH1_PD | CH0_PD; + AnalogixDpRegWrite(Dp, PhyPdAddr, Reg); + } else { + AnalogixDpRegWrite(Dp, PhyPdAddr, 0x00); + } + break; + default: + break; + } +} + +VOID +AnalogixDpSetPllPowerDown ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT32 Reg; + + if (Enable) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_PLL_CTL); + Reg |= DP_PLL_PD; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_CTL,Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_PLL_CTL); + Reg &= ~DP_PLL_PD; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_PLL_CTL,Reg); + } +} + +VOID +AnalogixDpInitAnalogFunc ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + AnalogixDpSetAnalogPowerDown(Dp, POWER_ALL, 0); + + Reg = PLL_LOCK_CHG; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_1, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_DEBUG_CTL); + Reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_DEBUG_CTL, Reg); + + /* Power up PLL */ + AnalogixDpSetPllPowerDown(Dp, 0); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_FUNC_EN_2); + Reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N + | AUX_FUNC_EN_N); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_2, Reg); +} + +VOID +AnalogixDpClearHotplugInterrupts ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + //TODO + Reg = HOTPLUG_CHG | HPD_LOST | PLUG; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_COMMON_INT_STA_4, Reg); + + Reg = INT_HPD; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA, Reg); +} + +VOID +AnalogixDpInitHpd ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + AnalogixDpClearHotplugInterrupts(Dp); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_3); + Reg &= ~(F_HPD | HPD_CTRL); + + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_3, Reg); +} + +VOID +AnalogixDpResetAux ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + /* Disable AUX channel module */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_FUNC_EN_2); + Reg |= AUX_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_2, Reg); +} + +VOID +AnalogixDpInitAux ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + /* Clear inerrupts related to AUX channel */ + Reg = RPLY_RECEIV | AUX_ERR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA, Reg); + + AnalogixDpResetAux(Dp); + + Reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) | + AUX_HW_RETRY_COUNT_SEL(3) | + AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_HW_RETRY_CTL, Reg); + + /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ + Reg = DEFER_CTRL_EN | DEFER_COUNT(1); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_DEFER_CTL, Reg); + + /* Enable AUX channel module */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_FUNC_EN_2); + Reg &= ~AUX_FUNC_EN_N; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_FUNC_EN_2, Reg); +} + +INT32 +AnalogixDpWriteByteToDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT8 Data + ) +{ + UINT32 Reg; + UINTN i; + UINTN Retval; + + for (i = 0; i < 3; i++) { + /* Clear AUX CH data buffer */ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + /* Select DPCD device address */ + Reg = AUX_ADDR_7_0(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_7_0, Reg); + Reg = AUX_ADDR_15_8(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_15_8, Reg); + Reg = AUX_ADDR_19_16(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_19_16, Reg); + + /* write Data buffer */ + Reg = (UINT32)Data; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUF_DATA_0, Reg); + + /* + * Set DisplayPort transaction and write 1 byte + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + + return Retval; +} + +INT32 +AnalogixDpWriteBytesToDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT32 Count, + IN UINT8 Data[] + ) +{ + UINT32 Reg; + UINT32 StartOffset; + UINT32 CurDataCount, CurDataIdx; + INT32 Retval = 0; + INT32 i; + + /* Clear AUX CH data buffer */ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + StartOffset = 0; + while (StartOffset < Count) { + /* Buffer size of AUX CH is 16 * 4bytes */ + if ((Count - StartOffset) > 16) + CurDataCount = 16; + else + CurDataCount = Count - StartOffset; + + for (i = 0; i < 3; i++) { + /* Select DPCD device address */ + Reg = AUX_ADDR_7_0(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_7_0, Reg); + Reg = AUX_ADDR_15_8(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_15_8, Reg); + Reg = AUX_ADDR_19_16(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_19_16, Reg); + + for (CurDataIdx = 0; CurDataIdx < CurDataCount; + CurDataIdx++) { + Reg = Data[StartOffset + CurDataIdx]; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUF_DATA_0 + + 4 * CurDataIdx, Reg); + } + + /* + * Set DisplayPort transaction and write + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_LENGTH(CurDataCount) | + AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + StartOffset += CurDataCount; + } + return Retval; +} + +INT32 +AnalogixDpReadByteFromDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT8 *Data + ) +{ + UINT32 Reg; + INT32 i; + INT32 Retval; + + for (i = 0; i < 3; i++) { + /* Clear AUX CH data buffer */ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + /* Select DPCD device address */ + Reg = AUX_ADDR_7_0(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_7_0, Reg); + Reg = AUX_ADDR_15_8(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_15_8, Reg); + Reg = AUX_ADDR_19_16(RegAddr); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_19_16, Reg); + + /* + * Set DisplayPort transaction and read 1 byte + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + + /* Read data buffer */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_BUF_DATA_0); + *Data = (UINT8)(Reg & 0xff); + + return Retval; +} + +INT32 +AnalogixDpStartAuxTransaction ( + OUT struct AnalogixDpDevice *Dp + ) +{ + INT32 Reg; + INT32 Retval = 0; + INT32 TimeOutLoop =0; + + /* Enable AUX CH operation */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_AUX_CH_CTL_2); + Reg |= AUX_EN; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_2, Reg); + + /* Is AUX CH command reply received? */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_INT_STA); + + while (!(Reg & RPLY_RECEIV)) { + TimeOutLoop++; + if (DP_TIMEOUT_LOOP_COUNT < TimeOutLoop) { + DEBUG ((DEBUG_WARN, "AUX CH command reply failed!\n")); + return -ETIMEDOUT; + } + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_INT_STA); + NanoSecondDelay (11000); + } + + /* Clear interrupt source for AUX CH command reply */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA, Reg); + + /* Clear interrupt source for AUX CH access error */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_INT_STA); + if (Reg & AUX_ERR) { + AnalogixDpRegWrite(Dp, ANALOGIX_DP_INT_STA,AUX_ERR); + return -EREMOTEIO; + } + + /* Check AUX CH error access status */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_AUX_CH_STA); + if ((Reg & AUX_STATUS_MASK) != 0) { + DEBUG ((DEBUG_ERROR,"AUX CH error happens: %d \n", + Reg & AUX_STATUS_MASK)); + return -EREMOTEIO; + } + + return Retval; +} + +INT32 +AnalogixDpReadBytesFromDpcd ( + OUT struct AnalogixDpDevice *Dp, + IN UINT32 RegAddr, + IN UINT32 Count, + IN UINT8 Data[] + ) +{ + UINT32 Reg; + UINT32 StartOffset; + UINT32 CurDataCount, CurDataIdx; + INT32 i; + INT32 Retval = 0; + + /* Clear AUX CH data buffer*/ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + StartOffset = 0; + while (StartOffset < Count) { + /* Buffer size of AUX CH is 16 * 4 bytes */ + if ((Count - StartOffset) > 16) + CurDataCount = 16; + else + CurDataCount = Count - StartOffset; + + /* AUX CH Request Transaction process */ + for (i = 0; i < 3; i++) { + /* Select DPCD device address */ + Reg = AUX_ADDR_7_0(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_7_0, Reg); + Reg = AUX_ADDR_15_8(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_15_8, Reg); + Reg = AUX_ADDR_19_16(RegAddr + StartOffset); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_19_16, Reg); + + /* + * Set DisplayPort transaction and read + * If bit 3 is 1,DisplayPort transaction + * If bit 3 is 0,I2C transaction + */ + Reg = AUX_LENGTH(CurDataCount) | + AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + + for (CurDataIdx = 0; CurDataIdx < CurDataCount; + CurDataIdx++) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_BUF_DATA_0 + + 4 * CurDataIdx); + Data[StartOffset + CurDataIdx] = + (UINT8)Reg; + } + + StartOffset += CurDataCount; + } + + return Retval; +} + +INTN +AnalogixDpSelectI2cDevice ( + OUT struct AnalogixDpDevice *Dp, + UINTN DeviceAddr, + UINTN RegAddr + ) +{ + UINT32 Reg; + INTN Retval; + + // Todo + /* Set EDID device address */ + Reg = DeviceAddr; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_7_0, Reg); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_15_8, 0x0); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_ADDR_19_16, 0x0); + + /* Set offset from base address of EDID device */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUF_DATA_0, RegAddr); + + /* + * Set I2C transaction and write address + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | + AUX_TX_COMM_WRITE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval < 0) + return Retval; + + return 0; +} + +INTN +AnalogixDpReadByteFromI2c ( + struct AnalogixDpDevice *Dp, + UINTN DeviceAddr, + UINTN RegAddr, + UINTN *DATA + ) +{ + UINT32 Reg; + INTN i; + INTN Retval; + + // Todo + for (i = 0; i < 3; i++) { + /* Clear AUX CH data buffer */ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + /* Select EDID device */ + Retval = AnalogixDpSelectI2cDevice(Dp, DeviceAddr, + RegAddr); + if (Retval != 0) + continue; + + /* + * Set I2C transaction and read data + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_TX_COMM_I2C_TRANSACTION | + AUX_TX_COMM_READ; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + + /* Read data */ + if (Retval == 0) + *DATA = AnalogixDpRegRead(Dp, ANALOGIX_DP_BUF_DATA_0); + + return Retval; +} + +INTN +AnalogixDpReadBytesFromI2c ( + OUT struct AnalogixDpDevice *Dp, + UINTN DeviceAddr, + UINTN RegAddr, + UINTN Count, + UINT8 Edid[]) +{ + UINT32 Reg; + UINTN i, j; + UINTN CurDataIdx; + UINTN Defer = 0; + INT32 Retval = 0; + + // Todo + for (i = 0; i < Count; i += 16) { + for (j = 0; j < 3; j++) { + /* Clear AUX CH data buffer */ + Reg = BUF_CLR; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_BUFFER_DATA_CTL, Reg); + + /* Set normal AUX CH command */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_AUX_CH_CTL_2); + Reg &= ~ADDR_ONLY; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_2, Reg); + + /* + * If Rx sends defer, Tx sends only reads + * request without sending address + */ + if (!Defer) + Retval = AnalogixDpSelectI2cDevice(Dp, + DeviceAddr, RegAddr + i); + else + Defer = 0; + + if (Retval == 0) { + /* + * Set I2C transaction and write data + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + Reg = AUX_LENGTH(16) | + AUX_TX_COMM_I2C_TRANSACTION | + AUX_TX_COMM_READ; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_AUX_CH_CTL_1, + Reg); + + /* Start AUX transaction */ + Retval = AnalogixDpStartAuxTransaction(Dp); + if (Retval == 0) + break; + } + /* Check if Rx sends defer */ + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_AUX_RX_COMM); + if (Reg == AUX_RX_COMM_AUX_DEFER || + Reg == AUX_RX_COMM_I2C_DEFER) + Defer = 1; + } + + for (CurDataIdx = 0; CurDataIdx < 16; CurDataIdx++) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_BUF_DATA_0 + + 4 * CurDataIdx); + Edid[i + CurDataIdx] = (UINT8)Reg; + } + } + + return Retval; +} + +VOID +AnalogixDpSetTrainingPattern ( + OUT struct AnalogixDpDevice *Dp, + OUT enum PatternSet Pattern + ) +{ + UINT32 Reg; + + switch (Pattern) { + case PRBS7: + Reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + break; + case D10_2: + Reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + break; + case TRAINING_PTN1: + Reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + break; + case TRAINING_PTN2: + Reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + break; + case TRAINING_PTN3: + Reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN3; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + break; + case DP_NONE: + Reg = SCRAMBLING_ENABLE | + LINK_QUAL_PATTERN_SET_DISABLE | + SW_TRAINING_PATTERN_SET_NORMAL; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); + default: + break; + } +} + +UINT32 +AnalogixDpGetLaneLinkTraining ( + OUT struct AnalogixDpDevice *Dp, + IN UINT8 Lane + ) +{ + return AnalogixDpRegRead(Dp, + ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * Lane); +} + +VOID +AnalogixDpGetLinkBandwidth ( + OUT struct AnalogixDpDevice *Dp, + UINT32 *BwType) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_LINK_BW_SET); + *BwType = Reg; +} + +VOID +AnalogixDpGetLaneCount ( + OUT struct AnalogixDpDevice *Dp, + UINT32 *Count + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_LANE_COUNT_SET); + *Count = Reg; +} + +INT32 +AnalogixDpIsSlaveVideoStreamClockOn ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_1); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_1, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_1); + + if (!(Reg & DET_STA)) + return -EINVAL; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_2); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_2, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_2); + + if (Reg & CHA_STA) + return -EINVAL; + + return 0; +} + +VOID +AnalogixDpEnableVideoMaster ( + OUT struct AnalogixDpDevice *Dp, + BOOLEAN Enable + ) +{ + UINT32 Reg; + + if (Enable) { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SOC_GENERAL_CTL); + Reg &= ~VIDEO_MODE_MASK; + Reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SOC_GENERAL_CTL, Reg); + } else { + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SOC_GENERAL_CTL); + Reg &= ~VIDEO_MODE_MASK; + Reg |= VIDEO_MODE_SLAVE_MODE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SOC_GENERAL_CTL, Reg); + } +} + +VOID +AnalogixDpStartVideo ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_VIDEO_CTL_1); + Reg |= VIDEO_EN; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_VIDEO_CTL_1, Reg); +} + +INTN +AnalogixDpIsVideoStreamOn ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_3); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_SYS_CTL_3, Reg); + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_SYS_CTL_3); + if (!(Reg & STRM_VALID)) + return -EINVAL; + + return 0; +} + +VOID +AnalogixDpEnableScrambling ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_TRAINING_PTN_SET); + Reg &= ~SCRAMBLING_DISABLE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); +} + +VOID +AnalogixDpDisableScrambling ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 Reg; + + Reg = AnalogixDpRegRead(Dp, ANALOGIX_DP_TRAINING_PTN_SET); + Reg |= ~SCRAMBLING_DISABLE; + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TRAINING_PTN_SET, Reg); +} + +VOID +AnalogixDpSetVideoFormat ( + OUT struct AnalogixDpDevice *Dp, + OUT CONST DRM_DISPLAY_MODE *Mode + ) +{ + UINT32 Hsw, Hfp, Hbp, Vsw, Vfp, Vbp; + + Dp->VideoInfo.Interlaced = !!(Mode->Flags & DRM_MODE_FLAG_INTERLACE); + Dp->VideoInfo.VSyncPolarity = TRUE; + Dp->VideoInfo.HSyncPolarity = TRUE; + + Hsw = Mode->HSyncEnd - Mode->HSyncStart; + Hfp = Mode->HSyncStart - Mode->HDisplay; + Hbp = Mode->HTotal - Mode->HSyncEnd; + Vsw = Mode->VSyncEnd - Mode->VSyncStart; + Vfp = Mode->VSyncStart - Mode->VDisplay; + Vbp = Mode->VTotal - Mode->VSyncEnd; + + /* Set Video Format Parameters */ + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TOTAL_LINE_CFG_L, + TOTAL_LINE_CFG_L(Mode->VTotal)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TOTAL_LINE_CFG_H, + TOTAL_LINE_CFG_H(Mode->VTotal >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ACTIVE_LINE_CFG_L, + ACTIVE_LINE_CFG_L(Mode->VDisplay)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ACTIVE_LINE_CFG_H, + ACTIVE_LINE_CFG_H(Mode->VDisplay >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_V_F_PORCH_CFG, + V_F_PORCH_CFG(Vfp)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_V_SYNC_WIDTH_CFG, + V_SYNC_WIDTH_CFG(Vsw)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_V_B_PORCH_CFG, + V_B_PORCH_CFG(Vbp)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TOTAL_PIXEL_CFG_L, + TOTAL_PIXEL_CFG_L(Mode->HTotal)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_TOTAL_PIXEL_CFG_H, + TOTAL_PIXEL_CFG_H(Mode->HTotal >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ACTIVE_PIXEL_CFG_L, + ACTIVE_PIXEL_CFG_L(Mode->HDisplay)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_ACTIVE_PIXEL_CFG_H, + ACTIVE_PIXEL_CFG_H(Mode->HDisplay >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_F_PORCH_CFG_L, + H_F_PORCH_CFG_L(Hfp)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_F_PORCH_CFG_H, + H_F_PORCH_CFG_H(Hfp >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_SYNC_CFG_L, + H_SYNC_CFG_L(Hsw)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_SYNC_CFG_H, + H_SYNC_CFG_H(Hsw >> 8)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_B_PORCH_CFG_L, + H_B_PORCH_CFG_L(Hbp)); + AnalogixDpRegWrite(Dp, ANALOGIX_DP_H_B_PORCH_CFG_H, + H_B_PORCH_CFG_H(Hbp >> 8)); +} + +VOID +DumpHdptxPhyRegisters ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINT32 i, Ret; + UINT32 Shift, BASE; + + if (!Dp->Id) + Shift = BASE = EDP0TX_PHY_BASE; + else + Shift = BASE = EDP1TX_PHY_BASE; + + DEBUG ((DEBUG_WARN, "\nHDPTX_PHY_BASE\n%.8x ", BASE)); + for (i = 0; i < 168; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if((i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE+0x400; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if( (i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE + 0x800; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if((i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE + 0x0C00; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if((i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE + 0x1000; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for ( i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if( (i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE + 0x1400; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if( (i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } + + Shift = BASE + 0x1800; + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 40; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if((i+1) % 4 == 0) { + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } + } +} + +VOID +DumpDpRegisters ( + OUT struct AnalogixDpDevice *Dp + ) +{ + UINTN i; + UINT32 Ret; + UINT32 Shift; + + if (!Dp->Id) + Shift = ANALOGIX_DP0_REG_BASE; + else + Shift = ANALOGIX_DP1_REG_BASE; + + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + for (i = 0; i < 800; i++) { + Ret = MmioRead32(Shift); + Shift = Shift + 0x04; + DEBUG ((DEBUG_WARN, "%.8x ", Ret)); + if( (i+1) % 4 == 0) + DEBUG ((DEBUG_WARN, "\n%.8x ", Shift)); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.c new file mode 100644 index 0000000..fd90c81 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.c @@ -0,0 +1,1706 @@ +/** @file + * + * Synopsys DesignWare DisplayPort 1.4 TX controller driver + * + * This was ported from U-Boot downstream. It currently lacks: + * - EDID and HPD. + * + * After all features are merged in and tested, the code should ideally + * be refactored to meet EDK II conventions. + * + * U-Boot file: drivers/video/drm/dw-dp.c + * + * Copyright (C) 2021 Rockchip Electronics Co., Ltd + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This code can be relicensed as BSD-2-Clause-Patent if permission + * is granted by the original authors. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DPTX_VERSION_NUMBER 0x0000 +#define DPTX_VERSION_TYPE 0x0004 +#define DPTX_ID 0x0008 + +#define DPTX_CONFIG_REG1 0x0100 +#define DPTX_CONFIG_REG2 0x0104 +#define DPTX_CONFIG_REG3 0x0108 + +#define DPTX_CCTL 0x0200 +#define FORCE_HPD BIT(4) +#define DEFAULT_FAST_LINK_TRAIN_EN BIT(2) +#define ENHANCE_FRAMING_EN BIT(1) +#define SCRAMBLE_DIS BIT(0) +#define DPTX_SOFT_RESET_CTRL 0x0204 +#define VIDEO_RESET BIT(5) +#define AUX_RESET BIT(4) +#define AUDIO_SAMPLER_RESET BIT(3) +#define PHY_SOFT_RESET BIT(1) +#define CONTROLLER_RESET BIT(0) + +#define DPTX_VSAMPLE_CTRL 0x0300 +#define PIXEL_MODE_SELECT GENMASK(22, 21) +#define VIDEO_MAPPING GENMASK(20, 16) +#define VIDEO_STREAM_ENABLE BIT(5) +#define DPTX_VSAMPLE_STUFF_CTRL1 0x0304 +#define DPTX_VSAMPLE_STUFF_CTRL2 0x0308 +#define DPTX_VINPUT_POLARITY_CTRL 0x030c +#define DE_IN_POLARITY BIT(2) +#define HSYNC_IN_POLARITY BIT(1) +#define VSYNC_IN_POLARITY BIT(0) +#define DPTX_VIDEO_CONFIG1 0x0310 +#define HACTIVE GENMASK(31, 16) +#define HBLANK GENMASK(15, 2) +#define I_P BIT(1) +#define R_V_BLANK_IN_OSC BIT(0) +#define DPTX_VIDEO_CONFIG2 0x0314 +#define VBLANK GENMASK(31, 16) +#define VACTIVE GENMASK(15, 0) +#define DPTX_VIDEO_CONFIG3 0x0318 +#define H_SYNC_WIDTH GENMASK(31, 16) +#define H_FRONT_PORCH GENMASK(15, 0) +#define DPTX_VIDEO_CONFIG4 0x031c +#define V_SYNC_WIDTH GENMASK(31, 16) +#define V_FRONT_PORCH GENMASK(15, 0) +#define DPTX_VIDEO_CONFIG5 0x0320 +#define INIT_THRESHOLD_HI GENMASK(22, 21) +#define AVERAGE_BYTES_PER_TU_FRAC GENMASK(19, 16) +#define INIT_THRESHOLD GENMASK(13, 7) +#define AVERAGE_BYTES_PER_TU GENMASK(6, 0) +#define DPTX_VIDEO_MSA1 0x0324 +#define VSTART GENMASK(31, 16) +#define HSTART GENMASK(15, 0) +#define DPTX_VIDEO_MSA2 0x0328 +#define MISC0 GENMASK(31, 24) +#define DPTX_VIDEO_MSA3 0x032c +#define MISC1 GENMASK(31, 24) +#define DPTX_VIDEO_HBLANK_INTERVAL 0x0330 +#define HBLANK_INTERVAL_EN BIT(16) +#define HBLANK_INTERVAL GENMASK(15, 0) + +#define DPTX_AUD_CONFIG1 0x0400 +#define AUDIO_TIMESTAMP_VERSION_NUM GENMASK(29, 24) +#define AUDIO_PACKET_ID GENMASK(23, 16) +#define AUDIO_MUTE BIT(15) +#define NUM_CHANNELS GENMASK(14, 12) +#define HBR_MODE_ENABLE BIT(10) +#define AUDIO_DATA_WIDTH GENMASK(9, 5) +#define AUDIO_DATA_IN_EN GENMASK(4, 1) +#define AUDIO_INF_SELECT BIT(0) + +#define DPTX_SDP_VERTICAL_CTRL 0x0500 +#define EN_VERTICAL_SDP BIT(2) +#define EN_AUDIO_STREAM_SDP BIT(1) +#define EN_AUDIO_TIMESTAMP_SDP BIT(0) +#define DPTX_SDP_HORIZONTAL_CTRL 0x0504 +#define EN_HORIZONTAL_SDP BIT(2) +#define DPTX_SDP_STATUS_REGISTER 0x0508 +#define DPTX_SDP_MANUAL_CTRL 0x050c +#define DPTX_SDP_STATUS_EN 0x0510 + +#define DPTX_SDP_REGISTER_BANK 0x0600 +#define SDP_REGS GENMASK(31, 0) + +#define DPTX_PHYIF_CTRL 0x0a00 +#define PHY_WIDTH BIT(25) +#define PHY_POWERDOWN GENMASK(20, 17) +#define PHY_BUSY GENMASK(15, 12) +#define SSC_DIS BIT(16) +#define XMIT_ENABLE GENMASK(11, 8) +#define PHY_LANES GENMASK(7, 6) +#define PHY_RATE GENMASK(5, 4) +#define TPS_SEL GENMASK(3, 0) +#define DPTX_PHY_TX_EQ 0x0a04 +#define DPTX_CUSTOMPAT0 0x0a08 +#define DPTX_CUSTOMPAT1 0x0a0c +#define DPTX_CUSTOMPAT2 0x0a10 +#define DPTX_HBR2_COMPLIANCE_SCRAMBLER_RESET 0x0a14 +#define DPTX_PHYIF_PWRDOWN_CTRL 0x0a18 + +#define DPTX_AUX_CMD 0x0b00 +#define AUX_CMD_TYPE GENMASK(31, 28) +#define AUX_ADDR GENMASK(27, 8) +#define I2C_ADDR_ONLY BIT(4) +#define AUX_LEN_REQ GENMASK(3, 0) +#define DPTX_AUX_STATUS 0x0b04 +#define AUX_TIMEOUT BIT(17) +#define AUX_BYTES_READ GENMASK(23, 19) +#define AUX_STATUS GENMASK(7, 4) +#define DPTX_AUX_DATA0 0x0b08 +#define DPTX_AUX_DATA1 0x0b0c +#define DPTX_AUX_DATA2 0x0b10 +#define DPTX_AUX_DATA3 0x0b14 + +#define DPTX_GENERAL_INTERRUPT 0x0d00 +#define VIDEO_FIFO_OVERFLOW_STREAM0 BIT(6) +#define AUDIO_FIFO_OVERFLOW_STREAM0 BIT(5) +#define SDP_EVENT_STREAM0 BIT(4) +#define AUX_CMD_INVALID BIT(3) +#define AUX_REPLY_EVENT BIT(1) +#define HPD_EVENT BIT(0) +#define DPTX_GENERAL_INTERRUPT_ENABLE 0x0d04 +#define AUX_REPLY_EVENT_EN BIT(1) +#define HPD_EVENT_EN BIT(0) +#define DPTX_HPD_STATUS 0x0d08 +#define HPD_STATE GENMASK(11, 9) +#define HPD_STATUS BIT(8) +#define HPD_HOT_UNPLUG BIT(2) +#define HPD_HOT_PLUG BIT(1) +#define HPD_IRQ BIT(0) +#define DPTX_HPD_INTERRUPT_ENABLE 0x0d0c +#define HPD_UNPLUG_ERR_EN BIT(3) +#define HPD_UNPLUG_EN BIT(2) +#define HPD_PLUG_EN BIT(1) +#define HPD_IRQ_EN BIT(0) + +#define DPTX_MAX_REGISTER DPTX_HPD_INTERRUPT_ENABLE + +#define SDP_REG_BANK_SIZE 16 + +#define DRM_COLOR_FORMAT_RGB444 BIT(0) +#define DRM_COLOR_FORMAT_YCRCB444 BIT(1) +#define DRM_COLOR_FORMAT_YCRCB422 BIT(2) +#define DRM_COLOR_FORMAT_YCRCB420 BIT(3) + +struct drm_dp_link_caps { + bool enhanced_framing; + bool tps3_supported; + bool tps4_supported; + bool channel_coding; + bool ssc; +}; + +struct drm_dp_link_train_set { + unsigned int voltage_swing[4]; + unsigned int pre_emphasis[4]; +}; + +struct drm_dp_link_train { + struct drm_dp_link_train_set request; + struct drm_dp_link_train_set adjust; + bool clock_recovered; + bool channel_equalized; +}; + +struct dw_dp_link { + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + unsigned char revision; + unsigned int rate; + unsigned int lanes; + struct drm_dp_link_caps caps; + struct drm_dp_link_train train; + u8 sink_count; + u8 vsc_sdp_extension_for_colorimetry_supported; +}; + +struct dw_dp_video { + DRM_DISPLAY_MODE mode; + u32 bus_format; + u8 video_mapping; + u8 pixel_mode; + u8 color_format; + u8 bpc; + u8 bpp; +}; + +struct dw_dp_sdp { + struct dp_sdp_header header; + u8 db[32]; + unsigned long flags; +}; + +struct dw_dp { + UINT32 Signature; + ROCKCHIP_CONNECTOR_PROTOCOL connector; + UINTN regmap; + DP_PHY_PROTOCOL *phy; + struct reset_ctl reset; + int id; + + //struct gpio_desc hpd_gpio; + struct drm_dp_aux aux; + struct dw_dp_link link; + struct dw_dp_video video; + + bool force_hpd; + bool force_output; + u32 max_link_rate; +}; + +#define DW_DP_SIGNATURE SIGNATURE_32 ('D', 'W', 'D', 'P') + +#define DW_DP_FROM_CONNECTOR_PROTOCOL(a) CR (a, struct dw_dp, connector, DW_DP_SIGNATURE) +#define DW_DP_FROM_DRM_DP_AUX(a) CR (a, struct dw_dp, aux, DW_DP_SIGNATURE) + +enum { + SOURCE_STATE_IDLE, + SOURCE_STATE_UNPLUG, + SOURCE_STATE_HPD_TIMEOUT = 4, + SOURCE_STATE_PLUG = 7 +}; + +enum { + DPTX_VM_RGB_6BIT, + DPTX_VM_RGB_8BIT, + DPTX_VM_RGB_10BIT, + DPTX_VM_RGB_12BIT, + DPTX_VM_RGB_16BIT, + DPTX_VM_YCBCR444_8BIT, + DPTX_VM_YCBCR444_10BIT, + DPTX_VM_YCBCR444_12BIT, + DPTX_VM_YCBCR444_16BIT, + DPTX_VM_YCBCR422_8BIT, + DPTX_VM_YCBCR422_10BIT, + DPTX_VM_YCBCR422_12BIT, + DPTX_VM_YCBCR422_16BIT, + DPTX_VM_YCBCR420_8BIT, + DPTX_VM_YCBCR420_10BIT, + DPTX_VM_YCBCR420_12BIT, + DPTX_VM_YCBCR420_16BIT, +}; + +enum { + DPTX_MP_SINGLE_PIXEL, + DPTX_MP_DUAL_PIXEL, + DPTX_MP_QUAD_PIXEL, +}; + +enum { + DPTX_SDP_VERTICAL_INTERVAL = BIT(0), + DPTX_SDP_HORIZONTAL_INTERVAL = BIT(1), +}; + +enum { + DPTX_PHY_PATTERN_NONE, + DPTX_PHY_PATTERN_TPS_1, + DPTX_PHY_PATTERN_TPS_2, + DPTX_PHY_PATTERN_TPS_3, + DPTX_PHY_PATTERN_TPS_4, + DPTX_PHY_PATTERN_SERM, + DPTX_PHY_PATTERN_PBRS7, + DPTX_PHY_PATTERN_CUSTOM_80BIT, + DPTX_PHY_PATTERN_CP2520_1, + DPTX_PHY_PATTERN_CP2520_2, +}; + +enum { + DPTX_PHYRATE_RBR, + DPTX_PHYRATE_HBR, + DPTX_PHYRATE_HBR2, + DPTX_PHYRATE_HBR3, +}; + +struct dw_dp_output_format { + u32 bus_format; + u32 color_format; + u8 video_mapping; + u8 bpc; + u8 bpp; +}; + +static const struct dw_dp_output_format possible_output_fmts[] = { + { MEDIA_BUS_FMT_RGB101010_1X30, DRM_COLOR_FORMAT_RGB444, + DPTX_VM_RGB_10BIT, 10, 30 }, + { MEDIA_BUS_FMT_RGB888_1X24, DRM_COLOR_FORMAT_RGB444, + DPTX_VM_RGB_8BIT, 8, 24 }, + { MEDIA_BUS_FMT_YUV10_1X30, DRM_COLOR_FORMAT_YCRCB444, + DPTX_VM_YCBCR444_10BIT, 10, 30 }, + { MEDIA_BUS_FMT_YUV8_1X24, DRM_COLOR_FORMAT_YCRCB444, + DPTX_VM_YCBCR444_8BIT, 8, 24}, + { MEDIA_BUS_FMT_YUYV10_1X20, DRM_COLOR_FORMAT_YCRCB422, + DPTX_VM_YCBCR422_10BIT, 10, 20 }, + { MEDIA_BUS_FMT_YUYV8_1X16, DRM_COLOR_FORMAT_YCRCB422, + DPTX_VM_YCBCR422_8BIT, 8, 16 }, + { MEDIA_BUS_FMT_UYYVYY10_0_5X30, DRM_COLOR_FORMAT_YCRCB420, + DPTX_VM_YCBCR420_10BIT, 10, 15 }, + { MEDIA_BUS_FMT_UYYVYY8_0_5X24, DRM_COLOR_FORMAT_YCRCB420, + DPTX_VM_YCBCR420_8BIT, 8, 12 }, + { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, DRM_COLOR_FORMAT_RGB444, + DPTX_VM_RGB_6BIT, 6, 18 }, +}; + +static int dw_dp_aux_write_data(struct dw_dp *dp, const u8 *buffer, size_t size) +{ + size_t i, j; + + for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num = min_t(size_t, size - i * 4, 4); + u32 value = 0; + + for (j = 0; j < num; j++) + value |= buffer[i * 4 + j] << (j * 8); + + regmap_write(dp->regmap, DPTX_AUX_DATA0 + i * 4, value); + } + + return size; +} + +static int dw_dp_aux_read_data(struct dw_dp *dp, u8 *buffer, size_t size) +{ + size_t i, j; + + for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num = min_t(size_t, size - i * 4, 4); + u32 value; + + regmap_read(dp->regmap, DPTX_AUX_DATA0 + i * 4, &value); + + for (j = 0; j < num; j++) + buffer[i * 4 + j] = value >> (j * 8); + } + + return size; +} + +static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + u32 status, value; + ssize_t ret = 0; + int timeout = 0; + struct dw_dp *dp = DW_DP_FROM_DRM_DP_AUX (aux); + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size); + if (ret < 0) + return ret; + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + break; + default: + return -EINVAL; + } + + if (msg->size > 0) + value = FIELD_PREP(AUX_LEN_REQ, msg->size - 1); + else + value = FIELD_PREP(I2C_ADDR_ONLY, 1); + + value |= FIELD_PREP(AUX_CMD_TYPE, msg->request); + value |= FIELD_PREP(AUX_ADDR, msg->address); + regmap_write(dp->regmap, DPTX_AUX_CMD, value); + + timeout = regmap_read_poll_timeout(dp->regmap, DPTX_GENERAL_INTERRUPT, + status, status & AUX_REPLY_EVENT, + 200, 10); + + if (timeout) { + printf("timeout waiting for AUX reply\n"); + return -ETIMEDOUT; + } + regmap_write(dp->regmap, DPTX_GENERAL_INTERRUPT, AUX_REPLY_EVENT); + + regmap_read(dp->regmap, DPTX_AUX_STATUS, &value); + if (value & AUX_TIMEOUT) { + printf("aux timeout\n"); + return -ETIMEDOUT; + } + + msg->reply = FIELD_GET(AUX_STATUS, value); + + if (msg->size > 0 && msg->reply == DP_AUX_NATIVE_REPLY_ACK) { + if (msg->request & DP_AUX_I2C_READ) { + size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1; + + if (count != msg->size) { + printf("aux fail to read %lu bytes\n", count); + return -EBUSY; + } + + ret = dw_dp_aux_read_data(dp, msg->buffer, count); + if (ret < 0) + return ret; + } + } + + return ret; +} + +static bool dw_dp_bandwidth_ok(struct dw_dp *dp, + const DRM_DISPLAY_MODE *mode, u32 bpp, + unsigned int lanes, unsigned int rate) +{ + u32 max_bw, req_bw; + + req_bw = mode->Clock * bpp / 8; + max_bw = lanes * rate; + if (req_bw > max_bw) + return false; + + return true; +} + +static void dw_dp_hpd_init(struct dw_dp *dp) +{ + /* Enable all HPD interrupts */ + regmap_update_bits(dp->regmap, DPTX_HPD_INTERRUPT_ENABLE, + HPD_UNPLUG_EN | HPD_PLUG_EN | HPD_IRQ_EN, + FIELD_PREP(HPD_UNPLUG_EN, 1) | + FIELD_PREP(HPD_PLUG_EN, 1) | + FIELD_PREP(HPD_IRQ_EN, 1)); + + /* Enable all top-level interrupts */ + regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, + HPD_EVENT_EN, FIELD_PREP(HPD_EVENT_EN, 1)); +} + +static void dw_dp_aux_init(struct dw_dp *dp) +{ + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, + FIELD_PREP(AUX_RESET, 1)); + udelay(10); + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, AUX_RESET, + FIELD_PREP(AUX_RESET, 0)); + + regmap_update_bits(dp->regmap, DPTX_GENERAL_INTERRUPT_ENABLE, + AUX_REPLY_EVENT_EN, + FIELD_PREP(AUX_REPLY_EVENT_EN, 1)); +} + +static void dw_dp_init(struct dw_dp *dp) +{ + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, + FIELD_PREP(CONTROLLER_RESET, 1)); + udelay(10); + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, CONTROLLER_RESET, + FIELD_PREP(CONTROLLER_RESET, 0)); + + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, + FIELD_PREP(PHY_SOFT_RESET, 1)); + udelay(10); + regmap_update_bits(dp->regmap, DPTX_SOFT_RESET_CTRL, PHY_SOFT_RESET, + FIELD_PREP(PHY_SOFT_RESET, 0)); + + regmap_update_bits(dp->regmap, DPTX_CCTL, DEFAULT_FAST_LINK_TRAIN_EN, + FIELD_PREP(DEFAULT_FAST_LINK_TRAIN_EN, 0)); + + dw_dp_hpd_init(dp); + dw_dp_aux_init(dp); +} + +static void dw_dp_phy_set_pattern(struct dw_dp *dp, u32 pattern) +{ + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, TPS_SEL, + FIELD_PREP(TPS_SEL, pattern)); +} + +static void dw_dp_phy_xmit_enable(struct dw_dp *dp, u32 lanes) +{ + u32 xmit_enable; + + switch (lanes) { + case 4: + case 2: + case 1: + xmit_enable = GENMASK(lanes - 1, 0); + break; + case 0: + default: + xmit_enable = 0; + break; + } + + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, XMIT_ENABLE, + FIELD_PREP(XMIT_ENABLE, xmit_enable)); +} + +static int dw_dp_link_power_up(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + u8 value; + int ret; + + if (link->revision < 0x11) + return 0; + + ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); + if (ret < 0) + return ret; + + value &= ~DP_SET_POWER_MASK; + value |= DP_SET_POWER_D0; + + ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); + if (ret < 0) + return ret; + + udelay(1000); + return 0; +} + +static int dw_dp_link_probe(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + u8 dpcd; + int ret; + + ret = drm_dp_read_dpcd_caps(&dp->aux, link->dpcd); + if (ret < 0) + return ret; + + ret = drm_dp_dpcd_readb(&dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, + &dpcd); + if (ret < 0) + return ret; + + link->vsc_sdp_extension_for_colorimetry_supported = + !!(dpcd & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED); + + link->revision = link->dpcd[DP_DPCD_REV]; + link->rate = min_t(u32, min(dp->max_link_rate, dp->phy->Capabilities.MaximumLinkRate * 100), + drm_dp_max_link_rate(link->dpcd)); + link->lanes = min_t(u8, dp->phy->Capabilities.BusWidth, + drm_dp_max_lane_count(link->dpcd)); + + link->caps.enhanced_framing = drm_dp_enhanced_frame_cap(link->dpcd); + link->caps.tps3_supported = drm_dp_tps3_supported(link->dpcd); + link->caps.tps4_supported = drm_dp_tps4_supported(link->dpcd); + link->caps.channel_coding = drm_dp_channel_coding_supported(link->dpcd); + link->caps.ssc = !!(link->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5); + + return 0; +} + +static int dw_dp_link_train_update_vs_emph(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + struct drm_dp_link_train_set *request = &link->train.request; + DP_PHY_CONFIGURATION phy_cfg; + unsigned int lanes = link->lanes, *vs, *pe; + u8 buf[4]; + int i, ret; + + vs = request->voltage_swing; + pe = request->pre_emphasis; + + for (i = 0; i < lanes; i++) { + phy_cfg.LaneVoltageSwingLevels[i] = vs[i]; + phy_cfg.LanePreEmphasisLevels[i] = pe[i]; + } + phy_cfg.LaneCount = lanes; + phy_cfg.LinkRate = link->rate / 100; + phy_cfg.SetLaneCount = false; + phy_cfg.SetLinkRateAndSpreadSpectrum = false; + phy_cfg.SetVoltageSwingAndPreEmphasisLevels = true; + ret = dp->phy->Configure(dp->phy, &phy_cfg); + if (ret) + return ret; + + for (i = 0; i < lanes; i++) + buf[i] = (vs[i] << DP_TRAIN_VOLTAGE_SWING_SHIFT) | + (pe[i] << DP_TRAIN_PRE_EMPHASIS_SHIFT); + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, lanes); + if (ret < 0) + return ret; + + return 0; +} + +static int dw_dp_link_configure(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + DP_PHY_CONFIGURATION phy_cfg; + u8 buf[2]; + int ret, phy_rate; + + /* Move PHY to P3 */ + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x3)); + + phy_cfg.LaneCount = link->lanes; + phy_cfg.LinkRate = link->rate / 100; + phy_cfg.EnableSpreadSpectrum = link->caps.ssc; + phy_cfg.SetLaneCount = true; + phy_cfg.SetLinkRateAndSpreadSpectrum = true; + phy_cfg.SetVoltageSwingAndPreEmphasisLevels = false; + ret = dp->phy->Configure(dp->phy, &phy_cfg); + if (ret) + return ret; + + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, + FIELD_PREP(PHY_LANES, link->lanes / 2)); + + switch (link->rate) { + case 810000: + phy_rate = DPTX_PHYRATE_HBR3; + break; + case 540000: + phy_rate = DPTX_PHYRATE_HBR2; + break; + case 270000: + phy_rate = DPTX_PHYRATE_HBR; + break; + case 162000: + default: + phy_rate = DPTX_PHYRATE_RBR; + break; + } + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, + FIELD_PREP(PHY_RATE, phy_rate)); + + /* Move PHY to P0 */ + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x0)); + + dw_dp_phy_xmit_enable(dp, link->lanes); + + buf[0] = drm_dp_link_rate_to_bw_code(link->rate); + buf[1] = link->lanes; + + if (link->caps.enhanced_framing) { + buf[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, + FIELD_PREP(ENHANCE_FRAMING_EN, 1)); + } else { + regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, + FIELD_PREP(ENHANCE_FRAMING_EN, 0)); + } + + ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, sizeof(buf)); + if (ret < 0) + return ret; + + buf[0] = link->caps.ssc ? DP_SPREAD_AMP_0_5 : 0; + buf[1] = link->caps.channel_coding ? DP_SET_ANSI_8B10B : 0; + + ret = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, + sizeof(buf)); + if (ret < 0) + return ret; + + return 0; +} + +static void dw_dp_link_train_init(struct drm_dp_link_train *train) +{ + struct drm_dp_link_train_set *request = &train->request; + struct drm_dp_link_train_set *adjust = &train->adjust; + unsigned int i; + + for (i = 0; i < 4; i++) { + request->voltage_swing[i] = 0; + adjust->voltage_swing[i] = 0; + + request->pre_emphasis[i] = 0; + adjust->pre_emphasis[i] = 0; + } + + train->clock_recovered = false; + train->channel_equalized = false; +} + +static int dw_dp_link_train_set_pattern(struct dw_dp *dp, u32 pattern) +{ + u8 buf = 0; + int ret; + + if (pattern && pattern != DP_TRAINING_PATTERN_4) { + buf |= DP_LINK_SCRAMBLING_DISABLE; + + regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, + FIELD_PREP(SCRAMBLE_DIS, 1)); + } else { + regmap_update_bits(dp->regmap, DPTX_CCTL, SCRAMBLE_DIS, + FIELD_PREP(SCRAMBLE_DIS, 0)); + } + + switch (pattern) { + case DP_TRAINING_PATTERN_DISABLE: + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); + break; + case DP_TRAINING_PATTERN_1: + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_1); + break; + case DP_TRAINING_PATTERN_2: + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_2); + break; + case DP_TRAINING_PATTERN_3: + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_3); + break; + case DP_TRAINING_PATTERN_4: + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_TPS_4); + break; + default: + return -EINVAL; + } + + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + buf | pattern); + if (ret < 0) + return ret; + + return 0; +} + +static void dw_dp_link_get_adjustments(struct dw_dp_link *link, + u8 status[DP_LINK_STATUS_SIZE]) +{ + struct drm_dp_link_train_set *adjust = &link->train.adjust; + unsigned int i; + + for (i = 0; i < link->lanes; i++) { + adjust->voltage_swing[i] = + drm_dp_get_adjust_request_voltage(status, i) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + + adjust->pre_emphasis[i] = + drm_dp_get_adjust_request_pre_emphasis(status, i) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + } +} + +static void dw_dp_link_train_adjust(struct drm_dp_link_train *train) +{ + struct drm_dp_link_train_set *request = &train->request; + struct drm_dp_link_train_set *adjust = &train->adjust; + unsigned int i; + + for (i = 0; i < 4; i++) + if (request->voltage_swing[i] != adjust->voltage_swing[i]) + request->voltage_swing[i] = adjust->voltage_swing[i]; + + for (i = 0; i < 4; i++) + if (request->pre_emphasis[i] != adjust->pre_emphasis[i]) + request->pre_emphasis[i] = adjust->pre_emphasis[i]; +} + +static int dw_dp_link_clock_recovery(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + u8 status[DP_LINK_STATUS_SIZE]; + unsigned int tries = 0; + int ret; + + ret = dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_1); + if (ret) + return ret; + + for (;;) { + ret = dw_dp_link_train_update_vs_emph(dp); + if (ret) + return ret; + + drm_dp_link_train_clock_recovery_delay(link->dpcd); + + ret = drm_dp_dpcd_read_link_status(&dp->aux, status); + if (ret < 0) { + dev_err(dp->dev, "failed to read link status: %d\n", + ret); + return ret; + } + + if (drm_dp_clock_recovery_ok(status, link->lanes)) { + link->train.clock_recovered = true; + break; + } + + dw_dp_link_get_adjustments(link, status); + + if (link->train.request.voltage_swing[0] == + link->train.adjust.voltage_swing[0]) + tries++; + else + tries = 0; + + if (tries == 5) + break; + + dw_dp_link_train_adjust(&link->train); + } + + return 0; +} + +static int dw_dp_link_channel_equalization(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + u8 status[DP_LINK_STATUS_SIZE], pattern; + unsigned int tries; + int ret; + + if (link->caps.tps4_supported) + pattern = DP_TRAINING_PATTERN_4; + else if (link->caps.tps3_supported) + pattern = DP_TRAINING_PATTERN_3; + else + pattern = DP_TRAINING_PATTERN_2; + ret = dw_dp_link_train_set_pattern(dp, pattern); + if (ret) + return ret; + + for (tries = 1; tries < 5; tries++) { + ret = dw_dp_link_train_update_vs_emph(dp); + if (ret) + return ret; + + drm_dp_link_train_channel_eq_delay(link->dpcd); + + ret = drm_dp_dpcd_read_link_status(&dp->aux, status); + if (ret < 0) + return ret; + + if (!drm_dp_clock_recovery_ok(status, link->lanes)) { + dev_err(dp->dev, + "clock recovery lost while eq\n"); + link->train.clock_recovered = false; + break; + } + + if (drm_dp_channel_eq_ok(status, link->lanes)) { + link->train.channel_equalized = true; + break; + } + + dw_dp_link_get_adjustments(link, status); + dw_dp_link_train_adjust(&link->train); + } + + return 0; +} + +static int dw_dp_link_downgrade(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + struct dw_dp_video *video = &dp->video; + + switch (link->rate) { + case 162000: + return -EINVAL; + case 270000: + link->rate = 162000; + break; + case 540000: + link->rate = 270000; + break; + case 810000: + link->rate = 540000; + break; + } + + if (!dw_dp_bandwidth_ok(dp, &video->mode, video->bpp, link->lanes, + link->rate)) + return -E2BIG; + + return 0; +} + +static int dw_dp_link_train(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + int ret; + +retry: + dw_dp_link_train_init(&link->train); + + printf("training link: %u lane%s at %u MHz\n", + link->lanes, (link->lanes > 1) ? "s" : "", link->rate / 100); + + ret = dw_dp_link_configure(dp); + if (ret < 0) { + dev_err(dp->dev, "failed to configure DP link: %d\n", ret); + return ret; + } + + ret = dw_dp_link_clock_recovery(dp); + if (ret < 0) { + dev_err(dp->dev, "clock recovery failed: %d\n", ret); + goto out; + } + + if (!link->train.clock_recovered) { + dev_err(dp->dev, "clock recovery failed, downgrading link\n"); + + ret = dw_dp_link_downgrade(dp); + if (ret < 0) + goto out; + else + goto retry; + } + + printf("clock recovery succeeded\n"); + + ret = dw_dp_link_channel_equalization(dp); + if (ret < 0) { + dev_err(dp->dev, "channel equalization failed: %d\n", ret); + goto out; + } + + if (!link->train.channel_equalized) { + dev_err(dp->dev, + "channel equalization failed, downgrading link\n"); + + ret = dw_dp_link_downgrade(dp); + if (ret < 0) + goto out; + else + goto retry; + } + + printf("channel equalization succeeded\n"); + +out: + dw_dp_link_train_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE); + return ret; +} + +static int dw_dp_link_enable(struct dw_dp *dp) +{ + int ret; + + ret = dw_dp_link_power_up(dp); + if (ret < 0) + return ret; + + ret = dw_dp_link_train(dp); + if (ret < 0) { + dev_err(dp->dev, "link training failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int dw_dp_set_phy_default_config(struct dw_dp *dp) +{ + struct dw_dp_link *link = &dp->link; + DP_PHY_CONFIGURATION phy_cfg; + int ret, i, phy_rate; + + link->vsc_sdp_extension_for_colorimetry_supported = false; + link->rate = 270000; + link->lanes = dp->phy->Capabilities.BusWidth; + + link->caps.enhanced_framing = true; + link->caps.channel_coding = true; + link->caps.ssc = true; + + /* Move PHY to P3 */ + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x3)); + + for (i = 0; i < link->lanes; i++) { + phy_cfg.LaneVoltageSwingLevels[i] = 3; + phy_cfg.LanePreEmphasisLevels[i] = 0; + } + phy_cfg.LaneCount = link->lanes; + phy_cfg.LinkRate = link->rate / 100; + phy_cfg.EnableSpreadSpectrum = link->caps.ssc; + phy_cfg.SetLaneCount = true; + phy_cfg.SetLinkRateAndSpreadSpectrum = true; + phy_cfg.SetVoltageSwingAndPreEmphasisLevels = true; + ret = dp->phy->Configure(dp->phy, &phy_cfg); + if (ret) + return ret; + + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_LANES, + FIELD_PREP(PHY_LANES, link->lanes / 2)); + + switch (link->rate) { + case 810000: + phy_rate = DPTX_PHYRATE_HBR3; + break; + case 540000: + phy_rate = DPTX_PHYRATE_HBR2; + break; + case 270000: + phy_rate = DPTX_PHYRATE_HBR; + break; + case 162000: + default: + phy_rate = DPTX_PHYRATE_RBR; + break; + } + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_RATE, + FIELD_PREP(PHY_RATE, phy_rate)); + + /* Move PHY to P0 */ + regmap_update_bits(dp->regmap, DPTX_PHYIF_CTRL, PHY_POWERDOWN, + FIELD_PREP(PHY_POWERDOWN, 0x0)); + + dw_dp_phy_xmit_enable(dp, link->lanes); + + regmap_update_bits(dp->regmap, DPTX_CCTL, ENHANCE_FRAMING_EN, + FIELD_PREP(ENHANCE_FRAMING_EN, 1)); + + dw_dp_phy_set_pattern(dp, DPTX_PHY_PATTERN_NONE); + return 0; +} + +static int dw_dp_send_sdp(struct dw_dp *dp, struct dw_dp_sdp *sdp) +{ + const u8 *payload = sdp->db; + u32 reg; + int i, nr = 0; + + reg = DPTX_SDP_REGISTER_BANK + nr * 9 * 4; + + /* SDP header */ + regmap_write(dp->regmap, reg, get_unaligned_le32(&sdp->header)); + + /* SDP data payload */ + for (i = 1; i < 9; i++, payload += 4) + regmap_write(dp->regmap, reg + i * 4, + FIELD_PREP(SDP_REGS, get_unaligned_le32(payload))); + + if (sdp->flags & DPTX_SDP_VERTICAL_INTERVAL) + regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL, + EN_VERTICAL_SDP << nr, + EN_VERTICAL_SDP << nr); + + if (sdp->flags & DPTX_SDP_HORIZONTAL_INTERVAL) + regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL, + EN_HORIZONTAL_SDP << nr, + EN_HORIZONTAL_SDP << nr); + + return 0; +} + +static void dw_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc, + struct dw_dp_sdp *sdp) +{ + sdp->header.HB0 = 0; + sdp->header.HB1 = DP_SDP_VSC; + sdp->header.HB2 = vsc->revision; + sdp->header.HB3 = vsc->length; + + sdp->db[16] = (vsc->pixelformat & 0xf) << 4; + sdp->db[16] |= vsc->colorimetry & 0xf; + + switch (vsc->bpc) { + case 8: + sdp->db[17] = 0x1; + break; + case 10: + sdp->db[17] = 0x2; + break; + case 12: + sdp->db[17] = 0x3; + break; + case 16: + sdp->db[17] = 0x4; + break; + case 6: + default: + break; + } + + if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA) + sdp->db[17] |= 0x80; + + sdp->db[18] = vsc->content_type & 0x7; + + sdp->flags |= DPTX_SDP_VERTICAL_INTERVAL; +} + +static int dw_dp_send_vsc_sdp(struct dw_dp *dp) +{ + struct dw_dp_video *video = &dp->video; + struct drm_dp_vsc_sdp vsc = {}; + struct dw_dp_sdp sdp = {}; + + vsc.revision = 0x5; + vsc.length = 0x13; + + switch (video->color_format) { + case DRM_COLOR_FORMAT_YCRCB444: + vsc.pixelformat = DP_PIXELFORMAT_YUV444; + break; + case DRM_COLOR_FORMAT_YCRCB420: + vsc.pixelformat = DP_PIXELFORMAT_YUV420; + break; + case DRM_COLOR_FORMAT_YCRCB422: + vsc.pixelformat = DP_PIXELFORMAT_YUV422; + break; + case DRM_COLOR_FORMAT_RGB444: + default: + vsc.pixelformat = DP_PIXELFORMAT_RGB; + break; + } + + if (video->color_format == DRM_COLOR_FORMAT_RGB444) + vsc.colorimetry = DP_COLORIMETRY_DEFAULT; + else + vsc.colorimetry = DP_COLORIMETRY_BT709_YCC; + + vsc.bpc = video->bpc; + vsc.dynamic_range = DP_DYNAMIC_RANGE_CTA; + vsc.content_type = DP_CONTENT_TYPE_NOT_DEFINED; + + dw_dp_vsc_sdp_pack(&vsc, &sdp); + + return dw_dp_send_sdp(dp, &sdp); +} + +static int dw_dp_video_set_pixel_mode(struct dw_dp *dp, u8 pixel_mode) +{ + switch (pixel_mode) { + case DPTX_MP_SINGLE_PIXEL: + case DPTX_MP_DUAL_PIXEL: + case DPTX_MP_QUAD_PIXEL: + break; + default: + return -EINVAL; + } + + regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, PIXEL_MODE_SELECT, + FIELD_PREP(PIXEL_MODE_SELECT, pixel_mode)); + + return 0; +} + +static int dw_dp_video_set_msa(struct dw_dp *dp, u8 color_format, u8 bpc, + u16 vstart, u16 hstart) +{ + struct dw_dp_link *link = &dp->link; + u16 misc = 0; + + if (link->vsc_sdp_extension_for_colorimetry_supported) + misc |= DP_MSA_MISC_COLOR_VSC_SDP; + + switch (color_format) { + case DRM_COLOR_FORMAT_RGB444: + misc |= DP_MSA_MISC_COLOR_RGB; + break; + case DRM_COLOR_FORMAT_YCRCB444: + misc |= DP_MSA_MISC_COLOR_YCBCR_444_BT709; + break; + case DRM_COLOR_FORMAT_YCRCB422: + misc |= DP_MSA_MISC_COLOR_YCBCR_422_BT709; + break; + case DRM_COLOR_FORMAT_YCRCB420: + break; + default: + return -EINVAL; + } + + switch (bpc) { + case 6: + misc |= DP_MSA_MISC_6_BPC; + break; + case 8: + misc |= DP_MSA_MISC_8_BPC; + break; + case 10: + misc |= DP_MSA_MISC_10_BPC; + break; + case 12: + misc |= DP_MSA_MISC_12_BPC; + break; + case 16: + misc |= DP_MSA_MISC_16_BPC; + break; + default: + return -EINVAL; + } + + regmap_write(dp->regmap, DPTX_VIDEO_MSA1, + FIELD_PREP(VSTART, vstart) | FIELD_PREP(HSTART, hstart)); + regmap_write(dp->regmap, DPTX_VIDEO_MSA2, FIELD_PREP(MISC0, misc)); + regmap_write(dp->regmap, DPTX_VIDEO_MSA3, FIELD_PREP(MISC1, misc >> 8)); + + return 0; +} + +static int dw_dp_video_enable(struct dw_dp *dp) +{ + struct dw_dp_video *video = &dp->video; + struct dw_dp_link *link = &dp->link; + DRM_DISPLAY_MODE *mode = &video->mode; + u8 color_format = video->color_format; + u8 bpc = video->bpc; + u8 pixel_mode = video->pixel_mode; + u8 bpp = video->bpp, init_threshold, vic; + u32 hactive, hblank, h_sync_width, h_front_porch; + u32 vactive, vblank, v_sync_width, v_front_porch; + u32 vstart = mode->VTotal - mode->VSyncStart; + u32 hstart = mode->HTotal - mode->HSyncStart; + u32 peak_stream_bandwidth, link_bandwidth; + u32 average_bytes_per_tu, average_bytes_per_tu_frac; + u32 ts, hblank_interval; + u32 value; + int ret; + + ret = dw_dp_video_set_pixel_mode(dp, pixel_mode); + if (ret) + return ret; + + ret = dw_dp_video_set_msa(dp, color_format, bpc, vstart, hstart); + if (ret) + return ret; + + regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_MAPPING, + FIELD_PREP(VIDEO_MAPPING, video->video_mapping)); + + /* Configure DPTX_VINPUT_POLARITY_CTRL register */ + value = 0; + if (mode->Flags & DRM_MODE_FLAG_PHSYNC) + value |= FIELD_PREP(HSYNC_IN_POLARITY, 1); + if (mode->Flags & DRM_MODE_FLAG_PVSYNC) + value |= FIELD_PREP(VSYNC_IN_POLARITY, 1); + regmap_write(dp->regmap, DPTX_VINPUT_POLARITY_CTRL, value); + + /* Configure DPTX_VIDEO_CONFIG1 register */ + hactive = mode->HDisplay; + hblank = mode->HTotal - mode->HDisplay; + value = FIELD_PREP(HACTIVE, hactive) | FIELD_PREP(HBLANK, hblank); + if (mode->Flags & DRM_MODE_FLAG_INTERLACE) + value |= FIELD_PREP(I_P, 1); +#if 0 + vic = drm_match_cea_mode(mode); + if (vic == 5 || vic == 6 || vic == 7 || + vic == 10 || vic == 11 || vic == 20 || + vic == 21 || vic == 22 || vic == 39 || + vic == 25 || vic == 26 || vic == 40 || + vic == 44 || vic == 45 || vic == 46 || + vic == 50 || vic == 51 || vic == 54 || + vic == 55 || vic == 58 || vic == 59) + value |= R_V_BLANK_IN_OSC; +#endif + regmap_write(dp->regmap, DPTX_VIDEO_CONFIG1, value); + + /* Configure DPTX_VIDEO_CONFIG2 register */ + vblank = mode->VTotal - mode->VDisplay; + vactive = mode->VDisplay; + regmap_write(dp->regmap, DPTX_VIDEO_CONFIG2, + FIELD_PREP(VBLANK, vblank) | FIELD_PREP(VACTIVE, vactive)); + + /* Configure DPTX_VIDEO_CONFIG3 register */ + h_sync_width = mode->HSyncEnd - mode->HSyncStart; + h_front_porch = mode->HSyncStart - mode->HDisplay; + regmap_write(dp->regmap, DPTX_VIDEO_CONFIG3, + FIELD_PREP(H_SYNC_WIDTH, h_sync_width) | + FIELD_PREP(H_FRONT_PORCH, h_front_porch)); + + /* Configure DPTX_VIDEO_CONFIG4 register */ + v_sync_width = mode->VSyncEnd - mode->VSyncStart; + v_front_porch = mode->VSyncStart - mode->VDisplay; + regmap_write(dp->regmap, DPTX_VIDEO_CONFIG4, + FIELD_PREP(V_SYNC_WIDTH, v_sync_width) | + FIELD_PREP(V_FRONT_PORCH, v_front_porch)); + + /* Configure DPTX_VIDEO_CONFIG5 register */ + peak_stream_bandwidth = mode->Clock * bpp / 8; + link_bandwidth = (link->rate / 1000) * link->lanes; + ts = peak_stream_bandwidth * 64 / link_bandwidth; + average_bytes_per_tu = ts / 1000; + average_bytes_per_tu_frac = ts / 100 - average_bytes_per_tu * 10; + if (pixel_mode == DPTX_MP_SINGLE_PIXEL) { + if (average_bytes_per_tu < 6) + init_threshold = 32; + else if (hblank <= 80 && + color_format != DRM_COLOR_FORMAT_YCRCB420) + init_threshold = 12; + else if (hblank <= 40 && + color_format == DRM_COLOR_FORMAT_YCRCB420) + init_threshold = 3; + else + init_threshold = 16; + } else { + u32 t1 = 0, t2 = 0, t3 = 0; + + switch (bpc) { + case 6: + t1 = (4 * 1000 / 9) * link->lanes; + break; + case 8: + if (color_format == DRM_COLOR_FORMAT_YCRCB422) { + t1 = (1000 / 2) * link->lanes; + } else { + if (pixel_mode == DPTX_MP_DUAL_PIXEL) + t1 = (1000 / 3) * link->lanes; + else + t1 = (3000 / 16) * link->lanes; + } + break; + case 10: + if (color_format == DRM_COLOR_FORMAT_YCRCB422) + t1 = (2000 / 5) * link->lanes; + else + t1 = (4000 / 15) * link->lanes; + break; + case 12: + if (color_format == DRM_COLOR_FORMAT_YCRCB422) { + if (pixel_mode == DPTX_MP_DUAL_PIXEL) + t1 = (1000 / 6) * link->lanes; + else + t1 = (1000 / 3) * link->lanes; + } else { + t1 = (2000 / 9) * link->lanes; + } + break; + case 16: + if (color_format != DRM_COLOR_FORMAT_YCRCB422 && + pixel_mode == DPTX_MP_DUAL_PIXEL) + t1 = (1000 / 6) * link->lanes; + else + t1 = (1000 / 4) * link->lanes; + break; + default: + return -EINVAL; + } + + if (color_format == DRM_COLOR_FORMAT_YCRCB420) + t2 = (link->rate / 4) * 1000 / (mode->Clock / 2); + else + t2 = (link->rate / 4) * 1000 / mode->Clock; + + if (average_bytes_per_tu_frac) + t3 = average_bytes_per_tu + 1; + else + t3 = average_bytes_per_tu; + init_threshold = t1 * t2 * t3 / (1000 * 1000); + if (init_threshold <= 16 || average_bytes_per_tu < 10) + init_threshold = 40; + } + + regmap_write(dp->regmap, DPTX_VIDEO_CONFIG5, + FIELD_PREP(INIT_THRESHOLD_HI, init_threshold >> 6) | + FIELD_PREP(AVERAGE_BYTES_PER_TU_FRAC, + average_bytes_per_tu_frac) | + FIELD_PREP(INIT_THRESHOLD, init_threshold) | + FIELD_PREP(AVERAGE_BYTES_PER_TU, average_bytes_per_tu)); + + /* Configure DPTX_VIDEO_HBLANK_INTERVAL register */ + hblank_interval = hblank * (link->rate / 4) / mode->Clock; + regmap_write(dp->regmap, DPTX_VIDEO_HBLANK_INTERVAL, + FIELD_PREP(HBLANK_INTERVAL_EN, 1) | + FIELD_PREP(HBLANK_INTERVAL, hblank_interval)); + + /* Video stream enable */ + regmap_update_bits(dp->regmap, DPTX_VSAMPLE_CTRL, VIDEO_STREAM_ENABLE, + FIELD_PREP(VIDEO_STREAM_ENABLE, 1)); + + if (link->vsc_sdp_extension_for_colorimetry_supported) + dw_dp_send_vsc_sdp(dp); + + return 0; +} + +static int dw_dp_connector_init(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + CONNECTOR_STATE *conn_state = &state->ConnectorState; + struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn); + int ret; + + conn_state->OutputInterface |= dp->id ? VOP_OUTPUT_IF_DP1 : VOP_OUTPUT_IF_DP0; + conn_state->OutputMode = ROCKCHIP_OUT_MODE_AAAA; + conn_state->ColorSpace = V4L2_COLORSPACE_DEFAULT; + + reset_assert(&dp->reset); + udelay(20); + reset_deassert(&dp->reset); + + dw_dp_init(dp); + dp->phy->PowerOn (dp->phy); + + return ret; +} + +static int dw_dp_connector_get_edid(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + return 0; +} + +static int dw_dp_get_output_fmts_index(u32 bus_format) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(possible_output_fmts); i++) { + const struct dw_dp_output_format *fmt = &possible_output_fmts[i]; + + if (fmt->bus_format == bus_format) + break; + } + + if (i == ARRAY_SIZE(possible_output_fmts)) + return 1; + + return i; +} + +static int dw_dp_connector_prepare(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + CONNECTOR_STATE *conn_state = &state->ConnectorState; + struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn); + struct dw_dp_video *video = &dp->video; + int bus_fmt; + + bus_fmt = dw_dp_get_output_fmts_index(conn_state->BusFormat); + video->video_mapping = possible_output_fmts[bus_fmt].video_mapping; + video->color_format = possible_output_fmts[bus_fmt].color_format; + video->bus_format = possible_output_fmts[bus_fmt].bus_format; + video->bpc = possible_output_fmts[bus_fmt].bpc; + video->bpp = possible_output_fmts[bus_fmt].bpp; + + return 0; +} + +static int dw_dp_connector_enable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + CONNECTOR_STATE *conn_state = &state->ConnectorState; + DRM_DISPLAY_MODE *mode = &conn_state->DisplayMode; + struct dw_dp *dp = DW_DP_FROM_CONNECTOR_PROTOCOL (conn); + struct dw_dp_video *video = &dp->video; + int ret; + + memcpy(&video->mode, mode, sizeof(video->mode)); + video->pixel_mode = DPTX_MP_QUAD_PIXEL; + + if (dp->force_output) { + ret = dw_dp_set_phy_default_config(dp); + if (ret < 0) + printf("failed to set phy_default config: %d\n", ret); + } else { + ret = dw_dp_link_enable(dp); + if (ret < 0) { + printf("failed to enable link: %d\n", ret); + return ret; + } + } + + ret = dw_dp_video_enable(dp); + if (ret < 0) { + printf("failed to enable video: %d\n", ret); + return ret; + } + + return 0; +} + +static int dw_dp_connector_disable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + /* TODO */ + + return 0; +} + +static int dw_dp_connector_detect(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + return 0; +} + +static int dw_dp_ddc_init(struct dw_dp *dp) +{ + dp->aux.name = "dw-dp"; + dp->aux.transfer = dw_dp_aux_transfer; + + return 0; +} + +EFI_STATUS +DwDpConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + + ConnectorState->Type = DRM_MODE_CONNECTOR_DisplayPort; + + return 0; +}; + +EFI_STATUS +DwDpConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_dp_connector_init(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwDpConnectorDetect ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_dp_connector_detect(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwDpConnectorGetEdid ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_dp_connector_get_edid(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwDpConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + /* this should be called by the GOP driver instead */ + dw_dp_connector_prepare (This, DisplayState); + + ret = dw_dp_connector_enable(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwDpConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_dp_connector_disable(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +ROCKCHIP_CONNECTOR_PROTOCOL mDpConnectorOps = { + NULL, + DwDpConnectorPreInit, + DwDpConnectorInit, + NULL, + DwDpConnectorDetect, + NULL, + DwDpConnectorGetEdid, + NULL, + DwDpConnectorEnable, + DwDpConnectorDisable, + NULL +}; + +static struct dw_dp mRk3588Dp[] = { + { + .regmap = 0xfde50000, + .reset = { 0xAE0, 8 }, + .id = 0, + }, + { + .regmap = 0xfde60000, + .reset = { 0xAE0, 9 }, + .id = 1, + }, +}; + +STATIC VOID *mDpPhyEventRegistration; + +STATIC +VOID +DpPhyRegistrationEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_HANDLE Handle; + UINTN BufferSize; + EFI_STATUS Status; + DP_PHY_PROTOCOL *DpPhy; + struct dw_dp *DwDp; + UINTN Index; + + while (TRUE) { + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle (ByRegisterNotify, + NULL, + mDpPhyEventRegistration, + &BufferSize, + &Handle); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_WARN, "%a: Failed to locate gDpPhyProtocolGuid. Status=%r\n", + __FUNCTION__, Status)); + } + break; + } + + Status = gBS->HandleProtocol (Handle, &gDpPhyProtocolGuid, (VOID **) &DpPhy); + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index < ARRAY_SIZE (mRk3588Dp); Index++) { + DwDp = &mRk3588Dp[Index]; + if (DwDp->id == DpPhy->Id) { + DwDp->Signature = DW_DP_SIGNATURE; + DwDp->phy = DpPhy; + DwDp->force_output = TRUE; + CopyMem (&DwDp->connector, &mDpConnectorOps, sizeof (ROCKCHIP_CONNECTOR_PROTOCOL)); + dw_dp_ddc_init (DwDp); + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipConnectorProtocolGuid, + &DwDp->connector, + NULL + ); + break; + } + } + + ASSERT_EFI_ERROR (Status); + break; + } +} + +EFI_STATUS +EFIAPI +DwDpInitDp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EfiCreateProtocolNotifyEvent (&gDpPhyProtocolGuid, + TPL_CALLBACK, + DpPhyRegistrationEventHandler, + NULL, + &mDpPhyEventRegistration); + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf new file mode 100644 index 0000000..11e3dcf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf @@ -0,0 +1,50 @@ +#/** @file +# +# Synopsys DesignWare DisplayPort 1.4 TX controller driver +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DwDpLib + FILE_GUID = e495b4c8-4793-429b-a5c5-5e5fd60bf63b + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwDpInitDp + +[Sources.common] + DwDpLib.c + drm_dp_helper.c + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + UefiBootServicesTableLib + TimerLib + DebugLib + IoLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + RockchipDisplayLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[BuildOptions] + +[Pcd] + +[Protocols] + gRockchipConnectorProtocolGuid ## PRODUCES + gDpPhyProtocolGuid ## CONSUMES + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.c new file mode 100644 index 0000000..ee26379 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.c @@ -0,0 +1,768 @@ +/** @file + Rockchip HDMI Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#define HIWORD_UPDATE(val, mask) (val | (mask) << 16) + +#define RK3588_GRF_SOC_CON2 0x0308 +#define RK3588_HDMI1_HPD_INT_MSK BIT(15) +#define RK3588_HDMI1_HPD_INT_CLR BIT(14) +#define RK3588_HDMI0_HPD_INT_MSK BIT(13) +#define RK3588_HDMI0_HPD_INT_CLR BIT(12) +#define RK3588_GRF_SOC_CON7 0x031c +#define RK3588_SET_HPD_PATH_MASK (0x3 << 12) +#define RK3588_GRF_SOC_STATUS1 0x0384 +#define RK3588_HDMI0_LOW_MORETHAN100MS BIT(20) +#define RK3588_HDMI0_HPD_PORT_LEVEL BIT(19) +#define RK3588_HDMI0_IHPD_PORT BIT(18) +#define RK3588_HDMI0_OHPD_INT BIT(17) +#define RK3588_HDMI0_LEVEL_INT BIT(16) +#define RK3588_HDMI0_INTR_CHANGE_CNT (0x7 << 13) +#define RK3588_HDMI1_LOW_MORETHAN100MS BIT(28) +#define RK3588_HDMI1_HPD_PORT_LEVEL BIT(27) +#define RK3588_HDMI1_IHPD_PORT BIT(26) +#define RK3588_HDMI1_OHPD_INT BIT(25) +#define RK3588_HDMI1_LEVEL_INT BIT(24) +#define RK3588_HDMI1_INTR_CHANGE_CNT (0x7 << 21) + +#define RK3588_GRF_VO1_CON3 0x000c +#define RK3588_COLOR_FORMAT_MASK 0xf +#define RK3588_YUV444 0x2 +#define RK3588_YUV420 0x3 +#define RK3588_COMPRESSED_DATA 0xb +#define RK3588_COLOR_DEPTH_MASK (0xf << 4) +#define RK3588_8BPC 0 +#define RK3588_10BPC (0x6 << 4) +#define RK3588_CECIN_MASK BIT(8) +#define RK3588_SCLIN_MASK BIT(9) +#define RK3588_SDAIN_MASK BIT(10) +#define RK3588_MODE_MASK BIT(11) +#define RK3588_COMPRESS_MODE_MASK BIT(12) +#define RK3588_I2S_SEL_MASK BIT(13) +#define RK3588_SPDIF_SEL_MASK BIT(14) +#define RK3588_GRF_VO1_CON4 0x0010 +#define RK3588_HDMI21_MASK BIT(0) +#define RK3588_GRF_VO1_CON9 0x0024 +#define RK3588_HDMI0_GRANT_SEL BIT(10) +#define RK3588_HDMI0_GRANT_SW BIT(11) +#define RK3588_HDMI1_GRANT_SEL BIT(12) +#define RK3588_HDMI1_GRANT_SW BIT(13) +#define RK3588_GRF_VO1_CON6 0x0018 +#define RK3588_GRF_VO1_CON7 0x001c + +#define PPS_TABLE_LEN 8 + +#define COLOR_DEPTH_10BIT BIT(31) +#define HDMI_FRL_MODE BIT(30) +#define HDMI_EARC_MODE BIT(29) +#define DATA_RATE_MASK 0xFFFFFFF + +#define HDMI20_MAX_RATE 600000 +#define HDMI_8K60_RATE 2376000 + +#define DDC_CI_ADDR 0x37 +#define DDC_SEGMENT_ADDR 0x30 + +#define HDMI_EDID_LEN 512 +#define HDMI_EDID_BLOCK_LEN 128 + +#define DDC_ADDR 0x50 + +VOID +DwHdmiQpRegWrite ( + OUT struct DwHdmiQpDevice *Hdmi, + IN UINT32 Value, + IN UINT32 Offset + ) +{ + UINT32 BASE; + + if (!Hdmi->Id) + BASE = HDMI0_BASE; + else + BASE = HDMI1_BASE; + + MmioWrite32(BASE + Offset, Value); +}; + +UINT32 +DwHdmiQpRegRead ( + OUT struct DwHdmiQpDevice *Hdmi, + IN UINT32 Offset + ) +{ + UINT32 Value; + UINT32 BASE; + + if (!Hdmi->Id) + BASE = HDMI0_BASE; + else + BASE = HDMI1_BASE; + + Value = MmioRead32(BASE + Offset); + return Value; +}; + +VOID +DwHdmiQpRegMod ( + OUT struct DwHdmiQpDevice *Hdmi, + IN UINT32 Value, + IN UINT32 Mask, + IN UINT32 Offset + ) +{ + UINT32 Val; + UINT32 BASE; + + if (!Hdmi->Id) + BASE = HDMI0_BASE; + else + BASE = HDMI1_BASE; + + Val = MmioRead32(BASE + Offset); + Val &= ~Mask; + Val |= Value; + + MmioWrite32(BASE + Offset, Val); +}; + +VOID +DwHdmiQpSetIomux( + OUT struct DwHdmiQpDevice *Hdmi + ) +{ + UINT32 Val; + + if (!Hdmi->Id) { + Val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | + HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | + HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | + HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON3, Val); + + Val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, + RK3588_SET_HPD_PATH_MASK); + MmioWrite32(0xFD58C000 + RK3588_GRF_SOC_CON7, Val); + + Val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, + RK3588_HDMI0_GRANT_SEL); + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON9, Val); + } else { + Val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | + HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | + HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | + HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON6, Val); + + Val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, + RK3588_SET_HPD_PATH_MASK); + MmioWrite32(0xFD58C000 + RK3588_GRF_SOC_CON7, Val); + + Val = HIWORD_UPDATE(RK3588_HDMI1_GRANT_SEL, + RK3588_HDMI1_GRANT_SEL); + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON9, Val); + } +}; + +STATIC +BOOLEAN +DwHdmiI2cPollForIrq( + OUT struct DwHdmiQpDevice *Hdmi +) +{ + struct DwHdmiQpI2c *I2c = &Hdmi->I2c; + UINT32 Stat; + + Stat = DwHdmiQpRegRead(Hdmi, MAINUNIT_1_INT_STATUS); + I2c->Stat = Stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | + I2CM_NACK_RCVD_IRQ); + Hdmi->ScdcIntr = Stat& (SCDC_UPD_FLAGS_RD_IRQ | + SCDC_UPD_FLAGS_CHG_IRQ | + SCDC_UPD_FLAGS_CLR_IRQ | + SCDC_RR_REPLY_STOP_IRQ | + SCDC_NACK_RCVD_IRQ); + + Hdmi->FltIntr = Stat & (FLT_EXIT_TO_LTSP_IRQ | + FLT_EXIT_TO_LTS4_IRQ | + FLT_EXIT_TO_LTSL_IRQ); + + DEBUG((DEBUG_VERBOSE, "i2c main unit irq:%02x\n", Stat)); + if (I2c->Stat) { + DwHdmiQpRegWrite(Hdmi, I2c->Stat, MAINUNIT_1_INT_CLEAR); + I2c->Cmp = TRUE; + } + + if (Hdmi->FltIntr) { + DEBUG((DEBUG_VERBOSE, "i2c flt irq:%02x\n", Hdmi->FltIntr)); + DwHdmiQpRegWrite(Hdmi, Hdmi->FltIntr, MAINUNIT_1_INT_CLEAR); + Hdmi->FltCmp = TRUE; + } + + if (Hdmi->ScdcIntr) { + UINT8 val; + + DEBUG((DEBUG_VERBOSE, "i2c scdc irq:%02x\n", Hdmi->ScdcIntr)); + DwHdmiQpRegWrite(Hdmi, Hdmi->ScdcIntr, MAINUNIT_1_INT_CLEAR); + val = DwHdmiQpRegRead(Hdmi, SCDC_STATUS0); + + /* frl start */ + if (val & BIT(4)) { + DwHdmiQpRegMod(Hdmi, 0, SCDC_UPD_FLAGS_POLL_EN | + SCDC_UPD_FLAGS_AUTO_CLR, SCDC_CONFIG0); + DwHdmiQpRegMod(Hdmi, 0, SCDC_UPD_FLAGS_RD_IRQ, + MAINUNIT_1_INT_MASK_N); + DEBUG((DEBUG_VERBOSE, "frl start\n")); + } + } + + if (Stat) + return TRUE; + + return FALSE; +} + +STATIC +EFI_STATUS +DwHdmiI2cRead( + IN struct DwHdmiQpDevice *Hdmi, + UINT8 *Buf, + UINTN Length +) +{ + EFI_STATUS Status = EFI_SUCCESS; + struct DwHdmiQpI2c *I2c = &Hdmi->I2c; + + if (!I2c->IsRegAddr) { + DEBUG((DEBUG_INFO, "Set read register address to 0\n")); + I2c->SlaveReg = 0x0; + I2c->IsRegAddr = TRUE; + } + + while (Length--) { + I2c->Cmp = FALSE; + DwHdmiQpRegMod(Hdmi, I2c->SlaveReg++ << 12, I2CM_ADDR, I2CM_INTERFACE_CONTROL0); + if (I2c->IsSegment) + DwHdmiQpRegMod(Hdmi, I2CM_EXT_READ, I2CM_WR_MASK, + I2CM_INTERFACE_CONTROL0); + else + DwHdmiQpRegMod(Hdmi, I2CM_FM_READ, I2CM_WR_MASK, + I2CM_INTERFACE_CONTROL0); + + // Wait for transfer done here + int timeout = 10 * 1000; + int interval = 100; + BOOLEAN ret; + while (timeout) { + ret = DwHdmiI2cPollForIrq(Hdmi); + if (I2c->Cmp) + break; + + timeout -= interval; + MicroSecondDelay(interval); + } + + if (!timeout && !ret) { + DEBUG((DEBUG_ERROR, "HDMI I2C read time out!\n")); + DwHdmiQpRegWrite(Hdmi, 0x01, I2CM_CONTROL0); + Status = EFI_TIMEOUT; + goto exit; + } + + if (I2c->Stat & I2CM_NACK_RCVD_IRQ) { + DEBUG((DEBUG_ERROR, "HDMI I2C read error\n")); + DwHdmiQpRegWrite(Hdmi, 0x01, I2CM_CONTROL0); + Status = EFI_DEVICE_ERROR; + goto exit; + } + + MicroSecondDelay(500); + + *Buf = DwHdmiQpRegRead(Hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; + Buf++; + DEBUG((DEBUG_VERBOSE, "i2c read succeed I2c->Stat = %02x 0x%02x RegAddr=%02x\n", I2c->Stat, + DwHdmiQpRegRead(Hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff, + I2c->SlaveReg-1)); + + DwHdmiQpRegMod(Hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); + } + I2c->IsSegment = FALSE; + +exit: + return Status; +} + +STATIC +EFI_STATUS +DwHdmiI2cWrite( + IN struct DwHdmiQpDevice *Hdmi, + UINT8 *Buf, + UINTN Length +) +{ + EFI_STATUS Status = EFI_SUCCESS; + struct DwHdmiQpI2c *I2c = &Hdmi->I2c; + + if (!I2c->IsRegAddr) { + I2c->SlaveReg = Buf[0]; + Length--; + Buf++; + I2c->IsRegAddr = TRUE; + } + + while (Length--) { + I2c->Cmp = FALSE; + DwHdmiQpRegWrite(Hdmi, *Buf, I2CM_INTERFACE_WRDATA_0_3); + Buf++; + DwHdmiQpRegMod(Hdmi, I2c->SlaveReg++ << 12, I2CM_ADDR, I2CM_INTERFACE_CONTROL0); + DwHdmiQpRegMod(Hdmi, I2CM_FM_WRITE, I2CM_WR_MASK, + I2CM_INTERFACE_CONTROL0); + + // Wait for transfer done here + int timeout = 10 * 1000; + int interval = 100; + BOOLEAN ret; + while (timeout) { + ret = DwHdmiI2cPollForIrq(Hdmi); + if (I2c->Cmp) + break; + + timeout -= interval; + MicroSecondDelay(interval); + } + + if (!timeout && !ret) { + DEBUG((DEBUG_ERROR, "HDMI I2C write time out!\n")); + DwHdmiQpRegWrite(Hdmi, 0x01, I2CM_CONTROL0); + Status = EFI_TIMEOUT; + goto exit; + } + + /* Check for error condition on the bus */ + if (I2c->Stat & I2CM_NACK_RCVD_IRQ) { + DEBUG((DEBUG_ERROR, "HDMI I2C write nack!\n")); + DwHdmiQpRegWrite(Hdmi, 0x01, I2CM_CONTROL0); + Status = EFI_DEVICE_ERROR; + goto exit; + } + + DwHdmiQpRegMod(Hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); + } + + DEBUG((DEBUG_VERBOSE, "HDMI I2C write done! I2c->Stat = %02x\n", I2c->Stat)); + +exit: + return Status; +} + +STATIC +EFI_STATUS +DwHdmiQpI2cXfer( + IN struct DwHdmiQpDevice *Hdmi, + IN struct i2c_msg *Msgs, + IN INTN Num +) +{ + EFI_STATUS Status = EFI_SUCCESS; + struct DwHdmiQpI2c *I2c = &Hdmi->I2c; + UINT8 Addr = Msgs[0].addr; + + if (Addr == DDC_CI_ADDR) + /* + * The internal I2C controller does not support the multi-byte + * read and write operations needed for DDC/CI. + * TOFIX: Blacklist the DDC/CI address until we filter out + * unsupported I2C operations. + */ + return EFI_UNSUPPORTED; + + DEBUG((DEBUG_VERBOSE, "HDMI I2C xfer: Num: %d, Addr: %02x\n", + Num, Addr)); + + for (int i = 0; i < Num; i++) { + if (Msgs[i].len == 0) { + DEBUG((DEBUG_ERROR, "Unsupported transfer %d/%d, no data\n", + i + 1, Num)); + return EFI_UNSUPPORTED; + } + } + + /* Unmute DONE and ERROR interrupts */ + DwHdmiQpRegMod(Hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, + I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, + MAINUNIT_1_INT_MASK_N); + + if (Addr == DDC_SEGMENT_ADDR && Msgs[0].len == 1) + Addr = DDC_ADDR; + + DwHdmiQpRegMod(Hdmi, Addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0); + + /* Set slave device register address on transfer */ + I2c->IsRegAddr = FALSE; + + /* Set segment pointer for I2C extended read mode operation */ + I2c->IsSegment = FALSE; + + for (int i = 0; i < Num; i++) { + DEBUG((DEBUG_VERBOSE, "xfer: num: %d/%d, len: %d, flags: %x\n", + i + 1, Num, Msgs[i].len, Msgs[i].flags)); + + if (Msgs[i].addr == DDC_SEGMENT_ADDR && Msgs[i].len == 1) { + I2c->IsSegment = TRUE; + DwHdmiQpRegMod(Hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, + I2CM_INTERFACE_CONTROL1); + DwHdmiQpRegMod(Hdmi, *Msgs[i].buf << 7, I2CM_SEG_PTR, + I2CM_INTERFACE_CONTROL1); + } else { + if (Msgs[i].flags & I2C_M_RD) + Status = DwHdmiI2cRead(Hdmi, Msgs[i].buf, Msgs[i].len); + else + Status = DwHdmiI2cWrite(Hdmi, Msgs[i].buf, Msgs[i].len); + } + + if (Status) + break; + } + + if (Status) + return Status; + + /* Mute DONE and ERROR interrupts */ + DwHdmiQpRegMod(Hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N, + MAINUNIT_1_INT_MASK_N); + + return Status; +} + +STATIC +VOID +DwHdmiI2cInit( + OUT struct DwHdmiQpDevice *Hdmi +) +{ + UINT32 BaseAddr; + if (Hdmi->Id) + BaseAddr = HDMI1_BASE; + else + BaseAddr = HDMI0_BASE; + + /* Software reset */ + DwHdmiQpRegWrite(Hdmi, 0x01, I2CM_CONTROL0); + + DwHdmiQpRegMod(Hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); + + /* Clear DONE and ERROR interrupts */ + DwHdmiQpRegWrite(Hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, + MAINUNIT_1_INT_CLEAR); +} + +STATIC +VOID +DumpEdid(IN struct DwHdmiQpDevice *Hdmi) +{ + DEBUG((DEBUG_INIT, "DwHdmiQpLib.c: Dumping EDID: \n")); + UINT8 EDID[EDID_SIZE]; + UINT8 BaseAddr = 0x0; + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &BaseAddr, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = EDID_SIZE, + .buf = EDID, + } + }; + if(DwHdmiQpI2cXfer(Hdmi, msgs, 2)) { + return; + } + for (int i = 0; i < EDID_SIZE; i++) { + DEBUG((DEBUG_INIT, "%02x ", EDID[i])); + if (!((i + 1) % 8)) + DEBUG((DEBUG_INIT, "\n")); + } +} + +VOID +DwHdmiQpI2cSetIomux( + OUT struct DwHdmiQpDevice *Hdmi + ) +{ + if (!Hdmi->Id) { + switch (Hdmi->I2c.PinMux) { + case 0: + GpioPinSetFunction(4, GPIO_PIN_PB7, 0x5); + GpioPinSetFunction(4, GPIO_PIN_PC0, 0x5); + break; + case 1: + GpioPinSetFunction(0, GPIO_PIN_PD5, 0xb); + GpioPinSetFunction(0, GPIO_PIN_PD4, 0xb); + break; + case 2: + GpioPinSetFunction(3, GPIO_PIN_PC7, 0x5); + GpioPinSetFunction(3, GPIO_PIN_PD0, 0x5); + break; + default: + break; + } + } else { + switch (Hdmi->I2c.PinMux) { + case 0: + GpioPinSetFunction(2, GPIO_PIN_PB4, 0x4); + GpioPinSetFunction(2, GPIO_PIN_PB5, 0x4); + break; + case 1: + GpioPinSetFunction(3, GPIO_PIN_PC5, 0x5); + GpioPinSetFunction(3, GPIO_PIN_PC6, 0x5); + break; + case 2: + GpioPinSetFunction(1, GPIO_PIN_PA3, 0x5); + GpioPinSetFunction(1, GPIO_PIN_PA4, 0x5); + break; + default: + break; + } + } +}; + +EFI_STATUS +DwHdmiQpConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + struct RockchipHdptxPhyHdmi Hdptx; + struct DwHdmiQpDevice *Hdmi; + Hdmi = AllocateZeroPool(sizeof (*Hdmi)); + + DEBUG ((DEBUG_INIT, "DwHdmiQpConnectorPreInit")); + ConnectorState->Type = DRM_MODE_CONNECTOR_HDMIA; + Hdmi->Id = Hdptx.Id = PcdGet32(PcdHdmiId); + Hdmi->I2c.PinMux = PcdGet32(PcdHdmiDDCI2CPinMux); + + if (Hdmi->Id) + ConnectorState->OutputInterface = VOP_OUTPUT_IF_HDMI1; + else + ConnectorState->OutputInterface = VOP_OUTPUT_IF_HDMI0; + + DwHdmiQpSetIomux(Hdmi); + DwHdmiQpI2cSetIomux(Hdmi); + DwHdmiI2cInit(Hdmi); + + HdptxRopllCmnConfig(&Hdptx); + DEBUG ((DEBUG_INFO, "%a hdmi pre init success\n", __func__)); + return 0; +}; + +EFI_STATUS +DwHdmiQpConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + + DEBUG ((DEBUG_INIT, "DwHdmiQpConnectorInit")); + ConnectorState->OutputMode = ROCKCHIP_OUT_MODE_AAAA; + ConnectorState->ColorSpace = V4L2_COLORSPACE_DEFAULT; + + return 0; +}; + +EFI_STATUS +DwHdmiQpConnectorGetEdid ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +VOID +Rk3588SetColorFormat( + OUT struct DwHdmiQpDevice *Hdmi, + IN UINT64 BusFormat, + IN UINT32 Depth + ) +{ + UINT32 Val = 0; + + switch (BusFormat) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB101010_1X30: + Val = HIWORD_UPDATE(0, RK3588_COLOR_FORMAT_MASK); + break; + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + Val = HIWORD_UPDATE(RK3588_YUV420, RK3588_COLOR_FORMAT_MASK); + break; + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + Val = HIWORD_UPDATE(RK3588_YUV444, RK3588_COLOR_FORMAT_MASK); + break; + default: + DEBUG ((DEBUG_INFO, "%a can't set correct color format\n", __func__)); + return; + } + + if (Depth == 8) + Val |= HIWORD_UPDATE(RK3588_8BPC, RK3588_COLOR_DEPTH_MASK); + else + Val |= HIWORD_UPDATE(RK3588_10BPC, RK3588_COLOR_DEPTH_MASK); + + if (!Hdmi->Id) + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON3, Val); + else + MmioWrite32(0xFD5A8000 + RK3588_GRF_VO1_CON6, Val); +} + +VOID +HdmiConfigAvi( + OUT struct DwHdmiQpDevice *Hdmi + ) +{ + /* 1080p60 */ + DwHdmiQpRegWrite(Hdmi, 0x000d0200, PKT_AVI_CONTENTS0); + DwHdmiQpRegWrite(Hdmi, 0x00281027, PKT_AVI_CONTENTS1); + DwHdmiQpRegWrite(Hdmi, 0x00000010, PKT_AVI_CONTENTS2); + DwHdmiQpRegWrite(Hdmi, 0x00000000, PKT_AVI_CONTENTS3); + DwHdmiQpRegWrite(Hdmi, 0x00000000, PKT_AVI_CONTENTS4); + DwHdmiQpRegWrite(Hdmi, 0x00000000, PKT_AVI_CONTENTS5); + DwHdmiQpRegWrite(Hdmi, 0x00000000, PKT_AVI_CONTENTS6); + DwHdmiQpRegWrite(Hdmi, 0x00000000, PKT_AVI_CONTENTS7); +}; + +VOID +DwHdmiQpSetup( + OUT struct DwHdmiQpDevice *Hdmi, + OUT DISPLAY_STATE *DisplayState + ) +{ + struct RockchipHdptxPhyHdmi Hdptx; + CONNECTOR_STATE *ConnectorState = &DisplayState->ConnectorState; + UINT32 Val = 0; + + ConnectorState->Type = DRM_MODE_CONNECTOR_HDMIA; + Hdptx.Id = PcdGet32(PcdHdmiId); + + Val = DwHdmiQpRegRead(Hdmi, 0xb0); + DEBUG ((DEBUG_INIT, "%a Hdptx.Id :%d\n", __func__, Hdptx.Id)); + DEBUG ((DEBUG_INIT, "%a 0xb0:%d\n", __func__, Val)); + Rk3588SetColorFormat(Hdmi, MEDIA_BUS_FMT_RGB888_1X24, 8); + HdmiConfigAvi(Hdmi); + + DwHdmiQpRegMod(Hdmi, 0, OPMODE_DVI, LINK_CONFIG0); + DwHdmiQpRegMod(Hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); + DwHdmiQpRegMod(Hdmi, KEEPOUT_REKEY_ALWAYS, KEEPOUT_REKEY_CFG, FRAME_COMPOSER_CONFIG9); + DwHdmiQpRegWrite(Hdmi, 0, FLT_CONFIG0); + + DumpEdid(Hdmi); + + //enable phy output + HdptxRopllTmdsModeConfig(&Hdptx); + MicroSecondDelay(50); + DwHdmiQpRegWrite(Hdmi, 2, PKTSCHED_PKT_CONTROL0); + DwHdmiQpRegMod(Hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); +}; + +EFI_STATUS +DwHdmiQpConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + struct DwHdmiQpDevice *Hdmi; + Hdmi = AllocatePool(sizeof (*Hdmi)); + DEBUG ((DEBUG_INIT, "DwHdmiQpConnectorEnable\n")); + Hdmi->Id = PcdGet32(PcdHdmiId); + + DwHdmiQpSetup(Hdmi, DisplayState); + + return 0; +}; + +EFI_STATUS +DwHdmiQpConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +EFI_STATUS +DwHdmiQpConnectorDetect ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + //Todo + return 0; +}; + +ROCKCHIP_CONNECTOR_PROTOCOL mHdmi = { + NULL, + DwHdmiQpConnectorPreInit, + DwHdmiQpConnectorInit, + NULL, + DwHdmiQpConnectorDetect, + NULL, + DwHdmiQpConnectorGetEdid, + NULL, + DwHdmiQpConnectorEnable, + DwHdmiQpConnectorDisable, + NULL +}; + +EFI_STATUS +EFIAPI +DwHdmiQpInitHdmi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + DEBUG ((DEBUG_INIT, "hdmi init start\n")); + Handle = NULL; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipConnectorProtocolGuid, + &mHdmi, + NULL + ); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INIT, "hdmi init success\n")); + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf new file mode 100644 index 0000000..c737a08 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf @@ -0,0 +1,63 @@ +#/** @file +# +# Component description file for dw-hdmi-qp module +# +# Copyright (c) 2017, Rockchip Inc. All rights reserved.
    +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DwHdmiQpLib + FILE_GUID = e4000dd0-b732-11ed-887a-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwHdmiQpInitHdmi + +[Sources.common] + DwHdmiQpLib.c + PhyRockchipSamsungHdptxHdmi.c + +[LibraryClasses] + TimerLib + DebugLib + IoLib + BaseLib + BaseMemoryLib + RockchipDisplayLib + MemoryAllocationLib + PWMLib + RockchipPlatformLib + UefiLib + UefiDriverEntryPoint + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[BuildOptions] + +[Pcd] + gRockchipTokenSpaceGuid.PcdLcdPixelFormat + gRockchipTokenSpaceGuid.PcdHdmiId + gRockchipTokenSpaceGuid.PcdHdmiDDCI2CPinMux + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution + +[Protocols] + gRockchipConnectorProtocolGuid + +[Depex] + TRUE + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.c new file mode 100644 index 0000000..e8c90a0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.c @@ -0,0 +1,1623 @@ +/** @file + * + * Synopsys DesignWare MIPI DSI2 controller driver + * + * This was ported from U-Boot downstream. + * + * After all features are merged in and tested, the code should ideally + * be refactored to meet EDK II conventions. + * + * U-Boot file: drivers/video/drm/dw_mipi_dsi2.c + * + * Copyright (C) 2021 Rockchip Electronics Co., Ltd + * Copyright (c) 2023-2024, Mario Bălănică + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This code can be relicensed as BSD-2-Clause-Patent if permission + * is granted by the original authors. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rockchip_phy.h" + +#define UPDATE(v, h, l) (((v) << (l)) & GENMASK((h), (l))) + +#define DSI2_PWR_UP 0x000c +#define RESET 0 +#define POWER_UP BIT(0) +#define CMD_TX_MODE(x) UPDATE(x, 24, 24) +#define DSI2_SOFT_RESET 0x0010 +#define SYS_RSTN BIT(2) +#define PHY_RSTN BIT(1) +#define IPI_RSTN BIT(0) +#define INT_ST_MAIN 0x0014 +#define DSI2_MODE_CTRL 0x0018 +#define DSI2_MODE_STATUS 0x001c +#define DSI2_CORE_STATUS 0x0020 +#define PRI_RD_DATA_AVAIL BIT(26) +#define PRI_FIFOS_NOT_EMPTY BIT(25) +#define PRI_BUSY BIT(24) +#define CRI_RD_DATA_AVAIL BIT(18) +#define CRT_FIFOS_NOT_EMPTY BIT(17) +#define CRI_BUSY BIT(16) +#define IPI_FIFOS_NOT_EMPTY BIT(9) +#define IPI_BUSY BIT(8) +#define CORE_FIFOS_NOT_EMPTY BIT(1) +#define CORE_BUSY BIT(0) +#define MANUAL_MODE_CFG 0x0024 +#define MANUAL_MODE_EN BIT(0) +#define DSI2_TIMEOUT_HSTX_CFG 0x0048 +#define TO_HSTX(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_HSTXRDY_CFG 0x004c +#define TO_HSTXRDY(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_LPRX_CFG 0x0050 +#define TO_LPRXRDY(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_LPTXRDY_CFG 0x0054 +#define TO_LPTXRDY(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_LPTXTRIG_CFG 0x0058 +#define TO_LPTXTRIG(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_LPTXULPS_CFG 0x005c +#define TO_LPTXULPS(x) UPDATE(x, 15, 0) +#define DSI2_TIMEOUT_BTA_CFG 0x60 +#define TO_BTA(x) UPDATE(x, 15, 0) + +#define DSI2_PHY_MODE_CFG 0x0100 +#define PPI_WIDTH(x) UPDATE(x, 9, 8) +#define PHY_LANES(x) UPDATE(x - 1, 5, 4) +#define PHY_TYPE(x) UPDATE(x, 0, 0) +#define DSI2_PHY_CLK_CFG 0X0104 +#define PHY_LPTX_CLK_DIV(x) UPDATE(x, 12, 8) +#define NON_CONTINUOUS_CLK BIT(0) +#define DSI2_PHY_LP2HS_MAN_CFG 0x010c +#define PHY_LP2HS_TIME(x) UPDATE(x, 28, 0) +#define DSI2_PHY_HS2LP_MAN_CFG 0x0114 +#define PHY_HS2LP_TIME(x) UPDATE(x, 28, 0) +#define DSI2_PHY_MAX_RD_T_MAN_CFG 0x011c +#define PHY_MAX_RD_TIME(x) UPDATE(x, 26, 0) +#define DSI2_PHY_ESC_CMD_T_MAN_CFG 0x0124 +#define PHY_ESC_CMD_TIME(x) UPDATE(x, 28, 0) +#define DSI2_PHY_ESC_BYTE_T_MAN_CFG 0x012c +#define PHY_ESC_BYTE_TIME(x) UPDATE(x, 28, 0) + +#define DSI2_PHY_IPI_RATIO_MAN_CFG 0x0134 +#define PHY_IPI_RATIO(x) UPDATE(x, 21, 0) +#define DSI2_PHY_SYS_RATIO_MAN_CFG 0x013C +#define PHY_SYS_RATIO(x) UPDATE(x, 16, 0) + +#define DSI2_DSI_GENERAL_CFG 0x0200 +#define BTA_EN BIT(1) +#define EOTP_TX_EN BIT(0) +#define DSI2_DSI_VCID_CFG 0x0204 +#define TX_VCID(x) UPDATE(x, 1, 0) +#define DSI2_DSI_SCRAMBLING_CFG 0x0208 +#define SCRAMBLING_SEED(x) UPDATE(x, 31, 16) +#define SCRAMBLING_EN BIT(0) +#define DSI2_DSI_VID_TX_CFG 0x020c +#define LPDT_DISPLAY_CMD_EN BIT(20) +#define BLK_VFP_HS_EN BIT(14) +#define BLK_VBP_HS_EN BIT(13) +#define BLK_VSA_HS_EN BIT(12) +#define BLK_HFP_HS_EN BIT(6) +#define BLK_HBP_HS_EN BIT(5) +#define BLK_HSA_HS_EN BIT(4) +#define VID_MODE_TYPE(x) UPDATE(x, 1, 0) +#define DSI2_CRI_TX_HDR 0x02c0 +#define CMD_TX_MODE(x) UPDATE(x, 24, 24) +#define DSI2_CRI_TX_PLD 0x02c4 +#define DSI2_CRI_RX_HDR 0x02c8 +#define DSI2_CRI_RX_PLD 0x02cc + +#define DSI2_IPI_COLOR_MAN_CFG 0x0300 +#define IPI_DEPTH(x) UPDATE(x, 7, 4) +#define IPI_DEPTH_5_6_5_BITS 0x02 +#define IPI_DEPTH_6_BITS 0x03 +#define IPI_DEPTH_8_BITS 0x05 +#define IPI_DEPTH_10_BITS 0x06 +#define IPI_FORMAT(x) UPDATE(x, 3, 0) +#define IPI_FORMAT_RGB 0x0 +#define IPI_FORMAT_DSC 0x0b +#define DSI2_IPI_VID_HSA_MAN_CFG 0x0304 +#define VID_HSA_TIME(x) UPDATE(x, 29, 0) +#define DSI2_IPI_VID_HBP_MAN_CFG 0x030c +#define VID_HBP_TIME(x) UPDATE(x, 29, 0) +#define DSI2_IPI_VID_HACT_MAN_CFG 0x0314 +#define VID_HACT_TIME(x) UPDATE(x, 29, 0) +#define DSI2_IPI_VID_HLINE_MAN_CFG 0x031c +#define VID_HLINE_TIME(x) UPDATE(x, 29, 0) +#define DSI2_IPI_VID_VSA_MAN_CFG 0x0324 +#define VID_VSA_LINES(x) UPDATE(x, 9, 0) +#define DSI2_IPI_VID_VBP_MAN_CFG 0X032C +#define VID_VBP_LINES(x) UPDATE(x, 9, 0) +#define DSI2_IPI_VID_VACT_MAN_CFG 0X0334 +#define VID_VACT_LINES(x) UPDATE(x, 13, 0) +#define DSI2_IPI_VID_VFP_MAN_CFG 0X033C +#define VID_VFP_LINES(x) UPDATE(x, 9, 0) +#define DSI2_IPI_PIX_PKT_CFG 0x0344 +#define MAX_PIX_PKT(x) UPDATE(x, 15, 0) + +#define DSI2_INT_ST_PHY 0x0400 +#define DSI2_INT_MASK_PHY 0x0404 +#define DSI2_INT_ST_TO 0x0410 +#define DSI2_INT_MASK_TO 0x0414 +#define DSI2_INT_ST_ACK 0x0420 +#define DSI2_INT_MASK_ACK 0x0424 +#define DSI2_INT_ST_IPI 0x0430 +#define DSI2_INT_MASK_IPI 0x0434 +#define DSI2_INT_ST_FIFO 0x0440 +#define DSI2_INT_MASK_FIFO 0x0444 +#define DSI2_INT_ST_PRI 0x0450 +#define DSI2_INT_MASK_PRI 0x0454 +#define DSI2_INT_ST_CRI 0x0460 +#define DSI2_INT_MASK_CRI 0x0464 +#define DSI2_INT_FORCE_CRI 0x0468 +#define DSI2_MAX_REGISGER DSI2_INT_FORCE_CRI + +#define CMD_PKT_STATUS_TIMEOUT_US 1000 +#define MODE_STATUS_TIMEOUT_US 20000 +#define SYS_CLK 351000000LL +#define PSEC_PER_SEC 1000000000000LL +#define USEC_PER_SEC 1000000L +#define MSEC_PER_SEC 1000L + +#define GRF_REG_FIELD(reg, lsb, msb) (((reg) << 16) | ((lsb) << 8) | (msb)) + +enum vid_mode_type { + VID_MODE_TYPE_NON_BURST_SYNC_PULSES, + VID_MODE_TYPE_NON_BURST_SYNC_EVENTS, + VID_MODE_TYPE_BURST, +}; + +enum mode_ctrl { + IDLE_MODE, + AUTOCALC_MODE, + COMMAND_MODE, + VIDEO_MODE, + DATA_STREAM_MODE, + VIDE_TEST_MODE, + DATA_STREAM_TEST_MODE, +}; + +enum grf_reg_fields { + TXREQCLKHS_EN, + GATING_EN, + IPI_SHUTDN, + IPI_COLORM, + IPI_COLOR_DEPTH, + IPI_FORMAT, + MAX_FIELDS, +}; + +enum phy_type { + DPHY, + CPHY, +}; + +enum ppi_width { + PPI_WIDTH_8_BITS, + PPI_WIDTH_16_BITS, + PPI_WIDTH_32_BITS, +}; + +#pragma pack(1) +struct rockchip_cmd_header { + u8 data_type; + u8 delay_ms; + u8 payload_length; +}; +#pragma pack() + +struct rockchip_cmd_desc { + struct rockchip_cmd_header header; + const u8 *payload; +}; + +struct rockchip_panel_cmds { + struct rockchip_cmd_desc *cmds; + int cmd_cnt; +}; + +struct dw_mipi_dsi2_plat_data { + const u32 *dsi0_grf_reg_fields; + const u32 *dsi1_grf_reg_fields; + unsigned long long dphy_max_bit_rate_per_lane; + unsigned long long cphy_max_symbol_rate_per_lane; +}; + +struct mipi_dcphy { + /* Non-SNPS PHY */ + struct rockchip_phy *phy; + + u16 input_div; + u16 feedback_div; +}; + +/** + * struct mipi_dphy_configure - MIPI D-PHY configuration set + * + * This structure is used to represent the configuration state of a + * MIPI D-PHY phy. + */ +struct mipi_dphy_configure { + unsigned int clk_miss; + unsigned int clk_post; + unsigned int clk_pre; + unsigned int clk_prepare; + unsigned int clk_settle; + unsigned int clk_term_en; + unsigned int clk_trail; + unsigned int clk_zero; + unsigned int d_term_en; + unsigned int eot; + unsigned int hs_exit; + unsigned int hs_prepare; + unsigned int hs_settle; + unsigned int hs_skip; + unsigned int hs_trail; + unsigned int hs_zero; + unsigned int init; + unsigned int lpx; + unsigned int ta_get; + unsigned int ta_go; + unsigned int ta_sure; + unsigned int wakeup; + unsigned long hs_clk_rate; + unsigned long lp_clk_rate; + unsigned char lanes; +}; + +struct dw_mipi_dsi2 { + UINT32 Signature; + ROCKCHIP_CONNECTOR_PROTOCOL connector; + UINTN base; + UINTN grf; + int id; + struct dw_mipi_dsi2 *master; + struct dw_mipi_dsi2 *slave; + bool prepared; + + bool auto_calc_mode; + bool c_option; + bool dsc_enable; + bool scrambling_en; + unsigned int slice_width; + unsigned int slice_height; + u32 version_major; + u32 version_minor; + + unsigned int lane_hs_rate; /* Kbps/Ksps per lane */ + u32 channel; + u32 lanes; + u32 format; + u32 mode_flags; + u64 mipi_pixel_rate; + struct mipi_dcphy dcphy; + DRM_DISPLAY_MODE mode; + bool data_swap; + + struct mipi_dsi_host host; + struct mipi_dsi_device *device; + struct mipi_dphy_configure mipi_dphy_cfg; + const struct dw_mipi_dsi2_plat_data *pdata; + struct drm_dsc_picture_parameter_set *pps; + + ROCKCHIP_DSI_PANEL_PROTOCOL *RockchipDsiPanel; +}; + +#define DW_MIPI_DSI2_SIGNATURE SIGNATURE_32 ('D', 'W', 'd', '2') + +#define DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(a) \ + CR (a, struct dw_mipi_dsi2, connector, DW_MIPI_DSI2_SIGNATURE) + +#define DW_MIPI_DSI2_FROM_MIPI_DSI_HOST(a) \ + CR (a, struct dw_mipi_dsi2, host, DW_MIPI_DSI2_SIGNATURE) + +static int rockchip_panel_parse_cmds(const u8 *data, int length, + struct rockchip_panel_cmds *pcmds) +{ + int len; + const u8 *buf; + const struct rockchip_cmd_header *header; + int i, cnt = 0; + + /* scan commands */ + cnt = 0; + buf = data; + len = length; + while (len > sizeof(*header)) { + header = (const struct rockchip_cmd_header *)buf; + buf += sizeof(*header) + header->payload_length; + len -= sizeof(*header) + header->payload_length; + cnt++; + } + + pcmds->cmds = calloc(cnt, sizeof(struct rockchip_cmd_desc)); + if (!pcmds->cmds) + return -ENOMEM; + + pcmds->cmd_cnt = cnt; + + buf = data; + len = length; + for (i = 0; i < cnt; i++) { + struct rockchip_cmd_desc *desc = &pcmds->cmds[i]; + + header = (const struct rockchip_cmd_header *)buf; + length -= sizeof(*header); + buf += sizeof(*header); + desc->header.data_type = header->data_type; + desc->header.delay_ms = header->delay_ms; + desc->header.payload_length = header->payload_length; + desc->payload = buf; + buf += header->payload_length; + length -= header->payload_length; + } + + return 0; +} + +static int rockchip_panel_send_dsi_cmds(struct mipi_dsi_device *dsi, + struct rockchip_panel_cmds *cmds) +{ + int i, ret; + struct drm_dsc_picture_parameter_set *pps = NULL; + + if (!cmds) + return -EINVAL; + + for (i = 0; i < cmds->cmd_cnt; i++) { + struct rockchip_cmd_desc *desc = &cmds->cmds[i]; + const struct rockchip_cmd_header *header = &desc->header; + + switch (header->data_type) { + case MIPI_DSI_COMPRESSION_MODE: + ret = mipi_dsi_compression_mode(dsi, desc->payload[0]); + break; + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_LONG_WRITE: + ret = mipi_dsi_generic_write(dsi, desc->payload, + header->payload_length); + break; + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_LONG_WRITE: + ret = mipi_dsi_dcs_write_buffer(dsi, desc->payload, + header->payload_length); + break; + case MIPI_DSI_PICTURE_PARAMETER_SET: + pps = AllocateZeroPool(sizeof(*pps)); + if (!pps) + return -ENOMEM; + + memcpy(pps, desc->payload, header->payload_length); + ret = mipi_dsi_picture_parameter_set(dsi, pps); + free(pps); + break; + default: + printf("unsupport command data type: %d\n", + header->data_type); + return -EINVAL; + } + + if (ret < 0) { + printf("failed to write cmd%d: %d\n", i, ret); + return ret; + } + + if (header->delay_ms) + mdelay(header->delay_ms); + } + + return 0; +} + +static int rockchip_panel_init(struct dw_mipi_dsi2 *dsi2) +{ + ROCKCHIP_DSI_PANEL_PROTOCOL *Panel = dsi2->RockchipDsiPanel; + const void *data; + int len = 0; + int ret; + struct rockchip_panel_cmds *on_cmds; + + Panel->Prepare(Panel); + + data = Panel->InitSequence; + len = Panel->InitSequenceLength; + + if (data) { + on_cmds = calloc(1, sizeof(*on_cmds)); + if (!on_cmds) + return -ENOMEM; + + ret = rockchip_panel_parse_cmds(data, len, on_cmds); + if (ret) { + printf("failed to parse panel init sequence\n"); + goto free_on_cmds; + } + + ret = rockchip_panel_send_dsi_cmds(dsi2->device, on_cmds); + if (ret) + printf("failed to send on cmds: %d\n", ret); + } + + return 0; + +free_on_cmds: + free(on_cmds); + return ret; +} + +static inline void dsi_write(struct dw_mipi_dsi2 *dsi2, u32 reg, u32 val) +{ + writel(val, dsi2->base + reg); +} + +static inline u32 dsi_read(struct dw_mipi_dsi2 *dsi2, u32 reg) +{ + return readl(dsi2->base + reg); +} + +static inline void dsi_update_bits(struct dw_mipi_dsi2 *dsi2, + u32 reg, u32 mask, u32 val) +{ + u32 orig, tmp; + + orig = dsi_read(dsi2, reg); + tmp = orig & ~mask; + tmp |= val & mask; + dsi_write(dsi2, reg, tmp); +} + +static void grf_field_write(struct dw_mipi_dsi2 *dsi2, enum grf_reg_fields index, + unsigned int val) +{ + const u32 field = dsi2->id ? dsi2->pdata->dsi1_grf_reg_fields[index] : + dsi2->pdata->dsi0_grf_reg_fields[index]; + u16 reg; + u8 msb, lsb; + + if (!field) + return; + + reg = (field >> 16) & 0xffff; + lsb = (field >> 8) & 0xff; + msb = (field >> 0) & 0xff; + + regmap_write(dsi2->grf, reg, GENMASK(msb, lsb) << 16 | val << lsb); +} + +static unsigned long dw_mipi_dsi2_get_lane_rate(struct dw_mipi_dsi2 *dsi2) +{ + const DRM_DISPLAY_MODE *mode = &dsi2->mode; + ROCKCHIP_DSI_PANEL_PROTOCOL *Panel = dsi2->RockchipDsiPanel; + u64 max_lane_rate, lane_rate; + unsigned int value; + int bpp, lanes; + u64 tmp; + + max_lane_rate = (dsi2->c_option) ? + dsi2->pdata->cphy_max_symbol_rate_per_lane : + dsi2->pdata->dphy_max_bit_rate_per_lane; + + /* + * optional override of the desired bandwidth + * High-Speed mode: Differential and terminated: 80Mbps ~ 4500 Mbps + */ + value = Panel->DsiLaneRate; + if (value >= 80000 && value <= 4500000) + return value * MSEC_PER_SEC; + else if (value >= 80 && value <= 4500) + return value * USEC_PER_SEC; + + bpp = mipi_dsi_pixel_format_to_bpp(dsi2->format); + if (bpp < 0) + bpp = 24; + + lanes = dsi2->slave ? dsi2->lanes * 2 : dsi2->lanes; + tmp = (u64)mode->CrtcClock * 1000 * bpp; + do_div(tmp, lanes); + + if (dsi2->c_option) + tmp = DIV_ROUND_CLOSEST(tmp * 100, 228); + + /* set BW a little larger only in video burst mode in + * consideration of the protocol overhead and HS mode + * switching to BLLP mode, take 1 / 0.9, since Mbps must + * big than bandwidth of RGB + */ + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { + tmp *= 10; + do_div(tmp, 9); + } + + if (tmp > max_lane_rate) + lane_rate = max_lane_rate; + else + lane_rate = tmp; + + return lane_rate; +} + +static int cri_fifos_wait_avail(struct dw_mipi_dsi2 *dsi2) +{ + u32 sts, mask; + int ret; + + mask = CRI_BUSY | CRT_FIFOS_NOT_EMPTY; + ret = readl_poll_timeout(dsi2->base + DSI2_CORE_STATUS, + sts, !(sts & mask), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + printf("command interface is busy: 0x%x\n", sts); + return ret; + } + + return 0; +} + +static int dw_mipi_dsi2_read_from_fifo(struct dw_mipi_dsi2 *dsi2, + const struct mipi_dsi_msg *msg) +{ + u8 *payload = msg->rx_buf; + u8 data_type; + u16 wc; + int i, j, ret, len = msg->rx_len; + unsigned int vrefresh = DrmModeVRefresh(&dsi2->mode); + u32 val; + + ret = readl_poll_timeout(dsi2->base + DSI2_CORE_STATUS, + val, val & CRI_RD_DATA_AVAIL, + DIV_ROUND_UP(1000000, vrefresh)); + if (ret) { + printf("CRI has no available read data\n"); + return ret; + } + + val = dsi_read(dsi2, DSI2_CRI_RX_HDR); + data_type = val & 0x3f; + + if (mipi_dsi_packet_format_is_short(data_type)) { + for (i = 0; i < len && i < 2; i++) + payload[i] = (val >> (8 * (i + 1))) & 0xff; + + return 0; + } + + wc = (val >> 8) & 0xffff; + /* Receive payload */ + for (i = 0; i < len && i < wc; i += 4) { + val = dsi_read(dsi2, DSI2_CRI_RX_PLD); + for (j = 0; j < 4 && j + i < len && j + i < wc; j++) + payload[i + j] = val >> (8 * j); + } + + return 0; +} + +static ssize_t dw_mipi_dsi2_transfer(struct dw_mipi_dsi2 *dsi2, + const struct mipi_dsi_msg *msg) +{ + struct mipi_dsi_packet packet; + int ret; + int val; + u32 mode; + + dsi_update_bits(dsi2, DSI2_DSI_VID_TX_CFG, LPDT_DISPLAY_CMD_EN, + msg->flags & MIPI_DSI_MSG_USE_LPM ? + LPDT_DISPLAY_CMD_EN : 0); + + /* create a packet to the DSI protocol */ + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { + printf("failed to create packet: %d\n", ret); + return ret; + } + + /* check cri interface is not busy */ + ret = cri_fifos_wait_avail(dsi2); + if (ret) + return ret; + + /* Send payload */ + while (DIV_ROUND_UP(packet.payload_length, 4)) { + if (packet.payload_length < 4) { + /* send residu payload */ + val = 0; + memcpy(&val, packet.payload, packet.payload_length); + dsi_write(dsi2, DSI2_CRI_TX_PLD, val); + packet.payload_length = 0; + } else { + val = get_unaligned_le32(packet.payload); + dsi_write(dsi2, DSI2_CRI_TX_PLD, val); + packet.payload += 4; + packet.payload_length -= 4; + } + } + + /* Send packet header */ + mode = CMD_TX_MODE(msg->flags & MIPI_DSI_MSG_USE_LPM ? 1 : 0); + val = get_unaligned_le32(packet.header); + dsi_write(dsi2, DSI2_CRI_TX_HDR, mode | val); + + ret = cri_fifos_wait_avail(dsi2); + if (ret) + return ret; + + if (msg->rx_len) { + ret = dw_mipi_dsi2_read_from_fifo(dsi2, msg); + if (ret < 0) + return ret; + } + + if (dsi2->slave) { + ret = dw_mipi_dsi2_transfer(dsi2->slave, msg); + if (ret < 0) + return ret; + } + + return msg->rx_len ? msg->rx_len : msg->tx_len; +} + +static void dw_mipi_dsi2_ipi_color_coding_cfg(struct dw_mipi_dsi2 *dsi2) +{ + u32 val, color_depth; + + switch (dsi2->format) { + case MIPI_DSI_FMT_RGB666: + case MIPI_DSI_FMT_RGB666_PACKED: + color_depth = IPI_DEPTH_6_BITS; + break; + case MIPI_DSI_FMT_RGB565: + color_depth = IPI_DEPTH_5_6_5_BITS; + break; + case MIPI_DSI_FMT_RGB888: + default: + color_depth = IPI_DEPTH_8_BITS; + break; + } + + val = IPI_DEPTH(color_depth) | + IPI_FORMAT(dsi2->dsc_enable ? IPI_FORMAT_DSC : IPI_FORMAT_RGB); + dsi_write(dsi2, DSI2_IPI_COLOR_MAN_CFG, val); + grf_field_write(dsi2, IPI_COLOR_DEPTH, color_depth); + + if (dsi2->dsc_enable) + grf_field_write(dsi2, IPI_FORMAT, IPI_FORMAT_DSC); +} + +static void dw_mipi_dsi2_ipi_set(struct dw_mipi_dsi2 *dsi2) +{ + DRM_DISPLAY_MODE *mode = &dsi2->mode; + u32 hline, hsa, hbp, hact; + u64 hline_time, hsa_time, hbp_time, hact_time, tmp; + u64 pixel_clk, phy_hs_clk; + u32 vact, vsa, vfp, vbp; + u16 val; + + if (dsi2->slave || dsi2->master) + val = mode->HDisplay / 2; + else + val = mode->HDisplay; + + dsi_write(dsi2, DSI2_IPI_PIX_PKT_CFG, MAX_PIX_PKT(val)); + + dw_mipi_dsi2_ipi_color_coding_cfg(dsi2); + + if (dsi2->auto_calc_mode) + return; + + /* + * if the controller is intended to operate in data stream mode, + * no more steps are required. + */ + if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) + return; + + vact = mode->VDisplay; + vsa = mode->VSyncEnd - mode->VSyncStart; + vfp = mode->VSyncStart - mode->VDisplay; + vbp = mode->VTotal - mode->VSyncEnd; + hact = mode->HDisplay; + hsa = mode->HSyncEnd - mode->HSyncStart; + hbp = mode->HTotal - mode->HSyncEnd; + hline = mode->HTotal; + + pixel_clk = mode->CrtcClock * MSEC_PER_SEC; + + if (dsi2->c_option) + phy_hs_clk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 7); + else + phy_hs_clk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 16); + + tmp = hsa * phy_hs_clk; + hsa_time = DIV_ROUND_CLOSEST(tmp << 16, pixel_clk); + dsi_write(dsi2, DSI2_IPI_VID_HSA_MAN_CFG, VID_HSA_TIME(hsa_time)); + + tmp = hbp * phy_hs_clk; + hbp_time = DIV_ROUND_CLOSEST(tmp << 16, pixel_clk); + dsi_write(dsi2, DSI2_IPI_VID_HBP_MAN_CFG, VID_HBP_TIME(hbp_time)); + + tmp = hact * phy_hs_clk; + hact_time = DIV_ROUND_CLOSEST(tmp << 16, pixel_clk); + dsi_write(dsi2, DSI2_IPI_VID_HACT_MAN_CFG, VID_HACT_TIME(hact_time)); + + tmp = hline * phy_hs_clk; + hline_time = DIV_ROUND_CLOSEST(tmp << 16, pixel_clk); + dsi_write(dsi2, DSI2_IPI_VID_HLINE_MAN_CFG, VID_HLINE_TIME(hline_time)); + + dsi_write(dsi2, DSI2_IPI_VID_VSA_MAN_CFG, VID_VSA_LINES(vsa)); + dsi_write(dsi2, DSI2_IPI_VID_VBP_MAN_CFG, VID_VBP_LINES(vbp)); + dsi_write(dsi2, DSI2_IPI_VID_VACT_MAN_CFG, VID_VACT_LINES(vact)); + dsi_write(dsi2, DSI2_IPI_VID_VFP_MAN_CFG, VID_VFP_LINES(vfp)); +} + +static void dw_mipi_dsi2_set_vid_mode(struct dw_mipi_dsi2 *dsi2) +{ + u32 val = 0, mode; + int ret; + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_HFP) + val |= BLK_HFP_HS_EN; + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_HBP) + val |= BLK_HBP_HS_EN; + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_HSA) + val |= BLK_HSA_HS_EN; + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |= VID_MODE_TYPE_BURST; + else if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; + else + val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; + + dsi_write(dsi2, DSI2_DSI_VID_TX_CFG, val); + + dsi_write(dsi2, DSI2_MODE_CTRL, VIDEO_MODE); + ret = readl_poll_timeout(dsi2->base + DSI2_MODE_STATUS, + mode, mode & VIDEO_MODE, + MODE_STATUS_TIMEOUT_US); + if (ret < 0) + printf("failed to enter video mode\n"); +} + +static void dw_mipi_dsi2_set_data_stream_mode(struct dw_mipi_dsi2 *dsi2) +{ + u32 mode; + int ret; + + dsi_write(dsi2, DSI2_MODE_CTRL, DATA_STREAM_MODE); + ret = readl_poll_timeout(dsi2->base + DSI2_MODE_STATUS, + mode, mode & DATA_STREAM_MODE, + MODE_STATUS_TIMEOUT_US); + if (ret < 0) + printf("failed to enter data stream mode\n"); +} + +static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2) +{ + u32 mode; + int ret; + + dsi_write(dsi2, DSI2_MODE_CTRL, COMMAND_MODE); + ret = readl_poll_timeout(dsi2->base + DSI2_MODE_STATUS, + mode, mode & COMMAND_MODE, + MODE_STATUS_TIMEOUT_US); + if (ret < 0) + printf("failed to enter cmd mode\n"); +} + +static void dw_mipi_dsi2_enable(struct dw_mipi_dsi2 *dsi2) +{ + u32 mode; + int ret; + + dw_mipi_dsi2_ipi_set(dsi2); + + if (dsi2->auto_calc_mode) { + dsi_write(dsi2, DSI2_MODE_CTRL, AUTOCALC_MODE); + ret = readl_poll_timeout(dsi2->base + DSI2_MODE_STATUS, + mode, mode == IDLE_MODE, + MODE_STATUS_TIMEOUT_US); + if (ret < 0) + printf("auto calculation training failed\n"); + } + + if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO) + dw_mipi_dsi2_set_vid_mode(dsi2); + else + dw_mipi_dsi2_set_data_stream_mode(dsi2); + + if (dsi2->slave) + dw_mipi_dsi2_enable(dsi2->slave); +} + +static void dw_mipi_dsi2_disable(struct dw_mipi_dsi2 *dsi2) +{ + dsi_write(dsi2, DSI2_IPI_PIX_PKT_CFG, 0); + dw_mipi_dsi2_set_cmd_mode(dsi2); + + if (dsi2->slave) + dw_mipi_dsi2_disable(dsi2->slave); +} + +static void dw_mipi_dsi2_post_disable(struct dw_mipi_dsi2 *dsi2) +{ + if (!dsi2->prepared) + return; + + dsi_write(dsi2, DSI2_PWR_UP, RESET); + + if (dsi2->dcphy.phy) + rockchip_phy_power_off(dsi2->dcphy.phy); + + dsi2->prepared = false; + + if (dsi2->slave) + dw_mipi_dsi2_post_disable(dsi2->slave); +} + +static int dw_mipi_dsi2_connector_pre_init(ROCKCHIP_CONNECTOR_PROTOCOL *conn, + DISPLAY_STATE *state) +{ + CONNECTOR_STATE *conn_state = &state->ConnectorState; + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + struct mipi_dsi_host *host = &dsi2->host; + struct mipi_dsi_device *device; + + conn_state->Type = DRM_MODE_CONNECTOR_DSI; + + device = dsi2->device; + if (!device) + return -ENODEV; + + device->host = host; + mipi_dsi_attach(device); + + return 0; +} + +static int dw_mipi_dsi2_get_dsc_params_from_sink(struct dw_mipi_dsi2 *dsi2) +{ + struct udevice *dev = dsi2->device->dev; + ROCKCHIP_DSI_PANEL_PROTOCOL *Panel = dsi2->RockchipDsiPanel; + struct rockchip_cmd_header *header; + struct drm_dsc_picture_parameter_set *pps = NULL; + u8 *dsc_packed_pps; + const void *data; + int len; + + dsi2->c_option = Panel->CPhyEnable; + dsi2->scrambling_en = Panel->ScramblingEnable; + dsi2->dsc_enable = Panel->DscEnable; + + if (dsi2->slave) { + dsi2->slave->c_option = dsi2->c_option; + dsi2->slave->scrambling_en = dsi2->scrambling_en; + dsi2->slave->dsc_enable = dsi2->dsc_enable; + } + + if (!dsi2->dsc_enable) + return 0; + + dsi2->slice_width = Panel->SliceWidth; + dsi2->slice_height = Panel->SliceHeight; + dsi2->version_major = Panel->VersionMajor; + dsi2->version_minor = Panel->VersionMinor; + + data = Panel->InitSequence; + len = Panel->InitSequenceLength; + + if (!data) + return -EINVAL; + + while (len > sizeof(*header)) { + header = (struct rockchip_cmd_header *)data; + data += sizeof(*header); + len -= sizeof(*header); + + if (header->payload_length > len) + return -EINVAL; + + if (header->data_type == MIPI_DSI_PICTURE_PARAMETER_SET) { + dsc_packed_pps = calloc(1, header->payload_length); + if (!dsc_packed_pps) + return -ENOMEM; + + memcpy(dsc_packed_pps, data, header->payload_length); + pps = (struct drm_dsc_picture_parameter_set *)dsc_packed_pps; + break; + } + + data += header->payload_length; + len -= header->payload_length; + } + + if (!pps) { + printf("not found dsc pps definition\n"); + return -EINVAL; + } + + dsi2->pps = pps; + + if (dsi2->slave) { + u16 pic_width = be16_to_cpu(pps->pic_width) / 2; + + dsi2->pps->pic_width = cpu_to_be16(pic_width); + printf("dsc pic_width change from %d to %d\n", pic_width * 2, pic_width); + } + + return 0; +} + +static int dw_mipi_dsi2_connector_init(ROCKCHIP_CONNECTOR_PROTOCOL *conn, DISPLAY_STATE *state) +{ + CONNECTOR_STATE *conn_state = &state->ConnectorState; + CRTC_STATE *cstate = &state->CrtcState; + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + struct rockchip_phy *phy = NULL; + struct udevice *phy_dev; + struct udevice *dev; + int ret; + + conn_state->OutputMode = ROCKCHIP_OUT_MODE_P888; + conn_state->ColorSpace = V4L2_COLORSPACE_DEFAULT; + conn_state->OutputInterface |= + dsi2->id ? VOP_OUTPUT_IF_MIPI1 : VOP_OUTPUT_IF_MIPI0; + + if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) { + conn_state->OutputFlags |= ROCKCHIP_OUTPUT_MIPI_DS_MODE; + conn_state->hold_mode = true; + } + +#if 0 + if (dsi2->lanes > 4) { + ret = uclass_get_device_by_name(UCLASS_DISPLAY, + "dsi@fde30000", + &dev); + if (ret) + return ret; + + dsi2->slave = dev_get_priv(dev); + if (!dsi2->slave) + return -ENODEV; + + dsi2->slave->master = dsi2; + dsi2->lanes /= 2; + + dsi2->slave->auto_calc_mode = dsi2->auto_calc_mode; + dsi2->slave->lanes = dsi2->lanes; + dsi2->slave->format = dsi2->format; + dsi2->slave->mode_flags = dsi2->mode_flags; + dsi2->slave->channel = dsi2->channel; + conn_state->OutputFlags |= + ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; + if (dsi2->data_swap) + conn_state->OutputFlags |= ROCKCHIP_OUTPUT_DATA_SWAP; + + conn_state->OutputInterface |= VOP_OUTPUT_IF_MIPI1; + + ret = uclass_get_device_by_phandle(UCLASS_PHY, dev, + "phys", &phy_dev); + if (ret) + return -ENODEV; + + phy = (struct rockchip_phy *)dev_get_driver_data(phy_dev); + if (!phy) + return -ENODEV; + + dsi2->slave->dcphy.phy = phy; + if (phy->funcs && phy->funcs->init) + return phy->funcs->init(phy); + } +#endif + + dw_mipi_dsi2_get_dsc_params_from_sink(dsi2); + + if (dsi2->dsc_enable) { + cstate->dsc_enable = 1; + cstate->dsc_sink_cap.version_major = dsi2->version_major; + cstate->dsc_sink_cap.version_minor = dsi2->version_minor; + cstate->dsc_sink_cap.slice_width = dsi2->slice_width; + cstate->dsc_sink_cap.slice_height = dsi2->slice_height; + /* only can support rgb888 panel now */ + cstate->dsc_sink_cap.target_bits_per_pixel_x16 = 8 << 4; + cstate->dsc_sink_cap.native_420 = 0; + memcpy(&cstate->pps, dsi2->pps, sizeof(struct drm_dsc_picture_parameter_set)); + } + + return 0; +} + +/* + * Minimum D-PHY timings based on MIPI D-PHY specification. Derived + * from the valid ranges specified in Section 6.9, Table 14, Page 41 + * of the D-PHY specification (v2.1). + */ +int mipi_dphy_get_default_config(unsigned long long hs_clk_rate, + struct mipi_dphy_configure *cfg) +{ + unsigned long long ui; + + if (!cfg) + return -EINVAL; + + ui = ALIGN(PSEC_PER_SEC, hs_clk_rate); + do_div(ui, hs_clk_rate); + + cfg->clk_miss = 0; + cfg->clk_post = 60000 + 52 * ui; + cfg->clk_pre = 8000; + cfg->clk_prepare = 38000; + cfg->clk_settle = 95000; + cfg->clk_term_en = 0; + cfg->clk_trail = 60000; + cfg->clk_zero = 262000; + cfg->d_term_en = 0; + cfg->eot = 0; + cfg->hs_exit = 100000; + cfg->hs_prepare = 40000 + 4 * ui; + cfg->hs_zero = 105000 + 6 * ui; + cfg->hs_settle = 85000 + 6 * ui; + cfg->hs_skip = 40000; + + /* + * The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40) + * contains this formula as: + * + * T_HS-TRAIL = max(n * 8 * ui, 60 + n * 4 * ui) + * + * where n = 1 for forward-direction HS mode and n = 4 for reverse- + * direction HS mode. There's only one setting and this function does + * not parameterize on anything other that ui, so this code will + * assumes that reverse-direction HS mode is supported and uses n = 4. + */ + cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui); + + cfg->init = 100; + cfg->lpx = 60000; + cfg->ta_get = 5 * cfg->lpx; + cfg->ta_go = 4 * cfg->lpx; + cfg->ta_sure = 2 * cfg->lpx; + cfg->wakeup = 1000; + + return 0; +} + +static void dw_mipi_dsi2_set_hs_clk(struct dw_mipi_dsi2 *dsi2, unsigned long rate) +{ + mipi_dphy_get_default_config(rate, &dsi2->mipi_dphy_cfg); + + if (!dsi2->c_option) + rockchip_phy_set_mode(dsi2->dcphy.phy, PHY_MODE_MIPI_DPHY); + + rate = rockchip_phy_set_pll(dsi2->dcphy.phy, rate); + dsi2->lane_hs_rate = DIV_ROUND_CLOSEST(rate, MSEC_PER_SEC); +} + +static void dw_mipi_dsi2_host_softrst(struct dw_mipi_dsi2 *dsi2) +{ + dsi_write(dsi2, DSI2_SOFT_RESET, 0X0); + udelay(100); + dsi_write(dsi2, DSI2_SOFT_RESET, SYS_RSTN | PHY_RSTN | IPI_RSTN); +} + +static void +dw_mipi_dsi2_work_mode(struct dw_mipi_dsi2 *dsi2, u32 mode) +{ + /* + * select controller work in Manual mode + * Manual: MANUAL_MODE_EN + * Automatic: 0 + */ + dsi_write(dsi2, MANUAL_MODE_CFG, mode); +} + +static void dw_mipi_dsi2_phy_mode_cfg(struct dw_mipi_dsi2 *dsi2) +{ + u32 val = 0; + + /* PPI width is fixed to 16 bits in DCPHY */ + val |= PPI_WIDTH(PPI_WIDTH_16_BITS) | PHY_LANES(dsi2->lanes); + val |= PHY_TYPE(dsi2->c_option ? CPHY : DPHY); + dsi_write(dsi2, DSI2_PHY_MODE_CFG, val); +} + +static void dw_mipi_dsi2_phy_clk_mode_cfg(struct dw_mipi_dsi2 *dsi2) +{ + u32 sys_clk = SYS_CLK / USEC_PER_SEC; + u32 esc_clk_div; + u32 val = 0; + + if (dsi2->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) + val |= NON_CONTINUOUS_CLK; + + /* The Escape clock ranges from 1MHz to 20MHz. */ + esc_clk_div = DIV_ROUND_UP(sys_clk, 20 * 2); + val |= PHY_LPTX_CLK_DIV(esc_clk_div); + + dsi_write(dsi2, DSI2_PHY_CLK_CFG, val); +} + +static void dw_mipi_dsi2_phy_ratio_cfg(struct dw_mipi_dsi2 *dsi2) +{ + u64 ipi_clk, phy_hsclk, tmp; + + /* + * in DPHY mode, the phy_hstx_clk is exactly 1/16 the Lane high-speed + * data rate; In CPHY mode, the phy_hstx_clk is exactly 1/7 the trio + * high speed symbol rate. + */ + if (dsi2->c_option) + phy_hsclk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 7); + + else + phy_hsclk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 16); + + /* IPI_RATIO_MAN_CFG = PHY_HSTX_CLK / IPI_CLK */ + ipi_clk = dsi2->mipi_pixel_rate; + + tmp = DIV_ROUND_CLOSEST(phy_hsclk << 16, ipi_clk); + dsi_write(dsi2, DSI2_PHY_IPI_RATIO_MAN_CFG, PHY_IPI_RATIO(tmp)); + + /* SYS_RATIO_MAN_CFG = MIPI_DCPHY_HSCLK_Freq / SYS_CLK */ + tmp = DIV_ROUND_CLOSEST(phy_hsclk << 16, SYS_CLK); + dsi_write(dsi2, DSI2_PHY_SYS_RATIO_MAN_CFG, PHY_SYS_RATIO(tmp)); +} + +static void dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(struct dw_mipi_dsi2 *dsi2) +{ + struct mipi_dphy_configure *cfg = &dsi2->mipi_dphy_cfg; + unsigned long long tmp, ui; + unsigned long long hstx_clk; + + hstx_clk = DIV_ROUND_CLOSEST(dsi2->lane_hs_rate * MSEC_PER_SEC, 16); + + ui = ALIGN(PSEC_PER_SEC, hstx_clk); + do_div(ui, hstx_clk); + + /* PHY_LP2HS_TIME = (TLPX + THS-PREPARE + THS-ZERO) / Tphy_hstx_clk */ + tmp = cfg->lpx + cfg->hs_prepare + cfg->hs_zero; + tmp = DIV_ROUND_CLOSEST(tmp << 16, ui); + dsi_write(dsi2, DSI2_PHY_LP2HS_MAN_CFG, PHY_LP2HS_TIME(tmp)); + + /* PHY_HS2LP_TIME = (THS-TRAIL + THS-EXIT) / Tphy_hstx_clk */ + tmp = cfg->hs_trail + cfg->hs_exit; + tmp = DIV_ROUND_CLOSEST(tmp << 16, ui); + dsi_write(dsi2, DSI2_PHY_HS2LP_MAN_CFG, PHY_HS2LP_TIME(tmp)); +} + +static void dw_mipi_dsi2_phy_init(struct dw_mipi_dsi2 *dsi2) +{ + dw_mipi_dsi2_phy_mode_cfg(dsi2); + dw_mipi_dsi2_phy_clk_mode_cfg(dsi2); + + if (dsi2->auto_calc_mode) + return; + + dw_mipi_dsi2_phy_ratio_cfg(dsi2); + dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(dsi2); + + /* phy configuration 8 - 10 */ +} + +static void dw_mipi_dsi2_tx_option_set(struct dw_mipi_dsi2 *dsi2) +{ + u32 val; + + val = BTA_EN | EOTP_TX_EN; + + if (dsi2->mode_flags & MIPI_DSI_MODE_EOT_PACKET) + val &= ~EOTP_TX_EN; + + dsi_write(dsi2, DSI2_DSI_GENERAL_CFG, val); + dsi_write(dsi2, DSI2_DSI_VCID_CFG, TX_VCID(dsi2->channel)); + + if (dsi2->scrambling_en) + dsi_write(dsi2, DSI2_DSI_SCRAMBLING_CFG, SCRAMBLING_EN); +} + +static void dw_mipi_dsi2_irq_enable(struct dw_mipi_dsi2 *dsi2, bool enable) +{ + if (enable) { + dsi_write(dsi2, DSI2_INT_MASK_PHY, 0x1); + dsi_write(dsi2, DSI2_INT_MASK_TO, 0xf); + dsi_write(dsi2, DSI2_INT_MASK_ACK, 0x1); + dsi_write(dsi2, DSI2_INT_MASK_IPI, 0x1); + dsi_write(dsi2, DSI2_INT_MASK_FIFO, 0x1); + dsi_write(dsi2, DSI2_INT_MASK_PRI, 0x1); + dsi_write(dsi2, DSI2_INT_MASK_CRI, 0x1); + } else { + dsi_write(dsi2, DSI2_INT_MASK_PHY, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_TO, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_ACK, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_IPI, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_FIFO, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_PRI, 0x0); + dsi_write(dsi2, DSI2_INT_MASK_CRI, 0x0); + }; +} + +static void mipi_dcphy_power_on(struct dw_mipi_dsi2 *dsi2) +{ + if (!dsi2->dcphy.phy) + return; + + rockchip_phy_power_on(dsi2->dcphy.phy); +} + +static void dw_mipi_dsi2_pre_enable(struct dw_mipi_dsi2 *dsi2) +{ + if (dsi2->prepared) + return; + + dw_mipi_dsi2_host_softrst(dsi2); + dsi_write(dsi2, DSI2_PWR_UP, RESET); + + dw_mipi_dsi2_work_mode(dsi2, dsi2->auto_calc_mode ? 0 : MANUAL_MODE_EN); + dw_mipi_dsi2_phy_init(dsi2); + dw_mipi_dsi2_tx_option_set(dsi2); + dw_mipi_dsi2_irq_enable(dsi2, 0); + mipi_dcphy_power_on(dsi2); + dsi_write(dsi2, DSI2_PWR_UP, POWER_UP); + dw_mipi_dsi2_set_cmd_mode(dsi2); + + dsi2->prepared = true; + + if (dsi2->slave) + dw_mipi_dsi2_pre_enable(dsi2->slave); +} + +static void dw_mipi_dsi2_get_mipi_pixel_clk(struct dw_mipi_dsi2 *dsi2, + CRTC_STATE *s) +{ + DRM_DISPLAY_MODE *mode = &dsi2->mode; + u8 k = dsi2->slave ? 2 : 1; + + /* 1.When MIPI works in uncompressed mode: + * (Video Timing Pixel Rate)/(4)=(MIPI Pixel ClockxK)=(dclk_out×K)=dclk_core + * 2.When MIPI works in compressed mode: + * MIPI Pixel Clock = cds_clk / 2 + * MIPI is configured as double channel display mode, K=2, otherwise K=1. + */ + if (dsi2->dsc_enable) { + dsi2->mipi_pixel_rate = s->dsc_cds_clk_rate / 2; + if (dsi2->slave) + dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate; + + return; + } + + dsi2->mipi_pixel_rate = (mode->CrtcClock * MSEC_PER_SEC) / (4 * k); + if (dsi2->slave) + dsi2->slave->mipi_pixel_rate = dsi2->mipi_pixel_rate; +} + +static int dw_mipi_dsi2_connector_prepare(ROCKCHIP_CONNECTOR_PROTOCOL *conn, + DISPLAY_STATE *state) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + CONNECTOR_STATE *conn_state = &state->ConnectorState; + CRTC_STATE *cstate = &state->CrtcState; + unsigned long lane_rate; + + memcpy(&dsi2->mode, &conn_state->DisplayMode, sizeof(DRM_DISPLAY_MODE)); + if (dsi2->slave) + memcpy(&dsi2->slave->mode, &dsi2->mode, + sizeof(DRM_DISPLAY_MODE)); + + dw_mipi_dsi2_get_mipi_pixel_clk(dsi2, cstate); + + lane_rate = dw_mipi_dsi2_get_lane_rate(dsi2); + if (dsi2->dcphy.phy) + dw_mipi_dsi2_set_hs_clk(dsi2, lane_rate); + + if (dsi2->slave && dsi2->slave->dcphy.phy) + dw_mipi_dsi2_set_hs_clk(dsi2->slave, lane_rate); + + printf("final DSI-Link bandwidth: %u %a x %d\n", + dsi2->lane_hs_rate, dsi2->c_option ? "Ksps" : "Kbps", + dsi2->slave ? dsi2->lanes * 2 : dsi2->lanes); + + dw_mipi_dsi2_pre_enable(dsi2); + + return 0; +} + +static void dw_mipi_dsi2_connector_unprepare(ROCKCHIP_CONNECTOR_PROTOCOL *conn, + DISPLAY_STATE *state) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + + dw_mipi_dsi2_post_disable(dsi2); +} + +static int dw_mipi_dsi2_connector_enable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, + DISPLAY_STATE *state) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + + dw_mipi_dsi2_enable(dsi2); + + rockchip_panel_init(dsi2); + + return 0; +} + +static int dw_mipi_dsi2_connector_disable(ROCKCHIP_CONNECTOR_PROTOCOL *conn, + DISPLAY_STATE *state) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_CONNECTOR_PROTOCOL(conn); + + dw_mipi_dsi2_disable(dsi2); + + return 0; +} + +EFI_STATUS +DwMipiDsi2ConnectorPreInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_mipi_dsi2_connector_pre_init(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +}; + +EFI_STATUS +DwMipiDsi2ConnectorInit ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_mipi_dsi2_connector_init(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwMipiDsi2ConnectorEnable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + /* this should be called by the GOP driver instead */ + dw_mipi_dsi2_connector_prepare (This, DisplayState); + + ret = dw_mipi_dsi2_connector_enable(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +DwMipiDsi2ConnectorDisable ( + OUT ROCKCHIP_CONNECTOR_PROTOCOL *This, + OUT DISPLAY_STATE *DisplayState + ) +{ + int ret; + + ret = dw_mipi_dsi2_connector_disable(This, DisplayState); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +ROCKCHIP_CONNECTOR_PROTOCOL mDwMipiDsi2ConnectorOps = { + NULL, + DwMipiDsi2ConnectorPreInit, + DwMipiDsi2ConnectorInit, + NULL, + NULL, + NULL, + NULL, + NULL, + DwMipiDsi2ConnectorEnable, + DwMipiDsi2ConnectorDisable, + NULL +}; + +static const u32 rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = { + [TXREQCLKHS_EN] = GRF_REG_FIELD(0x0000, 11, 11), + [GATING_EN] = GRF_REG_FIELD(0x0000, 10, 10), + [IPI_SHUTDN] = GRF_REG_FIELD(0x0000, 9, 9), + [IPI_COLORM] = GRF_REG_FIELD(0x0000, 8, 8), + [IPI_COLOR_DEPTH] = GRF_REG_FIELD(0x0000, 4, 7), + [IPI_FORMAT] = GRF_REG_FIELD(0x0000, 0, 3), +}; + +static const u32 rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = { + [TXREQCLKHS_EN] = GRF_REG_FIELD(0x0004, 11, 11), + [GATING_EN] = GRF_REG_FIELD(0x0004, 10, 10), + [IPI_SHUTDN] = GRF_REG_FIELD(0x0004, 9, 9), + [IPI_COLORM] = GRF_REG_FIELD(0x0004, 8, 8), + [IPI_COLOR_DEPTH] = GRF_REG_FIELD(0x0004, 4, 7), + [IPI_FORMAT] = GRF_REG_FIELD(0x0004, 0, 3), +}; + +static const struct dw_mipi_dsi2_plat_data rk3588_mipi_dsi2_plat_data = { + .dsi0_grf_reg_fields = rk3588_dsi0_grf_reg_fields, + .dsi1_grf_reg_fields = rk3588_dsi1_grf_reg_fields, + .dphy_max_bit_rate_per_lane = 4500000000ULL, + .cphy_max_symbol_rate_per_lane = 2000000000ULL, +}; + +static ssize_t dw_mipi_dsi2_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_MIPI_DSI_HOST(host); + + return dw_mipi_dsi2_transfer(dsi2, msg); +} + +static int dw_mipi_dsi2_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi2 *dsi2 = DW_MIPI_DSI2_FROM_MIPI_DSI_HOST(host); + + if (device->lanes < 1 || device->lanes > 8) + return -EINVAL; + + dsi2->lanes = device->lanes; + dsi2->channel = device->channel; + dsi2->format = device->format; + dsi2->mode_flags = device->mode_flags; + dsi2->device = device; + + return 0; +} + +static const struct mipi_dsi_host_ops dw_mipi_dsi2_host_ops = { + .attach = dw_mipi_dsi2_host_attach, + .transfer = dw_mipi_dsi2_host_transfer, +}; + +static int dw_mipi_dsi2_child_post_bind(struct dw_mipi_dsi2 *dsi2) +{ + struct mipi_dsi_host *host = &dsi2->host; + struct mipi_dsi_device *device = NULL; + ROCKCHIP_DSI_PANEL_PROTOCOL *Panel = dsi2->RockchipDsiPanel; + + device = AllocatePool(sizeof (struct mipi_dsi_device)); + if (device == NULL) { + return -ENOMEM; + } + + host->ops = &dw_mipi_dsi2_host_ops; + + device->host = host; + + device->lanes = Panel->DsiLanes; + device->format = Panel->DsiFormat; + device->mode_flags = Panel->DsiFlags; + device->channel = 0; + + dw_mipi_dsi2_host_attach(host, device); + + return 0; +} + +struct dw_mipi_dsi2 mRk3588MipiDsi[] = { + { + .base = 0xfde20000, + .grf = RK3588_VOP_GRF_BASE, + .id = 0, + .pdata = &rk3588_mipi_dsi2_plat_data, + }, + { + .base = 0xfde30000, + .grf = RK3588_VOP_GRF_BASE, + .id = 1, + .pdata = &rk3588_mipi_dsi2_plat_data, + }, +}; + +STATIC VOID *mDsiPanelEventRegistration; + +STATIC +VOID +DsiPanelRegistrationEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_HANDLE Handle; + UINTN BufferSize; + EFI_STATUS Status; + ROCKCHIP_DSI_PANEL_PROTOCOL *DsiPanel; + struct dw_mipi_dsi2 *dsi2; + UINTN Index; + + while (TRUE) { + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle (ByRegisterNotify, + NULL, + mDsiPanelEventRegistration, + &BufferSize, + &Handle); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_WARN, "%a: Failed to locate gRockchipDsiPanelProtocolGuid. Status=%r\n", + __FUNCTION__, Status)); + } + break; + } + + Status = gBS->HandleProtocol (Handle, &gRockchipDsiPanelProtocolGuid, (VOID **)&DsiPanel); + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index < ARRAY_SIZE (mRk3588MipiDsi); Index++) { + dsi2 = &mRk3588MipiDsi[Index]; + if (dsi2->id == DsiPanel->DsiId) { + dsi2->Signature = DW_MIPI_DSI2_SIGNATURE; + dsi2->dcphy.phy = rockchip_phy_by_id(dsi2->id); + dsi2->RockchipDsiPanel = DsiPanel; + CopyMem (&dsi2->connector, &mDwMipiDsi2ConnectorOps, sizeof (ROCKCHIP_CONNECTOR_PROTOCOL)); + + dw_mipi_dsi2_child_post_bind(dsi2); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipConnectorProtocolGuid, + &dsi2->connector, + NULL + ); + break; + } + } + + ASSERT_EFI_ERROR (Status); + break; + } +} + +EFI_STATUS +EFIAPI +DwMipiDsi2Init ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EfiCreateProtocolNotifyEvent (&gRockchipDsiPanelProtocolGuid, + TPL_CALLBACK, + DsiPanelRegistrationEventHandler, + NULL, + &mDsiPanelEventRegistration); + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf new file mode 100644 index 0000000..b1e4487 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Synopsys DesignWare MIPI DSI2 controller driver +# +# Copyright (c) 2023-2024, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DwMipiDsi2Lib + FILE_GUID = aa11f6f3-96a8-45f9-b757-47e1c793d409 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DwMipiDsi2Init + +[Sources.common] + DwMipiDsi2Lib.c + drm_dsc.c + drm_mipi_dsi.c + rockchip_phy.c + samsung_mipi_dcphy.c + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + UefiBootServicesTableLib + TimerLib + DebugLib + IoLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + RockchipDisplayLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[BuildOptions] + +[Pcd] + +[Protocols] + gRockchipConnectorProtocolGuid ## PRODUCES + gRockchipDsiPanelProtocolGuid ## CONSUMES + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptx.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptx.c new file mode 100644 index 0000000..263b400 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptx.c @@ -0,0 +1,897 @@ +/** @file + + Rockchip HDMI/DP Combo PHY with Samsung IP block + Copyright (c) 2022, Linaro, Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RO_REF_CLK_SEL GENMASK(11, 10) +#define LC_REF_CLK_SEL GENMASK(9, 8) +#define PLL_EN BIT(7) +#define BIAS_EN BIT(6) +#define BGR_EN BIT(5) +#define HDPTX_MODE_SEL BIT(0) +#define PLL_LOCK_DONE BIT(3) +#define PHY_CLK_RDY BIT(2) +#define PHY_RDY BIT(1) +#define SB_RDY BIT(0) + +/* cmn_reg0008 */ +#define OVRD_LCPLL_EN BIT(7) +#define LCPLL_EN BIT(6) + +/* cmn_reg003C */ +#define ANA_LCPLL_RESERVED7 BIT(7) + +/* cmn_reg003D */ +#define OVRD_ROPLL_EN BIT(7) +#define ROPLL_EN BIT(6) + +/* cmn_reg0046 */ +#define ROPLL_ANA_CPP_CTRL_COARSE GENMASK(7, 4) +#define ROPLL_ANA_CPP_CTRL_FINE GENMASK(3, 0) + +/* cmn_reg0047 */ +#define ROPLL_ANA_LPF_C_SEL_COARSE GENMASK(5, 3) +#define ROPLL_ANA_LPF_C_SEL_FINE GENMASK(2, 0) + +/* cmn_reg004E */ +#define ANA_ROPLL_PI_EN BIT(5) + +/* cmn_reg0051 */ +#define ROPLL_PMS_MDIV GENMASK(7, 0) + +/* cmn_reg0055 */ +#define ROPLL_PMS_MDIV_AFC GENMASK(7, 0) + +/* cmn_reg0059 */ +#define ANA_ROPLL_PMS_PDIV GENMASK(7, 4) +#define ANA_ROPLL_PMS_REFDIV GENMASK(3, 0) + +/* cmn_reg005A */ +#define ROPLL_PMS_SDIV_RBR GENMASK(7, 4) +#define ROPLL_PMS_SDIV_HBR GENMASK(3, 0) + +/* cmn_reg005B */ +#define ROPLL_PMS_SDIV_HBR2 GENMASK(7, 4) +#define ROPLL_PMS_SDIV_HBR3 GENMASK(3, 0) + +/* cmn_reg005D */ +#define OVRD_ROPLL_REF_CLK_SEL BIT(5) +#define ROPLL_REF_CLK_SEL GENMASK(4, 3) + +/* cmn_reg005E */ +#define ANA_ROPLL_SDM_EN BIT(6) +#define OVRD_ROPLL_SDM_RSTN BIT(5) +#define ROPLL_SDM_RSTN BIT(4) +#define ROPLL_SDC_FRACTIONAL_EN_RBR BIT(3) +#define ROPLL_SDC_FRACTIONAL_EN_HBR BIT(2) +#define ROPLL_SDC_FRACTIONAL_EN_HBR2 BIT(1) +#define ROPLL_SDC_FRACTIONAL_EN_HBR3 BIT(0) + +/* cmn_reg005F */ +#define OVRD_ROPLL_SDC_RSTN BIT(5) +#define ROPLL_SDC_RSTN BIT(4) + +/* cmn_reg0060 */ +#define ROPLL_SDM_DENOMINATOR GENMASK(7, 0) + +/* cmn_reg0064 */ +#define ROPLL_SDM_NUMERATOR_SIGN_RBR BIT(3) +#define ROPLL_SDM_NUMERATOR_SIGN_HBR BIT(2) +#define ROPLL_SDM_NUMERATOR_SIGN_HBR2 BIT(1) +#define ROPLL_SDM_NUMERATOR_SIGN_HBR3 BIT(0) + +/* cmn_reg0065 */ +#define ROPLL_SDM_NUMERATOR GENMASK(7, 0) + +/* cmn_reg0069 */ +#define ROPLL_SDC_N_RBR GENMASK(2, 0) + +/* cmn_reg006A */ +#define ROPLL_SDC_N_HBR GENMASK(5, 3) +#define ROPLL_SDC_N_HBR2 GENMASK(2, 0) + +/* cmn_reg006B */ +#define ROPLL_SDC_N_HBR3 GENMASK(3, 1) + +/* cmn_reg006C */ +#define ROPLL_SDC_NUMERATOR GENMASK(5, 0) + +/* cmn_reg0070 */ +#define ROPLL_SDC_DENOMINATOR GENMASK(5, 0) + +/* cmn_reg0074 */ +#define OVRD_ROPLL_SDC_NDIV_RSTN BIT(3) +#define ROPLL_SDC_NDIV_RSTN BIT(2) +#define OVRD_ROPLL_SSC_EN BIT(1) +#define ROPLL_SSC_EN BIT(0) + +/* cmn_reg0075 */ +#define ANA_ROPLL_SSC_FM_DEVIATION GENMASK(5, 0) + +/* cmn_reg0076 */ +#define ANA_ROPLL_SSC_FM_FREQ GENMASK(6, 2) + +/* cmn_reg0077 */ +#define ANA_ROPLL_SSC_CLK_DIV_SEL GENMASK(6, 3) + +/* cmn_reg0081 */ +#define ANA_PLL_CD_TX_SER_RATE_SEL BIT(3) +#define ANA_PLL_CD_HSCLK_WEST_EN BIT(1) +#define ANA_PLL_CD_HSCLK_EAST_EN BIT(0) + +/* cmn_reg0082 */ +#define ANA_PLL_CD_VREG_GAIN_CTRL GENMASK(3, 0) + +/* cmn_reg0083 */ +#define ANA_PLL_CD_VREG_ICTRL GENMASK(6, 5) + +/* cmn_reg0084 */ +#define PLL_LCRO_CLK_SEL BIT(5) + +/* cmn_reg0085 */ +#define ANA_PLL_SYNC_LOSS_DET_MODE GENMASK(1, 0) + +/* cmn_reg0087 */ +#define ANA_PLL_TX_HS_CLK_EN BIT(2) + +/* cmn_reg0095 */ +#define DP_TX_LINK_BW GENMASK(1, 0) + +/* cmn_reg0097 */ +#define DIG_CLK_SEL BIT(1) + +/* cmn_reg0099 */ +#define SSC_EN GENMASK(7, 6) +#define CMN_ROPLL_ALONE_MODE BIT(2) + +/* cmn_reg009A */ +#define HS_SPEED_SEL BIT(0) + +/* cmn_reg009B */ +#define LS_SPEED_SEL BIT(4) + +/* sb_reg0102 */ +#define OVRD_SB_RXTERM_EN BIT(5) +#define SB_RXRERM_EN BIT(4) +#define ANA_SB_RXTERM_OFFSP GENMASK(3, 0) + +/* sb_reg0103 */ +#define ANA_SB_RXTERM_OFFSN GENMASK(6, 3) +#define OVRD_SB_RX_RESCAL_DONE BIT(1) +#define SB_RX_RESCAL_DONE BIT(0) + +/* sb_reg0104 */ +#define OVRD_SB_EN BIT(5) +#define SB_EN BIT(4) +#define OVRD_SB_AUX_EN BIT(1) +#define SB_AUX_EN BIT(0) + +/* sb_reg0105 */ +#define ANA_SB_TX_HLVL_PROG GENMASK(2, 0) + +/* sb_reg0106 */ +#define ANA_SB_TX_LLVL_PROG GENMASK(6, 4) + +/* sb_reg010D */ +#define ANA_SB_DMRX_LPBK_DATA BIT(4) + +/* sb_reg010F */ +#define OVRD_SB_VREG_EN BIT(7) +#define SB_VREG_EN BIT(6) +#define ANA_SB_VREG_GAIN_CTRL GENMASK(3, 0) + +/* sb_reg0110 */ +#define ANA_SB_VREG_OUT_SEL BIT(1) +#define ANA_SB_VREG_REF_SEL BIT(0) + +/* sb_reg0113 */ +#define SB_RX_RCAL_OPT_CODE GENMASK(5, 4) +#define SB_RX_RTERM_CTRL GENMASK(3, 0) + +/* sb_reg0114 */ +#define SB_TG_SB_EN_DELAY_TIME GENMASK(5, 3) +#define SB_TG_RXTERN_EN_DELAY_TIME GENMASK(2, 0) + +/* sb_reg0115 */ +#define SB_READY_DELAY_TIME GENMASK(5, 3) +#define SB_TG_OSC_EN_DELAY_TIME GENMASK(2, 0) + +/* sb_reg0116 */ +#define SB_TG_OSC_EN_TO_AFC_RSTN_DELAT_TIME GENMASK(6, 4) + +/* sb_reg0117 */ +#define SB_TG_PLL_CD_VREG_FAST_PULSE_TIME GENMASK(3, 0) + +/* sb_reg0118 */ +#define SB_TG_EARC_DMRX_RECVRD_CLK_CNT GENMASK(7, 0) + +/* sb_reg011A */ +#define SB_TG_CNT_RUN_NO_7_0 GENMASK(7, 0) + +/* sb_reg011B */ +#define SB_EARC_SIG_DET_BYPASS BIT(4) +#define SB_AFC_TOL GENMASK(3, 0) + +/* sb_reg011C */ +#define SB_AFC_STB_NUM GENMASK(3, 0) + +/* sb_reg011D */ +#define SB_TG_OSC_CNT_MIN GENMASK(7, 0) + +/* sb_reg011E */ +#define SB_TG_OSC_CNT_MAX GENMASK(7, 0) + +/* sb_reg011F */ +#define SB_PWM_AFC_CTRL GENMASK(7, 2) +#define SB_RCAL_RSTN BIT(1) + +/* sb_reg0120 */ +#define SB_AUX_EN_IN BIT(7) + +/* sb_reg0123 */ +#define OVRD_SB_READY BIT(5) +#define SB_READY BIT(4) + +/* lntop_reg0200 */ +#define PROTOCOL_SEL BIT(2) + +/* lntop_reg0206 */ +#define DATA_BUS_WIDTH GENMASK(2, 1) +#define BUS_WIDTH_SEL BIT(0) + +/* lntop_reg0207 */ +#define LANE_EN GENMASK(3, 0) + +/* LANE_reg0301 */ +#define OVRD_LN_TX_DRV_EI_EN BIT(7) +#define LN_TX_DRV_EI_EN BIT(6) + +/* LANE_reg0303 */ +#define OVRD_LN_TX_DRV_LVL_CTRL BIT(5) +#define LN_TX_DRV_LVL_CTRL GENMASK(4, 0) + +/* LANE_reg0304 */ +#define OVRD_LN_TX_DRV_POST_LVL_CTRL BIT(4) +#define LN_TX_DRV_POST_LVL_CTRL GENMASK(3, 0) +#define LN_TX_DRV_POST_LVL_CTRL GENMASK(3, 0) + +/* LANE_reg0305 */ +#define OVRD_LN_TX_DRV_PRE_LVL_CTRL BIT(6) +#define LN_TX_DRV_PRE_LVL_CTRL GENMASK(5, 2) + +/* LANE_reg0306 */ +#define LN_ANA_TX_DRV_IDRV_IDN_CTRL GENMASK(7, 5) +#define LN_ANA_TX_DRV_IDRV_IUP_CTRL GENMASK(4, 2) +#define LN_ANA_TX_DRV_ACCDRV_EN BIT(0) + +/* LANE_reg0307 */ +#define LN_ANA_TX_DRV_ACCDRV_POL_SEL BIT(6) +#define LN_ANA_TX_DRV_ACCDRV_CTRL GENMASK(5, 3) + +/* LANE_reg030A */ +#define LN_ANA_TX_JEQ_EN BIT(4) +#define LN_TX_JEQ_EVEN_CTRL_RBR GENMASK(3, 0) + +/* LANE_reg030B */ +#define LN_TX_JEQ_EVEN_CTRL_HBR GENMASK(7, 4) +#define LN_TX_JEQ_EVEN_CTRL_HBR2 GENMASK(3, 0) + +/* LANE_reg030C */ +#define LN_TX_JEQ_EVEN_CTRL_HBR3 GENMASK(7, 4) +#define LN_TX_JEQ_ODD_CTRL_RBR GENMASK(3, 0) + +/* LANE_reg030D */ +#define LN_TX_JEQ_ODD_CTRL_HBR GENMASK(7, 4) +#define LN_TX_JEQ_ODD_CTRL_HBR2 GENMASK(3, 0) + +/* LANE_reg030E */ +#define LN_TX_JEQ_ODD_CTRL_HBR3 GENMASK(7, 4) + +/* LANE_reg0310 */ +#define LN_ANA_TX_SYNC_LOSS_DET_MODE GENMASK(1, 0) + +/* LANE_reg0311 */ +#define LN_TX_SER_40BIT_EN_RBR BIT(3) +#define LN_TX_SER_40BIT_EN_HBR BIT(2) +#define LN_TX_SER_40BIT_EN_HBR2 BIT(1) +#define LN_TX_SER_40BIT_EN_HBR3 BIT(0) + +/* LANE_reg0316 */ +#define LN_ANA_TX_SER_VREG_GAIN_CTRL GENMASK(3, 0) + +/* LANE_reg031B */ +#define LN_ANA_TX_RESERVED GENMASK(7, 0) + +/* LANE_reg031E */ +#define LN_POLARITY_INV BIT(2) + +#define LANE_REG(LANE, offset) (0x400 * (LANE) + (offset)) + +enum { + DP_BW_RBR, + DP_BW_HBR, + DP_BW_HBR2, + DP_BW_HBR3, +}; + +struct TxDrvCtrl { + UINT8 Tx_Drv_Lvl_Ctrl; + UINT8 Tx_Drv_Post_Lvl_Ctrl; + UINT8 Ana_Tx_Drv_Idrv_Idn_Ctrl; + UINT8 Ana_Tx_Drv_Idrv_Iup_Ctrl; + UINT8 Ana_Tx_Drv_Accdrv_En; + UINT8 Ana_Tx_Drv_Accdrv_Ctrl; +}; + +STATIC CONST struct TxDrvCtrl TX_DRV_CTRL_RBR[4][4] = { + /* VOLTAGE swing 0, pre-emphasis 0->3 */ + { + { 0x1, 0x0, 0x4, 0x6, 0x0, 0x4 }, + { 0x4, 0x3, 0x4, 0x6, 0x0, 0x4 }, + { 0x7, 0x6, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0xb, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 1, pre-emphasis 0->2 */ + { + { 0x4, 0x0, 0x4, 0x6, 0x0, 0x4 }, + { 0xa, 0x5, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x8, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 2, pre-emphasis 0->1 */ + { + { 0x8, 0x0, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x5, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 3, pre-emphasis 0 */ + { + { 0xd, 0x0, 0x7, 0x7, 0x1, 0x4 }, + } +}; + +STATIC CONST struct TxDrvCtrl TX_DRV_CTRL_HBR[4][4] = { + /* VOLTAGE swing 0, pre-emphasis 0->3 */ + { + { 0x2, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4 }, + { 0x9, 0x8, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0xb, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 1, pre-emphasis 0->2 */ + { + { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0xb, 0x6, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x8, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 2, pre-emphasis 0->1 */ + { + { 0x9, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x6, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 3, pre-emphasis 0 */ + { + { 0xd, 0x1, 0x7, 0x7, 0x1, 0x4 }, + } +}; + +STATIC CONST struct TxDrvCtrl TX_DRV_CTRL_HBR2[4][4] = { + /* VOLTAGE swing 0, pre-emphasis 0->3 */ + { + { 0x2, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4 }, + { 0x9, 0x8, 0x4, 0x6, 0x1, 0x4 }, + { 0xd, 0xb, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 1, pre-emphasis 0->2 */ + { + { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0xc, 0x7, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x8, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 2, pre-emphasis 0->1 */ + { + { 0x9, 0x1, 0x4, 0x6, 0x0, 0x4 }, + { 0xd, 0x6, 0x7, 0x7, 0x1, 0x7 }, + }, + + /* VOLTAGE swing 3, pre-emphasis 0 */ + { + { 0xd, 0x0, 0x7, 0x7, 0x1, 0x4 }, + } +}; + +INLINE +VOID +PhyWrite ( + OUT struct RockchipHdptxPhy *Hdptx, + UINTN Reg, + UINTN Val + ) +{ + UINT32 Shift; + + if (!Hdptx->Id) + Shift = EDP0TX_PHY_BASE; + else + Shift = EDP1TX_PHY_BASE; + + MmioWrite32(Shift + Reg, Val ); +} + +INLINE +UINTN +PhyRead ( + OUT struct RockchipHdptxPhy *Hdptx, + UINTN Reg + ) +{ + UINT32 Shift; + + if(!Hdptx->Id) + Shift = EDP0TX_PHY_BASE; + else + Shift = EDP1TX_PHY_BASE; + + return MmioRead32(Shift + Reg); +} + +STATIC +VOID +PhyUpdateBits ( + OUT struct RockchipHdptxPhy *Hdptx, + UINTN Reg, + UINTN Mask, + UINTN Val + ) +{ + UINTN Orig, Tmp; + + Orig = PhyRead(Hdptx, Reg); + Tmp = Orig & ~Mask; + Tmp |= Val & Mask; + PhyWrite(Hdptx, Reg, Tmp); +}; + +STATIC +VOID +GrfWrite ( + OUT struct RockchipHdptxPhy *Hdptx, + UINTN Reg, + UINTN Mask, + UINTN Val + ) +{ + UINT32 TempVal = 0; + UINT32 Shift; + + if (!Hdptx->Id) + Shift = HDPTXPHY0_GRF_BASE; + else + Shift = HDPTXPHY1_GRF_BASE; + + TempVal = (Mask << 16) | (Val & Mask); + MmioWrite32(Shift + Reg, TempVal); +}; + +STATIC +VOID +RockchipHdptxPhyDpPllInit ( + struct RockchipHdptxPhy *Hdptx + ) +{ + PhyUpdateBits(Hdptx, 0x20, OVRD_LCPLL_EN | + LCPLL_EN, + 0x80); + PhyWrite(Hdptx, 0xf4, 0xC0); + PhyUpdateBits(Hdptx, 0x0138, ANA_ROPLL_PI_EN, + 0x20); + PhyWrite(Hdptx, 0x0144, 0x87); + PhyWrite(Hdptx, 0x0148, 0x71); + PhyWrite(Hdptx, 0x014c, 0x71); + PhyWrite(Hdptx, 0x0154, 0x87); + PhyWrite(Hdptx, 0x0158, 0x71); + PhyWrite(Hdptx, 0x015c, 0x71); + PhyWrite(Hdptx, 0x0164, 0x11); + PhyWrite(Hdptx, 0x0168, 0x31); + PhyUpdateBits(Hdptx, 0x016c, ROPLL_PMS_SDIV_HBR2, 0x0); + PhyWrite(Hdptx, 0x0178, 0x7f); + PhyWrite(Hdptx, 0x017c, 0x31); + PhyWrite(Hdptx, 0x0180, 0x21); + PhyWrite(Hdptx, 0x0184, 0x27); + PhyWrite(Hdptx, 0x0188, 0x27); + PhyWrite(Hdptx, 0x0190, 0x7); + PhyWrite(Hdptx, 0x0194, 0x0); + PhyWrite(Hdptx, 0x0198, 0xd); + PhyWrite(Hdptx, 0x019c, 0xd); + PhyWrite(Hdptx, 0x01a4, 0x2); + PhyWrite(Hdptx, 0x01a8, 0x09); + PhyWrite(Hdptx, 0x01b0, 0x3); + PhyWrite(Hdptx, 0x01b4, 0x7); + PhyWrite(Hdptx, 0x01b8, 0x7); + PhyWrite(Hdptx, 0x01c0, 0x8); + PhyWrite(Hdptx, 0x01c4, 0x18); + PhyWrite(Hdptx, 0x01c8, 0x18); + PhyWrite(Hdptx, 0x01d0, 0x0f); + PhyWrite(Hdptx, 0x01dc, 0x08); + PhyWrite(Hdptx, 0x0118, 0xee); + PhyWrite(Hdptx, 0x011c, 0x24); + PhyWrite(Hdptx, 0x0204, 0x01); + PhyUpdateBits(Hdptx, 0x025c, DIG_CLK_SEL, 0x2); + PhyUpdateBits(Hdptx, 0x021c, ANA_PLL_TX_HS_CLK_EN, 0x4); + PhyUpdateBits(Hdptx, 0x0204, ANA_PLL_CD_HSCLK_EAST_EN | + ANA_PLL_CD_HSCLK_WEST_EN, + 0x1); + PhyWrite(Hdptx, 0x0264, 0x84); + PhyWrite(Hdptx, 0x0208, 0x04); + PhyUpdateBits(Hdptx, 0x00f0, ANA_LCPLL_RESERVED7, + 0x80); + PhyWrite(Hdptx, 0x020c, 0x24); + PhyWrite(Hdptx, 0x0214, 0x03); + PhyUpdateBits(Hdptx, 0x0210, PLL_LCRO_CLK_SEL, + 0x20); + PhyUpdateBits(Hdptx, 0x0268, HS_SPEED_SEL, + 0x1); + PhyUpdateBits(Hdptx, 0x026c, LS_SPEED_SEL, + 0x10); +} + +STATIC +INTN +RockchipHdptxPhyDpAuxInit ( + struct RockchipHdptxPhy *Hdptx + ) +{ + PhyUpdateBits(Hdptx, 0x0414, ANA_SB_TX_HLVL_PROG, 0x7); + PhyUpdateBits(Hdptx, 0x0418, ANA_SB_TX_LLVL_PROG, 0x70); + PhyWrite(Hdptx, 0x044c, 0x13); + PhyWrite(Hdptx, 0x0450, 0x12); + PhyWrite(Hdptx, 0x0454, 0x12); + PhyWrite(Hdptx, 0x0458, 0x20); + PhyWrite(Hdptx, 0x045c, 0x04); + PhyWrite(Hdptx, 0x0460, 0x0a); + PhyWrite(Hdptx, 0x0468, 0x03); + PhyWrite(Hdptx, 0x046c, 0x13); + PhyWrite(Hdptx, 0x0470, 0x04); + PhyUpdateBits(Hdptx, 0x0474, SB_TG_OSC_CNT_MIN, 0x67); + PhyUpdateBits(Hdptx, 0x0478, SB_TG_OSC_CNT_MAX, 0x6a); + PhyWrite(Hdptx, 0x047c, 0x16); + PhyUpdateBits(Hdptx, 0x0434, ANA_SB_DMRX_LPBK_DATA, 0x10); + PhyWrite(Hdptx, 0x0440, 0x03); + PhyUpdateBits(Hdptx, 0x043c, ANA_SB_VREG_GAIN_CTRL, 0x0); + PhyUpdateBits(Hdptx, 0x0408, ANA_SB_RXTERM_OFFSP, 0x3); + PhyWrite(Hdptx, 0x040c, 0x1b); + PhyUpdateBits(Hdptx, 0x047c, SB_RCAL_RSTN, 0x2); + PhyUpdateBits(Hdptx, 0x0410, SB_AUX_EN, 0x0); + PhyUpdateBits(Hdptx, 0x0480, SB_AUX_EN_IN, 0x80); + PhyUpdateBits(Hdptx, 0x0410, OVRD_SB_EN, 0x20); + PhyUpdateBits(Hdptx, 0x0408, OVRD_SB_RXTERM_EN, 0x20); + PhyUpdateBits(Hdptx, 0x0410, OVRD_SB_AUX_EN, 0x2); + + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BGR_EN, 0x21); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BIAS_EN, 0x61); + MicroSecondDelay(10); + + PhyUpdateBits(Hdptx, 0x0410, SB_EN, 0x10); + PhyUpdateBits(Hdptx, 0x0408, SB_RXRERM_EN, 0x10); + PhyWrite(Hdptx, 0x043c, 0xc0); + PhyUpdateBits(Hdptx, 0x0410, SB_AUX_EN, 0x1); + NanoSecondDelay (100000); + GrfWrite(Hdptx, HDPTXPHY_GRF_STATUS0, SB_RDY, 0x1); + MicroSecondDelay(10); + return 0; +} + +STATIC +VOID +RockchipHdptxPhyReset ( + struct RockchipHdptxPhy *Hdptx + ) +{ + UINT32 LANE; + + for (LANE = 0; LANE < 4; LANE++) + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c04), + OVRD_LN_TX_DRV_EI_EN | LN_TX_DRV_EI_EN, + 0x80); + + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, PLL_EN, 0x0); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BIAS_EN, 0x0); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BGR_EN, 0x0); +}; + +VOID +RockchipHdptxPhyInit ( + OUT struct RockchipHdptxPhy *Hdptx + ) +{ + RockchipHdptxPhyReset(Hdptx); + + MmioWrite32(0xFD7F0A0C, 0xFFFF8000); + + /* Todo lane-polarity-invert */ + PhyWrite(Hdptx, 0x0C78, 0x00); + PhyWrite(Hdptx, 0x1078, 0x00); + PhyWrite(Hdptx, 0x1478, 0x00); + PhyWrite(Hdptx, 0x1878, 0x00); + + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, HDPTX_MODE_SEL, 0x01); + + /* Todo RockchipHdptxPhyPowerOn */ + PhyWrite(Hdptx, 0x0800, 0x00); + PhyWrite(Hdptx, 0x0818, 0x02); + + RockchipHdptxPhyDpPllInit(Hdptx); + RockchipHdptxPhyDpAuxInit(Hdptx); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BGR_EN, 0x21); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, BIAS_EN, 0x61); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, PLL_EN, 0xe1); + MmioWrite32(0xFD7F0A0C, 0xFFFF8000); + MmioWrite32(0xFD7F0A0C, 0xFFFF0000); + MmioWrite32(0xFD7F0A10, 0xFFFF0000); +}; + +INTN +RockchipHdptxPhySetRate ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ) +{ + UINT32 BW; + + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, PLL_EN, 0x0); + PhyUpdateBits(Hdptx, 0x081c, LANE_EN, 0x0); + DEBUG ((DEBUG_INFO, "[DRIVER]enter %a rate %d Dp->SSC %d \n", + __func__, Dp->LINKRATE, Dp->SSC)); + + switch (Dp->LINKRATE) { + case 1620: + BW = DP_BW_RBR; + break; + case 2700: + BW = DP_BW_HBR; + break; + case 5400: + BW = DP_BW_HBR2; + break; + default: + return -EINVAL; + } + + PhyUpdateBits(Hdptx, 0x0254, DP_TX_LINK_BW, BW); + + if (Dp->SSC) { + PhyUpdateBits(Hdptx, 0x01d0, OVRD_ROPLL_SSC_EN | ROPLL_SSC_EN, + 0x3); + PhyUpdateBits(Hdptx, 0x01d4, ANA_ROPLL_SSC_FM_DEVIATION, + 0xc); + PhyUpdateBits(Hdptx, 0x01d8, ANA_ROPLL_SSC_FM_FREQ, + 0x7c); + PhyUpdateBits(Hdptx, 0x0264, SSC_EN, + 0x80); + } else { + PhyUpdateBits(Hdptx, 0x01d0, OVRD_ROPLL_SSC_EN | ROPLL_SSC_EN, + 0x3); + PhyUpdateBits(Hdptx, 0x01d4, ANA_ROPLL_SSC_FM_DEVIATION, + 0xe); + PhyUpdateBits(Hdptx, 0x01d8, ANA_ROPLL_SSC_FM_FREQ, + 0xd); + PhyUpdateBits(Hdptx, 0x0264, SSC_EN, + 0x20); + PhyUpdateBits(Hdptx, 0x01d8, ANA_ROPLL_SSC_FM_FREQ, + 0x30); + } + PhyWrite(Hdptx, 0x081C, 0x03); + PhyWrite(Hdptx, 0x0C0C, 0x26); + PhyWrite(Hdptx, 0x0C10, 0x11); + PhyWrite(Hdptx, 0x100C, 0x26); + PhyWrite(Hdptx, 0x101C, 0x60); + PhyWrite(Hdptx, 0x140C, 0x00); + PhyWrite(Hdptx, 0x1410, 0x00); + PhyWrite(Hdptx, 0x141C, 0x00); + PhyWrite(Hdptx, 0x1428, 0x00); + PhyWrite(Hdptx, 0x142C, 0x00); + PhyWrite(Hdptx, 0x1434, 0x00); + PhyWrite(Hdptx, 0x1444, 0x00); + PhyWrite(Hdptx, 0x1458, 0x00); + PhyWrite(Hdptx, 0x146C, 0x00); + PhyWrite(Hdptx, 0x180C, 0x00); + PhyWrite(Hdptx, 0x1810, 0x00); + PhyWrite(Hdptx, 0x181C, 0x00); + PhyWrite(Hdptx, 0x1828, 0x00); + PhyWrite(Hdptx, 0x182C, 0x00); + PhyWrite(Hdptx, 0x1834, 0x00); + PhyWrite(Hdptx, 0x1844, 0x00); + PhyWrite(Hdptx, 0x1858, 0x00); + PhyWrite(Hdptx, 0x186C, 0x00); + GrfWrite(Hdptx, HDPTXPHY_GRF_CON0, PLL_EN, 0x80); + GrfWrite(Hdptx, HDPTXPHY_GRF_STATUS0, PLL_LOCK_DONE, 0x8); + PhyUpdateBits(Hdptx, 0x081c, LANE_EN, + GENMASK(Dp->LANES - 1, 0)); + NanoSecondDelay (100000); + GrfWrite(Hdptx, HDPTXPHY_GRF_STATUS0, PHY_RDY, 0x2); + NanoSecondDelay (10000); + return 0; +} + +VOID +RockchipHdptxPhySetVoltage ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp, + UINT8 LANE + ) +{ + CONST struct TxDrvCtrl *ctrl; + DEBUG ((DEBUG_INFO, "[DRIVER]enter %a Dp->LINKRATE %d \n", + __func__, Dp->LINKRATE)); + + switch (Dp->LINKRATE) { + case 1620: + ctrl = &TX_DRV_CTRL_RBR[Dp->VOLTAGE[LANE]][Dp->PRE[LANE]]; + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c44), + LN_TX_SER_40BIT_EN_RBR, + 0x8); + break; + case 2700: + ctrl = &TX_DRV_CTRL_HBR[Dp->VOLTAGE[LANE]][Dp->PRE[LANE]]; + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c2c), + LN_TX_JEQ_EVEN_CTRL_HBR, + 0x70); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c34), + LN_TX_JEQ_ODD_CTRL_HBR, + 0x70); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c44), + LN_TX_SER_40BIT_EN_HBR, + 0x4); + break; + case 5400: + default: + ctrl = &TX_DRV_CTRL_HBR2[Dp->VOLTAGE[LANE]][Dp->PRE[LANE]]; + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c2c), + LN_TX_JEQ_EVEN_CTRL_HBR2, + 0x7); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c34), + LN_TX_JEQ_ODD_CTRL_HBR2, + 0x7); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c44), + LN_TX_SER_40BIT_EN_HBR2, + 0x2); + break; + } + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c0c), + OVRD_LN_TX_DRV_LVL_CTRL | LN_TX_DRV_LVL_CTRL, + 0x2d); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c10), + OVRD_LN_TX_DRV_POST_LVL_CTRL | LN_TX_DRV_POST_LVL_CTRL, + 0x10 | ctrl->Tx_Drv_Post_Lvl_Ctrl + ); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c18), + LN_ANA_TX_DRV_IDRV_IDN_CTRL | + LN_ANA_TX_DRV_IDRV_IUP_CTRL | + LN_ANA_TX_DRV_ACCDRV_EN, + 0x00); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c1c), + LN_ANA_TX_DRV_ACCDRV_POL_SEL | LN_ANA_TX_DRV_ACCDRV_CTRL, + 0x40 | ctrl->Ana_Tx_Drv_Accdrv_Ctrl); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c6c), + LN_ANA_TX_RESERVED, + 0x1); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c58), + LN_ANA_TX_SER_VREG_GAIN_CTRL, + 0x2); + PhyUpdateBits(Hdptx, LANE_REG(LANE, 0x0c40), + LN_ANA_TX_SYNC_LOSS_DET_MODE, + 0x3); +} + +INTN +RockchipHdptxPhySetVoltages ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ) +{ + UINT8 LANE; + + for (LANE = 0; LANE < Dp->LANES; LANE++) + RockchipHdptxPhySetVoltage(Hdptx, Dp, LANE); + + return 0; +} + +STATIC +INTN +RockchipHdptxPhyVerifyConfig ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ) +{ + INTN i; + + if (Dp->SETRATE) { + switch (Dp->LINKRATE) { + case 1620: + case 2700: + case 5400: + break; + default: + return -EINVAL; + } + } + + switch (Dp->LANES) { + case 1: + case 2: + case 4: + break; + default: + return -EINVAL; + } + + if (Dp->SETVOLTAGES) { + for (i = 0; i < Dp->LANES; i++) { + if (Dp->VOLTAGE[i] > 3 || Dp->PRE[i] > 3) + return -EINVAL; + + if (Dp->VOLTAGE[i] + Dp->PRE[i] > 3) + return -EINVAL; + } + } + + return 0; +} + +INTN +RockchipHdptxPhyConfigure ( + OUT struct RockchipHdptxPhy *Hdptx, + OUT struct PhyConfigureOptsDp *Dp + ) +{ + INTN Ret; + + Ret = RockchipHdptxPhyVerifyConfig(Hdptx, Dp); + if (Ret) { + DEBUG ((DEBUG_WARN, "Invalid params for phy configure\n")); + return Ret; + } + + if (Dp->SETRATE) { + Ret = RockchipHdptxPhySetRate(Hdptx, Dp); + if (Ret) { + DEBUG ((DEBUG_WARN, "Failed to set rate: %d\n",Ret)); + return Ret; + } + } + + if (Dp->SETVOLTAGES) { + Ret = RockchipHdptxPhySetVoltages(Hdptx, Dp); + if (Ret) { + DEBUG ((DEBUG_WARN, "Failed to set Voltages: %d\n",Ret)); + return Ret; + } + } + + return 0; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptxHdmi.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptxHdmi.c new file mode 100644 index 0000000..9970e46 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/PhyRockchipSamsungHdptxHdmi.c @@ -0,0 +1,1190 @@ +/** @file + + Rockchip HDMI/DP Combo PHY with Samsung IP block + Copyright (c) 2022, Linaro, Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) + +#define GRF_HDPTX_CON0 0x00 +#define LC_REF_CLK_SEL BIT(11) +#define HDPTX_I_PLL_EN BIT(7) +#define HDPTX_I_BIAS_EN BIT(6) +#define HDPTX_I_BGR_EN BIT(5) +#define GRF_HDPTX_STATUS 0x80 +#define HDPTX_O_PLL_LOCK_DONE BIT(3) +#define HDPTX_O_PHY_CLK_RDY BIT(2) +#define HDPTX_O_PHY_RDY BIT(1) +#define HDPTX_O_SB_RDY BIT(0) + +#define CMN_REG0000 0x0000 +#define CMN_REG0001 0x0004 +#define CMN_REG0002 0x0008 +#define CMN_REG0003 0x000C +#define CMN_REG0004 0x0010 +#define CMN_REG0005 0x0014 +#define CMN_REG0006 0x0018 +#define CMN_REG0007 0x001C +#define CMN_REG0008 0x0020 +#define LCPLL_EN_MASK BIT(6) +#define LCPLL_EN(x) UPDATE(x, 4, 4) +#define LCPLL_LCVCO_MODE_EN_MASK BIT(4) +#define LCPLL_LCVCO_MODE_EN(x) UPDATE(x, 4, 4) +#define CMN_REG0009 0x0024 +#define CMN_REG000A 0x0028 +#define CMN_REG000B 0x002C +#define CMN_REG000C 0x0030 +#define CMN_REG000D 0x0034 +#define CMN_REG000E 0x0038 +#define CMN_REG000F 0x003C +#define CMN_REG0010 0x0040 +#define CMN_REG0011 0x0044 +#define CMN_REG0012 0x0048 +#define CMN_REG0013 0x004C +#define CMN_REG0014 0x0050 +#define CMN_REG0015 0x0054 +#define CMN_REG0016 0x0058 +#define CMN_REG0017 0x005C +#define CMN_REG0018 0x0060 +#define CMN_REG0019 0x0064 +#define CMN_REG001A 0x0068 +#define CMN_REG001B 0x006C +#define CMN_REG001C 0x0070 +#define CMN_REG001D 0x0074 +#define CMN_REG001E 0x0078 +#define LCPLL_PI_EN_MASK BIT(5) +#define LCPLL_PI_EN(x) UPDATE(x, 5, 5) +#define LCPLL_100M_CLK_EN_MASK BIT(0) +#define LCPLL_100M_CLK_EN(x) UPDATE(x, 0, 0) +#define CMN_REG001F 0x007C +#define CMN_REG0020 0x0080 +#define CMN_REG0021 0x0084 +#define CMN_REG0022 0x0088 +#define CMN_REG0023 0x008C +#define CMN_REG0024 0x0090 +#define CMN_REG0025 0x0094 +#define LCPLL_PMS_IQDIV_RSTN BIT(4) +#define CMN_REG0026 0x0098 +#define CMN_REG0027 0x009C +#define CMN_REG0028 0x00A0 +#define LCPLL_SDC_FRAC_EN BIT(2) +#define LCPLL_SDC_FRAC_RSTN BIT(0) +#define CMN_REG0029 0x00A4 +#define CMN_REG002A 0x00A8 +#define CMN_REG002B 0x00AC +#define CMN_REG002C 0x00B0 +#define CMN_REG002D 0x00B4 +#define LCPLL_SDC_N_MASK GENMASK(3, 1) +#define LCPLL_SDC_N(x) UPDATE(x, 3, 1) +#define CMN_REG002E 0x00B8 +#define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0) +#define LCPLL_SDC_NUMBERATOR(x) UPDATE(x, 5, 0) +#define CMN_REG002F 0x00BC +#define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2) +#define LCPLL_SDC_DENOMINATOR(x) UPDATE(x, 7, 2) +#define LCPLL_SDC_NDIV_RSTN BIT(0) +#define CMN_REG0030 0x00C0 +#define CMN_REG0031 0x00C4 +#define CMN_REG0032 0x00C8 +#define CMN_REG0033 0x00CC +#define CMN_REG0034 0x00D0 +#define CMN_REG0035 0x00D4 +#define CMN_REG0036 0x00D8 +#define CMN_REG0037 0x00DC +#define CMN_REG0038 0x00E0 +#define CMN_REG0039 0x00E4 +#define CMN_REG003A 0x00E8 +#define CMN_REG003B 0x00EC +#define CMN_REG003C 0x00F0 +#define CMN_REG003D 0x00F4 +#define ROPLL_LCVCO_EN BIT(4) +#define CMN_REG003E 0x00F8 +#define CMN_REG003F 0x00FC +#define CMN_REG0040 0x0100 +#define CMN_REG0041 0x0104 +#define CMN_REG0042 0x0108 +#define CMN_REG0043 0x010C +#define CMN_REG0044 0x0110 +#define CMN_REG0045 0x0114 +#define CMN_REG0046 0x0118 +#define CMN_REG0047 0x011C +#define CMN_REG0048 0x0120 +#define CMN_REG0049 0x0124 +#define CMN_REG004A 0x0128 +#define CMN_REG004B 0x012C +#define CMN_REG004C 0x0130 +#define CMN_REG004D 0x0134 +#define CMN_REG004E 0x0138 +#define ROPLL_PI_EN BIT(5) +#define CMN_REG004F 0x013C +#define CMN_REG0050 0x0140 +#define CMN_REG0051 0x0144 +#define CMN_REG0052 0x0148 +#define CMN_REG0053 0x014C +#define CMN_REG0054 0x0150 +#define CMN_REG0055 0x0154 +#define CMN_REG0056 0x0158 +#define CMN_REG0057 0x015C +#define CMN_REG0058 0x0160 +#define CMN_REG0059 0x0164 +#define CMN_REG005A 0x0168 +#define CMN_REG005B 0x016C +#define CMN_REG005C 0x0170 +#define ROPLL_PMS_IQDIV_RSTN BIT(5) +#define CMN_REG005D 0x0174 +#define CMN_REG005E 0x0178 +#define ROPLL_SDM_EN_MASK BIT(6) +#define ROPLL_SDM_EN(x) UPDATE(x, 6, 6) +#define ROPLL_SDM_FRAC_EN_RBR BIT(3) +#define ROPLL_SDM_FRAC_EN_HBR BIT(2) +#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1) +#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0) +#define CMN_REG005F 0x017C +#define CMN_REG0060 0x0180 +#define CMN_REG0061 0x0184 +#define CMN_REG0062 0x0188 +#define CMN_REG0063 0x018C +#define CMN_REG0064 0x0190 +#define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3) +#define ROPLL_SDM_NUM_SIGN_RBR(x) UPDATE(x, 3, 3) +#define CMN_REG0065 0x0194 +#define CMN_REG0066 0x0198 +#define CMN_REG0067 0x019C +#define CMN_REG0068 0x01A0 +#define CMN_REG0069 0x01A4 +#define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0) +#define ROPLL_SDC_N_RBR(x) UPDATE(x, 2, 0) +#define CMN_REG006A 0x01A8 +#define CMN_REG006B 0x01AC +#define CMN_REG006C 0x01B0 +#define CMN_REG006D 0x01B4 +#define CMN_REG006E 0x01B8 +#define CMN_REG006F 0x01BC +#define CMN_REG0070 0x01C0 +#define CMN_REG0071 0x01C4 +#define CMN_REG0072 0x01C8 +#define CMN_REG0073 0x01CC +#define CMN_REG0074 0x01D0 +#define ROPLL_SDC_NDIV_RSTN BIT(2) +#define ROPLL_SSC_EN BIT(0) +#define CMN_REG0075 0x01D4 +#define CMN_REG0076 0x01D8 +#define CMN_REG0077 0x01DC +#define CMN_REG0078 0x01E0 +#define CMN_REG0079 0x01E4 +#define CMN_REG007A 0x01E8 +#define CMN_REG007B 0x01EC +#define CMN_REG007C 0x01F0 +#define CMN_REG007D 0x01F4 +#define CMN_REG007E 0x01F8 +#define CMN_REG007F 0x01FC +#define CMN_REG0080 0x0200 +#define CMN_REG0081 0x0204 +#define OVRD_PLL_CD_CLK_EN BIT(8) +#define PLL_CD_HSCLK_EAST_EN BIT(0) +#define CMN_REG0082 0x0208 +#define CMN_REG0083 0x020C +#define CMN_REG0084 0x0210 +#define CMN_REG0085 0x0214 +#define CMN_REG0086 0x0218 +#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) +#define PLL_PCG_POSTDIV_SEL(x) UPDATE(x, 7, 4) +#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) +#define PLL_PCG_CLK_SEL(x) UPDATE(x, 3, 1) +#define PLL_PCG_CLK_EN BIT(0) +#define CMN_REG0087 0x021C +#define PLL_FRL_MODE_EN BIT(3) +#define PLL_TX_HS_CLK_EN BIT(2) +#define CMN_REG0088 0x0220 +#define CMN_REG0089 0x0224 +#define LCPLL_ALONE_MODE BIT(1) +#define CMN_REG008A 0x0228 +#define CMN_REG008B 0x022C +#define CMN_REG008C 0x0230 +#define CMN_REG008D 0x0234 +#define CMN_REG008E 0x0238 +#define CMN_REG008F 0x023C +#define CMN_REG0090 0x0240 +#define CMN_REG0091 0x0244 +#define CMN_REG0092 0x0248 +#define CMN_REG0093 0x024C +#define CMN_REG0094 0x0250 +#define CMN_REG0095 0x0254 +#define CMN_REG0096 0x0258 +#define CMN_REG0097 0x025C +#define DIG_CLK_SEL BIT(1) +#define ROPLL_REF BIT(1) +#define LCPLL_REF 0 +#define CMN_REG0098 0x0260 +#define CMN_REG0099 0x0264 +#define CMN_ROPLL_ALONE_MODE BIT(2) +#define ROPLL_ALONE_MODE BIT(2) +#define CMN_REG009A 0x0268 +#define HS_SPEED_SEL BIT(0) +#define DIV_10_CLOCK BIT(0) +#define CMN_REG009B 0x026C +#define IS_SPEED_SEL BIT(4) +#define LINK_SYMBOL_CLOCK BIT(4) +#define LINK_SYMBOL_CLOCK1_2 0 +#define CMN_REG009C 0x0270 +#define CMN_REG009D 0x0274 +#define CMN_REG009E 0x0278 +#define CMN_REG009F 0x027C +#define CMN_REG00A0 0x0280 +#define CMN_REG00A1 0x0284 +#define CMN_REG00A2 0x0288 +#define CMN_REG00A3 0x028C +#define CMN_REG00AD 0x0290 +#define CMN_REG00A5 0x0294 +#define CMN_REG00A6 0x0298 +#define CMN_REG00A7 0x029C +#define SB_REG0100 0x0400 +#define SB_REG0101 0x0404 +#define SB_REG0102 0x0408 +#define OVRD_SB_RXTERM_EN_MASK BIT(5) +#define OVRD_SB_RXTERM_EN(x) UPDATE(x, 5, 5) +#define SB_RXTERM_EN_MASK BIT(4) +#define SB_RXTERM_EN(x) UPDATE(x, 4, 4) +#define ANA_SB_RXTERM_OFFSP_MASK GENMASK(3, 0) +#define ANA_SB_RXTERM_OFFSP(x) UPDATE(x, 3, 0) +#define SB_REG0103 0x040C +#define ANA_SB_RXTERM_OFFSN_MASK GENMASK(6, 3) +#define ANA_SB_RXTERM_OFFSN(x) UPDATE(x, 6, 3) +#define OVRD_SB_RX_RESCAL_DONE_MASK BIT(1) +#define OVRD_SB_RX_RESCAL_DONE(x) UPDATE(x, 1, 1) +#define SB_RX_RESCAL_DONE_MASK BIT(0) +#define SB_RX_RESCAL_DONE(x) UPDATE(x, 0, 0) +#define SB_REG0104 0x0410 +#define OVRD_SB_EN_MASK BIT(5) +#define OVRD_SB_EN(x) UPDATE(x, 5, 5) +#define SB_EN_MASK BIT(4) +#define SB_EN(x) UPDATE(x, 4, 4) +#define SB_REG0105 0x0414 +#define OVRD_SB_EARC_CMDC_EN_MASK BIT(6) +#define OVRD_SB_EARC_CMDC_EN(x) UPDATE(x, 6, 6) +#define SB_EARC_CMDC_EN_MASK BIT(5) +#define SB_EARC_CMDC_EN(x) UPDATE(x, 5, 5) +#define ANA_SB_TX_HLVL_PROG_MASK GENMASK(2, 0) +#define ANA_SB_TX_HLVL_PROG(x) UPDATE(x, 2, 0) +#define SB_REG0106 0x0418 +#define ANA_SB_TX_LLVL_PROG_MASK GENMASK(6, 4) +#define ANA_SB_TX_LLVL_PROG(x) UPDATE(x, 6, 4) +#define SB_REG0107 0x041C +#define SB_REG0108 0x0420 +#define SB_REG0109 0x0424 +#define ANA_SB_DMRX_AFC_DIV_RATIO_MASK GENMASK(2, 0) +#define ANA_SB_DMRX_AFC_DIV_RATIO(x) UPDATE(x, 2, 0) +#define SB_REG010A 0x0428 +#define SB_REG010B 0x042C +#define SB_REG010C 0x0430 +#define SB_REG010D 0x0434 +#define SB_REG010E 0x0438 +#define SB_REG010F 0x043C +#define OVRD_SB_VREG_EN_MASK BIT(7) +#define OVRD_SB_VREG_EN(x) UPDATE(x, 7, 7) +#define SB_VREG_EN_MASK BIT(6) +#define SB_VREG_EN(x) UPDATE(x, 6, 6) +#define OVRD_SB_VREG_LPF_BYPASS_MASK BIT(5) +#define OVRD_SB_VREG_LPF_BYPASS(x) UPDATE(x, 5, 5) +#define SB_VREG_LPF_BYPASS_MASK BIT(4) +#define SB_VREG_LPF_BYPASS(x) UPDATE(x, 4, 4) +#define ANA_SB_VREG_GAIN_CTRL_MASK GENMASK(3, 0) +#define ANA_SB_VREG_GAIN_CTRL(x) UPDATE(x, 3, 0) +#define SB_REG0110 0x0440 +#define ANA_SB_VREG_REF_SEL_MASK BIT(0) +#define ANA_SB_VREG_REF_SEL(x) UPDATE(x, 0, 0) +#define SB_REG0111 0x0444 +#define SB_REG0112 0x0448 +#define SB_REG0113 0x044C +#define SB_RX_RCAL_OPT_CODE_MASK GENMASK(5, 4) +#define SB_RX_RCAL_OPT_CODE(x) UPDATE(x, 5, 4) +#define SB_RX_RTERM_CTRL_MASK GENMASK(3, 0) +#define SB_RX_RTERM_CTRL(x) UPDATE(x, 3, 0) +#define SB_REG0114 0x0450 +#define SB_TG_SB_EN_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_TG_SB_EN_DELAY_TIME(x) UPDATE(x, 5, 3) +#define SB_TG_RXTERM_EN_DELAY_TIME_MASK GENMASK(2, 0) +#define SB_TG_RXTERM_EN_DELAY_TIME(x) UPDATE(x, 2, 0) +#define SB_REG0115 0x0454 +#define SB_READY_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_READY_DELAY_TIME(x) UPDATE(x, 5, 3) +#define SB_TG_OSC_EN_DELAY_TIME_MASK GENMASK(2, 0) +#define SB_TG_OSC_EN_DELAY_TIME(x) UPDATE(x, 2, 0) +#define SB_REG0116 0x0458 +#define AFC_RSTN_DELAY_TIME_MASK GENMASK(6, 4) +#define AFC_RSTN_DELAY_TIME(x) UPDATE(x, 6, 4) +#define SB_REG0117 0x045C +#define FAST_PULSE_TIME_MASK GENMASK(3, 0) +#define FAST_PULSE_TIME(x) UPDATE(x, 3, 0) +#define SB_REG0118 0x0460 +#define SB_REG0119 0x0464 +#define SB_REG011A 0x0468 +#define SB_REG011B 0x046C +#define SB_EARC_SIG_DET_BYPASS_MASK BIT(4) +#define SB_EARC_SIG_DET_BYPASS(x) UPDATE(x, 4, 4) +#define SB_AFC_TOL_MASK GENMASK(3, 0) +#define SB_AFC_TOL(x) UPDATE(x, 3, 0) +#define SB_REG011C 0x0470 +#define SB_REG011D 0x0474 +#define SB_REG011E 0x0478 +#define SB_REG011F 0x047C +#define SB_PWM_AFC_CTRL_MASK GENMASK(7, 2) +#define SB_PWM_AFC_CTRL(x) UPDATE(x, 7, 2) +#define SB_RCAL_RSTN_MASK BIT(1) +#define SB_RCAL_RSTN(x) UPDATE(x, 1, 1) +#define SB_REG0120 0x0480 +#define SB_EARC_EN_MASK BIT(1) +#define SB_EARC_EN(x) UPDATE(x, 1, 1) +#define SB_EARC_AFC_EN_MASK BIT(2) +#define SB_EARC_AFC_EN(x) UPDATE(x, 2, 2) +#define SB_REG0121 0x0484 +#define SB_REG0122 0x0488 +#define SB_REG0123 0x048C +#define OVRD_SB_READY_MASK BIT(5) +#define OVRD_SB_READY(x) UPDATE(x, 5, 5) +#define SB_READY_MASK BIT(4) +#define SB_READY(x) UPDATE(x, 4, 4) +#define SB_REG0124 0x0490 +#define SB_REG0125 0x0494 +#define SB_REG0126 0x0498 +#define SB_REG0127 0x049C +#define SB_REG0128 0x04A0 +#define SB_REG0129 0x04AD +#define LNTOP_REG0200 0x0800 +#define PROTOCOL_SEL BIT(2) +#define HDMI_MODE BIT(2) +#define HDMI_TMDS_FRL_SEL BIT(1) +#define LNTOP_REG0201 0x0804 +#define LNTOP_REG0202 0x0808 +#define LNTOP_REG0203 0x080C +#define LNTOP_REG0204 0x0810 +#define LNTOP_REG0205 0x0814 +#define LNTOP_REG0206 0x0818 +#define DATA_BUS_WIDTH (0x3 << 1) +#define WIDTH_40BIT (0x3 << 1) +#define WIDTH_36BIT (0x2 << 1) +#define DATA_BUS_SEL BIT(0) +#define DATA_BUS_36_40 BIT(0) +#define LNTOP_REG0207 0x081C +#define LANE_EN 0xf +#define ALL_LANE_EN 0xf +#define LNTOP_REG0208 0x0820 +#define LNTOP_REG0209 0x0824 +#define LNTOP_REG020A 0x0828 +#define LNTOP_REG020B 0x082C +#define LNTOP_REG020C 0x0830 +#define LNTOP_REG020D 0x0834 +#define LNTOP_REG020E 0x0838 +#define LNTOP_REG020F 0x083C +#define LNTOP_REG0210 0x0840 +#define LNTOP_REG0211 0x0844 +#define LNTOP_REG0212 0x0848 +#define LNTOP_REG0213 0x084C +#define LNTOP_REG0214 0x0850 +#define LNTOP_REG0215 0x0854 +#define LNTOP_REG0216 0x0858 +#define LNTOP_REG0217 0x085C +#define LNTOP_REG0218 0x0860 +#define LNTOP_REG0219 0x0864 +#define LNTOP_REG021A 0x0868 +#define LNTOP_REG021B 0x086C +#define LNTOP_REG021C 0x0870 +#define LNTOP_REG021D 0x0874 +#define LNTOP_REG021E 0x0878 +#define LNTOP_REG021F 0x087C +#define LNTOP_REG0220 0x0880 +#define LNTOP_REG0221 0x0884 +#define LNTOP_REG0222 0x0888 +#define LNTOP_REG0223 0x088C +#define LNTOP_REG0224 0x0890 +#define LNTOP_REG0225 0x0894 +#define LNTOP_REG0226 0x0898 +#define LNTOP_REG0227 0x089C +#define LNTOP_REG0228 0x08A0 +#define LNTOP_REG0229 0x08A4 +#define LANE_REG0300 0x0C00 +#define LANE_REG0301 0x0C04 +#define LANE_REG0302 0x0C08 +#define LANE_REG0303 0x0C0C +#define LANE_REG0304 0x0C10 +#define LANE_REG0305 0x0C14 +#define LANE_REG0306 0x0C18 +#define LANE_REG0307 0x0C1C +#define LANE_REG0308 0x0C20 +#define LANE_REG0309 0x0C24 +#define LANE_REG030A 0x0C28 +#define LANE_REG030B 0x0C2C +#define LANE_REG030C 0x0C30 +#define LANE_REG030D 0x0C34 +#define LANE_REG030E 0x0C38 +#define LANE_REG030F 0x0C3C +#define LANE_REG0310 0x0C40 +#define LANE_REG0311 0x0C44 +#define LANE_REG0312 0x0C48 +#define LN0_TX_SER_RATE_SEL_RBR BIT(5) +#define LN0_TX_SER_RATE_SEL_HBR BIT(4) +#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2) +#define LANE_REG0313 0x0C4C +#define LANE_REG0314 0x0C50 +#define LANE_REG0315 0x0C54 +#define LANE_REG0316 0x0C58 +#define LANE_REG0317 0x0C5C +#define LANE_REG0318 0x0C60 +#define LANE_REG0319 0x0C64 +#define LANE_REG031A 0x0C68 +#define LANE_REG031B 0x0C6C +#define LANE_REG031C 0x0C70 +#define LANE_REG031D 0x0C74 +#define LANE_REG031E 0x0C78 +#define LANE_REG031F 0x0C7C +#define LANE_REG0320 0x0C80 +#define LANE_REG0321 0x0C84 +#define LANE_REG0322 0x0C88 +#define LANE_REG0323 0x0C8C +#define LANE_REG0324 0x0C90 +#define LANE_REG0325 0x0C94 +#define LANE_REG0326 0x0C98 +#define LANE_REG0327 0x0C9C +#define LANE_REG0328 0x0CA0 +#define LANE_REG0329 0x0CA4 +#define LANE_REG032A 0x0CA8 +#define LANE_REG032B 0x0CAC +#define LANE_REG032C 0x0CB0 +#define LANE_REG032D 0x0CB4 +#define LANE_REG0400 0x1000 +#define LANE_REG0401 0x1004 +#define LANE_REG0402 0x1008 +#define LANE_REG0403 0x100C +#define LANE_REG0404 0x1010 +#define LANE_REG0405 0x1014 +#define LANE_REG0406 0x1018 +#define LANE_REG0407 0x101C +#define LANE_REG0408 0x1020 +#define LANE_REG0409 0x1024 +#define LANE_REG040A 0x1028 +#define LANE_REG040B 0x102C +#define LANE_REG040C 0x1030 +#define LANE_REG040D 0x1034 +#define LANE_REG040E 0x1038 +#define LANE_REG040F 0x103C +#define LANE_REG0410 0x1040 +#define LANE_REG0411 0x1044 +#define LANE_REG0412 0x1048 +#define LN1_TX_SER_RATE_SEL_RBR BIT(5) +#define LN1_TX_SER_RATE_SEL_HBR BIT(4) +#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2) +#define LANE_REG0413 0x104C +#define LANE_REG0414 0x1050 +#define LANE_REG0415 0x1054 +#define LANE_REG0416 0x1058 +#define LANE_REG0417 0x105C +#define LANE_REG0418 0x1060 +#define LANE_REG0419 0x1064 +#define LANE_REG041A 0x1068 +#define LANE_REG041B 0x106C +#define LANE_REG041C 0x1070 +#define LANE_REG041D 0x1074 +#define LANE_REG041E 0x1078 +#define LANE_REG041F 0x107C +#define LANE_REG0420 0x1080 +#define LANE_REG0421 0x1084 +#define LANE_REG0422 0x1088 +#define LANE_REG0423 0x108C +#define LANE_REG0424 0x1090 +#define LANE_REG0425 0x1094 +#define LANE_REG0426 0x1098 +#define LANE_REG0427 0x109C +#define LANE_REG0428 0x10A0 +#define LANE_REG0429 0x10A4 +#define LANE_REG042A 0x10A8 +#define LANE_REG042B 0x10AC +#define LANE_REG042C 0x10B0 +#define LANE_REG042D 0x10B4 +#define LANE_REG0500 0x1400 +#define LANE_REG0501 0x1404 +#define LANE_REG0502 0x1408 +#define LANE_REG0503 0x140C +#define LANE_REG0504 0x1410 +#define LANE_REG0505 0x1414 +#define LANE_REG0506 0x1418 +#define LANE_REG0507 0x141C +#define LANE_REG0508 0x1420 +#define LANE_REG0509 0x1424 +#define LANE_REG050A 0x1428 +#define LANE_REG050B 0x142C +#define LANE_REG050C 0x1430 +#define LANE_REG050D 0x1434 +#define LANE_REG050E 0x1438 +#define LANE_REG050F 0x143C +#define LANE_REG0510 0x1440 +#define LANE_REG0511 0x1444 +#define LANE_REG0512 0x1448 +#define LN2_TX_SER_RATE_SEL_RBR BIT(5) +#define LN2_TX_SER_RATE_SEL_HBR BIT(4) +#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2) +#define LANE_REG0513 0x144C +#define LANE_REG0514 0x1450 +#define LANE_REG0515 0x1454 +#define LANE_REG0516 0x1458 +#define LANE_REG0517 0x145C +#define LANE_REG0518 0x1460 +#define LANE_REG0519 0x1464 +#define LANE_REG051A 0x1468 +#define LANE_REG051B 0x146C +#define LANE_REG051C 0x1470 +#define LANE_REG051D 0x1474 +#define LANE_REG051E 0x1478 +#define LANE_REG051F 0x147C +#define LANE_REG0520 0x1480 +#define LANE_REG0521 0x1484 +#define LANE_REG0522 0x1488 +#define LANE_REG0523 0x148C +#define LANE_REG0524 0x1490 +#define LANE_REG0525 0x1494 +#define LANE_REG0526 0x1498 +#define LANE_REG0527 0x149C +#define LANE_REG0528 0x14A0 +#define LANE_REG0529 0x14AD +#define LANE_REG052A 0x14A8 +#define LANE_REG052B 0x14AC +#define LANE_REG052C 0x14B0 +#define LANE_REG052D 0x14B4 +#define LANE_REG0600 0x1800 +#define LANE_REG0601 0x1804 +#define LANE_REG0602 0x1808 +#define LANE_REG0603 0x180C +#define LANE_REG0604 0x1810 +#define LANE_REG0605 0x1814 +#define LANE_REG0606 0x1818 +#define LANE_REG0607 0x181C +#define LANE_REG0608 0x1820 +#define LANE_REG0609 0x1824 +#define LANE_REG060A 0x1828 +#define LANE_REG060B 0x182C +#define LANE_REG060C 0x1830 +#define LANE_REG060D 0x1834 +#define LANE_REG060E 0x1838 +#define LANE_REG060F 0x183C +#define LANE_REG0610 0x1840 +#define LANE_REG0611 0x1844 +#define LANE_REG0612 0x1848 +#define LN3_TX_SER_RATE_SEL_RBR BIT(5) +#define LN3_TX_SER_RATE_SEL_HBR BIT(4) +#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) +#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) +#define LANE_REG0613 0x184C +#define LANE_REG0614 0x1850 +#define LANE_REG0615 0x1854 +#define LANE_REG0616 0x1858 +#define LANE_REG0617 0x185C +#define LANE_REG0618 0x1860 +#define LANE_REG0619 0x1864 +#define LANE_REG061A 0x1868 +#define LANE_REG061B 0x186C +#define LANE_REG061C 0x1870 +#define LANE_REG061D 0x1874 +#define LANE_REG061E 0x1878 +#define LANE_REG061F 0x187C +#define LANE_REG0620 0x1880 +#define LANE_REG0621 0x1884 +#define LANE_REG0622 0x1888 +#define LANE_REG0623 0x188C +#define LANE_REG0624 0x1890 +#define LANE_REG0625 0x1894 +#define LANE_REG0626 0x1898 +#define LANE_REG0627 0x189C +#define LANE_REG0628 0x18A0 +#define LANE_REG0629 0x18A4 +#define LANE_REG062A 0x18A8 +#define LANE_REG062B 0x18AC +#define LANE_REG062C 0x18B0 +#define LANE_REG062D 0x18B4 + +#define HDMI20_MAX_RATE 600000000 +#define DATA_RATE_MASK 0xFFFFFFF +#define COLOR_DEPTH_MASK BIT(31) +#define HDMI_MODE_MASK BIT(30) +#define HDMI_EARC_MASK BIT(29) + +#define FRL_8G_4LANES 3200000000ULL +#define FRL_6G_3LANES 1800000000 +#define FRL_3G_3LANES 900000000 + +struct RoPllConfig { + UINT32 Bit_Rate; + UINT8 Pms_Mdiv; + UINT8 Pms_Mdiv_Afc; + UINT8 Pms_Pdiv; + UINT8 Pms_Refdiv; + UINT8 Pms_Sdiv; + UINT8 Pms_Iqdiv_Rstn; + UINT8 Ref_Clk_Sel; + UINT8 Sdm_En; + UINT8 Sdm_Rstn; + UINT8 Sdc_Frac_En; + UINT8 Sdc_Rstn; + UINT8 Sdm_Clk_Div; + UINT8 Sdm_Deno; + UINT8 Sdm_Num_Sign; + UINT8 Sdm_Num; + UINT8 Sdc_N; + UINT8 Sdc_Num; + UINT8 Sdc_Deno; + UINT8 Sdc_Ndiv_Rstn; + UINT8 Ssc_En; + UINT8 Ssc_Fm_Dev; + UINT8 Ssc_Fm_Freq; + UINT8 Ssc_Clk_Div_Sel; + UINT8 Ana_Cpp_Ctrl; + UINT8 Ana_Lpf_C_Sel; + UINT8 Cd_Tx_Ser_Rate_Sel; +}; + +STATIC CONST struct RoPllConfig ROPLL_TMDS_CONFIG[] = { + { 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1462500, 122, 122, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 1, 0, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, + 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 855000, 125, 125, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 80, 1, 16, 2, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, + 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, 0x14, + 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, + }, + { ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }, +}; + +INLINE +VOID +PhyWrite ( + OUT struct RockchipHdptxPhyHdmi *Hdptx, + UINTN Reg, + UINTN Val + ) +{ + UINT32 Shift; + + if (!Hdptx->Id) + Shift = HDMI0TX_PHY_BASE; + else + Shift = HDMI1TX_PHY_BASE; + + MmioWrite32(Shift + Reg, Val ); +} + +INLINE +UINTN +PhyRead ( + OUT struct RockchipHdptxPhyHdmi *Hdptx, + UINTN Reg + ) +{ + UINT32 Shift; + + if(!Hdptx->Id) + Shift = HDMI0TX_PHY_BASE; + else + Shift = HDMI1TX_PHY_BASE; + + return MmioRead32(Shift + Reg); +} + +STATIC +VOID +PhyUpdateBits ( + OUT struct RockchipHdptxPhyHdmi *Hdptx, + UINTN Reg, + UINTN Mask, + UINTN Val + ) +{ + UINTN Orig, Tmp; + + Orig = PhyRead(Hdptx, Reg); + Tmp = Orig & ~Mask; + Tmp |= Val & Mask; + PhyWrite(Hdptx, Reg, Tmp); +}; + +STATIC +VOID +GrfWrite ( + OUT struct RockchipHdptxPhyHdmi *Hdptx, + UINTN Reg, + UINTN Mask, + UINTN Val + ) +{ + UINT32 TempVal = 0; + UINT32 Shift; + + if (!Hdptx->Id) + Shift = HDPTXPHY0_GRF_BASE; + else + Shift = HDPTXPHY1_GRF_BASE; + + TempVal = (Mask << 16) | (Val & Mask); + MmioWrite32(Shift + Reg, TempVal); +}; + +STATIC +UINT32 +GrfRead ( + OUT struct RockchipHdptxPhyHdmi *Hdptx, + UINTN Reg + ) +{ + UINT32 Shift; + + if (!Hdptx->Id) + Shift = HDPTXPHY0_GRF_BASE; + else + Shift = HDPTXPHY1_GRF_BASE; + + return MmioRead32(Shift + Reg); +}; + +STATIC +VOID +CruWrite ( + UINTN Reg, + UINTN Mask, + UINTN Val + ) +{ + UINT32 TempVal = 0; + + TempVal = (Mask << 16) | (Val & Mask); + MmioWrite32(PMU1CRU_BASE + Reg, TempVal); +}; + +VOID +HdptxPrePowerUp ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ) +{ + UINT32 Val = 0; + + /* assert lane/cmn/init reset */ + if (!Hdptx->Id) { + CruWrite(PMU1CRU_SOFTRST_CON03, 0x3800, 0x3800); + } else { + CruWrite(PMU1CRU_SOFTRST_CON03, BIT(15), BIT(15)); + CruWrite(PMU1CRU_SOFTRST_CON04, 0x3, 0x3); + } + + Val = HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + GrfWrite(Hdptx, GRF_HDPTX_CON0, Val, 0); +} + +STATIC +UINT32 +HdptxPostEnablePll ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ) +{ + UINT32 Val = 0; + UINT32 i; + + Val = HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + GrfWrite(Hdptx, GRF_HDPTX_CON0, Val, Val); + NanoSecondDelay (10000); + /* deassert init reset */ + if (!Hdptx->Id) + CruWrite(PMU1CRU_SOFTRST_CON03, BIT(11), 0); + else + CruWrite(PMU1CRU_SOFTRST_CON03, BIT(15), 0); + NanoSecondDelay (10000); + Val = HDPTX_I_PLL_EN; + GrfWrite(Hdptx, GRF_HDPTX_CON0, Val, Val); + NanoSecondDelay (10000); + /* deassert cmn reset */ + if (!Hdptx->Id) + CruWrite(PMU1CRU_SOFTRST_CON03, BIT(12), 0); + else + CruWrite(PMU1CRU_SOFTRST_CON04, BIT(0), 0); + + Val = 0; + for (i = 0; i < 50; i++) { + Val = GrfRead(Hdptx, GRF_HDPTX_STATUS); + + if (Val & HDPTX_O_PHY_CLK_RDY) + break; + NanoSecondDelay (20000); + } + + if (i == 50) { + DEBUG ((DEBUG_INIT, "%a hdptx phy pll can't lock!\n", __func__)); + return -EINVAL; + } + + DEBUG ((DEBUG_INIT, "%a hdptx phy pll locked!\n", __func__)); + + return 0; +} + +UINT32 +HdptxRopllCmnConfig ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ) +{ + CONST struct RoPllConfig *Cfg = ROPLL_TMDS_CONFIG; + + for (; Cfg->Bit_Rate != ~0; Cfg++) + if (Cfg->Bit_Rate == 1485000) + break; + DEBUG ((DEBUG_INIT, "%a HdptxRopllCmnConfig start\n", __func__)); + HdptxPrePowerUp(Hdptx); + DEBUG ((DEBUG_INIT, "%a HdptxRopllCmnConfig %d\n", __func__, Cfg->Bit_Rate)); + GrfWrite(Hdptx, GRF_HDPTX_CON0, LC_REF_CLK_SEL, 0); + + PhyWrite(Hdptx, CMN_REG0008, 0x00); + PhyWrite(Hdptx, CMN_REG0009, 0x0c); + PhyWrite(Hdptx, CMN_REG000A, 0x83); + PhyWrite(Hdptx, CMN_REG000B, 0x06); + PhyWrite(Hdptx, CMN_REG000C, 0x20); + PhyWrite(Hdptx, CMN_REG000D, 0xb8); + PhyWrite(Hdptx, CMN_REG000E, 0x0f); + PhyWrite(Hdptx, CMN_REG000F, 0x0f); + PhyWrite(Hdptx, CMN_REG0010, 0x04); + PhyWrite(Hdptx, CMN_REG0011, 0x01); + PhyWrite(Hdptx, CMN_REG0012, 0x26); + PhyWrite(Hdptx, CMN_REG0013, 0x22); + PhyWrite(Hdptx, CMN_REG0014, 0x24); + PhyWrite(Hdptx, CMN_REG0015, 0x77); + PhyWrite(Hdptx, CMN_REG0016, 0x08); + PhyWrite(Hdptx, CMN_REG0017, 0x20); + PhyWrite(Hdptx, CMN_REG0018, 0x04); + PhyWrite(Hdptx, CMN_REG0019, 0x48); + PhyWrite(Hdptx, CMN_REG001A, 0x01); + PhyWrite(Hdptx, CMN_REG001B, 0x00); + PhyWrite(Hdptx, CMN_REG001C, 0x01); + PhyWrite(Hdptx, CMN_REG001D, 0x64); + PhyWrite(Hdptx, CMN_REG001E, 0x14); + PhyWrite(Hdptx, CMN_REG001F, 0x00); + PhyWrite(Hdptx, CMN_REG0020, 0x00); + PhyWrite(Hdptx, CMN_REG0021, 0x00); + PhyWrite(Hdptx, CMN_REG0022, 0x11); + PhyWrite(Hdptx, CMN_REG0023, 0x00); + PhyWrite(Hdptx, CMN_REG0024, 0x00); + PhyWrite(Hdptx, CMN_REG0025, 0x53); + PhyWrite(Hdptx, CMN_REG0026, 0x00); + PhyWrite(Hdptx, CMN_REG0027, 0x00); + PhyWrite(Hdptx, CMN_REG0028, 0x01); + PhyWrite(Hdptx, CMN_REG0029, 0x01); + PhyWrite(Hdptx, CMN_REG002A, 0x00); + PhyWrite(Hdptx, CMN_REG002B, 0x00); + PhyWrite(Hdptx, CMN_REG002C, 0x00); + PhyWrite(Hdptx, CMN_REG002D, 0x00); + PhyWrite(Hdptx, CMN_REG002E, 0x04); + PhyWrite(Hdptx, CMN_REG002F, 0x00); + PhyWrite(Hdptx, CMN_REG0030, 0x20); + PhyWrite(Hdptx, CMN_REG0031, 0x30); + PhyWrite(Hdptx, CMN_REG0032, 0x0b); + PhyWrite(Hdptx, CMN_REG0033, 0x23); + PhyWrite(Hdptx, CMN_REG0034, 0x00); + PhyWrite(Hdptx, CMN_REG0035, 0x00); + PhyWrite(Hdptx, CMN_REG0038, 0x00); + PhyWrite(Hdptx, CMN_REG0039, 0x00); + PhyWrite(Hdptx, CMN_REG003A, 0x00); + PhyWrite(Hdptx, CMN_REG003B, 0x00); + PhyWrite(Hdptx, CMN_REG003C, 0x80); + PhyWrite(Hdptx, CMN_REG003D, 0x40); + PhyWrite(Hdptx, CMN_REG003E, 0x0c); + PhyWrite(Hdptx, CMN_REG003F, 0x83); + PhyWrite(Hdptx, CMN_REG0040, 0x06); + PhyWrite(Hdptx, CMN_REG0041, 0x20); + PhyWrite(Hdptx, CMN_REG0042, 0x78); + PhyWrite(Hdptx, CMN_REG0043, 0x00); + PhyWrite(Hdptx, CMN_REG0044, 0x46); + PhyWrite(Hdptx, CMN_REG0045, 0x24); + PhyWrite(Hdptx, CMN_REG0046, 0xdd); + PhyWrite(Hdptx, CMN_REG0047, 0x00); + PhyWrite(Hdptx, CMN_REG0048, 0x11); + PhyWrite(Hdptx, CMN_REG0049, 0xfa); + PhyWrite(Hdptx, CMN_REG004A, 0x08); + PhyWrite(Hdptx, CMN_REG004B, 0x00); + PhyWrite(Hdptx, CMN_REG004C, 0x01); + PhyWrite(Hdptx, CMN_REG004D, 0x64); + PhyWrite(Hdptx, CMN_REG004E, 0x34); + PhyWrite(Hdptx, CMN_REG004F, 0x00); + PhyWrite(Hdptx, CMN_REG0050, 0x00); + DEBUG ((DEBUG_INIT, "%a HdptxRopllCmnConfig 2\n", __func__)); + PhyWrite(Hdptx, CMN_REG0051, Cfg->Pms_Mdiv); + PhyWrite(Hdptx, CMN_REG0055, Cfg->Pms_Mdiv_Afc); + + PhyWrite(Hdptx, CMN_REG0059, (Cfg->Pms_Pdiv << 4) | Cfg->Pms_Refdiv); + + PhyWrite(Hdptx, CMN_REG005A, (Cfg->Pms_Sdiv << 4)); + + PhyWrite(Hdptx, CMN_REG005C, 0x25); + PhyWrite(Hdptx, CMN_REG005D, 0x0c); + PhyWrite(Hdptx, CMN_REG005E, 0x4f); + PhyUpdateBits(Hdptx, CMN_REG005E, ROPLL_SDM_EN_MASK, + ROPLL_SDM_EN(Cfg->Sdm_En)); + if (!Cfg->Sdm_En) + PhyUpdateBits(Hdptx, CMN_REG005E, 0xf, 0); + + PhyWrite(Hdptx, CMN_REG005F, 0x01); + + PhyUpdateBits(Hdptx, CMN_REG0064, ROPLL_SDM_NUM_SIGN_RBR_MASK, + ROPLL_SDM_NUM_SIGN_RBR(Cfg->Sdm_Num_Sign)); + PhyWrite(Hdptx, CMN_REG0065, Cfg->Sdm_Num); + PhyWrite(Hdptx, CMN_REG0060, Cfg->Sdm_Deno); + + PhyUpdateBits(Hdptx, CMN_REG0069, ROPLL_SDC_N_RBR_MASK, + ROPLL_SDC_N_RBR(Cfg->Sdc_N)); + + PhyWrite(Hdptx, CMN_REG006C, Cfg->Sdc_Num); + PhyWrite(Hdptx, CMN_REG0070, Cfg->Sdc_Deno); + + PhyWrite(Hdptx, CMN_REG006B, 0x04); + + PhyWrite(Hdptx, CMN_REG0073, 0x30); + PhyWrite(Hdptx, CMN_REG0074, 0x04); + PhyWrite(Hdptx, CMN_REG0075, 0x20); + PhyWrite(Hdptx, CMN_REG0076, 0x30); + PhyWrite(Hdptx, CMN_REG0077, 0x08); + PhyWrite(Hdptx, CMN_REG0078, 0x0c); + PhyWrite(Hdptx, CMN_REG0079, 0x00); + PhyWrite(Hdptx, CMN_REG007B, 0x00); + PhyWrite(Hdptx, CMN_REG007C, 0x00); + PhyWrite(Hdptx, CMN_REG007D, 0x00); + PhyWrite(Hdptx, CMN_REG007E, 0x00); + PhyWrite(Hdptx, CMN_REG007F, 0x00); + PhyWrite(Hdptx, CMN_REG0080, 0x00); + PhyWrite(Hdptx, CMN_REG0081, 0x01); + PhyWrite(Hdptx, CMN_REG0082, 0x04); + PhyWrite(Hdptx, CMN_REG0083, 0x24); + PhyWrite(Hdptx, CMN_REG0084, 0x20); + PhyWrite(Hdptx, CMN_REG0085, 0x03); + + PhyUpdateBits(Hdptx, CMN_REG0086, PLL_PCG_POSTDIV_SEL_MASK, + PLL_PCG_POSTDIV_SEL(Cfg->Pms_Sdiv)); + + PhyUpdateBits(Hdptx, CMN_REG0086, PLL_PCG_CLK_SEL_MASK, + PLL_PCG_CLK_SEL(8)); + + PhyUpdateBits(Hdptx, CMN_REG0086, PLL_PCG_CLK_EN, PLL_PCG_CLK_EN); + + PhyWrite(Hdptx, CMN_REG0087, 0x04); + PhyWrite(Hdptx, CMN_REG0089, 0x00); + PhyWrite(Hdptx, CMN_REG008A, 0x55); + PhyWrite(Hdptx, CMN_REG008B, 0x25); + PhyWrite(Hdptx, CMN_REG008C, 0x2c); + PhyWrite(Hdptx, CMN_REG008D, 0x22); + PhyWrite(Hdptx, CMN_REG008E, 0x14); + PhyWrite(Hdptx, CMN_REG008F, 0x20); + PhyWrite(Hdptx, CMN_REG0090, 0x00); + PhyWrite(Hdptx, CMN_REG0091, 0x00); + PhyWrite(Hdptx, CMN_REG0092, 0x00); + PhyWrite(Hdptx, CMN_REG0093, 0x00); + PhyWrite(Hdptx, CMN_REG0095, 0x00); + PhyWrite(Hdptx, CMN_REG0097, 0x02); + PhyWrite(Hdptx, CMN_REG0099, 0x04); + PhyWrite(Hdptx, CMN_REG009A, 0x11); + PhyWrite(Hdptx, CMN_REG009B, 0x00); + DEBUG ((DEBUG_INIT, "%a HdptxRopllCmnConfig end\n", __func__)); + return HdptxPostEnablePll(Hdptx); +} + +UINT32 +HdptxPostEnableLane ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ) +{ + UINT32 Val = 0; + UINT32 i; + + /* deassert lane reset */ + if (!Hdptx->Id) + CruWrite(PMU1CRU_SOFTRST_CON03, BIT(13), 0); + else + CruWrite(PMU1CRU_SOFTRST_CON04, BIT(1), 0); + + Val = HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + GrfWrite(Hdptx, GRF_HDPTX_CON0, Val, Val); + + /* 4 lanes frl mode */ + PhyWrite(Hdptx, LNTOP_REG0207, 0x0f); + + Val = 0; + for (i = 0; i < 50; i++) { + Val = GrfRead(Hdptx, GRF_HDPTX_STATUS); + + if (Val & HDPTX_O_PHY_RDY && Val & HDPTX_O_PLL_LOCK_DONE) + break; + NanoSecondDelay (100000); + } + + if (i == 50) { + DEBUG ((DEBUG_INIT, "%a hdptx phy lane can't ready!\n", __func__)); + return -EINVAL; + } + + DEBUG ((DEBUG_INIT, "%a hdptx phy lane locked!\n", __func__)); + + return 0; +} + +UINT32 +HdptxRopllTmdsModeConfig ( + OUT struct RockchipHdptxPhyHdmi *Hdptx + ) +{ + PhyWrite(Hdptx, SB_REG0114, 0x00); + PhyWrite(Hdptx, SB_REG0115, 0x00); + PhyWrite(Hdptx, SB_REG0116, 0x00); + PhyWrite(Hdptx, SB_REG0117, 0x00); + PhyWrite(Hdptx, LNTOP_REG0200, 0x06); + + /* For 1/10 bitrate clk */ + PhyWrite(Hdptx, LNTOP_REG0201, 0x07); + PhyWrite(Hdptx, LNTOP_REG0202, 0xc1); + PhyWrite(Hdptx, LNTOP_REG0203, 0xf0); + PhyWrite(Hdptx, LNTOP_REG0204, 0x7c); + PhyWrite(Hdptx, LNTOP_REG0205, 0x1f); + + PhyWrite(Hdptx, LNTOP_REG0206, 0x07); + PhyWrite(Hdptx, LANE_REG0303, 0x0c); + PhyWrite(Hdptx, LANE_REG0307, 0x20); + PhyWrite(Hdptx, LANE_REG030A, 0x17); + PhyWrite(Hdptx, LANE_REG030B, 0x77); + PhyWrite(Hdptx, LANE_REG030C, 0x77); + PhyWrite(Hdptx, LANE_REG030D, 0x77); + PhyWrite(Hdptx, LANE_REG030E, 0x38); + PhyWrite(Hdptx, LANE_REG0310, 0x03); + PhyWrite(Hdptx, LANE_REG0311, 0x0f); + PhyWrite(Hdptx, LANE_REG0312, 0x00); + PhyWrite(Hdptx, LANE_REG0316, 0x02); + PhyWrite(Hdptx, LANE_REG031B, 0x01); + PhyWrite(Hdptx, LANE_REG031E, 0x00); + PhyWrite(Hdptx, LANE_REG031F, 0x15); + PhyWrite(Hdptx, LANE_REG0320, 0xa0); + PhyWrite(Hdptx, LANE_REG0403, 0x0c); + PhyWrite(Hdptx, LANE_REG0407, 0x20); + PhyWrite(Hdptx, LANE_REG040A, 0x17); + PhyWrite(Hdptx, LANE_REG040B, 0x77); + PhyWrite(Hdptx, LANE_REG040C, 0x77); + PhyWrite(Hdptx, LANE_REG040D, 0x77); + PhyWrite(Hdptx, LANE_REG040E, 0x38); + PhyWrite(Hdptx, LANE_REG0410, 0x03); + PhyWrite(Hdptx, LANE_REG0411, 0x0f); + PhyWrite(Hdptx, LANE_REG0412, 0x00); + PhyWrite(Hdptx, LANE_REG0416, 0x02); + PhyWrite(Hdptx, LANE_REG041B, 0x01); + PhyWrite(Hdptx, LANE_REG041E, 0x00); + PhyWrite(Hdptx, LANE_REG041F, 0x15); + PhyWrite(Hdptx, LANE_REG0420, 0xa0); + PhyWrite(Hdptx, LANE_REG0503, 0x0c); + PhyWrite(Hdptx, LANE_REG0507, 0x20); + PhyWrite(Hdptx, LANE_REG050A, 0x17); + PhyWrite(Hdptx, LANE_REG050B, 0x77); + PhyWrite(Hdptx, LANE_REG050C, 0x77); + PhyWrite(Hdptx, LANE_REG050D, 0x77); + PhyWrite(Hdptx, LANE_REG050E, 0x38); + PhyWrite(Hdptx, LANE_REG0510, 0x03); + PhyWrite(Hdptx, LANE_REG0511, 0x0f); + PhyWrite(Hdptx, LANE_REG0512, 0x00); + PhyWrite(Hdptx, LANE_REG0516, 0x02); + PhyWrite(Hdptx, LANE_REG051B, 0x01); + PhyWrite(Hdptx, LANE_REG051E, 0x00); + PhyWrite(Hdptx, LANE_REG051F, 0x15); + PhyWrite(Hdptx, LANE_REG0520, 0xa0); + PhyWrite(Hdptx, LANE_REG0603, 0x0c); + PhyWrite(Hdptx, LANE_REG0607, 0x20); + PhyWrite(Hdptx, LANE_REG060A, 0x17); + PhyWrite(Hdptx, LANE_REG060B, 0x77); + PhyWrite(Hdptx, LANE_REG060C, 0x77); + PhyWrite(Hdptx, LANE_REG060D, 0x77); + PhyWrite(Hdptx, LANE_REG060E, 0x38); + PhyWrite(Hdptx, LANE_REG0610, 0x03); + PhyWrite(Hdptx, LANE_REG0611, 0x0f); + PhyWrite(Hdptx, LANE_REG0612, 0x00); + PhyWrite(Hdptx, LANE_REG0616, 0x02); + PhyWrite(Hdptx, LANE_REG061B, 0x01); + PhyWrite(Hdptx, LANE_REG061E, 0x08); + PhyWrite(Hdptx, LANE_REG061F, 0x15); + PhyWrite(Hdptx, LANE_REG0620, 0xa0); + + PhyWrite(Hdptx, LANE_REG0303, 0x2f); + PhyWrite(Hdptx, LANE_REG0403, 0x2f); + PhyWrite(Hdptx, LANE_REG0503, 0x2f); + PhyWrite(Hdptx, LANE_REG0603, 0x2f); + PhyWrite(Hdptx, LANE_REG0305, 0x03); + PhyWrite(Hdptx, LANE_REG0405, 0x03); + PhyWrite(Hdptx, LANE_REG0505, 0x03); + PhyWrite(Hdptx, LANE_REG0605, 0x03); + PhyWrite(Hdptx, LANE_REG0306, 0x1c); + PhyWrite(Hdptx, LANE_REG0406, 0x1c); + PhyWrite(Hdptx, LANE_REG0506, 0x1c); + PhyWrite(Hdptx, LANE_REG0606, 0x1c); + + return HdptxPostEnableLane(Hdptx); +} + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.c new file mode 100644 index 0000000..4d692af --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.c @@ -0,0 +1,107 @@ +/** @file + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +EFIAPI +EFI_STATUS +DisplaySetCrtcInfo ( + OUT DRM_DISPLAY_MODE *Mode, + IN UINT32 AdjustFlags + ) +{ + if ((Mode == NULL) || ((Mode->Type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) + return EFI_UNSUPPORTED; + + if (Mode->Flags & DRM_MODE_FLAG_DBLCLK) + Mode->CrtcClock = 2 * Mode->Clock; + else + Mode->CrtcClock = Mode->Clock; + Mode->CrtcHDisplay = Mode->HDisplay; + Mode->CrtcHSyncStart = Mode->HSyncStart; + Mode->CrtcHSyncEnd = Mode->HSyncEnd; + Mode->CrtcHTotal = Mode->HTotal; + Mode->CrtcHSkew = Mode->HSkew; + Mode->CrtcVDisplay = Mode->VDisplay; + Mode->CrtcVSyncStart = Mode->VSyncStart; + Mode->CrtcVSyncEnd = Mode->VSyncEnd; + Mode->CrtcVTotal = Mode->VTotal; + + if (Mode->Flags & DRM_MODE_FLAG_INTERLACE) { + if (AdjustFlags & CRTC_INTERLACE_HALVE_V) { + Mode->CrtcVDisplay /= 2; + Mode->CrtcVSyncStart /= 2; + Mode->CrtcVSyncEnd /= 2; + Mode->CrtcVTotal /= 2; + } + } + + if (!(AdjustFlags & CRTC_NO_DBLSCAN)) { + if (Mode->Flags & DRM_MODE_FLAG_DBLSCAN) { + Mode->CrtcVDisplay *= 2; + Mode->CrtcVSyncStart *= 2; + Mode->CrtcVSyncEnd *= 2; + Mode->CrtcVTotal *= 2; + } + } + + if (!(AdjustFlags & CRTC_NO_VSCAN)) { + if (Mode->VScan > 1) { + Mode->CrtcVDisplay *= Mode->VScan; + Mode->CrtcVSyncStart *= Mode->VScan; + Mode->CrtcVSyncEnd *= Mode->VScan; + Mode->CrtcVTotal *= Mode->VScan; + } + } + + Mode->CrtcVBlankStart = MIN(Mode->CrtcVSyncStart, Mode->CrtcVDisplay); + Mode->CrtcVBlankEnd = MAX(Mode->CrtcVSyncEnd, Mode->CrtcVTotal); + Mode->CrtcHBlankStart = MIN(Mode->CrtcHSyncStart, Mode->CrtcHDisplay); + Mode->CrtcHBblankEnd = MAX(Mode->CrtcHSyncEnd, Mode->CrtcHTotal); + + return EFI_SUCCESS; +} + +UINT32 +EFIAPI +DrmModeVRefresh ( + DRM_DISPLAY_MODE *Mode + ) +{ + UINT32 Refresh = 0; + UINT32 CalcVal; + + if (Mode->VRefresh > 0) { + Refresh = Mode->VRefresh; + } else if (Mode->HTotal > 0 && Mode->VTotal > 0) { + int VTotal; + + VTotal = Mode->VTotal; + /* work out VRefresh the value will be x1000 */ + CalcVal = (Mode->Clock * 1000); + CalcVal /= Mode->HTotal; + Refresh = (CalcVal + VTotal / 2) / VTotal; + + if (Mode->Flags & DRM_MODE_FLAG_INTERLACE) + Refresh *= 2; + if (Mode->Flags & DRM_MODE_FLAG_DBLSCAN) + Refresh /= 2; + if (Mode->VScan > 1) + Refresh /= Mode->VScan; + } + return Refresh; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.inf new file mode 100644 index 0000000..84afd44 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.inf @@ -0,0 +1,35 @@ +## @file +# +# Copyright (c) 2022 Rockchip Electronics Co. Ltd. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RockchipDisplayLib + FILE_GUID = 967dc52a-7cfa-11ec-b45f-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DisplayLib + +[Sources.common] + RockchipDisplayLib.c + +[LibraryClasses] + IoLib + DebugLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseLib + BaseMemoryLib + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + ArmPkg/ArmPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dp_helper.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dp_helper.c new file mode 100644 index 0000000..7b0ee2b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dp_helper.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright © 2009 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include + +/** + * DOC: dp helpers + * + * These functions contain some common logic and helpers at various abstraction + * levels to deal with Display Port sink devices and related things like DP aux + * channel transfers, EDID reading over DP aux channels, decoding certain DPCD + * blocks, ... + */ + +/* Helpers for DP link training */ +static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) +{ + return link_status[r - DP_LANE0_1_STATUS]; +} + +static u8 dp_get_lane_status(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_LANE0_1_STATUS + (lane >> 1); + int s = (lane & 1) * 4; + u8 l = dp_link_status(link_status, i); + + return (l >> s) & 0xf; +} + +bool drm_dp_channel_eq_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count) +{ + u8 lane_align; + u8 lane_status; + int lane; + + lane_align = dp_link_status(link_status, + DP_LANE_ALIGN_STATUS_UPDATED); + if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) + return false; + for (lane = 0; lane < lane_count; lane++) { + lane_status = dp_get_lane_status(link_status, lane); + if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) + return false; + } + return true; +} + +bool drm_dp_clock_recovery_ok(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane_count) +{ + int lane; + u8 lane_status; + + for (lane = 0; lane < lane_count; lane++) { + lane_status = dp_get_lane_status(link_status, lane); + if ((lane_status & DP_LANE_CR_DONE) == 0) + return false; + } + return true; +} + +u8 drm_dp_get_adjust_request_voltage(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : + DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; +} + +u8 drm_dp_get_adjust_request_pre_emphasis(const u8 link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); + u8 l = dp_link_status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; +} + +void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + + if (rd_interval > 4) + printf("AUX interval %d, out of range (max 4)\n", rd_interval); + + if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) + udelay(100); + else + mdelay(rd_interval * 4); +} + +void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_TRAINING_AUX_RD_MASK; + + if (rd_interval > 4) + printf("AUX interval %d, out of range (max 4)\n", rd_interval); + + if (rd_interval == 0) + udelay(400); + else + mdelay(rd_interval * 4); +} + +u8 drm_dp_link_rate_to_bw_code(int link_rate) +{ + switch (link_rate) { + default: + WARN(1, "unknown DP link rate %d, using %x\n", link_rate, + DP_LINK_BW_1_62); + case 162000: + return DP_LINK_BW_1_62; + case 270000: + return DP_LINK_BW_2_7; + case 540000: + return DP_LINK_BW_5_4; + case 810000: + return DP_LINK_BW_8_1; + } +} + +int drm_dp_bw_code_to_link_rate(u8 link_bw) +{ + switch (link_bw) { + default: + WARN(1, "unknown DP link BW code %x, using 162000\n", link_bw); + case DP_LINK_BW_1_62: + return 162000; + case DP_LINK_BW_2_7: + return 270000; + case DP_LINK_BW_5_4: + return 540000; + case DP_LINK_BW_8_1: + return 810000; + } +} + +#define AUX_RETRY_INTERVAL 500 /* us */ + +static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, + unsigned int offset, void *buffer, size_t size) +{ + struct drm_dp_aux_msg msg; + unsigned int retry, native_reply; + int err = 0, ret = 0; + + memset(&msg, 0, sizeof(msg)); + msg.address = offset; + msg.request = request; + msg.buffer = buffer; + msg.size = size; + + /* + * The specification doesn't give any recommendation on how often to + * retry native transactions. We used to retry 7 times like for + * aux i2c transactions but real world devices this wasn't + * sufficient, bump to 32 which makes Dell 4k monitors happier. + */ + for (retry = 0; retry < 32; retry++) { + if (ret != 0 && ret != -ETIMEDOUT) + udelay(AUX_RETRY_INTERVAL); + + ret = aux->transfer(aux, &msg); + if (ret >= 0) { + native_reply = msg.reply & DP_AUX_NATIVE_REPLY_MASK; + if (native_reply == DP_AUX_NATIVE_REPLY_ACK) { + if (ret == size) + goto out; + + ret = -EPROTO; + } else { + ret = -EIO; + } + } + + /* + * We want the error we return to be the error we received on + * the first transaction, since we may get a different error the + * next time we retry + */ + if (!err) + err = ret; + } + + printf("%s: Too many retries, giving up. First error: %d\n", + aux->name, err); + ret = err; + +out: + return ret; +} + +ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size) +{ + int ret; + + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, + buffer, 1); + if (ret != 1) + goto out; + + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, + buffer, size); + +out: + return ret; +} + +ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, + void *buffer, size_t size) +{ + int ret; + + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, + buffer, size); + + return ret; +} + +int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, + u8 status[DP_LINK_STATUS_SIZE]) +{ + return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status, + DP_LINK_STATUS_SIZE); +} + +static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + u8 dpcd_ext[6]; + int ret; + + /* + * Prior to DP1.3 the bit represented by + * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved. + * If it is set DP_DPCD_REV at 0000h could be at a value less than + * the true capability of the panel. The only way to check is to + * then compare 0000h and 2200h. + */ + if (!(dpcd[DP_TRAINING_AUX_RD_INTERVAL] & + DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT)) + return 0; + + ret = drm_dp_dpcd_read(aux, DP_DP13_DPCD_REV, &dpcd_ext, + sizeof(dpcd_ext)); + if (ret < 0) + return ret; + if (ret != sizeof(dpcd_ext)) + return -EIO; + + if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) { + printf("%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n", + aux->name, dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]); + return 0; + } + + if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext))) + return 0; + + debug("%s: Base DPCD: %*ph\n", + aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + + memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext)); + + return 0; +} + +int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux, + u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + int ret; + + ret = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, DP_RECEIVER_CAP_SIZE); + if (ret < 0) + return ret; + if (ret != DP_RECEIVER_CAP_SIZE || dpcd[DP_DPCD_REV] == 0) + return -EIO; + + ret = drm_dp_read_extended_dpcd_caps(aux, dpcd); + if (ret < 0) + return ret; + + debug("%s: DPCD: %*ph\n", + aux->name, DP_RECEIVER_CAP_SIZE, dpcd); + + return ret; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dsc.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dsc.c new file mode 100644 index 0000000..82a1576 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_dsc.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2018 Intel Corp + * + * Author: + * Manasi Navare + */ + +#include +#include +#include + +/** + * DOC: dsc helpers + * + * VESA specification for DP 1.4 adds a new feature called Display Stream + * Compression (DSC) used to compress the pixel bits before sending it on + * DP/eDP/MIPI DSI interface. DSC is required to be enabled so that the existing + * display interfaces can support high resolutions at higher frames rates using + * the maximum available link capacity of these interfaces. + * + * These functions contain some common logic and helpers to deal with VESA + * Display Stream Compression standard required for DSC on Display Port/eDP or + * MIPI display interfaces. + */ + +/** + * drm_dsc_dp_pps_header_init() - Initializes the PPS Header + * for DisplayPort as per the DP 1.4 spec. + * @pps_header: Secondary data packet header for DSC Picture + * Parameter Set as defined in &struct dp_sdp_header + * + * DP 1.4 spec defines the secondary data packet for sending the + * picture parameter infoframes from the source to the sink. + * This function populates the SDP header defined in + * &struct dp_sdp_header. + */ +void drm_dsc_dp_pps_header_init(struct dp_sdp_header *pps_header) +{ + memset(pps_header, 0, sizeof(*pps_header)); + + pps_header->HB1 = DP_SDP_PPS; + pps_header->HB2 = DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1; +} + +/** + * drm_dsc_pps_payload_pack() - Populates the DSC PPS + * + * @pps_payload: + * Bitwise struct for DSC Picture Parameter Set. This is defined + * by &struct drm_dsc_picture_parameter_set + * @dsc_cfg: + * DSC Configuration data filled by driver as defined by + * &struct drm_dsc_config + * + * DSC source device sends a picture parameter set (PPS) containing the + * information required by the sink to decode the compressed frame. Driver + * populates the DSC PPS struct using the DSC configuration parameters in + * the order expected by the DSC Display Sink device. For the DSC, the sink + * device expects the PPS payload in big endian format for fields + * that span more than 1 byte. + */ +void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_payload, + const struct drm_dsc_config *dsc_cfg) +{ + int i; + + /* Protect against someone accidentally changing struct size */ + BUILD_BUG_ON(sizeof(*pps_payload) != + DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1); + + memset(pps_payload, 0, sizeof(*pps_payload)); + + /* PPS 0 */ + pps_payload->dsc_version = + dsc_cfg->dsc_version_minor | + dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT; + + /* PPS 1, 2 is 0 */ + + /* PPS 3 */ + pps_payload->pps_3 = + dsc_cfg->line_buf_depth | + dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT; + + /* PPS 4 */ + pps_payload->pps_4 = + ((dsc_cfg->bits_per_pixel & DSC_PPS_BPP_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT) | + dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT | + dsc_cfg->simple_422 << DSC_PPS_SIMPLE422_SHIFT | + dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT | + dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT; + + /* PPS 5 */ + pps_payload->bits_per_pixel_low = + (dsc_cfg->bits_per_pixel & DSC_PPS_LSB_MASK); + + /* + * The DSC panel expects the PPS packet to have big endian format + * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert + * to big endian format. If format is little endian, it will swap + * bytes to convert to Big endian else keep it unchanged. + */ + + /* PPS 6, 7 */ + pps_payload->pic_height = cpu_to_be16(dsc_cfg->pic_height); + + /* PPS 8, 9 */ + pps_payload->pic_width = cpu_to_be16(dsc_cfg->pic_width); + + /* PPS 10, 11 */ + pps_payload->slice_height = cpu_to_be16(dsc_cfg->slice_height); + + /* PPS 12, 13 */ + pps_payload->slice_width = cpu_to_be16(dsc_cfg->slice_width); + + /* PPS 14, 15 */ + pps_payload->chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size); + + /* PPS 16 */ + pps_payload->initial_xmit_delay_high = + ((dsc_cfg->initial_xmit_delay & + DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT); + + /* PPS 17 */ + pps_payload->initial_xmit_delay_low = + (dsc_cfg->initial_xmit_delay & DSC_PPS_LSB_MASK); + + /* PPS 18, 19 */ + pps_payload->initial_dec_delay = + cpu_to_be16(dsc_cfg->initial_dec_delay); + + /* PPS 20 is 0 */ + + /* PPS 21 */ + pps_payload->initial_scale_value = + dsc_cfg->initial_scale_value; + + /* PPS 22, 23 */ + pps_payload->scale_increment_interval = + cpu_to_be16(dsc_cfg->scale_increment_interval); + + /* PPS 24 */ + pps_payload->scale_decrement_interval_high = + ((dsc_cfg->scale_decrement_interval & + DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT); + + /* PPS 25 */ + pps_payload->scale_decrement_interval_low = + (dsc_cfg->scale_decrement_interval & DSC_PPS_LSB_MASK); + + /* PPS 26[7:0], PPS 27[7:5] RESERVED */ + + /* PPS 27 */ + pps_payload->first_line_bpg_offset = + dsc_cfg->first_line_bpg_offset; + + /* PPS 28, 29 */ + pps_payload->nfl_bpg_offset = + cpu_to_be16(dsc_cfg->nfl_bpg_offset); + + /* PPS 30, 31 */ + pps_payload->slice_bpg_offset = + cpu_to_be16(dsc_cfg->slice_bpg_offset); + + /* PPS 32, 33 */ + pps_payload->initial_offset = + cpu_to_be16(dsc_cfg->initial_offset); + + /* PPS 34, 35 */ + pps_payload->final_offset = cpu_to_be16(dsc_cfg->final_offset); + + /* PPS 36 */ + pps_payload->flatness_min_qp = dsc_cfg->flatness_min_qp; + + /* PPS 37 */ + pps_payload->flatness_max_qp = dsc_cfg->flatness_max_qp; + + /* PPS 38, 39 */ + pps_payload->rc_model_size = + cpu_to_be16(DSC_RC_MODEL_SIZE_CONST); + + /* PPS 40 */ + pps_payload->rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST; + + /* PPS 41 */ + pps_payload->rc_quant_incr_limit0 = + dsc_cfg->rc_quant_incr_limit0; + + /* PPS 42 */ + pps_payload->rc_quant_incr_limit1 = + dsc_cfg->rc_quant_incr_limit1; + + /* PPS 43 */ + pps_payload->rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST | + DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT; + + /* PPS 44 - 57 */ + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) + pps_payload->rc_buf_thresh[i] = + dsc_cfg->rc_buf_thresh[i]; + + /* PPS 58 - 87 */ + /* + * For DSC sink programming the RC Range parameter fields + * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0] + */ + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + pps_payload->rc_range_parameters[i] = + cpu_to_be16((dsc_cfg->rc_range_params[i].range_min_qp << + DSC_PPS_RC_RANGE_MINQP_SHIFT) | + (dsc_cfg->rc_range_params[i].range_max_qp << + DSC_PPS_RC_RANGE_MAXQP_SHIFT) | + (dsc_cfg->rc_range_params[i].range_bpg_offset)); + } + + /* PPS 88 */ + pps_payload->native_422_420 = dsc_cfg->native_422 | + dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT; + + /* PPS 89 */ + pps_payload->second_line_bpg_offset = + dsc_cfg->second_line_bpg_offset; + + /* PPS 90, 91 */ + pps_payload->nsl_bpg_offset = + cpu_to_be16(dsc_cfg->nsl_bpg_offset); + + /* PPS 92, 93 */ + pps_payload->second_line_offset_adj = + cpu_to_be16(dsc_cfg->second_line_offset_adj); + + /* PPS 94 - 127 are O */ +} + +/** + * drm_dsc_compute_rc_parameters() - Write rate control + * parameters to the dsc configuration defined in + * &struct drm_dsc_config in accordance with the DSC 1.2 + * specification. Some configuration fields must be present + * beforehand. + * + * @vdsc_cfg: + * DSC Configuration data partially filled by driver + */ +int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg) +{ + unsigned long groups_per_line = 0; + unsigned long groups_total = 0; + unsigned long num_extra_mux_bits = 0; + unsigned long slice_bits = 0; + unsigned long hrd_delay = 0; + unsigned long final_scale = 0; + unsigned long rbs_min = 0; + + if (vdsc_cfg->native_420 || vdsc_cfg->native_422) { + /* Number of groups used to code each line of a slice */ + groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width / 2, + DSC_RC_PIXELS_PER_GROUP); + + /* chunksize in Bytes */ + vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width / 2 * + vdsc_cfg->bits_per_pixel, + (8 * 16)); + } else { + /* Number of groups used to code each line of a slice */ + groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width, + DSC_RC_PIXELS_PER_GROUP); + + /* chunksize in Bytes */ + vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width * + vdsc_cfg->bits_per_pixel, + (8 * 16)); + } + + if (vdsc_cfg->convert_rgb) + num_extra_mux_bits = 3 * (vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + - 2); + else if (vdsc_cfg->native_422) + num_extra_mux_bits = 4 * vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + + 3 * (4 * vdsc_cfg->bits_per_component) - 2; + else + num_extra_mux_bits = 3 * vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + + 2 * (4 * vdsc_cfg->bits_per_component) - 2; + /* Number of bits in one Slice */ + slice_bits = 8 * vdsc_cfg->slice_chunk_size * vdsc_cfg->slice_height; + + while ((num_extra_mux_bits > 0) && + ((slice_bits - num_extra_mux_bits) % vdsc_cfg->mux_word_size)) + num_extra_mux_bits--; + + if (groups_per_line < vdsc_cfg->initial_scale_value - 8) + vdsc_cfg->initial_scale_value = groups_per_line + 8; + + /* scale_decrement_interval calculation according to DSC spec 1.11 */ + if (vdsc_cfg->initial_scale_value > 8) + vdsc_cfg->scale_decrement_interval = groups_per_line / + (vdsc_cfg->initial_scale_value - 8); + else + vdsc_cfg->scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX; + + vdsc_cfg->final_offset = vdsc_cfg->rc_model_size - + (vdsc_cfg->initial_xmit_delay * + vdsc_cfg->bits_per_pixel + 8) / 16 + num_extra_mux_bits; + + if (vdsc_cfg->final_offset >= vdsc_cfg->rc_model_size) { + printf("FinalOfs < RcModelSze for this InitialXmitDelay\n"); + return -ERANGE; + } + + final_scale = (vdsc_cfg->rc_model_size * 8) / + (vdsc_cfg->rc_model_size - vdsc_cfg->final_offset); + if (vdsc_cfg->slice_height > 1) + /* + * NflBpgOffset is 16 bit value with 11 fractional bits + * hence we multiply by 2^11 for preserving the + * fractional part + */ + vdsc_cfg->nfl_bpg_offset = DIV_ROUND_UP((vdsc_cfg->first_line_bpg_offset << 11), + (vdsc_cfg->slice_height - 1)); + else + vdsc_cfg->nfl_bpg_offset = 0; + + /* Number of groups used to code the entire slice */ + groups_total = groups_per_line * vdsc_cfg->slice_height; + + /* slice_bpg_offset is 16 bit value with 11 fractional bits */ + vdsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((vdsc_cfg->rc_model_size - + vdsc_cfg->initial_offset + + num_extra_mux_bits) << 11), + groups_total); + + if (final_scale > 9) { + /* + * ScaleIncrementInterval = + * finaloffset/((NflBpgOffset + SliceBpgOffset)*8(finalscale - 1.125)) + * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional value, + * we need divide by 2^11 from pstDscCfg values + */ + vdsc_cfg->scale_increment_interval = + (vdsc_cfg->final_offset * (1 << 11)) / + ((vdsc_cfg->nfl_bpg_offset + + vdsc_cfg->slice_bpg_offset) * + (final_scale - 9)); + } else { + /* + * If finalScaleValue is less than or equal to 9, a value of 0 should + * be used to disable the scale increment at the end of the slice + */ + vdsc_cfg->scale_increment_interval = 0; + } + + /* + * DSC spec mentions that bits_per_pixel specifies the target + * bits/pixel (bpp) rate that is used by the encoder, + * in steps of 1/16 of a bit per pixel + */ + rbs_min = vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset + + DIV_ROUND_UP(vdsc_cfg->initial_xmit_delay * + vdsc_cfg->bits_per_pixel, 16) + + groups_per_line * vdsc_cfg->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP((rbs_min * 16), vdsc_cfg->bits_per_pixel); + vdsc_cfg->rc_bits = (hrd_delay * vdsc_cfg->bits_per_pixel) / 16; + vdsc_cfg->initial_dec_delay = hrd_delay - vdsc_cfg->initial_xmit_delay; + + return 0; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_mipi_dsi.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_mipi_dsi.c new file mode 100644 index 0000000..d4ca770 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/drm_mipi_dsi.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda + */ + +#include +#include + +/** + * mipi_dsi_attach - attach a DSI device to its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_attach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->attach) + return -ENOSYS; + + return ops->attach(dsi->host, dsi); +} + +/** + * mipi_dsi_detach - detach a DSI device from its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_detach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->detach) + return -ENOSYS; + + return ops->detach(dsi->host, dsi); +} + +static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, + struct mipi_dsi_msg *msg) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->transfer) + return -ENOSYS; + + if (dsi->mode_flags & MIPI_DSI_MODE_LPM) + msg->flags |= MIPI_DSI_MSG_USE_LPM; + + return ops->transfer(dsi->host, msg); +} + +/** + * mipi_dsi_packet_format_is_short - check if a packet is of the short format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a short packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_short(u8 type) +{ + switch (type) { + case MIPI_DSI_V_SYNC_START: + case MIPI_DSI_V_SYNC_END: + case MIPI_DSI_H_SYNC_START: + case MIPI_DSI_H_SYNC_END: + case MIPI_DSI_COMPRESSION_MODE: + case MIPI_DSI_END_OF_TRANSMISSION: + case MIPI_DSI_COLOR_MODE_OFF: + case MIPI_DSI_COLOR_MODE_ON: + case MIPI_DSI_SHUTDOWN_PERIPHERAL: + case MIPI_DSI_TURN_ON_PERIPHERAL: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + return true; + } + + return false; +} + +/** + * mipi_dsi_packet_format_is_long - check if a packet is of the long format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a long packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_long(u8 type) +{ + switch (type) { + case MIPI_DSI_NULL_PACKET: + case MIPI_DSI_BLANKING_PACKET: + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_PICTURE_PARAMETER_SET: + case MIPI_DSI_COMPRESSED_PIXEL_STREAM: + case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: + case MIPI_DSI_PACKED_PIXEL_STREAM_30: + case MIPI_DSI_PACKED_PIXEL_STREAM_36: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: + case MIPI_DSI_PACKED_PIXEL_STREAM_16: + case MIPI_DSI_PACKED_PIXEL_STREAM_18: + case MIPI_DSI_PIXEL_STREAM_3BYTE_18: + case MIPI_DSI_PACKED_PIXEL_STREAM_24: + return true; + } + + return false; +} + +/** + * mipi_dsi_create_packet - create a packet from a message according to the + * DSI protocol + * @packet: pointer to a DSI packet structure + * @msg: message to translate into a packet + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg) +{ + if (!packet || !msg) + return -EINVAL; + + /* do some minimum sanity checking */ + if (!mipi_dsi_packet_format_is_short(msg->type) && + !mipi_dsi_packet_format_is_long(msg->type)) + return -EINVAL; + + if (msg->channel > 3) + return -EINVAL; + + memset(packet, 0, sizeof(*packet)); + packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); + if (mipi_dsi_packet_format_is_long(msg->type)) { + packet->header[1] = (msg->tx_len >> 0) & 0xff; + packet->header[2] = (msg->tx_len >> 8) & 0xff; + + packet->payload_length = msg->tx_len; + packet->payload = msg->tx_buf; + } else { + const u8 *tx = msg->tx_buf; + + packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; + packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; + } + + packet->size = sizeof(packet->header) + packet->payload_length; + + return 0; +} + +/** + * mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SHUTDOWN_PERIPHERAL, + .tx_buf = (u8 [2]) { 0, 0 }, + .tx_len = 2, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} + +/** + * mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_TURN_ON_PERIPHERAL, + .tx_buf = (u8 [2]) { 0, 0 }, + .tx_len = 2, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} + +/* + * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the + * the payload in a long packet transmitted from the peripheral back to the + * host processor + * @dsi: DSI peripheral device + * @value: the maximum size of the payload + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi, + u16 value) +{ + u8 tx[2] = { value & 0xff, value >> 8 }; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_len = sizeof(tx), + .tx_buf = tx, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} + +/** + * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral + * @dsi: DSI peripheral device + * @enable: Whether to enable or disable the DSC + * + * Enable or disable Display Stream Compression on the peripheral using the + * default Picture Parameter Set and VESA DSC 1.1 algorithm. + * + * Return: 0 on success or a negative error code on failure. + */ +ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) +{ + /* Note: Needs updating for non-default PPS or algorithm */ + u8 tx[2] = { enable << 0, 0 }; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_COMPRESSION_MODE, + .tx_len = sizeof(tx), + .tx_buf = tx, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} + +/** + * mipi_dsi_picture_parameter_set() - transmit the DSC PPS to the peripheral + * @dsi: DSI peripheral device + * @pps: VESA DSC 1.1 Picture Parameter Set + * + * Transmit the VESA DSC 1.1 Picture Parameter Set to the peripheral. + * + * Return: 0 on success or a negative error code on failure. + */ +ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, + const struct drm_dsc_picture_parameter_set *pps) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_PICTURE_PARAMETER_SET, + .tx_len = sizeof(*pps), + .tx_buf = pps, + }; + int ret = mipi_dsi_device_transfer(dsi, &msg); + + return (ret < 0) ? ret : 0; +} + +/** + * mipi_dsi_generic_write() - transmit data using a generic write packet + * @dsi: DSI peripheral device + * @payload: buffer containing the payload + * @size: size of payload buffer + * + * This function will automatically choose the right data type depending on + * the payload length. + * + * Return: The number of bytes transmitted on success or a negative error code + * on failure. + */ +ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, + size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = payload, + .tx_len = size + }; + + switch (size) { + case 0: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM; + break; + case 1: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM; + break; + case 2: + msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM; + break; + default: + msg.type = MIPI_DSI_GENERIC_LONG_WRITE; + break; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} + +/** + * mipi_dsi_generic_read() - receive data using a generic read packet + * @dsi: DSI peripheral device + * @params: buffer containing the request parameters + * @num_params: number of request parameters + * @data: buffer in which to return the received data + * @size: size of receive buffer + * + * This function will automatically choose the right data type depending on + * the number of parameters passed in. + * + * Return: The number of bytes successfully read or a negative error code on + * failure. + */ +ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, + size_t num_params, void *data, size_t size) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_len = num_params, + .tx_buf = params, + .rx_len = size, + .rx_buf = data + }; + + switch (num_params) { + case 0: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; + break; + + case 1: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; + break; + + case 2: + msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; + break; + + default: + return -EINVAL; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} + +/** + * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload + * @dsi: DSI peripheral device + * @data: buffer containing data to be transmitted + * @len: size of transmission buffer + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = data, + .tx_len = len + }; + + switch (len) { + case 0: + return -EINVAL; + + case 1: + msg.type = MIPI_DSI_DCS_SHORT_WRITE; + break; + + case 2: + msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + + default: + msg.type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + + return mipi_dsi_device_transfer(dsi, &msg); +} + +/** + * mipi_dsi_dcs_write() - send DCS write command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer containing the command payload + * @len: command payload length + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len) +{ + ssize_t err; + size_t size; + u8 *tx; + + if (len > 0) { + size = 1 + len; + + tx = malloc(size); + if (!tx) + return -ENOMEM; + + /* concatenate the DCS command byte and the payload */ + tx[0] = cmd; + memcpy(&tx[1], data, len); + } else { + tx = &cmd; + size = 1; + } + + err = mipi_dsi_dcs_write_buffer(dsi, tx, size); + + if (len > 0) + free(tx); + + return err; +} + +/** + * mipi_dsi_dcs_read() - send DCS read request command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer in which to receive data + * @len: size of receive buffer + * Return: The number of bytes read or a negative error code on failure. + */ +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, + size_t len) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_DCS_READ, + .tx_buf = &cmd, + .tx_len = 1, + .rx_buf = data, + .rx_len = len + }; + + return mipi_dsi_device_transfer(dsi, &msg); +} + +/** + * mipi_dsi_dcs_nop() - send DCS nop packet + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_soft_reset() - perform a software reset of the display module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_get_power_mode() - query the display module's current power + * mode + * @dsi: DSI peripheral device + * @mode: return location for the current power mode + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode, + sizeof(*mode)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} + +/** + * mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: return location for the pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format, + sizeof(*format)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} + +/** + * mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the + * display module except interface communication + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display + * module + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_display_off() - stop displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_display_on() - start displaying the image data on the + * display device + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_column_address() - define the column extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first column of frame memory + * @end: last column of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_page_address() - define the page extent of the frame + * memory accessed by the host processor + * @dsi: DSI peripheral device + * @start: first page of frame memory + * @end: last page of frame memory + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, + u16 end) +{ + u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload, + sizeof(payload)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect + * output signal on the TE signal line + * @dsi: DSI peripheral device + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect + * output signal on the TE signal line. + * @dsi: DSI peripheral device + * @mode: the Tearing Effect Output Line mode + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, + enum mipi_dsi_dcs_tear_mode mode) +{ + u8 value = mode; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value, + sizeof(value)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image + * data used by the interface + * @dsi: DSI peripheral device + * @format: pixel format + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format) +{ + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format, + sizeof(format)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for + * the Tearing Effect output signal of the display module + * @dsi: DSI peripheral device + * @scanline: scanline to use as trigger + * + * Return: 0 on success or a negative error code on failure + */ +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) +{ + u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8, + scanline & 0xff }; + ssize_t err; + + err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the + * display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, + u16 brightness) +{ + u8 payload[2] = { brightness & 0xff, brightness >> 8 }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} + +/** + * mipi_dsi_dcs_get_display_brightness() - gets the current brightness value + * of the display + * @dsi: DSI peripheral device + * @brightness: brightness value + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, + u16 *brightness) +{ + ssize_t err; + + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, + brightness, sizeof(*brightness)); + if (err <= 0) { + if (err == 0) + err = -ENODATA; + + return err; + } + + return 0; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.c new file mode 100644 index 0000000..e7bd89e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.c @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include "rockchip_phy.h" + +int rockchip_phy_init(struct rockchip_phy *phy) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->init) + return phy->funcs->init(phy); + + return 0; +} + +int rockchip_phy_power_on(struct rockchip_phy *phy) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->power_on) + return phy->funcs->power_on(phy); + + return 0; +} + +int rockchip_phy_power_off(struct rockchip_phy *phy) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->power_off) + return phy->funcs->power_off(phy); + + return 0; +} + +unsigned long rockchip_phy_set_pll(struct rockchip_phy *phy, + unsigned long rate) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->set_pll) + return phy->funcs->set_pll(phy, rate); + + return 0; +} + +int rockchip_phy_set_bus_width(struct rockchip_phy *phy, u32 bus_width) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->set_bus_width) + return phy->funcs->set_bus_width(phy, bus_width); + + return 0; +} + +long rockchip_phy_round_rate(struct rockchip_phy *phy, unsigned long rate) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->round_rate) + return phy->funcs->round_rate(phy, rate); + + return 0; +} + +int rockchip_phy_set_mode(struct rockchip_phy *phy, enum phy_mode mode) +{ + if (!phy) + return -ENODEV; + + if (phy->funcs && phy->funcs->set_mode) + return phy->funcs->set_mode(phy, mode); + + return 0; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.h new file mode 100644 index 0000000..865cdb4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/rockchip_phy.h @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ROCKCHIP_PHY_H_ +#define _ROCKCHIP_PHY_H_ + +enum phy_mode { + PHY_MODE_INVALID, + PHY_MODE_MIPI_DPHY, + PHY_MODE_VIDEO_LVDS, + PHY_MODE_VIDEO_TTL, +}; + +struct rockchip_phy; + +struct rockchip_phy_funcs { + int (*init)(struct rockchip_phy *phy); + int (*power_on)(struct rockchip_phy *phy); + int (*power_off)(struct rockchip_phy *phy); + unsigned long (*set_pll)(struct rockchip_phy *phy, unsigned long rate); + int (*set_bus_width)(struct rockchip_phy *phy, u32 bus_width); + long (*round_rate)(struct rockchip_phy *phy, unsigned long rate); + int (*set_mode)(struct rockchip_phy *phy, enum phy_mode mode); +}; + +struct rockchip_phy { + const struct rockchip_phy_funcs *funcs; +}; + +int rockchip_phy_init(struct rockchip_phy *phy); +int rockchip_phy_power_off(struct rockchip_phy *phy); +int rockchip_phy_power_on(struct rockchip_phy *phy); +unsigned long rockchip_phy_set_pll(struct rockchip_phy *phy, + unsigned long rate); +int rockchip_phy_set_bus_width(struct rockchip_phy *phy, u32 bus_width); +long rockchip_phy_round_rate(struct rockchip_phy *phy, unsigned long rate); +int rockchip_phy_set_mode(struct rockchip_phy *phy, enum phy_mode mode); + +struct rockchip_phy *rockchip_phy_by_id(unsigned int id); + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/samsung_mipi_dcphy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/samsung_mipi_dcphy.c new file mode 100644 index 0000000..bd088b4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DisplayLib/samsung_mipi_dcphy.c @@ -0,0 +1,1830 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2008-2018 Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Guochun Huang + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rockchip_phy.h" + +#define MAX_DPHY_BW 4500000L +#define MAX_CPHY_BW 2000000L + +#define MSEC_PER_SEC 1000L +#define USEC_PER_SEC 1000000LL +#define PSEC_PER_SEC 1000000000000LL + +#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) +#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) + +#define BIAS_CON0 0x0000 +#define BIAS_CON1 0x0004 +#define BIAS_CON2 0x0008 +#define BIAS_CON4 0x0010 +#define I_MUX_SEL_MASK GENMASK(6, 5) +#define I_MUX_SEL(x) UPDATE(x, 6, 5) + +#define PLL_CON0 0x0100 +#define PLL_EN BIT(12) +#define S_MASK GENMASK(10, 8) +#define S(x) UPDATE(x, 10, 8) +#define P_MASK GENMASK(5, 0) +#define P(x) UPDATE(x, 5, 0) +#define PLL_CON1 0x0104 +#define PLL_CON2 0x0108 +#define M_MASK GENMASK(9, 0) +#define M(x) UPDATE(x, 9, 0) +#define PLL_CON3 0x010c +#define MRR_MASK GENMASK(13, 8) +#define MRR(x) UPDATE(x, 13, 8) +#define MFR_MASK GENMASK(7, 0) +#define MFR(x) UPDATE(x, 7, 0) +#define PLL_CON4 0x0110 +#define SSCG_EN BIT(11) +#define PLL_CON5 0x0114 +#define RESET_N_SEL BIT(10) +#define PLL_ENABLE_SEL BIT(8) +#define PLL_CON6 0x0118 +#define PLL_CON7 0x011c +#define PLL_LOCK_CNT(x) UPDATE(x, 15, 0) +#define PLL_CON8 0x0120 +#define PLL_STB_CNT(x) UPDATE(x, 15, 0) +#define PLL_STAT0 0x0140 +#define PLL_LOCK BIT(0) + +#define DPHY_MC_GNR_CON0 0x0300 +#define PHY_READY BIT(1) +#define PHY_ENABLE BIT(0) +#define DPHY_MC_GNR_CON1 0x0304 +#define T_PHY_READY(x) UPDATE(x, 15, 0) +#define DPHY_MC_ANA_CON0 0x0308 +#define DPHY_MC_ANA_CON1 0x030c +#define DPHY_MC_ANA_CON2 0x0310 +#define HS_VREG_AMP_ICON(x) UPDATE(x, 1, 0) +#define DPHY_MC_TIME_CON0 0x0330 +#define HSTX_CLK_SEL BIT(12) +#define T_LPX(x) UPDATE(x, 11, 4) +#define DPHY_MC_TIME_CON1 0x0334 +#define T_CLK_ZERO(x) UPDATE(x, 15, 8) +#define T_CLK_PREPARE(x) UPDATE(x, 7, 0) +#define DPHY_MC_TIME_CON2 0x0338 +#define T_HS_EXIT(x) UPDATE(x, 15, 8) +#define T_CLK_TRAIL(x) UPDATE(x, 7, 0) +#define DPHY_MC_TIME_CON3 0x033c +#define T_CLK_POST(x) UPDATE(x, 7, 0) +#define DPHY_MC_TIME_CON4 0x0340 +#define T_ULPS_EXIT(x) UPDATE(x, 9, 0) +#define DPHY_MC_DESKEW_CON0 0x0350 +#define SKEW_CAL_RUN_TIME(x) UPDATE(x, 15, 12) + +#define SKEW_CAL_INIT_RUN_TIME(x) UPDATE(x, 11, 8) +#define SKEW_CAL_INIT_WAIT_TIME(x) UPDATE(x, 7, 4) +#define SKEW_CAL_EN BIT(0) + +#define COMBO_MD0_GNR_CON0 0x0400 +#define COMBO_MD0_GNR_CON1 0x0404 +#define COMBO_MD0_ANA_CON0 0x0408 +#define COMBO_MD0_ANA_CON1 0x040C +#define COMBO_MD0_ANA_CON2 0x0410 + +#define COMBO_MD0_TIME_CON0 0x0430 +#define COMBO_MD0_TIME_CON1 0x0434 +#define COMBO_MD0_TIME_CON2 0x0438 +#define COMBO_MD0_TIME_CON3 0x043C +#define COMBO_MD0_TIME_CON4 0x0440 +#define COMBO_MD0_DATA_CON0 0x0444 + +#define COMBO_MD1_GNR_CON0 0x0500 +#define COMBO_MD1_GNR_CON1 0x0504 +#define COMBO_MD1_ANA_CON0 0x0508 +#define COMBO_MD1_ANA_CON1 0x050c +#define COMBO_MD1_ANA_CON2 0x0510 +#define COMBO_MD1_TIME_CON0 0x0530 +#define COMBO_MD1_TIME_CON1 0x0534 +#define COMBO_MD1_TIME_CON2 0x0538 +#define COMBO_MD1_TIME_CON3 0x053C +#define COMBO_MD1_TIME_CON4 0x0540 +#define COMBO_MD1_DATA_CON0 0x0544 + +#define COMBO_MD2_GNR_CON0 0x0600 +#define COMBO_MD2_GNR_CON1 0x0604 +#define COMBO_MD2_ANA_CON0 0X0608 +#define COMBO_MD2_ANA_CON1 0X060C +#define COMBO_MD2_ANA_CON2 0X0610 +#define COMBO_MD2_TIME_CON0 0x0630 +#define COMBO_MD2_TIME_CON1 0x0634 +#define COMBO_MD2_TIME_CON2 0x0638 +#define COMBO_MD2_TIME_CON3 0x063C +#define COMBO_MD2_TIME_CON4 0x0640 +#define COMBO_MD2_DATA_CON0 0x0644 + +#define DPHY_MD3_GNR_CON0 0x0700 +#define DPHY_MD3_GNR_CON1 0x0704 +#define DPHY_MD3_ANA_CON0 0X0708 +#define DPHY_MD3_ANA_CON1 0X070C +#define DPHY_MD3_ANA_CON2 0X0710 +#define DPHY_MD3_TIME_CON0 0x0730 +#define DPHY_MD3_TIME_CON1 0x0734 +#define DPHY_MD3_TIME_CON2 0x0738 +#define DPHY_MD3_TIME_CON3 0x073C +#define DPHY_MD3_TIME_CON4 0x0740 +#define DPHY_MD3_DATA_CON0 0x0744 + +#define T_LP_EXIT_SKEW(x) UPDATE(x, 3, 2) +#define T_LP_ENTRY_SKEW(x) UPDATE(x, 1, 0) +#define T_HS_ZERO(x) UPDATE(x, 15, 8) +#define T_HS_PREPARE(x) UPDATE(x, 7, 0) +#define T_HS_EXIT(x) UPDATE(x, 15, 8) +#define T_HS_TRAIL(x) UPDATE(x, 7, 0) +#define T_TA_GET(x) UPDATE(x, 7, 4) +#define T_TA_GO(x) UPDATE(x, 3, 0) + +/* MIPI_CDPHY_GRF registers */ +#define MIPI_DCPHY_GRF_CON0 0x0000 +#define S_CPHY_MODE HIWORD_UPDATE(1, 3, 3) +#define M_CPHY_MODE HIWORD_UPDATE(1, 0, 0) + +struct samsung_mipi_dphy_timing { + unsigned int max_lane_mbps; + u8 clk_prepare; + u8 clk_zero; + u8 clk_post; + u8 clk_trail_eot; + u8 hs_prepare; + u8 hs_zero; + u8 hs_trail_eot; + u8 lpx; + u8 hs_exit; + u8 hs_settle; +}; + +struct samsung_mipi_cphy_timing { + unsigned int max_lane_msps; + u8 prepare_3; + u8 prebegin_3; + u8 post_3; + u8 lpx; + u8 hs_exit; + u8 settle_3; +}; + +struct samsung_mipi_dcphy { + UINT32 Signature; + struct rockchip_phy phy; + enum phy_mode mode; + UINTN base; + UINTN grf; + int id; + int lanes; + bool c_option; + struct reset_ctl m_phy_rst; + + struct { + unsigned long long rate; + u8 prediv; + u16 fbdiv; + long dsm; + u8 scaler; + + bool ssc_en; + u8 mfr; + u8 mrr; + } pll; +}; + +#define SAMSUNG_MIPI_DCPHY_SIGNATURE SIGNATURE_32 ('S', 'M', 'D', 'c') + +#define SAMSUNG_MIPI_DCPHY_FROM_PHY(a) \ + CR (a, struct samsung_mipi_dcphy, phy, SAMSUNG_MIPI_DCPHY_SIGNATURE) + +static const +struct samsung_mipi_dphy_timing samsung_mipi_dphy_timing_table[] = { + {6500, 32, 117, 31, 28, 30, 56, 27, 24, 44, 37}, + {6490, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, + {6480, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, + {6470, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, + {6460, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, + {6450, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37}, + {6440, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37}, + {6430, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37}, + {6420, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37}, + {6410, 31, 116, 31, 27, 30, 55, 27, 24, 44, 37}, + {6400, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, + {6390, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, + {6380, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, + {6370, 31, 115, 30, 27, 30, 55, 26, 23, 43, 36}, + {6360, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, + {6350, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, + {6340, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, + {6330, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, + {6320, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, + {6310, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, + {6300, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, + {6290, 31, 113, 30, 27, 29, 54, 26, 23, 43, 36}, + {6280, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, + {6270, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, + {6260, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, + {6250, 31, 112, 30, 27, 29, 54, 26, 23, 42, 36}, + {6240, 30, 113, 30, 27, 29, 54, 26, 23, 42, 36}, + {6230, 30, 112, 30, 27, 29, 54, 26, 23, 42, 35}, + {6220, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35}, + {6210, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35}, + {6200, 30, 112, 29, 27, 29, 53, 26, 23, 42, 35}, + {6190, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35}, + {6180, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35}, + {6170, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35}, + {6160, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35}, + {6150, 30, 110, 29, 26, 29, 53, 26, 23, 42, 35}, + {6140, 30, 110, 29, 26, 29, 52, 26, 23, 42, 35}, + {6130, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, + {6120, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, + {6110, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, + {6100, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35}, + {6090, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35}, + {6080, 30, 109, 29, 26, 28, 53, 25, 22, 41, 35}, + {6070, 30, 109, 29, 26, 28, 52, 25, 22, 41, 34}, + {6060, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34}, + {6050, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34}, + {6040, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34}, + {6030, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34}, + {6020, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34}, + {6010, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34}, + {6000, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34}, + {5990, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34}, + {5980, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34}, + {5970, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34}, + {5960, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34}, + {5950, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34}, + {5940, 29, 107, 28, 25, 28, 51, 25, 22, 40, 34}, + {5930, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, + {5920, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, + {5910, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, + {5900, 29, 106, 28, 25, 28, 50, 24, 22, 40, 33}, + {5890, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33}, + {5880, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33}, + {5870, 29, 105, 28, 25, 27, 51, 24, 22, 40, 33}, + {5860, 29, 105, 28, 25, 27, 51, 24, 21, 40, 33}, + {5850, 29, 104, 28, 25, 27, 50, 24, 21, 40, 33}, + {5840, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, + {5830, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, + {5820, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, + {5810, 28, 104, 28, 25, 27, 50, 24, 21, 39, 33}, + {5800, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33}, + {5790, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33}, + {5780, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33}, + {5770, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33}, + {5760, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, + {5750, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, + {5740, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, + {5730, 28, 103, 27, 25, 27, 49, 24, 21, 39, 32}, + {5720, 28, 102, 27, 25, 27, 49, 24, 21, 39, 32}, + {5710, 28, 102, 27, 25, 27, 48, 24, 21, 39, 32}, + {5700, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32}, + {5690, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32}, + {5680, 28, 101, 27, 24, 27, 48, 24, 21, 39, 32}, + {5670, 28, 101, 27, 24, 27, 48, 23, 21, 38, 32}, + {5660, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32}, + {5650, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32}, + {5640, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, + {5630, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, + {5620, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, + {5610, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, + {5600, 27, 101, 26, 24, 26, 48, 23, 20, 38, 32}, + {5590, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32}, + {5580, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32}, + {5570, 27, 100, 26, 24, 26, 48, 23, 20, 38, 31}, + {5560, 27, 100, 26, 24, 26, 47, 23, 20, 38, 31}, + {5550, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, + {5540, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, + {5530, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, + {5520, 27, 99, 26, 24, 26, 47, 23, 20, 37, 31}, + {5510, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31}, + {5500, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31}, + {5490, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31}, + {5480, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31}, + {5470, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31}, + {5460, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31}, + {5450, 27, 97, 26, 23, 25, 47, 23, 20, 37, 31}, + {5440, 26, 98, 26, 23, 25, 47, 23, 20, 37, 31}, + {5430, 26, 98, 26, 23, 25, 47, 22, 20, 37, 31}, + {5420, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31}, + {5410, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31}, + {5400, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30}, + {5390, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30}, + {5380, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, + {5370, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, + {5360, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, + {5350, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, + {5340, 26, 95, 25, 23, 25, 45, 22, 20, 36, 30}, + {5330, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, + {5320, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, + {5310, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, + {5300, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, + {5290, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30}, + {5280, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30}, + {5270, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30}, + {5260, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30}, + {5250, 25, 94, 25, 23, 24, 45, 22, 19, 36, 30}, + {5240, 25, 94, 25, 23, 24, 45, 22, 19, 36, 29}, + {5230, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29}, + {5220, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29}, + {5210, 25, 93, 25, 22, 24, 45, 22, 19, 35, 29}, + {5200, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, + {5190, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, + {5180, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, + {5170, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, + {5160, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, + {5150, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, + {5140, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, + {5130, 25, 92, 24, 22, 24, 43, 21, 19, 35, 29}, + {5120, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, + {5110, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, + {5100, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, + {5090, 25, 91, 24, 22, 24, 43, 21, 19, 34, 29}, + {5080, 25, 90, 24, 22, 24, 43, 21, 19, 34, 29}, + {5070, 25, 90, 24, 22, 24, 43, 21, 19, 34, 28}, + {5060, 25, 90, 24, 22, 24, 43, 21, 18, 34, 28}, + {5050, 24, 91, 24, 22, 24, 42, 21, 18, 34, 28}, + {5040, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, + {5030, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, + {5020, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, + {5010, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, + {5000, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28}, + {4990, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28}, + {4980, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28}, + {4970, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28}, + {4960, 24, 89, 23, 21, 23, 42, 20, 18, 34, 28}, + {4950, 24, 88, 23, 21, 23, 42, 20, 18, 34, 28}, + {4940, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, + {4930, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, + {4920, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, + {4910, 24, 87, 23, 21, 23, 41, 20, 18, 33, 28}, + {4900, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, + {4890, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, + {4880, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, + {4870, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27}, + {4860, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27}, + {4850, 23, 87, 23, 21, 23, 41, 20, 18, 33, 27}, + {4840, 23, 87, 23, 21, 23, 40, 20, 18, 33, 27}, + {4830, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, + {4820, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, + {4810, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, + {4800, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27}, + {4790, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27}, + {4780, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27}, + {4770, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27}, + {4760, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27}, + {4750, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27}, + {4740, 23, 84, 22, 20, 22, 40, 20, 17, 32, 26}, + {4730, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, + {4720, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, + {4710, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, + {4700, 23, 83, 22, 20, 22, 40, 19, 17, 32, 26}, + {4690, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, + {4680, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, + {4670, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, + {4660, 23, 82, 22, 20, 22, 39, 19, 17, 32, 26}, + {4650, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, + {4640, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, + {4630, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, + {4620, 22, 83, 22, 20, 21, 39, 19, 17, 31, 26}, + {4610, 22, 82, 22, 20, 21, 39, 19, 17, 31, 26}, + {4600, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, + {4590, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, + {4580, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, + {4570, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25}, + {4560, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25}, + {4550, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25}, + {4540, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25}, + {4530, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, + {4520, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, + {4510, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, + {4500, 22, 80, 21, 19, 21, 38, 19, 16, 30, 25}, + {4490, 22, 80, 21, 19, 21, 38, 18, 16, 30, 25}, + {4480, 22, 79, 21, 19, 21, 38, 18, 16, 30, 25}, + {4470, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25}, + {4460, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25}, + {4450, 21, 80, 21, 19, 21, 37, 18, 16, 30, 25}, + {4440, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, + {4430, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, + {4420, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, + {4410, 21, 79, 21, 19, 20, 38, 18, 16, 30, 25}, + {4400, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, + {4390, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, + {4380, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, + {4370, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, + {4360, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, + {4350, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, + {4340, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, + {4330, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24}, + {4320, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24}, + {4310, 21, 76, 20, 19, 20, 36, 18, 16, 29, 24}, + {4300, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, + {4290, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, + {4280, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, + {4270, 21, 75, 20, 18, 20, 36, 18, 16, 29, 24}, + {4260, 21, 75, 20, 18, 20, 35, 17, 15, 29, 24}, + {4250, 20, 76, 20, 18, 20, 35, 17, 15, 29, 24}, + {4240, 20, 76, 20, 18, 20, 35, 17, 15, 29, 23}, + {4230, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23}, + {4220, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23}, + {4210, 20, 75, 20, 18, 20, 35, 17, 15, 28, 23}, + {4200, 20, 75, 19, 18, 19, 36, 17, 15, 28, 23}, + {4190, 20, 74, 19, 18, 19, 36, 17, 15, 28, 23}, + {4180, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, + {4170, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, + {4160, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, + {4150, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, + {4140, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, + {4130, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, + {4120, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, + {4110, 20, 73, 19, 18, 19, 34, 17, 15, 28, 23}, + {4100, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, + {4090, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, + {4080, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, + {4070, 20, 72, 19, 18, 19, 34, 17, 15, 27, 22}, + {4060, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22}, + {4050, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22}, + {4040, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22}, + {4030, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22}, + {4020, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22}, + {4010, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22}, + {4000, 19, 71, 18, 17, 19, 33, 16, 14, 27, 22}, + {3990, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22}, + {3980, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22}, + {3970, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, + {3960, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, + {3950, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, + {3940, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, + {3930, 19, 69, 18, 17, 18, 33, 16, 14, 27, 22}, + {3920, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22}, + {3910, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22}, + {3900, 19, 69, 18, 17, 18, 33, 16, 14, 26, 21}, + {3890, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, + {3880, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, + {3870, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, + {3860, 18, 69, 18, 17, 18, 32, 16, 14, 26, 21}, + {3850, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21}, + {3840, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21}, + {3830, 18, 68, 18, 16, 18, 32, 16, 14, 26, 21}, + {3820, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21}, + {3810, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21}, + {3800, 18, 67, 17, 16, 18, 31, 16, 14, 26, 21}, + {3790, 18, 67, 17, 16, 17, 32, 15, 14, 26, 21}, + {3780, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21}, + {3770, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21}, + {3760, 18, 66, 17, 16, 17, 32, 15, 14, 25, 21}, + {3750, 18, 66, 17, 16, 17, 31, 15, 14, 25, 21}, + {3740, 18, 66, 17, 16, 17, 31, 15, 14, 25, 20}, + {3730, 18, 66, 17, 16, 17, 31, 15, 13, 25, 20}, + {3720, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, + {3710, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, + {3700, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, + {3690, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, + {3680, 18, 64, 17, 16, 17, 31, 15, 13, 25, 20}, + {3670, 18, 64, 17, 16, 17, 30, 15, 13, 25, 20}, + {3660, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, + {3650, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, + {3640, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, + {3630, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, + {3620, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, + {3610, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, + {3600, 17, 64, 16, 16, 17, 29, 15, 13, 24, 20}, + {3590, 17, 63, 16, 15, 17, 29, 15, 13, 24, 20}, + {3580, 17, 63, 16, 15, 16, 30, 15, 13, 24, 20}, + {3570, 17, 63, 16, 15, 16, 30, 15, 13, 24, 19}, + {3560, 17, 63, 16, 15, 16, 30, 14, 13, 24, 19}, + {3550, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19}, + {3540, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19}, + {3530, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, + {3520, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, + {3510, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, + {3500, 17, 61, 16, 15, 16, 29, 14, 13, 24, 19}, + {3490, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, + {3480, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, + {3470, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, + {3460, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, + {3450, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, + {3440, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, + {3430, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, + {3420, 16, 60, 16, 15, 16, 28, 14, 12, 23, 19}, + {3410, 16, 60, 16, 15, 16, 28, 14, 12, 23, 18}, + {3400, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18}, + {3390, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18}, + {3380, 16, 59, 15, 15, 16, 27, 14, 12, 23, 18}, + {3370, 16, 59, 15, 15, 15, 28, 14, 12, 23, 18}, + {3360, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18}, + {3350, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18}, + {3340, 16, 59, 15, 14, 15, 28, 14, 12, 22, 18}, + {3330, 16, 58, 15, 14, 15, 28, 14, 12, 22, 18}, + {3320, 16, 58, 15, 14, 15, 28, 13, 12, 22, 18}, + {3310, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18}, + {3300, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18}, + {3290, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, + {3280, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, + {3270, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, + {3260, 15, 58, 15, 14, 15, 27, 13, 12, 22, 18}, + {3250, 15, 57, 15, 14, 15, 27, 13, 12, 22, 18}, + {3240, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, + {3230, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, + {3220, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, + {3210, 15, 56, 15, 14, 15, 26, 13, 12, 22, 17}, + {3200, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, + {3190, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, + {3180, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, + {3170, 15, 56, 14, 14, 15, 25, 13, 11, 21, 17}, + {3160, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, + {3150, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, + {3140, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, + {3130, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, + {3120, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, + {3110, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, + {3100, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, + {3090, 15, 54, 14, 13, 14, 25, 12, 11, 21, 17}, + {3080, 15, 53, 14, 13, 14, 25, 12, 11, 21, 17}, + {3070, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16}, + {3060, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16}, + {3050, 14, 54, 14, 13, 14, 25, 12, 11, 20, 16}, + {3040, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16}, + {3030, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16}, + {3020, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16}, + {3010, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16}, + {3000, 14, 53, 13, 13, 14, 24, 12, 11, 20, 16}, + {2990, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, + {2980, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, + {2970, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, + {2960, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, + {2950, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16}, + {2940, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16}, + {2930, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16}, + {2920, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16}, + {2910, 14, 50, 13, 13, 13, 24, 12, 10, 20, 15}, + {2900, 14, 50, 13, 13, 13, 24, 12, 10, 19, 15}, + {2890, 14, 50, 13, 12, 13, 24, 12, 10, 19, 15}, + {2880, 14, 50, 13, 12, 13, 23, 12, 10, 19, 15}, + {2870, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15}, + {2860, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15}, + {2850, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, + {2840, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, + {2830, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, + {2820, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15}, + {2810, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15}, + {2800, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15}, + {2790, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15}, + {2780, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15}, + {2770, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15}, + {2760, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15}, + {2750, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15}, + {2740, 13, 47, 12, 12, 12, 23, 11, 10, 18, 14}, + {2730, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, + {2720, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, + {2710, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, + {2700, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, + {2690, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14}, + {2680, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14}, + {2670, 12, 47, 12, 12, 12, 22, 11, 10, 18, 14}, + {2660, 12, 47, 12, 12, 12, 21, 11, 9, 18, 14}, + {2650, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, + {2640, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, + {2630, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, + {2620, 12, 46, 12, 11, 12, 21, 10, 9, 18, 14}, + {2610, 12, 45, 12, 11, 12, 21, 10, 9, 17, 14}, + {2600, 12, 45, 11, 11, 12, 21, 10, 9, 17, 14}, + {2590, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14}, + {2580, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14}, + {2570, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, + {2560, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, + {2550, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, + {2540, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13}, + {2530, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13}, + {2520, 12, 43, 11, 11, 11, 21, 10, 9, 17, 13}, + {2510, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, + {2500, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, + {2490, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, + {2480, 12, 42, 11, 11, 11, 20, 10, 9, 17, 13}, + {2470, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, + {2460, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, + {2450, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, + {2440, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13}, + {2430, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13}, + {2420, 11, 42, 11, 10, 11, 19, 10, 9, 16, 13}, + {2410, 11, 42, 11, 10, 11, 19, 10, 9, 16, 12}, + {2400, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12}, + {2390, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12}, + {2380, 11, 41, 10, 10, 11, 19, 9, 8, 16, 12}, + {2370, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12}, + {2360, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12}, + {2350, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12}, + {2340, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12}, + {2330, 11, 40, 10, 10, 10, 19, 9, 8, 16, 12}, + {2320, 11, 40, 10, 10, 10, 19, 9, 8, 15, 12}, + {2310, 11, 39, 10, 10, 10, 19, 9, 8, 15, 12}, + {2300, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2290, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2280, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2270, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2260, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2250, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, + {2240, 10, 39, 10, 10, 10, 18, 9, 8, 15, 11}, + {2230, 10, 38, 10, 10, 10, 18, 9, 8, 15, 11}, + {2220, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11}, + {2210, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11}, + {2200, 10, 38, 9, 10, 10, 17, 9, 8, 15, 11}, + {2190, 10, 38, 9, 9, 10, 17, 9, 8, 15, 11}, + {2180, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, + {2170, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, + {2160, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, + {2150, 10, 37, 9, 9, 10, 16, 8, 8, 14, 11}, + {2140, 10, 36, 9, 9, 10, 16, 8, 8, 14, 11}, + {2130, 10, 36, 9, 9, 10, 16, 8, 7, 14, 11}, + {2120, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11}, + {2110, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11}, + {2100, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11}, + {2090, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11}, + {2080, 9, 36, 9, 9, 9, 16, 8, 7, 14, 11}, + {2070, 9, 36, 9, 9, 9, 16, 8, 7, 14, 10}, + {2060, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, + {2050, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, + {2040, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, + {2030, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10}, + {2020, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10}, + {2010, 9, 34, 9, 9, 9, 15, 8, 7, 13, 10}, + {2000, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, + {1990, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, + {1980, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, + {1970, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10}, + {1960, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10}, + {1950, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10}, + {1940, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10}, + {1930, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10}, + {1920, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10}, + {1910, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9}, + {1900, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9}, + {1890, 9, 31, 8, 8, 8, 15, 7, 7, 12, 9}, + {1880, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9}, + {1870, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9}, + {1860, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9}, + {1850, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9}, + {1840, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, + {1830, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, + {1820, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, + {1810, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, + {1800, 8, 30, 7, 8, 8, 14, 7, 6, 12, 9}, + {1790, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, + {1780, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, + {1770, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, + {1760, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9}, + {1750, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9}, + {1740, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8}, + {1730, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8}, + {1720, 8, 29, 7, 7, 8, 13, 7, 6, 11, 8}, + {1710, 8, 28, 7, 7, 8, 12, 7, 6, 11, 8}, + {1700, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8}, + {1690, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8}, + {1680, 7, 29, 7, 7, 7, 13, 6, 6, 11, 8}, + {1670, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, + {1660, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, + {1650, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, + {1640, 7, 28, 7, 7, 7, 12, 6, 6, 11, 8}, + {1630, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, + {1620, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, + {1610, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, + {1600, 7, 27, 6, 7, 7, 12, 6, 5, 10, 8}, + {1590, 7, 26, 6, 7, 7, 12, 6, 5, 10, 8}, + {1580, 7, 26, 6, 7, 7, 12, 6, 5, 10, 7}, + {1570, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, + {1560, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, + {1550, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, + {1540, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, + {1530, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, + {1520, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, + {1510, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, + {1500, 7, 24, 6, 7, 7, 10, 6, 5, 10, 7}, + {1490, 59, 25, 6, 77, 59, 10, 70, 44, 9, 73}, + {1480, 59, 24, 6, 76, 58, 10, 70, 44, 9, 73}, + {1470, 58, 24, 6, 76, 58, 10, 69, 44, 9, 72}, + {1460, 58, 24, 6, 76, 58, 10, 69, 43, 9, 72}, + {1450, 58, 24, 6, 75, 57, 10, 68, 43, 9, 71}, + {1440, 57, 24, 6, 75, 57, 10, 68, 43, 9, 71}, + {1430, 57, 23, 6, 75, 57, 10, 68, 43, 8, 70}, + {1420, 56, 23, 6, 74, 57, 9, 67, 43, 8, 70}, + {1410, 56, 23, 6, 74, 57, 9, 67, 43, 8, 69}, + {1400, 56, 23, 5, 74, 55, 9, 67, 41, 8, 69}, + {1390, 55, 23, 5, 73, 55, 9, 66, 41, 8, 68}, + {1380, 55, 23, 5, 73, 54, 9, 66, 41, 8, 68}, + {1370, 54, 22, 5, 72, 54, 9, 66, 41, 8, 67}, + {1360, 54, 22, 5, 72, 54, 9, 65, 40, 8, 67}, + {1350, 54, 22, 5, 72, 53, 9, 65, 40, 8, 66}, + {1340, 53, 22, 5, 71, 53, 9, 65, 40, 8, 66}, + {1330, 53, 22, 5, 71, 53, 9, 64, 39, 8, 65}, + {1320, 52, 22, 5, 71, 53, 8, 64, 40, 8, 65}, + {1310, 52, 21, 5, 70, 53, 8, 64, 40, 8, 64}, + {1300, 51, 21, 5, 70, 51, 8, 63, 38, 8, 64}, + {1290, 51, 21, 5, 70, 51, 8, 63, 38, 7, 64}, + {1280, 51, 21, 5, 69, 51, 8, 63, 38, 7, 63}, + {1270, 50, 21, 5, 69, 50, 8, 62, 38, 7, 63}, + {1260, 50, 20, 5, 69, 50, 8, 62, 37, 7, 62}, + {1250, 49, 20, 5, 68, 49, 8, 62, 37, 7, 62}, + {1240, 49, 20, 5, 68, 49, 8, 61, 37, 7, 61}, + {1230, 49, 20, 5, 68, 49, 8, 61, 36, 7, 61}, + {1220, 48, 20, 5, 67, 48, 8, 61, 36, 7, 60}, + {1210, 48, 19, 5, 67, 48, 7, 60, 36, 7, 60}, + {1200, 49, 19, 4, 67, 49, 7, 60, 36, 7, 59}, + {1190, 48, 19, 4, 66, 48, 7, 60, 36, 7, 59}, + {1180, 48, 19, 4, 66, 48, 7, 59, 36, 7, 58}, + {1170, 46, 19, 4, 66, 46, 7, 59, 35, 7, 58}, + {1160, 46, 18, 4, 65, 46, 7, 59, 34, 7, 57}, + {1150, 45, 18, 4, 65, 46, 7, 58, 34, 7, 57}, + {1140, 45, 18, 4, 65, 45, 7, 58, 34, 6, 56}, + {1130, 45, 18, 4, 64, 45, 7, 58, 33, 6, 56}, + {1120, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55}, + {1110, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55}, + {1100, 43, 17, 4, 63, 44, 6, 57, 32, 6, 54}, + {1090, 43, 17, 4, 63, 44, 6, 56, 33, 6, 54}, + {1080, 43, 17, 4, 63, 44, 6, 56, 33, 6, 53}, + {1070, 42, 17, 4, 62, 44, 6, 56, 33, 6, 53}, + {1060, 42, 17, 4, 62, 42, 6, 55, 31, 6, 52}, + {1050, 41, 17, 4, 62, 42, 6, 55, 31, 6, 52}, + {1040, 41, 16, 4, 61, 41, 6, 54, 31, 6, 52}, + {1030, 41, 16, 4, 61, 41, 6, 54, 30, 6, 51}, + {1020, 40, 16, 4, 61, 41, 6, 54, 30, 6, 51}, + {1010, 40, 16, 4, 60, 40, 6, 53, 30, 6, 50}, + {1000, 39, 16, 3, 60, 40, 6, 53, 29, 5, 50}, + { 990, 39, 15, 3, 60, 39, 6, 53, 29, 5, 49}, + { 980, 39, 15, 3, 59, 39, 5, 52, 29, 5, 49}, + { 970, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48}, + { 960, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48}, + { 950, 37, 15, 3, 58, 39, 5, 51, 29, 5, 47}, + { 940, 37, 14, 3, 58, 39, 5, 51, 29, 5, 47}, + { 930, 37, 14, 3, 57, 37, 5, 51, 27, 5, 46}, + { 920, 36, 14, 3, 57, 37, 5, 50, 27, 5, 46}, + { 910, 36, 14, 3, 57, 36, 5, 50, 27, 5, 45}, + { 900, 35, 14, 3, 56, 36, 5, 50, 26, 5, 45}, + { 890, 35, 14, 3, 56, 36, 5, 49, 26, 5, 44}, + { 880, 35, 13, 3, 56, 35, 5, 49, 26, 5, 44}, + { 870, 34, 13, 3, 55, 35, 4, 49, 26, 5, 43}, + { 860, 34, 13, 3, 55, 35, 4, 48, 25, 5, 43}, + { 850, 33, 13, 3, 55, 35, 4, 48, 26, 4, 42}, + { 840, 33, 13, 3, 54, 35, 4, 48, 26, 4, 42}, + { 830, 33, 12, 3, 54, 33, 4, 47, 24, 4, 41}, + { 820, 32, 12, 3, 54, 33, 4, 47, 24, 4, 41}, + { 810, 32, 12, 3, 53, 33, 4, 47, 24, 4, 40}, + { 800, 31, 12, 2, 53, 32, 4, 46, 23, 4, 40}, + { 790, 31, 12, 2, 53, 32, 4, 46, 23, 4, 39}, + { 780, 30, 12, 2, 52, 31, 4, 46, 23, 4, 39}, + { 770, 30, 11, 2, 52, 31, 4, 45, 23, 4, 39}, + { 760, 30, 11, 2, 52, 31, 3, 45, 22, 4, 38}, + { 750, 29, 11, 2, 51, 30, 3, 45, 22, 4, 38}, + { 740, 29, 11, 2, 51, 30, 3, 44, 22, 4, 37}, + { 730, 28, 11, 2, 51, 31, 3, 44, 22, 4, 37}, + { 720, 28, 10, 2, 50, 30, 3, 44, 22, 4, 36}, + { 710, 28, 10, 2, 50, 30, 3, 43, 22, 4, 36}, + { 700, 27, 10, 2, 50, 28, 3, 43, 20, 3, 35}, + { 690, 27, 10, 2, 49, 28, 3, 43, 20, 3, 35}, + { 680, 26, 10, 2, 49, 28, 3, 42, 20, 3, 34}, + { 670, 26, 10, 2, 49, 27, 3, 42, 20, 3, 34}, + { 660, 26, 9, 2, 48, 27, 3, 42, 19, 3, 33}, + { 650, 25, 9, 2, 48, 26, 3, 41, 19, 3, 33}, + { 640, 25, 9, 2, 48, 26, 2, 41, 19, 3, 32}, + { 630, 24, 9, 2, 47, 26, 2, 40, 18, 3, 32}, + { 620, 24, 9, 2, 47, 26, 2, 40, 19, 3, 31}, + { 610, 24, 8, 2, 47, 26, 2, 40, 19, 3, 31}, + { 600, 23, 8, 1, 46, 26, 2, 39, 18, 3, 30}, + { 590, 23, 8, 1, 46, 24, 2, 39, 17, 3, 30}, + { 580, 22, 8, 1, 46, 24, 2, 39, 17, 3, 29}, + { 570, 22, 8, 1, 45, 23, 2, 38, 17, 3, 29}, + { 560, 22, 7, 1, 45, 23, 2, 38, 16, 2, 28}, + { 550, 21, 7, 1, 45, 23, 2, 38, 16, 2, 28}, + { 540, 21, 7, 1, 44, 22, 2, 37, 16, 2, 27}, + { 530, 20, 7, 1, 44, 22, 1, 37, 15, 2, 27}, + { 520, 20, 7, 1, 43, 21, 1, 37, 15, 2, 27}, + { 510, 20, 6, 1, 43, 21, 1, 36, 15, 2, 26}, + { 500, 19, 6, 1, 43, 22, 1, 36, 15, 2, 26}, + { 490, 19, 6, 1, 42, 21, 1, 36, 15, 2, 25}, + { 480, 18, 6, 1, 42, 21, 1, 35, 15, 2, 25}, + { 470, 18, 6, 1, 42, 21, 1, 35, 15, 2, 24}, + { 460, 18, 6, 1, 41, 19, 1, 35, 13, 2, 24}, + { 450, 17, 5, 1, 41, 19, 1, 34, 13, 2, 23}, + { 440, 17, 5, 1, 41, 18, 1, 34, 13, 2, 23}, + { 430, 16, 5, 1, 40, 18, 0, 34, 12, 2, 22}, + { 420, 16, 5, 1, 40, 18, 0, 33, 12, 2, 22}, + { 410, 16, 5, 1, 40, 17, 0, 33, 12, 1, 21}, + { 400, 15, 5, 0, 39, 17, 0, 33, 11, 1, 21}, + { 390, 15, 4, 0, 39, 17, 0, 32, 12, 1, 20}, + { 380, 14, 4, 0, 39, 17, 0, 32, 12, 1, 20}, + { 370, 14, 4, 0, 38, 17, 0, 32, 12, 1, 19}, + { 360, 14, 4, 0, 38, 15, 0, 31, 10, 1, 19}, + { 350, 13, 4, 0, 38, 15, 0, 31, 10, 1, 18}, + { 340, 13, 3, 0, 37, 15, 0, 31, 10, 1, 18}, + { 330, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17}, + { 320, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17}, + { 310, 12, 3, 0, 36, 13, 0, 30, 9, 1, 16}, + { 300, 11, 3, 0, 36, 13, 0, 29, 8, 1, 16}, + { 290, 11, 2, 0, 36, 13, 0, 29, 8, 1, 15}, + { 280, 10, 2, 0, 35, 12, 0, 29, 8, 1, 15}, + { 270, 10, 2, 0, 35, 12, 0, 28, 8, 0, 14}, + { 260, 9, 2, 0, 35, 12, 0, 28, 8, 0, 14}, + { 250, 9, 2, 0, 34, 12, 0, 28, 8, 0, 14}, + { 240, 9, 2, 0, 34, 12, 0, 27, 8, 0, 13}, + { 230, 8, 1, 0, 34, 10, 0, 27, 6, 0, 13}, + { 220, 8, 1, 0, 33, 10, 0, 27, 6, 0, 12}, + { 210, 7, 1, 0, 33, 10, 0, 26, 6, 0, 12}, + { 200, 7, 1, 0, 33, 9, 0, 26, 5, 0, 11}, + { 190, 7, 1, 0, 32, 9, 0, 25, 5, 0, 11}, + { 180, 6, 1, 0, 32, 8, 0, 25, 5, 0, 10}, + { 170, 6, 0, 0, 32, 8, 0, 25, 5, 0, 10}, + { 160, 5, 0, 0, 31, 8, 0, 24, 4, 0, 9}, + { 150, 5, 0, 0, 31, 8, 0, 24, 5, 0, 9}, + { 140, 5, 0, 0, 31, 8, 0, 24, 5, 0, 8}, + { 130, 4, 0, 0, 30, 6, 0, 23, 3, 0, 8}, + { 120, 4, 0, 0, 30, 6, 0, 23, 3, 0, 7}, + { 110, 3, 0, 0, 30, 6, 0, 23, 3, 0, 7}, + { 100, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6}, + { 90, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6}, + { 80, 2, 0, 0, 28, 5, 0, 22, 2, 0, 5}, +}; + +static const +struct samsung_mipi_cphy_timing samsung_mipi_cphy_timing_table[] = { + { 3500, 39, 50, 25, 29, 54, 1 }, + { 3490, 39, 50, 25, 29, 54, 1 }, + { 3480, 39, 50, 25, 29, 54, 1 }, + { 3470, 39, 50, 25, 29, 54, 1 }, + { 3460, 39, 50, 25, 29, 54, 1 }, + { 3450, 39, 50, 25, 29, 54, 1 }, + { 3440, 38, 50, 25, 29, 54, 1 }, + { 3430, 38, 50, 25, 29, 53, 1 }, + { 3420, 38, 50, 25, 29, 53, 1 }, + { 3410, 38, 50, 25, 29, 53, 1 }, + { 3400, 38, 50, 25, 29, 53, 1 }, + { 3390, 38, 50, 25, 29, 53, 1 }, + { 3380, 38, 50, 25, 28, 53, 1 }, + { 3370, 38, 50, 25, 28, 52, 1 }, + { 3360, 37, 50, 25, 28, 52, 1 }, + { 3350, 37, 50, 25, 28, 52, 1 }, + { 3340, 37, 50, 25, 28, 52, 1 }, + { 3330, 37, 50, 25, 28, 52, 1 }, + { 3320, 37, 50, 25, 28, 52, 1 }, + { 3310, 37, 50, 25, 28, 52, 1 }, + { 3300, 37, 50, 25, 28, 51, 1 }, + { 3290, 37, 50, 25, 28, 51, 1 }, + { 3280, 37, 50, 25, 28, 51, 1 }, + { 3270, 36, 50, 25, 28, 51, 1 }, + { 3260, 36, 50, 25, 27, 51, 1 }, + { 3250, 36, 50, 25, 27, 51, 1 }, + { 3240, 36, 50, 25, 27, 50, 1 }, + { 3230, 36, 50, 25, 27, 50, 1 }, + { 3220, 36, 50, 25, 27, 50, 1 }, + { 3210, 36, 50, 25, 27, 50, 1 }, + { 3200, 36, 50, 25, 27, 50, 1 }, + { 3190, 36, 50, 25, 27, 50, 1 }, + { 3180, 35, 50, 25, 27, 49, 1 }, + { 3170, 35, 50, 25, 27, 49, 1 }, + { 3160, 35, 50, 25, 27, 49, 1 }, + { 3150, 35, 50, 25, 26, 49, 1 }, + { 3140, 35, 50, 25, 26, 49, 1 }, + { 3130, 35, 50, 25, 26, 49, 1 }, + { 3120, 35, 50, 25, 26, 49, 1 }, + { 3110, 35, 50, 25, 26, 48, 1 }, + { 3100, 34, 50, 25, 26, 48, 1 }, + { 3090, 34, 50, 25, 26, 48, 1 }, + { 3080, 34, 50, 25, 26, 48, 1 }, + { 3070, 34, 50, 25, 26, 48, 1 }, + { 3060, 34, 50, 25, 26, 48, 1 }, + { 3050, 34, 50, 25, 26, 47, 1 }, + { 3040, 34, 50, 25, 26, 47, 1 }, + { 3030, 34, 50, 25, 25, 47, 1 }, + { 3020, 34, 50, 25, 25, 47, 1 }, + { 3010, 33, 50, 25, 25, 47, 1 }, + { 3000, 33, 50, 25, 25, 47, 1 }, + { 2990, 33, 50, 25, 25, 46, 1 }, + { 2980, 33, 50, 25, 25, 46, 1 }, + { 2970, 33, 50, 25, 25, 46, 1 }, + { 2960, 33, 50, 25, 25, 46, 1 }, + { 2950, 33, 50, 25, 25, 46, 1 }, + { 2940, 33, 50, 25, 25, 46, 1 }, + { 2930, 33, 50, 25, 25, 46, 1 }, + { 2920, 32, 50, 25, 25, 45, 1 }, + { 2910, 32, 50, 25, 24, 45, 1 }, + { 2900, 32, 50, 25, 24, 45, 1 }, + { 2890, 32, 50, 25, 24, 45, 1 }, + { 2880, 32, 50, 25, 24, 45, 1 }, + { 2870, 32, 50, 25, 24, 45, 1 }, + { 2860, 32, 50, 25, 24, 44, 1 }, + { 2850, 32, 50, 25, 24, 44, 1 }, + { 2840, 31, 50, 25, 24, 44, 1 }, + { 2830, 31, 50, 25, 24, 44, 1 }, + { 2820, 31, 50, 25, 24, 44, 1 }, + { 2810, 31, 50, 25, 24, 44, 1 }, + { 2800, 31, 50, 25, 23, 43, 1 }, + { 2790, 31, 50, 25, 23, 43, 1 }, + { 2780, 31, 50, 25, 23, 43, 1 }, + { 2770, 31, 50, 25, 23, 43, 1 }, + { 2760, 31, 50, 25, 23, 43, 1 }, + { 2750, 30, 50, 25, 23, 43, 1 }, + { 2740, 30, 50, 25, 23, 43, 1 }, + { 2730, 30, 50, 25, 23, 42, 1 }, + { 2720, 30, 50, 25, 23, 42, 1 }, + { 2710, 30, 50, 25, 23, 42, 1 }, + { 2700, 30, 50, 25, 23, 42, 1 }, + { 2690, 30, 50, 25, 23, 42, 1 }, + { 2680, 30, 50, 25, 22, 42, 1 }, + { 2670, 30, 50, 25, 22, 41, 1 }, + { 2660, 29, 50, 25, 22, 41, 1 }, + { 2650, 29, 50, 25, 22, 41, 1 }, + { 2640, 29, 50, 25, 22, 41, 1 }, + { 2630, 29, 50, 25, 22, 41, 1 }, + { 2620, 29, 50, 25, 22, 41, 1 }, + { 2610, 29, 50, 25, 22, 41, 1 }, + { 2600, 29, 50, 25, 22, 40, 1 }, + { 2590, 29, 50, 25, 22, 40, 1 }, + { 2580, 28, 50, 25, 22, 40, 1 }, + { 2570, 28, 50, 25, 22, 40, 1 }, + { 2560, 28, 50, 25, 21, 40, 1 }, + { 2550, 28, 50, 25, 21, 40, 1 }, + { 2540, 28, 50, 25, 21, 39, 1 }, + { 2530, 28, 50, 25, 21, 39, 1 }, + { 2520, 28, 50, 25, 21, 39, 1 }, + { 2510, 28, 50, 25, 21, 39, 1 }, + { 2500, 28, 50, 25, 21, 39, 1 }, + { 2490, 27, 50, 25, 21, 39, 1 }, + { 2480, 27, 50, 25, 21, 38, 1 }, + { 2470, 27, 50, 25, 21, 38, 1 }, + { 2460, 27, 50, 25, 21, 38, 1 }, + { 2450, 27, 50, 25, 20, 38, 1 }, + { 2440, 27, 50, 25, 20, 38, 1 }, + { 2430, 27, 50, 25, 20, 38, 1 }, + { 2420, 27, 50, 25, 20, 38, 1 }, + { 2410, 27, 50, 25, 20, 37, 1 }, + { 2400, 26, 50, 25, 20, 37, 1 }, + { 2390, 26, 50, 25, 20, 37, 1 }, + { 2380, 26, 50, 25, 20, 37, 1 }, + { 2370, 26, 50, 25, 20, 37, 1 }, + { 2360, 26, 50, 25, 20, 37, 1 }, + { 2350, 26, 50, 25, 20, 36, 1 }, + { 2340, 26, 50, 25, 20, 36, 1 }, + { 2330, 26, 50, 25, 19, 36, 1 }, + { 2320, 25, 50, 25, 19, 36, 1 }, + { 2310, 25, 50, 25, 19, 36, 1 }, + { 2300, 25, 50, 25, 19, 36, 1 }, + { 2290, 25, 50, 25, 19, 35, 1 }, + { 2280, 25, 50, 25, 19, 35, 1 }, + { 2270, 25, 50, 25, 19, 35, 1 }, + { 2260, 25, 50, 25, 19, 35, 1 }, + { 2250, 25, 50, 25, 19, 35, 1 }, + { 2240, 25, 50, 25, 19, 35, 1 }, + { 2230, 24, 50, 25, 19, 35, 1 }, + { 2220, 24, 50, 25, 19, 34, 1 }, + { 2210, 24, 50, 25, 18, 34, 1 }, + { 2200, 24, 50, 25, 18, 34, 1 }, + { 2190, 24, 50, 25, 18, 34, 1 }, + { 2180, 24, 50, 25, 18, 34, 1 }, + { 2170, 24, 50, 25, 18, 34, 1 }, + { 2160, 24, 50, 25, 18, 33, 1 }, + { 2150, 24, 50, 25, 18, 33, 1 }, + { 2140, 23, 50, 25, 18, 33, 1 }, + { 2130, 23, 50, 25, 18, 33, 1 }, + { 2120, 23, 50, 25, 18, 33, 1 }, + { 2110, 23, 50, 25, 18, 33, 1 }, + { 2100, 23, 50, 25, 17, 32, 1 }, + { 2090, 23, 50, 25, 17, 32, 1 }, + { 2080, 23, 50, 25, 17, 32, 1 }, + { 2070, 23, 50, 25, 17, 32, 1 }, + { 2060, 22, 50, 25, 17, 32, 1 }, + { 2050, 22, 50, 25, 17, 32, 1 }, + { 2040, 22, 50, 25, 17, 32, 1 }, + { 2030, 22, 50, 25, 17, 31, 1 }, + { 2020, 22, 50, 25, 17, 31, 1 }, + { 2010, 22, 50, 25, 17, 31, 1 }, + { 2000, 22, 50, 25, 17, 31, 1 }, + { 1990, 22, 50, 25, 17, 31, 1 }, + { 1980, 22, 50, 25, 16, 31, 1 }, + { 1970, 21, 50, 25, 16, 30, 1 }, + { 1960, 21, 50, 25, 16, 30, 1 }, + { 1950, 21, 50, 25, 16, 30, 1 }, + { 1940, 21, 50, 25, 16, 30, 1 }, + { 1930, 21, 50, 25, 16, 30, 1 }, + { 1920, 21, 50, 25, 16, 30, 1 }, + { 1910, 21, 50, 25, 16, 30, 1 }, + { 1900, 21, 50, 25, 16, 29, 1 }, + { 1890, 21, 50, 25, 16, 29, 1 }, + { 1880, 20, 50, 25, 16, 29, 1 }, + { 1870, 20, 50, 25, 16, 29, 1 }, + { 1860, 20, 50, 25, 15, 29, 1 }, + { 1850, 20, 50, 25, 15, 29, 1 }, + { 1840, 20, 50, 25, 15, 28, 1 }, + { 1830, 20, 50, 25, 15, 28, 1 }, + { 1820, 20, 50, 25, 15, 28, 1 }, + { 1810, 20, 50, 25, 15, 28, 1 }, + { 1800, 19, 50, 25, 15, 28, 1 }, + { 1790, 19, 50, 25, 15, 28, 1 }, + { 1780, 19, 50, 25, 15, 27, 1 }, + { 1770, 19, 50, 25, 15, 27, 1 }, + { 1760, 19, 50, 25, 15, 27, 1 }, + { 1750, 19, 50, 25, 14, 27, 1 }, + { 1740, 19, 50, 25, 14, 27, 1 }, + { 1730, 19, 50, 25, 14, 27, 1 }, + { 1720, 19, 50, 25, 14, 27, 1 }, + { 1710, 18, 50, 25, 14, 26, 1 }, + { 1700, 18, 50, 25, 14, 26, 1 }, + { 1690, 18, 50, 25, 14, 26, 1 }, + { 1680, 18, 50, 25, 14, 26, 1 }, + { 1670, 18, 50, 25, 14, 26, 1 }, + { 1660, 18, 50, 25, 14, 26, 1 }, + { 1650, 18, 50, 25, 14, 25, 1 }, + { 1640, 18, 50, 25, 14, 25, 1 }, + { 1630, 18, 50, 25, 13, 25, 1 }, + { 1620, 17, 50, 25, 13, 25, 1 }, + { 1610, 17, 50, 25, 13, 25, 1 }, + { 1600, 17, 50, 25, 13, 25, 1 }, + { 1590, 17, 50, 25, 13, 24, 1 }, + { 1580, 17, 50, 25, 13, 24, 1 }, + { 1570, 17, 50, 25, 13, 24, 1 }, + { 1560, 17, 50, 25, 13, 24, 1 }, + { 1550, 17, 50, 25, 13, 24, 1 }, + { 1540, 16, 50, 25, 13, 24, 1 }, + { 1530, 16, 50, 25, 13, 24, 1 }, + { 1520, 16, 50, 25, 13, 23, 1 }, + { 1510, 16, 50, 25, 12, 23, 1 }, + { 1500, 16, 50, 25, 12, 23, 1 }, + { 1490, 16, 50, 25, 12, 23, 1 }, + { 1480, 16, 50, 25, 12, 23, 1 }, + { 1470, 16, 50, 25, 12, 23, 1 }, + { 1460, 16, 50, 25, 12, 22, 1 }, + { 1450, 15, 50, 25, 12, 22, 1 }, + { 1440, 15, 50, 25, 12, 22, 1 }, + { 1430, 15, 50, 25, 12, 22, 1 }, + { 1420, 15, 50, 25, 12, 22, 1 }, + { 1410, 15, 50, 25, 12, 22, 1 }, + { 1400, 15, 50, 25, 11, 21, 1 }, + { 1390, 15, 50, 25, 11, 21, 1 }, + { 1380, 15, 50, 25, 11, 21, 1 }, + { 1370, 15, 50, 25, 11, 21, 1 }, + { 1360, 14, 50, 25, 11, 21, 1 }, + { 1350, 14, 50, 25, 11, 21, 1 }, + { 1340, 14, 50, 25, 11, 21, 1 }, + { 1330, 14, 50, 25, 11, 20, 1 }, + { 1320, 14, 50, 25, 11, 20, 1 }, + { 1310, 14, 50, 25, 11, 20, 1 }, + { 1300, 14, 50, 25, 11, 20, 1 }, + { 1290, 14, 50, 25, 11, 20, 1 }, + { 1280, 13, 50, 25, 10, 20, 1 }, + { 1270, 13, 50, 25, 10, 19, 1 }, + { 1260, 13, 50, 25, 10, 19, 1 }, + { 1250, 13, 50, 25, 10, 19, 1 }, + { 1240, 13, 50, 25, 10, 19, 1 }, + { 1230, 13, 50, 25, 10, 19, 1 }, + { 1220, 13, 50, 25, 10, 19, 1 }, + { 1210, 13, 50, 25, 10, 19, 1 }, + { 1200, 13, 50, 25, 10, 18, 1 }, + { 1190, 12, 50, 25, 10, 18, 1 }, + { 1180, 12, 50, 25, 10, 18, 1 }, + { 1170, 12, 50, 25, 10, 18, 1 }, + { 1160, 12, 50, 25, 9, 18, 1 }, + { 1150, 12, 50, 25, 9, 18, 1 }, + { 1140, 12, 50, 25, 9, 17, 1 }, + { 1130, 12, 50, 25, 9, 17, 1 }, + { 1120, 12, 50, 25, 9, 17, 1 }, + { 1110, 12, 50, 25, 9, 17, 1 }, + { 1100, 11, 50, 25, 9, 17, 1 }, + { 1090, 11, 50, 25, 9, 17, 1 }, + { 1080, 11, 50, 25, 9, 16, 1 }, + { 1070, 11, 50, 25, 9, 16, 1 }, + { 1060, 11, 50, 25, 9, 16, 1 }, + { 1050, 11, 50, 25, 8, 16, 1 }, + { 1040, 11, 50, 25, 8, 16, 1 }, + { 1030, 11, 50, 25, 8, 16, 1 }, + { 1020, 10, 50, 25, 8, 16, 1 }, + { 1010, 10, 50, 25, 8, 15, 1 }, + { 1000, 10, 50, 25, 8, 15, 1 }, + { 990, 10, 50, 25, 8, 15, 2 }, + { 980, 10, 50, 25, 8, 15, 2 }, + { 970, 10, 50, 25, 8, 15, 2 }, + { 960, 10, 50, 25, 8, 15, 2 }, + { 950, 10, 50, 25, 8, 14, 2 }, + { 940, 10, 50, 25, 8, 14, 2 }, + { 930, 9, 50, 25, 7, 14, 2 }, + { 920, 9, 50, 25, 7, 14, 2 }, + { 910, 9, 50, 25, 7, 14, 2 }, + { 900, 9, 50, 25, 7, 14, 2 }, + { 890, 9, 50, 25, 7, 13, 2 }, + { 880, 9, 50, 25, 7, 13, 2 }, + { 870, 9, 50, 25, 7, 13, 2 }, + { 860, 9, 50, 25, 7, 13, 2 }, + { 850, 9, 50, 25, 7, 13, 2 }, + { 840, 8, 50, 25, 7, 13, 2 }, + { 830, 8, 50, 25, 7, 13, 2 }, + { 820, 8, 50, 25, 7, 12, 2 }, + { 810, 8, 50, 25, 6, 12, 2 }, + { 800, 8, 50, 25, 6, 12, 2 }, + { 790, 8, 50, 25, 6, 12, 2 }, + { 780, 8, 50, 25, 6, 12, 2 }, + { 770, 8, 50, 25, 6, 12, 2 }, + { 760, 7, 50, 25, 6, 11, 2 }, + { 750, 7, 50, 25, 6, 11, 2 }, + { 740, 7, 50, 25, 6, 11, 2 }, + { 730, 7, 50, 25, 6, 11, 2 }, + { 720, 7, 50, 25, 6, 11, 2 }, + { 710, 7, 50, 25, 6, 11, 2 }, + { 700, 7, 50, 25, 5, 10, 2 }, + { 690, 7, 50, 25, 5, 10, 2 }, + { 680, 7, 50, 25, 5, 10, 2 }, + { 670, 6, 50, 25, 5, 10, 2 }, + { 660, 6, 50, 25, 5, 10, 2 }, + { 650, 6, 50, 25, 5, 10, 2 }, + { 640, 6, 50, 25, 5, 10, 2 }, + { 630, 6, 50, 25, 5, 9, 2 }, + { 620, 6, 50, 25, 5, 9, 2 }, + { 610, 6, 50, 25, 5, 9, 2 }, + { 600, 6, 50, 25, 5, 9, 2 }, + { 590, 6, 50, 25, 5, 9, 2 }, + { 580, 5, 50, 25, 4, 9, 2 }, + { 570, 5, 50, 25, 4, 8, 2 }, + { 560, 5, 50, 25, 4, 8, 2 }, + { 550, 5, 50, 25, 4, 8, 2 }, + { 540, 5, 50, 25, 4, 8, 2 }, + { 530, 5, 50, 25, 4, 8, 2 }, + { 520, 5, 50, 25, 4, 8, 2 }, + { 510, 5, 50, 25, 4, 8, 2 }, + { 500, 4, 50, 25, 4, 7, 2 }, + { 490, 18, 50, 25, 14, 6, 2 }, + { 480, 17, 50, 25, 14, 6, 2 }, + { 470, 17, 50, 25, 14, 6, 2 }, + { 460, 17, 50, 25, 13, 6, 2 }, + { 450, 16, 50, 25, 13, 6, 2 }, + { 440, 16, 50, 25, 13, 6, 2 }, + { 430, 15, 50, 25, 12, 6, 2 }, + { 420, 15, 50, 25, 12, 5, 2 }, + { 410, 15, 50, 25, 12, 5, 2 }, + { 400, 14, 50, 25, 11, 5, 2 }, + { 390, 14, 50, 25, 11, 5, 2 }, + { 380, 13, 50, 25, 11, 5, 2 }, + { 370, 13, 50, 25, 11, 5, 2 }, + { 360, 13, 50, 25, 10, 4, 2 }, + { 350, 12, 50, 25, 10, 4, 2 }, + { 340, 12, 50, 25, 10, 4, 2 }, + { 330, 11, 50, 25, 9, 4, 2 }, + { 320, 11, 50, 25, 9, 4, 2 }, + { 310, 11, 50, 25, 9, 4, 2 }, + { 300, 10, 50, 25, 8, 3, 2 }, + { 290, 10, 50, 25, 8, 3, 2 }, + { 280, 9, 50, 25, 8, 3, 2 }, + { 270, 9, 50, 25, 8, 3, 2 }, + { 260, 8, 50, 25, 7, 3, 2 }, + { 250, 8, 50, 25, 7, 3, 2 }, + { 240, 8, 50, 25, 7, 3, 2 }, + { 230, 7, 50, 25, 6, 2, 2 }, + { 220, 7, 50, 25, 6, 2, 2 }, + { 210, 6, 50, 25, 6, 2, 2 }, + { 200, 6, 50, 25, 5, 2, 2 }, + { 190, 6, 50, 25, 5, 2, 2 }, + { 180, 5, 50, 25, 5, 2, 2 }, + { 170, 5, 50, 25, 5, 1, 2 }, + { 160, 4, 50, 25, 4, 1, 2 }, + { 150, 4, 50, 25, 4, 1, 2 }, + { 140, 4, 50, 25, 4, 1, 2 }, + { 130, 3, 50, 25, 3, 1, 2 }, + { 120, 3, 50, 25, 3, 1, 2 }, + { 110, 2, 50, 25, 3, 1, 2 }, + { 100, 2, 50, 25, 2, 0, 2 }, + { 90, 2, 50, 25, 2, 0, 2 }, + { 80, 1, 50, 25, 2, 0, 2 }, +}; + +static inline void +phy_write(struct samsung_mipi_dcphy *samsung, u32 reg, u32 val) +{ + writel(val, samsung->base + reg); +} + +static inline u32 phy_read(struct samsung_mipi_dcphy *samsung, u32 reg) +{ + return readl(samsung->base + reg); +} + +static inline void phy_update_bits(struct samsung_mipi_dcphy *samsung, + u32 reg, u32 mask, u32 val) +{ + u32 orig, tmp; + + orig = phy_read(samsung, reg); + tmp = orig & ~mask; + tmp |= val & mask; + phy_write(samsung, reg, tmp); +} + +static inline void grf_write(struct samsung_mipi_dcphy *samsung, + u32 reg, u32 val) +{ + regmap_write(samsung->grf, reg, val); +} + +static const struct samsung_mipi_dphy_timing * +samsung_mipi_dphy_get_timing(struct samsung_mipi_dcphy *samsung) +{ + const struct samsung_mipi_dphy_timing *timings; + unsigned int num_timings; + unsigned int lane_mbps = samsung->pll.rate / USEC_PER_SEC; + unsigned int i; + + timings = samsung_mipi_dphy_timing_table; + num_timings = ARRAY_SIZE(samsung_mipi_dphy_timing_table); + + for (i = num_timings; i > 0; i--) + if (lane_mbps <= timings[i - 1].max_lane_mbps) + break; + + if (i == 0) + ++i; + + return &timings[i - 1]; +} + +static const struct samsung_mipi_cphy_timing * +samsung_mipi_cphy_get_timing(struct samsung_mipi_dcphy *samsung) +{ + const struct samsung_mipi_cphy_timing *timings; + unsigned int num_timings; + unsigned int lane_msps = div64_ul(samsung->pll.rate, USEC_PER_SEC); + unsigned int i; + + timings = samsung_mipi_cphy_timing_table; + num_timings = ARRAY_SIZE(samsung_mipi_cphy_timing_table); + + for (i = num_timings; i > 0; i--) + if (lane_msps <= timings[i - 1].max_lane_msps) + break; + + if (i == 0) + ++i; + + return &timings[i - 1]; +} + +static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung) +{ + phy_write(samsung, BIAS_CON0, 0x0010); + phy_write(samsung, BIAS_CON1, 0x0110); + phy_write(samsung, BIAS_CON2, 0x3223); + + if (samsung->c_option) + phy_update_bits(samsung, BIAS_CON4, I_MUX_SEL_MASK, I_MUX_SEL(2)); +} + +static void samsung_mipi_dcphy_bias_block_disable(struct samsung_mipi_dcphy *samsung) +{ +} + +static void samsung_mipi_dcphy_pll_configure(struct samsung_mipi_dcphy *samsung) +{ + phy_update_bits(samsung, PLL_CON0, S_MASK | P_MASK, + S(samsung->pll.scaler) | P(samsung->pll.prediv)); + + if (samsung->pll.dsm < 0) { + u16 dsm_tmp; + + /* Using opposite number subtraction to find complement */ + dsm_tmp = abs(samsung->pll.dsm); + dsm_tmp = dsm_tmp - 1; + dsm_tmp ^= 0xffff; + phy_write(samsung, PLL_CON1, dsm_tmp); + } else { + phy_write(samsung, PLL_CON1, samsung->pll.dsm); + } + + phy_update_bits(samsung, PLL_CON2, M_MASK, M(samsung->pll.fbdiv)); + + if (samsung->pll.ssc_en) { + phy_write(samsung, PLL_CON3, + MRR(samsung->pll.mrr) | MFR(samsung->pll.mfr)); + phy_update_bits(samsung, PLL_CON4, SSCG_EN, SSCG_EN); + } + + phy_write(samsung, PLL_CON5, RESET_N_SEL | PLL_ENABLE_SEL); + phy_write(samsung, PLL_CON7, PLL_LOCK_CNT(0xf000)); + phy_write(samsung, PLL_CON8, PLL_STB_CNT(0xf000)); +} + +static void +samsung_mipi_dphy_clk_lane_timing_init(struct samsung_mipi_dcphy *samsung) +{ + const struct samsung_mipi_dphy_timing *timing; + unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); + u32 val = 0; + + timing = samsung_mipi_dphy_get_timing(samsung); + phy_write(samsung, DPHY_MC_GNR_CON0, 0xf000); + phy_write(samsung, DPHY_MC_ANA_CON0, 0x7133); + + if (lane_hs_rate >= 4500) + phy_write(samsung, DPHY_MC_ANA_CON1, 0x0001); + + /* + * Divide-by-2 Clock from Serial Clock. Use this when data rate is under + * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock + */ + if (lane_hs_rate < 1500) + val = HSTX_CLK_SEL; + + val |= T_LPX(timing->lpx); + /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ + phy_write(samsung, DPHY_MC_TIME_CON0, val); + + val = T_CLK_ZERO(timing->clk_zero) | T_CLK_PREPARE(timing->clk_prepare); + phy_write(samsung, DPHY_MC_TIME_CON1, val); + + val = T_HS_EXIT(timing->hs_exit) | T_CLK_TRAIL(timing->clk_trail_eot); + phy_write(samsung, DPHY_MC_TIME_CON2, val); + + val = T_CLK_POST(timing->clk_post); + phy_write(samsung, DPHY_MC_TIME_CON3, val); + + /* Escape Clock is 20.00MHz */ + phy_write(samsung, DPHY_MC_TIME_CON4, 0x1f4); + + /* + * skew calibration should be off, if the operation data rate is + * under 1.5Gbps or equal to 1.5Gbps. + */ + if (lane_hs_rate > 1500) + phy_write(samsung, DPHY_MC_DESKEW_CON0, 0x9cb1); +} + +static void +samsung_mipi_dphy_data_lane_timing_init(struct samsung_mipi_dcphy *samsung) +{ + const struct samsung_mipi_dphy_timing *timing; + unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); + u32 val = 0; + + timing = samsung_mipi_dphy_get_timing(samsung); + + phy_write(samsung, COMBO_MD0_ANA_CON0, 0x7133); + phy_write(samsung, COMBO_MD1_ANA_CON0, 0x7133); + phy_write(samsung, COMBO_MD2_ANA_CON0, 0x7133); + phy_write(samsung, DPHY_MD3_ANA_CON0, 0x7133); + + if (lane_hs_rate >= 1500) { + phy_write(samsung, COMBO_MD0_ANA_CON1, 0x0001); + phy_write(samsung, COMBO_MD1_ANA_CON1, 0x0001); + phy_write(samsung, COMBO_MD2_ANA_CON1, 0x0001); + phy_write(samsung, DPHY_MD3_ANA_CON1, 0x0001); + } + + /* + * Divide-by-2 Clock from Serial Clock. Use this when data rate is under + * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock + */ + if (lane_hs_rate < 1500) + val = HSTX_CLK_SEL; + + val |= T_LPX(timing->lpx); + /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ + phy_write(samsung, COMBO_MD0_TIME_CON0, val); + phy_write(samsung, COMBO_MD1_TIME_CON0, val); + phy_write(samsung, COMBO_MD2_TIME_CON0, val); + phy_write(samsung, DPHY_MD3_TIME_CON0, val); + + val = T_HS_ZERO(timing->hs_zero) | T_HS_PREPARE(timing->hs_prepare); + phy_write(samsung, COMBO_MD0_TIME_CON1, val); + phy_write(samsung, COMBO_MD1_TIME_CON1, val); + phy_write(samsung, COMBO_MD2_TIME_CON1, val); + phy_write(samsung, DPHY_MD3_TIME_CON1, val); + + val = T_HS_EXIT(timing->hs_exit) | T_HS_TRAIL(timing->hs_trail_eot); + phy_write(samsung, COMBO_MD0_TIME_CON2, val); + phy_write(samsung, COMBO_MD1_TIME_CON2, val); + phy_write(samsung, COMBO_MD2_TIME_CON2, val); + phy_write(samsung, DPHY_MD3_TIME_CON2, val); + + /* TTA-GET/TTA-GO Timing Counter register use default value */ + val = T_TA_GET(0x3) | T_TA_GO(0x0); + phy_write(samsung, COMBO_MD0_TIME_CON3, val); + phy_write(samsung, COMBO_MD1_TIME_CON3, val); + phy_write(samsung, COMBO_MD2_TIME_CON3, val); + phy_write(samsung, DPHY_MD3_TIME_CON3, val); + + /* Escape Clock is 20.00MHz */ + phy_write(samsung, COMBO_MD0_TIME_CON4, 0x1f4); + phy_write(samsung, COMBO_MD1_TIME_CON4, 0x1f4); + phy_write(samsung, COMBO_MD2_TIME_CON4, 0x1f4); + phy_write(samsung, DPHY_MD3_TIME_CON4, 0x1f4); +} + +static void samsung_mipi_dcphy_pll_enable(struct samsung_mipi_dcphy *samsung) +{ + u32 sts; + int ret; + + phy_update_bits(samsung, PLL_CON0, PLL_EN, PLL_EN); + + ret = readl_poll_timeout(samsung->base + PLL_STAT0, + sts, (sts & PLL_LOCK), 20000); + if (ret < 0) + dev_err(samsung->dev, "DC-PHY pll is not locked\n"); +} + +static void samsung_mipi_dcphy_pll_disable(struct samsung_mipi_dcphy *samsung) +{ + phy_update_bits(samsung, PLL_CON0, PLL_EN, 0); +} + +static void samsung_mipi_dphy_lane_enable(struct samsung_mipi_dcphy *samsung) +{ + phy_write(samsung, DPHY_MC_GNR_CON1, T_PHY_READY(0x2000)); + phy_update_bits(samsung, DPHY_MC_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + + switch (samsung->lanes) { + case 4: + phy_write(samsung, DPHY_MD3_GNR_CON1, T_PHY_READY(0x2000)); + phy_update_bits(samsung, DPHY_MD3_GNR_CON0, + PHY_ENABLE, PHY_ENABLE); + //fallthrough; + case 3: + phy_write(samsung, COMBO_MD2_GNR_CON1, T_PHY_READY(0x2000)); + phy_update_bits(samsung, COMBO_MD2_GNR_CON0, + PHY_ENABLE, PHY_ENABLE); + //fallthrough; + case 2: + phy_write(samsung, COMBO_MD1_GNR_CON1, T_PHY_READY(0x2000)); + phy_update_bits(samsung, COMBO_MD1_GNR_CON0, + PHY_ENABLE, PHY_ENABLE); + //fallthrough; + case 1: + default: + phy_write(samsung, COMBO_MD0_GNR_CON1, T_PHY_READY(0x2000)); + phy_update_bits(samsung, COMBO_MD0_GNR_CON0, + PHY_ENABLE, PHY_ENABLE); + break; + } +} + +static void samsung_mipi_cphy_timing_init(struct samsung_mipi_dcphy *samsung) +{ + const struct samsung_mipi_cphy_timing *timing; + unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); + u32 val = 0; + + timing = samsung_mipi_cphy_get_timing(samsung); + + /* + * Divide-by-2 Clock from Serial Clock. Use this when data rate is under + * 500Msps, otherwise divide-by-16 Clock from Serial Clock + */ + if (lane_hs_rate < 500) + val = HSTX_CLK_SEL; + + val |= T_LPX(timing->lpx); + /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ + phy_write(samsung, COMBO_MD0_TIME_CON0, val); + phy_write(samsung, COMBO_MD1_TIME_CON0, val); + phy_write(samsung, COMBO_MD2_TIME_CON0, val); + + val = T_HS_ZERO(timing->prebegin_3) | T_HS_PREPARE(timing->prepare_3); + phy_write(samsung, COMBO_MD0_TIME_CON1, val); + phy_write(samsung, COMBO_MD1_TIME_CON1, val); + phy_write(samsung, COMBO_MD2_TIME_CON1, val); + + val = T_HS_EXIT(timing->hs_exit) | T_HS_TRAIL(timing->post_3); + phy_write(samsung, DPHY_MD3_TIME_CON2, val); + phy_write(samsung, COMBO_MD0_TIME_CON2, val); + phy_write(samsung, COMBO_MD1_TIME_CON2, val); + phy_write(samsung, COMBO_MD2_TIME_CON2, val); + + /* TTA-GET/TTA-GO Timing Counter register use default value */ + val = T_TA_GET(0x3) | T_TA_GO(0x0); + phy_write(samsung, COMBO_MD0_TIME_CON3, val); + phy_write(samsung, COMBO_MD1_TIME_CON3, val); + phy_write(samsung, COMBO_MD2_TIME_CON3, val); + + /* Escape Clock is 20.00MHz */ + phy_write(samsung, COMBO_MD0_TIME_CON4, 0x1f4); + phy_write(samsung, COMBO_MD1_TIME_CON4, 0x1f4); + phy_write(samsung, COMBO_MD2_TIME_CON4, 0x1f4); + + /* set T_ERR_SOT_SYNC default value */ +} + +static void samsung_mipi_cphy_lane_enable(struct samsung_mipi_dcphy *samsung) +{ + phy_write(samsung, COMBO_MD0_GNR_CON1, T_PHY_READY(0x2000)); + phy_write(samsung, COMBO_MD1_GNR_CON1, T_PHY_READY(0x2000)); + phy_write(samsung, COMBO_MD2_GNR_CON1, T_PHY_READY(0x2000)); + + phy_update_bits(samsung, COMBO_MD0_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + phy_update_bits(samsung, COMBO_MD1_GNR_CON0, PHY_ENABLE, PHY_ENABLE); + phy_update_bits(samsung, COMBO_MD2_GNR_CON0, PHY_ENABLE, PHY_ENABLE); +} + +static void +samsung_mipi_dcphy_hs_vreg_amp_config(struct samsung_mipi_dcphy *samsung) +{ + phy_write(samsung, DPHY_MC_ANA_CON2, HS_VREG_AMP_ICON(2)); +} + +static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) +{ + reset_assert(&samsung->m_phy_rst); + + samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_pll_configure(samsung); + samsung_mipi_dphy_clk_lane_timing_init(samsung); + samsung_mipi_dphy_data_lane_timing_init(samsung); + samsung_mipi_dcphy_pll_enable(samsung); + samsung_mipi_dphy_lane_enable(samsung); + + reset_deassert(&samsung->m_phy_rst); + + /* The Tskewcal maximum is 100 usec at initial calibration. */ + udelay(100); +} + +static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung) +{ + grf_write(samsung, MIPI_DCPHY_GRF_CON0, M_CPHY_MODE); + reset_assert(&samsung->m_phy_rst); + + samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_hs_vreg_amp_config(samsung); + samsung_mipi_dcphy_pll_configure(samsung); + samsung_mipi_cphy_timing_init(samsung); + samsung_mipi_dcphy_pll_enable(samsung); + samsung_mipi_cphy_lane_enable(samsung); + + reset_deassert(&samsung->m_phy_rst); +} + +static void samsung_mipi_dphy_lane_disable(struct samsung_mipi_dcphy *samsung) +{ + phy_update_bits(samsung, DPHY_MC_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, COMBO_MD0_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, COMBO_MD1_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, COMBO_MD2_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, DPHY_MD3_GNR_CON0, PHY_ENABLE, 0); +} + +static void samsung_mipi_cphy_lane_disable(struct samsung_mipi_dcphy *samsung) +{ + phy_update_bits(samsung, COMBO_MD0_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, COMBO_MD1_GNR_CON0, PHY_ENABLE, 0); + phy_update_bits(samsung, COMBO_MD2_GNR_CON0, PHY_ENABLE, 0); +} + +static int samsung_mipi_dcphy_power_on(struct rockchip_phy *phy) +{ + struct samsung_mipi_dcphy *samsung = SAMSUNG_MIPI_DCPHY_FROM_PHY(phy); + + if (samsung->mode == PHY_MODE_MIPI_DPHY) + samsung_mipi_dphy_power_on(samsung); + else + samsung_mipi_cphy_power_on(samsung); + + return 0; +} + +static int samsung_mipi_dcphy_power_off(struct rockchip_phy *phy) +{ + struct samsung_mipi_dcphy *samsung = SAMSUNG_MIPI_DCPHY_FROM_PHY(phy); + + if (samsung->mode == PHY_MODE_MIPI_DPHY) + samsung_mipi_dphy_lane_disable(samsung); + else + samsung_mipi_cphy_lane_disable(samsung); + + samsung_mipi_dcphy_pll_disable(samsung); + samsung_mipi_dcphy_bias_block_disable(samsung); + + return 0; +} + +static int +samsung_mipi_dcphy_pll_ssc_modulation_calc(struct samsung_mipi_dcphy *samsung, + u8 *mfr, u8 *mrr) +{ + unsigned long fin = 24000; + u16 prediv = samsung->pll.prediv; + u16 fbdiv = samsung->pll.fbdiv; + u16 min_mfr, max_mfr; + u16 _mfr, best_mfr = 0; + u16 mr, _mrr, best_mrr = 0; + + /* 20KHz ≤ MF ≤ 150KHz */ + max_mfr = DIV_ROUND_UP(fin, (20 * prediv) << 5); + min_mfr = div64_ul(fin, ((150 * prediv) << 5)); + /*0 ≤ mfr ≤ 255 */ + if (max_mfr > 256) + max_mfr = 256; + + for (_mfr = min_mfr; _mfr < max_mfr; _mfr++) { + /* 1 ≤ mrr ≤ 31 */ + for (_mrr = 1; _mrr < 32; _mrr++) { + mr = DIV_ROUND_UP(_mfr * _mrr * 100, fbdiv << 6); + /* 0 ≤ MR ≤ 5% */ + if (mr > 5) + continue; + + if (_mfr * _mrr < 513) { + best_mfr = _mfr; + best_mrr = _mrr; + break; + } + } + } + + if (best_mrr) { + *mfr = best_mfr & 0xff; + *mrr = best_mrr & 0x3f; + } else { + dev_err(samsung->dev, "failed to calc ssc parameter mfr and mrr\n"); + return -EINVAL; + } + + return 0; +} + +static unsigned long +samsung_mipi_dcphy_pll_round_rate(struct samsung_mipi_dcphy *samsung, + unsigned long prate, unsigned long rate, + u8 *prediv, u16 *fbdiv, int *dsm, u8 *scaler) +{ + u64 max_fout = samsung->c_option ? MAX_CPHY_BW : MAX_DPHY_BW; + u64 best_freq = 0; + u64 fin, fvco, fout; + u8 min_prediv, max_prediv; + u8 _prediv, best_prediv = 1; + u16 _fbdiv, best_fbdiv = 1; + u8 _scaler, best_scaler = 0; + long _dsm, best_dsm = 0; + u32 min_delta = 0xffffffff; + + /* + * The PLL output frequency can be calculated using a simple formula: + * Fvco = ((m+k/65536) x 2 x Fin) / p + * Fout = ((m+k/65536) x 2 x Fin) / (p x 2^s) + */ + fin = div64_ul(prate, MSEC_PER_SEC); + + while (!best_freq) { + fout = div64_ul(rate, MSEC_PER_SEC); + if (fout > max_fout) + fout = max_fout; + + /* 0 ≤ S[2:0] ≤ 6 */ + for (_scaler = 0; _scaler < 7; _scaler++) { + fvco = fout << _scaler; + + /* + * 2600MHz ≤ FVCO ≤ 6600MHz + */ + if (fvco < 2600 * MSEC_PER_SEC || fvco > 6600 * MSEC_PER_SEC) + continue; + + /* 6MHz ≤ Fref(Fin / p) ≤ 30MHz */ + min_prediv = DIV_ROUND_UP(fin, 30 * MSEC_PER_SEC); + max_prediv = DIV_ROUND_CLOSEST(fin, 6 * MSEC_PER_SEC); + + for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) { + u64 delta, tmp; + + _fbdiv = DIV_ROUND_CLOSEST(fvco * _prediv, 2 * fin); + + /* 64 ≤ M[9:0] ≤ 1023 */ + if ((_fbdiv < 64) || (_fbdiv > 1023)) + continue; + + /* -32767 ≤ K[15:0] ≤ 32767 */ + _dsm = ((_prediv * fvco) - (2 * _fbdiv * fin)); + _dsm = DIV_ROUND_UP(_dsm << 15, fin); + if (abs(_dsm) > 32767) + continue; + + tmp = DIV_ROUND_CLOSEST((_fbdiv * fin * 2 * 1000), _prediv); + tmp += DIV_ROUND_CLOSEST((_dsm * fin * 1000), _prediv << 15); + + delta = abs(fvco * MSEC_PER_SEC - tmp); + if (delta < min_delta) { + best_prediv = _prediv; + best_fbdiv = _fbdiv; + best_dsm = _dsm; + best_scaler = _scaler; + min_delta = delta; + best_freq = DIV_ROUND_CLOSEST(tmp, 1000) * MSEC_PER_SEC; + } + } + } + + rate += 100 * MSEC_PER_SEC; + } + + *prediv = best_prediv; + *fbdiv = best_fbdiv; + *dsm = (int)best_dsm & 0xffff; + *scaler = best_scaler; + dev_info(samsung->dev, "p: %d, m: %d, dsm:%ld, scaler: %d\n", + best_prediv, best_fbdiv, best_dsm, best_scaler); + + return best_freq >> best_scaler; +} + +static unsigned long samsung_mipi_dcphy_set_pll(struct rockchip_phy *phy, + unsigned long rate) +{ + struct samsung_mipi_dcphy *samsung = SAMSUNG_MIPI_DCPHY_FROM_PHY(phy); + unsigned long fin = 24000000, fout; + u8 scaler = 0, mfr = 0, mrr = 0; + u16 fbdiv = 1; + u8 prediv = 1; + int dsm = 0; + int ret; + + samsung->c_option = (samsung->mode == PHY_MODE_MIPI_DPHY) ? false : true; + fout = samsung_mipi_dcphy_pll_round_rate(samsung, fin, rate, &prediv, + &fbdiv, &dsm, &scaler); + + dev_info(samsung->dev, "fin=%lu, req_rate=%lu\n", fin, rate); + dev_info(samsung->dev, "fout=%lu, prediv=%u, fbdiv=%u\n", fout, prediv, fbdiv); + + samsung->pll.prediv = prediv; + samsung->pll.fbdiv = fbdiv; + samsung->pll.dsm = dsm; + samsung->pll.scaler = scaler; + samsung->pll.rate = fout; + + /* + * All DPHY 2.0 compliant Transmitters shall support SSC operating above + * 2.5 Gbps + */ + if (fout > 2500000000LL) { + ret = samsung_mipi_dcphy_pll_ssc_modulation_calc(samsung, + &mfr, &mrr); + if (!ret) { + samsung->pll.ssc_en = true; + samsung->pll.mfr = mfr; + samsung->pll.mrr = mrr; + } + } + + return fout; +} + +static int samsung_mipi_dcphy_set_mode(struct rockchip_phy *phy, + enum phy_mode mode) +{ + struct samsung_mipi_dcphy *samsung = SAMSUNG_MIPI_DCPHY_FROM_PHY(phy); + + samsung->mode = mode; + + return 0; +} + +static const struct rockchip_phy_funcs samsung_mipi_dcphy_funcs = { + .power_on = samsung_mipi_dcphy_power_on, + .power_off = samsung_mipi_dcphy_power_off, + .set_pll = samsung_mipi_dcphy_set_pll, + .set_mode = samsung_mipi_dcphy_set_mode, +}; + +struct samsung_mipi_dcphy mMipiDcPhy[] = { + { + .Signature = SAMSUNG_MIPI_DCPHY_SIGNATURE, + .base = 0xfeda0000, + .grf = 0xfd5e8000, + .id = 0, + .lanes = 4, + .m_phy_rst = { 0x30A10, 3 }, /* mresetn_mipi_dcphy0 */ + .phy = { + .funcs = &samsung_mipi_dcphy_funcs + }, + }, + { + .Signature = SAMSUNG_MIPI_DCPHY_SIGNATURE, + .base = 0xfedb0000, + .grf = 0xfd5ec000, + .id = 1, + .lanes = 4, + .m_phy_rst = { 0x30A10, 5 }, /* mresetn_mipi_dcphy1 */ + .phy = { + .funcs = &samsung_mipi_dcphy_funcs + }, + }, +}; + +struct rockchip_phy *rockchip_phy_by_id(unsigned int id) +{ + for (int i = 0; i < ARRAY_SIZE(mMipiDcPhy); i++) { + if (id == mMipiDcPhy[i].id) { + return &mMipiDcPhy[i].phy; + } + } + return NULL; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.c new file mode 100644 index 0000000..f056332 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.c @@ -0,0 +1,40 @@ +/** @file + UART Serial Port library functions + + Copyright (c) 2006 - 2009, Intel Corporation + Copyright (c) 2015 - 2016, Hisilicon Limited. All rights reserved. + Copyright (c) 2015 - 2016, Linaro Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +**/ +#include +#include +#include +#include +#include + +#include "Dw8250SerialPortLib.h" + +/** + Initialize the serial device hardware. + + If no initialization is required, then return RETURN_SUCCESS. + If the serial device was successfuly initialized, then return RETURN_SUCCESS. + If the serial device could not be initialized, then return RETURN_DEVICE_ERROR. + + @retval RETURN_SUCCESS The serial device was initialized. + @retval RETURN_DEVICE_ERROR The serail device could not be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + // + // Assume already initialized. + // + return RETURN_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.inf new file mode 100644 index 0000000..a9dc5fe --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.inf @@ -0,0 +1,35 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.
    +# Copyright (c) 2015-2016, Hisilicon Limited. All rights reserved.
    +# Copyright (c) 2015-2016, Linaro Limited. All rights reserved.
    +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Dw8250SerialPortLib + FILE_GUID = e9b88aa0-16a5-447b-9c05-a77521db1a9e + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +[Sources.common] + DebugDw8250SerialPortLib.c + Dw8250SerialPortLibCommon.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Hisilicon/HisiPkg.dec + +[LibraryClasses] + BaseLib + IoLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gHisiTokenSpaceGuid.PcdSerialPortSendDelay diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.c new file mode 100644 index 0000000..ad093b3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.c @@ -0,0 +1,50 @@ +/** @file + UART Serial Port library functions + + Copyright (c) 2006 - 2009, Intel Corporation + Copyright (c) 2015 - 2016, Hisilicon Limited. All rights reserved. + Copyright (c) 2015 - 2016, Linaro Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +**/ +#include +#include +#include +#include +#include + +#include "Dw8250SerialPortLib.h" + +/** + Initialize the serial device hardware. + + If no initialization is required, then return RETURN_SUCCESS. + If the serial device was successfuly initialized, then return RETURN_SUCCESS. + If the serial device could not be initialized, then return RETURN_DEVICE_ERROR. + + @retval RETURN_SUCCESS The serial device was initialized. + @retval RETURN_DEVICE_ERROR The serail device could not be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + UINT32 ulUartClkFreq; + + MmioWrite8 (UART_LCR_REG, UART_LCR_DLS8); + MmioWrite8 (UART_FCR_REG, UART_FCR_EN | UART_FCR_RXCLR | UART_FCR_TXCLR); + MmioWrite8 (UART_LCR_REG, UART_LCR_DLAB | UART_LCR_DLS8); + + ulUartClkFreq = PcdGet32(PcdUartClkInHz); + + MmioWrite8 (UART_DLL_REG, (ulUartClkFreq / (16 * (UINT32)BAUDRATE) ) & 0xff); + MmioWrite8 (UART_DLH_REG, ((ulUartClkFreq/ (16 * (UINT32)BAUDRATE) ) >> 8 ) & 0xff); + MmioWrite8 (UART_LCR_REG, UART_LCR_DLS8); + MmioWrite8 (UART_IEL_REG, 0x00); + + return RETURN_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.h new file mode 100644 index 0000000..a1d3668 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.h @@ -0,0 +1,110 @@ +/** @file +* +* Copyright (c) 2011-2015, ARM Limited. All rights reserved. +* Copyright (c) 2015-2016, Hisilicon Limited. All rights reserved. +* Copyright (c) 2015-2016, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +* Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +**/ + +#ifndef __DW8250_SERIALPORTLIB_H__ +#define __DW8250_SERIALPORTLIB_H__ + + +#define SERIAL_0_BASE_ADR (PcdGet64(PcdSerialRegisterBase)) + + +#define UART_SEND_DELAY (PcdGet32(PcdSerialPortSendDelay)) +#define BAUDRATE (PcdGet64(PcdUartDefaultBaudRate)) + + +#define UART_THR_REG (SERIAL_0_BASE_ADR + UART_THR) +#define UART_RBR_REG (SERIAL_0_BASE_ADR + UART_RBR) +#define UART_DLL_REG (SERIAL_0_BASE_ADR + UART_DLL) +#define UART_DLH_REG (SERIAL_0_BASE_ADR + UART_DLH) +#define UART_IEL_REG (SERIAL_0_BASE_ADR + UART_IEL) +#define UART_IIR_REG (SERIAL_0_BASE_ADR + UART_IIR) +#define UART_FCR_REG (SERIAL_0_BASE_ADR + UART_FCR) +#define UART_LCR_REG (SERIAL_0_BASE_ADR + UART_LCR) +#define UART_LSR_REG (SERIAL_0_BASE_ADR + UART_LSR) +#define UART_USR_REG (SERIAL_0_BASE_ADR + UART_USR) + + +#define UART_RBR 0x00 +#define UART_THR 0x00 +#define UART_DLL 0x00 +#define UART_DLH 0x04 +#define UART_IEL 0x04 +#define UART_IIR 0x08 +#define UART_FCR 0x08 +#define UART_LCR 0x0C +#define UART_MCR 0x10 +#define UART_LSR 0x14 +#define UART_USR 0x7C + +/* register definitions */ + +#define UART_FCR_EN 0x01 +#define UART_FCR_RXCLR 0x02 +#define UART_FCR_TXCLR 0x04 +#define UART_FCR_CLEARFIFO 0x00 +#define UART_FCR_RXL1 0x00 +#define UART_FCR_RXL4 0x40 +#define UART_FCR_RXL8 0x80 +#define UART_FCR_RXL14 0xc0 +#define UART_FCR_TXL0 0x00 +#define UART_FCR_TXL4 0x20 +#define UART_FCR_TXL8 0x30 +#define UART_FCR_TXL14 0x10 + +/*LCR Name: Line Control Register fields*/ +#define UART_LCR_DLAB 0x80 +#define UART_LCR_EPS 0x10 +#define UART_LCR_PEN 0x08 +#define UART_LCR_STOP 0x04 +#define UART_LCR_DLS8 0x03 +#define UART_LCR_DLS7 0x02 +#define UART_LCR_DLS6 0x01 +#define UART_LCR_DLS5 0x00 + + +#define UART_DLH_AND_DLL_WIDTH 0xFF + + +#define UART_IER_PTIME 0x80 +#define UART_IER_ELSI 0x04 +#define UART_IER_ETBEI 0x02 +#define UART_IER_ERBFI 0x01 + + +#define UART_IIR_FIFOSE 0xC0 + + +#define UART_IIR_InterruptID 0x01 +#define UART_IIR_INTIDTE 0x02 +#define UART_IIR_INTIDRA 0x04 +#define UART_IIR_INTIDRLS 0x06 +#define UART_IIR_INTMASK 0x0f +#define UART_IIR_RDA 0x04 +#define UART_IIR_TE 0x02 + +#define UART_LSR_TEMT 0x40 +#define UART_LSR_THRE 0x20 +#define UART_LSR_BI 0x10 +#define UART_LSR_FE 0x08 +#define UART_LSR_PE 0x04 +#define UART_LSR_R 0x02 +#define UART_LSR_DR 0x01 + + +#define UART_USR_BUSY 0x01 + +#define FIFO_MAXSIZE 32 + +extern UINT8 SerialPortReadChar(VOID); +extern VOID SerialPortWriteChar(UINT8 scShowChar); + +#endif + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.inf new file mode 100644 index 0000000..752f468 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.inf @@ -0,0 +1,37 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.
    +# Copyright (c) 2015-2016, Hisilicon Limited. All rights reserved.
    +# Copyright (c) 2015-2016, Linaro Limited. All rights reserved.
    +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Dw8250SerialPortLib + FILE_GUID = e7016ad2-40dd-406f-81ef-535da603c8e1 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +[Sources.common] + Dw8250SerialPortLib.c + Dw8250SerialPortLibCommon.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Hisilicon/HisiPkg.dec + +[LibraryClasses] + BaseLib + IoLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate + gHisiTokenSpaceGuid.PcdSerialPortSendDelay + gHisiTokenSpaceGuid.PcdUartClkInHz diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLibCommon.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLibCommon.c new file mode 100644 index 0000000..a65497b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLibCommon.c @@ -0,0 +1,260 @@ +/** @file + UART Serial Port library functions + + Copyright (c) 2006 - 2009, Intel Corporation + Copyright (c) 2015 - 2016, Hisilicon Limited. All rights reserved. + Copyright (c) 2015 - 2016, Linaro Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + Based on the files under ArmPlatformPkg/Library/PL011SerialPortLib/ +**/ +#include +#include +#include +#include +#include + +#include "Dw8250SerialPortLib.h" + +/** + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + + If Buffer is NULL, then ASSERT(). + + If NumberOfBytes is zero, then return 0. + + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + + if (NULL == Buffer) { + return 0; + } + + Result = NumberOfBytes; + + while (NumberOfBytes--) { + + SerialPortWriteChar(*Buffer); + Buffer++; + } + + return Result; +} + + +/** + Reads data from a serial device into a buffer. + + @param Buffer Pointer to the data buffer to store the data read from the serial device. + @param NumberOfBytes Number of bytes to read from the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes read from the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + + if (NULL == Buffer) { + return 0; + } + + Result = 0; + + while (NumberOfBytes--) { + // + // Wait for the serail port to be ready. + // + *Buffer=SerialPortReadChar(); + Buffer++ ; + Result++; + } + + return Result; +} + +/** + Polls a serial device to see if there is any data waiting to be read. + + Polls aserial device to see if there is any data waiting to be read. + If there is data waiting to be read from the serial device, then TRUE is returned. + If there is no data waiting to be read from the serial device, then FALSE is returned. + + @retval TRUE Data is waiting to be read from the serial device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + + return (BOOLEAN) ((MmioRead8 (UART_LSR_REG) & UART_LSR_DR) == UART_LSR_DR); + +} + + +VOID SerialPortWriteChar(UINT8 scShowChar) +{ + UINT32 ulLoop = 0; + + while(ulLoop < (UINT32)UART_SEND_DELAY) + { + + if ((MmioRead8 (UART_USR_REG) & 0x02) == 0x02) + { + break; + } + + ulLoop++; + } + MmioWrite8 (UART_THR_REG, (UINT8)scShowChar); + + ulLoop = 0; + while(ulLoop < (UINT32)UART_SEND_DELAY) + { + if ((MmioRead8 (UART_USR_REG) & 0x04) == 0x04) + { + break; + } + ulLoop++; + } + + return; +} + + +UINT8 SerialPortReadChar(VOID) +{ + UINT8 recvchar = 0; + + while(1) + { + if ((MmioRead8 (UART_LSR_REG) & UART_LSR_DR) == UART_LSR_DR) + { + break; + } + } + + recvchar = MmioRead8 (UART_RBR_REG); + + return recvchar; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receice time out, parity, + data bits, and stop bits on a serial device. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the + device's default interface speed. + On output, the value actually set. + @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's default FIFO depth. + On output, the value actually set. + @param Timeout The requested time out for a single character in microseconds. + This timeout applies to both the transmit and receive side of the + interface. A Timeout value of 0 will use the device's default time + out value. + On output, the value actually set. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + On output, the value actually set. + @param DataBits The number of data bits to use on the serial device. A DataBits + vaule of 0 will use the device's default data bit setting. + On output, the value actually set. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + On output, the value actually set. + + @retval RETURN_SUCCESS The new attributes were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetAttributes ( + IN OUT UINT64 *BaudRate, + IN OUT UINT32 *ReceiveFifoDepth, + IN OUT UINT32 *Timeout, + IN OUT EFI_PARITY_TYPE *Parity, + IN OUT UINT8 *DataBits, + IN OUT EFI_STOP_BITS_TYPE *StopBits + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Set the serial device control bits. + + @param Control Control bits which are to be set on the serial device. + + @retval EFI_SUCCESS The new control bits were set on the serial device. + @retval EFI_UNSUPPORTED The serial device does not support this operation. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetControl ( + IN UINT32 Control + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Get the serial device control bits. + + @param Control Control signals read from the serial device. + + @retval EFI_SUCCESS The control bits were read from the serial device. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortGetControl ( + OUT UINT32 *Control + ) +{ + + if (SerialPortPoll ()) { + // If a character is pending don't set EFI_SERIAL_INPUT_BUFFER_EMPTY + *Control = EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } else { + *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY | EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.c new file mode 100644 index 0000000..4f947c4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.c @@ -0,0 +1,30 @@ +/** @file + * + * DwcSdhciDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include + +EFI_STATUS +EFIAPI +DwcSdhciSetClockRate ( + IN UINTN Frequency + ) +{ + return EFI_UNSUPPORTED; +} + +VOID +EFIAPI +DwcSdhciSetIoMux ( + VOID + ) +{ + return; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.inf new file mode 100644 index 0000000..1e13c87 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.inf @@ -0,0 +1,24 @@ +#/** @file +# +# DwcSdhciDxe platform helper library. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = DwcSdhciPlatformLibNull + FILE_GUID = 98fc1cd7-aeca-4b8d-894f-5d2f9899a47d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DwcSdhciPlatformLib + +[Sources] + DwcSdhciPlatformLibNull.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.c new file mode 100644 index 0000000..b502b06 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.c @@ -0,0 +1,497 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + */ + +#include "Soc.h" +#include +#include +#include +#include +#include +#include + +#define HAL_IS_ALIGNED(x, a) (((x) & (a - 1)) == 0) +/********************* Private MACRO Definition ******************************/ +// #define FSPI_DEBUG +#ifdef FSPI_DEBUG +#define FSPI_DBG(...) +#else +#define FSPI_DBG(...) +#endif + +/* FSPI_CTRL */ +#define FSPI_CTRL_SHIFTPHASE_NEGEDGE 1 + +/* FSPI_RCVR */ +#define FSPI_RCVR_RCVR_RESET (1 << FSPI_RCVR_RCVR_SHIFT) /* Recover The FSPI State Machine */ + +/* FSPI_ISR */ +#define FSPI_ISR_DMAS_ACTIVE (1 << FSPI_ISR_DMAS_SHIFT) /* DMA Finish Interrupt Active */ +#define FSPI_ISR_NSPIS_ACTIVE (1 << FSPI_ISR_NSPIS_SHIFT) /* SPI Error Interrupt Active */ +#define FSPI_ISR_AHBS_ACTIVE (1 << FSPI_ISR_AHBS_SHIFT) /* AHB Error Interrupt Active */ +#define FSPI_ISR_TRANSS_ACTIVE (1 << FSPI_ISR_TRANSS_SHIFT) /* Transfer finish Interrupt Active */ +#define FSPI_ISR_TXES_ACTIVE (1 << FSPI_ISR_TXES_SHIFT) /* Transmit FIFO Empty Interrupt Active */ +#define FSPI_ISR_TXOS_ACTIVE (1 << FSPI_ISR_TXOS_SHIFT) /* Transmit FIFO Overflow Interrupt Active */ +#define FSPI_ISR_RXUS_ACTIVE (1 << FSPI_ISR_RXUS_SHIFT) /* Receive FIFO Underflow Interrupt Active */ +#define FSPI_ISR_RXFS_ACTIVE (1 << FSPI_ISR_RXFS_SHIFT) /* Receive FIFO Full Interrupt Active */ + +/* FSPI_FSR */ +#define FSPI_FSR_RXFS_EMPTY (1 << FSPI_FSR_RXFS_SHIFT) /* Receive FIFO Full */ +#define FSPI_FSR_RXES_EMPTY (1 << FSPI_FSR_RXES_SHIFT) /* Receive FIFO Empty */ +#define FSPI_FSR_TXFS_FULL (1 << FSPI_FSR_TXFS_SHIFT) /* Transmit FIFO Full */ +#define FSPI_FSR_TXES_EMPTY (1 << FSPI_FSR_TXES_SHIFT) /* Transmit FIFO Empty */ + +/* FSPI_SR */ +#define FSPI_SR_SR_BUSY (1 << FSPI_SR_SR_SHIFT) /* When busy, do not set the control register. */ + +/* FSPI_DMATR */ +#define FSPI_DMATR_DMATR_START (1 << FSPI_DMATR_DMATR_SHIFT) /* Write 1 to start the dma transfer. */ + +/* FSPI_RISR */ +#define FSPI_RISR_TRANSS_ACTIVE (1 << FSPI_RISR_TRANSS_SHIFT) + +/* FSPI attributes */ +#define FSPI_VER_VER_1 1 +#define FSPI_VER_VER_3 3 +#define FSPI_VER_VER_5 5 + +#define FSPI_NOR_FLASH_PAGE_SIZE 0x100 + +#define FSPI_MAX_IOSIZE_VER3 (1024U * 8) +#define FSPI_MAX_IOSIZE_VER4 (0xFFFFFFFFU) + +/********************* Private Structure Definition **************************/ + +typedef union { + UINT32 d32; + struct { + unsigned txempty : 1; /* tx fifo empty */ + unsigned txfull : 1; /* tx fifo full */ + unsigned rxempty : 1; /* rx fifo empty */ + unsigned rxfull : 1; /* tx fifo empty interrupt mask */ + unsigned reserved7_4 : 4; + unsigned txlevel : 5; /* tx fifo: 0: full; 1: left 1 entry; ... */ + unsigned reserved15_13 : 3; + unsigned rxlevel : 5; /* rx fifo: 0: full; 1: left 1 entry; ... */ + unsigned reserved31_21 : 11; + } b; +} FSPIFSR_DATA; + +/** FSPI_XMMC bit union */ +typedef union { + UINT32 d32; + struct { + unsigned reserverd1 : 5; + unsigned devHwEn : 1; /* device Hwrite Enable */ + unsigned prefetch : 1; /* prefetch enable */ + unsigned uincrPrefetchEn : 1; /* undefine INCR Burst Prefetch Enable */ + unsigned uincrLen : 4; /* undefine INCR length */ + unsigned devWrapEn : 1; /* device Wrap Enable */ + unsigned devIncrEn : 1; /* device INCR2/4/8/16 Enable */ + unsigned devUdfincrEn : 1; /* device Undefine INCR Enable */ + unsigned reserved2 : 17; + } b; +} FSPIXMMCCTRL_DATA; +/********************* Private Variable Definition ***************************/ + +/********************* Private Function Definition ***************************/ +static void FSPI_Reset(struct HAL_FSPI_HOST *host) +{ + INT32 timeout = 10000; + + host->instance->RCVR = FSPI_RCVR_RCVR_RESET; + while ((host->instance->RCVR == FSPI_RCVR_RCVR_RESET) && (timeout > 0)) { + HAL_CPUDelayUs(1); + timeout--; + } + host->instance->ICLR = 0xFFFFFFFF; +} + +static void FSPI_ContModeInit(struct HAL_FSPI_HOST *host) +{ + /* Setup when FSPI->AX = 0xa5, Cancel when FSPI->AX = 0x0 */ + WRITE_REG(host->instance->EXT_AX, 0xa5 << FSPI_EXT_AX_AX_SETUP_PAT_SHIFT | + 0x5a << FSPI_EXT_AX_AX_CANCEL_PAT_SHIFT); + /* Skip Continuous mode in default */ + switch (host->cs) { + case 0: + WRITE_REG(host->instance->AX0, 0 << FSPI_AX0_AX_SHIFT); + break; + case 1: + WRITE_REG(host->instance->AX1, 0 << FSPI_AX1_AX_SHIFT); + break; + default: + break; + } +} + +static void FSPI_ContModeDeInit(struct HAL_FSPI_HOST *host) +{ + /* FSPI avoid setup pattern match with FSPI->AX */ + WRITE_REG(host->instance->EXT_AX, 0x77 << FSPI_EXT_AX_AX_SETUP_PAT_SHIFT | + 0x88 << FSPI_EXT_AX_AX_CANCEL_PAT_SHIFT); +} + +/** + * @brief Configuration register with flash operation protocol. + * @param host: FSPI host. + * @param op: flash operation protocol. + * @return RETURN_STATUS. + * @attention Set host->cs to select chip. + */ +RETURN_STATUS HAL_FSPI_XferStart(struct HAL_FSPI_HOST *host, struct HAL_SPI_MEM_OP *op) +{ + struct FSPI_REG *pReg = host->instance; + FSPICMD_DATA FSPICmd; + FSPICTRL_DATA FSPICtrl; + + FSPICmd.d32 = 0; + FSPICtrl.d32 = 0; + + /* set CMD */ + FSPICmd.b.cmd = op->cmd.opcode; + if (op->cmd.buswidth == 4) { + FSPICtrl.b.cmdlines = FSPI_LINES_X4; + FSPICtrl.b.datalines = FSPI_LINES_X4; /* cmdlines work with datalines */ + } + + /* set ADDR */ + if (op->addr.nbytes) { + if (op->addr.nbytes == 4) { + FSPICmd.b.addrbits = FSPI_ADDR_32BITS; + } else if (op->addr.nbytes == 3) { + FSPICmd.b.addrbits = FSPI_ADDR_24BITS; + } else { + FSPICmd.b.addrbits = FSPI_ADDR_XBITS; + pReg->ABIT0 = op->addr.nbytes * 8 - 1; + } + + FSPICtrl.b.addrlines = op->addr.buswidth == 4 ? FSPI_LINES_X4 : FSPI_LINES_X1; + } + + /* set DUMMY*/ + if (op->dummy.nbytes) { + switch (op->dummy.buswidth) { + case 4: + FSPICmd.b.dummybits = op->dummy.nbytes * 2; + break; + case 2: + FSPICmd.b.dummybits = op->dummy.nbytes * 4; + break; + default: + FSPICmd.b.dummybits = op->dummy.nbytes * 8; + break; + } + } + + /* set DATA */ + WRITE_REG(pReg->LEN_EXT, op->data.nbytes); + if (op->data.nbytes) { + if (op->data.dir == HAL_SPI_MEM_DATA_OUT) { + FSPICmd.b.rw = FSPI_WRITE; + } + if (op->data.buswidth == 4) { + FSPICtrl.b.datalines = FSPI_LINES_X4; + } else if (op->data.buswidth == 2) { + FSPICtrl.b.datalines = FSPI_LINES_X2; + } else { + FSPICtrl.b.datalines = FSPI_LINES_X1; + } + } + + /* spitial setting */ + FSPICtrl.b.sps = host->mode & HAL_SPI_CPHA; + FSPICmd.b.cs = host->cs; + if (op->data.nbytes == 0 && op->addr.nbytes) { + FSPICmd.b.rw = FSPI_WRITE; + } + + if (!(pReg->FSR & FSPI_FSR_TXES_EMPTY) || !(pReg->FSR & FSPI_FSR_RXES_EMPTY) || (pReg->SR & FSPI_SR_SR_BUSY)) { + FSPI_Reset(host); + } + + // FSPI_DBG("%s 1 %x %x %x\n", __func__, op->addr.nbytes, op->dummy.nbytes, op->data.nbytes); + // FSPI_DBG("%s 2 %lx %lx %lx %x\n", __func__, FSPICtrl.d32, FSPICmd.d32, op->addr.val, host->cs); + + /* config FSPI */ + switch (host->cs) { + case 0: + pReg->CTRL0 = FSPICtrl.d32; + break; + case 1: + pReg->CTRL1 = FSPICtrl.d32; + break; + default: + break; + } + pReg->CMD = FSPICmd.d32; + if (op->addr.nbytes) { + pReg->ADDR = op->addr.val; + } + + return RETURN_SUCCESS; +} + +/** + * @brief IO transfer. + * @param host: FSPI host. + * @param len: data n bytes. + * @param data: transfer buffer. + * @param dir: transfer direction. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_FSPI_XferData(struct HAL_FSPI_HOST *host, UINT32 len, void *data, UINT32 dir) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + __IO FSPIFSR_DATA fifostat; + INT32 timeout = 0; + UINT32 i, words; + UINT32 *pData = (UINT32 *)data; + struct FSPI_REG *pReg = host->instance; + UINT32 temp = 0; + + HAL_ASSERT(data && len); + + if (len && len < 4 && dir == FSPI_WRITE) { + if (len == 1) { + temp = *((uint8_t *)data); + } else if (len == 2) { + temp = *((uint16_t *)data); + } else { + temp = ((uint8_t *)data)[0] | ((uint8_t *)data)[1] << 8 | ((uint8_t *)data)[2] << 16; + } + pData = &temp; + } else if (len >= 4 && !HAL_IS_ALIGNED((long)data, 4)) { + FSPI_DBG("%s data unaligned access\n", __func__); + } + + /* FSPI_DBG("%s %p len %lx word0 %lx dir %lx\n", __func__, pData, len, pData[0], dir); */ + if (dir == FSPI_WRITE) { + words = (len + 3) >> 2; + while (words) { + fifostat.d32 = pReg->FSR; + if (fifostat.b.txlevel > 0) { + UINT32 count = MIN(words, fifostat.b.txlevel); + + for (i = 0; i < count; i++) { + pReg->DATA = *pData++; + words--; + } + if (words == 0) { + break; + } + timeout = 0; + } else { + HAL_CPUDelayUs(1); + if (timeout++ > 10000) { + ret = RETURN_TIMEOUT; + break; + } + } + } + } else { + UINT32 bytes = len & 0x3; + + words = len >> 2; + while (words) { + fifostat.d32 = pReg->FSR; + if (fifostat.b.rxlevel > 0) { + UINT32 count = MIN(words, fifostat.b.rxlevel); + if (count == 15) { /* Reduce CPU cost */ + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + *pData++ = pReg->DATA; + words -= 15; + } else { + for (i = 0; i < count; i++) { + *pData++ = pReg->DATA; + } + words -= count; + } + + if (0 == words) { + break; + } + timeout = 0; + } else { + HAL_CPUDelayUs(1); + if (timeout++ > 10000) { + ret = RETURN_TIMEOUT; + break; + } + } + } + + timeout = 0; + while (bytes) { + fifostat.d32 = pReg->FSR; + if (fifostat.b.rxlevel > 0) { + uint8_t *pData1 = (uint8_t *)pData; + words = pReg->DATA; + for (i = 0; i < bytes; i++) { + pData1[i] = (uint8_t)((words >> (i * 8)) & 0xFF); + } + break; + } else { + HAL_CPUDelayUs(1); + if (timeout++ > 10000) { + ret = RETURN_TIMEOUT; + break; + } + } + } + } + + return ret; +} + +/** + * @brief Wait for FSPI host transfer finished. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_FSPI_XferDone(struct HAL_FSPI_HOST *host) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + INT32 timeout = 0; + struct FSPI_REG *pReg = host->instance; + + while (pReg->SR & FSPI_SR_SR_BUSY) { + HAL_CPUDelayUs(1); + if (timeout++ > 100000) { /*wait 100ms*/ + ret = RETURN_TIMEOUT; + break; + } + } + HAL_CPUDelayUs(1); //CS# High Time (read/write) >100ns + + return ret; +} + +/** + * @brief SPI Nor flash data transmission interface to support open source specifications SNOR. + * @param host: FSPI host. + * @param op: flash operation protocol. + * @return RETURN_STATUS. + * @attention Set host->cs to select chip. + */ +RETURN_STATUS HAL_FSPI_SpiXfer(struct HAL_FSPI_HOST *host, struct HAL_SPI_MEM_OP *op) +{ + RETURN_STATUS ret = RETURN_SUCCESS; + UINT32 dir = op->data.dir; + void *pData = NULL; + + HAL_ASSERT(IS_FSPI_INSTANCE(host->instance)); + + if (op->data.buf.in) { + pData = (void *)op->data.buf.in; + } else if (op->data.buf.out) { + pData = (void *)op->data.buf.out; + } + + HAL_FSPI_XferStart(host, op); + if (pData) { + ret = HAL_FSPI_XferData(host, op->data.nbytes, pData, dir); + if (ret) { + FSPI_DBG("%s xfer data failed ret %d\n", __func__, ret); + + return ret; + } + } + + return HAL_FSPI_XferDone(host); +} + +/** @} */ + +/** @defgroup FSPI_Exported_Functions_Group4 Init and DeInit Functions + + This section provides functions allowing to init and deinit the module: + + * @{ + */ + +/** + * @brief Init FSPI. + * @param host: FSPI host. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_FSPI_Init(struct HAL_FSPI_HOST *host) +{ + INT32 timeout = 0; + struct FSPI_REG *pReg; + RETURN_STATUS ret = RETURN_SUCCESS; + + HAL_ASSERT(IS_FSPI_INSTANCE(host->instance)); + + pReg = host->instance; + pReg->MODE = 0; + while (pReg->SR & FSPI_SR_SR_BUSY) { + HAL_CPUDelayUs(1); + if (timeout++ > 1000) { + return RETURN_TIMEOUT; + } + } + FSPI_ContModeInit(host); + pReg->CTRL0 = 0; + +#if (FSPI_VER > FSPI_VER_VER_3) + WRITE_REG(pReg->LEN_CTRL, FSPI_LEN_CTRL_TRB_SEL_MASK); +#endif + + return ret; +} + +/** + * @brief DeInit FSPI. + * @param host: FSPI host. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_FSPI_DeInit(struct HAL_FSPI_HOST *host) +{ + HAL_ASSERT(IS_FSPI_INSTANCE(host->instance)); + + host->instance->MODE = 0; + FSPI_ContModeDeInit(host); + FSPI_Reset(host); + + return RETURN_SUCCESS; +} + +/** + * @brief Set FSPI delay line. + * @param host: FSPI host. + * @param cells: delay line cells. + * @return RETURN_STATUS. + */ +RETURN_STATUS HAL_FSPI_SetDelayLines(struct HAL_FSPI_HOST *host, uint8_t cells) +{ + HAL_ASSERT(IS_FSPI_INSTANCE(host->instance)); + if (host->cs == 0) { + WRITE_REG(host->instance->DLL_CTRL0, 1 << FSPI_DLL_CTRL0_SCLK_SMP_SEL_SHIFT | cells); + } else { + WRITE_REG(host->instance->DLL_CTRL1, 1 << FSPI_DLL_CTRL0_SCLK_SMP_SEL_SHIFT | cells); + } + + return RETURN_SUCCESS; +} + +UINT32 HAL_FSPI_GetMaxIoSize(struct HAL_FSPI_HOST *host) +{ + HAL_ASSERT(IS_FSPI_INSTANCE(host->instance)); + + return FSPI_MAX_IOSIZE_VER4; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.inf new file mode 100644 index 0000000..9eaa4a4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/FspiLib/FspiLib.inf @@ -0,0 +1,39 @@ +#/** @file +# +# Component description file for Uart module +# +# Copyright (c) 2022, Rockchip Inc. All rights reserved.
    +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FspiLib + FILE_GUID = b1bbeb92-9df6-11ec-9573-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FspiLib + +[Sources.common] + FspiLib.c + +[LibraryClasses] + DebugLib + IoLib + TimerLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[Pcd] + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.c new file mode 100644 index 0000000..e2b5a79 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.c @@ -0,0 +1,139 @@ +/** @file + Rockchip PWM Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + +#define PWM_INT_EN(ch) (1 << (ch)) +#define PWM_PWR_INT_EN(ch) (1 << ((ch) + 4 )) + +#define PWM_DISABLE (0 << PWM_PWM0_CTRL_PWM_EN_SHIFT) +#define PWM_ENABLE (1 << PWM_PWM0_CTRL_PWM_EN_SHIFT) + +#define PWM_MODE_SHIFT (1) +#define PWM_MODE_MASK (0x3U << PWM_MODE_SHIFT) + +#define PWM_DUTY_POSTIVE (1 << PWM_PWM0_CTRL_DUTY_POL_SHIFT) +#define PWM_DUTY_NEGATIVE (0 << PWM_PWM0_CTRL_DUTY_POL_SHIFT) +#define PWM_DUTY_MASK (1 << 3) + +#define PWM_INACTIVE_POSTIVE (1 << PWM_PWM0_CTRL_INACTIVE_POL_SHIFT) +#define PWM_INACTIVE_NEGATIVE (0 << PWM_PWM0_CTRL_INACTIVE_POL_SHIFT) +#define PWM_INACTIVE_MASK (1 << 4) + +#define PWM_OUTPUT_LEFT (0 << PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT) +#define PWM_OUTPUT_CENTER (1 << PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT) + +#define PWM_UNLOCK (0 << PWM_PWM0_CTRL_CONLOCK_SHIFT) +#define PWM_LOCK (1 << PWM_PWM0_CTRL_CONLOCK_SHIFT) + +#define PWM_LP_DISABLE (0 << PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT) +#define PWM_LP_ENABLE (1 << PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT) + +#define PWM_SEL_SRC_CLK (0 << PWM_PWM0_CTRL_CLK_SEL_SHIFT) +#define PWM_SEL_SCALE_CLK (1 << PWM_PWM0_CTRL_CLK_SEL_SHIFT) + +#define PWM_CTRL_SCALE_SHIFT (PWM_PWM0_CTRL_SCALE_SHIFT) +#define PWM_CTRL_SCALE_MASK (PWM_PWM0_CTRL_SCALE_MASK) + +#define PWM_PWRMATCH_MAX_SHIFT (PWM_PWRMATCH_LPRE_CNT_MIN_SHIFT) + +#define PWM_CTRL_OFFSET (PWM_PWM0_CTRL_OFFSET) +#define PWM_PERIOD_HPR_OFFSET (PWM_PWM0_PERIOD_HPR_OFFSET) +#define PWM_DUTY_LPR_OFFSET (PWM_PWM0_DUTY_LPR_OFFSET) + +#define PWM_ONE_SHOT_MODE (0) +#define PWM_CONTINUOUS_MODE (1) +#define PWM_CAPTURE_MODE (2) + +#define FREQUENCY_24M (24000000) + +#define PWM_MAX_CONTROLLER_NUM (4) + +UINTN mPwmControllerBase[PWM_MAX_CONTROLLER_NUM] = { + RK3588_PWM0_BASE, + RK3588_PWM1_BASE, + RK3588_PWM2_BASE, + RK3588_PWM3_BASE +}; + +RETURN_STATUS +EFIAPI +RkPwmSetConfig ( + IN PWM_DATA *Data + ) +{ + UINTN Base = mPwmControllerBase[Data->ControllerID]; + UINT32 Ctrl; + UINT32 PeriodCycle, DutyCycle; + UINT64 ChannelOffset = Data->ChannelID * 0x10; + + PeriodCycle = ((UINT64)FREQUENCY_24M * Data->PeriodNs / 1000000000); + DutyCycle = ((UINT64)FREQUENCY_24M * Data->DutyNs / 1000000000); + + Ctrl = MmioRead32(Base + ChannelOffset + PWM_CTRL_OFFSET); + Ctrl |= PWM_LOCK; + MmioWrite32(Base + ChannelOffset + PWM_CTRL_OFFSET, Ctrl); + MicroSecondDelay (1); + + MmioWrite32(Base + ChannelOffset + PWM_PERIOD_HPR_OFFSET, PeriodCycle); + MmioWrite32(Base + ChannelOffset + PWM_DUTY_LPR_OFFSET, DutyCycle); + + Ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); + + if (Data->Polarity) { + Ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; + } else { + Ctrl |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; + } + + Ctrl &= ~PWM_LOCK; + MmioWrite32(Base + ChannelOffset + PWM_CTRL_OFFSET, Ctrl); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +EFIAPI +RkPwmEnable ( + IN PWM_DATA *Data + ) +{ + UINTN Base = mPwmControllerBase[Data->ControllerID]; + UINT32 Ctrl; + UINT64 ChannelOffset = Data->ChannelID * 0x10; + + Ctrl = MmioRead32(Base + ChannelOffset + PWM_CTRL_OFFSET); + Ctrl &= ~PWM_MODE_MASK; + Ctrl |= (PWM_CONTINUOUS_MODE << PWM_MODE_SHIFT) | PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE; + + MmioWrite32(Base + ChannelOffset + PWM_CTRL_OFFSET, Ctrl); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +EFIAPI +RkPwmDisable ( + IN PWM_DATA *Data + ) +{ + UINTN Base = mPwmControllerBase[Data->ControllerID]; + UINT32 Ctrl; + UINT64 ChannelOffset = Data->ChannelID * 0x10; + + Ctrl = MmioRead32(Base + ChannelOffset + PWM_CTRL_OFFSET); + Ctrl &= ~PWM_ENABLE; + + MmioWrite32(Base + ChannelOffset + PWM_CTRL_OFFSET, Ctrl); + + return RETURN_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.inf new file mode 100644 index 0000000..a02d6f1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PWMLib/PWMLib.inf @@ -0,0 +1,35 @@ +/** @file + Component description file for Rockchip PWM Driver. + + Copyright (c) 2022 Rockchip Electronics Co. Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PWMLib + FILE_GUID = 2f34109a-6f62-11ec-ac42-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PWMLib + +[Sources.common] + PWMLib.c + +[LibraryClasses] + DebugLib + IoLib + TimerLib + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[BuildOptions] + +[Pcd] + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.c new file mode 100644 index 0000000..f17b1e5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.c @@ -0,0 +1,416 @@ +/** @file + * + * Boot Manager device description handler. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RKATAG_BOOTDEV_TYPE mBootDeviceType; + +CHAR16 mBootDescUefiPrefix[] = L"UEFI "; +CHAR16 mBootDescGenericManufacturer[] = L"Generic"; +CHAR16 mBootDescEmmc[] = L" eMMC"; +CHAR16 mBootDescEmmcUserData[] = L" eMMC User Data"; +CHAR16 mBootDescEmmcBoot1[] = L" eMMC Boot 1"; +CHAR16 mBootDescEmmcBoot2[] = L" eMMC Boot 2"; +CHAR16 mBootDescEmmcGp1[] = L" eMMC GP 1"; +CHAR16 mBootDescEmmcGp2[] = L" eMMC GP 2"; +CHAR16 mBootDescEmmcGp3[] = L" eMMC GP 3"; +CHAR16 mBootDescEmmcGp4[] = L" eMMC GP 4"; +CHAR16 mBootDescSd[] = L" SD Device"; +CHAR16 mBootDescFirmwareSuffix[] = L" [Fw]"; + +typedef struct { + UINT8 Id; + CHAR16 *Name; +} SDMMC_MANUFACTURER; + +// +// List based on: +// - https://www.cameramemoryspeed.com/sd-memory-card-faq/reading-sd-card-cid-serial-psn-internal-numbers/ +// - https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c +// +STATIC SDMMC_MANUFACTURER mSdManufacturers[] = { + { 0x01, L"Panasonic" }, + { 0x02, L"Toshiba/Kingston/Viking" }, + { 0x03, L"SanDisk" }, + { 0x08, L"Silicon Power" }, + { 0x18, L"Infineon" }, + { 0x1b, L"Transcend/Samsung" }, + { 0x1c, L"Transcend" }, + { 0x1d, L"Corsair/AData" }, + { 0x1e, L"Transcend" }, + { 0x1f, L"Kingston" }, + { 0x27, L"Delkin/Phison" }, + { 0x28, L"Lexar" }, + { 0x30, L"SanDisk" }, + { 0x31, L"Silicon Power" }, + { 0x33, L"STMicroelectronics" }, + { 0x41, L"Kingston" }, + { 0x6f, L"STMicroelectronics" }, + { 0x74, L"Transcend" }, + { 0x76, L"Patriot" }, + { 0x82, L"Gobe/Sony" }, + { 0x9c, L"Angelbird/Hoodman" }, +}; + +STATIC SDMMC_MANUFACTURER mMmcManufacturers[] = { + { 0x00, L"SanDisk" }, + { 0x02, L"Kingston/SanDisk" }, + { 0x03, L"Toshiba" }, + { 0x11, L"Toshiba" }, + { 0x13, L"Micron" }, + { 0x15, L"Samsung" }, + { 0x37, L"KingMax" }, + { 0x44, L"ATP" }, + { 0x45, L"SanDisk" }, + { 0x2c, L"Kingston" }, + { 0x70, L"Kingston" }, + { 0x88, L"Foresee" }, + { 0x9b, L"YMTC" }, + { 0xd6, L"Foresee" }, + { 0xfe, L"Micron" }, +}; + +STATIC +NON_DISCOVERABLE_DEVICE * +GetNonDiscoverableDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + NON_DISCOVERABLE_DEVICE *Device; + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + + CurrentDevicePath = DevicePath; + + if (DevicePath->Type != HARDWARE_DEVICE_PATH + || DevicePath->SubType != HW_VENDOR_DP) { + return NULL; + } + + Status = gBS->LocateDevicePath (&gEdkiiNonDiscoverableDeviceProtocolGuid, + &CurrentDevicePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + return NULL; + } + + Status = gBS->HandleProtocol (DeviceHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **) &Device); + if (EFI_ERROR (Status)) { + return NULL; + } + + return Device; +} + +STATIC +BOOLEAN +CheckIsBootDevice ( + IN NON_DISCOVERABLE_DEVICE *Device + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + Descriptor = &Device->Resources[0]; + + if (Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR || + Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { + return FALSE; + } + + if (mBootDeviceType == RkAtagBootDevTypeEmmc) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdDwcSdhciBaseAddress); + } + if (mBootDeviceType == RkAtagBootDevTypeSd0) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdRkSdmmcBaseAddress); + } + + return FALSE; +} + +STATIC +EFI_STATUS +GetDiskInfoInquiryData ( + IN EFI_HANDLE Handle, + OUT VOID *InquiryData, + IN UINT32 InquiryDataSize + ) +{ + EFI_STATUS Status; + EFI_DISK_INFO_PROTOCOL *DiskInfo; + + if (InquiryData == NULL || InquiryDataSize == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->HandleProtocol (Handle, + &gEfiDiskInfoProtocolGuid, (VOID **) &DiskInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // InquiryDataSize is set to the expected size if EFI_BUFFER_TOO_SMALL + // is returned but we'll always call with the correct size. + Status = DiskInfo->Inquiry (DiskInfo, InquiryData, &InquiryDataSize); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +STATIC +CHAR16 * +GetSdMmcManufacturerName ( + IN UINT8 Id, + IN BOOLEAN IsMmc + ) +{ + SDMMC_MANUFACTURER *List; + UINT8 Count; + + List = IsMmc ? mMmcManufacturers : mSdManufacturers; + Count = IsMmc ? ARRAY_SIZE (mMmcManufacturers) + : ARRAY_SIZE (mSdManufacturers); + + for (UINT8 Index; Index < Count; ++Index) { + if (List[Index].Id == Id) { + return List[Index].Name; + } + } + return mBootDescGenericManufacturer; +} + +STATIC +EFI_STATUS +AsciiSwapAppendToUnicode ( + IN CHAR8 *Source, + IN UINTN Length, + IN CHAR16 *Destination, + IN UINTN DestMax + ) +{ + EFI_STATUS Status; + CHAR8 Temp; + UINTN ConvertedLength; + + if (StrLen (Destination) + Length + 1 > DestMax) { + return EFI_BUFFER_TOO_SMALL; + } + + for (UINTN Index = 0; Index < Length / 2; ++Index) { + Temp = Source[Index]; + Source[Index] = Source[Length - 1 - Index]; + Source[Length - 1 - Index] = Temp; + } + + Status = AsciiStrnToUnicodeStrS (Source, Length, + Destination + StrLen (Destination), + DestMax, &ConvertedLength); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +STATIC +CHAR16 * +GetEmmcDescription ( + CONTROLLER_DEVICE_PATH *DevicePath + ) +{ + switch (DevicePath->ControllerNumber) { + case EmmcPartitionUserData: + return mBootDescEmmcUserData; + case EmmcPartitionBoot1: + return mBootDescEmmcBoot1; + case EmmcPartitionBoot2: + return mBootDescEmmcBoot2; + case EmmcPartitionGP1: + return mBootDescEmmcGp1; + case EmmcPartitionGP2: + return mBootDescEmmcGp2; + case EmmcPartitionGP3: + return mBootDescEmmcGp3; + case EmmcPartitionGP4: + return mBootDescEmmcGp4; + } + return mBootDescEmmc; +} + +STATIC +CHAR16 * +GetSdMmcUefiBootDescription ( + IN CHAR16 *ManufacturerName, + IN UINT8 *ProductName, + IN UINT8 ProductNameLength, + IN UINT8 SerialNumber[4], + IN CHAR16 *DeviceType, + IN BOOLEAN IsBootDevice + ) +{ + CHAR16 *Desc; + UINTN DescSize; + UINT32 Serial32; + + Desc = mBootDescUefiPrefix; + + DescSize = StrSize (Desc) - sizeof (CHAR16) // "UEFI " + + StrSize (ManufacturerName) - sizeof (CHAR16) // "Samsung" + + sizeof (CHAR16) // " " + + ProductNameLength * sizeof (CHAR16) // "BJTD4R" + + sizeof (CHAR16) // " " + + sizeof (UINT32) * 2 * sizeof (CHAR16) // "00000000" + + StrSize (DeviceType) - sizeof (CHAR16); // " EMMC User Data" + if (IsBootDevice) { + DescSize += StrSize (mBootDescFirmwareSuffix) - sizeof (CHAR16); // " [Fw]" + } + DescSize += sizeof (CHAR16); // '\0' + + Desc = AllocateCopyPool (DescSize, Desc); + if (Desc == NULL) { + return NULL; + } + + StrCatS (Desc, DescSize / sizeof (CHAR16), ManufacturerName); + StrCatS (Desc, DescSize / sizeof (CHAR16), L" "); + + AsciiSwapAppendToUnicode ((CHAR8 *) ProductName, + ProductNameLength, + Desc, + DescSize / sizeof (CHAR16)); + + Serial32 = (SerialNumber[0] + | (SerialNumber[1]) << 8 + | (SerialNumber[2]) << 16 + | (SerialNumber[3] << 24)); + + StrCatS (Desc, DescSize / sizeof (CHAR16), L" "); + + UnicodeValueToStringS (Desc + StrLen (Desc), + DescSize - StrSize (Desc), + RADIX_HEX | PREFIX_ZERO, + Serial32, 8); + + StrCatS (Desc, DescSize / sizeof (CHAR16), DeviceType); + + if (IsBootDevice) { + StrCatS (Desc, DescSize / sizeof (CHAR16), mBootDescFirmwareSuffix); + } + + return Desc; +} + +STATIC +CHAR16 * +EFIAPI +PlatformBootDescriptionHandler ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *DefaultDescription + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + NON_DISCOVERABLE_DEVICE *NonDiscoverableDevice; + BOOLEAN IsBootDevice; + CHAR16 *Desc; + EMMC_CID EmmcCid; + CHAR16 *EmmcDesc; + SD_CID SdCid; + + DevicePath = DevicePathFromHandle (Handle); + + NonDiscoverableDevice = GetNonDiscoverableDevice (DevicePath); + if (NonDiscoverableDevice == NULL) { + return NULL; + } + + IsBootDevice = CheckIsBootDevice (NonDiscoverableDevice); + + DevicePath = NextDevicePathNode (DevicePath); + + if (DevicePath->SubType == MSG_EMMC_DP) { + Status = GetDiskInfoInquiryData (Handle, &EmmcCid, sizeof (EMMC_CID)); + if (EFI_ERROR (Status)) { + return NULL; + } + + EmmcDesc = mBootDescEmmc; + + DevicePath = NextDevicePathNode (DevicePath); + if (DevicePath->SubType == HW_CONTROLLER_DP) { + if (((CONTROLLER_DEVICE_PATH *) DevicePath)->ControllerNumber != EmmcPartitionUserData) { + // + // There can only be one boot device. + // eMMC has multiple partitions, but I don't know if it's possible + // to load UEFI from anything other than UserData. + // If it turns out to be a possibility, we'd need to create a protocol + // for RkFvbDxe that would allow getting the Device Path of the block + // device that holds the NVRAM. + // + IsBootDevice = FALSE; + } + + EmmcDesc = GetEmmcDescription ((CONTROLLER_DEVICE_PATH *) DevicePath); + } + + Desc = GetSdMmcUefiBootDescription ( + GetSdMmcManufacturerName (EmmcCid.ManufacturerId, TRUE), + EmmcCid.ProductName, + ARRAY_SIZE (EmmcCid.ProductName), + EmmcCid.ProductSerialNumber, + EmmcDesc, + IsBootDevice); + + } else if (DevicePath->SubType == MSG_SD_DP) { + Status = GetDiskInfoInquiryData (Handle, &SdCid, sizeof (SD_CID)); + if (EFI_ERROR (Status)) { + return NULL; + } + + Desc = GetSdMmcUefiBootDescription ( + GetSdMmcManufacturerName (SdCid.ManufacturerId, FALSE), + SdCid.ProductName, + ARRAY_SIZE (SdCid.ProductName), + SdCid.ProductSerialNumber, + mBootDescSd, + IsBootDevice); + } else { + return NULL; + } + + return Desc; +} + +EFI_STATUS +EFIAPI +PlatformBootDescriptionLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + RKATAG_BOOTDEV *BootDevice; + + BootDevice = RkAtagsGetBootDev (); + mBootDeviceType = BootDevice != NULL ? BootDevice->DevType : RkAtagBootDevTypeUnknown; + + return EfiBootManagerRegisterBootDescriptionHandler (PlatformBootDescriptionHandler); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.inf new file mode 100644 index 0000000..035f01a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.inf @@ -0,0 +1,42 @@ +#/** @file +# +# Boot Manager device description handler. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = PlatformBootDescriptionLib + FILE_GUID = 8d63c2d3-b621-41f1-80fe-037c46d23790 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = PlatformBootDescriptionLibConstructor + +[Sources] + PlatformBootDescriptionLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + UefiLib + UefiBootServicesTableLib + UefiBootManagerLib + MemoryAllocationLib + DevicePathLib + RkAtagsLib + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskInfoProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.c new file mode 100644 index 0000000..c289907 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.c @@ -0,0 +1,1331 @@ +/** @file + Implementation for PlatformBootManagerLib library class interfaces. + + Copyright (C) 2015-2016, Red Hat, Inc. + Copyright (c) 2014 - 2021, ARM Ltd. All rights reserved.
    + Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
    + Copyright (c) 2016, Linaro Ltd. All rights reserved.
    + Copyright (c) 2021, Semihalf All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PlatformBm.h" + +#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) } + +#pragma pack (1) +typedef struct { + VENDOR_DEVICE_PATH SerialDxe; + UART_DEVICE_PATH Uart; + VENDOR_DEFINED_DEVICE_PATH TermType; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_SERIAL_CONSOLE; +#pragma pack () + +STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = { + // + // VENDOR_DEVICE_PATH SerialDxe + // + { + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) }, + EDKII_SERIAL_PORT_LIB_VENDOR_GUID + }, + + // + // UART_DEVICE_PATH Uart + // + { + { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) }, + 0, // Reserved + 0, // BaudRate + 0, // DataBits + 0, // Parity + 0, // StopBits + }, + + // + // VENDOR_DEFINED_DEVICE_PATH TermType + // + { + { + MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, + DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH) + } + // + // Guid to be filled in dynamically + // + }, + + // + // EFI_DEVICE_PATH_PROTOCOL End + // + { + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, + DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) + } +}; + +#pragma pack (1) +typedef struct { + USB_CLASS_DEVICE_PATH Keyboard; + EFI_DEVICE_PATH_PROTOCOL End; +} PLATFORM_USB_KEYBOARD; +#pragma pack () + +STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = { + // + // USB_CLASS_DEVICE_PATH Keyboard + // + { + { + MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP, + DP_NODE_LEN (USB_CLASS_DEVICE_PATH) + }, + 0xFFFF, // VendorId: any + 0xFFFF, // ProductId: any + 3, // DeviceClass: HID + 1, // DeviceSubClass: boot + 1 // DeviceProtocol: keyboard + }, + + // + // EFI_DEVICE_PATH_PROTOCOL End + // + { + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, + DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL) + } +}; + +/** + Check if the handle satisfies a particular condition. + + @param[in] Handle The handle to check. + @param[in] ReportText A caller-allocated string passed in for reporting + purposes. It must never be NULL. + + @retval TRUE The condition is satisfied. + @retval FALSE Otherwise. This includes the case when the condition could not + be fully evaluated due to an error. +**/ +typedef +BOOLEAN +(EFIAPI *FILTER_FUNCTION)( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ); + +/** + Process a handle. + + @param[in] Handle The handle to process. + @param[in] ReportText A caller-allocated string passed in for reporting + purposes. It must never be NULL. +**/ +typedef +VOID +(EFIAPI *CALLBACK_FUNCTION)( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ); + +/** + Locate all handles that carry the specified protocol, filter them with a + callback function, and pass each handle that passes the filter to another + callback. + + @param[in] ProtocolGuid The protocol to look for. + + @param[in] Filter The filter function to pass each handle to. If this + parameter is NULL, then all handles are processed. + + @param[in] Process The callback function to pass each handle to that + clears the filter. +**/ +STATIC +VOID +FilterAndProcess ( + IN EFI_GUID *ProtocolGuid, + IN FILTER_FUNCTION Filter OPTIONAL, + IN CALLBACK_FUNCTION Process + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN NoHandles; + UINTN Idx; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + ProtocolGuid, + NULL /* SearchKey */, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + // + // This is not an error, just an informative condition. + // + DEBUG (( + DEBUG_VERBOSE, + "%a: %g: %r\n", + __FUNCTION__, + ProtocolGuid, + Status + )); + return; + } + + ASSERT (NoHandles > 0); + for (Idx = 0; Idx < NoHandles; ++Idx) { + CHAR16 *DevicePathText; + STATIC CHAR16 Fallback[] = L""; + + // + // The ConvertDevicePathToText() function handles NULL input transparently. + // + DevicePathText = ConvertDevicePathToText ( + DevicePathFromHandle (Handles[Idx]), + FALSE, // DisplayOnly + FALSE // AllowShortcuts + ); + if (DevicePathText == NULL) { + DevicePathText = Fallback; + } + + if ((Filter == NULL) || Filter (Handles[Idx], DevicePathText)) { + Process (Handles[Idx], DevicePathText); + } + + if (DevicePathText != Fallback) { + FreePool (DevicePathText); + } + } + + gBS->FreePool (Handles); +} + +/** + This FILTER_FUNCTION checks if a handle corresponds to a PCI display device. +**/ +STATIC +BOOLEAN +EFIAPI +IsPciDisplay ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + + Status = gBS->HandleProtocol ( + Handle, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + if (EFI_ERROR (Status)) { + // + // This is not an error worth reporting. + // + return FALSE; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0 /* Offset */, + sizeof Pci / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status)); + return FALSE; + } + + return IS_PCI_DISPLAY (&Pci); +} + +/** + This FILTER_FUNCTION checks if a handle corresponds to a non-discoverable + USB host controller. +**/ +STATIC +BOOLEAN +EFIAPI +IsUsbHost ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ) +{ + NON_DISCOVERABLE_DEVICE *Device; + EFI_STATUS Status; + + Status = gBS->HandleProtocol ( + Handle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **)&Device + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (CompareGuid (Device->Type, &gEdkiiNonDiscoverableUhciDeviceGuid) || + CompareGuid (Device->Type, &gEdkiiNonDiscoverableEhciDeviceGuid) || + CompareGuid (Device->Type, &gEdkiiNonDiscoverableXhciDeviceGuid)) + { + return TRUE; + } + + return FALSE; +} + +/** + This FILTER_FUNCTION checks if the Block I/O protocol handle + corresponds to that of the boot SD/eMMC device. + + This code is almost identical to FvbCheckIsBootDevice from RkFvbDxe. +**/ +STATIC +BOOLEAN +EFIAPI +IsSdBootBlockIo ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DeviceHandle; + NON_DISCOVERABLE_DEVICE *Device; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + RKATAG_BOOTDEV *BootDevice; + + BootDevice = RkAtagsGetBootDev (); + if (BootDevice == NULL) { + return FALSE; + } + + DevicePath = DevicePathFromHandle (Handle); + + if (DevicePath->Type != HARDWARE_DEVICE_PATH + || DevicePath->SubType != HW_VENDOR_DP) { + return FALSE; + } + + Status = gBS->LocateDevicePath (&gEdkiiNonDiscoverableDeviceProtocolGuid, + &DevicePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = gBS->HandleProtocol (DeviceHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **) &Device); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Descriptor = &Device->Resources[0]; + + if (Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR || + Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { + return FALSE; + } + + if (BootDevice->DevType == RkAtagBootDevTypeEmmc) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdDwcSdhciBaseAddress); + } + if (BootDevice->DevType == RkAtagBootDevTypeSd0) { + return Descriptor->AddrRangeMin == PcdGet32 (PcdRkSdmmcBaseAddress); + } + + return FALSE; +} + +/** + This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking + the matching driver to produce all first-level child handles. +**/ +STATIC +VOID +EFIAPI +Connect ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ) +{ + EFI_STATUS Status; + + Status = gBS->ConnectController ( + Handle, // ControllerHandle + NULL, // DriverImageHandle + NULL, // RemainingDevicePath -- produce all children + FALSE // Recursive + ); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, + "%a: %s: %r\n", + __FUNCTION__, + ReportText, + Status + )); +} + +/** + This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the + handle, and adds it to ConOut and ErrOut. +**/ +STATIC +VOID +EFIAPI +AddOutput ( + IN EFI_HANDLE Handle, + IN CONST CHAR16 *ReportText + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + DevicePath = DevicePathFromHandle (Handle); + if (DevicePath == NULL) { + DEBUG (( + DEBUG_ERROR, + "%a: %s: handle %p: device path not found\n", + __FUNCTION__, + ReportText, + Handle + )); + return; + } + + Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: %s: adding to ConOut: %r\n", + __FUNCTION__, + ReportText, + Status + )); + return; + } + + Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: %s: adding to ErrOut: %r\n", + __FUNCTION__, + ReportText, + Status + )); + return; + } + + DEBUG (( + DEBUG_VERBOSE, + "%a: %s: added to ConOut and ErrOut\n", + __FUNCTION__, + ReportText + )); +} + +STATIC +VOID +PlatformRegisterFvBootOption ( + CONST EFI_GUID *FileGuid, + CHAR16 *Description, + UINT32 Attributes, + EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + INTN OptionIndex; + EFI_BOOT_MANAGER_LOAD_OPTION NewOption; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + Status = gBS->HandleProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + ASSERT_EFI_ERROR (Status); + + EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid); + DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle); + ASSERT (DevicePath != NULL); + DevicePath = AppendDevicePathNode ( + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&FileNode + ); + ASSERT (DevicePath != NULL); + + Status = EfiBootManagerInitializeLoadOption ( + &NewOption, + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + Attributes, + Description, + DevicePath, + NULL, + 0 + ); + ASSERT_EFI_ERROR (Status); + FreePool (DevicePath); + + BootOptions = EfiBootManagerGetLoadOptions ( + &BootOptionCount, + LoadOptionTypeBoot + ); + + OptionIndex = EfiBootManagerFindLoadOption ( + &NewOption, + BootOptions, + BootOptionCount + ); + + if (OptionIndex == -1) { + Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN); + ASSERT_EFI_ERROR (Status); + Status = EfiBootManagerAddKeyOptionVariable ( + NULL, + (UINT16)NewOption.OptionNumber, + 0, + Key, + NULL + ); + ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); + } + + EfiBootManagerFreeLoadOption (&NewOption); + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +} + +STATIC +VOID +GetPlatformOptions ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + EFI_INPUT_KEY *BootKeys; + PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager; + UINTN CurrentBootOptionCount; + UINTN Index; + UINTN BootCount; + + Status = gBS->LocateProtocol ( + &gPlatformBootManagerProtocolGuid, + NULL, + (VOID **)&PlatformBootManager + ); + if (EFI_ERROR (Status)) { + return; + } + + Status = PlatformBootManager->GetPlatformBootOptionsAndKeys ( + &BootCount, + &BootOptions, + &BootKeys + ); + if (EFI_ERROR (Status)) { + return; + } + + // + // Fetch the existent boot options. If there are none, CurrentBootCount + // will be zeroed. + // + CurrentBootOptions = EfiBootManagerGetLoadOptions ( + &CurrentBootOptionCount, + LoadOptionTypeBoot + ); + // + // Process the platform boot options. + // + for (Index = 0; Index < BootCount; Index++) { + INTN Match; + UINTN BootOptionNumber; + + // + // If there are any preexistent boot options, and the subject platform boot + // option is already among them, then don't try to add it. Just get its + // assigned boot option number so we can associate a hotkey with it. Note + // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions + // == NULL) if (CurrentBootCount == 0). + // + Match = EfiBootManagerFindLoadOption ( + &BootOptions[Index], + CurrentBootOptions, + CurrentBootOptionCount + ); + if (Match >= 0) { + BootOptionNumber = CurrentBootOptions[Match].OptionNumber; + } else { + // + // Add the platform boot options as a new one, at the end of the boot + // order. Note that if the platform provided this boot option with an + // unassigned option number, then the below function call will assign a + // number. + // + Status = EfiBootManagerAddLoadOptionVariable ( + &BootOptions[Index], + MAX_UINTN + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: failed to register \"%s\": %r\n", + __FUNCTION__, + BootOptions[Index].Description, + Status + )); + continue; + } + + BootOptionNumber = BootOptions[Index].OptionNumber; + } + + // + // Register a hotkey with the boot option, if requested. + // + if (BootKeys[Index].UnicodeChar == L'\0') { + continue; + } + + Status = EfiBootManagerAddKeyOptionVariable ( + NULL, + BootOptionNumber, + 0, + &BootKeys[Index], + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: failed to register hotkey for \"%s\": %r\n", + __FUNCTION__, + BootOptions[Index].Description, + Status + )); + } + } + + EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount); + EfiBootManagerFreeLoadOptions (BootOptions, BootCount); + FreePool (BootKeys); +} + +/** + Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options + whose device paths do not resolve exactly to an FvFile in the system. + + This removes any boot options that point to binaries built into the firmware + and have become stale due to any of the following: + - DXEFV's base address or size changed (historical), + - DXEFV's FvNameGuid changed, + - the FILE_GUID of the pointed-to binary changed, + - the referenced binary is no longer built into the firmware. + + EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only + avoids exact duplicates. +**/ +VOID +RemoveStaleFvFileOptions ( + VOID + ) +{ + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + UINTN Index; + + BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, + LoadOptionTypeBoot); + + for (Index = 0; Index < BootOptionCount; ++Index) { + EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode; + EFI_STATUS Status; + EFI_HANDLE FvHandle; + + // + // If the device path starts with neither MemoryMapped(...) nor Fv(...), + // then keep the boot option. + // + Node1 = BootOptions[Index].FilePath; + if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH && + DevicePathSubType (Node1) == HW_MEMMAP_DP) && + !(DevicePathType (Node1) == MEDIA_DEVICE_PATH && + DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) { + continue; + } + + // + // If the second device path node is not FvFile(...), then keep the boot + // option. + // + Node2 = NextDevicePathNode (Node1); + if (DevicePathType (Node2) != MEDIA_DEVICE_PATH || + DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) { + continue; + } + + // + // Locate the Firmware Volume2 protocol instance that is denoted by the + // boot option. If this lookup fails (i.e., the boot option references a + // firmware volume that doesn't exist), then we'll proceed to delete the + // boot option. + // + SearchNode = Node1; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, + &SearchNode, &FvHandle); + + if (!EFI_ERROR (Status)) { + // + // The firmware volume was found; now let's see if it contains the FvFile + // identified by GUID. + // + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode; + UINTN BufferSize; + EFI_FV_FILETYPE FoundType; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + UINT32 AuthenticationStatus; + + Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, + (VOID **)&FvProtocol); + ASSERT_EFI_ERROR (Status); + + FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2; + // + // Buffer==NULL means we request metadata only: BufferSize, FoundType, + // FileAttributes. + // + Status = FvProtocol->ReadFile ( + FvProtocol, + &FvFileNode->FvFileName, // NameGuid + NULL, // Buffer + &BufferSize, + &FoundType, + &FileAttributes, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + // + // The FvFile was found. Keep the boot option. + // + continue; + } + } + + // + // Delete the boot option. + // + Status = EfiBootManagerDeleteLoadOptionVariable ( + BootOptions[Index].OptionNumber, LoadOptionTypeBoot); + DEBUG_CODE ( + CHAR16 *DevicePathString; + + DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath, + FALSE, FALSE); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE, + "%a: removing stale Boot#%04x %s: %r\n", + __FUNCTION__, + (UINT32)BootOptions[Index].OptionNumber, + DevicePathString == NULL ? L"" : DevicePathString, + Status + )); + if (DevicePathString != NULL) { + FreePool (DevicePathString); + } + ); + } + + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +} + +STATIC +VOID +PlatformRegisterOptionsAndKeys ( + VOID + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Enter; + EFI_INPUT_KEY F2; + EFI_INPUT_KEY Esc; + EFI_BOOT_MANAGER_LOAD_OPTION BootOption; + + GetPlatformOptions (); + + // + // Register ENTER as CONTINUE key + // + Enter.ScanCode = SCAN_NULL; + Enter.UnicodeChar = CHAR_CARRIAGE_RETURN; + Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); + ASSERT_EFI_ERROR (Status); + + // + // Map F2 and ESC to Boot Manager Menu + // + F2.ScanCode = SCAN_F2; + F2.UnicodeChar = CHAR_NULL; + Esc.ScanCode = SCAN_ESC; + Esc.UnicodeChar = CHAR_NULL; + Status = EfiBootManagerGetBootManagerMenu (&BootOption); + ASSERT_EFI_ERROR (Status); + Status = EfiBootManagerAddKeyOptionVariable ( + NULL, + (UINT16)BootOption.OptionNumber, + 0, + &F2, + NULL + ); + ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); + Status = EfiBootManagerAddKeyOptionVariable ( + NULL, + (UINT16)BootOption.OptionNumber, + 0, + &Esc, + NULL + ); + ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED); +} + +// +// BDS Platform Functions +// + +/** + Do the platform init, can be customized by OEM/IBV + Possible things that can be done in PlatformBootManagerBeforeConsole: + > Update console variable: 1. include hot-plug devices; + > 2. Clear ConIn and add SOL for AMT + > Register new Driver#### or Boot#### + > Register new Key####: e.g.: F12 + > Signal ReadyToLock event + > Authentication action: 1. connect Auth devices; + > 2. Identify auto logon user. +**/ +VOID +EFIAPI +PlatformBootManagerBeforeConsole ( + VOID + ) +{ + // + // Signal EndOfDxe PI Event + // + EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); + + // + // Dispatch deferred images after EndOfDxe event. + // + EfiBootManagerDispatchDeferredImages (); + + // + // Add the hardcoded short-form USB keyboard device path to ConIn. + // This must be done prior to connecting any USB bus controllers, because + // when a keyboard gets installed, ConPlatformDxe will immediately check + // that its device path exists in the ConIn variable before enabling input + // from it. Since this variable is not initially populated at first boot, + // we would otherwise end up with no keyboard input during BDS countdown. + // + EfiBootManagerUpdateConsoleVariable ( + ConIn, + (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, + NULL + ); + + // + // Locate the PCI root bridges and make the PCI bus driver connect each, + // non-recursively. This will produce a number of child handles with PciIo on + // them. + // + FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect); + + // + // Find all display class PCI devices (using the handles from the previous + // step), and connect them non-recursively. This should produce a number of + // child handles with GOPs on them. + // + FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect); + + // + // Now add the device path of all handles with GOP on them to ConOut and + // ErrOut. + // + FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput); + + // + // The core BDS code connects short-form USB device paths by explicitly + // looking for handles with PCI I/O installed, and checking the PCI class + // code whether it matches the one for a USB host controller. This means + // non-discoverable USB host controllers need to have the non-discoverable + // PCI driver attached first. + // + FilterAndProcess (&gEdkiiNonDiscoverableDeviceProtocolGuid, IsUsbHost, Connect); + + // + // Connect USB OHCI controller(s) + // + FilterAndProcess (&gOhciDeviceProtocolGuid, NULL, Connect); + + // + // Connect the Block I/O device produced by the SD/eMMC device that + // booted UEFI. We don't want BDS to ignore this device as it would + // prevent RkFvbDxe from detecting it and dumping the NVRAM variables + // in time. + // + FilterAndProcess (&gEfiBlockIoProtocolGuid, IsSdBootBlockIo, Connect); + + // + // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut. + // + STATIC_ASSERT ( + FixedPcdGet8 (PcdDefaultTerminalType) == 4, + "PcdDefaultTerminalType must be TTYTERM" + ); + STATIC_ASSERT ( + FixedPcdGet8 (PcdUartDefaultParity) != 0, + "PcdUartDefaultParity must be set to an actual value, not 'default'" + ); + STATIC_ASSERT ( + FixedPcdGet8 (PcdUartDefaultStopBits) != 0, + "PcdUartDefaultStopBits must be set to an actual value, not 'default'" + ); + + mSerialConsole.Uart.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); + mSerialConsole.Uart.DataBits = PcdGet8 (PcdUartDefaultDataBits); + mSerialConsole.Uart.Parity = PcdGet8 (PcdUartDefaultParity); + mSerialConsole.Uart.StopBits = PcdGet8 (PcdUartDefaultStopBits); + + CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid); + + EfiBootManagerUpdateConsoleVariable ( + ConIn, + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, + NULL + ); + EfiBootManagerUpdateConsoleVariable ( + ConOut, + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, + NULL + ); + EfiBootManagerUpdateConsoleVariable ( + ErrOut, + (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, + NULL + ); + + // + // Register platform-specific boot options and keyboard shortcuts. + // + PlatformRegisterOptionsAndKeys (); +} + +STATIC +VOID +HandleCapsules ( + VOID + ) +{ + ESRT_MANAGEMENT_PROTOCOL *EsrtManagement; + EFI_PEI_HOB_POINTERS HobPointer; + EFI_CAPSULE_HEADER *CapsuleHeader; + BOOLEAN NeedReset; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__)); + + Status = gBS->LocateProtocol ( + &gEsrtManagementProtocolGuid, + NULL, + (VOID **)&EsrtManagement + ); + if (!EFI_ERROR (Status)) { + EsrtManagement->SyncEsrtFmp (); + } + + // + // Find all capsule images from hob + // + HobPointer.Raw = GetHobList (); + NeedReset = FALSE; + while ((HobPointer.Raw = GetNextHob ( + EFI_HOB_TYPE_UEFI_CAPSULE, + HobPointer.Raw + )) != NULL) + { + CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress; + + Status = ProcessCapsuleImage (CapsuleHeader); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: failed to process capsule %p - %r\n", + __FUNCTION__, + CapsuleHeader, + Status + )); + return; + } + + NeedReset = TRUE; + HobPointer.Raw = GET_NEXT_HOB (HobPointer); + } + + if (NeedReset) { + DEBUG (( + DEBUG_WARN, + "%a: capsule update successful, resetting ...\n", + __FUNCTION__ + )); + + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + CpuDeadLoop (); + } +} + +#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version " + +/** + This functions checks the value of BootDiscoverPolicy variable and + connect devices of class specified by that variable. Then it refreshes + Boot order for newly discovered boot device. + + @retval EFI_SUCCESS Devices connected successfully or connection + not required. + @retval others Return values from GetVariable(), LocateProtocol() + and ConnectDeviceClass(). +**/ +STATIC +EFI_STATUS +BootDiscoveryPolicyHandler ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 DiscoveryPolicy; + UINT32 DiscoveryPolicyOld; + UINTN Size; + EFI_BOOT_MANAGER_POLICY_PROTOCOL *BMPolicy; + EFI_GUID *Class; + + Size = sizeof (DiscoveryPolicy); + Status = gRT->GetVariable ( + BOOT_DISCOVERY_POLICY_VAR, + &gBootDiscoveryPolicyMgrFormsetGuid, + NULL, + &Size, + &DiscoveryPolicy + ); + if (Status == EFI_NOT_FOUND) { + DiscoveryPolicy = PcdGet32 (PcdBootDiscoveryPolicy); + Status = PcdSet32S (PcdBootDiscoveryPolicy, DiscoveryPolicy); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } else if (EFI_ERROR (Status)) { + return Status; + } + } else if (EFI_ERROR (Status)) { + return Status; + } + + if (DiscoveryPolicy == BDP_CONNECT_MINIMAL) { + return EFI_SUCCESS; + } + + switch (DiscoveryPolicy) { + case BDP_CONNECT_NET: + Class = &gEfiBootManagerPolicyNetworkGuid; + break; + case BDP_CONNECT_ALL: + Class = &gEfiBootManagerPolicyConnectAllGuid; + break; + default: + DEBUG (( + DEBUG_INFO, + "%a - Unexpected DiscoveryPolicy (0x%x). Run Minimal Discovery Policy\n", + __FUNCTION__, + DiscoveryPolicy + )); + return EFI_SUCCESS; + } + + Status = gBS->LocateProtocol ( + &gEfiBootManagerPolicyProtocolGuid, + NULL, + (VOID **)&BMPolicy + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "%a - Failed to locate gEfiBootManagerPolicyProtocolGuid." + "Driver connect will be skipped.\n", + __FUNCTION__ + )); + return Status; + } + + Status = BMPolicy->ConnectDeviceClass (BMPolicy, Class); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - ConnectDeviceClass returns - %r\n", __FUNCTION__, Status)); + return Status; + } + + // + // Refresh Boot Options if Boot Discovery Policy has been changed + // + Size = sizeof (DiscoveryPolicyOld); + Status = gRT->GetVariable ( + BOOT_DISCOVERY_POLICY_OLD_VAR, + &gBootDiscoveryPolicyMgrFormsetGuid, + NULL, + &Size, + &DiscoveryPolicyOld + ); + if ((Status == EFI_NOT_FOUND) || (DiscoveryPolicyOld != DiscoveryPolicy)) { + EfiBootManagerRefreshAllBootOption (); + + Status = gRT->SetVariable ( + BOOT_DISCOVERY_POLICY_OLD_VAR, + &gBootDiscoveryPolicyMgrFormsetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (DiscoveryPolicyOld), + &DiscoveryPolicy + ); + } + + return EFI_SUCCESS; +} + +/** + Do the platform specific action after the console is ready + Possible things that can be done in PlatformBootManagerAfterConsole: + > Console post action: + > Dynamically switch output mode from 100x31 to 80x25 for certain scenario + > Signal console ready platform customized event + > Run diagnostics like memory testing + > Connect certain devices + > Dispatch additional option roms + > Special boot: e.g.: USB boot, enter UI +**/ +VOID +EFIAPI +PlatformBootManagerAfterConsole ( + VOID + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + UINTN FirmwareVerLength; + UINTN PosX; + UINTN PosY; + EFI_INPUT_KEY Key; + + EfiEventGroupSignal (&gRockchipEventPlatformBmAfterConsoleGuid); + + FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString)); + + // + // Show the splash screen. + // + Status = BootLogoEnableLogo (); + if (EFI_ERROR (Status)) { + if (FirmwareVerLength > 0) { + Print ( + VERSION_STRING_PREFIX L"%s\n", + PcdGetPtr (PcdFirmwareVersionString) + ); + } + Print (L"Press ESCAPE for boot options"); + } else if (FirmwareVerLength > 0) { + Status = gBS->HandleProtocol ( + gST->ConsoleOutHandle, + &gEfiGraphicsOutputProtocolGuid, + (VOID **)&GraphicsOutput + ); + if (!EFI_ERROR (Status)) { + PosX = (GraphicsOutput->Mode->Info->HorizontalResolution - + (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) * + EFI_GLYPH_WIDTH) / 2; + PosY = 0; + + PrintXY ( + PosX, + PosY, + NULL, + NULL, + VERSION_STRING_PREFIX L"%s", + PcdGetPtr (PcdFirmwareVersionString) + ); + } + } + + // + // Connect device specified by BootDiscoverPolicy variable and + // refresh Boot order for newly discovered boot devices + // + BootDiscoveryPolicyHandler (); + + // + // On ARM, there is currently no reason to use the phased capsule + // update approach where some capsules are dispatched before EndOfDxe + // and some are dispatched after. So just handle all capsules here, + // when the console is up and we can actually give the user some + // feedback about what is going on. + // + HandleCapsules (); + + // + // Register UEFI Shell + // + Key.ScanCode = SCAN_NULL; + Key.UnicodeChar = L's'; + PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", 0, &Key); + + RemoveStaleFvFileOptions (); +} + +/** + This function is called each second during the boot manager waits the + timeout. + + @param TimeoutRemain The remaining timeout. +**/ +VOID +EFIAPI +PlatformBootManagerWaitCallback ( + UINT16 TimeoutRemain + ) +{ + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; + UINT16 Timeout; + EFI_STATUS Status; + + Timeout = PcdGet16 (PcdPlatformBootTimeOut); + + Black.Raw = 0x00000000; + White.Raw = 0x00FFFFFF; + + Status = BootLogoUpdateProgress ( + White.Pixel, + Black.Pixel, + L"Press ESCAPE for boot options", + White.Pixel, + (Timeout - TimeoutRemain) * 100 / Timeout, + 0 + ); + if (EFI_ERROR (Status)) { + Print (L"."); + } +} + +/** + The function is called when no boot option could be launched, + including platform recovery options and options pointing to applications + built into firmware volumes. + + If this function returns, BDS attempts to enter an infinite loop. +**/ +VOID +EFIAPI +PlatformBootManagerUnableToBoot ( + VOID + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN OldBootOptionCount; + UINTN NewBootOptionCount; + + // + // Record the total number of boot configured boot options + // + BootOptions = EfiBootManagerGetLoadOptions ( + &OldBootOptionCount, + LoadOptionTypeBoot + ); + EfiBootManagerFreeLoadOptions (BootOptions, OldBootOptionCount); + + // + // Connect all devices, and regenerate all boot options + // + EfiBootManagerConnectAll (); + EfiBootManagerRefreshAllBootOption (); + + // + // Record the updated number of boot configured boot options + // + BootOptions = EfiBootManagerGetLoadOptions ( + &NewBootOptionCount, + LoadOptionTypeBoot + ); + EfiBootManagerFreeLoadOptions (BootOptions, NewBootOptionCount); + + // + // If the number of configured boot options has changed, reboot + // the system so the new boot options will be taken into account + // while executing the ordinary BDS bootflow sequence. + // *Unless* persistent varstore is being emulated, since we would + // then end up in an endless reboot loop. + // + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { + if (NewBootOptionCount != OldBootOptionCount) { + DEBUG (( + DEBUG_WARN, + "%a: rebooting after refreshing all boot options\n", + __FUNCTION__ + )); + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + + Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu); + if (EFI_ERROR (Status)) { + return; + } + + for ( ; ;) { + EfiBootManagerBoot (&BootManagerMenu); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.h new file mode 100644 index 0000000..a40a2ff --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBm.h @@ -0,0 +1,53 @@ +/** @file + Head file for BDS Platform specific code + + Copyright (C) 2015-2016, Red Hat, Inc. + Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.
    + Copyright (c) 2016, Linaro Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PLATFORM_BM_H_ +#define PLATFORM_BM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Use SystemTable Conout to stop video based Simple Text Out consoles from + going to the video device. Put up LogoFile on every video device that is a + console. + + @param[in] LogoFile File name of logo to display on the center of the + screen. + + @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo + displayed. + @retval EFI_UNSUPPORTED Logo not found +**/ +EFI_STATUS +EnableQuietBoot ( + IN EFI_GUID *LogoFile + ); + +/** + Use SystemTable Conout to turn on video based Simple Text Out consoles. The + Simple Text Out screens will now be synced up with all non video output + devices + + @retval EFI_SUCCESS UGA devices are back in text mode and synced up. +**/ +EFI_STATUS +DisableQuietBoot ( + VOID + ); + +#endif // PLATFORM_BM_H_ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf new file mode 100644 index 0000000..deab399 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf @@ -0,0 +1,100 @@ +## @file +# Implementation for PlatformBootManagerLib library class interfaces. +# +# Copyright (C) 2015-2016, Red Hat, Inc. +# Copyright (c) 2014, ARM Ltd. All rights reserved.
    +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
    +# Copyright (c) 2016, Linaro Ltd. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformBootManagerLib + FILE_GUID = 92FD2DE3-B9CB-4B35-8141-42AD34D73C9F + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + PlatformBm.c + PlatformBm.h + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + BootLogoLib + CapsuleLib + DebugLib + DevicePathLib + DxeServicesLib + HobLib + MemoryAllocationLib + PcdLib + PrintLib + UefiBootManagerLib + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + RkAtagsLib + +[FeaturePcd] + gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString + gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits + gEfiMdeModulePkgTokenSpaceGuid.PcdBootDiscoveryPolicy + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress + +[Guids] + gBootDiscoveryPolicyMgrFormsetGuid + gEdkiiNonDiscoverableEhciDeviceGuid + gEdkiiNonDiscoverableUhciDeviceGuid + gEdkiiNonDiscoverableXhciDeviceGuid + gEfiBootManagerPolicyNetworkGuid + gEfiBootManagerPolicyConnectAllGuid + gEfiFileInfoGuid + gEfiFileSystemInfoGuid + gEfiFileSystemVolumeLabelInfoIdGuid + gEfiEndOfDxeEventGroupGuid + gEfiTtyTermGuid + gUefiShellFileGuid + gRockchipEventPlatformBmAfterConsoleGuid + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid + gEfiBootManagerPolicyProtocolGuid + gEfiDevicePathProtocolGuid + gEfiGraphicsOutputProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiPciRootBridgeIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiBlockIoProtocolGuid + gEsrtManagementProtocolGuid + gPlatformBootManagerProtocolGuid + gOhciDeviceProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.c new file mode 100644 index 0000000..9f29ae7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.c @@ -0,0 +1,172 @@ +/** @file + Platform Flash Access library. + + Copyright (c) 2018, Hisilicon Limited. All rights reserved. + Copyright (c) 2018, Linaro Limited. All rights reserved. + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC EFI_PHYSICAL_ADDRESS mInternalFdAddress; +STATIC EFI_PHYSICAL_ADDRESS mSFCMEM0BaseAddress; + +STATIC UNI_NOR_FLASH_PROTOCOL *mSpiProtocol; + +/** + Perform flash write operation with progress indicator. The start and end + completion percentage values are passed into this function. If the requested + flash write operation is broken up, then completion percentage between the + start and end values may be passed to the provided Progress function. The + caller of this function is required to call the Progress function for the + start and end completion percentage values. This allows the Progress, + StartPercentage, and EndPercentage parameters to be ignored if the requested + flash write operation can not be broken up + + @param[in] FirmwareType The type of firmware. + @param[in] FlashAddress The address of flash device to be accessed. + @param[in] FlashAddressType The type of flash device address. + @param[in] Buffer The pointer to the data buffer. + @param[in] Length The length of data buffer in bytes. + @param[in] Progress A function used report the progress of the + firmware update. This is an optional parameter + that may be NULL. + @param[in] StartPercentage The start completion percentage value that may + be used to report progress during the flash + write operation. + @param[in] EndPercentage The end completion percentage value that may + be used to report progress during the flash + write operation. + + @retval EFI_SUCCESS The operation returns successfully. + @retval EFI_WRITE_PROTECTED The flash device is read only. + @retval EFI_UNSUPPORTED The flash device access is unsupported. + @retval EFI_INVALID_PARAMETER The input parameter is not valid. +**/ +EFI_STATUS +EFIAPI +PerformFlashWriteWithProgress ( + IN PLATFORM_FIRMWARE_TYPE FirmwareType, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN FLASH_ADDRESS_TYPE FlashAddressType, + IN VOID *Buffer, + IN UINTN Length, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL + IN UINTN StartPercentage, + IN UINTN EndPercentage + ) +{ + UINT32 RomAddress; + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, + "PerformFlashWrite - 0x%x(%x) - 0x%x\n", + (UINTN)FlashAddress, + (UINTN)FlashAddressType, + Length)); + + if (FlashAddressType == FlashAddressTypeAbsoluteAddress) { + FlashAddress = FlashAddress - mInternalFdAddress; + } + + RomAddress = (UINT32)FlashAddress + (mInternalFdAddress - mSFCMEM0BaseAddress); + + DEBUG ((DEBUG_INFO, "Erase and Write Flash Start\n")) + + Status = mSpiProtocol->Update ( + mSpiProtocol, + (UINT32) RomAddress, + (UINT8 *)Buffer, + (UINT32) Length + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Erase and Write Status = %r \n", Status)); + } + + return Status; +} + +/** + Perform flash write operation. + + @param[in] FirmwareType The type of firmware. + @param[in] FlashAddress The address of flash device to be accessed. + @param[in] FlashAddressType The type of flash device address. + @param[in] Buffer The pointer to the data buffer. + @param[in] Length The length of data buffer in bytes. + + @retval EFI_SUCCESS The operation returns successfully. + @retval EFI_WRITE_PROTECTED The flash device is read only. + @retval EFI_UNSUPPORTED The flash device access is unsupported. + @retval EFI_INVALID_PARAMETER The input parameter is not valid. +**/ +EFI_STATUS +EFIAPI +PerformFlashWrite ( + IN PLATFORM_FIRMWARE_TYPE FirmwareType, + IN EFI_PHYSICAL_ADDRESS FlashAddress, + IN FLASH_ADDRESS_TYPE FlashAddressType, + IN VOID *Buffer, + IN UINTN Length + ) +{ + return PerformFlashWriteWithProgress ( + FirmwareType, + FlashAddress, + FlashAddressType, + Buffer, + Length, + NULL, + 0, + 0 + ); +} + +/** + Platform Flash Access Lib Constructor. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Constructor returns successfully. +**/ +EFI_STATUS +EFIAPI +PerformFlashAccessLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mInternalFdAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFdBaseAddress); + + mSFCMEM0BaseAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdSFCMEM0BaseAddress); + + DEBUG ((DEBUG_INFO, + "PcdFlashAreaBaseAddress - 0x%x, PcdSFCMEM0BaseAddress - 0x%x \n", + mInternalFdAddress, + mSFCMEM0BaseAddress)); + + Status = gBS->LocateProtocol ( + &gUniNorFlashProtocolGuid, + NULL, + (VOID **)&mSpiProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "LocateProtocol gUniNorFlashProtocolGuid Status = %r \n", + Status)); + } + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.inf new file mode 100644 index 0000000..9e2f265 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.inf @@ -0,0 +1,45 @@ +## @file +# Platform Flash Access library. +# +# Copyright (c) 2018, Hisilicon Limited. All rights reserved. +# Copyright (c) 2018, Linaro Limited. All rights reserved. +# Copyright (c) 2016, Intel Corporation. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = PlatformFlashAccessLibDxe + FILE_GUID = a6f6d6ea-3177-11ec-95b4-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformFlashAccessLib|DXE_DRIVER + CONSTRUCTOR = PerformFlashAccessLibConstructor + +[Sources] + PlatformFlashAccessLibDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + SignedCapsulePkg/SignedCapsulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + PcdLib + UefiBootServicesTableLib + +[Protocols] + gUniNorFlashProtocolGuid + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + gRockchipTokenSpaceGuid.PcdSFCMEM0BaseAddress + +[Depex] + gUniNorFlashProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.c new file mode 100644 index 0000000..ec4c939 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.c @@ -0,0 +1,164 @@ +/** @file + ResetSystemLib implementation for RK35xx platform + + Copyright (c) 2017 - 2018, Linaro Ltd. All rights reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved. + Copyright (c) 2022, Xilin Wu + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +STATIC +VOID +SignalResetEvent ( + VOID + ) +{ + if (!EfiAtRuntime ()) { + EfiEventGroupSignal (&gRockchipEventResetGuid); + } +} + +/** + This function causes a system-wide initialization (warm reset), in which all processors + are set to their initial state. Pending cycles are not corrupted. + + If this function returns, it means that the system does not support warm reset. +**/ +VOID +EFIAPI +ResetWarm ( + VOID + ) +{ + SignalResetEvent (); + + // RK3588-specific! + // Should be moved into a lib if SoC abstraction is needed. + + // First global software reset by programming CRU_GLB_SRST_FST as 0xfdb9 + MmioWrite32 (0xFD7C0C08, 0xfdb9); +} + +/** + This function causes a system-wide reset (cold reset), in which + all circuitry within the system returns to its initial state. This type of reset + is asynchronous to system operation and operates without regard to + cycle boundaries. + + If this function returns, it means that the system does not support cold reset. +**/ +VOID +EFIAPI +ResetCold ( + VOID + ) +{ + ARM_SMC_ARGS ArmSmcArgs; + + SignalResetEvent (); + + // Send a PSCI 0.2 SYSTEM_RESET command + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_SYSTEM_RESET; + ArmCallSmc (&ArmSmcArgs); +} + +/** + This function causes the system to enter a power state equivalent + to the ACPI G2/S5 or G3 states. + + If this function returns, it means that the system does not support shutdown reset. +**/ +VOID +EFIAPI +ResetShutdown ( + VOID + ) +{ + ARM_SMC_ARGS ArmSmcArgs; + + SignalResetEvent (); + + // Send a PSCI 0.2 SYSTEM_OFF command + ArmSmcArgs.Arg0 = ARM_SMC_ID_PSCI_SYSTEM_OFF; + ArmCallSmc (&ArmSmcArgs); +} + +/** + This function causes a systemwide reset. The exact type of the reset is + defined by the EFI_GUID that follows the Null-terminated Unicode string passed + into ResetData. If the platform does not recognize the EFI_GUID in ResetData + the platform must pick a supported reset type to perform.The platform may + optionally log the parameters from any non-normal reset that occurs. + + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData The data buffer starts with a Null-terminated string, + followed by the EFI_GUID. +**/ +VOID +EFIAPI +ResetPlatformSpecific ( + IN UINTN DataSize, + IN VOID *ResetData + ) +{ + SignalResetEvent (); + + ResetCold(); +} + +/** + The ResetSystem function resets the entire platform. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown + the data buffer starts with a Null-terminated string, optionally + followed by additional binary data. The string is a description + that the caller may use to further indicate the reason for the + system reset. +**/ +VOID +EFIAPI +ResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + switch (ResetType) { + case EfiResetWarm: + ResetWarm (); + break; + + case EfiResetCold: + ResetCold (); + break; + + case EfiResetShutdown: + ResetShutdown (); + return; + + case EfiResetPlatformSpecific: + ResetPlatformSpecific (DataSize, ResetData); + return; + + default: + return; + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.inf new file mode 100644 index 0000000..524f349 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.inf @@ -0,0 +1,35 @@ +#/** @file +# ResetSystemLib implementation for RK35xx platform +# +# Copyright (c) 2017, Linaro Ltd. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = ResetSystemLib + FILE_GUID = 18B12C83-7718-4D83-ADA4-87F2FE698DD4 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ResetSystemLib + +[Sources] + ResetSystemLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmSmcLib + BaseLib + DebugLib + UefiLib + UefiRuntimeLib + +[Guids] + gRockchipEventResetGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.c new file mode 100644 index 0000000..d7f1da1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.c @@ -0,0 +1,213 @@ +/** @file + * + * Rockchip ATAGS library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include + +#define ATAGS_BASE 0x1FE000 +#define ATAGS_SIZE 0x2000 + +#define ATAG_SIZE_BYTES(Size) (Size * 4) + +#define ATAG_ID_HASH 0x47C6A7E6 +#define ATAG_HASH_LENGTH sizeof (UINT32) + +typedef enum { + RkAtagTypeNone = 0x00000000, + RkAtagTypeCore = 0x54410001, + RkAtagTypeSerial = 0x54410050, + RkAtagTypeBootDev = 0x54410051, + RkAtagTypeDdrMem = 0x54410052, + RkAtagTypeTosMem = 0x54410053, + RkAtagTypeRamPartition = 0x54410054, + RkAtagTypeAtfMem = 0x54410055, + RkAtagTypePubKey = 0x54410056, + RkAtagTypeSocInfo = 0x54410057, + RkAtagTypeBoot1Param = 0x54410058, + RkAtagTypeMax = 0x544100ff +} RKATAG_TYPE; + +#pragma pack(1) + +typedef struct { + UINT32 Flags; + UINT32 Pagesize; + UINT32 RootDev; +} RKATAG_CORE; + +typedef struct { + UINT32 Size; + RKATAG_TYPE Type; +} RKATAG_HEADER; + +#pragma pack() + +STATIC +UINT32 +ComputeHash ( + IN VOID *Buffer, + IN UINT32 Length + ) +{ + UINT32 Index; + UINT32 Hash; + UINT8 *Data; + + Hash = ATAG_ID_HASH; + Data = Buffer; + + if (Data == NULL) { + return Hash; + } + + for (Index = 0; Index < Length; Index++) { + Hash ^= ((Hash << 5) + Data[Index] + (Hash >> 2)); + } + + return Hash; +} + +STATIC +VOID * +RkAtagsGetTagBuffer ( + IN RKATAG_TYPE Type + ) +{ + VOID *TagBuffer; + RKATAG_HEADER *TagHeader; + UINT32 TagHashOffset; + UINT32 *TagHash; + UINT32 ComputedTagHash; + + TagBuffer = (VOID *) ATAGS_BASE; + TagHeader = (RKATAG_HEADER *) TagBuffer; + + if (TagHeader->Type != RkAtagTypeCore) { + DEBUG ((DEBUG_ERROR, "%a: ATAGS not initialized!\n", + __FUNCTION__)); + return NULL; + } + + if (Type <= RkAtagTypeCore || Type > RkAtagTypeMax) { + DEBUG ((DEBUG_ERROR, "%a: Type=%x unsupported!\n", + __FUNCTION__, Type)); + return NULL; + } + + while (TagHeader->Size > 0) { + if ((UINTN)TagBuffer + ATAG_SIZE_BYTES(TagHeader->Size) - ATAGS_BASE > ATAGS_SIZE) { + DEBUG ((DEBUG_ERROR, "%a: Type=%x overflown!\n", + __FUNCTION__, TagHeader->Type)); + return NULL; + } + + if (TagHeader->Type == Type) { + TagHashOffset = ATAG_SIZE_BYTES(TagHeader->Size) - ATAG_HASH_LENGTH; + TagHash = (UINT32 *)(TagBuffer + TagHashOffset); + + if (*TagHash == 0) { + DEBUG ((DEBUG_WARN, "%a: Tag hash missing! Type=%x. Ignoring.\n", + __FUNCTION__, TagHeader->Type)); + return TagBuffer + sizeof (RKATAG_HEADER); + } + + ComputedTagHash = ComputeHash(TagBuffer, TagHashOffset); + + if (ComputedTagHash != *TagHash) { + DEBUG ((DEBUG_ERROR, "%a: Corrupted tag hash! Type=%x, TagHash=%x, ComputedTagHash=%x\n", + __FUNCTION__, TagHeader->Type, *TagHash, ComputedTagHash)); + return NULL; + } + + return TagBuffer + sizeof (RKATAG_HEADER); + } + + TagBuffer = (VOID *)((UINT32 *) TagBuffer + TagHeader->Size); + TagHeader = (RKATAG_HEADER *) TagBuffer; + } + + DEBUG ((DEBUG_ERROR, "%a: Tag not found! Type=%x.\n", + __FUNCTION__, Type)); + return NULL; +} + +RKATAG_SERIAL * +RkAtagsGetSerial ( + VOID + ) +{ + return (RKATAG_SERIAL *) RkAtagsGetTagBuffer (RkAtagTypeSerial); +} + +RKATAG_BOOTDEV * +RkAtagsGetBootDev ( + VOID + ) +{ + return (RKATAG_BOOTDEV *) RkAtagsGetTagBuffer (RkAtagTypeBootDev); +} + +RKATAG_DDR_MEM * +RkAtagsGetDdrMem ( + VOID + ) +{ + return (RKATAG_DDR_MEM *) RkAtagsGetTagBuffer (RkAtagTypeDdrMem); +} + +RKATAG_TOS_MEM * +RkAtagsGetTosMem ( + VOID + ) +{ + return (RKATAG_TOS_MEM *) RkAtagsGetTagBuffer (RkAtagTypeTosMem); +} + +RKATAG_RAM_PARTITION * +RkAtagsGetRamPartition ( + VOID + ) +{ + return (RKATAG_RAM_PARTITION *) RkAtagsGetTagBuffer (RkAtagTypeRamPartition); +} + +RKATAG_ATF_MEM * +RkAtagsGetAtfMem ( + VOID + ) +{ + return (RKATAG_ATF_MEM *) RkAtagsGetTagBuffer (RkAtagTypeAtfMem); +} + +RKATAG_PUB_KEY * +RkAtagsGetPubKey ( + VOID + ) +{ + return (RKATAG_PUB_KEY *) RkAtagsGetTagBuffer (RkAtagTypePubKey); +} + +RKATAG_SOC_INFO * +RkAtagsGetSocInfo ( + VOID + ) +{ + return (RKATAG_SOC_INFO *) RkAtagsGetTagBuffer (RkAtagTypeSocInfo); +} + +RKATAG_BOOT1_PARAM * +RkAtagsGetBoot1Param ( + VOID + ) +{ + return (RKATAG_BOOT1_PARAM *) RkAtagsGetTagBuffer (RkAtagTypeBoot1Param); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.inf new file mode 100644 index 0000000..204ac57 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.inf @@ -0,0 +1,28 @@ +#/** @file +# +# Rockchip ATAGS library. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = RkAtagsLib + FILE_GUID = EEA8B68F-1262-44D6-9D89-2AE700B969F3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RkAtagsLib + +[Sources] + RkAtagsLib.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.c new file mode 100644 index 0000000..cd9664a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.c @@ -0,0 +1,197 @@ +/** @file + + Copyright (c) 2021, Jared McNeill + Copyright (c) 2017-2018, Arm Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + System Control and Management Interface V1.0 + http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/ + DEN0056A_System_Control_and_Management_Interface.pdf +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RkMtlPrivateLib.h" + +// Shared mailbox +STATIC CONST MTL_CHANNEL Channels[NUM_CHANNELS] = { + { + MTL_CHANNEL_TYPE_LOW, + (MTL_MAILBOX*)(MTL_MAILBOX_BASE) + }, + }; + +/** Wait until channel is free. + + @param[in] Channel Pointer to a channel. + @param[in] TimeOutInMicroSeconds Time out in micro seconds. + + @retval EFI_SUCCESS Channel is free. + @retval EFI_TIMEOUT Time out error. +**/ +EFI_STATUS +MtlWaitUntilChannelFree ( + IN MTL_CHANNEL *Channel, + IN UINTN TimeOutInMicroSeconds + ) +{ + while (TimeOutInMicroSeconds != 0) { + ArmDataSynchronizationBarrier (); + + // If channel is free then we have received the reply. + if (Channel->MailBox->ChannelStatus == MTL_CHANNEL_FREE) { + return EFI_SUCCESS; + } + if (TimeOutInMicroSeconds < MTL_POLL_WAIT_TIME) { + gBS->Stall (TimeOutInMicroSeconds); + break; + } + // Wait for some arbitrary time. + gBS->Stall (MTL_POLL_WAIT_TIME); + TimeOutInMicroSeconds -= MTL_POLL_WAIT_TIME; + } + + // No response from SCP. + if (Channel->MailBox->ChannelStatus != MTL_CHANNEL_FREE) { + ASSERT (FALSE); + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/** Return the address of the message payload. + + @param[in] Channel Pointer to a channel. + + @retval UINT32* Pointer to the payload. +**/ +UINT32* +MtlGetChannelPayload ( + IN MTL_CHANNEL *Channel + ) +{ + return Channel->MailBox->Payload; +} + +/** Return pointer to a channel for the requested channel type. + + @param[in] ChannelType ChannelType, only supports Low priority channel. + MTL_CHANNEL_TYPE_LOW + + @param[out] Channel Holds pointer to the channel. + + @retval EFI_SUCCESS Pointer to channel is returned. + @retval EFI_UNSUPPORTED Requested channel type not supported. +**/ +EFI_STATUS +MtlGetChannel ( + IN MTL_CHANNEL_TYPE ChannelType, + OUT MTL_CHANNEL **Channel + ) +{ + if (ChannelType != MTL_CHANNEL_TYPE_LOW) { + return EFI_UNSUPPORTED; + } + + *Channel = (MTL_CHANNEL*)&Channels[ChannelType]; + + return EFI_SUCCESS; +} + +/** Mark the channel busy and ring the doorbell. + + @param[in] Channel Pointer to a channel. + @param[in] MessageHeader Message header. + + @param[out] PayloadLength Message length. + + @retval EFI_SUCCESS Message sent successfully. + @retval EFI_DEVICE_ERROR Channel is busy. +**/ +EFI_STATUS +MtlSendMessage ( + IN MTL_CHANNEL *Channel, + IN UINT32 MessageHeader, + OUT UINT32 PayloadLength + ) +{ + MTL_MAILBOX *MailBox = Channel->MailBox; + ARM_SMC_ARGS SmcRegs = {0}; + + ArmDataSynchronizationBarrier (); + if (Channel->MailBox->ChannelStatus != MTL_CHANNEL_FREE) { + DEBUG ((DEBUG_WARN, "Mailbox is busy\n")); + return EFI_DEVICE_ERROR; + } + + // Mark the channel busy before ringing doorbell. + Channel->MailBox->ChannelStatus = MTL_CHANNEL_BUSY; + ArmDataSynchronizationBarrier (); + + MailBox->Flags = MTL_POLL; + MailBox->MessageHeader = MessageHeader; + + // Add length of message header. + MailBox->Length = PayloadLength + sizeof (MessageHeader); + + ArmDataSynchronizationBarrier (); + + DEBUG ((DEBUG_INFO, "MtlSendMessage ringing doorbell 0x%08X with message header 0x%08X length 0x%08X\n", + FixedPcdGet32 (PcdRkMtlMailBoxSmcId), MailBox->MessageHeader, MailBox->Length)); + + // Ring the doorbell. + SmcRegs.Arg0 = FixedPcdGet32 (PcdRkMtlMailBoxSmcId); + ArmCallSmc (&SmcRegs); + + if (SmcRegs.Arg0 != 0) { + DEBUG ((DEBUG_WARN, "SMC doorbell call failed: 0x%lX\n", FixedPcdGet32 (PcdRkMtlMailBoxSmcId), SmcRegs.Arg0)); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** Wait for a response on a channel. + + If channel is free after sending message, it implies SCP responded + with a response on the channel. + + @param[in] Channel Pointer to a channel. + + @retval EFI_SUCCESS Message received successfully. + @retval EFI_TIMEOUT Time out error. +**/ +EFI_STATUS +MtlReceiveMessage ( + IN MTL_CHANNEL *Channel, + OUT UINT32 *MessageHeader, + OUT UINT32 *PayloadLength + ) +{ + EFI_STATUS Status; + + MTL_MAILBOX *MailBox = Channel->MailBox; + + Status = MtlWaitUntilChannelFree (Channel, RESPONSE_TIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + *MessageHeader = MailBox->MessageHeader; + + // Deduct message header length. + *PayloadLength = MailBox->Length - sizeof (*MessageHeader); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.inf new file mode 100644 index 0000000..a8c66c5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.inf @@ -0,0 +1,35 @@ +#/** @file +# Copyright (c) 2021, Jared McNeill +# Copyright (c) 2017-2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = RkMtlLib + FILE_GUID = 8C4393C9-3012-4862-A19C-259477D6F518 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmMtlLib + +[Sources.common] + RkMtlLib.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + ArmSmcLib + DebugLib + IoLib + UefiBootServicesTableLib + +[FixedPcd.common] + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSmcId \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlPrivateLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlPrivateLib.h new file mode 100644 index 0000000..49e75a4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/RkMtlPrivateLib.h @@ -0,0 +1,33 @@ +/** @file + + Copyright (c) 2017-2018, Arm Limited. All rights reserved. + Copyright (c) 2021, Jared McNeill + + SPDX-License-Identifier: BSD-2-Clause-Patent + + System Control and Management Interface V1.0 + http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/ + DEN0056A_System_Control_and_Management_Interface.pdf +**/ + +#ifndef RK_MTL_PRIVATE_LIB_H_ +#define RK_MTL_PRIVATE_LIB_H_ + +// Mailbox transport layer. +#define MTL_MAILBOX_BASE (FixedPcdGet64 (PcdRkMtlMailBoxBase)) +#define MTL_MAILBOX_SIZE (FixedPcdGet32 (PcdRkMtlMailBoxSize)) + +#define MTL_POLL 0 + +#define MTL_CHANNEL_BUSY 0 +#define MTL_CHANNEL_FREE 1 + +// Response time out value on a channel 1s. +#define RESPONSE_TIMEOUT 1000000 +#define NUM_CHANNELS 1 + +// Arbitarary poll time. +#define MTL_POLL_WAIT_TIME 100000 + +#endif /* RK_MTL_PRIVATE_LIB_H_ */ + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/source.txt b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/source.txt new file mode 100644 index 0000000..8b97dec --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkMtlLib/source.txt @@ -0,0 +1 @@ +Source: https://github.com/jaredmcneill/quartz64_uefi diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.c new file mode 100644 index 0000000..c35f80a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.c @@ -0,0 +1,39 @@ +/** @file + * + * RkSdmmcDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include + +EFI_STATUS +EFIAPI +RkSdmmcSetClockRate ( + IN UINTN Frequency + ) +{ + return EFI_UNSUPPORTED; +} + +VOID +EFIAPI +RkSdmmcSetIoMux ( + VOID + ) +{ + return; +} + +RKSDMMC_CARD_PRESENCE_STATE +EFIAPI +RkSdmmcGetCardPresenceState ( + VOID + ) +{ + return RkSdmmcCardPresenceUnsupported; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.inf new file mode 100644 index 0000000..0cf0702 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.inf @@ -0,0 +1,24 @@ +#/** @file +# +# RkSdmmcDxe platform helper library. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = RkSdmmcPlatformLibNull + FILE_GUID = 3e414bfa-0637-4e2a-a272-eb3767cc5061 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RkSdmmcPlatformLib + +[Sources] + RkSdmmcPlatformLibNull.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.c new file mode 100644 index 0000000..a9a88c2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.c @@ -0,0 +1,144 @@ +/** @file + * + * SDRAM size detection for Rockchip SoCs + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Gábor Stefanik + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +// TODO convert these to PCDs +#define SDRAM_OS_REG_BASE 0xFD58A208 +#define SDRAM_BANK_COUNT 2 + +typedef enum { + SDRAM_DDR4 = 0, + SDRAM_DDR2 = 2, + SDRAM_DDR3 = 3, + SDRAM_LPDDR2 = 5, + SDRAM_LPDDR3 = 6, + SDRAM_LPDDR4 = 7, + SDRAM_LPDDR4X = 8, + SDRAM_LPDDR5 = 9, + SDRAM_DDR5 = 10 +} SDRAM_DDRTYPE; + +#define SYS_REG_DDRTYPE(x) (((x) >> 13) & 0x7) +#define SYS_REG_CHANNELNUM(x) (((x) >> 12) & 0x1) +#define SYS_REG_RANK_CH(x, c) (((x) >> ((c) ? 27 : 11)) & 0x1) +#define SYS_REG_COL_CH(x, c) (((x) >> ((c) ? 25 : 9)) & 0x3) +#define SYS_REG_BK_CH(x, c) (((x) >> ((c) ? 24 : 8)) & 0x1) +#define SYS_REG_CS0_ROW_CH_LO(x, c) (((x) >> ((c) ? 22 : 6)) & 0x3) +#define SYS_REG_CS1_ROW_CH_LO(x, c) (((x) >> ((c) ? 20 : 4)) & 0x3) +#define SYS_REG_BW_CH(x, c) (((x) >> ((c) ? 18 : 2)) & 0x3) +#define SYS_REG_ROW34_CH(x, c) (((x) >> ((c) ? 31 : 30)) & 0x1) +#define SYS_REG_DBW_CH(x, c) (((x) >> ((c) ? 16 : 0)) & 0x3) + +#define SYS_REG1_VERSION(x) (((x) >> 28) & 0xF) +#define SYS_REG1_CS0_ROW_CH_HI(x, c) (((x) >> ((c) ? 7 : 5)) & 0x1) +#define SYS_REG1_CS1_ROW_CH_HI(x, c) (((x) >> ((c) ? 6 : 4)) & 0x1) +#define SYS_REG1_CS1_COL_CH(x, c) (((x) >> ((c) ? 2 : 0)) & 0x3) +#define SYS_REG1_EXTENDED_DDRTYPE(x) (((x) >> 12) & 0x3) + +UINT64 +SdramGetMemorySize ( + VOID + ) +{ + UINT32 OsReg; + UINT32 OsReg1; + INT32 Bank; + INT32 ChNum; + INT32 Ch; + INT32 Rank; + INT32 Cs0Col, Cs1Col; + INT32 Cs0Row, Cs1Row; + INT32 Bk; + INT32 Bw; + INT32 Row34; + INT32 Bg; + INT32 ChSizeMb; + INT32 SizeMb = 0; + UINT32 Version; + UINT32 DdrType; + + for (Bank = 0; Bank < SDRAM_BANK_COUNT; Bank++) { + OsReg = MmioRead32 (SDRAM_OS_REG_BASE + 8 * Bank); + OsReg1 = MmioRead32 (SDRAM_OS_REG_BASE + 8 * Bank + 4); + + Version = SYS_REG1_VERSION(OsReg1); + + DdrType = SYS_REG_DDRTYPE(OsReg); + if (Version >= 3) { + DdrType |= SYS_REG1_EXTENDED_DDRTYPE(OsReg1) << 3; + } + + ChNum = 1 + SYS_REG_CHANNELNUM(OsReg); + + DEBUG ((DEBUG_INFO, "%a(): Bank #%d: %d channel(s), type 0x%X, version 0x%X\n", + __func__, Bank, ChNum, SYS_REG_DDRTYPE(OsReg), Version)); + + for (Ch = 0; Ch < ChNum; Ch++) { + Rank = 1 + SYS_REG_RANK_CH(OsReg, Ch); + Cs0Col = 9 + SYS_REG_COL_CH(OsReg, Ch); + Cs1Col = Cs0Col; + + if (DdrType == SDRAM_LPDDR5) { + Bk = 3 + SYS_REG_BK_CH(OsReg, Ch); + } else { + Bk = 3 - SYS_REG_BK_CH(OsReg, Ch); + } + + if (Version >= 0x2) { + Cs1Col = 9 + SYS_REG1_CS1_COL_CH(OsReg1, Ch); + if (((SYS_REG1_CS0_ROW_CH_HI(OsReg1, Ch) << 2) + + SYS_REG_CS0_ROW_CH_LO(OsReg, Ch)) == 7) { + Cs0Row = 12; + } else { + Cs0Row = 13 + (SYS_REG1_CS0_ROW_CH_HI(OsReg1, Ch) << 2) + + SYS_REG_CS0_ROW_CH_LO(OsReg, Ch); + } + if (((SYS_REG1_CS1_ROW_CH_HI(OsReg1, Ch) << 2) + + SYS_REG_CS1_ROW_CH_LO(OsReg, Ch)) == 7) { + Cs1Row = 12; + } else { + Cs1Row = 13 + (SYS_REG1_CS1_ROW_CH_HI(OsReg1, Ch) << 2) + + SYS_REG_CS1_ROW_CH_LO(OsReg, Ch); + } + } else { + Cs0Row = 13 + SYS_REG_CS0_ROW_CH_LO(OsReg, Ch); + Cs1Row = 13 + SYS_REG_CS1_ROW_CH_LO(OsReg, Ch); + } + Bw = 2 >> SYS_REG_BW_CH(OsReg, Ch); + Row34 = SYS_REG_ROW34_CH(OsReg, Ch); + if (DdrType == SDRAM_DDR4 && Version != 0x3) { + Bg = SYS_REG_DBW_CH(OsReg, Ch) == 2 ? 2 : 1; + } else { + Bg = 0; + } + + ChSizeMb = 1 << (Cs0Row + Cs0Col + Bk + Bg + Bw - 20); + if (Rank > 1) { + ChSizeMb += ChSizeMb >> ((Cs0Row - Cs1Row) + (Cs0Col - Cs1Col)); + } + if (Row34) { + ChSizeMb = ChSizeMb * 3 / 4; + } + + DEBUG ((DEBUG_INFO, "%a(): Ch #%d: %u MB\n", __func__, Ch + Bank * 2, ChSizeMb)); + SizeMb += ChSizeMb; + } + } + + DEBUG ((DEBUG_INFO, "%a(): Detected %u MB RAM\n", __func__, SizeMb)); + + ASSERT (SizeMb != 0); + + return (UINT64)SizeMb * 1024 * 1024; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.inf new file mode 100644 index 0000000..516be60 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SdramLib/SdramLib.inf @@ -0,0 +1,36 @@ +#/** @file +# +# Rockchip SDRAM Library. +# +# Copyright (c) 2022, Jared McNeill +# Copyright (c) 2023, Gábor Stefanik +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = SdramLib + FILE_GUID = F1722CDD-AB5E-4341-8E98-C04CA151D5FB + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SdramLib + +[Sources] + SdramLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + +[FixedPcd] + +[Guids] diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.c new file mode 100644 index 0000000..75567fa --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.c @@ -0,0 +1,611 @@ + +#include +#include "Soc.h" +#include +#include +#include +#include +#include +#if 0 +/* Not used or exisit register and configure */ +#define NA -1 +#define BIT(n) (1 << (n)) +#define RK806_DBG DEBUG_ERROR +/* rk806 buck*/ +#define RK806_BUCK_ON_VSEL(n) (0x1a + n - 1) +#define RK806_BUCK_SLP_VSEL(n) (0x24 + n - 1) +#define RK806_BUCK_CONFIG(n) (0x10 + n - 1) +#define RK806_BUCK_VSEL_MASK 0xff + +/* RK806 LDO */ +#define RK806_NLDO_ON_VSEL(n) (0x43 + n - 1) +#define RK806_NLDO_SLP_VSEL(n) (0x48 + n - 1) +#define RK806_NLDO_VSEL_MASK 0xff +#define RK806_PLDO_ON_VSEL(n) (0x4e + n - 1) +#define RK806_PLDO_SLP_VSEL(n) (0x54 + n - 1) +#define RK806_PLDO_VSEL_MASK 0xff + +/* RK806 ENABLE */ +#define RK806_POWER_EN(n) (0x00 + n) +#define RK806_NLDO_EN(n) (0x03 + n) +#define RK806_PLDO_EN(n) (0x04 + n) +#define RK806_RAMP_RATE_MASK1 0xc0 +#define RK806_RAMP_RATE_REG1(n) (0x10 + n) +#define RK806_RAMP_RATE_REG1_8 0xeb +#define RK806_RAMP_RATE_REG9_10 0xea + +#define RK806_RAMP_RATE_4LSB_PER_1CLK 0x00/* LDO 100mV/uS buck 50mV/us */ +#define RK806_RAMP_RATE_2LSB_PER_1CLK 0x01/* LDO 50mV/uS buck 25mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_1CLK 0x02/* LDO 25mV/uS buck 12.5mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_2CLK 0x03/* LDO 12.5mV/uS buck 6.25mV/us */ + +#define RK806_RAMP_RATE_1LSB_PER_4CLK 0x04/* LDO 6.28/2mV/uS buck 3.125mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_8CLK 0x05/* LDO 3.12mV/uS buck 1.56mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_13CLK 0x06/* LDO 1.9mV/uS buck 961mV/us */ +#define RK806_RAMP_RATE_1LSB_PER_32CLK 0x07/* LDO 0.78mV/uS buck 0.39mV/us */ + +#define RK806_PLDO0_2_MSK(pldo) (BIT(pldo + 5)) +#define RK806_PLDO0_2_SET(pldo) (BIT(pldo + 1) | RK806_PLDO0_2_MSK(pldo)) +#define RK806_PLDO0_2_CLR(pldo) RK806_PLDO0_2_MSK(pldo) + +#define RK806_CHIP_NAME 0x5A +#define RK806_CHIP_VER 0x5B + +#define RK806_CMD_READ 0 +#define RK806_CMD_WRITE BIT(7) +#define RK806_CMD_CRC_EN BIT(6) +#define RK806_CMD_CRC_DIS 0 +#define RK806_CMD_LEN_MSK 0x0f +#define RK806_REG_H 0x00 + +#define RK806_SYS_CFG1 0x5f +#define RK806_SYS_CFG3 0x72 +#define RK806_PWRON_KEY 0x76 +#define RK806_INT_STS0 0x77 +#define RK806_INT_MSK0 0x78 +#define RK806_INT_STS1 0x79 +#define RK806_INT_MSK1 0x7A +#define RK806_GPIO_INT_CONFIG 0x7B +#define RK806_IRQ_PWRON_FALL_MSK BIT(0) +#define RK806_IRQ_PWRON_RISE_MSK BIT(1) +#define RK806_DEV_OFF BIT(0) +#define RK806_RST_MODE1 0x01 +#define RK806_RST_MODE2 0x02 +#define VERSION_AB 0x01 + +struct regulator_init_data { + const char *supply_regulator; /* or NULL for system supply */ + INT32 reg_id; + INT32 init_voltage_mv; +}; + +struct rk8xx_reg_info { + UINT32 min_uv; + UINT32 step_uv; + UINT8 vsel_reg; + UINT8 vsel_sleep_reg; + UINT8 config_reg; + UINT8 vsel_mask; + UINT8 min_sel; + /* only for buck now */ + UINT8 max_sel; + UINT8 range_num; +}; + +#define RK8XX_DESC_COM(_name, _reg_info, _ops) \ +{ \ + .reg_info = (_reg_info), \ + .name = (_reg_id), \ + .ops = _ops, \ +} + +#define RK8XX_VOLTAGE_INIT(_id, _voltage) \ +{ \ + .reg_id = (_id),\ + .init_voltage_mv = (_voltage),\ +} + +/****************************************** +8 -12: MASTER, SLAVE +4 -7: BUCK, NLDO, PLDO +0 -3: num +******************************************/ +#define MASTER (0x0 << 8) +#define SLAVER (0x1 << 8) +#define BUCK (0x0 << 4) +#define NLDO (0x1 << 4) +#define PLDO (0x2 << 4) + +enum master_num { + MASTER_BUCK1 = (MASTER | BUCK | 0), + MASTER_BUCK2 = (MASTER | BUCK | 1), + MASTER_BUCK3 = (MASTER | BUCK | 2), + MASTER_BUCK4 = (MASTER | BUCK | 3), + MASTER_BUCK5 = (MASTER | BUCK | 4), + MASTER_BUCK6 = (MASTER | BUCK | 5), + MASTER_BUCK7 = (MASTER | BUCK | 6), + MASTER_BUCK8 = (MASTER | BUCK | 7), + MASTER_BUCK9 = (MASTER | BUCK | 8), + MASTER_BUCK10 = (MASTER | BUCK | 9), + + MASTER_NLDO1 = (MASTER | NLDO | 0), + MASTER_NLDO2 = (MASTER | NLDO | 1), + MASTER_NLDO3 = (MASTER | NLDO | 2), + MASTER_NLDO4 = (MASTER | NLDO | 3), + MASTER_NLDO5 = (MASTER | NLDO | 4), + + MASTER_PLDO1 = (MASTER | PLDO | 0), + MASTER_PLDO2 = (MASTER | PLDO | 1), + MASTER_PLDO3 = (MASTER | PLDO | 2), + MASTER_PLDO4 = (MASTER | PLDO | 3), + MASTER_PLDO5 = (MASTER | PLDO | 4), + MASTER_PLDO6 = (MASTER | PLDO | 5), +}; + +enum slaver_num { + SLAVER_BUCK1 = (SLAVER | BUCK | 0), + SLAVER_BUCK2 = (SLAVER | BUCK | 1), + SLAVER_BUCK3 = (SLAVER | BUCK | 2), + SLAVER_BUCK4 = (SLAVER | BUCK | 3), + SLAVER_BUCK5 = (SLAVER | BUCK | 4), + SLAVER_BUCK6 = (SLAVER | BUCK | 5), + SLAVER_BUCK7 = (SLAVER | BUCK | 6), + SLAVER_BUCK8 = (SLAVER | BUCK | 7), + SLAVER_BUCK9 = (SLAVER | BUCK | 8), + SLAVER_BUCK10 = (SLAVER | BUCK | 9), + + SLAVER_NLDO1 = (SLAVER | NLDO | 0), + SLAVER_NLDO2 = (SLAVER | NLDO | 1), + SLAVER_NLDO3 = (SLAVER | NLDO | 2), + SLAVER_NLDO4 = (SLAVER | NLDO | 3), + SLAVER_NLDO5 = (SLAVER | NLDO | 4), + + SLAVER_PLDO1 = (SLAVER | PLDO | 0), + SLAVER_PLDO2 = (SLAVER | PLDO | 1), + SLAVER_PLDO3 = (SLAVER | PLDO | 2), + SLAVER_PLDO4 = (SLAVER | PLDO | 3), + SLAVER_PLDO5 = (SLAVER | PLDO | 4), + SLAVER_PLDO6 = (SLAVER | PLDO | 5), +}; +#endif + +struct SPI_HANDLE gSPI; + +static const struct rk8xx_reg_info rk806_buck[] = { + /* buck 1 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(1), RK806_BUCK_SLP_VSEL(1), RK806_BUCK_CONFIG(1), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 2 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(2), RK806_BUCK_SLP_VSEL(2), RK806_BUCK_CONFIG(2), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 3 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(3), RK806_BUCK_SLP_VSEL(3), RK806_BUCK_CONFIG(3), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 4 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(4), RK806_BUCK_SLP_VSEL(4), RK806_BUCK_CONFIG(4), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 5 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(5), RK806_BUCK_SLP_VSEL(5), RK806_BUCK_CONFIG(5), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 6 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(6), RK806_BUCK_SLP_VSEL(6), RK806_BUCK_CONFIG(6), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 7 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(7), RK806_BUCK_SLP_VSEL(7), RK806_BUCK_CONFIG(7), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 8 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(8), RK806_BUCK_SLP_VSEL(8), RK806_BUCK_CONFIG(8), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 9 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(9), RK806_BUCK_SLP_VSEL(9), RK806_BUCK_CONFIG(9), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, + /* buck 10 */ + { 500000, 6250, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0x00, 0xa0, 3}, + { 1500000, 25000, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xa1, 0xed, 3}, + { 3400000, 0, RK806_BUCK_ON_VSEL(10), RK806_BUCK_SLP_VSEL(10), RK806_BUCK_CONFIG(10), RK806_BUCK_VSEL_MASK, 0xee, 0xff, 3}, +}; + +static const struct rk8xx_reg_info rk806_nldo[] = { + /* nldo1 */ + { 500000, 12500, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0xE8, }, + /* nldo2 */ + { 500000, 12500, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_NLDO_ON_VSEL(2), RK806_NLDO_SLP_VSEL(2), NA, RK806_NLDO_VSEL_MASK, 0xE8, }, + /* nldo3 */ + { 500000, 12500, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_NLDO_ON_VSEL(3), RK806_NLDO_SLP_VSEL(3), NA, RK806_NLDO_VSEL_MASK, 0xE8, }, + /* nldo4 */ + { 500000, 12500, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_NLDO_ON_VSEL(4), RK806_NLDO_SLP_VSEL(4), NA, RK806_NLDO_VSEL_MASK, 0xE8, }, + /* nldo5 */ + { 500000, 12500, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_NLDO_ON_VSEL(5), RK806_NLDO_SLP_VSEL(5), NA, RK806_NLDO_VSEL_MASK, 0xE8, }, +}; + +static const struct rk8xx_reg_info rk806_pldo[] = { + /* pldo1 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(1), RK806_PLDO_SLP_VSEL(1), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, + /* pldo2 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(2), RK806_PLDO_SLP_VSEL(2), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, + /* pldo3 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(3), RK806_PLDO_SLP_VSEL(3), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, + /* pldo4 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(4), RK806_PLDO_SLP_VSEL(4), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, + /* pldo5 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(5), RK806_PLDO_SLP_VSEL(5), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, + /* pldo6 */ + { 500000, 12500, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0x00, }, + { 3400000, 0, RK806_PLDO_ON_VSEL(6), RK806_PLDO_SLP_VSEL(6), NA, RK806_PLDO_VSEL_MASK, 0xE8, }, +}; + +#if 0 +static void io_mem_show(const char *label, unsigned long base, unsigned int start, unsigned int end) +{ + unsigned int val, offset = start, nr = 0; + + if (label) + DEBUG ((DEBUG_ERROR, "%a:\n", label)); + + DEBUG ((DEBUG_ERROR, "%08lx: ", base + offset)); + for (offset = start; offset <= end; offset += 0x04) { + if (nr >= 4) { + DEBUG ((DEBUG_ERROR, "\n%08lx: ", base + offset)); + nr = 0; + } + val = MmioRead32(base + offset); + DEBUG ((DEBUG_ERROR, "%08lx ", val)); + nr++; + } + DEBUG ((DEBUG_ERROR, "\n")); +} +#endif + +static RETURN_STATUS _spi_read(INT32 cs_id, UINT32 reg, UINT8 *buffer, INT32 len) +{ + UINT8 txbuf[8]; + RETURN_STATUS status; + + txbuf[0] = RK806_CMD_READ; + txbuf[1] = reg; + txbuf[2] = RK806_REG_H; + + SPI_SetCS(&gSPI, cs_id, 1); + status = SPI_Configure(&gSPI, txbuf, NULL, 3); + status = SPI_PioTransfer(&gSPI); + SPI_Stop(&gSPI); + status = SPI_Configure(&gSPI, NULL, buffer, 1); + status = SPI_PioTransfer(&gSPI); + SPI_Stop(&gSPI); + SPI_SetCS(&gSPI, cs_id, 0); + + return status; +} + +static RETURN_STATUS _spi_write(INT32 cs_id, UINT32 reg, const UINT8 *buffer, INT32 len) +{ + UINT8 txbuf[4]; + RETURN_STATUS status; + + txbuf[0] = RK806_CMD_WRITE; + txbuf[1] = reg; + txbuf[2] = RK806_REG_H; + txbuf[3] = *buffer; + SPI_SetCS(&gSPI, cs_id, 1); + status = SPI_Configure(&gSPI, txbuf, NULL, 4); + status = SPI_PioTransfer(&gSPI); + + SPI_Stop(&gSPI); + SPI_SetCS(&gSPI, cs_id, 0); + + return status; +} + +static RETURN_STATUS pmic_reg_read(INT32 cs_id, + UINT32 reg, + UINT8 *buffer, + INT32 len) +{ + RETURN_STATUS ret; + + ret = _spi_read(cs_id, reg, buffer, len); + if (ret) + DEBUG ((DEBUG_ERROR, "cs_id %d rk806 read reg(0x%x) error: %d buffer = %x\n", + cs_id, reg, ret, buffer[0])); + + return ret; +} + +static INT32 pmic_reg_write(INT32 cs_id, + UINT32 reg, + const UINT8 *buffer, + INT32 len) +{ + RETURN_STATUS ret; + + ret = _spi_write(cs_id, reg, buffer, len); + if (ret) + DEBUG ((DEBUG_ERROR, "cs_id %d rk806 write reg(0x%x) error: %d %x\n", + cs_id, reg, ret, buffer[0])); + + return ret; +} + +static RETURN_STATUS pmic_clrsetbits(INT32 cs_id, UINT32 reg, UINT32 clr, UINT32 set) +{ + UINT8 byte; + RETURN_STATUS ret; + + ret = pmic_reg_read(cs_id, reg, &byte, 0x01); + if (ret < 0) + return ret; + byte = (ret & ~clr) | set; + + pmic_reg_write(cs_id, reg, &byte, 1); + ret = pmic_reg_read(cs_id, reg, &byte, 0x01); + return ret; +} + +static const struct rk8xx_reg_info *get_buck_reg(INT32 num, INT32 uvolt) +{ + if (uvolt < 1500000) + return &rk806_buck[num * 3 + 0]; + else if (uvolt < 3400000) + return &rk806_buck[num * 3 + 1]; + else + return &rk806_buck[num * 3 + 2]; +} + +static const struct rk8xx_reg_info *get_nldo_reg(INT32 num, INT32 uvolt) +{ + if (uvolt < 3400000) + return &rk806_nldo[num * 2]; + else + return &rk806_nldo[num * 2 + 1]; +} + +static const struct rk8xx_reg_info *get_pldo_reg(INT32 num, INT32 uvolt) +{ + if (uvolt < 3400000) + return &rk806_pldo[num * 2]; + else + return &rk806_pldo[num * 2 + 1]; +} +static RETURN_STATUS buck_set_voltage(INT32 reg_id, INT32 uvolt) +{ + INT32 buck = reg_id & 0x0f; + const struct rk8xx_reg_info *info = get_buck_reg(buck, uvolt); + INT32 mask = info->vsel_mask; + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 val; + + if (info->vsel_reg == NA) + return RETURN_INVALID_PARAMETER; + + if (info->step_uv == 0) /* Fixed voltage */ + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + DEBUG ((DEBUG_INFO, "%a: volt=%d, buck=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, buck + 1, info->vsel_reg, mask, val)); + + return pmic_clrsetbits(cs_id, info->vsel_reg, mask, val); +} + +static RETURN_STATUS nldo_set_voltage(INT32 reg_id, INT32 uvolt) +{ + INT32 ldo = reg_id & 0x0f; + const struct rk8xx_reg_info *info = get_nldo_reg(ldo, uvolt); + INT32 mask = info->vsel_mask; + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 val; + + if (info->vsel_reg == NA) + return RETURN_INVALID_PARAMETER; + + if (info->step_uv == 0) + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + DEBUG ((DEBUG_INFO, "%a: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, ldo + 1, info->vsel_reg, mask, val)); + + return pmic_clrsetbits(cs_id, info->vsel_reg, mask, val); +} + +static RETURN_STATUS pldo_set_voltage(INT32 reg_id, INT32 uvolt) +{ + INT32 ldo = reg_id & 0x0f; + const struct rk8xx_reg_info *info = get_pldo_reg(ldo, uvolt); + INT32 mask = info->vsel_mask; + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 val; + + if (info->vsel_reg == NA) + return RETURN_INVALID_PARAMETER; + + if (info->step_uv == 0) + val = info->min_sel; + else + val = ((uvolt - info->min_uv) / info->step_uv) + info->min_sel; + + DEBUG ((DEBUG_INFO, "%s: volt=%d, ldo=%d, reg=0x%x, mask=0x%x, val=0x%x\n", + __func__, uvolt, ldo + 1, info->vsel_reg, mask, val)); + + return pmic_clrsetbits(cs_id, info->vsel_reg, mask, val); +} + +static RETURN_STATUS buck_set_enable(INT32 reg_id, BOOLEAN enable) +{ + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 buck = reg_id & 0x0f; + UINT8 value, en_reg; + RETURN_STATUS ret; + + en_reg = RK806_POWER_EN(buck / 4); + if (enable) + value = ((1 << buck % 4) | (1 << (buck % 4 + 4))); + else + value = ((0 << buck % 4) | (1 << (buck % 4 + 4))); + + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + + return ret; +} + +static RETURN_STATUS nldo_set_enable(INT32 reg_id, BOOLEAN enable) +{ + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 ldo = reg_id & 0x0f; + UINT8 value, en_reg; + RETURN_STATUS ret; + + if (ldo < 4) { + en_reg = RK806_NLDO_EN(0); + if (enable) + value = ((1 << ldo % 4) | (1 << (ldo % 4 + 4))); + else + value = ((0 << ldo % 4) | (1 << (ldo % 4 + 4))); + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } else { + en_reg = RK806_NLDO_EN(2); + if (enable) + value = 0x44; + else + value = 0x40; + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } + + return ret; +} + +static RETURN_STATUS pldo_set_enable(INT32 reg_id, BOOLEAN enable) +{ + INT32 cs_id = (reg_id & 0xf00) >> 8; + INT32 pldo = reg_id & 0x0f; + UINT8 value, en_reg; + RETURN_STATUS ret; + + if (pldo < 3) { + en_reg = RK806_PLDO_EN(0); + if (enable) + value = RK806_PLDO0_2_SET(pldo); + else + value = RK806_PLDO0_2_CLR(pldo); + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } else if (pldo == 3) { + en_reg = RK806_PLDO_EN(1); + if (enable) { + value = ((1 << 0) | (1 << 4)); + } else { + value = (1 << 4); + } + + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } else if (pldo == 4) { + en_reg = RK806_PLDO_EN(1); + if (enable) + value = ((1 << 1) | (1 << 5)); + else + value = ((0 << 1) | (1 << 5)); + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } else if (pldo == 5) { + en_reg = RK806_PLDO_EN(0); + if (enable) + value = ((1 << 0) | (1 << 4)); + else + value = ((0 << 0) | (1 << 4)); + ret = pmic_reg_write(cs_id, en_reg, &value, 1); + } + + return ret; +} + +void RK806RegulatorInit(struct regulator_init_data init_data) +{ + INT32 reg_id; + INT32 init_voltage; + + init_voltage = init_data.init_voltage_mv; + reg_id = init_data.reg_id; + + if ((reg_id & 0xf0) == BUCK) { + buck_set_voltage(reg_id, init_voltage); + buck_set_enable(reg_id, 1); + } else if ((reg_id & 0xf0) == NLDO) { + nldo_set_voltage(reg_id, init_voltage); + nldo_set_enable(reg_id, 1); + } if ((reg_id & 0xf0) == PLDO) { + pldo_set_voltage(reg_id, init_voltage); + pldo_set_enable(reg_id, 1); + } +} + +static +RETURN_STATUS +SpiCongig(struct SPI_HANDLE *pSPI) +{ + struct SPI_CONFIG *pSPIConfig = &pSPI->config; + DEBUG ((DEBUG_INFO, "%a(%u): 0: %x\n", "SpiCongig", __LINE__, 0)); + + /* Data width */ + pSPIConfig->nBytes = CR0_DATA_FRAME_SIZE_8BIT; + + /* CPOL */ + //pSPIConfig->clkPolarity = CR0_POLARITY_HIGH; + pSPIConfig->clkPolarity = CR0_POLARITY_LOW; + + /* CPHA */ + //pSPIConfig->clkPhase = CR0_PHASE_2EDGE; + pSPIConfig->clkPhase = CR0_PHASE_1EDGE; + + /* MSB or LSB */ + pSPIConfig->firstBit = CR0_FIRSTBIT_MSB; + //pSPIConfig->firstBit = CR0_FIRSTBIT_LSB; + + /* Master or Slave */ + //pSPIConfig->opMode = CR0_OPM_SLAVE; + pSPIConfig->opMode = CR0_OPM_MASTER; + + /* CSM cycles */ + pSPIConfig->csm = 0; + + pSPI->maxFreq = 24000000; + pSPIConfig->speed = 2000000; + + if (pSPI->config.speed > HAL_SPI_MASTER_MAX_SCLK_OUT) { + pSPI->config.speed = HAL_SPI_MASTER_MAX_SCLK_OUT; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS RK806Init(void) +{ + UINT32 base = FixedPcdGet32 (SpiRK806BaseAddr); + + Rk806SpiIomux(); + + DEBUG ((DEBUG_INIT, "%a(%u): base: %x\n", "RK806Init", __LINE__, base)); + + SPI_Init(&gSPI, base); + SpiCongig(&gSPI); + + return RETURN_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.inf new file mode 100644 index 0000000..284d880 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/RK806.inf @@ -0,0 +1,41 @@ +#/** @file +# +# Component description file for Uart module +# +# Copyright (c) 2011-2016, ARM Ltd. All rights reserved.
    +# Copyright (c) 2017, Rockchip Inc. All rights reserved.
    +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RK806Lib + FILE_GUID = b90498c8-728a-11ec-ac42-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RK806Lib + +[Sources.common] + RK806.c + +[LibraryClasses] + DebugLib + IoLib + SpiLib + RockchipPlatformLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[Pcd] + gRockchipTokenSpaceGuid.SpiRK806BaseAddr diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.c new file mode 100755 index 0000000..8eecd18 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.c @@ -0,0 +1,491 @@ +/** + Copyright (c) 2021, Rockchip Inc. All rights reserved.
    + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "Soc.h" +#include +#include +#include +#include + +/** @defgroup How_To_Use How To Use + * + + The SPI HAL driver can be used as follows: + + - Declare a SPI_Handle handle structure, for example: + ``` + SPI_Handle instance; + ``` + + - Invoke SPI_Init() API to configure default config: + - opMode: slave or master + - apbTransform + - endianMode + - ssd + - Clock rate + + - Invoke SPI_Configure() API to program other mode: + - Data size + - Clock polarity and phase + - FirstBit + - Clock div + - Number of data frames received at RX only mode + - IT FIFO Level and DMA FIFO Level + - Transfer Mode + + - Blocking transfer: + - The communication is performed in polling mode by calling SPI_PioTransfer(). + - after transfer done, invoke SPI_Stop to release the chip select. + + */ + +#define HAL_SPI_FIFO_LENGTH 64 +/* Bit fields in SR */ +#define HAL_SPI_SR_BUSY (0x1 << SPI_SR_BSF_SHIFT) +#define HAL_SPI_SR_STB_BUSY (0x1 << SPI_SR_STB_SHIFT) + +/* Bit fields in ISR, IMR, RISR, 7 bits */ +#define SPI_INT_TXEI (1 << SPI_IMR_TFEIM_SHIFT) +#define SPI_INT_TXOI (1 << SPI_IMR_TFOIM_SHIFT) +#define SPI_INT_RXUI (1 << SPI_IMR_RFUIM_SHIFT) +#define SPI_INT_RXOI (1 << SPI_IMR_RFOIM_SHIFT) +#define SPI_INT_RXFI (1 << SPI_IMR_RFFIM_SHIFT) +#define SPI_INT_TOI (1 << SPI_IMR_TOIM_SHIFT) +#define SPI_INT_SSPI (1 << SPI_IMR_SSPIM_SHIFT) +#define SPI_INT_TXFIM (1 << SPI_IMR_TXFIM_SHIFT) + +/* Bit fields in ICR */ +#define SPI_CLEAR_INT_ALL (1 << SPI_ICR_CCI_SHIFT) +#define SPI_CLEAR_INT_RXUI (1 << SPI_ICR_CRFUI_SHIFT) +#define SPI_CLEAR_INT_RXOI (1 << SPI_ICR_CRFOI_SHIFT) +#define SPI_CLEAR_INT_TXOI (1 << SPI_ICR_CTFOI_SHIFT) +#define SPI_CLEAR_INT_TOI (1 << SPI_ICR_CTOI_SHIFT) +#define SPI_ICR_SSPI_SHIFT (1 << SPI_ICR_CSSPI_SHIFT) +#define SPI_CLEAR_INT_TXFI (1 << SPI_ICR_CTXFI_SHIFT) + +/* Bit fields in DMACR */ +#define SPI_DMACR_TX_ENABLE (1 << SPI_DMACR_TDE_SHIFT) +#define SPI_DMACR_RX_ENABLE (1 << SPI_DMACR_RDE_SHIFT) + +/* Bit fields in SPI TIMEOUT */ +#define SPI_TIMEOUT_ENABLE (1 << SPI_TIMEOUT_TOE_SHIFT) +#define SPI_TIMEOUT_DISABLE 0 + +#define IS_SPI_MODE(__MODE__) (((__MODE__) == CR0_OPM_SLAVE) || \ + ((__MODE__) == CR0_OPM_MASTER)) + +#define IS_SPI_DIRECTION(__MODE__) (((__MODE__) == CR0_XFM_TR) || \ + ((__MODE__) == CR0_XFM_TO) || \ + ((__MODE__) == CR0_XFM_RO)) + +#define IS_SPI_DATASIZE(__DATASIZE__) (((__DATASIZE__) == CR0_DATA_FRAME_SIZE_4BIT) || \ + ((__DATASIZE__) == CR0_DATA_FRAME_SIZE_8BIT) || \ + ((__DATASIZE__) == CR0_DATA_FRAME_SIZE_16BIT)) + +#define IS_SPI_CPOL(__CPOL__) (((__CPOL__) == CR0_POLARITY_LOW) || \ + ((__CPOL__) == CR0_POLARITY_HIGH)) + +#define IS_SPI_CPHA(__CPHA__) (((__CPHA__) == CR0_PHASE_1EDGE) || \ + ((__CPHA__) == CR0_PHASE_2EDGE)) + +#define IS_SPI_FIRST_BIT(__BIT__) (((__BIT__) == CR0_FIRSTBIT_MSB) || \ + ((__BIT__) == CR0_FIRSTBIT_LSB)) + +#define IS_SPI_APBTRANSFORM(__MODE__) (((__MODE__) == CR0_BHT_16BIT) || \ + ((__MODE__) == CR0_BHT_8BIT)) + +#define IS_SPI_ENDIAN_MODE(__MODE__) (((__MODE__) == CR0_EM_BIG) || \ + ((__MODE__) == CR0_EM_LITTLE)) + +#define IS_SPI_SSD_BIT(__MODE__) (((__MODE__) == CR0_SSD_HALF) || \ + ((__MODE__) == CR0_SSD_ONE)) + +#define IS_SPI_CSM(__NCYCLES__) (((__NCYCLES__) == CR0_CSM_0CYCLE) || \ + ((__NCYCLES__) == CR0_CSM_1CYCLE) || \ + ((__NCYCLES__) == CR0_CSM_2CYCLES) || \ + ((__NCYCLES__) == CR0_CSM_3CYCLES)) + +/** + * @brief Initialize the SPI according to the specified parameters. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @param base: SPI controller register base address. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_Init(struct SPI_HANDLE *pSPI, UINT32 base) +{ + pSPI->pReg = (struct SPI_REG *)(long)base; + + pSPI->config.opMode = CR0_OPM_MASTER; + + /* Default config */ + pSPI->config.apbTransform = CR0_BHT_8BIT; + pSPI->config.endianMode = CR0_EM_BIG; + pSPI->config.ssd = CR0_SSD_ONE; + pSPI->config.csm = CR0_CSM_0CYCLE; + + return RETURN_SUCCESS; +} + +/** + * @brief Start or stop the spi module. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @param enable: start or stop the spi module. + * @return status + */ +static inline RETURN_STATUS SPI_EnableChip(struct SPI_HANDLE *pSPI, int enable) +{ + WRITE_REG(pSPI->pReg->ENR, (enable ? 1 : 0)); + + return RETURN_SUCCESS; +} + +/** + * @brief Configure the spi clock division. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @param div: clock division. + * @return status + */ +static inline RETURN_STATUS SPI_SetClock(struct SPI_HANDLE *pSPI, UINT16 div) +{ + WRITE_REG(pSPI->pReg->BAUDR, div); + + return RETURN_SUCCESS; +} + +/** + * @brief Configure the cs signal. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @param select: cs number select. + * @param enable: active or inactive the cs signal. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_SetCS(struct SPI_HANDLE *pSPI, UINT8 select, UINT8 enable) +{ + UINT32 ser; + + ASSERT(pSPI != NULL); + + ser = READ_REG(pSPI->pReg->SER) & SPI_SER_SER_MASK; + + if (enable) { + ser |= 1 << select; + } else { + ser &= ~(1 << select); + } + + WRITE_REG(pSPI->pReg->SER, ser); + + return RETURN_SUCCESS; +} + +/** + * @brief Wait for the transfer finished. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_FlushFifo(struct SPI_HANDLE *pSPI) +{ + ASSERT(pSPI != NULL); + + while (READ_REG(pSPI->pReg->RXFLR)) { + READ_REG(pSPI->pReg->RXDR); + } + + return RETURN_SUCCESS; +} + +/** + * @brief The max amount of data can be written in blocking mode. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return Max bytes can xfer. + */ +static inline UINT32 SPI_TxMax(struct SPI_HANDLE *pSPI) +{ + UINT32 txLeft, txRoom; + + txLeft = (pSPI->pTxBufferEnd - pSPI->pTxBuffer) / pSPI->config.nBytes; + txRoom = HAL_SPI_FIFO_LENGTH - READ_REG(pSPI->pReg->TXFLR); + + return MIN(txLeft, txRoom); +} + +/** + * @brief Send an amount of data in blocking mode. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +static RETURN_STATUS SPI_PioWrite(struct SPI_HANDLE *pSPI) +{ + UINT32 max = SPI_TxMax(pSPI); + UINT32 txw = 0; + + while (max--) { + if (pSPI->config.nBytes == 1) { + txw = *(const UINT8 *)(pSPI->pTxBuffer); + } else { + txw = *(const UINT16 *)(pSPI->pTxBuffer); + } + + WRITE_REG(pSPI->pReg->TXDR, txw); + pSPI->pTxBuffer += pSPI->config.nBytes; + } + + return RETURN_SUCCESS; +} + +/** + * @brief Read an amount of data(byte) in blocking mode. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +static RETURN_STATUS SPI_PioReadByte(struct SPI_HANDLE *pSPI) +{ + UINT32 rxLeft = pSPI->pRxBufferEnd - pSPI->pRxBuffer; + UINT32 rxRoom = READ_REG(pSPI->pReg->RXFLR); + UINT32 max = MIN(rxLeft, rxRoom); + + while (max > 7) { + *(pSPI->pRxBuffer + 0) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 1) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 2) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 3) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 4) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 5) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 6) = (UINT8)READ_REG(pSPI->pReg->RXDR); + *(pSPI->pRxBuffer + 7) = (UINT8)READ_REG(pSPI->pReg->RXDR); + pSPI->pRxBuffer += 8; + max -= 8; + } + + while (max--) { + *pSPI->pRxBuffer = (UINT8)READ_REG(pSPI->pReg->RXDR); + pSPI->pRxBuffer++; + } + + return RETURN_SUCCESS; +} + +/** + * @brief Read an amount of data(short) in blocking mode. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +static RETURN_STATUS SPI_PioReadShort(struct SPI_HANDLE *pSPI) +{ + UINT32 rxLeft = (pSPI->pRxBufferEnd - pSPI->pRxBuffer) >> 1; + UINT32 rxRoom = READ_REG(pSPI->pReg->RXFLR); + UINT32 max = MIN(rxLeft, rxRoom); + + while (max > 7) { + *((UINT16 *)pSPI->pRxBuffer + 0) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 1) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 2) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 3) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 4) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 5) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 6) = (UINT16)READ_REG(pSPI->pReg->RXDR); + *((UINT16 *)pSPI->pRxBuffer + 7) = (UINT16)READ_REG(pSPI->pReg->RXDR); + pSPI->pRxBuffer += 16; + max -= 8; + } + + while (max--) { + *((UINT16 *)pSPI->pRxBuffer) = (UINT16)READ_REG(pSPI->pReg->RXDR); + pSPI->pRxBuffer += 2; + } + + return RETURN_SUCCESS; +} + +/** + * @brief Transmit an amount of data in blocking mode. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_PioTransfer(struct SPI_HANDLE *pSPI) +{ + UINT32 remain = 0; + + ASSERT(pSPI != NULL); + + pSPI->type = SPI_POLL; + SPI_EnableChip(pSPI, 1); + + do { + if (pSPI->pTxBuffer) { + remain = pSPI->pTxBufferEnd - pSPI->pTxBuffer; + SPI_PioWrite(pSPI); + } + + if (pSPI->pRxBuffer) { + remain = pSPI->pRxBufferEnd - pSPI->pRxBuffer; + + if (pSPI->config.nBytes == 1) { + SPI_PioReadByte(pSPI); + } else { + SPI_PioReadShort(pSPI); + } + } + } while (remain); + + return RETURN_SUCCESS; +} + +/** + * @brief Query the SPI bus state is idle or busy. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return HAL status + */ +RETURN_STATUS SPI_QueryBusState(struct SPI_HANDLE *pSPI) +{ + HAL_ASSERT(pSPI != NULL); + if (!(READ_REG(pSPI->pReg->SR) & HAL_SPI_SR_BUSY)) { + return RETURN_SUCCESS; + } + + return -2; +} + +/** + * @brief Stop the transmit. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_Stop(struct SPI_HANDLE *pSPI) +{ + UINT32 ret; + ASSERT(pSPI != NULL); + + do + { + ret = SPI_QueryBusState(pSPI); + if (ret == RETURN_SUCCESS) + break; + } while(1); + + SPI_EnableChip(pSPI, 0); + + return RETURN_SUCCESS; +} + +/** + * @brief Configure the SPI transfer mode depend on the tx/rx buffer. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @return status + */ +static RETURN_STATUS HAL_SPI_ConfigureTransferMode(struct SPI_HANDLE *pSPI) +{ + UINT32 cr0; + + if (pSPI->pTxBuffer && pSPI->pRxBuffer) { + pSPI->config.xfmMode = CR0_XFM_TR; + } else if (pSPI->pTxBuffer) { + pSPI->config.xfmMode = CR0_XFM_TO; + } else if (pSPI->pRxBuffer) { + pSPI->config.xfmMode = CR0_XFM_RO; + } + + cr0 = READ_REG(pSPI->pReg->CTRLR[0]); + cr0 &= ~SPI_CTRLR0_XFM_MASK; + cr0 |= pSPI->config.xfmMode; + + WRITE_REG(pSPI->pReg->DMARDLR, pSPI->dmaBurstSize - 1); + WRITE_REG(pSPI->pReg->CTRLR[0], cr0); + + return RETURN_SUCCESS; +} + +/** + * @brief Program the SPI config via this api. + * @param pSPI: pointer to a SPI_Handle structure that contains + * the configuration information for SPI module. + * @param pTxData: pointer to TX buffer. + * @param pRxData: pointer to RX buffer. + * @param size: amount of data to be sent. + * @return status + */ +RETURN_STATUS +EFIAPI +SPI_Configure(struct SPI_HANDLE *pSPI, const UINT8 *pTxData, UINT8 *pRxData, UINT32 size) +{ + UINT32 cr0 = 0; + UINT32 div = 0; + + cr0 |= pSPI->config.opMode; + + cr0 |= pSPI->config.apbTransform | pSPI->config.endianMode | pSPI->config.ssd; + /* Data width */ + cr0 |= pSPI->config.nBytes; + + /* Mode for polarity, phase, first bit and endian */ + cr0 |= pSPI->config.clkPolarity | pSPI->config.clkPhase | pSPI->config.firstBit; + + /* Config CSM cycles */ + cr0 |= pSPI->config.csm; + + /* div doesn't support odd number */ + div = DIV_ROUND_UP(pSPI->maxFreq, pSPI->config.speed); + div = (div + 1) & 0xfffe; + + WRITE_REG(pSPI->pReg->CTRLR[0], cr0); + + WRITE_REG(pSPI->pReg->TXFTLR, HAL_SPI_FIFO_LENGTH / 2 - 1); + WRITE_REG(pSPI->pReg->RXFTLR, HAL_SPI_FIFO_LENGTH / 2 - 1); + + WRITE_REG(pSPI->pReg->DMATDLR, HAL_SPI_FIFO_LENGTH / 2 - 1); + WRITE_REG(pSPI->pReg->DMARDLR, 0); + + SPI_SetClock(pSPI, div); + + pSPI->pTxBuffer = pTxData; + pSPI->pTxBufferEnd = pTxData + size; + pSPI->pRxBuffer = pRxData; + pSPI->pRxBufferEnd = pRxData + size; + pSPI->len = size; + + HAL_SPI_ConfigureTransferMode(pSPI); + + if (pSPI->config.xfmMode == CR0_XFM_RO) { + if (pSPI->config.nBytes == 1) { + WRITE_REG(pSPI->pReg->CTRLR[1], pSPI->len - 1); + } else if (pSPI->config.nBytes == 2) { + WRITE_REG(pSPI->pReg->CTRLR[1], (pSPI->len / 2) - 1); + } else { + WRITE_REG(pSPI->pReg->CTRLR[1], (pSPI->len * 2) - 1); + } + } + + return RETURN_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.inf new file mode 100644 index 0000000..856bfbf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Library/SpiLib/SpiLib.inf @@ -0,0 +1,39 @@ +#/** @file +# +# Component description file for Uart module +# +# Copyright (c) 2011-2016, ARM Ltd. All rights reserved.
    +# Copyright (c) 2017, Rockchip Inc. All rights reserved.
    +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SpiLib + FILE_GUID = b90498c8-728a-11ec-ac42-f42a7dcb925d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SpiLib + +[Sources.common] + SpiLib.c + +[LibraryClasses] + DebugLib + IoLib + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[Pcd] + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Cpu.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Cpu.asl new file mode 100644 index 0000000..16fbd7d --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Cpu.asl @@ -0,0 +1,134 @@ +/** @file + * + * RK3588 CPU devices. + * + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018-2020, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +Device (PKG0) +{ + Name (_HID, "ACPI0010") + Name (_UID, 8) + Method (_STA) + { + Return (0xF) + } + + Device (CLU0) + { + Name (_HID, "ACPI0010") + Name (_UID, 9) + Method (_STA) + { + Return (0xF) + } + + Device (CPU0) + { + Name (_HID, "ACPI0007") + Name (_UID, 0) + Method (_STA) + { + Return (0xF) + } + } + + Device (CPU1) + { + Name (_HID, "ACPI0007") + Name (_UID, 1) + Method (_STA) + { + Return (0xF) + } + } + + Device (CPU2) + { + Name (_HID, "ACPI0007") + Name (_UID, 2) + Method (_STA) + { + Return (0xF) + } + } + + Device (CPU3) + { + Name (_HID, "ACPI0007") + Name (_UID, 3) + Method (_STA) + { + Return (0xF) + } + } + } + + Device (CLU1) + { + Name (_HID, "ACPI0010") + Name (_UID, 10) + Method (_STA) + { + Return (0xF) + } + + Device (CPU4) + { + Name (_HID, "ACPI0007") + Name (_UID, 4) + Method (_STA) + { + Return (0xF) + } + } + + Device (CPU5) + { + Name (_HID, "ACPI0007") + Name (_UID, 5) + Method (_STA) + { + Return (0xF) + } + } + } + + Device (CLU2) + { + Name (_HID, "ACPI0010") + Name (_UID, 11) + Method (_STA) + { + Return (0xF) + } + + Device (CPU6) + { + Name (_HID, "ACPI0007") + Name (_UID, 6) + Method (_STA) + { + Return (0xF) + } + } + + Device (CPU7) + { + Name (_HID, "ACPI0007") + Name (_UID, 7) + Method (_STA) + { + Return (0xF) + } + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dbg2.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dbg2.aslc new file mode 100644 index 0000000..7534cec --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dbg2.aslc @@ -0,0 +1,69 @@ +/** @file +* Debug Port Table (DBG2) +* +* Copyright (c) 2021, Jared McNeill +* Copyright (c) 2020 Linaro Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#include +#include +#include +#include + +#include "AcpiTables.h" + +#pragma pack(1) + +#define UART_STR { '\\', '_', 'S', 'B', '.', 'U', 'A', 'R', '2', 0x00 } + +typedef struct { + EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT Dbg2Device; + EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE BaseAddressRegister; + UINT32 AddressSize; + UINT8 NameSpaceString[10]; +} DBG2_DEBUG_DEVICE_INFORMATION; + +typedef struct { + EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE Description; + DBG2_DEBUG_DEVICE_INFORMATION Dbg2DeviceInfo; +} DBG2_TABLE; + + +STATIC DBG2_TABLE Dbg2 = { + { + ACPI_HEADER ( + EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE, + DBG2_TABLE, + EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION + ), + OFFSET_OF (DBG2_TABLE, Dbg2DeviceInfo), + 1 /* NumberOfDebugPorts */ + }, + { + { + EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION, + sizeof (DBG2_DEBUG_DEVICE_INFORMATION), + 1, /* NumberofGenericAddressRegisters */ + 10, /* NameSpaceStringLength */ + OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION, NameSpaceString), + 0, /* OemDataLength */ + 0, /* OemDataOffset */ + EFI_ACPI_DBG2_PORT_TYPE_SERIAL, + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS, + {EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE}, + OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION, BaseAddressRegister), + OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION, AddressSize) + }, + ARM_GAS32 (FixedPcdGet64(PcdSerialRegisterBase)), /* BaseAddressRegister */ + 0x1000, /* AddressSize */ + UART_STR, /* NameSpaceString */ + } +}; + +#pragma pack() + +// Reference the table being generated to prevent the optimizer from removing +// the data structure from the executable +VOID* CONST ReferenceAcpiTable = &Dbg2; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dma.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dma.asl new file mode 100644 index 0000000..53a69b7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Dma.asl @@ -0,0 +1,104 @@ +/** @file + * + * Copyright (c) 2022, Rockchip Electronics Co. Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + +// +// Description: DMA +// + Device (DMA0) + { + Name (_HID, "ARMH0330") + Name (_UID, 0) + Method (_CRS, 0, Serialized) + { + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, + 0xFEA10000, // Address Base + 0x00004000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x00000076, + } + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x00000077, + } + }) + Return (RBUF) /* \_SB_.DMA0._CRS.RBUF */ + } + Name (_DSD, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) {"ctlrName", "DMA0"} + } + }) + } + + Device (DMA1) + { + Name (_HID, "ARMH0330") + Name (_UID, 1) + Method (_CRS, 0, Serialized) + { + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, + 0xFEA30000, // Address Base + 0x00004000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x00000078, + } + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x00000079, + } + }) + Return (RBUF) /* \_SB_.DMA0._CRS.RBUF */ + } + Name (_DSD, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) {"ctlrName", "DMA1"} + } + }) + } + + Device (DMA2) + { + Name (_HID, "ARMH0330") + Name (_UID, 2) + Method (_CRS, 0, Serialized) + { + Name (RBUF, ResourceTemplate () + { + Memory32Fixed (ReadWrite, + 0xFED10000, // Address Base + 0x00004000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x0000007A, + } + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x0000007B, + } + }) + Return (RBUF) /* \_SB_.DMA0._CRS.RBUF */ + } + Name (_DSD, Package() { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) {"ctlrName", "DMA2"} + } + }) + } \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/DsdtCommon.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/DsdtCommon.asl new file mode 100644 index 0000000..7b8afe6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/DsdtCommon.asl @@ -0,0 +1,13 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +Scope (\_SB_) { + Include ("Scmi.asl") +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Emmc.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Emmc.asl new file mode 100644 index 0000000..0d08672 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Emmc.asl @@ -0,0 +1,133 @@ +/** @file + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + + + Device (SDC3) { + Name (_HID, "RKCP0D40") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe2e0000, 0x10000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 237 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3588-dwcmshc" }, + Package () { "max-frequency", 200000000 }, + Package () { "bus-width", 8 }, + Package () { "no-sd", 0x1 }, + Package () { "no-sdio", 0x1 }, + Package () { "mmc-hs400-1_8v", 0x1 }, + Package () { "mmc-hs400-enhanced-strobe", 0x1 }, + Package () { "non-removable", 0x1 }, + } + }) + + OperationRegion(EMMC, SystemMemory, 0xFD7C0434, 0x4) + Field(EMMC, DWordAcc, NoLock, WriteAsZeros) { + PLLE, 32, + } + + Method (_DSM, 4) { + If (LEqual (Arg0, ToUUID("434addb0-8ff3-49d5-a724-95844b79ad1f"))) { + Switch (ToInteger (Arg2)) { + Case (0) { + Return (0x3) + } + Case (1) { + Local0 = DerefOf (Arg3 [0]) + If (Local0 >= 200000000) { + Store (0xFF000500, PLLE) + Return (200000000) + } + If (Local0 >= 150000000) { + Store (0xFF000700, PLLE) + Return (150000000) + } + If (Local0 >= 100000000) { + Store (0xFF000B00, PLLE) + Return (100000000) + } + If (Local0 >= 50000000) { + Store (0xFF001700, PLLE) + Return (50000000) + } + If (Local0 >= 24000000) { + Store (0xFF008000, PLLE) + Return (24000000) + } + if (Local0 >= 375000) { + Store (0xFF00BF00, PLLE) + Return (375000) + } + Return (0) + } + } + } + Return (0) + } + + // Used by downstream Linux driver. + Method(SCLK, 1, Serialized) { + If (Arg0 <= 400000) + { + Store (0xFF00BF00, PLLE) + } + ElseIF (Arg0 <= 50000000) + { + Store (0xFF008000, PLLE) + } + Else + { + Store (0xFF000600, PLLE) + } + } + + /* TODO: + Method(_PS3) { + + } + + Method(_PS2) { + Store (0xFF00BF00, PLLE) + } + + Method(_PS1) { + Store (0xFF008000, PLLE) + } + + Method(_PS0) { + Store (0xFF000600, PLLE) + } + + Method(_PSC) { + Return(0x01) + } + */ + + // + // A child device that represents the non-removable eMMC. + // + Device (SDMM) + { + Method (_ADR) + { + Return (0) + } + Method (_RMV) // Is removable + { + Return (0) // 0 - fixed + } + } + } \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Es8388.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Es8388.asl new file mode 100644 index 0000000..964432a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Es8388.asl @@ -0,0 +1,28 @@ +/** @file + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + + Device (JACK) { + Name (_HID, BOARD_AUDIO_CODEC_HID) + Name (_UID, 0) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + I2cSerialBusV2(BOARD_CODEC_I2C_ADDR, ControllerInitiated, 0x000186A0, + AddressingMode7Bit, BOARD_CODEC_I2C, + 0x00, ResourceConsumer, , Exclusive) + GpioInt (Edge, ActiveHigh, Exclusive, PullNone, 0x0000, + BOARD_CODEC_GPIO, 0x00, ResourceConsumer) + { + BOARD_CODEC_GPIO_PIN + } + }) + Return (RBUF) + } + } \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Fadt.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Fadt.aslc new file mode 100644 index 0000000..c2d079c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Fadt.aslc @@ -0,0 +1,86 @@ +/** @file + * + * Fixed ACPI Description Table (FADT) + * + * Copyright (c) 2019, Pete Batard + * Copyright (c) 2018, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "AcpiTables.h" + +EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE Fadt = { + ACPI_HEADER ( + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION + ), + 0, // UINT32 FirmwareCtrl + 0, // UINT32 Dsdt + EFI_ACPI_RESERVED_BYTE, // UINT8 Reserved0 + EFI_ACPI_6_3_PM_PROFILE_APPLIANCE_PC, // UINT8 PreferredPmProfile + 0, // UINT16 SciInt + 0, // UINT32 SmiCmd + 0, // UINT8 AcpiEnable + 0, // UINT8 AcpiDisable + 0, // UINT8 S4BiosReq + 0, // UINT8 PstateCnt + 0, // UINT32 Pm1aEvtBlk + 0, // UINT32 Pm1bEvtBlk + 0, // UINT32 Pm1aCntBlk + 0, // UINT32 Pm1bCntBlk + 0, // UINT32 Pm2CntBlk + 0, // UINT32 PmTmrBlk + 0, // UINT32 Gpe0Blk + 0, // UINT32 Gpe1Blk + 0, // UINT8 Pm1EvtLen + 0, // UINT8 Pm1CntLen + 0, // UINT8 Pm2CntLen + 0, // UINT8 PmTmrLen + 0, // UINT8 Gpe0BlkLen + 0, // UINT8 Gpe1BlkLen + 0, // UINT8 Gpe1Base + 0, // UINT8 CstCnt + 0, // UINT16 PLvl2Lat + 0, // UINT16 PLvl3Lat + 0, // UINT16 FlushSize + 0, // UINT16 FlushStride + 0, // UINT8 DutyOffset + 0, // UINT8 DutyWidth + 0, // UINT8 DayAlrm + 0, // UINT8 MonAlrm + 0, // UINT8 Century + EFI_ACPI_6_3_MSI_NOT_SUPPORTED, // UINT16 IaPcBootArch (Reserved on ARM) + EFI_ACPI_RESERVED_BYTE, // UINT8 Reserved1 + EFI_ACPI_6_3_WBINVD | EFI_ACPI_6_3_SLP_BUTTON | // UINT32 Flags + EFI_ACPI_6_3_HW_REDUCED_ACPI, + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE ResetReg + 0, // UINT8 ResetValue + EFI_ACPI_6_3_ARM_PSCI_COMPLIANT, // UINT16 ArmBootArchFlags + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION, // UINT8 MinorRevision + 0, // UINT64 XFirmwareCtrl + 0, // UINT64 XDsdt + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe0Blk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe1Blk + NULL_GAS, // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE SleepControlReg + NULL_GAS // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE SleepStatusReg +}; + +// +// Reference the table being generated to prevent the optimizer from removing the +// data structure from the executable +// +VOID* CONST ReferenceAcpiTable = &Fadt; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac0.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac0.asl new file mode 100644 index 0000000..a800b7e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac0.asl @@ -0,0 +1,96 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +// Gigabit Media Access Controller (GMAC0) +Device (MAC0) { + Name (_HID, "RKCP6543") + Name (_CID, Package() { + "PRP0001" + }) + Name (_UID, 60) + Name (_CCA, 0) + Name (_STA, 0xF) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe1b0000, 0x10000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 259, 258 } + }) + Return (RBUF) + } + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", Package () { "snps,dwmac-4.20a", "snps,dwmac" } }, + Package () { "interrupt-names", Package () { "macirq", "eth_wake_irq" } }, + Package () { "snps,mixed-burst", 1 }, + Package () { "snps,tso", 1 }, + Package () { "snps,axi-config", "AXIC" }, + } + }) + + Name (AXIC, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "snps,wr_osr_lmt", 4 }, + Package () { "snps,rd_osr_lmt", 8 }, + Package () { "snps,blen", Package () { 0, 0, 0, 0, 16, 8, 4 } }, + } + }) + + Method (_DSM, 4, Serialized) { + // PHP_GRF_CLK_CON1 + OperationRegion (PGRF, SystemMemory, 0xfd5b0070, 0x4) + Field (PGRF, DWordAcc, NoLock, Preserve) { + CON1, 32 + } + + // Check the UUID + If (Arg0 == ToUUID ("d637828d-556c-4829-966a-237072f00ff1")) { + // Check the revision + If (Arg1 >= 0) { + // Check the function index + Switch (ToInteger (Arg2)) { + // + // Supported functions: + // Bit 0 - Indicates support for functions other than 0 + // Bit 1 - Indicates support for setting the MII speed + // + Case (0) { + Return (Buffer () { 0x03 }) + } + + // + // Function Index 1: Set MII speed + // + Case (1) { + Local0 = DerefOf (Arg3[0]) + + Switch (ToInteger (Local0)) { + Case (1000) { + CON1 = 0x000c0000 + } + Case (100) { + CON1 = 0x000c000c + } + Case (10) { + CON1 = 0x000c0008 + } + } + Return (Buffer () { 0x00 }) + } + } // Function index check + } // Revision check + } // UUID check + Return (Buffer () { 0x0 }) + } // _DSM +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac1.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac1.asl new file mode 100644 index 0000000..314c4bb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gmac1.asl @@ -0,0 +1,96 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +// Gigabit Media Access Controller (GMAC1) +Device (MAC1) { + Name (_HID, "RKCP6543") + Name (_CID, Package() { + "PRP0001" + }) + Name (_UID, 61) + Name (_CCA, 0) + Name (_STA, 0xF) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe1c0000, 0x10000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 266, 265 } + }) + Return (RBUF) + } + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", Package () { "snps,dwmac-4.20a", "snps,dwmac" } }, + Package () { "interrupt-names", Package () { "macirq", "eth_wake_irq" } }, + Package () { "snps,mixed-burst", 1 }, + Package () { "snps,tso", 1 }, + Package () { "snps,axi-config", "AXIC" }, + } + }) + + Name (AXIC, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "snps,wr_osr_lmt", 4 }, + Package () { "snps,rd_osr_lmt", 8 }, + Package () { "snps,blen", Package () { 0, 0, 0, 0, 16, 8, 4 } }, + } + }) + + Method (_DSM, 4, Serialized) { + // PHP_GRF_CLK_CON1 + OperationRegion (PGRF, SystemMemory, 0xfd5b0070, 0x4) + Field (PGRF, DWordAcc, NoLock, Preserve) { + CON1, 32 + } + + // Check the UUID + If (Arg0 == ToUUID ("d637828d-556c-4829-966a-237072f00ff1")) { + // Check the revision + If (Arg1 >= 0) { + // Check the function index + Switch (ToInteger (Arg2)) { + // + // Supported functions: + // Bit 0 - Indicates support for functions other than 0 + // Bit 1 - Indicates support for setting the MII speed + // + Case (0) { + Return (Buffer () { 0x03 }) + } + + // + // Function Index 1: Set MII speed + // + Case (1) { + Local0 = DerefOf (Arg3[0]) + + Switch (ToInteger (Local0)) { + Case (1000) { + CON1 = 0x01800000 + } + Case (100) { + CON1 = 0x01800180 + } + Case (10) { + CON1 = 0x01800100 + } + } + Return (Buffer () { 0x00 }) + } + } // Function index check + } // Revision check + } // UUID check + Return (Buffer () { 0x0 }) + } // _DSM +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gpio.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gpio.asl new file mode 100644 index 0000000..59255c0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gpio.asl @@ -0,0 +1,166 @@ +/** @file + * + * Copyright (c) 2022, Rockchip Electronics Co. Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + +// +// Description: GPIO +// +Device (GPI0) +{ + Name (_HID, "RKCP3002") + Name (_CID, "PRP0001") + Name (_UID, 0x0) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,gpio-bank" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFD8A0000, 0x100) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {309} + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +}//GPIO0 + + +Device (GPI1) +{ + Name (_HID, "RKCP3002") + Name (_CID, "PRP0001") + Name (_UID, 0x1) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,gpio-bank" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFEC20000, 0x100) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {310} + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +}//GPIO1 + +Device (GPI2) +{ + Name (_HID, "RKCP3002") + Name (_CID, "PRP0001") + Name (_UID, 0x2) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,gpio-bank" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFEC30000, 0x100) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {311} + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +}//GPIO2 + +Device (GPI3) +{ + Name (_HID, "RKCP3002") + Name (_CID, "PRP0001") + Name (_UID, 0x3) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,gpio-bank" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFEC40000, 0x100) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {312} + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +}//GPIO3 + +Device (GPI4) +{ + Name (_HID, "RKCP3002") + Name (_CID, "PRP0001") + Name (_UID, 0x4) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,gpio-bank" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFEC50000, 0x100) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) {313} + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +}//GPIO4 + +Device (PINC) +{ + Name (_HID, "PRP0001") + Name (_UID, 0x4) + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "rockchip,rk3588-pinctrl" }, + } + }) + Method (_CRS, 0x0, NotSerialized) + { + Name (RBUF, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xFD5F0000, 0x10000) + }) + Return(RBUF) + } + Method (_STA) + { + Return(0xf) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gtdt.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gtdt.aslc new file mode 100644 index 0000000..e17ebc1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Gtdt.aslc @@ -0,0 +1,71 @@ +/** @file +* Generic Timer Description Table (GTDT) +* +* Copyright (c) 2018, Linaro Limited. All rights reserved. +* Copyright (c) 2012 - 2016, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include + +#include "AcpiTables.h" + +#define GTDT_GLOBAL_FLAGS_MAPPED EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_MEMORY_MAPPED_BLOCK_PRESENT +#define GTDT_GLOBAL_FLAGS_NOT_MAPPED 0 +#define GTDT_GLOBAL_FLAGS_EDGE EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_INTERRUPT_MODE +#define GTDT_GLOBAL_FLAGS_LEVEL 0 + +// Note: We could have a build flag that switches between memory mapped/non-memory mapped timer +#ifdef SYSTEM_TIMER_BASE_ADDRESS + #define GTDT_GLOBAL_FLAGS (GTDT_GLOBAL_FLAGS_MAPPED | GTDT_GLOBAL_FLAGS_LEVEL) +#else + #define GTDT_GLOBAL_FLAGS (GTDT_GLOBAL_FLAGS_NOT_MAPPED | GTDT_GLOBAL_FLAGS_LEVEL) + #define SYSTEM_TIMER_BASE_ADDRESS 0xFFFFFFFFFFFFFFFF +#endif + +#define GTDT_TIMER_EDGE_TRIGGERED EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE +#define GTDT_TIMER_LEVEL_TRIGGERED 0 +#define GTDT_TIMER_ACTIVE_LOW EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY +#define GTDT_TIMER_ACTIVE_HIGH 0 + +#define GTDT_GTIMER_FLAGS (GTDT_TIMER_ACTIVE_LOW | GTDT_TIMER_LEVEL_TRIGGERED) + +#pragma pack (1) + +typedef struct { + EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE Gtdt; +} GENERIC_TIMER_DESCRIPTION_TABLE; + +#pragma pack () + +GENERIC_TIMER_DESCRIPTION_TABLE Gtdt = { + { + ACPI_HEADER( + EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE, + GENERIC_TIMER_DESCRIPTION_TABLE, + EFI_ACPI_5_1_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION + ), + SYSTEM_TIMER_BASE_ADDRESS, // UINT64 PhysicalAddress + 0, // UINT32 Reserved + FixedPcdGet32 (PcdArmArchTimerSecIntrNum), // UINT32 SecurePL1TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 SecurePL1TimerFlags + FixedPcdGet32 (PcdArmArchTimerIntrNum), // UINT32 NonSecurePL1TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL1TimerFlags + FixedPcdGet32 (PcdArmArchTimerVirtIntrNum), // UINT32 VirtualTimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 VirtualTimerFlags + FixedPcdGet32 (PcdArmArchTimerHypIntrNum), // UINT32 NonSecurePL2TimerGSIV + GTDT_GTIMER_FLAGS, // UINT32 NonSecurePL2TimerFlags + 0xFFFFFFFFFFFFFFFF, // UINT64 CntReadBasePhysicalAddress + 0, // UINT32 PlatformTimerCount + }, +}; + +// +// Reference the table being generated to prevent the optimizer +// from removing the data structure from the executable +// +VOID* CONST ReferenceAcpiTable = &Gtdt; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2c.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2c.asl new file mode 100644 index 0000000..428a738 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2c.asl @@ -0,0 +1,200 @@ +/** @file + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + + Device (I2C1) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 1) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfea90000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 350 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C2) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 2) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeaa0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 351 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C3) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeab0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 352 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C4) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 4) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeac0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 353 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C5) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 5) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfead0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 354 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C6) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 6) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfec80000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 355 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C7) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 7) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfec90000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 356 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } + + Device (I2C8) { + Name (_HID, "RKCP3001") + Name (_CID, "PRP0001") + Name (_UID, 8) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeca0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 357 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "i2c,clk-rate", 198000000 }, + Package (2) { "rockchip,bclk", 198000000 }, + Package (2) { "#address-cells", 1 }, + Package (2) { "#size-cells", 0 }, + } + }) + } diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2s.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2s.asl new file mode 100644 index 0000000..64d2424 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/I2s.asl @@ -0,0 +1,240 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2024, CoolStar. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + +#define RK3588_PLL_AUPLL_RATE 786432000 +#define RK3588_PLL_CPLL_RATE 1500000000 + +#define I2S_INITIAL_CLOCK (256 * 48000) + +#define I2S_DSM_UUID ToUUID ("7056bfa1-af0b-48e5-b67f-139f2004a26a") + +#if FixedPcdGetBool(PcdI2S0Supported) + Device (I2S0) { + Name (_HID, "RKCP3003") + Name (_UID, 0) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe470000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 212 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "rockchip,dma", "DMA0" }, + Package (2) { "rockchip,tx", 0 }, + Package (2) { "rockchip,rx", 1 }, + Package (2) { "rockchip,tplg", BOARD_I2S0_TPLG }, + } + }) + Name (_DEP, Package () { \_SB.DMA0 }) + + Method (_INI, 0, Serialized) { + _DSM (I2S_DSM_UUID, 0, 1, Package () { I2S_INITIAL_CLOCK }) + } + + Method (_DSM, 4, Serialized) { + // CRU_CLKSEL_CON24 + OperationRegion (CRU, SystemMemory, 0xFD7C0360, 0x8) + Field (CRU, DWordAcc, NoLock, Preserve) { + C24, 32, + C25, 32 + } + + // Check the UUID + If (Arg0 == I2S_DSM_UUID) { + // Check the revision + If (Arg1 >= 0) { + // Check the function index + Switch (ToInteger (Arg2)) { + // + // Supported functions: + // Bit 0 - Indicates support for functions other than 0 + // Bit 1 - Indicates support for setting TX master clock + // Bit 2 - Indicates support for setting RX master clock + // + Case (0) { + Return (Buffer () { 0x03 }) + } + + // + // Function Index 1: Set TX master clock + // Takes the target clock rate in Hz, returns the actual set rate. + // + Case (1) { + // Source divided by clk_i2s0_8ch_tx_src_div + 1 + Local0 = RK3588_PLL_AUPLL_RATE / (((C24 >> 4) & 0xf) + 1) + + // Compute numerator/denumerator + Local1 = FRBA (DerefOf (Arg3[0]), Local0, 0xFFFF, 0xFFFF) + + // Set fractional register + C25 = (DerefOf (Local1[0])) << 16 | DerefOf (Local1[1]) + + Return ((Local0 * DerefOf (Local1[0])) / DerefOf (Local1[1])) + } + } // Function index check + } // Revision check + } // UUID check + Return (Buffer () { 0x0 }) + } // _DSM + } +#endif + +#if FixedPcdGetBool(PcdI2S1Supported) + Device (I2S1) { + Name (_HID, "RKCP3003") + Name (_UID, 1) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe480000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 213 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "rockchip,dma", "DMA0" }, + Package (2) { "rockchip,tx", 2 }, + Package (2) { "rockchip,rx", 3 }, + Package (2) { "rockchip,tplg", BOARD_I2S1_TPLG }, + // XXX: Currently I2S1 is only used by Orange Pi 5. + // The following properties should be board specific + Package (2) { "rockchip,i2s-tx-route", 0x3210 },, + Package (2) { "rockchip,i2s-rx-route", 0x1320 }, + } + }) + Name (_DEP, Package () { \_SB.DMA0 }) + + Method (_INI, 0, Serialized) { + _DSM (I2S_DSM_UUID, 0, 1, Package () { I2S_INITIAL_CLOCK }) + } + + Method (_DSM, 4, Serialized) { + // PMU1CRU_CLKSEL_CON05 + OperationRegion (CRU, SystemMemory, 0xFD7F0314, 0x8) + Field (CRU, DWordAcc, NoLock, Preserve) { + C05, 32, + C06, 32 + } + + // Check the UUID + If (Arg0 == I2S_DSM_UUID) { + // Check the revision + If (Arg1 >= 0) { + // Check the function index + Switch (ToInteger (Arg2)) { + // + // Supported functions: + // Bit 0 - Indicates support for functions other than 0 + // Bit 1 - Indicates support for setting TX master clock + // Bit 2 - Indicates support for setting RX master clock + // + Case (0) { + Return (Buffer () { 0x03 }) + } + + // + // Function Index 1: Set TX master clock + // Takes the target clock rate in Hz, returns the actual set rate. + // + Case (1) { + // Source divided by clk_i2s1_8ch_tx_src_div + 1 + Local0 = RK3588_PLL_CPLL_RATE / (((C05 >> 2) & 0xf) + 1) + + // Compute numerator/denumerator + Local1 = FRBA (DerefOf (Arg3[0]), Local0, 0xFFFF, 0xFFFF) + + // Set fractional register + C06 = (DerefOf (Local1[0])) << 16 | DerefOf (Local1[1]) + + Return ((Local0 * DerefOf (Local1[0])) / DerefOf (Local1[1])) + } + } // Function index check + } // Revision check + } // UUID check + Return (Buffer () { 0x0 }) + } // _DSM + } +#endif + + // + // FRBA - Find Rational Best Approximation + // + // Arguments: (4) + // Arg0 - Given numerator + // Arg1 - Given denominator + // Arg2 - Maximum numerator + // Arg3 - Maximum denominator + // + // Return: + // Package of two integers: best numerator, best denominator + // + Function (FRBA, PkgObj, { IntObj, IntObj, IntObj, IntObj }) { + // + // Variables used throughout this function: + // Local0, Local1 - Remaining numerator/denominator for Euclidean algorithm + // Local2, Local4 - Previous numerator/denominator convergent + // Local3, Local5 - Current numerator/denominator convergent + // Local6 - Temporary variable for swapping values around + // Local7 - Next term in the continued fraction + // + Local0 = Arg0 + Local1 = Arg1 + Local2 = 0 + Local3 = 1 + Local4 = 1 + Local5 = 0 + + While (1) { + // Reached limits? Fall back to previous convergent. + If (Local3 > Arg2 || Local5 > Arg3) { + Local3 = Local2 + Local5 = Local4 + Break + } + + // No remainder? We're done. + If (Local1 == 0) { + Break + } + + // Find next term for convergent + Local7 = Local0 / Local1 + + // Set remainder + Local6 = Local1 + Local1 = Local0 % Local1 + Local0 = Local6 + + // Calculate numerator and save previous one + Local6 = Local2 + Local7 * Local3 + Local2 = Local3 + Local3 = Local6 + + // Caculate denominator and save previous one + Local6 = Local4 + Local7 * Local5 + Local4 = Local5 + Local5 = Local6 + } + + // Prepare return object + Local0 = Package (2) { 0, 0 } + Local0[0] = Local3 + Local0[1] = Local5 + + Return (Local0) + } diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Madt.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Madt.aslc new file mode 100644 index 0000000..05cd5d1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Madt.aslc @@ -0,0 +1,123 @@ +/** @file +* Multiple APIC Description Table (MADT) +* +* Copyright (c) 2021, Jared McNeill +* Copyright (c) 2012 - 2016, ARM Limited. All rights reserved. +* Copyright (c) 2018, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include + +#include "AcpiTables.h" + +// +// Multiple APIC Description Table +// +#pragma pack (1) + +typedef struct { + EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER Header; + EFI_ACPI_6_0_GIC_STRUCTURE GicInterfaces[8]; + EFI_ACPI_6_0_GIC_DISTRIBUTOR_STRUCTURE GicDistributor; + EFI_ACPI_6_0_GICR_STRUCTURE GicRedistributors; + // EFI_ACPI_6_0_GIC_MSI_FRAME_STRUCTURE GicMsiFrame; + // EFI_ACPI_6_0_GIC_ITS_STRUCTURE GicIts[2]; +} EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE; + +#pragma pack () + +EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE Madt = { + { + ACPI_HEADER ( + EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, + EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE, + EFI_ACPI_6_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION + ), + // + // MADT specific fields + // + 0, // LocalApicAddress + 0, // Flags + }, + { + // Format: EFI_ACPI_6_0_GICC_STRUCTURE_INIT(GicId, AcpiCpuUid, Mpidr, + // Flags, + // PmuIrq, GicBase, GicVBase, GicHBase, GsivId, GicRBase, Efficiency) + // Note: The GIC Structure of the primary CPU must be the first entry + // (see note in 5.2.12.14 GICC Structure of ACPI v6.0). + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A55-0 + 0, 0, GET_MPID(0, 0x000), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 0), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A55-1 + 0, 1, GET_MPID(0, 0x100), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 0), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A55-2 + 0, 2, GET_MPID(0, 0x200), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 0), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A55-3 + 0, 3, GET_MPID(0, 0x300), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 0), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A76-0 + 0, 4, GET_MPID(0, 0x400), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 1), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A76-1 + 0, 5, GET_MPID(0, 0x500), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 1), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A76-2 + 0, 6, GET_MPID(0, 0x600), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 1), + EFI_ACPI_6_0_GICC_STRUCTURE_INIT( // A76-3 + 0, 7, GET_MPID(0, 0x700), + EFI_ACPI_6_0_GIC_ENABLED, + 23, 0, 0, 0, 25, 0, 1), + }, + // GIC Distributor Entry + EFI_ACPI_6_0_GIC_DISTRIBUTOR_INIT (0, FixedPcdGet64 (PcdGicDistributorBase), + 0, EFI_ACPI_6_0_GIC_V3), + // GIC Redistributors Entry + EFI_ACPI_6_0_GIC_REDISTRIBUTOR_INIT (FixedPcdGet64 (PcdGicRedistributorsBase), + 0x100000), + // GIC MSI Frame + // + // Disable for now, will need to put it behind a config option + // as some OSes are not happy about it (like Windows). + // + // { + // EFI_ACPI_6_0_GIC_MSI_FRAME, + // sizeof (EFI_ACPI_6_0_GIC_MSI_FRAME_STRUCTURE), + // EFI_ACPI_RESERVED_WORD, + // 0, + // FixedPcdGet64 (PcdGicDistributorBase) + 0x10000, + // EFI_ACPI_6_0_SPI_COUNT_BASE_SELECT, + // 56, + // 424 + // }, + + /* ITS is broken on RK35xx!*/ + // Linux has a workaround for the erratum, but no way to describe + // this in ACPI yet. + // + // { + // EFI_ACPI_6_0_GIC_ITS_FRAME_INIT(0, 0xfe640000), + // EFI_ACPI_6_0_GIC_ITS_FRAME_INIT(1, 0xfe660000) + // }, +}; + +// +// Reference the table being generated to prevent the optimizer +// from removing the data structure from the executable +// +VOID* CONST ReferenceAcpiTable = &Madt; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Mcfg.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Mcfg.aslc new file mode 100644 index 0000000..ce84490 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Mcfg.aslc @@ -0,0 +1,102 @@ +/** @file + * + * PCI Express Memory-mapped Configuration Space base address description table (MCFG) + * + * Copyright (c) 2021, Jared McNeill + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +// +// MCFG is patched by AcpiPlatformDxe. +// + +RK3588_MCFG_TABLE Mcfg = { + { + ACPI_HEADER ( + EFI_ACPI_6_4_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE, + RK3588_MCFG_TABLE, + EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION + ), + }, + { // Main config space + { + PCIE_CFG_BASE (0), + 0, // PciSegmentNumber + 1, // PciBusMin + 1, // PciBusMax + 0 // Reserved + }, + { + PCIE_CFG_BASE (1), + 1, // PciSegmentNumber + 1, // PciBusMin + 1, // PciBusMax + 0 // Reserved + }, + { + PCIE_CFG_BASE (2), + 2, // PciSegmentNumber + 1, // PciBusMin + 1, // PciBusMax + 0 // Reserved + }, + { + PCIE_CFG_BASE (3), + 3, // PciSegmentNumber + 1, // PciBusMin + 1, // PciBusMax + 0 // Reserved + }, + { + PCIE_CFG_BASE (4), + 4, // PciSegmentNumber + 1, // PciBusMin + 1, // PciBusMax + 0 // Reserved + } + }, + { // Root Port DBI config space (for Windows) + { + PCIE_DBI_BASE (0), + 0, // PciSegmentNumber + 0, // PciBusMin + 0, // PciBusMax + 0 // Reserved + }, + { + PCIE_DBI_BASE (1), + 1, // PciSegmentNumber + 0, // PciBusMin + 0, // PciBusMax + 0 // Reserved + }, + { + PCIE_DBI_BASE (2), + 2, // PciSegmentNumber + 0, // PciBusMin + 0, // PciBusMax + 0 // Reserved + }, + { + PCIE_DBI_BASE (3), + 3, // PciSegmentNumber + 0, // PciBusMin + 0, // PciBusMax + 0 // Reserved + }, + { + PCIE_DBI_BASE (4), + 4, // PciSegmentNumber + 0, // PciBusMin + 0, // PciBusMax + 0 // Reserved + } + } +}; + +VOID* CONST ReferenceAcpiTable = &Mcfg; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pcie.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pcie.asl new file mode 100644 index 0000000..99418bc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pcie.asl @@ -0,0 +1,120 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define PCIE_ROOT_COMPLEX(Segment, LegacyIrq) \ + Device (PCI ## Segment) { \ + Name (_HID, "PNP0A08") \ + Name (_CID, "PNP0A03") \ + Name (_CCA, 0) \ + Name (_UID, Segment) \ + Name (_SEG, Segment) \ + Method (_BBN) { \ + Return (PBMI) \ + } \ + Name (_STA, 0xF) \ + \ + Name (_PRT, Package() { \ + Package (4) { 0x0FFFF, 0, 0, LegacyIrq }, \ + Package (4) { 0x0FFFF, 1, 0, LegacyIrq }, \ + Package (4) { 0x0FFFF, 2, 0, LegacyIrq }, \ + Package (4) { 0x0FFFF, 3, 0, LegacyIrq } \ + }) \ + \ + Method (_CRS, 0, Serialized) { \ + Name (RBUF, ResourceTemplate () { \ + WORDBUSNUMBER_BUF (00, ResourceProducer) \ + DWORDMEMORY_BUF (01, ResourceProducer) \ + QWORDMEMORY_BUF (02, ResourceProducer) \ + QWORDIO_BUF (03, ResourceProducer) \ + }) \ + WORD_SET (00, PBMI, PBMA - PBMI + 1, 0) \ + DWORD_SET (01, PCIE_MEM_BASE (Segment), PCIE_MEM_SIZE, 0) \ + QWORD_SET (02, PCIE_MEM64_BASE (Segment), PCIE_MEM64_SIZE, 0) \ + QWORD_SET (03, PCIE_IO_BASE, PCIE_IO_SIZE, PCIE_IO_XLATE (Segment)) \ + Return (RBUF) \ + } \ + \ + Device (RES0) { \ + Name (_HID, "AMZN0001") \ + Name (_CID, "PNP0C02") \ + Name (_UID, Segment) \ + Method (_CRS, 0, Serialized) { \ + Name (RBUF, ResourceTemplate () { \ + QWORDMEMORY_BUF (00, ResourceProducer) \ + }) \ + QWORD_SET (00, PCIE_DBI_BASE (Segment), PCIE_DBI_SIZE, 0) \ + Return (RBUF) \ + } \ + } \ + \ + Device (RES1) { \ + Name (_HID, "PNP0C02") \ + Name (_UID, Segment + 1) \ + Method (_CRS, 0, Serialized) { \ + Name (RBUF, ResourceTemplate () { \ + QWORDMEMORY_BUF (00, ResourceProducer) \ + }) \ + QWORD_SET (00, PCIE_CFG_BASE (Segment), SIZE_256MB, 0) \ + Return (RBUF) \ + } \ + } \ + \ + Name (SUPP, Zero) /* PCI _OSC Support Field value */ \ + Name (CTRL, Zero) /* PCI _OSC Control Field value */ \ + \ + Method (_OSC, 4) { \ + If (Arg0 == ToUUID ("33DB4D5B-1FF7-401C-9657-7441C03DD766")) { \ + /* Create DWord-adressable fields from the Capabilities Buffer */ \ + CreateDWordField (Arg3, 0, CDW1) \ + CreateDWordField (Arg3, 4, CDW2) \ + CreateDWordField (Arg3, 8, CDW3) \ + \ + /* Save Capabilities DWord2 & 3 */ \ + SUPP = CDW2 \ + CTRL = CDW3 \ + \ + /* Mask out native hot plug control */ \ + CTRL &= 0x1E \ + \ + /* Always allow native PME, AER and Capability Structure control */ \ + /* Never allow SHPC and LTR control */ \ + CTRL &= 0x1D \ + \ + /* Unknown revision */ \ + If (Arg1 != 1) { \ + Cdw1 |= 0x08 \ + } \ + \ + /* Capabilities bits were masked */ \ + If (CDW3 != CTRL) { \ + CDW1 |= 0x10 \ + } \ + \ + /* Update DWORD3 in the buffer */ \ + CDW3 = CTRL \ + Return (Arg3) \ + } Else { \ + /* Unrecognized UUID */ \ + CDW1 |= 4 \ + Return (Arg3) \ + } \ + } \ + } + +Scope (\_SB_) { + Name (PBMI, 0xABCD) // PCI Bus Minimum + Name (PBMA, 0xABCD) // PCI Bus Maximum + + PCIE_ROOT_COMPLEX (0, 292) + PCIE_ROOT_COMPLEX (1, 287) + PCIE_ROOT_COMPLEX (2, 272) + PCIE_ROOT_COMPLEX (3, 277) + PCIE_ROOT_COMPLEX (4, 282) +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pptt.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pptt.aslc new file mode 100644 index 0000000..207b5d2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Pptt.aslc @@ -0,0 +1,267 @@ +/** @file + * + * RK3588 SoC Processor Properties Topology Table + * + * This table is based on the ACPI 6.2 spec because Windows + * (tested with build 22621.1992) is not able to properly parse + * newer revisions: + * - ACPI 6.3 (rev 2) leads to doubled L3 cache size. + * - ACPI 6.4 (rev 3) leads to a 0x7E bug check due to the new + * Cache ID field in the Cache Type Structure (see Table 5.140). + * + * It also entirely ignores cache sizes described here, relying on + * CCSIDR instead. The info there is mostly correct, except for L3. + * + * Linux parses and displays all this data correctly. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#pragma pack(1) +typedef struct { + EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR Package; + UINT32 L3CacheRef; +} RK3588_PPTT_PACKAGE_NODE; + +typedef struct { + EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR Cluster; +} RK3588_PPTT_CLUSTER_NODE; + +typedef struct { + EFI_ACPI_6_2_PPTT_STRUCTURE_PROCESSOR Core; + UINT32 L1DCacheRef; + UINT32 L1ICacheRef; + UINT32 L2CacheRef; +} RK3588_PPTT_CORE_NODE; + +typedef struct { + EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER Header; + RK3588_PPTT_PACKAGE_NODE Package; + RK3588_PPTT_CLUSTER_NODE Clusters[3]; + RK3588_PPTT_CORE_NODE Cores[8]; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE PackageL3Cache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A55L1DCache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A55L1ICache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A55L2Cache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A76L1DCache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A76L1ICache; + EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE A76L2Cache; +} RK3588_PPTT; +#pragma pack() + +/// +/// For PPTT struct processor flags +/// +#define EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL 0x0 +#define EFI_ACPI_6_2_PPTT_PACKAGE_PHYSICAL 0x1 +#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID 0x1 + +/// +/// For PPTT struct cache flags +/// +#define EFI_ACPI_6_2_PPTT_CACHE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_CACHE_SIZE_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_CACHE_TYPE_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_CACHE_TYPE_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_WRITE_POLICY_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_WRITE_POLICY_VALID 0x1 +#define EFI_ACPI_6_2_PPTT_LINE_SIZE_INVALID 0x0 +#define EFI_ACPI_6_2_PPTT_LINE_SIZE_VALID 0x1 + +#define PPTT_DATA_CACHE_ATTRIBUTES \ + { \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_DATA, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK \ + } + +#define PPTT_INST_CACHE_ATTRIBUTES \ + { \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_INSTRUCTION, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK \ + } + +#define PPTT_UNIFIED_CACHE_ATTRIBUTES \ + { \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_ALLOCATION_READ_WRITE, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_CACHE_TYPE_UNIFIED, \ + EFI_ACPI_6_2_CACHE_ATTRIBUTES_WRITE_POLICY_WRITE_BACK \ + } + +#define RK3588_PPTT_CLUSTER_NODE_INIT(ClusterUid) { \ + { /* Cluster */ \ + EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR, /* Type */ \ + sizeof (RK3588_PPTT_CLUSTER_NODE), /* Length */ \ + { /* Reserved[2] */ \ + EFI_ACPI_RESERVED_BYTE, \ + EFI_ACPI_RESERVED_BYTE \ + }, \ + { /* Flags */ \ + EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL, \ + EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID \ + }, \ + OFFSET_OF (RK3588_PPTT, Package), /* Parent */ \ + ClusterUid, /* AcpiProcessorId */ \ + 0 /* NumberOfPrivateResources */ \ + } \ +} + +#define RK3588_PPTT_CORE_NODE_INIT(ClusterIndex, CoreUid, \ + L1DCacheField, L1ICacheField, L2CacheField) { \ + { /* Core */ \ + EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR, /* Type */ \ + sizeof (RK3588_PPTT_CORE_NODE), /* Length */ \ + { /* Reserved[2] */ \ + EFI_ACPI_RESERVED_BYTE, \ + EFI_ACPI_RESERVED_BYTE \ + }, \ + { /* Flags */ \ + EFI_ACPI_6_2_PPTT_PACKAGE_NOT_PHYSICAL, \ + EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID \ + }, \ + OFFSET_OF (RK3588_PPTT, \ + Clusters[ClusterIndex]), /* Parent */ \ + CoreUid, /* AcpiProcessorId */ \ + 3 /* NumberOfPrivateResources */ \ + }, \ + OFFSET_OF (RK3588_PPTT, L1DCacheField), /* L1DCacheRef */ \ + OFFSET_OF (RK3588_PPTT, L1ICacheField), /* L1ICacheRef */ \ + OFFSET_OF (RK3588_PPTT, L2CacheField) /* L2CacheRef */ \ +} + +#define RK3588_PPTT_A55_CORE_NODE_INIT(ClusterIndex, CoreUid) \ + RK3588_PPTT_CORE_NODE_INIT ( \ + ClusterIndex, CoreUid, \ + A55L1DCache, A55L1ICache, A55L2Cache \ + ) + +#define RK3588_PPTT_A76_CORE_NODE_INIT(ClusterIndex, CoreUid) \ + RK3588_PPTT_CORE_NODE_INIT ( \ + ClusterIndex, CoreUid, \ + A76L1DCache, A76L1ICache, A76L2Cache \ + ) + +#define RK3588_PPTT_CACHE_NODE_INIT(NextLevelOfCache, Size, \ + NumberOfSets, Attributes) { \ + EFI_ACPI_6_2_PPTT_TYPE_CACHE, /* Type */ \ + sizeof (EFI_ACPI_6_2_PPTT_STRUCTURE_CACHE), /* Length */ \ + { /* Reserved[2] */ \ + EFI_ACPI_RESERVED_BYTE, \ + EFI_ACPI_RESERVED_BYTE \ + }, \ + { /* Flags */ \ + EFI_ACPI_6_2_PPTT_CACHE_SIZE_VALID, \ + EFI_ACPI_6_2_PPTT_NUMBER_OF_SETS_VALID, \ + EFI_ACPI_6_2_PPTT_ASSOCIATIVITY_VALID, \ + EFI_ACPI_6_2_PPTT_ALLOCATION_TYPE_VALID, \ + EFI_ACPI_6_2_PPTT_CACHE_TYPE_VALID, \ + EFI_ACPI_6_2_PPTT_WRITE_POLICY_VALID, \ + EFI_ACPI_6_2_PPTT_LINE_SIZE_VALID \ + }, \ + NextLevelOfCache, /* NextLevelOfCache */ \ + Size, /* Size */ \ + NumberOfSets, /* NumberOfSets */ \ + Size / NumberOfSets / 64, /* Associativity */ \ + Attributes, /* Attributes */ \ + 64 /* LineSize */ \ +} + +STATIC RK3588_PPTT Pptt = { + { + ACPI_HEADER ( + EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE, + RK3588_PPTT, + EFI_ACPI_6_2_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION + ), + }, + { + { /* Package */ + EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR, /* Type */ + sizeof (RK3588_PPTT_PACKAGE_NODE), /* Length */ + { /* Reserved[2] */ + EFI_ACPI_RESERVED_BYTE, + EFI_ACPI_RESERVED_BYTE + }, + { /* Flags */ + EFI_ACPI_6_2_PPTT_PACKAGE_PHYSICAL, + EFI_ACPI_6_2_PPTT_PROCESSOR_ID_VALID + }, + 0, /* Parent */ + 8, /* AcpiProcessorId */ + 1 /* NumberOfPrivateResources */ + }, + OFFSET_OF (RK3588_PPTT, PackageL3Cache) + }, + { /* Clusters */ + RK3588_PPTT_CLUSTER_NODE_INIT (9), /* Little cluster */ + RK3588_PPTT_CLUSTER_NODE_INIT (10), /* Big cluster 0 */ + RK3588_PPTT_CLUSTER_NODE_INIT (11) /* Big cluster 1 */ + }, + { /* Cores */ + RK3588_PPTT_A55_CORE_NODE_INIT (0, 0), /* 4x Cortex-A55 (Little cluster) */ + RK3588_PPTT_A55_CORE_NODE_INIT (0, 1), + RK3588_PPTT_A55_CORE_NODE_INIT (0, 2), + RK3588_PPTT_A55_CORE_NODE_INIT (0, 3), + RK3588_PPTT_A76_CORE_NODE_INIT (1, 4), /* 2x Cortex-A76 (Big cluster 0) */ + RK3588_PPTT_A76_CORE_NODE_INIT (1, 5), + RK3588_PPTT_A76_CORE_NODE_INIT (2, 6), /* 2x Cortex-A76 (Big cluster 1) */ + RK3588_PPTT_A76_CORE_NODE_INIT (2, 7) + }, + RK3588_PPTT_CACHE_NODE_INIT ( /* PackageL3Cache */ + 0, /* NextLevelOfCache */ + SIZE_1MB * 3, /* Size */ + 4096, /* NumberOfSets */ + PPTT_UNIFIED_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A55L1DCache */ + OFFSET_OF (RK3588_PPTT, A55L2Cache), /* NextLevelOfCache */ + SIZE_32KB, /* Size */ + 128, /* NumberOfSets */ + PPTT_DATA_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A55L1ICache */ + OFFSET_OF (RK3588_PPTT, A55L2Cache), /* NextLevelOfCache */ + SIZE_32KB, /* Size */ + 128, /* NumberOfSets */ + PPTT_INST_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A55L2Cache */ + 0, /* NextLevelOfCache */ + SIZE_128KB, /* Size */ + 512, /* NumberOfSets */ + PPTT_UNIFIED_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A76L1DCache */ + OFFSET_OF (RK3588_PPTT, A76L2Cache), /* NextLevelOfCache */ + SIZE_64KB, /* Size */ + 256, /* NumberOfSets */ + PPTT_DATA_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A76L1ICache */ + OFFSET_OF (RK3588_PPTT, A76L2Cache), /* NextLevelOfCache */ + SIZE_64KB, /* Size */ + 256, /* NumberOfSets */ + PPTT_INST_CACHE_ATTRIBUTES /* Attributes */ + ), + RK3588_PPTT_CACHE_NODE_INIT ( /* A76L2Cache */ + 0, /* NextLevelOfCache */ + SIZE_512KB, /* Size */ + 1024, /* NumberOfSets */ + PPTT_UNIFIED_CACHE_ATTRIBUTES /* Attributes */ + ) +}; + +VOID* CONST ReferenceAcpiTable = &Pptt; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/RK3588PcieIort.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/RK3588PcieIort.aslc new file mode 100644 index 0000000..172ef9a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/RK3588PcieIort.aslc @@ -0,0 +1,121 @@ +/** @file +* I/O Remapping Table (Iort) +* +* Copyright (c) 2018, ARM Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include "AcpiTables.h" + +#pragma pack(1) + +typedef struct +{ + EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE ItsNode; + UINT32 ItsIdentifiers; +} ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE; + +typedef struct +{ + EFI_ACPI_6_0_IO_REMAPPING_RC_NODE RcNode; + EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE RcIdMap; +} ARM_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE; + +typedef struct +{ + EFI_ACPI_6_0_IO_REMAPPING_TABLE Header; + ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE Its0Node; + ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE Its1Node; + ARM_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE Rc3x4Node; +} ARM_EFI_ACPI_6_0_IO_REMAPPING_TABLE; + +#pragma pack (1) + +ARM_EFI_ACPI_6_0_IO_REMAPPING_TABLE Iort = +{ + // EFI_ACPI_6_0_IO_REMAPPING_TABLE + { + ACPI_HEADER // EFI_ACPI_DESCRIPTION_HEADER + ( + EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE, + ARM_EFI_ACPI_6_0_IO_REMAPPING_TABLE, + EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00 + ), + 3, // NumNodes + sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE), // NodeOffset + 0, // Reserved + }, + + // ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_NODE + { + EFI_ACPI_IORT_TYPE_ITS_GROUP, // Type + sizeof (ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE), // Length + 0, // Revision + 0, // Reserved + 0, // NumIdMappings + 0, // IdReference + }, + 1, // ITS count + }, + 0, // GIC ITS Identifiers + }, + + // ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_NODE + { + EFI_ACPI_IORT_TYPE_ITS_GROUP, // Type + sizeof (ARM_EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE), // Length + 0, // Revision + 0, // Reserved + 0, // NumIdMappings + 0, // IdReference + }, + 1, // ITS count + }, + 1, // GIC ITS Identifiers + }, + // ARM_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_RC_NODE + { + // EFI_ACPI_6_0_IO_REMAPPING_NODE + { + EFI_ACPI_IORT_TYPE_ROOT_COMPLEX, // Type + sizeof (ARM_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE), // Length + 0, // Revision + 0, // Reserved + 1, // NumIdMappings + OFFSET_OF (ARM_EFI_ACPI_6_0_IO_REMAPPING_RC_NODE, RcIdMap) // IdReference + }, + 0, // CacheCoherent + 0, // AllocationHints + 0, // Reserved + 0, // MemoryAccessFlags + EFI_ACPI_IORT_ROOT_COMPLEX_ATS_SUPPORTED, // AtsAttribute + 0x0, // PciSegmentNumber + }, + // EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE + { + 0x0000, // InputBase + 0xffff, // NumIds + 0x0000, // OutputBase + OFFSET_OF (ARM_EFI_ACPI_6_0_IO_REMAPPING_TABLE, Its1Node), // OutputReference + 0, // Flags + } + } +}; + +VOID* CONST ReferenceAcpiTable = &Iort; + diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sata.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sata.asl new file mode 100644 index 0000000..d094c54 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sata.asl @@ -0,0 +1,77 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +Scope (\_SB_) { + Device (ATA0) { + Name (_HID, "RKCP0161") + Name (_UID, 0) + Name (_CLS, Package() { 0x01, 0x06, 0x01 }) + Name (_CCA, 0) + Name (_STA, 0xF) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe210000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 305 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk-ahci" }, + } + }) + } + + Device (ATA1) { + Name (_HID, "RKCP0161") + Name (_UID, 1) + Name (_CLS, Package() { 0x01, 0x06, 0x01 }) + Name (_CCA, 0) + Name (_STA, 0xF) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe220000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 306 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk-ahci" }, + } + }) + } + + Device (ATA2) { + Name (_HID, "RKCP0161") + Name (_UID, 2) + Name (_CLS, Package() { 0x01, 0x06, 0x01 }) + Name (_CCA, 0) + Name (_STA, 0xF) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe230000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 307 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk-ahci" }, + } + }) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Scmi.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Scmi.asl new file mode 100644 index 0000000..f5d8965 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Scmi.asl @@ -0,0 +1,264 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#define SCMI_SHARED_MEM_BASE FixedPcdGet32(PcdRkMtlMailBoxBase) +#define SCMI_SHARED_MEM_SIZE FixedPcdGet32(PcdRkMtlMailBoxSize) + +// Mailbox 0, channel 0 +#define SCMI_DOORBELL_BASE 0xfec60030 +#define SCMI_DOORBELL_SIZE 0x8 + +#define SMT_MESSAGE_TYPE_COMMAND 0 + +#define SMT_CHANNEL_STATUS_ERROR (0x1 << 1) +#define SMT_CHANNEL_STATUS_FREE (0x1 << 0) +#define SMT_CHANNEL_STATUS_BUSY 0 + +#define SMT_CHANNEL_FLAGS_INTERRUPT (0x1 << 0) +#define SMT_CHANNEL_FLAGS_POLL 0 + +#define SMT_POLL_TIMEOUT_US 20000 + +#define SCMI_STATUS_SUCCESS 0 + +Device (SCMI) { + Name (_HID, "PNP0C02") + Name (_UID, 0) + + Method (_CRS, 0, Serialized) { + Name (RBUF, ResourceTemplate () { + Memory32Fixed (ReadWrite, SCMI_SHARED_MEM_BASE, SCMI_SHARED_MEM_SIZE) + }) + Return (RBUF) + } + + // + // CLRG - Clock Rate Get + // + // Arguments: + // Arg0: Clock ID + // + // Return: + // Package of two integers: Status, Clock rate + // Values following Status are only valid on success. + // + Method (CLRG, 1, Serialized) { + Name(PBUF, Buffer (4) { }) // Parameters + CreateDWordField (PBUF, 0, PCID) // Clock ID + PCID = Arg0 + + Local0 = SMT (0x14, 0x6, PBUF) // Response + CreateDWordField (Local0, 0, RSTA) // Status + CreateDWordField (Local0, 4, RRTL) // Rate low part + CreateDWordField (Local0, 8, RRTH) // Rate high part + + // Prepare return package + Local1 = Package (2) { 0, 0 } + Local1[0] = RSTA + + If (RSTA == SCMI_STATUS_SUCCESS) { + Local1[1] = (RRTH << 32) | RRTL + } + + Return (Local1) + } + + // + // CLRS - Clock Rate Set + // + // Arguments: + // Arg0: Clock ID + // Arg1: Clock rate + // + // Return: + // Package of one integer: Status + // + Method (CLRS, 2, Serialized) { + Name(PBUF, Buffer (16) { }) // Parameters + CreateDWordField (PBUF, 0, PFLG) // Flags + CreateDWordField (PBUF, 4, PCID) // Clock ID + CreateDWordField (PBUF, 8, PRTL) // Rate low part + CreateDWordField (PBUF, 12, PRTH) // Rate high part + PFLG = 0 + PCID = Arg0 + PRTL = Arg1 + PRTH = Arg1 >> 32 + + Local0 = SMT (0x14, 0x5, PBUF) // Response + CreateDWordField (Local0, 0, RSTA) // Status + + // Prepare return package + Local1 = Package (1) { 0 } + Local1[0] = RSTA + + Return (Local1) + } + + // + // CLCS - Clock Config Set + // + // Arguments: + // Arg0: Clock ID + // Arg1: Attributes (1 -> enable, 0 -> disable) + // + // Return: + // Package of one integer: Status + // + Method (CLCS, 2, Serialized) { + Name(PBUF, Buffer (8) { }) // Parameters + CreateDWordField (PBUF, 0, PCID) // Clock ID + CreateDWordField (PBUF, 4, PATR) // Attributes + PCID = Arg0 + PATR = Arg1 + + Local0 = SMT (0x14, 0x7, PBUF) // Response + CreateDWordField (Local0, 0, RSTA) // Status + + // Prepare return package + Local1 = Package (1) { 0 } + Local1[0] = RSTA + + Return (Local1) + } + + // + // VDLG - Voltage Domain Level Get + // + // Arguments: + // Arg0: Domain ID + // + // Return: + // Package of two integers: Status, Voltage level + // Values following Status are only valid on success. + // + Method (VDLG, 1, Serialized) { + Name(PBUF, Buffer (4) { }) // Parameters + CreateDWordField (PBUF, 0, PDID) // Domain ID + PDID = Arg0 + + Local0 = SMT (0x17, 0x8, PBUF) // Response + CreateDWordField (Local0, 0, RSTA) // Status + CreateDWordField (Local0, 4, RVOL) // Voltage level + + // Prepare return package + Local1 = Package (2) { 0, 0 } + Local1[0] = RSTA + + If (RSTA == SCMI_STATUS_SUCCESS) { + Local1[1] = RVOL + } + + Return (Local1) + } + + // + // VDLS - Voltage Domain Level Set + // + // Arguments: + // Arg0: Domain ID + // Arg1: Voltage level + // + // Return: + // Package of one integer: Status + // + Method (VDLS, 2, Serialized) { + Name(PBUF, Buffer (12) { }) // Parameters + CreateDWordField (PBUF, 0, PDID) // Domain ID + CreateDWordField (PBUF, 4, PFLG) // Flags + CreateDWordField (PBUF, 8, PVOL) // Voltage level + PDID = Arg0 + PFLG = 0 + PVOL = Arg1 + + Local0 = SMT (0x17, 0x7, PBUF) // Response + CreateDWordField (Local0, 0, RSTA) // Status + + // Prepare return package + Local1 = Package (1) { 0 } + Local1[0] = RSTA + + Return (Local1) + } + + OperationRegion (SHM, SystemMemory, SCMI_SHARED_MEM_BASE, SCMI_SHARED_MEM_SIZE) + Field (SHM, ByteAcc, NoLock, Preserve) { + , 32, // Reserved + SCHS, 32, // Channel status + , 64, // Reserved + SCHF, 32, // Channel flags + SLEN, 32, // Length + SMSH, 32, // Message header + SPLD, 736 // Payload + } + + OperationRegion (DBEL, SystemMemory, SCMI_DOORBELL_BASE, SCMI_DOORBELL_SIZE) + Field (DBEL, DWordAcc, NoLock, Preserve) { + DCMD, 32, // Command + DDAT, 32 // Data + } + + Method (FREE, 0, Serialized) { + For (Local0 = SMT_POLL_TIMEOUT_US, Local0 > 0, Local0--) { + If ((SCHS & SMT_CHANNEL_STATUS_FREE) != 0) { + Return (1) + } + Sleep (1) + } + Return (0) + } + + // + // SMT - Shared Memory Transport + // + // Arguments: + // Arg0: SCMI Protocol ID + // Arg1: SCMI Message ID + // Arg2: SCMI Input Buffer + // + // Return: + // Buffer: SCMI Payload + // + Method (SMT, 3, Serialized) { + // Initial return value (transport error) + Local0 = Buffer (4) { 1 } + + // Wait for any previous message + If (FREE () == 0) { + Return (Local0) + } + + // Fill in the message header + Name (MSGH, Buffer (4) { }) + CreateField (MSGH, 10, 8, PRTI) // Protocol identifier + CreateField (MSGH, 8, 2, MSGT) // Message type + CreateField (MSGH, 0, 8, MSGI) // Message identifier + PRTI = Arg0 + MSGT = SMT_MESSAGE_TYPE_COMMAND + MSGI = Arg1 + SMSH = MSGH + + SCHS = SMT_CHANNEL_STATUS_BUSY + SCHF = SMT_CHANNEL_FLAGS_POLL + SLEN = 4 + SizeOf (Arg2) // Message header + Payload + SPLD = Arg2 + + // Ring the doorbell + DCMD = 0 + DDAT = 0 + + // Wait for completion + If ((FREE () == 0) || ((SCHS & SMT_CHANNEL_STATUS_ERROR) != 0)) { + Return (Local0) + } + + Local0 = SPLD + Return (Local0) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sdhc.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sdhc.asl new file mode 100644 index 0000000..e66d479 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Sdhc.asl @@ -0,0 +1,72 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +#ifndef SDMMC_CAP_DDR50 +#define SDMMC_CAP_DDR50 1 +#endif +#ifndef SDMMC_CAP_SDR50 +#define SDMMC_CAP_SDR50 1 +#endif +#ifndef SDMMC_CAP_SDR104 +#define SDMMC_CAP_SDR104 1 +#endif + +Scope (\_SB_) { + Name (SDRM, 1) // SD slot is removable + + Device (SDHC) { + Name (_HID, "RKCPFE2C") + Name (_UID, 0x0) + Name (_CCA, 0x0) + Name (_S1D, 0x1) + Name (_S2D, 0x1) + Name (_S3D, 0x1) + Name (_S4D, 0x1) + Name (_STA, 0xf) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfe2c0000, 0x4000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 235 } + + // SDMMC_DET + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GPI0") { GPIO_PIN_PA4 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0") { GPIO_PIN_PA4 } + }) + Return (RBUF) + } + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", Package () { "rockchip,rk3588-dw-mshc", "rockchip,rk3288-dw-mshc" } }, + Package () { "fifo-depth", 0x100 }, + Package () { "max-frequency", 200000000 }, + Package () { "bus-width", 4 }, + Package () { "cap-sd-highspeed", 1 }, + Package () { "sd-uhs-ddr50", SDMMC_CAP_DDR50 }, + Package () { "sd-uhs-sdr50", SDMMC_CAP_SDR50 }, + Package () { "sd-uhs-sdr104", SDMMC_CAP_SDR104 }, + Package () { "broken-cd", FixedPcdGetBool (PcdRkSdmmcCardDetectBroken) }, + } + }) + + // + // A child device that represents the SD card. + // + Device (SDMM) { + Name (_ADR, 0x0) + + Method (_RMV) { + Return (SDRM) + } + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spcr.aslc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spcr.aslc new file mode 100644 index 0000000..d834494 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spcr.aslc @@ -0,0 +1,50 @@ +/** @file +* Serial Port Console Redirection Table (SPCR). +* +* Copyright (c) 2021, Jared McNeill +* Copyright (c) 2020 Linaro Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include + +#include "AcpiTables.h" + +#pragma pack(push, 1) + +STATIC EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE Spcr = { + ACPI_HEADER ( + EFI_ACPI_6_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE, + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE, + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION), + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERFACE_TYPE_16550_WITH_GAS, + { EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE }, + ARM_GAS32 (FixedPcdGet64 (PcdSerialRegisterBase)), + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC, + 0, /* Irq */ + 365, /* GlobalSystemInterrupt */ + 0, + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_PARITY_NO_PARITY, + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1, + 0, /* Flow Control */ + EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT_UTF8, + EFI_ACPI_RESERVED_BYTE, /* Language */ + 0xFFFF, /* PciDeviceId */ + 0xFFFF, /* PciVendorId */ + 0x00, /* PciBusNumber */ + 0x00, /* PciDeviceNumber */ + 0x00, /* PciFunctionNumber */ + 0, /* PciFlags */ + 0, /* PciSegment */ + EFI_ACPI_RESERVED_DWORD +}; + +#pragma pack(pop) + +// Reference the table being generated to prevent the optimizer from removing +// the data structure from the executable +VOID* CONST ReferenceAcpiTable = &Spcr; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spi.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spi.asl new file mode 100644 index 0000000..f9b5971 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Spi.asl @@ -0,0 +1,145 @@ +/** @file + * + * Copyright (c) 2022 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include "AcpiTables.h" + +Device (SPI0) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeb00000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 358 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3036-spi" }, + Package () { "clock-frequency", 200000000 }, + Package () { "num-cs", 2 }, + } + }) +} + +Device (SPI1) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeb10000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 359 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3036-spi" }, + Package () { "clock-frequency", 200000000 }, + Package () { "num-cs", 2 }, + } + }) +} + +Device (SPI2) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeb20000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 360 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3036-spi" }, + Package () { "clock-frequency", 200000000 }, + Package () { "num-cs", 2 }, + } + }) +} + +Device (SPI3) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfeb30000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 361 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3036-spi" }, + Package () { "clock-frequency", 200000000 }, + Package () { "num-cs", 2 }, + } + }) +} + +Device (SPI4) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfecb0000, 0x1000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 362 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,rk3036-spi" }, + Package () { "clock-frequency", 200000000 }, + Package () { "num-cs", 2 }, + } + }) +} + +Device (SFC0) +{ + Name (_HID, "PRP0001") + Name (_UID, 3) + Name (_CCA, 0) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfe2b0000, 0x4000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 238 } + }) + Return (RBUF) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package (2) { "compatible", "rockchip,sfc" }, + Package () { "clock-frequency", 100000000 }, + } + }) +} \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Uart.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Uart.asl new file mode 100644 index 0000000..8643c4a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Uart.asl @@ -0,0 +1,36 @@ +/** @file + * + * [DSDT] Serial devices (UART). + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2018, Andrey Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +Device(UAR2) { + Name (_HID, "HISI0031") + Name (_UID, 2) + Name (_CRS, ResourceTemplate() { + Memory32Fixed(ReadWrite, 0xfeb50000, 0x1000) + Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 365 } + }) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "reg-shift", 2 }, + Package () { "reg-io-width", 4 }, + Package () { "clock-frequency", 24000000 }, + } + }) + + Method (_STA, 0, NotSerialized) { + Return(0x0F) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb2Host.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb2Host.asl new file mode 100644 index 0000000..40a6df9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb2Host.asl @@ -0,0 +1,198 @@ +/** @file + * + * USB 2.0 (EHCI + OHCI) controllers. + * + * Copyright (c) 2022, Rockchip Electronics Co., Ltd + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "AcpiTables.h" + +Scope (\_SB_) { + Name (EHID, 1) // Expose EHCI PNP _CID + + Device (EHC0) { + Name (_HID, "RKCP0D20") + If (EHID == 1) { + Name (_CID, "PNP0D20") + } + Name (_UID, Zero) + Name (_CCA, Zero) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xFC800000, 0x40000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 247 } + }) + Return (RBUF) + } + + Device (RHUB) { + Name (_ADR, 0) + Device (PRT1) { + Name (_ADR, 1) + Name (_UPC, Package() { + 0xFF, // Port is connectable + 0x00, // Connector type - Type 'A' + 0x00000000, // Reserved, must be zero + 0x00000000 // Reserved, must be zero + }) + Name (_PLD, Package (0x01) { + ToPLD ( + PLD_Revision = 0x2, + PLD_IgnoreColor = 0x1, + PLD_UserVisible = 0x1, + PLD_Panel = "UNKNOWN", + PLD_VerticalPosition = "UPPER", + PLD_HorizontalPosition = "LEFT", + PLD_Shape = "HORIZONTALRECTANGLE", + PLD_Ejectable = 0x1, + PLD_EjectRequired = 0x1, + ) + }) + } + } + } + + Device (EHC1) { + Name (_HID, "RKCP0D20") + If (EHID == 1) { + Name (_CID, "PNP0D20") + } + Name (_UID, One) + Name (_CCA, Zero) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xFC880000, 0x40000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 250 } + }) + Return (RBUF) + } + + Device (RHUB) { + Name (_ADR, 0) + Device (PRT1) { + Name (_ADR, 1) + Name (_UPC, Package() { + 0xFF, // Port is connectable + 0x00, // Connector type - Type 'A' + 0x00000000, // Reserved, must be zero + 0x00000000 // Reserved, must be zero + }) + Name (_PLD, Package (0x01) { + ToPLD ( + PLD_Revision = 0x2, + PLD_IgnoreColor = 0x1, + PLD_UserVisible = 0x1, + PLD_Panel = "UNKNOWN", + PLD_VerticalPosition = "LOWER", + PLD_HorizontalPosition = "LEFT", + PLD_Shape = "HORIZONTALRECTANGLE", + PLD_Ejectable = 0x1, + PLD_EjectRequired = 0x1, + ) + }) + } + } + } + + Device (OHC0) { + Name (_HID, "PRP0001") + Name (_CLS, Package() { 0x0c, 0x03, 0x10 }) + Name (_UID, Zero) + Name (_CCA, Zero) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "generic-ohci" }, + } + }) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xFC840000, 0x40000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 248 } + }) + Return (RBUF) + } + + Device (RHUB) { + Name (_ADR, 0) + Device (PRT1) { + Name (_ADR, 1) + Name (_UPC, Package() { + 0xFF, // Port is connectable + 0x00, // Connector type - Type 'A' + 0x00000000, // Reserved, must be zero + 0x00000000 // Reserved, must be zero + }) + Name (_PLD, Package (0x01) { + ToPLD ( + PLD_Revision = 0x2, + PLD_IgnoreColor = 0x1, + PLD_UserVisible = 0x1, + PLD_Panel = "UNKNOWN", + PLD_VerticalPosition = "UPPER", + PLD_HorizontalPosition = "LEFT", + PLD_Shape = "HORIZONTALRECTANGLE", + PLD_Ejectable = 0x1, + PLD_EjectRequired = 0x1, + ) + }) + } + } + } + + Device (OHC1) { + Name (_HID, "PRP0001") + Name (_CLS, Package() { 0x0c, 0x03, 0x10 }) + Name (_UID, One) + Name (_CCA, Zero) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", "generic-ohci" }, + } + }) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xFC8C0000, 0x40000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 251 } + }) + Return (RBUF) + } + + Device (RHUB) { + Name (_ADR, 0) + Device (PRT1) { + Name (_ADR, 1) + Name (_UPC, Package() { + 0xFF, // Port is connectable + 0x00, // Connector type - Type 'A' + 0x00000000, // Reserved, must be zero + 0x00000000 // Reserved, must be zero + }) + Name (_PLD, Package (0x01) { + ToPLD ( + PLD_Revision = 0x2, + PLD_IgnoreColor = 0x1, + PLD_UserVisible = 0x1, + PLD_Panel = "UNKNOWN", + PLD_VerticalPosition = "LOWER", + PLD_HorizontalPosition = "LEFT", + PLD_Shape = "HORIZONTALRECTANGLE", + PLD_Ejectable = 0x1, + PLD_EjectRequired = 0x1, + ) + }) + } + } + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host0.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host0.asl new file mode 100644 index 0000000..a83aaf8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host0.asl @@ -0,0 +1,23 @@ +/** @file +* DWC3 XHCI controller #0 in host mode. +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "AcpiTables.h" + +Device (XHC0) { + Name (_HID, "PNP0D10") + Name (_UID, Zero) + Name (_CCA, Zero) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfc000000, 0x400000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 252 } + }) + Return (RBUF) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host1.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host1.asl new file mode 100644 index 0000000..ed758e0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host1.asl @@ -0,0 +1,23 @@ +/** @file +* DWC3 XHCI controller #1 in host mode. (only exposed on full RK3588) +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "AcpiTables.h" + +Device (XHC1) { + Name (_HID, "PNP0D10") + Name (_UID, One) + Name (_CCA, Zero) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfc400000, 0x400000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 253 } + }) + Return (RBUF) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host2.asl b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host2.asl new file mode 100644 index 0000000..0325410 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/AcpiTables/Usb3Host2.asl @@ -0,0 +1,26 @@ +/** @file +* DWC3 XHCI controller #2 in host mode. +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "AcpiTables.h" + +// This only supports USB 3.0 devices. +// USB2 DP / DM are connected to one of the EHCI controllers instead (EHC1 usually). + +Device (XHC2) { + Name (_HID, "PNP0D10") + Name (_UID, 2) + Name (_CCA, Zero) + + Method (_CRS, 0x0, Serialized) { + Name (RBUF, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfcd00000, 0x400000) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 254 } + }) + Return (RBUF) + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c new file mode 100644 index 0000000..9287f74 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.c @@ -0,0 +1,581 @@ +/** @file + * + * ACPI platform driver + * + * Copyright (c) 2020, Jeremy Linton + * Copyright (c) 2024, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC CONST EFI_GUID mAcpiTableFile = { + 0x7E374E25, 0x8E01, 0x4FEE, { 0x87, 0xf2, 0x39, 0x0C, 0x23, 0xC6, 0x06, 0xCD } +}; + +STATIC EFI_EXIT_BOOT_SERVICES mOriginalExitBootServices; + +STATIC EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; +STATIC EFI_ACPI_DESCRIPTION_HEADER *mDsdtTable; + +STATIC BOOLEAN mIsSdmmcBoot = FALSE; + +typedef enum { + AcpiOsUnknown = 0, + AcpiOsWindows, +} ACPI_OS_BOOT_TYPE; + +#define SDT_PATTERN_LEN (AML_NAME_SEG_SIZE + 1) + +// +// Simple NameOp integer patcher. +// Does not allocate memory and can be safely used at ExitBootServices. +// +STATIC +EFI_STATUS +AcpiUpdateSdtNameInteger ( + IN EFI_ACPI_DESCRIPTION_HEADER *AcpiTable, + IN CHAR8 Name[AML_NAME_SEG_SIZE], + IN UINTN Value + ) +{ + UINTN Index; + CHAR8 Pattern[SDT_PATTERN_LEN]; + UINT8 *SdtPtr; + UINT32 DataSize; + UINT32 ValueOffset; + + if (AcpiTable->Length <= SDT_PATTERN_LEN) { + return EFI_INVALID_PARAMETER; + } + + SdtPtr = (UINT8 *)AcpiTable; + // + // Do a single NameOp variable replacement. These are of the + // form "08 XXXX SIZE VAL", where SIZE is: 0A=byte, 0B=word, 0C=dword, + // XXXX is the name and VAL is the value. + // + Pattern[0] = AML_NAME_OP; + CopyMem (Pattern + 1, Name, AML_NAME_SEG_SIZE); + + ValueOffset = SDT_PATTERN_LEN + 1; + + for (Index = 0; Index < (AcpiTable->Length - SDT_PATTERN_LEN); Index++) { + if (CompareMem (SdtPtr + Index, Pattern, SDT_PATTERN_LEN) == 0) { + switch (SdtPtr[Index + SDT_PATTERN_LEN]) { + case AML_QWORD_PREFIX: + DataSize = sizeof (UINT64); + break; + case AML_DWORD_PREFIX: + DataSize = sizeof (UINT32); + break; + case AML_WORD_PREFIX: + DataSize = sizeof (UINT16); + break; + case AML_ONE_OP: + case AML_ZERO_OP: + ValueOffset--; + // Fallthrough + case AML_BYTE_PREFIX: + DataSize = sizeof (UINT8); + break; + default: + return EFI_UNSUPPORTED; + } + CopyMem (SdtPtr + Index + ValueOffset, &Value, DataSize); + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +STATIC +VOID +EFIAPI +AcpiDsdtFixupStatus ( + IN EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol, + IN EFI_ACPI_HANDLE TableHandle + ) +{ + EFI_STATUS Status; + UINTN Index; + + struct { + CHAR8 *ObjectPath; + BOOLEAN Enabled; + } DevStatus[] = { + { "\\_SB.PCI0._STA", FixedPcdGetBool (PcdPcie30Supported) && + PcdGet32 (PcdPcie30State) == PCIE30_STATE_ENABLED }, + { "\\_SB.PCI1._STA", PcdGet8 (PcdPcie30PhyMode) != PCIE30_PHY_MODE_AGGREGATION }, + { "\\_SB.PCI2._STA", PcdGet32 (PcdComboPhy1Mode) == COMBO_PHY_MODE_PCIE }, + { "\\_SB.PCI3._STA", PcdGet32 (PcdComboPhy2Mode) == COMBO_PHY_MODE_PCIE }, + { "\\_SB.PCI4._STA", PcdGet32 (PcdComboPhy0Mode) == COMBO_PHY_MODE_PCIE }, + { "\\_SB.ATA0._STA", PcdGet32 (PcdComboPhy0Mode) == COMBO_PHY_MODE_SATA }, + { "\\_SB.ATA1._STA", PcdGet32 (PcdComboPhy1Mode) == COMBO_PHY_MODE_SATA }, + { "\\_SB.ATA2._STA", PcdGet32 (PcdComboPhy2Mode) == COMBO_PHY_MODE_SATA }, + }; + + for (Index = 0; Index < ARRAY_SIZE (DevStatus); Index++) { + if (DevStatus[Index].Enabled == FALSE) { + Status = AcpiAmlObjectUpdateInteger (AcpiSdtProtocol, TableHandle, + DevStatus[Index].ObjectPath, 0x0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Failed to patch %a. Status=%r\n", + DevStatus[Index].ObjectPath, Status)); + } + } + } +} + +STATIC +VOID +EFIAPI +NotifyEndOfDxeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN TableKey; + UINTN TableIndex; + EFI_ACPI_HANDLE TableHandle; + + Status = gBS->LocateProtocol ( + &gEfiAcpiSdtProtocolGuid, + NULL, + (VOID **)&mAcpiSdtProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Couldn't locate gEfiAcpiSdtProtocolGuid! Status=%r\n", Status)); + return; + } + + Status = LocateAndInstallAcpiFromFvConditional (&mAcpiTableFile, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "AcpiPlatform: Failed to install firmware ACPI as config table. Status=%r\n", + Status)); + } + + TableIndex = 0; + Status = AcpiLocateTableBySignature ( + mAcpiSdtProtocol, + EFI_ACPI_6_3_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + &TableIndex, + &mDsdtTable, + &TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Couldn't locate ACPI DSDT table!\n", __func__)); + return; + } + + Status = mAcpiSdtProtocol->OpenSdt (TableKey, &TableHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Couldn't open ACPI DSDT table!\n", __func__)); + mAcpiSdtProtocol->Close (TableHandle); + return; + } + + AcpiDsdtFixupStatus (mAcpiSdtProtocol, TableHandle); + + mAcpiSdtProtocol->Close (TableHandle); +} + +STATIC +EFI_STATUS +EFIAPI +AcpiFixupPcieEcam ( + IN ACPI_OS_BOOT_TYPE OsType + ) +{ + EFI_STATUS Status; + UINTN Index; + RK3588_MCFG_TABLE *McfgTable; + EFI_ACPI_DESCRIPTION_HEADER *FadtTable; + UINTN TableKey; + UINT32 PcieEcamMode; + UINT8 PcieBusMin; + UINT8 PcieBusMax; + UINT8 McfgMainBusMin; + BOOLEAN McfgSplitRootPort; + BOOLEAN McfgSingleDevQuirk; + + Index = 0; + Status = AcpiLocateTableBySignature ( + mAcpiSdtProtocol, + EFI_ACPI_6_4_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE, + &Index, + (EFI_ACPI_DESCRIPTION_HEADER **)&McfgTable, + &TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Couldn't locate ACPI MCFG table! Status=%r\n", + Status)); + return Status; + } + + PcieEcamMode = PcdGet32 (PcdAcpiPcieEcamCompatMode); + + if (PcieEcamMode == ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV || + PcieEcamMode == ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON) { + if (OsType == AcpiOsWindows) { + PcieEcamMode = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6; + } else { + PcieEcamMode &= ~ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6; + } + } + + switch (PcieEcamMode) { + case ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6: + PcieBusMin = 0; + PcieBusMax = PCIE_BUS_LIMIT; + McfgMainBusMin = 1; + McfgSplitRootPort = TRUE; + McfgSingleDevQuirk = FALSE; + + Index = 0; + Status = AcpiLocateTableBySignature ( + mAcpiSdtProtocol, + EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE, + &Index, + &FadtTable, + &TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Couldn't locate ACPI FADT table! Status=%r\n", + Status)); + return Status; + } + + CopyMem (FadtTable->OemId, "NXPMX6", sizeof (FadtTable->OemId)); + AcpiUpdateChecksum ((UINT8 *)FadtTable, FadtTable->Length); + break; + + case ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON: + PcieBusMin = 0; + PcieBusMax = PCIE_BUS_LIMIT; + McfgMainBusMin = 0; + McfgSplitRootPort = FALSE; + McfgSingleDevQuirk = FALSE; + + CopyMem (McfgTable->Header.Header.OemId, "AMAZON", sizeof (McfgTable->Header.Header.OemId)); + McfgTable->Header.Header.OemTableId = SIGNATURE_64 ('G','R','A','V','I','T','O','N'); + break; + + default: // ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV + PcieBusMin = 1; + PcieBusMax = 1; + McfgMainBusMin = 1; + McfgSplitRootPort = FALSE; + McfgSingleDevQuirk = TRUE; + break; + } + + for (Index = 0; Index < ARRAY_SIZE (McfgTable->MainEntries); Index++) { + if (McfgSingleDevQuirk) { + if ((PcdGet32 (PcdPcieEcamCompliantSegmentsMask) & (1 << Index)) == 0) { + McfgTable->MainEntries[Index].BaseAddress += 0x8000; + } + } + McfgTable->MainEntries[Index].StartBusNumber = McfgMainBusMin; + McfgTable->MainEntries[Index].EndBusNumber = PcieBusMax; + } + + if (McfgSplitRootPort == FALSE) { + McfgTable->Header.Header.Length -= sizeof (McfgTable->RootPortEntries); + } + + AcpiUpdateChecksum ((UINT8 *)McfgTable, McfgTable->Header.Header.Length); + + AcpiUpdateSdtNameInteger (mDsdtTable, "PBMI", PcieBusMin); + AcpiUpdateSdtNameInteger (mDsdtTable, "PBMA", PcieBusMax); + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +AcpiPlatformOsBootHandler ( + IN ACPI_OS_BOOT_TYPE OsType + ) +{ + if (mAcpiSdtProtocol == NULL || mDsdtTable == NULL) { + return; + } + + // + // Hide EHCI PNP ID for Windows to avoid binding to the inbox driver, + // which by default uses atomics on uncached memory and would crash + // the system. + // + if (OsType == AcpiOsWindows) { + AcpiUpdateSdtNameInteger (mDsdtTable, "EHID", 0); + } + + // + // If the boot device is SDMMC, mark the slot as non-removable. + // This allows Windows to create a page file on it. + // + if (mIsSdmmcBoot) { + AcpiUpdateSdtNameInteger (mDsdtTable, "SDRM", 0); + } + + AcpiFixupPcieEcam (OsType); + + AcpiUpdateChecksum ((UINT8 *)mDsdtTable, mDsdtTable->Length); +} + +STATIC +UINTN +EFIAPI +FindPeImageBase ( + EFI_PHYSICAL_ADDRESS Base + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + Base &= ~(EFI_PAGE_SIZE - 1); + + while (Base != 0) { + DosHdr = (EFI_IMAGE_DOS_HEADER *)Base; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Base + DosHdr->e_lfanew); + if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + break; + } + } + + Base -= EFI_PAGE_SIZE; + } + + return Base; +} + +STATIC CHAR8 mWinLoadNameStr[] = "winload"; +#define PDB_NAME_MAX_LENGTH 256 + +STATIC +BOOLEAN +IsPeImageWinLoader ( + IN VOID *PeImage + ) +{ + CHAR8 *PdbStr; + UINTN Index; + + PdbStr = (CHAR8 *)PeCoffLoaderGetPdbPointer (PeImage); + if (PdbStr == NULL) { + return FALSE; + } + + for (Index = 0; Index < PDB_NAME_MAX_LENGTH && PdbStr[Index] != '\0'; Index++) { + if (AsciiStrnCmp (PdbStr + Index, mWinLoadNameStr, sizeof (mWinLoadNameStr) - sizeof (CHAR8)) == 0) { + return TRUE; + } + } + + return FALSE; +} + +STATIC +EFI_STATUS +EFIAPI +AcpiPlatformExitBootServicesHook ( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ) +{ + UINTN ReturnAddress; + UINTN OsLoaderAddress; + ACPI_OS_BOOT_TYPE OsType; + + ReturnAddress = (UINTN)RETURN_ADDRESS (0); + + gBS->ExitBootServices = mOriginalExitBootServices; + + OsType = AcpiOsUnknown; + + OsLoaderAddress = FindPeImageBase (ReturnAddress); + if (OsLoaderAddress > 0) { + if (IsPeImageWinLoader ((VOID *)OsLoaderAddress)) { + OsType = AcpiOsWindows; + } + } + + AcpiPlatformOsBootHandler (OsType); + + return gBS->ExitBootServices (ImageHandle, MapKey); +} + +STATIC +BOOLEAN +IsDeviceSdmmc ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DeviceHandle; + NON_DISCOVERABLE_DEVICE *Device; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + + DevicePath = DevicePathFromHandle (Handle); + + if (DevicePath == NULL + || DevicePath->Type != HARDWARE_DEVICE_PATH + || DevicePath->SubType != HW_VENDOR_DP) { + return FALSE; + } + + Status = gBS->LocateDevicePath (&gEdkiiNonDiscoverableDeviceProtocolGuid, + &DevicePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = gBS->HandleProtocol (DeviceHandle, + &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **) &Device); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Descriptor = &Device->Resources[0]; + + if (Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR || + Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { + return FALSE; + } + + return Descriptor->AddrRangeMin == PcdGet32 (PcdRkSdmmcBaseAddress); +} + + +STATIC VOID *mLoadedImageEventRegistration; + +STATIC +VOID +EFIAPI +NotifyLoadedImage ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + + while (TRUE) { + Status = gBS->LocateHandleBuffer ( + ByRegisterNotify, + NULL, + mLoadedImageEventRegistration, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Failed to locate gEfiLoadedImageProtocolGuid. Status=%r\n", + Status)); + } + break; + } + ASSERT (HandleCount == 1); + + Status = gBS->HandleProtocol ( + Handles[0], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + FreePool (Handles); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AcpiPlatform: Failed to get gEfiLoadedImageProtocolGuid. Status=%r\n", + Status)); + break; + } + + if (LoadedImage->DeviceHandle == NULL) { + continue; + } + + // + // If the last image was loaded from SDMMC, then assume that's + // the boot device. + // + mIsSdmmcBoot = IsDeviceSdmmc (LoadedImage->DeviceHandle); + } +} + +STATIC +VOID +EFIAPI +NotifyReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gBS->CloseEvent (Event); + + EfiCreateProtocolNotifyEvent ( + &gEfiLoadedImageProtocolGuid, + TPL_CALLBACK, + NotifyLoadedImage, + NULL, + &mLoadedImageEventRegistration + ); +} + +EFI_STATUS +EFIAPI +AcpiPlatformDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + if ((PcdGet32 (PcdConfigTableMode) & CONFIG_TABLE_MODE_ACPI) == 0) { + DEBUG ((DEBUG_WARN, "AcpiPlatform: ACPI support is disabled by the settings.\n")); + return EFI_UNSUPPORTED; + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + NotifyEndOfDxeEvent, // NotifyFunction + NULL, // NotifyContext + &gEfiEndOfDxeEventGroupGuid, // EventGroup + &Event // Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + NotifyReadyToBoot, // NotifyFunction + NULL, // NotifyContext + &gEfiEventReadyToBootGuid, // EventGroup + &Event // Event + ); + ASSERT_EFI_ERROR (Status); + + mOriginalExitBootServices = gBS->ExitBootServices; + gBS->ExitBootServices = AcpiPlatformExitBootServicesHook; + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf new file mode 100644 index 0000000..a3ddbc6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -0,0 +1,63 @@ +#/** @file +# +# ACPI platform driver +# +# Copyright (c) 2024, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = AcpiPlatformDxe + FILE_GUID = 1f7decf3-c2dc-49ee-a932-8074718cdc6d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = AcpiPlatformDxeInitialize + +[Sources] + AcpiPlatformDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + AcpiLib + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + PeCoffGetEntryPointLib + UefiBootServicesTableLib + UefiLib + UefiDriverEntryPoint + +[Guids] + gEfiEndOfDxeEventGroupGuid + gEfiEventReadyToBootGuid + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid + gEfiAcpiSdtProtocolGuid + gEfiLoadedImageProtocolGuid + +[Pcd] + gRK3588TokenSpaceGuid.PcdConfigTableMode + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatMode + gRK3588TokenSpaceGuid.PcdComboPhy0Mode + gRK3588TokenSpaceGuid.PcdComboPhy1Mode + gRK3588TokenSpaceGuid.PcdComboPhy2Mode + gRK3588TokenSpaceGuid.PcdPcie30Supported + gRK3588TokenSpaceGuid.PcdPcie30State + gRK3588TokenSpaceGuid.PcdPcie30PhyMode + gRK3588TokenSpaceGuid.PcdPcieEcamCompliantSegmentsMask + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress + +[Depex] + gRockchipPlatformConfigAppliedProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.c new file mode 100644 index 0000000..04cb8a8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.c @@ -0,0 +1,717 @@ +/** @file + * + * Flattened Device Tree platform driver + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define MAX_PATH_LENGTH 512 + +STATIC VOID *mPlatformFdt; +STATIC VOID *mLoadedImageEventRegistration; + +STATIC +INTN +EFIAPI +StriCmp ( + IN CONST CHAR16 *String1, + IN CONST CHAR16 *String2 + ) +{ + while ((*String1 != L'\0') && + (CharToUpper (*String1) == CharToUpper (*String2))) { + String1++; + String2++; + } + + return CharToUpper (*String1) - CharToUpper (*String2); +} + +STATIC +BOOLEAN +EFIAPI +StrEndsWith ( + IN CONST CHAR16 *String, + IN CONST CHAR16 *Extension + ) +{ + UINTN StringLength = StrLen (String); + UINTN ExtensionLength = StrLen (Extension); + + if (StringLength < ExtensionLength) { + return FALSE; + } + + return StriCmp (String + StringLength - ExtensionLength, Extension) == 0; +} + +STATIC +EFI_STATUS +EFIAPI +FdtOpenIntoAlloc ( + IN OUT VOID **Fdt, + IN OUT VOID **DestinationFdt, OPTIONAL + IN UINTN Size + ) +{ + VOID *NewFdt; + INTN Ret; + + NewFdt = AllocatePool (Size); + if (NewFdt == NULL) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Not enough resources to reallocate FDT (%d bytes).\n", + Size)); + return EFI_OUT_OF_RESOURCES; + } + + Ret = fdt_open_into (*Fdt, NewFdt, Size); + if (Ret) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to copy FDT. Ret=%a\n", fdt_strerror (Ret))); + FreePool (NewFdt); + return EFI_LOAD_ERROR; + } + + if (DestinationFdt != NULL) { + *DestinationFdt = NewFdt; + } else { + FreePool (*Fdt); + *Fdt = NewFdt; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +ReadFdtFromFilePath ( + IN EFI_FILE_PROTOCOL *Root, + IN CHAR16 *Path, + IN OUT UINTN *FileSize, OPTIONAL + IN OUT VOID **Fdt + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *File; + UINTN FileBufferSize; + UINTN FileInfoSize; + EFI_FILE_INFO *FileInfo = NULL; + INT32 Ret; + + Status = Root->Open (Root, &File, Path, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Couldn't open '%s'. Status=%r\n", Path, Status)); + return Status; + } + + if (FileSize == NULL) { + FileInfoSize = 0; + Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, NULL); + if (EFI_ERROR (Status) && FileInfoSize == 0) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to get '%s' file info size. Status=%r\n", + Path, Status)); + goto Exit; + } + + FileInfo = AllocatePool (FileInfoSize); + if (FileInfo == NULL) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Not enough resources for '%s' file info (%d bytes).\n", + Path, FileInfoSize)); + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, FileInfo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to get '%s' file info. Status=%r\n", + Path, Status)); + goto Exit; + } + FileBufferSize = FileInfo->FileSize; + } else { + FileBufferSize = *FileSize; + } + + *Fdt = AllocatePool (FileBufferSize); + if (*Fdt == NULL) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Not enough resources for '%s' file buffer (%d bytes).\n", + Path, FileBufferSize)); + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Status = File->Read (File, &FileBufferSize, *Fdt); + if (EFI_ERROR (Status)) { + if (FileSize != NULL) { + *FileSize = FileBufferSize; + } + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to read '%s' (%d bytes). Status=%r\n", + Path, FileBufferSize, Status)); + goto Exit; + } + + Ret = fdt_check_header (*Fdt); + if (Ret) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: '%s' has an invalid header! Ret=%a\n", + Path, fdt_strerror (Ret))); + Status = EFI_NOT_FOUND; + goto Exit; + } + +Exit: + Root->Close (File); + if (FileInfo != NULL) { + FreePool (FileInfo); + } + if (EFI_ERROR (Status) && *Fdt != NULL) { + FreePool (*Fdt); + *Fdt = NULL; + } + return Status; +} + +#define FDT_GET_USED_SIZE(Fdt) (fdt_off_dt_struct (Fdt) \ + + fdt_size_dt_struct (Fdt) \ + + fdt_size_dt_strings (Fdt)) + +STATIC +EFI_STATUS +EFIAPI +InstallOverlaysFromDirectoryPath ( + IN EFI_FILE_PROTOCOL *Root, + IN CHAR16 *Path, + IN OUT VOID **Fdt, + IN OUT UINTN *OverlaysCount + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *Dir; + UINTN DirEntryInfoSize; + UINTN CurrentInfoSize; + EFI_FILE_INFO *DirEntryInfo; + VOID *FdtOverlay; + UINTN FdtSize; + INT32 Ret; + + Status = Root->Open (Root, &Dir, Path, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Couldn't open directory '%s'. Status=%r\n", + Path, Status)); + return Status; + } + + DirEntryInfoSize = sizeof (EFI_FILE_INFO) + MAX_PATH_LENGTH; + DirEntryInfo = AllocatePool (DirEntryInfoSize); + if (DirEntryInfo == NULL) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Not enough resources for '%s' directory entry info.\n", + Path)); + Root->Close (Dir); + return EFI_OUT_OF_RESOURCES; + } + + DEBUG ((DEBUG_INFO, "FdtPlatform: Processing overlays in sub-directory '%s'\n", Path)); + + while (TRUE) { + CurrentInfoSize = DirEntryInfoSize; + Status = Dir->Read (Dir, &CurrentInfoSize, (VOID *) DirEntryInfo); + if (EFI_ERROR (Status) || CurrentInfoSize == 0) { + // Reached end of directory? + ASSERT (CurrentInfoSize <= DirEntryInfoSize); + ASSERT_EFI_ERROR (Status); + break; + } + + if (DirEntryInfo->Attribute & EFI_FILE_DIRECTORY) { + continue; + } + + if (!StrEndsWith (DirEntryInfo->FileName, L".dtbo")) { + continue; + } + + DEBUG ((DEBUG_INFO, "FdtPlatform: Installing overlay '%s'\n", + DirEntryInfo->FileName)); + + Status = ReadFdtFromFilePath (Dir, DirEntryInfo->FileName, + &DirEntryInfo->FileSize, &FdtOverlay); + if (EFI_ERROR (Status)) { + if (Status == EFI_OUT_OF_RESOURCES) { + break; + } + continue; + } + + FdtSize = FDT_GET_USED_SIZE (*Fdt); + if (FdtSize + DirEntryInfo->FileSize >= fdt_totalsize (*Fdt)) { + // + // Expand the buffer by at least 8 KB, so we don't end up + // reallocating for every small overlay. + // + FdtSize = fdt_totalsize (*Fdt) + MAX (DirEntryInfo->FileSize, SIZE_8KB); + Status = FdtOpenIntoAlloc (Fdt, NULL, FdtSize); + if (EFI_ERROR (Status)) { + FreePool (FdtOverlay); + break; + } + } + + Ret = fdt_overlay_apply (*Fdt, FdtOverlay); + FreePool (FdtOverlay); + if (Ret) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to apply overlay '%s' (%d bytes). Ret=%a\n", + DirEntryInfo->FileName, DirEntryInfo->FileSize, fdt_strerror (Ret))); + + if (Ret == -FDT_ERR_NOSPACE) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: FDT bytes used: %d, total: %d\n", + FDT_GET_USED_SIZE (*Fdt), fdt_totalsize (*Fdt))); + } + // + // The FDT is damaged at this point, we can't continue. + // + Status = EFI_LOAD_ERROR; + break; + } + + *OverlaysCount += 1; + } + + FreePool (DirEntryInfo); + Root->Close (Dir); + + return Status; +} + +STATIC CHAR16 mDtbOverrideRootPath[] = L"\\dtb"; + +STATIC +EFI_STATUS +EFIAPI +FdtPlatformProcessFileSystem ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *Root; + EFI_FILE_PROTOCOL *DtbDir; + UINTN PathSize; + CHAR16 *Path; + CHAR8 *FdtName; + VOID *Fdt = NULL; + VOID *NewFdt = NULL; + VOID *FdtToInstall = NULL; + UINTN OverlaysCount = 0; + + Status = FileSystem->OpenVolume (FileSystem, &Root); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to open volume. Status=%r\n", Status)); + return Status; + } + + Status = Root->Open (Root, &DtbDir, mDtbOverrideRootPath, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to open directory '%s'. Status=%r\n", + mDtbOverrideRootPath, Status)); + } + return Status; + } else { + DEBUG ((DEBUG_INFO, "FdtPlatform: Found override directory '%s'.\n", + mDtbOverrideRootPath)); + } + + PathSize = MAX_PATH_LENGTH * sizeof (CHAR16); + Path = AllocatePool (PathSize); + if (Path == NULL) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Not enough resources for '%s' access path.\n", + mDtbOverrideRootPath)); + Root->Close (DtbDir); + return EFI_OUT_OF_RESOURCES; + } + + FdtName = FixedPcdGetPtr (PcdDeviceTreeName); + + // + // Try to open the FDT override. + // + UnicodeSPrint (Path, PathSize, L"base\\%a.dtb", FdtName); + Status = ReadFdtFromFilePath (DtbDir, Path, NULL, &Fdt); + if (EFI_ERROR (Status)) { + if (mPlatformFdt == NULL) { + goto Exit; + } + Fdt = mPlatformFdt; + } else { + DEBUG ((DEBUG_INFO, "FdtPlatform: Loaded FDT override '%s'.\n", Path)); + } + + // + // Clone the FDT so that we can restore the original one + // in case it gets damaged. + // + Status = FdtOpenIntoAlloc (&Fdt, &NewFdt, fdt_totalsize (Fdt)); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Process the overlays common to all platforms. + // + Status = InstallOverlaysFromDirectoryPath (DtbDir, L"overlays", &NewFdt, &OverlaysCount); + if (Status == EFI_LOAD_ERROR || Status == EFI_OUT_OF_RESOURCES) { + goto Exit; + } + + // + // Process the platform-specific overlays. + // + UnicodeSPrint (Path, PathSize, L"overlays\\%a", FdtName); + Status = InstallOverlaysFromDirectoryPath (DtbDir, Path, &NewFdt, &OverlaysCount); + if (Status == EFI_LOAD_ERROR || Status == EFI_OUT_OF_RESOURCES) { + goto Exit; + } + +Exit: + Root->Close (DtbDir); + FreePool (Path); + + if (NewFdt != NULL) { + if (fdt_check_header (NewFdt) == 0) { + FdtToInstall = NewFdt; + DEBUG ((DEBUG_INFO, "FdtPlatform: Using FDT with %d overlays merged.\n", OverlaysCount)); + } else { + FreePool (NewFdt); + } + } + if (Fdt != NULL && Fdt != mPlatformFdt) { + if (FdtToInstall == NULL && fdt_check_header (Fdt) == 0) { + FdtToInstall = Fdt; + DEBUG ((DEBUG_INFO, "FdtPlatform: Using original FDT without overlays.\n")); + } else { + FreePool (Fdt); + } + } + + if (FdtToInstall != NULL) { + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, FdtToInstall); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to install the new FDT as config table. Status=%r\n", + Status)); + } + } + + return Status; +} + +STATIC +VOID +EFIAPI +NotifyLoadedImage ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; + + while (TRUE) { + Status = gBS->LocateHandleBuffer ( + ByRegisterNotify, + NULL, + mLoadedImageEventRegistration, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to locate gEfiLoadedImageProtocolGuid. Status=%r\n", + Status)); + } + break; + } + ASSERT (HandleCount == 1); + + Status = gBS->HandleProtocol ( + Handles[0], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + FreePool (Handles); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to get gEfiLoadedImageProtocolGuid. Status=%r\n", + Status)); + break; + } + + if (LoadedImage->DeviceHandle == NULL) { + continue; + } + + Status = gBS->HandleProtocol ( + LoadedImage->DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&FileSystem + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_UNSUPPORTED) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to get gEfiSimpleFileSystemProtocolGuid. Status=%r\n", + Status)); + } + continue; + } + + Status = FdtPlatformProcessFileSystem (FileSystem); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to process the file system. Status=%r\n", Status)); + } + continue; + } + } +} + +STATIC +VOID +EFIAPI +NotifyReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gBS->CloseEvent (Event); + + EfiCreateProtocolNotifyEvent ( + &gEfiLoadedImageProtocolGuid, + TPL_CALLBACK, + NotifyLoadedImage, + NULL, + &mLoadedImageEventRegistration + ); +} + +STATIC +VOID +EFIAPI +NotifyExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Dtb; + + Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb); + if (EFI_ERROR (Status) || Dtb == NULL) { + DEBUG ((DEBUG_WARN, "FdtPlatform: No FDT installed!\n")); + } else if (fdt_totalsize (Dtb) <= SIZE_4KB) { + // Some loaders may install a dummy table, warn in this case too. + DEBUG ((DEBUG_WARN, "FdtPlatform: No usable FDT installed!\n")); + } +} + +STATIC +EFI_STATUS +EFIAPI +FdtEnableNode ( + IN VOID *Fdt, + IN CONST CHAR8 *NodePath, + IN BOOLEAN Enable + ) +{ + INT32 Node; + INT32 Ret; + CHAR8 *NodeStatus; + + Node = fdt_path_offset (Fdt, NodePath); + if (Node < 0) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Couldn't locate FDT node path '%a'. Ret=%a\n", + NodePath, fdt_strerror (Node))); + return EFI_NOT_FOUND; + } + + NodeStatus = Enable ? "okay" : "disabled"; + Ret = fdt_setprop_string (Fdt, Node, "status", NodeStatus); + if (Ret) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Failed to set '%a' status to '%a'. Ret=%a\n", + NodePath, NodeStatus, fdt_strerror (Ret))); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +FdtFixupComboPhyDevices ( + IN VOID *Fdt + ) +{ + DEBUG ((DEBUG_INFO, "FdtPlatform: Fixing up Combo PHY devices (PCIe, SATA, USB)\n")); + + FdtEnableNode (Fdt, "/pcie@fe170000", + PcdGet32 (PcdComboPhy1Mode) == COMBO_PHY_MODE_PCIE); + FdtEnableNode (Fdt, "/pcie@fe180000", + PcdGet32 (PcdComboPhy2Mode) == COMBO_PHY_MODE_PCIE); + FdtEnableNode (Fdt, "/pcie@fe190000", + PcdGet32 (PcdComboPhy0Mode) == COMBO_PHY_MODE_PCIE); + + FdtEnableNode (Fdt, "/sata@fe210000", + PcdGet32 (PcdComboPhy0Mode) == COMBO_PHY_MODE_SATA); + FdtEnableNode (Fdt, "/sata@fe220000", + PcdGet32 (PcdComboPhy1Mode) == COMBO_PHY_MODE_SATA); + FdtEnableNode (Fdt, "/sata@fe230000", + PcdGet32 (PcdComboPhy2Mode) == COMBO_PHY_MODE_SATA); + + FdtEnableNode (Fdt, "/usbhost3_0", + PcdGet32 (PcdComboPhy2Mode) == COMBO_PHY_MODE_USB3); +} + +STATIC +VOID +EFIAPI +FdtFixupPcie3Devices ( + IN VOID *Fdt + ) +{ + if (!FixedPcdGetBool (PcdPcie30Supported)) { + return; + } + + DEBUG ((DEBUG_INFO, "FdtPlatform: Fixing up PCIe 3 devices\n")); + + FdtEnableNode (Fdt, "/pcie@fe150000", + PcdGet32 (PcdPcie30State) == PCIE30_STATE_ENABLED); + if (PcdGet8 (PcdPcie30PhyMode) != PCIE30_PHY_MODE_AGGREGATION) { + FdtEnableNode (Fdt, "/pcie@fe160000", + PcdGet32 (PcdPcie30State) == PCIE30_STATE_ENABLED); + } +} + +STATIC +VOID +EFIAPI +ApplyPlatformFdtFixups ( + IN VOID *Fdt + ) +{ + FdtFixupComboPhyDevices (Fdt); + FdtFixupPcie3Devices (Fdt); +} + +STATIC +EFI_STATUS +EFIAPI +LoadPlatformFdt ( + OUT VOID **PlatformFdt + ) +{ + EFI_STATUS Status; + VOID *Fdt; + UINTN FdtSize; + INT32 Ret; + + Status = GetSectionFromAnyFv ( + &gDtPlatformDefaultDtbFileGuid, + EFI_SECTION_RAW, + 0, + &Fdt, + &FdtSize + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Ret = fdt_check_header (Fdt); + if (Ret) { + DEBUG ((DEBUG_ERROR, "FdtPlatform: Firmware FDT has an invalid header! Ret=%a\n", + fdt_strerror (Ret))); + return EFI_NOT_FOUND; + } + + // Expand the FDT a bit to give room for any additions. + Status = FdtOpenIntoAlloc (&Fdt, NULL, fdt_totalsize (Fdt) + SIZE_1KB); + if (EFI_ERROR (Status)) { + return Status; + } + + *PlatformFdt = Fdt; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +FdtPlatformDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + if ((PcdGet32 (PcdConfigTableMode) & CONFIG_TABLE_MODE_FDT) == 0) { + DEBUG ((DEBUG_WARN, "FdtPlatform: FDT support is disabled by the settings.\n")); + return EFI_UNSUPPORTED; + } + + if (PcdGet8 (PcdFdtSupportOverrides)) { + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + NotifyReadyToBoot, // NotifyFunction + NULL, // NotifyContext + &gEfiEventReadyToBootGuid, // EventGroup + &Event // Event + ); + ASSERT_EFI_ERROR (Status); + } + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + NotifyExitBootServices, // NotifyFunction + NULL, // NotifyContext + &gEfiEventExitBootServicesGuid, // EventGroup + &Event // Event + ); + ASSERT_EFI_ERROR (Status); + + Status = LoadPlatformFdt (&mPlatformFdt); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "FdtPlatform: Failed to load firmware FDT. Status=%r\n", Status)); + return EFI_SUCCESS; + } + + ApplyPlatformFdtFixups (mPlatformFdt); + + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, mPlatformFdt); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "FdtPlatform: Failed to install firmware DTB as config table. Status=%r\n", + Status)); + } + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf new file mode 100644 index 0000000..2d2cae6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf @@ -0,0 +1,62 @@ +#/** @file +# +# Flattened Device Tree platform driver +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = FdtPlatformDxe + FILE_GUID = 5d028f9c-bb17-4ff5-8c61-dbb4474e4a13 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FdtPlatformDxeInitialize + +[Sources] + FdtPlatformDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + DebugLib + PrintLib + DxeServicesLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + FdtLib + +[Guids] + gFdtTableGuid + gDtPlatformDefaultDtbFileGuid + gEfiEventReadyToBootGuid + gEfiEventExitBootServicesGuid + +[Protocols] + gEfiLoadedImageProtocolGuid + gEfiSimpleFileSystemProtocolGuid + +[Pcd] + gRockchipTokenSpaceGuid.PcdDeviceTreeName + gRK3588TokenSpaceGuid.PcdConfigTableMode + gRK3588TokenSpaceGuid.PcdFdtSupportOverrides + gRK3588TokenSpaceGuid.PcdComboPhy0Mode + gRK3588TokenSpaceGuid.PcdComboPhy1Mode + gRK3588TokenSpaceGuid.PcdComboPhy2Mode + gRK3588TokenSpaceGuid.PcdPcie30Supported + gRK3588TokenSpaceGuid.PcdPcie30State + gRK3588TokenSpaceGuid.PcdPcie30PhyMode + +[Depex] + gRockchipPlatformConfigAppliedProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/EthernetPhy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/EthernetPhy.h new file mode 100644 index 0000000..367b105 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/EthernetPhy.h @@ -0,0 +1,50 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef ETHERNETPHY_H__ +#define ETHERNETPHY_H__ + +typedef +EFI_STATUS +(EFIAPI *ETHERNET_PHY_INIT) ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT32 PhyId + ); + +VOID +PhyRead ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT8 Phy, + IN UINT16 Reg, + OUT UINT16 *Value + ); + +VOID +PhyWrite ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT8 Phy, + IN UINT16 Reg, + IN UINT16 Value + ); + +EFI_STATUS +EFIAPI +RealtekPhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT32 PhyId + ); + +EFI_STATUS +EFIAPI +MotorcommPhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT32 PhyId + ); + +#endif /* ETHERNETPHY_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c new file mode 100644 index 0000000..a3f2307 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.c @@ -0,0 +1,309 @@ +/** @file + * + * RK3588 GMAC initializer + * + * Copyright (c) 2021-2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CRU_SOFTRST_CON32 (CRU_BASE + 0x0A80) + +#define PHP_GRF_BASE 0xFD5B0000 +#define PHP_GRF_CLK_CON1 (PHP_GRF_BASE + 0x0070) +#define PHP_GRF_GMAC_CON0 (PHP_GRF_BASE + 0x0008) + +#define SYS_GRF_BASE 0xFD58C000 +#define SYS_GRF_SOC_CON7 (SYS_GRF_BASE + 0x031C) +#define SYS_GRF_SOC_CON8 (SYS_GRF_BASE + 0x0320) +#define SYS_GRF_SOC_CON9 (SYS_GRF_BASE + 0x0324) +#define CLK_RX_DL_CFG_SHIFT 8 +#define CLK_TX_DL_CFG_SHIFT 0 + +#define TX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0TxDelay) +#define RX_DELAY_GMAC0 FixedPcdGet8 (PcdGmac0RxDelay) +#define TX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1TxDelay) +#define RX_DELAY_GMAC1 FixedPcdGet8 (PcdGmac1RxDelay) + +#define GMAC0_BASE 0xfe1b0000 +#define GMAC1_BASE 0xfe1c0000 + +/* GMAC registers */ +#define GMAC_MAC_MDIO_ADDRESS 0x0200 +#define GMAC_MAC_MDIO_ADDRESS_PA_SHIFT 21 +#define GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT 16 +#define GMAC_MAC_MDIO_ADDRESS_CR_SHIFT 8 +#define GMAC_MAC_MDIO_ADDRESS_CR_100_150 (1U << GMAC_MAC_MDIO_ADDRESS_CR_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT 2 +#define GMAC_MAC_MDIO_ADDRESS_GOC_READ (3U << GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_GOC_WRITE (1U << GMAC_MAC_MDIO_ADDRESS_GOC_SHIFT) +#define GMAC_MAC_MDIO_ADDRESS_GB BIT0 +#define GMAC_MAC_MDIO_DATA 0x0204 + +#define GMAC_MAC_ADDRESS0_LOW 0x0304 +#define GMAC_MAC_ADDRESS0_HIGH 0x0300 + +/* MII registers */ +#define MII_PHYIDR1 0x02 +#define MII_PHYIDR2 0x03 + +STATIC ETHERNET_PHY_INIT mPhyInitList[] = { + RealtekPhyInit, + MotorcommPhyInit +}; + +VOID +PhyRead ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT8 Phy, + IN UINT16 Reg, + OUT UINT16 *Value + ) +{ + UINT32 Addr; + UINTN Retry; + + Addr = GMAC_MAC_MDIO_ADDRESS_CR_100_150 | + (Phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | + (Reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | + GMAC_MAC_MDIO_ADDRESS_GOC_READ | + GMAC_MAC_MDIO_ADDRESS_GB; + MmioWrite32 (GmacBase + GMAC_MAC_MDIO_ADDRESS, Addr); + + MicroSecondDelay (10000); + + for (Retry = 1000; Retry > 0; Retry--) { + Addr = MmioRead32 (GmacBase + GMAC_MAC_MDIO_ADDRESS); + if ((Addr & GMAC_MAC_MDIO_ADDRESS_GB) == 0) { + *Value = MmioRead32 (GmacBase + GMAC_MAC_MDIO_DATA) & 0xFFFFu; + break; + } + MicroSecondDelay (10); + } + if (Retry == 0) { + DEBUG ((DEBUG_WARN, "MDIO: PHY read timeout!\n")); + *Value = 0xFFFFU; + ASSERT (FALSE); + } +} + +VOID +PhyWrite ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT8 Phy, + IN UINT16 Reg, + IN UINT16 Value + ) +{ + UINT32 Addr; + UINTN Retry; + + MmioWrite32 (GmacBase + GMAC_MAC_MDIO_DATA, Value); + + Addr = GMAC_MAC_MDIO_ADDRESS_CR_100_150 | + (Phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | + (Reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | + GMAC_MAC_MDIO_ADDRESS_GOC_WRITE | + GMAC_MAC_MDIO_ADDRESS_GB; + MmioWrite32 (GmacBase + GMAC_MAC_MDIO_ADDRESS, Addr); + + MicroSecondDelay (10000); + + for (Retry = 1000; Retry > 0; Retry--) { + Addr = MmioRead32 (GmacBase + GMAC_MAC_MDIO_ADDRESS); + if ((Addr & GMAC_MAC_MDIO_ADDRESS_GB) == 0) { + break; + } + MicroSecondDelay (10); + } + if (Retry == 0) { + DEBUG ((DEBUG_WARN, "MDIO: PHY write timeout!\n")); + ASSERT (FALSE); + } +} + +STATIC +VOID +EFIAPI +PhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase + ) +{ + EFI_STATUS Status; + UINT16 PhyIdReg; + UINT32 PhyId; + UINT32 Index; + + PhyRead (GmacBase, 0, MII_PHYIDR1, &PhyIdReg); + PhyId = PhyIdReg << 16; + PhyRead (GmacBase, 0, MII_PHYIDR2, &PhyIdReg); + PhyId |= PhyIdReg; + + for (Index = 0; Index < ARRAY_SIZE (mPhyInitList); Index++) { + Status = mPhyInitList[Index] (GmacBase, PhyId); + if (Status == EFI_UNSUPPORTED) { + continue; + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: mPhyInitList[%d]() failed: %r\n", __func__, Index, Status)); + } + return; + } + + DEBUG ((DEBUG_ERROR, "%a: Unknown PHY ID %08X\n", __func__, PhyId)); +} + +STATIC +VOID +EFIAPI +InitGmac0 ( + VOID + ) +{ + /* Assert reset */ + MmioWrite32 (CRU_SOFTRST_CON32, 0x04000400); // aresetn_gmac0 = 1 + + /* Configure pins */ + GmacIomux (0); + + /* Setup clocks */ + MmioWrite32 (PHP_GRF_CLK_CON1, 0x001d0000); // io_clksel_gmac0 = io + // mii_tx_clk_sel_gamc0 = 125 MHz + // rmii_mode_gmac0 = RGMII mode + + MmioWrite32 (PHP_GRF_GMAC_CON0, 0x00380008); // gmac0_phy_intf_sel = RGMII + + /* Setup DLLs */ + if (TX_DELAY_GMAC0) { + MmioWrite32 (SYS_GRF_SOC_CON7, 0x00040004); // gmac0_txclk_dly_ena = 1 + MmioWrite32 (SYS_GRF_SOC_CON8, 0x007F0000U | + (TX_DELAY_GMAC0 << CLK_TX_DL_CFG_SHIFT)); + } + + if (RX_DELAY_GMAC0) { + MmioWrite32 (SYS_GRF_SOC_CON7, 0x00080008); // gmac0_rxclk_dly_ena = 1 + MmioWrite32 (SYS_GRF_SOC_CON8, 0x7F000000U | + (RX_DELAY_GMAC0 << CLK_RX_DL_CFG_SHIFT)); + } + + /* Reset PHY */ + GmacIoPhyReset (0, TRUE); + MicroSecondDelay (20000); + GmacIoPhyReset (0, FALSE); + MicroSecondDelay (200000); + + /* Deassert reset */ + MmioWrite32 (CRU_SOFTRST_CON32, 0x04000000); // aresetn_gmac0 = 0 + + PhyInit (GMAC0_BASE); +} + +STATIC +VOID +EFIAPI +InitGmac1 ( + VOID + ) +{ + /* Assert reset */ + MmioWrite32 (CRU_SOFTRST_CON32, 0x08000800); // aresetn_gmac1 = 1 + + /* Configure pins */ + GmacIomux (1); + + /* Setup clocks */ + MmioWrite32 (PHP_GRF_CLK_CON1, 0x03a00000); // io_clksel_gmac1 = io + // mii_tx_clk_sel_gamc1 = 125 MHz + // rmii_mode_gmac1 = RGMII mode + + MmioWrite32 (PHP_GRF_GMAC_CON0, 0x0e000200); // gmac1_phy_intf_sel = RGMII + + /* Setup DLLs */ + if (TX_DELAY_GMAC1) { + MmioWrite32 (SYS_GRF_SOC_CON7, 0x00100010); // gmac1_txclk_dly_ena = 1 + MmioWrite32 (SYS_GRF_SOC_CON9, 0x007F0000U | + (TX_DELAY_GMAC1 << CLK_TX_DL_CFG_SHIFT)); + } + + if (RX_DELAY_GMAC1) { + MmioWrite32 (SYS_GRF_SOC_CON7, 0x00200020); // gmac1_rxclk_dly_ena = 1 + MmioWrite32 (SYS_GRF_SOC_CON9, 0x7F000000U | + (RX_DELAY_GMAC1 << CLK_RX_DL_CFG_SHIFT)); + } + + /* Reset PHY */ + GmacIoPhyReset (1, TRUE); + MicroSecondDelay (20000); + GmacIoPhyReset (1, FALSE); + MicroSecondDelay (200000); + + /* Deassert reset */ + MmioWrite32 (CRU_SOFTRST_CON32, 0x08000000); // aresetn_gmac1 = 0 + + PhyInit (GMAC1_BASE); +} + +EFI_STATUS +EFIAPI +GmacPlatformDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT8 OtpData[32]; + UINT8 Hash[SHA256_DIGEST_SIZE]; + UINT32 MacLo, MacHi; + + if (!FixedPcdGetBool (PcdGmac0Supported) + && !FixedPcdGetBool (PcdGmac1Supported)) { + return EFI_SUCCESS; + } + + /* Generate MAC addresses from the first 32 bytes in the OTP and write it to GMAC0 and GMAC1 */ + /* Use sequential MAC addresses. Last byte is even for GMAC0, and odd for GMAC1. */ + OtpRead (0x00, sizeof (OtpData), OtpData); + Sha256HashAll (OtpData, sizeof (OtpData), Hash); + Hash[0] &= 0xFE; + Hash[0] |= 0x02; + + if (FixedPcdGetBool (PcdGmac0Supported)) { + InitGmac0 (); + + Hash[5] &= ~1; + DEBUG ((DEBUG_INFO, "%a: GMAC0 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", + __func__, + Hash[0], Hash[1], Hash[2], + Hash[3], Hash[4], Hash[5])); + MacLo = Hash[3] | (Hash[2] << 8) | (Hash[1] << 16) | (Hash[0] << 24); + MacHi = Hash[5] | (Hash[4] << 8); + MmioWrite32 (GMAC0_BASE + GMAC_MAC_ADDRESS0_LOW, MacLo); + MmioWrite32 (GMAC0_BASE + GMAC_MAC_ADDRESS0_HIGH, MacHi); + } + + if (FixedPcdGetBool (PcdGmac1Supported)) { + InitGmac1 (); + + Hash[5] |= 1; + DEBUG ((DEBUG_INFO, "%a: GMAC1 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", + __func__, + Hash[0], Hash[1], Hash[2], + Hash[3], Hash[4], Hash[5])); + MacLo = Hash[3] | (Hash[2] << 8) | (Hash[1] << 16) | (Hash[0] << 24); + MacHi = Hash[5] | (Hash[4] << 8); + MmioWrite32 (GMAC1_BASE + GMAC_MAC_ADDRESS0_LOW, MacLo); + MmioWrite32 (GMAC1_BASE + GMAC_MAC_ADDRESS0_HIGH, MacHi); + } + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf new file mode 100644 index 0000000..808e3e1 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf @@ -0,0 +1,51 @@ +#/** @file +# +# RK3588 GMAC initializer +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = GmacPlatformDxe + FILE_GUID = e08592c7-55f6-4f90-be56-327356aa1462 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = GmacPlatformDxeInitialize + +[Sources.common] + GmacPlatformDxe.c + RealtekPhy.c + MotorcommPhy.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + IoLib + TimerLib + BaseCryptLib + OtpLib + RockchipPlatformLib + +[Protocols] + +[Pcd] + gRK3588TokenSpaceGuid.PcdGmac0Supported + gRK3588TokenSpaceGuid.PcdGmac1Supported + gRK3588TokenSpaceGuid.PcdGmac0TxDelay + gRK3588TokenSpaceGuid.PcdGmac0RxDelay + gRK3588TokenSpaceGuid.PcdGmac1TxDelay + gRK3588TokenSpaceGuid.PcdGmac1RxDelay + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/MotorcommPhy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/MotorcommPhy.c new file mode 100644 index 0000000..cbb5ab0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/MotorcommPhy.c @@ -0,0 +1,97 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "EthernetPhy.h" + +/* Motorcomm PHY registers */ +#define EXT_REG_ADDR 0x1E +#define EXT_REG_DATA 0x1F +#define PHY_CLOCK_GATING_REG 0x0C +#define RX_CLK_EN BIT12 +#define TX_CLK_DELAY_SEL_SHIFT 4 +#define TX_CLK_DELAY_SEL (0xFU << TX_CLK_DELAY_SEL_SHIFT) +#define CLK_25M_SEL_SHIFT 1 +#define CLK_25M_SEL_MASK (0x3U << CLK_25M_SEL_SHIFT) +#define CLK_25M_SEL_125M (3U << CLK_25M_SEL_SHIFT) +#define RX_CLK_DELAY_EN BIT0 +#define PHY_SLEEP_CONTROL1_REG 0x27 +#define SLEEP_SW BIT15 +#define PLLON_IN_SLP BIT14 + +#define YTPHY_SYNCE_CFG_REG 0xA012 +#define YT8531_SCR_SYNCE_ENABLE BIT6 +#define YT8531_SCR_CLK_FRE_SEL_125M BIT4 +#define YT8531_SCR_CLK_SRC_SEL_SHIFT 1 +#define YT8531_SCR_CLK_SRC_SEL_PLL_125M (0 << YT8531_SCR_CLK_SRC_SEL_SHIFT) + +#define LED1_CFG_REG 0xA00D +#define LED2_CFG_REG 0xA00E +#define LED_BLINK_CFG_REG 0xA00F + +STATIC +VOID +YT8531PhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase + ) +{ + UINT16 OldAddr; + UINT16 Data; + + PhyRead (GmacBase, 0, EXT_REG_ADDR, &OldAddr); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, YTPHY_SYNCE_CFG_REG); + PhyWrite (GmacBase, 0, EXT_REG_DATA, YT8531_SCR_SYNCE_ENABLE | + YT8531_SCR_CLK_FRE_SEL_125M | + YT8531_SCR_CLK_SRC_SEL_PLL_125M); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, PHY_CLOCK_GATING_REG); + PhyRead (GmacBase, 0, EXT_REG_DATA, &Data); + Data &= ~RX_CLK_EN; + Data &= ~CLK_25M_SEL_MASK; + Data |= CLK_25M_SEL_125M; + PhyWrite (GmacBase, 0, EXT_REG_DATA, Data); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, PHY_SLEEP_CONTROL1_REG); + PhyRead (GmacBase, 0, EXT_REG_DATA, &Data); + Data &= ~SLEEP_SW; + PhyWrite (GmacBase, 0, EXT_REG_DATA, Data); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, LED1_CFG_REG); + PhyWrite (GmacBase, 0, EXT_REG_DATA, 0x0670); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, LED2_CFG_REG); + PhyWrite (GmacBase, 0, EXT_REG_DATA, 0x2070); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, LED_BLINK_CFG_REG); + PhyWrite (GmacBase, 0, EXT_REG_DATA, 0x007e); + + PhyWrite (GmacBase, 0, EXT_REG_ADDR, OldAddr); +} + +EFI_STATUS +EFIAPI +MotorcommPhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT32 PhyId + ) +{ + switch (PhyId) { + case 0x4F51E91B: + DEBUG ((DEBUG_INFO, "%a: Found Motorcomm YT8531 GbE PHY\n", __func__)); + YT8531PhyInit (GmacBase); + break; + default: + return EFI_UNSUPPORTED; + } + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/RealtekPhy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/RealtekPhy.c new file mode 100644 index 0000000..da4d96e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/RealtekPhy.c @@ -0,0 +1,54 @@ +/** @file + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "EthernetPhy.h" + +/* Realtek RTL8211F PHY registers */ +#define PAGSR 0x1F +#define LCR 0x10 +#define LCR_VALUE 0x6940 + +STATIC +VOID +RTL8211FPhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase + ) +{ + PhyWrite (GmacBase, 0, PAGSR, 0xD04); + MicroSecondDelay (10000); + PhyWrite (GmacBase, 0, LCR, LCR_VALUE); + MicroSecondDelay (10000); + PhyWrite (GmacBase, 0, PAGSR, 0); +} + +EFI_STATUS +EFIAPI +RealtekPhyInit ( + IN EFI_PHYSICAL_ADDRESS GmacBase, + IN UINT32 PhyId + ) +{ + switch (PhyId) { + case 0x001CC916: + DEBUG ((DEBUG_INFO, "%a: Found Realtek RTL8211F GbE PHY\n", __func__)); + RTL8211FPhyInit (GmacBase); + break; + case 0x001CC878: + DEBUG ((DEBUG_INFO, "%a: Found Realtek RTL8211F-VD GbE PHY\n", __func__)); + RTL8211FPhyInit (GmacBase); + break; + default: + return EFI_UNSUPPORTED; + } + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.c new file mode 100644 index 0000000..c8ce318 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.c @@ -0,0 +1,216 @@ +/** @file + * + * Copyright (c) 2021, Rockchip Limited. All rights reserved. + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "ComboPhy.h" + +#define COMBO_PIPE_PHY0 0xFEE00000 +#define COMBO_PIPE_PHY1 0xFEE10000 +#define COMBO_PIPE_PHY2 0xFEE20000 + +#define PHP_GRF_BASE 0xFD5B0000 +#define PHP_GRF_PCIESEL_CON 0x100 + +#define PIPE_PHY0_GRF 0xFD5BC000 +#define PIPE_PHY1_GRF 0xFD5C0000 +#define PIPE_PHY2_GRF 0xFD5C4000 + +static UINTN ComPhyReg[3][2] = { + { COMBO_PIPE_PHY0, PIPE_PHY0_GRF }, + { COMBO_PIPE_PHY1, PIPE_PHY1_GRF }, + { COMBO_PIPE_PHY2, PIPE_PHY2_GRF }, +}; + +STATIC +VOID +EFIAPI +InitComPhyConfig ( + UINTN PhyBaseAddr, + UINTN PhpBaseAddr, + UINT32 PhyMode + ) +{ + UINT32 Val; + DEBUG ((DEBUG_INIT, "%a reg=%x %x mode = %d\n", __func__, PhyBaseAddr, PhpBaseAddr, PhyMode)); + + switch (PhyMode) { + case COMBO_PHY_MODE_PCIE: + MmioWrite32 (PhpBaseAddr + 0x0, 0xFFFF1000); + MmioWrite32 (PhpBaseAddr + 0x4, 0xFFFF4000); + MmioWrite32 (PhpBaseAddr + 0x8, 0xFFFF0101); + MmioWrite32 (PhpBaseAddr + 0xc, 0xFFFF0200); + + /* gate_tx_pck_sel length select work for L1SS */ + MmioWrite32 (PhyBaseAddr + 0x74, 0xc0); + + /* PLL KVCO tuning fine */ + Val = MmioRead32 (PhyBaseAddr + (0x20 << 2)); + Val &= ~(0x7 << 2); + Val |= 0x4 << 2; + MmioWrite32 (PhyBaseAddr + (0x20 << 2), Val); + + /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */ + MmioWrite32 (PhyBaseAddr + (0x1b << 2), 0x4c); + + /* Set up su_trim: T3 */ + MmioWrite32 (PhyBaseAddr + (0xa << 2), 0xb0); + MmioWrite32 (PhyBaseAddr + (0xb << 2), 0x47); + MmioWrite32 (PhyBaseAddr + (0xd << 2), 0x57); + + if (PhyBaseAddr == COMBO_PIPE_PHY0) { + MmioWrite32 (PHP_GRF_BASE + PHP_GRF_PCIESEL_CON, BIT1 << 16); + } + + if (PhyBaseAddr == COMBO_PIPE_PHY1) { + MmioWrite32 (PHP_GRF_BASE + PHP_GRF_PCIESEL_CON, BIT0 << 16); + } + break; + + case COMBO_PHY_MODE_SATA: + MmioWrite32 (PhyBaseAddr + 0x38, 0x41); + MmioWrite32 (PhyBaseAddr + 0x18, 0x8F); + MmioWrite32 (PhyBaseAddr + 0x7C, 0x50); + MmioWrite32 (PhyBaseAddr + 0x24, 0x07); + + MmioWrite32 (PhpBaseAddr + 0x0, 0xFFFF0129); + MmioWrite32 (PhpBaseAddr + 0x4, 0xFFFF4000); + MmioWrite32 (PhpBaseAddr + 0x8, 0xFFFF80c1); + MmioWrite32 (PhpBaseAddr + 0xc, 0xFFFF4007); + + /* Should we tune the rest of the parameters too? */ + + break; + + case COMBO_PHY_MODE_USB3: + /* Set SSC downward spread spectrum */ + Val = MmioRead32 (PhyBaseAddr + (0x1f << 2)); + Val &= ~(0x3 << 4); + Val |= 0x01 << 4; + MmioWrite32 (PhyBaseAddr + 0x7c, Val); + + /* Enable adaptive CTLE for USB3.0 Rx */ + Val = MmioRead32 (PhyBaseAddr + (0x0e << 2)); + Val &= ~(0x1 << 0); + Val |= 0x01; + MmioWrite32 (PhyBaseAddr + (0x0e << 2), Val); + + /* Set PLL KVCO fine tuning signals */ + Val = MmioRead32 (PhyBaseAddr + (0x20 << 2)); + Val &= ~(0x7 << 2); + Val |= 0x2 << 2; + MmioWrite32 (PhyBaseAddr + (0x20 << 2), Val); + + /* Set PLL LPF R1 to su_trim[10:7]=1001 */ + MmioWrite32 (PhyBaseAddr + (0xb << 2), 0x4); + + /* Set PLL input clock divider 1/2 */ + Val = MmioRead32 (PhyBaseAddr + (0x5 << 2)); + Val &= ~(0x3 << 6); + Val |= 0x1 << 6; + MmioWrite32 (PhyBaseAddr + (0x5 << 2), Val); + + /* Set PLL loop divider */ + MmioWrite32 (PhyBaseAddr + (0x11 << 2), 0x32); + + /* Set PLL KVCO to min and set PLL charge pump current to max */ + MmioWrite32 (PhyBaseAddr + (0xa << 2), 0xf0); + + /* Set Rx squelch input filler bandwidth */ + MmioWrite32 (PhyBaseAddr + (0x14 << 2), 0x0d); + + /* Set txcomp_sel[15] to 1b'0 */ + MmioWrite32 (PhpBaseAddr + 0x8, 0x80000000); + /* Set txelec_sel[12] to 1b'0 */ + MmioWrite32 (PhpBaseAddr + 0x8, 0x10000000); + /* Set usb_mode_set[5:0]=6b'000100 */ + MmioWrite32 (PhpBaseAddr + 0x0, 0x003F0004); + + /* phy_clk_sel to 100MHz */ + MmioWrite32 (PhpBaseAddr + 0x4, 0x60004000); + break; + + default: + break; + } +} + +VOID +EFIAPI +ApplyComboPhyVariables ( + VOID + ) +{ + UINTN Index; + + UINT32 ComPhyMode[] = { PcdGet32 (PcdComboPhy0Mode), + PcdGet32 (PcdComboPhy1Mode), + PcdGet32 (PcdComboPhy2Mode) }; + + /* config phy clock to 100Mhz */ + HAL_CRU_ClkSetFreq (PLL_PPLL, 100 * 1000000); + HAL_CRU_ClkSetFreq (CLK_REF_PIPE_PHY0, 100 * 1000000); + HAL_CRU_ClkSetFreq (CLK_REF_PIPE_PHY1, 100 * 1000000); + HAL_CRU_ClkSetFreq (CLK_REF_PIPE_PHY2, 100 * 1000000); + + /* Initialize echo combo phy */ + for (Index = 0; Index < ARRAY_SIZE (ComPhyMode); Index++) { + InitComPhyConfig (ComPhyReg[Index][0], ComPhyReg[Index][1], ComPhyMode[Index]); + } + + MmioWrite32 (PHP_GRF_BASE + 0x0, 0x07E00440); + MmioWrite32 (PHP_GRF_BASE + 0x4, 0x00070002); + + /* reset deassert */ + MmioWrite32 (0xfd7c0000 + 0x0b34, 0x01c00000); +} + +VOID +EFIAPI +SetupComboPhyVariables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + EFI_STATUS Status; + + Size = sizeof (UINT32); + + Status = gRT->GetVariable (L"ComboPhy0Mode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status) || !FixedPcdGetBool (PcdComboPhy0Switchable)) { + Status = PcdSet32S (PcdComboPhy0Mode, FixedPcdGet32 (PcdComboPhy0ModeDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"ComboPhy1Mode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status) || !FixedPcdGetBool (PcdComboPhy1Switchable)) { + Status = PcdSet32S (PcdComboPhy1Mode, FixedPcdGet32 (PcdComboPhy1ModeDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"ComboPhy2Mode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status) || !FixedPcdGetBool (PcdComboPhy2Switchable)) { + Status = PcdSet32S (PcdComboPhy2Mode, FixedPcdGet32 (PcdComboPhy2ModeDefault)); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.h new file mode 100644 index 0000000..dd1e6f7 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ComboPhy.h @@ -0,0 +1,29 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_COMBO_PHY_H__ +#define __RK3588DXE_COMBO_PHY_H__ + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyComboPhyVariables ( + VOID + ); + +VOID +EFIAPI +SetupComboPhyVariables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_COMBO_PHY_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.c new file mode 100644 index 0000000..97dff95 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.c @@ -0,0 +1,63 @@ +/** @file + * + * Copyright (c) 2020, Jeremy Linton + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "ConfigTable.h" + +VOID +EFIAPI +ApplyConfigTableVariables ( + VOID + ) +{ + /* nothing to do here, the PCDs are read by AcpiPlatformDxe and FdtPlatformDxe */ +} + +VOID +EFIAPI +SetupConfigTableVariables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + UINT8 Var8; + EFI_STATUS Status; + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"ConfigTableMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdConfigTableMode, PcdGet32 (PcdConfigTableMode)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"AcpiPcieEcamCompatMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdAcpiPcieEcamCompatMode, FixedPcdGet32 (PcdAcpiPcieEcamCompatModeDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT8); + Status = gRT->GetVariable (L"FdtSupportOverrides", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var8); + if (EFI_ERROR (Status)) { + Status = PcdSet8S (PcdFdtSupportOverrides, PcdGet8 (PcdFdtSupportOverrides)); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.h new file mode 100644 index 0000000..6c3f8dd --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/ConfigTable.h @@ -0,0 +1,29 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_CONFIG_TABLE_H__ +#define __RK3588DXE_CONFIG_TABLE_H__ + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyConfigTableVariables ( + VOID + ); + +VOID +EFIAPI +SetupConfigTableVariables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_CONFIG_TABLE_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.c new file mode 100644 index 0000000..cba6e9b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.c @@ -0,0 +1,498 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "CpuPerformance.h" + +#define SCMI_CLK_CPUL 0 +#define SCMI_CLK_CPUB01 2 +#define SCMI_CLK_CPUB23 3 + +#define FREQ_1_MHZ 1000000 + +typedef struct { + UINT64 Hz; + UINT32 Microvolts; +} OPERATING_PERFORMANCE_POINT; + +STATIC CONST OPERATING_PERFORMANCE_POINT mCPULOppTable[] = { + { 408000000, 675000 }, + { 600000000, 675000 }, + { 816000000, 675000 }, + { 1008000000, 675000 }, + { 1200000000, 712500 }, + { 1416000000, 762500 }, + { 1608000000, 850000 }, + { 1800000000, 950000 } +}; + +STATIC CONST OPERATING_PERFORMANCE_POINT mCPUBOppTable[] = { + { 408000000, 675000 }, + { 600000000, 675000 }, + { 816000000, 675000 }, + { 1008000000, 675000 }, + { 1200000000, 675000 }, + { 1416000000, 725000 }, + { 1608000000, 762500 }, + { 1800000000, 850000 }, + { 2016000000, 925000 }, + { 2208000000, 987500 }, + { 2256000000, 1000000 }, + { 2304000000, 1000000 }, + { 2352000000, 1000000 }, + { 2400000000, 1000000 } +}; + +typedef struct { + UINT32 ClockId; + CONST OPERATING_PERFORMANCE_POINT *Opp; + UINT32 OppCount; +} SCMI_OPP_TABLE; + +STATIC CONST SCMI_OPP_TABLE mScmiOppTable[] = { + { SCMI_CLK_CPUL, mCPULOppTable, ARRAY_SIZE (mCPULOppTable) }, + { SCMI_CLK_CPUB01, mCPUBOppTable, ARRAY_SIZE (mCPUBOppTable) }, + { SCMI_CLK_CPUB23, mCPUBOppTable, ARRAY_SIZE (mCPUBOppTable) } +}; + +STATIC +EFI_STATUS +EFIAPI +ScmiSetClockRate ( + IN UINT32 ClockId, + IN UINT64 Hz + ) +{ + EFI_STATUS Status; + SCMI_CLOCK_PROTOCOL *ClockProtocol; + EFI_GUID ClockProtocolGuid = ARM_SCMI_CLOCK_PROTOCOL_GUID; + UINT64 ClockRate; + BOOLEAN Enabled; + CHAR8 ClockName[SCMI_MAX_STR_LEN]; + + Status = gBS->LocateProtocol ( + &ClockProtocolGuid, + NULL, + (VOID**)&ClockProtocol + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = ClockProtocol->GetClockAttributes ( + ClockProtocol, + ClockId, + &Enabled, + ClockName + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = ClockProtocol->RateGet (ClockProtocol, ClockId, &ClockRate); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DEBUG ((DEBUG_INFO, "SCMI: %a: Current rate is %uHz\n", ClockName, ClockRate)); + + ClockRate = Hz; + + DEBUG ((DEBUG_INFO, "SCMI: %a: New rate is %uHz\n", ClockName, ClockRate)); + + Status = ClockProtocol->RateSet ( + ClockProtocol, + ClockId, + ClockRate + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = ClockProtocol->RateGet (ClockProtocol, ClockId, &ClockRate); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DEBUG ((DEBUG_INFO, "SCMI: %a: Current rate is %uHz\n", ClockName, ClockRate)); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +ScmiGetClockRate ( + IN UINT32 ClockId, + OUT UINT64 *Hz + ) +{ + EFI_STATUS Status; + SCMI_CLOCK_PROTOCOL *ClockProtocol; + EFI_GUID ClockProtocolGuid = ARM_SCMI_CLOCK_PROTOCOL_GUID; + + Status = gBS->LocateProtocol ( + &ClockProtocolGuid, + NULL, + (VOID**)&ClockProtocol + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + return ClockProtocol->RateGet (ClockProtocol, ClockId, Hz); +} + +STATIC +EFI_STATUS +EFIAPI +GetOppVoltage ( + IN CONST OPERATING_PERFORMANCE_POINT *OppTable, + IN UINT32 OppCount, + IN UINT64 Hz, + OUT UINT32 *Microvolts + ) +{ + for (UINTN Index = 0; Index < OppCount; Index++) { + if (Hz <= OppTable[Index].Hz) { + *Microvolts = OppTable[Index].Microvolts; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +STATIC +VOID +EFIAPI +SetRk860xRegulatorByTag ( + IN UINT32 Tag, + OUT UINT32 Microvolts + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + RK860X_REGULATOR_PROTOCOL *Rk860xRegulator; + UINTN NumRegulators; + UINT32 Index; + UINT32 Voltage; + BOOLEAN FoundReg; + + Status = gBS->LocateHandleBuffer (ByProtocol, + &gRk860xRegulatorProtocolGuid, + NULL, + &NumRegulators, + &HandleBuffer); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_WARN, "Couldn't locate gRk860xRegulatorProtocolGuid. Status=%r\n", Status)); + return; + } + + FoundReg = FALSE; + for (Index = 0; Index < NumRegulators; Index++) { + Status = gBS->OpenProtocol (HandleBuffer[Index], + &gRk860xRegulatorProtocolGuid, + (VOID **) &Rk860xRegulator, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to open protocol for reg %d. Status=%r\n", Index)); + return; + } + + if (Rk860xRegulator->Tag != Tag) { + goto CloseProtocol; + } + + FoundReg = TRUE; + DEBUG((DEBUG_INFO, "Found 0x%x on I2C bus %d for tag %u\n", + I2C_DEVICE_ADDRESS(Rk860xRegulator->Identifier), + I2C_DEVICE_BUS(Rk860xRegulator->Identifier), + Tag)); + + Status = Rk860xRegulator->GetVoltage (Rk860xRegulator, &Voltage, FALSE); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to get voltage. Status=%r\n", Status)); + goto CloseProtocol; + } + DEBUG((DEBUG_INFO, "Current voltage: %d uV\n", Voltage)); + + Voltage = Microvolts; + + DEBUG((DEBUG_INFO, "Setting voltage to: %d uV\n", Voltage)); + Status = Rk860xRegulator->SetVoltage (Rk860xRegulator, Voltage, FALSE); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to set voltage. Status=%r\n", Status)); + goto CloseProtocol; + } + + Status = Rk860xRegulator->GetVoltage (Rk860xRegulator, &Voltage, FALSE); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Failed to get voltage. Status=%r\n", Status)); + goto CloseProtocol; + } + DEBUG((DEBUG_INFO, "Current voltage: %d uV\n", Voltage)); + +CloseProtocol: + gBS->CloseProtocol (HandleBuffer[Index], + &gRk860xRegulatorProtocolGuid, + gImageHandle, + NULL); + + if (FoundReg) { + break; + } + } +} + +STATIC +VOID +EFIAPI +SetCpuVoltage ( + IN UINT32 ClockId, + OUT UINT32 Microvolts + ) +{ + if (Microvolts > CLUSTER_MICROVOLTS_MAX) { + Microvolts = CLUSTER_MICROVOLTS_MAX; + } + if (Microvolts < CLUSTER_MICROVOLTS_MIN) { + Microvolts = CLUSTER_MICROVOLTS_MIN; + } + + if (ClockId == SCMI_CLK_CPUL) { + SetCPULittleVoltage (Microvolts); + } else { + SetRk860xRegulatorByTag (ClockId, Microvolts); + } +} + +VOID +EFIAPI +ApplyCpuClockVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 Index; + UINT64 ClockRate; + SCMI_OPP_TABLE ScmiOppTable; + UINT32 CPUClusterClockPreset[] = { PcdGet32 (PcdCPULClusterClockPreset), + PcdGet32 (PcdCPUB01ClusterClockPreset), + PcdGet32 (PcdCPUB23ClusterClockPreset) }; + UINT32 CPUClusterClockCustom[] = { PcdGet32 (PcdCPULClusterClockCustom), + PcdGet32 (PcdCPUB01ClusterClockCustom), + PcdGet32 (PcdCPUB23ClusterClockCustom) }; + + for (Index = 0; Index < ARRAY_SIZE(CPUClusterClockPreset); Index++) { + ScmiOppTable = mScmiOppTable[Index]; + + switch (CPUClusterClockPreset[Index]) { + case CPU_PERF_CLUSTER_CLOCK_PRESET_MIN: + ClockRate = ScmiOppTable.Opp[0].Hz; + break; + case CPU_PERF_CLUSTER_CLOCK_PRESET_MAX: + ClockRate = ScmiOppTable.Opp[ScmiOppTable.OppCount - 1].Hz; + break; + case CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM: + ClockRate = CPUClusterClockCustom[Index] * FREQ_1_MHZ; + break; + default: + continue; + } + + Status = ScmiSetClockRate (ScmiOppTable.ClockId, ClockRate); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_WARN, "%a: ScmiSetClockRate failed. Status=%r\n", __FUNCTION__, Status)); + } + } +} + +VOID +EFIAPI +ApplyCpuVoltageVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 ClockRate; + UINT32 Index; + SCMI_OPP_TABLE ScmiOppTable; + UINT32 Microvolts; + UINT32 CPUClusterVoltageMode[] = { PcdGet32 (PcdCPULClusterVoltageMode), + PcdGet32 (PcdCPUB01ClusterVoltageMode), + PcdGet32 (PcdCPUB23ClusterVoltageMode) }; + UINT32 CPUClusterVoltageCustom[] = { PcdGet32 (PcdCPULClusterVoltageCustom), + PcdGet32 (PcdCPUB01ClusterVoltageCustom), + PcdGet32 (PcdCPUB23ClusterVoltageCustom) }; + + for (Index = 0; Index < ARRAY_SIZE (CPUClusterVoltageMode); Index++) { + ScmiOppTable = mScmiOppTable[Index]; + + switch (CPUClusterVoltageMode[Index]) { + case CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO: + Status = ScmiGetClockRate (ScmiOppTable.ClockId, &ClockRate); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: ScmiGetClockRate failed. Status=%r\n", __FUNCTION__, Status)); + continue; + } + + Status = GetOppVoltage (ScmiOppTable.Opp, ScmiOppTable.OppCount, + ClockRate, &Microvolts); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a: GetOppVoltage failed. Status=%r\n", __FUNCTION__, Status)); + continue; + } + break; + case CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM: + Microvolts = CPUClusterVoltageCustom[Index]; + break; + default: + continue; + } + + SetCpuVoltage (ScmiOppTable.ClockId, Microvolts); + } +} + +VOID +EFIAPI +SetupCpuPerfVariables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + EFI_STATUS Status; + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPULClusterClockPreset", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPULClusterClockPreset, PcdGet32 (PcdCPULClusterClockPresetDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPULClusterClockCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPULClusterClockCustom, PcdGet32 (PcdCPULClusterClockCustom)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB01ClusterClockPreset", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB01ClusterClockPreset, PcdGet32 (PcdCPUB01ClusterClockPresetDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB01ClusterClockCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB01ClusterClockCustom, PcdGet32 (PcdCPUB01ClusterClockCustom)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB23ClusterClockPreset", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB23ClusterClockPreset, PcdGet32 (PcdCPUB23ClusterClockPresetDefault)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB23ClusterClockCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB23ClusterClockCustom, PcdGet32 (PcdCPUB23ClusterClockCustom)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPULClusterVoltageMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPULClusterVoltageMode, PcdGet32 (PcdCPULClusterVoltageMode)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPULClusterVoltageCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPULClusterVoltageCustom, PcdGet32 (PcdCPULClusterVoltageCustom)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB01ClusterVoltageMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB01ClusterVoltageMode, PcdGet32 (PcdCPUB01ClusterVoltageMode)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB01ClusterVoltageCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB01ClusterVoltageCustom, PcdGet32 (PcdCPUB01ClusterVoltageCustom)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB23ClusterVoltageMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB23ClusterVoltageMode, PcdGet32 (PcdCPUB23ClusterVoltageMode)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT32); + Status = gRT->GetVariable (L"CpuPerf_CPUB23ClusterVoltageCustom", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCPUB23ClusterVoltageCustom, PcdGet32 (PcdCPUB23ClusterVoltageCustom)); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.h new file mode 100644 index 0000000..d01b103 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.h @@ -0,0 +1,40 @@ +/** @file +* +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ +#ifndef __RK3588DXE_CPU_PERF_H__ +#define __RK3588DXE_CPU_PERF_H__ + +#define CLUSTER_MICROVOLTS_MIN 500000 +#define CLUSTER_MICROVOLTS_MAX 1500000 +#define CLUSTER_MICROVOLTS_STEP 6250 +#define CPUL_CLUSTER_MICROVOLTS_DEFAULT 950000 +#define CPUB_CLUSTER_MICROVOLTS_DEFAULT 1000000 + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyCpuClockVariables ( + VOID + ); + +VOID +EFIAPI +ApplyCpuVoltageVariables ( + VOID + ); + +VOID +EFIAPI +SetupCpuPerfVariables ( + VOID + ); +#endif + +#endif // __RK3588DXE_CPU_PERF_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.c new file mode 100644 index 0000000..19855d6 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.c @@ -0,0 +1,50 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "DebugSerialPort.h" + +VOID +EFIAPI +ApplyDebugSerialPortVariables ( + VOID + ) +{ + /* nothing to do here */ +} + +VOID +EFIAPI +SetupDebugSerialPortVariables ( + VOID + ) +{ + UINTN Size; + UINT64 Var64; + EFI_STATUS Status; + + Size = sizeof (UINT64); + + Status = gRT->GetVariable (L"DebugSerialPortBaudRate", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var64); + if (EFI_ERROR (Status)) { + Var64 = DEBUG_SERIAL_PORT_BAUD_RATE_DEFAULT; + Status = gRT->SetVariable ( + L"DebugSerialPortBaudRate", + &gRK3588DxeFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + &Var64); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.h new file mode 100644 index 0000000..0ffeaeb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/DebugSerialPort.h @@ -0,0 +1,33 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_DEBUG_SERIAL_PORT_H__ +#define __RK3588DXE_DEBUG_SERIAL_PORT_H__ + +#define DEBUG_SERIAL_PORT_BAUD_RATE_MIN 0 +#define DEBUG_SERIAL_PORT_BAUD_RATE_MAX 1500000 +#define DEBUG_SERIAL_PORT_BAUD_RATE_DEFAULT 1500000 + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyDebugSerialPortVariables ( + VOID + ); + +VOID +EFIAPI +SetupDebugSerialPortVariables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_DEBUG_SERIAL_PORT_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.c new file mode 100644 index 0000000..8679758 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.c @@ -0,0 +1,58 @@ +/** @file + * + * Copyright (c) 2023, Molly Sophia + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include +#include "RK3588DxeFormSetGuid.h" +#include "FanControl.h" + +VOID +EFIAPI +ApplyCoolingFanVariables ( + VOID + ) +{ + UINT32 Var32 = PcdGet32 (PcdCoolingFanState); + if (Var32 == COOLING_FAN_STATE_ENABLED) { + Var32 = PcdGet32 (PcdCoolingFanSpeed); + PwmFanIoSetup(); + PwmFanSetSpeed(Var32); + } +} + +VOID +EFIAPI +SetupCoolingFanVariables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + EFI_STATUS Status; + + Size = sizeof (UINT32); + + Status = gRT->GetVariable (L"CoolingFanState", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCoolingFanState, 1); + ASSERT_EFI_ERROR (Status); + } + + Status = gRT->GetVariable (L"CoolingFanSpeed", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdCoolingFanSpeed, FAN_PERCENTAGE_DEFAULT); + ASSERT_EFI_ERROR (Status); + } +} \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.h new file mode 100644 index 0000000..d493405 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/FanControl.h @@ -0,0 +1,34 @@ +/** @file + * + * Copyright (c) 2023, Molly Sophia + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_FANCONTROL_H__ +#define __RK3588DXE_FANCONTROL_H__ + +#define FAN_PERCENTAGE_MIN 0 +#define FAN_PERCENTAGE_MAX 100 +#define FAN_PERCENTAGE_STEP 1 +#define FAN_PERCENTAGE_DEFAULT 50 + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyCoolingFanVariables ( + VOID + ); + +VOID +EFIAPI +SetupCoolingFanVariables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_FANCONTROL_H__ \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.c new file mode 100644 index 0000000..ccacadf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.c @@ -0,0 +1,56 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "PciExpress30.h" + +VOID +EFIAPI +ApplyPcie30Variables ( + VOID + ) +{ + /* nothing to do yet */ +} + +VOID +EFIAPI +SetupPcie30Variables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + UINT8 Var8; + + EFI_STATUS Status; + + Size = sizeof (UINT32); + + Status = gRT->GetVariable (L"Pcie30State", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status) || !FixedPcdGetBool (PcdPcie30Supported)) { + Status = PcdSet32S (PcdPcie30State, FixedPcdGet32 (PcdPcie30Supported)); + ASSERT_EFI_ERROR (Status); + } + + Size = sizeof (UINT8); + + Status = gRT->GetVariable (L"Pcie30PhyMode", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var8); + if (EFI_ERROR (Status) || !FixedPcdGetBool (PcdPcie30Supported)) { + Status = PcdSet8S (PcdPcie30PhyMode, FixedPcdGet8 (PcdPcie30PhyModeDefault)); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.h new file mode 100644 index 0000000..7d3deec --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/PciExpress30.h @@ -0,0 +1,29 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_PCIE30_H__ +#define __RK3588DXE_PCIE30_H__ + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyPcie30Variables ( + VOID + ); + +VOID +EFIAPI +SetupPcie30Variables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_PCIE30_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.c new file mode 100644 index 0000000..9c1bd07 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.c @@ -0,0 +1,520 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Limited. All rights reserved. +* Copyright (c) 2023, Mario Bălănică +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RK3588Dxe.h" +#include "RK3588DxeFormSetGuid.h" +#include "CpuPerformance.h" +#include "ComboPhy.h" +#include "PciExpress30.h" +#include "ConfigTable.h" +#include "FanControl.h" +#include "UsbDpPhy.h" +#include "DebugSerialPort.h" + +extern UINT8 RK3588DxeHiiBin[]; +extern UINT8 RK3588DxeStrings[]; + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +STATIC HII_VENDOR_DEVICE_PATH mVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(sizeof (VENDOR_DEVICE_PATH)), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + RK3588DXE_FORMSET_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8)(END_DEVICE_PATH_LENGTH), + (UINT8)((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +#define SATA_CAP 0x0000 +#define SATA_CAP_SSS BIT27 +#define SATA_PI 0x000C +#define SATA_CMD 0x0118 +#define SATA_CMD_FBSCP BIT22 + +static UINTN AhciReg[3] = { + 0xFE210000, + 0xFE220000, + 0xFE230000, +}; + +STATIC +VOID +InstallSataDevices ( + VOID + ) +{ + UINT32 Index; + UINT32 PcieSlotIndex; + UINT32 ComPhyMode[] = { PcdGet32 (PcdComboPhy0Mode), + PcdGet32 (PcdComboPhy1Mode), + PcdGet32 (PcdComboPhy2Mode) }; + + for (Index = 0; Index < ARRAY_SIZE (ComPhyMode); Index++) { + if (ComPhyMode[Index] == COMBO_PHY_MODE_SATA) { + /* Enable power at the M.2 PCIe/SATA slots */ + switch (Index) { + case 0: + PcieSlotIndex = PCIE_SEGMENT_PCIE20L2; + break; + case 1: + PcieSlotIndex = PCIE_SEGMENT_PCIE20L0; + break; + case 2: + PcieSlotIndex = PCIE_SEGMENT_PCIE20L1; + break; + default: + ASSERT (FALSE); + continue; + } + PcieIoInit(PcieSlotIndex); + PciePowerEn(PcieSlotIndex, TRUE); + + /* Set port implemented flag */ + MmioWrite32 (AhciReg[Index] + SATA_PI, 0x1); + + /* Supports staggered spin-up */ + /* Disable for now, otherwise NetBSD seems to not pick up any drive? */ + MmioAndThenOr32 (AhciReg[Index] + SATA_CAP, ~SATA_CAP_SSS, 0); + + /* Supports FIS-based switching */ + MmioOr32 (AhciReg[Index] + SATA_CMD, SATA_CMD_FBSCP); + + RegisterNonDiscoverableMmioDevice (NonDiscoverableDeviceTypeAhci, + NonDiscoverableDeviceDmaTypeNonCoherent, + NULL, + NULL, + 1, + AhciReg[Index], SIZE_4KB); + } + } +} + +STATIC +EFI_STATUS +EFIAPI +InstallHiiPages ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + DriverHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, + &gEfiDevicePathProtocolGuid, + &mVendorDevicePath, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + HiiHandle = HiiAddPackages (&gRK3588DxeFormSetGuid, + DriverHandle, + RK3588DxeStrings, + RK3588DxeHiiBin, + NULL); + + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces (DriverHandle, + &gEfiDevicePathProtocolGuid, + &mVendorDevicePath, + NULL); + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +SetupVariables ( + VOID + ) +{ + SetupCpuPerfVariables (); + SetupComboPhyVariables (); + SetupPcie30Variables (); + SetupConfigTableVariables (); + SetupCoolingFanVariables (); + SetupUsbDpPhyVariables (); + SetupDebugSerialPortVariables (); + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +AfterApplyVariablesInit ( + VOID + ) +{ + InstallSataDevices (); +} + +STATIC +VOID +EFIAPI +InstallConfigAppliedProtocol ( + VOID + ) +{ + EFI_HANDLE Handle = NULL; + EFI_STATUS Status; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gRockchipPlatformConfigAppliedProtocolGuid, + NULL, + NULL); + ASSERT_EFI_ERROR (Status); +} + +STATIC +VOID +EFIAPI +ApplyVariables ( + VOID + ) +{ + ApplyCpuClockVariables (); + ApplyComboPhyVariables (); + ApplyPcie30Variables (); + ApplyConfigTableVariables (); + ApplyCoolingFanVariables (); + ApplyUsbDpPhyVariables (); + ApplyDebugSerialPortVariables (); + + InstallConfigAppliedProtocol (); + + AfterApplyVariablesInit (); +} + +STATIC +VOID +RK3588SetupAudio ( + IN VOID + ) +{ + // Source PLL, ACPI expects this exact rate. + HAL_CRU_ClkSetFreq (PLL_AUPLL, 786432000); + + // Warning: Only enable I2S if present. + // E.g. Enabling I2S1 on OPI5+ causes PCIe devices to disappear + if (FixedPcdGetBool(PcdI2S0Supported)){ + //Configure I2S0 (e.g. Orange Pi 5 Plus) + GpioPinSetFunction(1, GPIO_PIN_PD4, 2); //i2s0_sdi0 + GpioPinSetFunction(1, GPIO_PIN_PC7, 1); //i2s0_sdo0 + + GpioPinSetFunction(1, GPIO_PIN_PC5, 1); //i2s0_lrck + GpioPinSetFunction(1, GPIO_PIN_PC3, 1); //i2s0_sclk + GpioPinSetFunction(1, GPIO_PIN_PC2, 1); //i2s0_mclk + + HAL_CRU_ClkSetMux (CLK_I2S0_8CH_TX_SRC, 0x1); // clk_aupll_mux + HAL_CRU_ClkSetMux (MCLK_I2S0_8CH_TX, 0x1); // clk_i2s0_8ch_tx_frac + } + + if (FixedPcdGetBool(PcdI2S1Supported)){ + //Configure I2S1 (e.g. Orange Pi 5) + GpioPinSetFunction(4, GPIO_PIN_PA6, 3); //i2s1m0_sdi1 + GpioPinSetFunction(4, GPIO_PIN_PB4, 3); //i2s1m0_sdo3 + + GpioPinSetFunction(4, GPIO_PIN_PA2, 3); //i2s1m0_lrck + GpioPinSetFunction(4, GPIO_PIN_PA1, 3); //i2s1m0_sclk + GpioPinSetFunction(4, GPIO_PIN_PA0, 3); //i2s1m0_mclk + + // CLK_I2S1_8CH_TX_SRC fixed parent: PLL_CPLL + HAL_CRU_ClkSetMux (MCLK_I2S1_8CH_TX, 0x1); // clk_i2s1_8ch_tx_frac + } +} + +EFI_STATUS +RK3588InitPeripherals ( + IN VOID + ) +{ + DEBUG((DEBUG_INIT, "RK3588InitPeripherals: Entry\n")); + + RK3588SetupAudio (); + + Rk806Configure(); + + return EFI_SUCCESS; +} + +STATIC VOID SetFlashAttributeToUncache(VOID) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR desp = {0}; + + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + PcdGet64(FspiBaseAddr), + SIZE_64KB, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to add memory space Status = %r\n", Status)); + return; + } + + Status = gDS->GetMemorySpaceDescriptor(PcdGet64(FspiBaseAddr),&desp); + if(EFI_ERROR(Status)){ + DEBUG ((DEBUG_ERROR, "%a: GetMemorySpaceDescriptor failed = %x\n", __FUNCTION__, Status)); + return; + } + + Status = gDS->SetMemorySpaceAttributes ( + PcdGet64(FspiBaseAddr), + SIZE_64KB, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes Status = %x\n",__FUNCTION__, Status)); + } + + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + PcdGet64(CruBaseAddr), + SIZE_64KB, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "RTC: Failed to add memory space Status = %r\n", Status)); + return; + } + + Status = gDS->GetMemorySpaceDescriptor(PcdGet64(CruBaseAddr),&desp); + if(EFI_ERROR(Status)){ + DEBUG ((DEBUG_ERROR, "%a: GetMemorySpaceDescriptor failed = %x\n", __FUNCTION__, Status)); + return; + } + + Status = gDS->SetMemorySpaceAttributes ( + PcdGet64(CruBaseAddr), + SIZE_64KB, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes Status = %x\n",__FUNCTION__, Status)); + } +} + +STATIC +VOID +EFIAPI +OnEfiVariableWriteArchRegistrationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumProtocols; + + Status = gBS->LocateHandleBuffer (ByProtocol, + &gEfiVariableWriteArchProtocolGuid, + NULL, + &NumProtocols, + &HandleBuffer); + if (EFI_ERROR(Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG((DEBUG_WARN, "Couldn't locate gEfiVariableWriteArchProtocolGuid. Status=%r\n", Status)); + } + return; + } + + gBS->CloseEvent (Event); + + Status = SetupVariables (); + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Couldn't setup NV vars. Status=%r\n", Status)); + } + + ApplyVariables (); + + Status = InstallHiiPages (); + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Couldn't install RK3588Dxe HII pages. Status=%r\n", Status)); + } +} + +VOID +EFIAPI +RK3588NotifyReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // We set CPU voltages late on first notification of the ReadyToBoot event because + // the user should have a chance to dial settings back in case they've set values that are + // too high and/or the power supply is insufficient. Setting them earlier may prevent this. + // The default values provide enough performance for the UEFI environment, so there's + // really no need to set them early. + // + + DEBUG ((DEBUG_INFO, "%a: called. Configure CPU voltages once.\n", __FUNCTION__)); + + ApplyCpuVoltageVariables (); + + gBS->CloseEvent (Event); +} + + +/** + This function uninstalls the recently added EFI_MEMORY_ATTRIBUTE_PROTOCOL + to workaround older versions of OS loaders/shims using it incorrectly and + throwing a Synchronous Exception. + + See: + - https://github.com/microsoft/mu_silicon_arm_tiano/issues/124 + - https://edk2.groups.io/g/devel/topic/99631663 +**/ +STATIC +VOID +EFIAPI +UninstallMemoryAttributeProtocol ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles; + UINTN HandleCount; + EFI_MEMORY_ATTRIBUTE_PROTOCOL *MemoryAttributeProtocol; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiMemoryAttributeProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + ASSERT_EFI_ERROR (Status); + ASSERT (HandleCount == 1); + + Status = gBS->HandleProtocol ( + Handles[0], + &gEfiMemoryAttributeProtocolGuid, + (VOID **)&MemoryAttributeProtocol + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handles[0], + &gEfiMemoryAttributeProtocolGuid, + MemoryAttributeProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + + gBS->FreePool (Handles); +} + +STATIC +VOID +EFIAPI +RK3588NotifyEndOfDxe ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gBS->CloseEvent (Event); + + UninstallMemoryAttributeProtocol (); +} + +EFI_STATUS +EFIAPI +RK3588EntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *EfiVariableArchRegistrationEvent; + EFI_EVENT Event; + + PlatformEarlyInit(); + + // + // We actually depend on gEfiVariableWriteArchProtocolGuid but don't want to + // delay the entire driver, so we create a notify event on protocol arrival instead + // and set up the variables & HII data in the callback. + // + EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, + TPL_CALLBACK, + OnEfiVariableWriteArchRegistrationEvent, + NULL, + &EfiVariableArchRegistrationEvent); + + Status = EfiCreateEventReadyToBootEx (TPL_CALLBACK, + RK3588NotifyReadyToBoot, + NULL, + &Event); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RK3588NotifyEndOfDxe, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &Event); + ASSERT_EFI_ERROR (Status); + + Status = RK3588InitPeripherals (); + if (EFI_ERROR (Status)) { + return Status; + } + + SetFlashAttributeToUncache(); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.h new file mode 100644 index 0000000..1aa55e5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.h @@ -0,0 +1,12 @@ +/** @file +* +* Copyright (c) 2018, Linaro Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __RK3588DXE_H__ +#define __RK3588DXE_H__ + +#endif /* __RK3588DXE_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf new file mode 100644 index 0000000..93d266f --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf @@ -0,0 +1,119 @@ +# +# Copyright (c) 2013 - 2014, ARM Ltd. All rights reserved. +# Copyright (c) 2018, Linaro Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +[Defines] + INF_VERSION = 0x0001001a + BASE_NAME = RK3588Dxe + FILE_GUID = f6c64348-45ec-11ec-9726-f42a7dcb925d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RK3588EntryPoint + +[Sources.common] + RK3588Dxe.c + RK3588DxeHii.uni + RK3588DxeHii.vfr + CpuPerformance.c + ComboPhy.c + PciExpress30.c + ConfigTable.c + FanControl.c + UsbDpPhy.c + DebugSerialPort.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + CacheMaintenanceLib + DebugLib + IoLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiLib + UefiDriverEntryPoint + DxeServicesTableLib + SpiLib + RK806 + CruLib + ArmLib + NonDiscoverableDeviceRegistrationLib + HiiLib + PcdLib + RockchipPlatformLib + +[Protocols] + gEfiVariableWriteArchProtocolGuid ## CONSUMES + gEfiMemoryAttributeProtocolGuid ## CONSUMES + gRk860xRegulatorProtocolGuid ## CONSUMES + gRockchipPlatformConfigAppliedProtocolGuid ## PRODUCES + +[Pcd] + gRockchipTokenSpaceGuid.CruBaseAddr + gRockchipTokenSpaceGuid.FspiBaseAddr + + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPULClusterClockPreset + gRK3588TokenSpaceGuid.PcdCPULClusterClockCustom + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPreset + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockCustom + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPreset + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockCustom + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageMode + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageCustom + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageMode + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageCustom + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageMode + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageCustom + + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault + gRK3588TokenSpaceGuid.PcdComboPhy0Mode + gRK3588TokenSpaceGuid.PcdComboPhy1Mode + gRK3588TokenSpaceGuid.PcdComboPhy2Mode + + gRK3588TokenSpaceGuid.PcdPcie30Supported + gRK3588TokenSpaceGuid.PcdPcie30State + gRK3588TokenSpaceGuid.PcdPcie30PhyMode + gRK3588TokenSpaceGuid.PcdPcie30PhyModeDefault + + gRK3588TokenSpaceGuid.PcdConfigTableMode + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatModeDefault + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatMode + gRK3588TokenSpaceGuid.PcdFdtSupportOverrides + + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput + gRK3588TokenSpaceGuid.PcdCoolingFanState + gRK3588TokenSpaceGuid.PcdCoolingFanSpeed + + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Usb3State + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Usb3State + + gRK3588TokenSpaceGuid.PcdI2S0Supported + gRK3588TokenSpaceGuid.PcdI2S1Supported + +[Guids] + gRK3588DxeFormSetGuid + gEfiEndOfDxeEventGroupGuid + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeFormSetGuid.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeFormSetGuid.h new file mode 100644 index 0000000..ca10926 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeFormSetGuid.h @@ -0,0 +1,17 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_FORMSET_GUID_H__ +#define __RK3588DXE_FORMSET_GUID_H__ + +#define RK3588DXE_FORMSET_GUID \ + { 0x10f41c33, 0xa468, 0x42cd, { 0x85, 0xee, 0x70, 0x43, 0x21, 0x3f, 0x73, 0xa3 } } + +extern EFI_GUID gRK3588DxeFormSetGuid; + +#endif // __RK3588DXE_FORMSET_GUID_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.uni b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.uni new file mode 100644 index 0000000..112a705 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.uni @@ -0,0 +1,183 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#langdef en-US "English" + +#string STR_NULL_STRING #language en-US "" + +#string STR_FORM_SET_TITLE #language en-US "Rockchip Platform Configuration" +#string STR_FORM_SET_TITLE_HELP #language en-US "Configure various platform settings." +#string STR_FORM_SET_TITLE_SUBTITLE #language en-US "Configuration Options" + +/* + * Common strings + */ +#string STR_DISABLED #language en-US "Disabled" +#string STR_ENABLED #language en-US "Enabled" + +/* + * CPU Performance configuration + */ +#string STR_CPU_PERF_FORM_TITLE #language en-US "CPU Performance" +#string STR_CPU_PERF_FORM_HELP #language en-US "Adjust CPU clocks and voltages." +#string STR_CPU_PERF_FORM_SUBTITLE #language en-US "Note: All these settings may be overridden by the OS if supported." + +#string STR_CPU_PERF_CLUSTER_CLOCKS_SUBTITLE #language en-US "Cluster Clocks" + +#string STR_CPU_PERF_CPUL_CLUSTER_CLOCK_PRESET_PROMPT #language en-US "CPUL Clock Preset" +#string STR_CPU_PERF_CPUL_CLUSTER_CLOCK_PRESET_HELP #language en-US "Clock preset for the Arm LITTLE cores (Cortex-A55) cluster.\n\nBoot default will retain the frequency set by earlier boot stages.\n\nWARNING! Setting Maximum clock rate is NOT recommended without adequate cooling and power supply." +#string STR_CPU_PERF_CPUL_CLUSTER_CLOCK_CUSTOM_PROMPT #language en-US "CPUL Custom Clock (MHz)" +#string STR_CPU_PERF_CPUL_CLUSTER_CLOCK_CUSTOM_HELP #language en-US "Custom target clock for the Arm LITTLE cores (Cortex-A55) cluster.\n\nNote that the actual frequency will vary with voltage starting from 816 MHz." + +#string STR_CPU_PERF_CPUB01_CLUSTER_CLOCK_PRESET_PROMPT #language en-US "CPUB01 Clock Preset" +#string STR_CPU_PERF_CPUB01_CLUSTER_CLOCK_CUSTOM_PROMPT #language en-US "CPUB01 Custom Clock (MHz)" + +#string STR_CPU_PERF_CPUB23_CLUSTER_CLOCK_PRESET_PROMPT #language en-US "CPUB23 Clock Preset" +#string STR_CPU_PERF_CPUB23_CLUSTER_CLOCK_CUSTOM_PROMPT #language en-US "CPUB23 Custom Clock (MHz)" + +#string STR_CPU_PERF_CPUB_CLUSTER_CLOCK_PRESET_HELP #language en-US "Clock preset for the selected Arm big cores (Cortex-A76) cluster.\n\nBoot default will retain the frequency set by earlier boot stages.\n\nWARNING! Setting Maximum clock rate is NOT recommended without adequate cooling and power supply." +#string STR_CPU_PERF_CPUB_CLUSTER_CLOCK_CUSTOM_HELP #language en-US "Custom target clock for the selected Arm big cores (Cortex-A76) cluster.\n\nNote that the actual frequency will vary with voltage starting from 816 MHz." + +#string STR_CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEF #language en-US "Boot default" +#string STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MIN #language en-US "Minimum" +#string STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MAX #language en-US "Maximum" +#string STR_CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM #language en-US "Custom" + +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_408 #language en-US "408" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_600 #language en-US "600" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_816 #language en-US "816" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1008 #language en-US "1008" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1200 #language en-US "1200" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1416 #language en-US "1416" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1608 #language en-US "1608" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1800 #language en-US "1800" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2016 #language en-US "2016" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2208 #language en-US "2208" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2256 #language en-US "2256" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2304 #language en-US "2304" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2352 #language en-US "2352" +#string STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2400 #language en-US "2400" + +#string STR_CPU_PERF_CLUSTER_VOLTAGES_SUBTITLE #language en-US "Cluster Voltages" + +#string STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_MODE_PROMPT #language en-US "CPUL Voltage Mode" +#string STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_MODE_HELP #language en-US "Voltage mode for the Arm LITTLE cores (Cortex-A55) cluster.\n\n Automatic = voltage is set according to predefined OPP table.\n Custom = voltage is user-controlled, affecting clock rate too due to PVTPLL." +#string STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_CUSTOM_PROMPT #language en-US "CPUL Custom Volt (uV)" +#string STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_CUSTOM_HELP #language en-US "Custom regulator voltage for the Arm LITTLE cores (Cortex-A55) cluster.\n\nUse +/- keys to increment/decrement value by the predefined step.\n\nWARNING! Higher custom voltage may cause system instability and excessive heat." + +#string STR_CPU_PERF_CPUB01_CLUSTER_VOLTAGE_MODE_PROMPT #language en-US "CPUB01 Voltage Mode" +#string STR_CPU_PERF_CPUB01_CLUSTER_VOLTAGE_CUSTOM_PROMPT #language en-US "CPUB01 Custom Volt (uV)" + +#string STR_CPU_PERF_CPUB23_CLUSTER_VOLTAGE_MODE_PROMPT #language en-US "CPUB23 Voltage Mode" +#string STR_CPU_PERF_CPUB23_CLUSTER_VOLTAGE_CUSTOM_PROMPT #language en-US "CPUB23 Custom Volt (uV)" + +#string STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_MODE_HELP #language en-US "Voltage mode for the selected Arm big cores (Cortex-A76) cluster.\n\n Automatic = voltage is set according to predefined OPP table.\n Custom = voltage is user-controlled, affecting clock rate too due to PVTPLL." +#string STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_CUSTOM_HELP #language en-US "Custom regulator voltage for the selected Arm big cores (Cortex-A76) cluster.\n\nUse +/- keys to increment/decrement value by the predefined step.\n\nWARNING! Higher custom voltage may cause system instability and excessive heat." + +#string STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO #language en-US "Automatic" +#string STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM #language en-US "Custom" + +/* + * PCIe/SATA/USB Combo PIPE PHY configuration + */ +#string STR_COMBO_PHY_FORM_TITLE #language en-US "PCIe/SATA/USB Combo PIPE PHY" +#string STR_COMBO_PHY_FORM_HELP #language en-US "Configure the Combo PIPE PHY operation modes." +#string STR_COMBO_PHY_FORM_SUBTITLE #language en-US "Note: the selected mode must match the interface of the connected device." + +#string STR_COMBO_PHY0_MODE_PROMPT #language en-US "PHY #0 Mode" +#string STR_COMBO_PHY1_MODE_PROMPT #language en-US "PHY #1 Mode" +#string STR_COMBO_PHY2_MODE_PROMPT #language en-US "PHY #2 Mode" + +#string STR_COMBO_PHY_MODE_UNCONNECTED #language en-US "Unconnected" +#string STR_COMBO_PHY_MODE_PCIE #language en-US "PCIe 2.1 x1" +#string STR_COMBO_PHY_MODE_SATA #language en-US "SATA 3.1" +#string STR_COMBO_PHY_MODE_USB3 #language en-US "USB 3.1 Gen 1" + +#string STR_COMBO_PHY_MODE_DEFAULT_UNCONNECTED_HELP #language en-US "This PHY may not be wired to any slot or device." +#string STR_COMBO_PHY_MODE_DEFAULT_PCIE_HELP #language en-US "This PHY may be wired to an M.2 or Mini PCIe slot.\n\nConsult your platform's documentation for details on potential alternate modes, such as SATA or USB." +#string STR_COMBO_PHY_MODE_DEFAULT_SATA_HELP #language en-US "This PHY may be wired to a SATA or M.2 slot.\n\nConsult your platform's documentation for details on potential alternate modes, such as PCIe or USB." +#string STR_COMBO_PHY_MODE_DEFAULT_USB3_HELP #language en-US "This PHY is wired to an USB 3.1 Gen 1 Type-A port.\n\nConsult your platform's documentation for details on potential alternate modes, such as PCIe or SATA (via non-standard adapters)." + +/* + * USB/DP Combo PHY configuration + */ +#string STR_USBDP_PHY_FORM_TITLE #language en-US "USB/DP Combo PHY" +#string STR_USBDP_PHY_FORM_HELP #language en-US "Configure the USB/DP Combo PHY operation modes." + +#string STR_USBDP_PHY0_USB3_STATE_PROMPT #language en-US "PHY #0 USB 3 SuperSpeed State" +#string STR_USBDP_PHY1_USB3_STATE_PROMPT #language en-US "PHY #1 USB 3 SuperSpeed State" +#string STR_USBDP_PHY_USB3_STATE_PROMPT #language en-US "Enable or disable SuperSpeed signaling on the selected PHY.\n\nIf USB 3.0 devices connected to the associated Type-C or Type-A port malfunction, disabling this option may help." + +/* + * PCI Express 3.0 configuration + */ +#string STR_PCIE30_FORM_TITLE #language en-US "PCI Express 3.0" +#string STR_PCIE30_FORM_HELP #language en-US "Configure the PCIe 3.0 operation modes." + +#string STR_PCIE30_STATE_PROMPT #language en-US "Support State" +#string STR_PCIE30_STATE_HELP #language en-US "Enable or disable PCIe 3.0 support." + +#string STR_PCIE30_PHY_MODE_PROMPT #language en-US "PHY Mode" +#string STR_PCIE30_PHY_MODE_HELP #language en-US "Choose PHY Mode\n\nx4:\n 4l -> PCIe3 PHY lane 0123\n 2l -> Not connected\n 1l0 -> Combo PHY #1\n 1l1 -> Combo PHY #2\n 1l2 -> Combo PHY #0\n\nx2 x2:\n 4l -> PCIe3 PHY lane 01\n 2l -> PCIe3 PHY lane 23\n 1l0 -> Combo PHY #1\n 1l1 -> Combo PHY #2\n 1l2 -> Combo PHY #0\n\nx1x1 x2:\n 4l -> PCIe3 PHY lane 0\n 2l -> PCIe3 PHY lane 23\n 1l0 -> PCIe3 PHY lane 1\n 1l1 -> Combo PHY #2\n 1l2 -> Combo PHY #0\n\nx2 x1x1:\n 4l -> PCIe3 PHY lane 01\n 2l -> PCIe3 PHY lane 2\n 1l0 -> Combo PHY #1\n 1l1 -> PCIe3 PHY lane 3\n 1l2 -> Combo PHY #0\n\nx1x1 x1x1:\n 4l -> PCIe3 PHY lane 0\n 2l -> PCIe3 PHY lane 2\n 1l0 -> PCIe3 PHY lane 1\n 1l1 -> PCIe3 PHY lane 3\n 1l2 -> Combo PHY #0\n" +#string STR_PCIE30_PHY_MODE_AGGREGATION #language en-US "x4" +#string STR_PCIE30_PHY_MODE_NANBNB #language en-US "x2 x2" +#string STR_PCIE30_PHY_MODE_NANBBI #language en-US "x1x1 x2" +#string STR_PCIE30_PHY_MODE_NABINB #language en-US "x2 x1x1" +#string STR_PCIE30_PHY_MODE_NABIBI #language en-US "x1x1 x1x1" + +/* + * ACPI / Device Tree configuration + */ +#string STR_CONFIG_TABLE_FORM_TITLE #language en-US "ACPI / Device Tree" +#string STR_CONFIG_TABLE_FORM_HELP #language en-US "Configure the ACPI and Device Tree system tables support." + +#string STR_CONFIG_TABLE_MODE_PROMPT #language en-US "Config Table Mode" +#string STR_CONFIG_TABLE_MODE_HELP #language en-US "Choose what config tables to expose to the OS.\n\nACPI - provides basic hardware support (USB, PCIe, SATA) for most OS/kernel versions.\n\nDevice Tree - provides extensive hardware support specific to a kernel version.\nThe firmware includes a DTB compatible with Rockchip SDK Linux 5.10 legacy kernel.\n\nIf both are exposed, the OS will decide which one to use." +#string STR_CONFIG_TABLE_MODE_ACPI #language en-US "ACPI" +#string STR_CONFIG_TABLE_MODE_FDT #language en-US "Device Tree" +#string STR_CONFIG_TABLE_MODE_ACPI_FDT #language en-US "Both" + +#string STR_CONFIG_TABLE_ACPI_SUBTITLE #language en-US "ACPI Configuration" + +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_PROMPT #language en-US "PCIe ECAM Compatibility Mode" +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_HELP #language en-US "Choose how to expose the non-standard PCIe configuration space to the OS.\n\n" + "Single Device - compatible with all OSes. Allows usage of a single or multi-function device. Switches are not supported.\n\n" + "NXPMX6 - compatible with Windows. Exposes the full bus topology and supports switches.\n\n" + "AMAZON GRAVITON - compatible with Linux. Exposes the full bus topology and supports switches.\n\n" + "The Auto modes select NXPMX6 for Windows and fall back to the second option when booting other OSes." +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV #language en-US "Auto (NXPMX6 + Single Device)" +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON #language en-US "Auto (NXPMX6 + AMAZON GRAVITON)" +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV #language en-US "Single Device" +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6 #language en-US "NXPMX6" +#string STR_ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON #language en-US "AMAZON GRAVITON" + +#string STR_CONFIG_TABLE_FDT_SUBTITLE #language en-US "Device Tree Configuration" +#string STR_FDT_SUPPORT_OVERRIDES_PROMPT #language en-US "Support DTB override & overlays" +#string STR_FDT_SUPPORT_OVERRIDES_HELP #language en-US "Enable or disable support for overriding the firmware-provided DTB and installing overlays.\n\nCheck firmware documentation for more details." + +/* + * Cooling fan configuration + */ + +#string STR_COOLING_FAN_FORM_TITLE #language en-US "Cooling Fan" +#string STR_COOLING_FAN_FORM_HELP #language en-US "Configure the on-board cooling fan." + +#string STR_COOLING_FAN_STATE_PROMPT #language en-US "On-board Fan" +#string STR_COOLING_FAN_STATE_HELP #language en-US "Enable or disable the on-board fan output." + +#string STR_COOLING_FAN_SPEED_PROMPT #language en-US "Fan Speed (%)" +#string STR_COOLING_FAN_SPEED_HELP #language en-US "PWM duty cycle of on-board fan output." + +/* + * Debug Serial Port configuration + */ +#string STR_DEBUG_SERIAL_PORT_FORM_TITLE #language en-US "Debug Serial Port" +#string STR_DEBUG_SERIAL_PORT_FORM_HELP #language en-US "Configure the debug (UART) serial port." +#string STR_DEBUG_SERIAL_PORT_SUBTITLE #language en-US "Note: These settings only take effect in UEFI and might be overridden by the OS. Earlier boot messages will be printed at the default settings." + +#string STR_DEBUG_SERIAL_PORT_BAUD_RATE_PROMPT #language en-US "Baud Rate" diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.vfr b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.vfr new file mode 100644 index 0000000..3ce4b4c --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588DxeHii.vfr @@ -0,0 +1,576 @@ +/** @file + * + * Copyright (c) 2018 Andrei Warkentin + * Copyright (c) 2020, ARM Limited. All rights reserved. + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include + +#include "RK3588DxeFormSetGuid.h" + +#define VFR_FILE_INCLUDE +#include "CpuPerformance.h" +#include "FanControl.h" +#include "DebugSerialPort.h" + +// +// EFI Variable attributes +// +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_READ_ONLY 0x00000008 + +formset + guid = RK3588DXE_FORMSET_GUID, + title = STRING_TOKEN(STR_FORM_SET_TITLE), + help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + efivarstore CPU_PERF_CLUSTER_CLOCK_PRESET_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPULClusterClockPreset, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_CLOCK_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPULClusterClockCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_CLOCK_PRESET_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB01ClusterClockPreset, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_CLOCK_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB01ClusterClockCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_CLOCK_PRESET_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB23ClusterClockPreset, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_CLOCK_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB23ClusterClockCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPULClusterVoltageMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPULClusterVoltageCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB01ClusterVoltageMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB01ClusterVoltageCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB23ClusterVoltageMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CPU_PERF_CLUSTER_VOLTAGE_CUSTOM_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CpuPerf_CPUB23ClusterVoltageCustom, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore COMBO_PHY_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = ComboPhy0Mode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore COMBO_PHY_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = ComboPhy1Mode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore COMBO_PHY_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = ComboPhy2Mode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore USBDP_PHY_USB3_STATE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = UsbDpPhy0Usb3State, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore USBDP_PHY_USB3_STATE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = UsbDpPhy1Usb3State, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore PCIE30_STATE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = Pcie30State, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore PCIE30_PHY_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = Pcie30PhyMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore CONFIG_TABLE_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = ConfigTableMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = AcpiPcieEcamCompatMode, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore FDT_SUPPORT_OVERRIDES_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = FdtSupportOverrides, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore COOLING_FAN_STATE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CoolingFanState, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore COOLING_FAN_SPEED_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = CoolingFanSpeed, + guid = RK3588DXE_FORMSET_GUID; + + efivarstore DEBUG_SERIAL_PORT_BAUD_RATE_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = DebugSerialPortBaudRate, + guid = RK3588DXE_FORMSET_GUID; + + form formid = 1, + title = STRING_TOKEN(STR_FORM_SET_TITLE); + subtitle text = STRING_TOKEN(STR_FORM_SET_TITLE_SUBTITLE); + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + goto 0x1000, + prompt = STRING_TOKEN(STR_CPU_PERF_FORM_TITLE), + help = STRING_TOKEN(STR_CPU_PERF_FORM_HELP); + + goto 0x1001, + prompt = STRING_TOKEN(STR_COMBO_PHY_FORM_TITLE), + help = STRING_TOKEN(STR_COMBO_PHY_FORM_HELP); + +#if FixedPcdGetBool (PcdUsbDpPhy0Supported) || FixedPcdGetBool (PcdUsbDpPhy1Supported) + goto 0x1002, + prompt = STRING_TOKEN(STR_USBDP_PHY_FORM_TITLE), + help = STRING_TOKEN(STR_USBDP_PHY_FORM_HELP); +#endif + +#if FixedPcdGetBool (PcdPcie30Supported) + goto 0x1003, + prompt = STRING_TOKEN(STR_PCIE30_FORM_TITLE), + help = STRING_TOKEN(STR_PCIE30_FORM_HELP); +#endif + + goto 0x1004, + prompt = STRING_TOKEN(STR_CONFIG_TABLE_FORM_TITLE), + help = STRING_TOKEN(STR_CONFIG_TABLE_FORM_HELP); + +#if FixedPcdGetBool (PcdHasOnBoardFanOutput) + goto 0x1005, + prompt = STRING_TOKEN(STR_COOLING_FAN_FORM_TITLE), + help = STRING_TOKEN(STR_COOLING_FAN_FORM_HELP); +#endif + + goto 0x1006, + prompt = STRING_TOKEN(STR_DEBUG_SERIAL_PORT_FORM_TITLE), + help = STRING_TOKEN(STR_DEBUG_SERIAL_PORT_FORM_HELP); + endform; + + form formid = 0x1000, + title = STRING_TOKEN(STR_CPU_PERF_FORM_TITLE); + subtitle text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCKS_SUBTITLE); + + oneof varid = CpuPerf_CPULClusterClockPreset.Preset, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_CLOCK_PRESET_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_CLOCK_PRESET_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdCPULClusterClockPresetDefault), + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEF), value = CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MIN), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MIN, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MAX), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MAX, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM), value = CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPULClusterClockPreset.Preset == CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM; + oneof varid = CpuPerf_CPULClusterClockCustom.Mhz, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_CLOCK_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_CLOCK_CUSTOM_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_408), value = 408, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_600), value = 600, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_816), value = 816, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1008), value = 1008, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1200), value = 1200, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1416), value = 1416, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1608), value = 1608, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1800), value = 1800, flags = DEFAULT; + endoneof; + endif; + + oneof varid = CpuPerf_CPUB01ClusterClockPreset.Preset, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB01_CLUSTER_CLOCK_PRESET_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_CLOCK_PRESET_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdCPUB01ClusterClockPresetDefault), + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEF), value = CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MIN), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MIN, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MAX), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MAX, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM), value = CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPUB01ClusterClockPreset.Preset == CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM; + oneof varid = CpuPerf_CPUB01ClusterClockCustom.Mhz, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB01_CLUSTER_CLOCK_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_CLOCK_CUSTOM_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_408), value = 408, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_600), value = 600, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_816), value = 816, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1008), value = 1008, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1200), value = 1200, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1416), value = 1416, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1608), value = 1608, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1800), value = 1800, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2016), value = 2016, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2208), value = 2208, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2256), value = 2256, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2304), value = 2304, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2352), value = 2352, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2400), value = 2400, flags = DEFAULT; + endoneof; + endif; + + oneof varid = CpuPerf_CPUB23ClusterClockPreset.Preset, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB23_CLUSTER_CLOCK_PRESET_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_CLOCK_PRESET_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdCPUB23ClusterClockPresetDefault), + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEF), value = CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MIN), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MIN, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_MAX), value = CPU_PERF_CLUSTER_CLOCK_PRESET_MAX, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM), value = CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPUB23ClusterClockPreset.Preset == CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM; + oneof varid = CpuPerf_CPUB23ClusterClockCustom.Mhz, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB23_CLUSTER_CLOCK_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_CLOCK_CUSTOM_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_408), value = 408, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_600), value = 600, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_816), value = 816, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1008), value = 1008, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1200), value = 1200, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1416), value = 1416, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1608), value = 1608, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_1800), value = 1800, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2016), value = 2016, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2208), value = 2208, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2256), value = 2256, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2304), value = 2304, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2352), value = 2352, flags = 0; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_CLOCK_CUSTOM_2400), value = 2400, flags = DEFAULT; + endoneof; + endif; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGES_SUBTITLE); + + oneof varid = CpuPerf_CPULClusterVoltageMode.Mode, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_MODE_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_MODE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPULClusterVoltageMode.Mode == CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM; + numeric varid = CpuPerf_CPULClusterVoltageCustom.Microvolts, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUL_CLUSTER_VOLTAGE_CUSTOM_HELP), + flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + minimum = CLUSTER_MICROVOLTS_MIN, + maximum = CLUSTER_MICROVOLTS_MAX, + step = CLUSTER_MICROVOLTS_STEP, + default = CPUL_CLUSTER_MICROVOLTS_DEFAULT, + endnumeric; + endif; + + oneof varid = CpuPerf_CPUB01ClusterVoltageMode.Mode, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB01_CLUSTER_VOLTAGE_MODE_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_MODE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPUB01ClusterVoltageMode.Mode == CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM; + numeric varid = CpuPerf_CPUB01ClusterVoltageCustom.Microvolts, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB01_CLUSTER_VOLTAGE_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_CUSTOM_HELP), + flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + minimum = CLUSTER_MICROVOLTS_MIN, + maximum = CLUSTER_MICROVOLTS_MAX, + step = CLUSTER_MICROVOLTS_STEP, + default = CPUB_CLUSTER_MICROVOLTS_DEFAULT, + endnumeric; + endif; + + oneof varid = CpuPerf_CPUB23ClusterVoltageMode.Mode, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB23_CLUSTER_VOLTAGE_MODE_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_MODE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO, flags = DEFAULT; + option text = STRING_TOKEN(STR_CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM), value = CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM, flags = 0; + endoneof; + + grayoutif NOT ideqval CpuPerf_CPUB23ClusterVoltageMode.Mode == CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM; + numeric varid = CpuPerf_CPUB23ClusterVoltageCustom.Microvolts, + prompt = STRING_TOKEN(STR_CPU_PERF_CPUB23_CLUSTER_VOLTAGE_CUSTOM_PROMPT), + help = STRING_TOKEN(STR_CPU_PERF_CPUB_CLUSTER_VOLTAGE_CUSTOM_HELP), + flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + minimum = CLUSTER_MICROVOLTS_MIN, + maximum = CLUSTER_MICROVOLTS_MAX, + step = CLUSTER_MICROVOLTS_STEP, + default = CPUB_CLUSTER_MICROVOLTS_DEFAULT, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_CPU_PERF_FORM_SUBTITLE); + endform; + + form formid = 0x1001, + title = STRING_TOKEN(STR_COMBO_PHY_FORM_TITLE); + + grayoutif FixedPcdGetBool (PcdComboPhy0Switchable) == 0; + oneof varid = ComboPhy0Mode.Mode, + prompt = STRING_TOKEN(STR_COMBO_PHY0_MODE_PROMPT), +#if FixedPcdGet32 (PcdComboPhy0ModeDefault) == COMBO_PHY_MODE_PCIE + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_PCIE_HELP), +#elif FixedPcdGet32 (PcdComboPhy0ModeDefault) == COMBO_PHY_MODE_SATA + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_SATA_HELP), +#elif FixedPcdGet32 (PcdComboPhy0ModeDefault) == COMBO_PHY_MODE_USB3 + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_USB3_HELP), +#else + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_UNCONNECTED_HELP), +#endif + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdComboPhy0ModeDefault), + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_UNCONNECTED), value = COMBO_PHY_MODE_UNCONNECTED, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_PCIE), value = COMBO_PHY_MODE_PCIE, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_SATA), value = COMBO_PHY_MODE_SATA, flags = 0; + endoneof; + endif; + + grayoutif FixedPcdGetBool (PcdComboPhy1Switchable) == 0; + oneof varid = ComboPhy1Mode.Mode, + prompt = STRING_TOKEN(STR_COMBO_PHY1_MODE_PROMPT), +#if FixedPcdGet32 (PcdComboPhy1ModeDefault) == COMBO_PHY_MODE_PCIE + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_PCIE_HELP), +#elif FixedPcdGet32 (PcdComboPhy1ModeDefault) == COMBO_PHY_MODE_SATA + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_SATA_HELP), +#elif FixedPcdGet32 (PcdComboPhy1ModeDefault) == COMBO_PHY_MODE_USB3 + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_USB3_HELP), +#else + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_UNCONNECTED_HELP), +#endif + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdComboPhy1ModeDefault), + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_UNCONNECTED), value = COMBO_PHY_MODE_UNCONNECTED, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_PCIE), value = COMBO_PHY_MODE_PCIE, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_SATA), value = COMBO_PHY_MODE_SATA, flags = 0; + endoneof; + endif; + + grayoutif FixedPcdGetBool (PcdComboPhy2Switchable) == 0; + oneof varid = ComboPhy2Mode.Mode, + prompt = STRING_TOKEN(STR_COMBO_PHY2_MODE_PROMPT), +#if FixedPcdGet32 (PcdComboPhy2ModeDefault) == COMBO_PHY_MODE_PCIE + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_PCIE_HELP), +#elif FixedPcdGet32 (PcdComboPhy2ModeDefault) == COMBO_PHY_MODE_SATA + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_SATA_HELP), +#elif FixedPcdGet32 (PcdComboPhy2ModeDefault) == COMBO_PHY_MODE_USB3 + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_USB3_HELP), +#else + help = STRING_TOKEN(STR_COMBO_PHY_MODE_DEFAULT_UNCONNECTED_HELP), +#endif + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdComboPhy2ModeDefault), + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_UNCONNECTED), value = COMBO_PHY_MODE_UNCONNECTED, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_PCIE), value = COMBO_PHY_MODE_PCIE, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_SATA), value = COMBO_PHY_MODE_SATA, flags = 0; + option text = STRING_TOKEN(STR_COMBO_PHY_MODE_USB3), value = COMBO_PHY_MODE_USB3, flags = 0; + endoneof; + endif; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_COMBO_PHY_FORM_SUBTITLE); + endform; + + form formid = 0x1002, + title = STRING_TOKEN(STR_USBDP_PHY_FORM_TITLE); + +#if FixedPcdGetBool (PcdUsbDpPhy0Supported) + oneof varid = UsbDpPhy0Usb3State.State, + prompt = STRING_TOKEN(STR_USBDP_PHY0_USB3_STATE_PROMPT), + help = STRING_TOKEN(STR_USBDP_PHY_USB3_STATE_PROMPT), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = USBDP_PHY_USB3_STATE_ENABLED, + option text = STRING_TOKEN(STR_ENABLED), value = USBDP_PHY_USB3_STATE_ENABLED, flags = 0; + option text = STRING_TOKEN(STR_DISABLED), value = USBDP_PHY_USB3_STATE_DISABLED, flags = 0; + endoneof; +#endif + +#if FixedPcdGetBool (PcdUsbDpPhy1Supported) + oneof varid = UsbDpPhy1Usb3State.State, + prompt = STRING_TOKEN(STR_USBDP_PHY1_USB3_STATE_PROMPT), + help = STRING_TOKEN(STR_USBDP_PHY_USB3_STATE_PROMPT), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = USBDP_PHY_USB3_STATE_ENABLED, + option text = STRING_TOKEN(STR_ENABLED), value = USBDP_PHY_USB3_STATE_ENABLED, flags = 0; + option text = STRING_TOKEN(STR_DISABLED), value = USBDP_PHY_USB3_STATE_DISABLED, flags = 0; + endoneof; +#endif + endform; + +#if FixedPcdGetBool (PcdPcie30Supported) + form formid = 0x1003, + title = STRING_TOKEN(STR_PCIE30_FORM_TITLE); + + oneof varid = Pcie30State.State, + prompt = STRING_TOKEN(STR_PCIE30_STATE_PROMPT), + help = STRING_TOKEN(STR_PCIE30_STATE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = PCIE30_STATE_ENABLED, + option text = STRING_TOKEN(STR_DISABLED), value = PCIE30_STATE_DISABLED, flags = 0; + option text = STRING_TOKEN(STR_ENABLED), value = PCIE30_STATE_ENABLED, flags = 0; + endoneof; + + /* shoule we move this to single PHY settings form */ + oneof varid = Pcie30PhyMode.Mode, + prompt = STRING_TOKEN(STR_PCIE30_PHY_MODE_PROMPT), + help = STRING_TOKEN(STR_PCIE30_PHY_MODE_HELP), + flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet8 (PcdPcie30PhyModeDefault), + option text = STRING_TOKEN(STR_PCIE30_PHY_MODE_AGGREGATION), value = PCIE30_PHY_MODE_AGGREGATION, flags = 0; + option text = STRING_TOKEN(STR_PCIE30_PHY_MODE_NANBNB), value = PCIE30_PHY_MODE_NANBNB, flags = 0; + option text = STRING_TOKEN(STR_PCIE30_PHY_MODE_NANBBI), value = PCIE30_PHY_MODE_NANBBI, flags = 0; + option text = STRING_TOKEN(STR_PCIE30_PHY_MODE_NABINB), value = PCIE30_PHY_MODE_NABINB, flags = 0; + option text = STRING_TOKEN(STR_PCIE30_PHY_MODE_NABIBI), value = PCIE30_PHY_MODE_NABIBI, flags = 0; + endoneof; + endform; +#endif + + form formid = 0x1004, + title = STRING_TOKEN(STR_CONFIG_TABLE_FORM_TITLE); + + oneof varid = ConfigTableMode.Mode, + prompt = STRING_TOKEN(STR_CONFIG_TABLE_MODE_PROMPT), + help = STRING_TOKEN(STR_CONFIG_TABLE_MODE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = CONFIG_TABLE_MODE_ACPI, + option text = STRING_TOKEN(STR_CONFIG_TABLE_MODE_ACPI), value = CONFIG_TABLE_MODE_ACPI, flags = 0; + option text = STRING_TOKEN(STR_CONFIG_TABLE_MODE_FDT), value = CONFIG_TABLE_MODE_FDT, flags = 0; + option text = STRING_TOKEN(STR_CONFIG_TABLE_MODE_ACPI_FDT), value = CONFIG_TABLE_MODE_ACPI_FDT, flags = 0; + endoneof; + + suppressif (get(ConfigTableMode.Mode) & CONFIG_TABLE_MODE_ACPI) == 0; + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_CONFIG_TABLE_ACPI_SUBTITLE); + + oneof varid = AcpiPcieEcamCompatMode.Mode, + prompt = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_PROMPT), + help = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_HELP), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = FixedPcdGet32 (PcdAcpiPcieEcamCompatModeDefault), + option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV, flags = 0; + option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON, flags = 0; + option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV), value = ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV, flags = 0; + option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6), value = ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6, flags = 0; + option text = STRING_TOKEN(STR_ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON), value = ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON, flags = 0; + endoneof; + endif; + + suppressif (get(ConfigTableMode.Mode) & CONFIG_TABLE_MODE_FDT) == 0; + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_CONFIG_TABLE_FDT_SUBTITLE); + + oneof varid = FdtSupportOverrides.State, + prompt = STRING_TOKEN(STR_FDT_SUPPORT_OVERRIDES_PROMPT), + help = STRING_TOKEN(STR_FDT_SUPPORT_OVERRIDES_HELP), + flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED, + default = FALSE, + option text = STRING_TOKEN(STR_DISABLED), value = FALSE, flags = 0; + option text = STRING_TOKEN(STR_ENABLED), value = TRUE, flags = 0; + endoneof; + endif; + endform; + +#if FixedPcdGetBool (PcdHasOnBoardFanOutput) + form formid = 0x1005, + title = STRING_TOKEN(STR_COOLING_FAN_FORM_TITLE); + + oneof varid = CoolingFanState.State, + prompt = STRING_TOKEN(STR_COOLING_FAN_STATE_PROMPT), + help = STRING_TOKEN(STR_COOLING_FAN_STATE_PROMPT), + flags = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + default = COOLING_FAN_STATE_ENABLED, + option text = STRING_TOKEN(STR_DISABLED), value = COOLING_FAN_STATE_DISABLED, flags = 0; + option text = STRING_TOKEN(STR_ENABLED), value = COOLING_FAN_STATE_ENABLED, flags = 0; + endoneof; + + grayoutif NOT ideqval CoolingFanState.State == COOLING_FAN_STATE_ENABLED; + numeric varid = CoolingFanSpeed.Percentage, + prompt = STRING_TOKEN(STR_COOLING_FAN_SPEED_PROMPT), + help = STRING_TOKEN(STR_COOLING_FAN_SPEED_PROMPT), + flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED, + minimum = FAN_PERCENTAGE_MIN, + maximum = FAN_PERCENTAGE_MAX, + step = FAN_PERCENTAGE_STEP, + default = FAN_PERCENTAGE_DEFAULT, + endnumeric; + endif; + endform; +#endif + + form formid = 0x1006, + title = STRING_TOKEN(STR_DEBUG_SERIAL_PORT_FORM_TITLE); + + numeric varid = DebugSerialPortBaudRate.Value, + prompt = STRING_TOKEN(STR_DEBUG_SERIAL_PORT_BAUD_RATE_PROMPT), + help = STRING_TOKEN(STR_NULL_STRING), + flags = DISPLAY_UINT_DEC | NUMERIC_SIZE_8 | INTERACTIVE | RESET_REQUIRED, + minimum = DEBUG_SERIAL_PORT_BAUD_RATE_MIN, + maximum = DEBUG_SERIAL_PORT_BAUD_RATE_MAX, + step = 0, + default = DEBUG_SERIAL_PORT_BAUD_RATE_DEFAULT, + endnumeric; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + subtitle text = STRING_TOKEN(STR_DEBUG_SERIAL_PORT_SUBTITLE); + endform; + +endformset; diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.c new file mode 100644 index 0000000..b2cb799 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.c @@ -0,0 +1,52 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include + +#include "RK3588DxeFormSetGuid.h" +#include "UsbDpPhy.h" + +VOID +EFIAPI +ApplyUsbDpPhyVariables ( + VOID + ) +{ + /* nothing to do here, the PCDs are read by UsbDpPhyDxe */ +} + +VOID +EFIAPI +SetupUsbDpPhyVariables ( + VOID + ) +{ + UINTN Size; + UINT32 Var32; + EFI_STATUS Status; + + Size = sizeof (UINT32); + + Status = gRT->GetVariable (L"UsbDpPhy0Usb3State", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdUsbDpPhy0Usb3State, USBDP_PHY_USB3_STATE_ENABLED); + ASSERT_EFI_ERROR (Status); + } + + Status = gRT->GetVariable (L"UsbDpPhy1Usb3State", + &gRK3588DxeFormSetGuid, + NULL, &Size, &Var32); + if (EFI_ERROR (Status)) { + Status = PcdSet32S (PcdUsbDpPhy1Usb3State, USBDP_PHY_USB3_STATE_ENABLED); + ASSERT_EFI_ERROR (Status); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.h new file mode 100644 index 0000000..7ae4364 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/UsbDpPhy.h @@ -0,0 +1,29 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588DXE_USBDP_PHY_H__ +#define __RK3588DXE_USBDP_PHY_H__ + +// +// Don't declare these in the VFR file. +// +#ifndef VFR_FILE_INCLUDE +VOID +EFIAPI +ApplyUsbDpPhyVariables ( + VOID + ); + +VOID +EFIAPI +SetupUsbDpPhyVariables ( + VOID + ); +#endif // VFR_FILE_INCLUDE + +#endif // __RK3588DXE_USBDP_PHY_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhy.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhy.h new file mode 100644 index 0000000..733bccc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhy.h @@ -0,0 +1,79 @@ +/** @file + * + * Rockchip USBDP Combo PHY with Samsung IP block driver + * + * U-Boot file: include/linux/usb/phy-rockchip-usbdp.h + * + * Copyright (C) 2021 Rockchip Electronics Co., Ltd + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This code can be relicensed as BSD-2-Clause-Patent if permission + * is granted by the original authors. + * + **/ + +#ifndef __PHY_ROCKCHIP_USBDP_H_ +#define __PHY_ROCKCHIP_USBDP_H_ + +#include "uboot-env.h" + +/* RK3588 USBDP PHY Register Definitions */ + +#define UDPHY_PCS 0x4000 +#define UDPHY_PMA 0x8000 + +/* VO0 GRF Registers */ +#define RK3588_GRF_VO0_CON0 0x0000 +#define RK3588_GRF_VO0_CON2 0x0008 +#define DP_SINK_HPD_CFG BIT(11) +#define DP_SINK_HPD_SEL BIT(10) +#define DP_AUX_DIN_SEL BIT(9) +#define DP_AUX_DOUT_SEL BIT(8) +#define DP_LANE_SEL_N(n) GENMASK(2 * (n) + 1, 2 * (n)) +#define DP_LANE_SEL_ALL GENMASK(7, 0) +#define PHY_AUX_DP_DATA_POL_NORMAL 0 +#define PHY_AUX_DP_DATA_POL_INVERT 1 + +/* PMA CMN Registers */ +#define CMN_LANE_MUX_AND_EN_OFFSET 0x0288 /* cmn_reg00A2 */ +#define CMN_DP_LANE_MUX_N(n) BIT((n) + 4) +#define CMN_DP_LANE_EN_N(n) BIT(n) +#define CMN_DP_LANE_MUX_ALL GENMASK(7, 4) +#define CMN_DP_LANE_EN_ALL GENMASK(3, 0) +#define PHY_LANE_MUX_USB 0 +#define PHY_LANE_MUX_DP 1 + +#define CMN_DP_LINK_OFFSET 0x28c /*cmn_reg00A3 */ +#define CMN_DP_TX_LINK_BW GENMASK(6, 5) +#define CMN_DP_TX_LANE_SWAP_EN BIT(2) + +#define CMN_SSC_EN_OFFSET 0x2d0 /* cmn_reg00B4 */ +#define CMN_ROPLL_SSC_EN BIT(1) +#define CMN_LCPLL_SSC_EN BIT(0) + +#define CMN_ANA_LCPLL_DONE_OFFSET 0x0350 /* cmn_reg00D4 */ +#define CMN_ANA_LCPLL_LOCK_DONE BIT(7) +#define CMN_ANA_LCPLL_AFC_DONE BIT(6) + +#define CMN_ANA_ROPLL_DONE_OFFSET 0x0354 /* cmn_reg00D5 */ +#define CMN_ANA_ROPLL_LOCK_DONE BIT(1) +#define CMN_ANA_ROPLL_AFC_DONE BIT(0) + +#define CMN_DP_RSTN_OFFSET 0x038c /* cmn_reg00E3 */ +#define CMN_DP_INIT_RSTN BIT(3) +#define CMN_DP_CMN_RSTN BIT(2) +#define CMN_CDR_WTCHDG_EN BIT(1) +#define CMN_CDR_WTCHDG_MSK_CDR_EN BIT(0) + +#define TRSV_ANA_TX_CLK_OFFSET_N(n) (0x854 + (n) * 0x800) /* trsv_reg0215 */ +#define LN_ANA_TX_SER_TXCLK_INV BIT(1) + +#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET 0x0b84 /* trsv_reg02E1 */ +#define TRSV_LN0_MON_RX_CDR_LOCK_DONE BIT(0) + +#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET 0x1b84 /* trsv_reg06E1 */ +#define TRSV_LN2_MON_RX_CDR_LOCK_DONE BIT(0) + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.c new file mode 100644 index 0000000..81d0ed9 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.c @@ -0,0 +1,1253 @@ +/** @file + * + * Rockchip USBDP Combo PHY with Samsung IP block driver + * + * This was ported from U-Boot upstream/downstream. It currently lacks: + * - lane orientation flip binding, exposed via a protocol to the TCPM driver. + * + * After all features are merged in and tested, the code should ideally + * be refactored to meet EDK II conventions. + * + * U-Boot file: drivers/phy/rockchip/phy-rockchip-usbdp.c + * + * Copyright (C) 2021 Rockchip Electronics Co., Ltd + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This code can be relicensed as BSD-2-Clause-Patent if permission + * is granted by the original authors. + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uboot-env.h" + +#include "UsbDpPhy.h" + +#define BIT_WRITEABLE_SHIFT 16 + +enum { + DP_BW_RBR, + DP_BW_HBR, + DP_BW_HBR2, + DP_BW_HBR3, +}; + +enum { + UDPHY_MODE_NONE = 0, + UDPHY_MODE_USB = BIT(0), + UDPHY_MODE_DP = BIT(1), + UDPHY_MODE_DP_USB = BIT(1) | BIT(0), +}; + +struct udphy_grf_reg { + unsigned int offset; + unsigned int bitend; + unsigned int bitstart; + unsigned int disable; + unsigned int enable; +}; + +/** + * struct reg_sequence - An individual write from a sequence of writes. + * + * @reg: Register address. + * @def: Register value. + * @delay_us: Delay to be applied after the register write in microseconds + * + * Register/value pairs for sequences of writes with an optional delay in + * microseconds to be applied after each write. + */ +struct reg_sequence { + unsigned int reg; + unsigned int def; + unsigned int delay_us; +}; + +struct udphy_grf_cfg { + /* u2phy-grf */ + struct udphy_grf_reg bvalid_phy_con; + struct udphy_grf_reg bvalid_grf_con; + + /* usb-grf */ + struct udphy_grf_reg usb3otg0_cfg; + struct udphy_grf_reg usb3otg1_cfg; + + /* usbdpphy-grf */ + struct udphy_grf_reg low_pwrn; + struct udphy_grf_reg rx_lfps; +}; + +struct dp_tx_drv_ctrl { + u32 trsv_reg0204; + u32 trsv_reg0205; + u32 trsv_reg0206; + u32 trsv_reg0207; +}; + +struct rockchip_udphy; + +struct rockchip_udphy_cfg { + struct udphy_grf_cfg grfcfg; + const struct dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; + int (*combophy_init)(struct rockchip_udphy *udphy); + int (*dp_phy_set_rate)(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp); + int (*dp_phy_set_voltages)(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp); + int (*dplane_enable)(struct rockchip_udphy *udphy, int dp_lanes); + int (*dplane_select)(struct rockchip_udphy *udphy); +}; + +struct cru_reset_reg { + unsigned int offset; + unsigned int bit; +}; + +struct rockchip_udphy { + UINT32 Signature; + EFI_HANDLE Handle; + DP_PHY_PROTOCOL DpPhyProtocol; + + UINTN pma_regmap; + UINTN u2phygrf; + UINTN udphygrf; + UINTN usbgrf; + UINTN vogrf; + + /* clocks and rests */ + struct cru_reset_reg rst_init; + struct cru_reset_reg rst_cmn; + struct cru_reset_reg rst_lane; + struct cru_reset_reg rst_pcs_apb; + struct cru_reset_reg rst_pma_apb; + + /* PHY status management */ + bool flip; + bool mode_change; + u8 mode; + u8 status; + + /* utilized for USB */ + bool hs; /* flag for high-speed */ + + /* utilized for DP */ + //struct gpio_desc *sbu1_dc_gpio; + //struct gpio_desc *sbu2_dc_gpio; + u32 lane_mux_sel[4]; + u32 dp_lane_sel[4]; + u32 dp_aux_dout_sel; + u32 dp_aux_din_sel; + u32 max_link_rate; + u8 bw; /* dp bandwidth */ + int id; + + /* PHY const config */ + const struct rockchip_udphy_cfg *cfgs; +}; + +#define UDPHY_SIGNATURE SIGNATURE_32 ('U', 'D', 'P', 'Y') + +#define ROCKCHIP_UDPHY_FROM_DP_PHY_PROTOCOL(a) CR (a, struct rockchip_udphy, DpPhyProtocol, UDPHY_SIGNATURE) + +static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x20, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x29, 0x18, 0x42, 0xe5 }, + { 0x2b, 0x1c, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x23, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x29, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x2a, 0x19, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x28, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x29, 0x18, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x18, 0x43, 0xe7 }, + { 0x2b, 0x1b, 0x43, 0xe7 } + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x18, 0x43, 0xe7 } + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct reg_sequence rk3588_udphy_24m_refclk_cfg[] = { + {0x0090, 0x68}, {0x0094, 0x68}, + {0x0128, 0x24}, {0x012c, 0x44}, + {0x0130, 0x3f}, {0x0134, 0x44}, + {0x015c, 0xa9}, {0x0160, 0x71}, + {0x0164, 0x71}, {0x0168, 0xa9}, + {0x0174, 0xa9}, {0x0178, 0x71}, + {0x017c, 0x71}, {0x0180, 0xa9}, + {0x018c, 0x41}, {0x0190, 0x00}, + {0x0194, 0x05}, {0x01ac, 0x2a}, + {0x01b0, 0x17}, {0x01b4, 0x17}, + {0x01b8, 0x2a}, {0x01c8, 0x04}, + {0x01cc, 0x08}, {0x01d0, 0x08}, + {0x01d4, 0x04}, {0x01d8, 0x20}, + {0x01dc, 0x01}, {0x01e0, 0x09}, + {0x01e4, 0x03}, {0x01f0, 0x29}, + {0x01f4, 0x02}, {0x01f8, 0x02}, + {0x01fc, 0x29}, {0x0208, 0x2a}, + {0x020c, 0x17}, {0x0210, 0x17}, + {0x0214, 0x2a}, {0x0224, 0x20}, + {0x03f0, 0x0d}, {0x03f4, 0x09}, + {0x03f8, 0x09}, {0x03fc, 0x0d}, + {0x0404, 0x0e}, {0x0408, 0x14}, + {0x040c, 0x14}, {0x0410, 0x3b}, + {0x0ce0, 0x68}, {0x0ce8, 0xd0}, + {0x0cf0, 0x87}, {0x0cf8, 0x70}, + {0x0d00, 0x70}, {0x0d08, 0xa9}, + {0x1ce0, 0x68}, {0x1ce8, 0xd0}, + {0x1cf0, 0x87}, {0x1cf8, 0x70}, + {0x1d00, 0x70}, {0x1d08, 0xa9}, + {0x0a3c, 0xd0}, {0x0a44, 0xd0}, + {0x0a48, 0x01}, {0x0a4c, 0x0d}, + {0x0a54, 0xe0}, {0x0a5c, 0xe0}, + {0x0a64, 0xa8}, {0x1a3c, 0xd0}, + {0x1a44, 0xd0}, {0x1a48, 0x01}, + {0x1a4c, 0x0d}, {0x1a54, 0xe0}, + {0x1a5c, 0xe0}, {0x1a64, 0xa8} +}; + +static const struct reg_sequence rk3588_udphy_init_sequence[] = { + {0x0104, 0x44}, {0x0234, 0xE8}, + {0x0248, 0x44}, {0x028C, 0x18}, + {0x081C, 0xE5}, {0x0878, 0x00}, + {0x0994, 0x1C}, {0x0AF0, 0x00}, + {0x181C, 0xE5}, {0x1878, 0x00}, + {0x1994, 0x1C}, {0x1AF0, 0x00}, + {0x0428, 0x60}, {0x0D58, 0x33}, + {0x1D58, 0x33}, {0x0990, 0x74}, + {0x0D64, 0x17}, {0x08C8, 0x13}, + {0x1990, 0x74}, {0x1D64, 0x17}, + {0x18C8, 0x13}, {0x0D90, 0x40}, + {0x0DA8, 0x40}, {0x0DC0, 0x40}, + {0x0DD8, 0x40}, {0x1D90, 0x40}, + {0x1DA8, 0x40}, {0x1DC0, 0x40}, + {0x1DD8, 0x40}, {0x03C0, 0x30}, + {0x03C4, 0x06}, {0x0E10, 0x00}, + {0x1E10, 0x00}, {0x043C, 0x0F}, + {0x0D2C, 0xFF}, {0x1D2C, 0xFF}, + {0x0D34, 0x0F}, {0x1D34, 0x0F}, + {0x08FC, 0x2A}, {0x0914, 0x28}, + {0x0A30, 0x03}, {0x0E38, 0x05}, + {0x0ECC, 0x27}, {0x0ED0, 0x22}, + {0x0ED4, 0x26}, {0x18FC, 0x2A}, + {0x1914, 0x28}, {0x1A30, 0x03}, + {0x1E38, 0x05}, {0x1ECC, 0x27}, + {0x1ED0, 0x22}, {0x1ED4, 0x26}, + {0x0048, 0x0F}, {0x0060, 0x3C}, + {0x0064, 0xF7}, {0x006C, 0x20}, + {0x0070, 0x7D}, {0x0074, 0x68}, + {0x0AF4, 0x1A}, {0x1AF4, 0x1A}, + {0x0440, 0x3F}, {0x10D4, 0x08}, + {0x20D4, 0x08}, {0x00D4, 0x30}, + {0x0024, 0x6e}, +}; + +static inline int grfreg_write(UINTN base, + const struct udphy_grf_reg *reg, bool en) +{ + u32 val, mask, tmp; + + tmp = en ? reg->enable : reg->disable; + mask = GENMASK(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); + + return regmap_write(base, reg->offset, val); +} + +static int __regmap_multi_reg_write(UINTN map, + const struct reg_sequence *regs, + int num_regs) +{ + int i, ret = 0; + + for (i = 0; i < num_regs; i++) { + ret = regmap_write(map, regs[i].reg, regs[i].def); + + if (regs[i].delay_us) + udelay(regs[i].delay_us); + } + + return ret; +} + +static int udphy_clk_init(struct rockchip_udphy *udphy) +{ + return 0; +} + +static int udphy_reset(struct cru_reset_reg *reset, BOOLEAN assert) +{ + struct udphy_grf_reg grf; + grf.offset = reset->offset; + grf.bitend = reset->bit; + grf.bitstart = reset->bit; + grf.disable = 0; + grf.enable = 1; + + return grfreg_write(CRU_BASE, &grf, assert); +} + +static int udphy_reset_assert(struct cru_reset_reg *reset) +{ + return udphy_reset(reset, TRUE); +} + +static int udphy_reset_deassert(struct cru_reset_reg *reset) +{ + return udphy_reset(reset, FALSE); +} + +static int udphy_reset_init(struct rockchip_udphy *udphy) +{ + udphy_reset_assert (&udphy->rst_init); + udphy_reset_assert (&udphy->rst_cmn); + udphy_reset_assert (&udphy->rst_lane); + udphy_reset_assert (&udphy->rst_pcs_apb); + udphy_reset_assert (&udphy->rst_pma_apb); + + return 0; +} + +static void udphy_u3_port_disable(struct rockchip_udphy *udphy, u8 disable) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + const struct udphy_grf_reg *preg; + + preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; + grfreg_write(udphy->usbgrf, preg, disable); +} + +__maybe_unused +static void udphy_usb_bvalid_enable(struct rockchip_udphy *udphy, u8 enable) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + + grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); + grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); +} + +/* + * In usb/dp combo phy driver, here are 2 ways to mapping lanes. + * + * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) + * --------------------------------------------------------------------------- + * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 + * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * C/E(Normal) dpln3 dpln2 dpln0 dpln1 + * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 + * D/F(Normal) usbrx usbtx dpln0 dpln1 + * D/F(Flip ) dpln0 dpln1 usbrx usbtx + * A(Normal ) dpln3 dpln1 dpln2 dpln0 + * A(Flip ) dpln2 dpln0 dpln3 dpln1 + * B(Normal ) usbrx usbtx dpln1 dpln0 + * B(Flip ) dpln1 dpln0 usbrx usbtx + * --------------------------------------------------------------------------- + * + * 2 Mapping the lanes in dtsi + * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = ; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 + * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 + * --------------------------------------------------------------------------- + * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = ; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1> dpln0 dpln1 usbrx usbtx + * <2 3> usbrx usbtx dpln0 dpln1 + * --------------------------------------------------------------------------- + */ +static int udphy_dplane_select(struct rockchip_udphy *udphy) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + + if (cfg->dplane_select) + return cfg->dplane_select(udphy); + + return 0; +} + +static int udphy_dplane_get(struct rockchip_udphy *udphy) +{ + int dp_lanes; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + dp_lanes = 4; + break; + case UDPHY_MODE_DP_USB: + dp_lanes = 2; + break; + case UDPHY_MODE_USB: + /* fallthrough; */ + default: + dp_lanes = 0; + break; + } + + return dp_lanes; +} + +static int udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + int ret = 0; + + if (cfg->dplane_enable) + ret = cfg->dplane_enable(udphy, dp_lanes); + + return ret; +} + +__maybe_unused +static int upphy_set_typec_default_mapping(struct rockchip_udphy *udphy) +{ + if (udphy->flip) { + udphy->dp_lane_sel[0] = 0; + udphy->dp_lane_sel[1] = 1; + udphy->dp_lane_sel[2] = 3; + udphy->dp_lane_sel[3] = 2; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; + } else { + udphy->dp_lane_sel[0] = 2; + udphy->dp_lane_sel[1] = 3; + udphy->dp_lane_sel[2] = 1; + udphy->dp_lane_sel[3] = 0; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; + } + + udphy->mode = UDPHY_MODE_DP_USB; + + return 0; +} + +static int udphy_setup(struct rockchip_udphy *udphy) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + int ret = 0; + + if (cfg->combophy_init) { + ret = cfg->combophy_init(udphy); + if (ret) + dev_err(udphy->dev, "failed to init usbdp combophy\n"); + } + + return ret; +} + +static int udphy_disable(struct rockchip_udphy *udphy) +{ + udphy_reset_assert (&udphy->rst_init); + udphy_reset_assert (&udphy->rst_cmn); + udphy_reset_assert (&udphy->rst_lane); + udphy_reset_assert (&udphy->rst_pcs_apb); + udphy_reset_assert (&udphy->rst_pma_apb); + + return 0; +} + +static int udphy_parse_lane_mux_data(struct rockchip_udphy *udphy, UINT8 *prop, UINTN num_lanes) +{ + int ret, i; + + if (!prop) { + dev_dbg(udphy->dev, + "failed to find dp lane mux, following dp alt mode\n"); + udphy->mode = UDPHY_MODE_USB; + return 0; + } + + if (num_lanes != 2 && num_lanes != 4) { + dev_err(udphy->dev, "invalid number of lane mux\n"); + return -EINVAL; + } + + for (i = 0; i < num_lanes; i++) { + udphy->dp_lane_sel[i] = prop[i]; + } + + for (i = 0; i < num_lanes; i++) { + int j; + + if (udphy->dp_lane_sel[i] > 3) { + dev_err(udphy->dev, + "lane mux between 0 and 3, exceeding the range\n"); + return -EINVAL; + } + + udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; + + for (j = i + 1; j < num_lanes; j++) { + if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) { + dev_err(udphy->dev, + "set repeat lane mux value\n"); + return -EINVAL; + } + } + } + + udphy->mode = UDPHY_MODE_DP; + if (num_lanes == 2) { + udphy->mode |= UDPHY_MODE_USB; + udphy->flip = udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP ? true : false; + } + + return 0; +} + +static int udphy_power_on(struct rockchip_udphy *udphy, u8 mode) +{ + int ret; + + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); + return 0; + } + + if (udphy->status == UDPHY_MODE_NONE) { + udphy->mode_change = false; + ret = udphy_setup(udphy); + if (ret) + return ret; + + if (udphy->mode & UDPHY_MODE_USB) + udphy_u3_port_disable(udphy, false); + } else if (udphy->mode_change) { + udphy->mode_change = false; + udphy->status = UDPHY_MODE_NONE; + if (udphy->mode == UDPHY_MODE_DP) + udphy_u3_port_disable(udphy, true); + + ret = udphy_disable(udphy); + if (ret) + return ret; + ret = udphy_setup(udphy); + if (ret) + return ret; + } + + udphy->status |= mode; + + return 0; +} + +static int udphy_power_off(struct rockchip_udphy *udphy, u8 mode) +{ + int ret; + + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not supported\n", mode); + return 0; + } + + if (!udphy->status) + return 0; + + udphy->status &= ~mode; + + if (udphy->status == UDPHY_MODE_NONE) { + ret = udphy_disable(udphy); + if (ret) + return ret; + } + + return 0; +} + +static int rockchip_dpphy_power_on(struct rockchip_udphy *udphy) +{ + int ret, dp_lanes; + + dp_lanes = udphy_dplane_get(udphy); + udphy->DpPhyProtocol.Capabilities.BusWidth = dp_lanes; + udphy->DpPhyProtocol.Capabilities.MaximumLinkRate = udphy->max_link_rate; + + ret = udphy_power_on(udphy, UDPHY_MODE_DP); + if (ret) + return ret; + + ret = udphy_dplane_enable(udphy, dp_lanes); + if (ret) + return ret; + + return udphy_dplane_select(udphy); +} + +static int rockchip_dpphy_power_off(struct rockchip_udphy *udphy) +{ + int ret; + + ret = udphy_dplane_enable(udphy, 0); + if (ret) + return ret; + + return udphy_power_off(udphy, UDPHY_MODE_DP); +} + +static int rockchip_dpphy_verify_config(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp) +{ + int i; + + /* If changing link rate was required, verify it's supported. */ + if (dp->SetLinkRateAndSpreadSpectrum) { + switch (dp->LinkRate) { + case 1620: + case 2700: + case 5400: + case 8100: + /* valid bit rate */ + break; + default: + return -EINVAL; + } + } + + /* Verify lane count. */ + switch (dp->LaneCount) { + case 1: + case 2: + case 4: + /* valid lane count. */ + break; + default: + return -EINVAL; + } + + /* + * If changing voltages is required, check swing and pre-emphasis + * levels, per-lane. + */ + if (dp->SetVoltageSwingAndPreEmphasisLevels) { + /* Lane count verified previously. */ + for (i = 0; i < dp->LaneCount; i++) { + if (dp->LaneVoltageSwingLevels[i] > 3 || dp->LanePreEmphasisLevels[i] > 3) + return -EINVAL; + + /* + * Sum of voltage swing and pre-emphasis levels cannot + * exceed 3. + */ + if (dp->LaneVoltageSwingLevels[i] + dp->LanePreEmphasisLevels[i] > 3) + return -EINVAL; + } + } + + return 0; +} + +static int rockchip_dpphy_configure(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + int ret; + + ret = rockchip_dpphy_verify_config(udphy, dp); + if (ret) + return ret; + + if (dp->SetLinkRateAndSpreadSpectrum && cfg->dp_phy_set_rate) { + ret = cfg->dp_phy_set_rate(udphy, dp); + if (ret) { + dev_err(udphy->dev, "rockchip_hdptx_phy_set_rate failed\n"); + return ret; + } + } + + if (dp->SetVoltageSwingAndPreEmphasisLevels && cfg->dp_phy_set_voltages) { + ret = cfg->dp_phy_set_voltages(udphy, dp); + if (ret) { + dev_err(udphy->dev, "rockchip_dp_phy_set_voltages failed\n"); + return ret; + } + } + + return 0; +} + +static int rockchip_u3phy_init(struct rockchip_udphy *udphy) +{ + /* DP only or high-speed, disable U3 port */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { + udphy_u3_port_disable(udphy, true); + return 0; + } + + return udphy_power_on(udphy, UDPHY_MODE_USB); +} + +static int rockchip_u3phy_exit(struct rockchip_udphy *udphy) +{ + /* DP only or high-speed */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) + return 0; + + return udphy_power_off(udphy, UDPHY_MODE_USB); +} + +static int rk3588_udphy_refclk_set(struct rockchip_udphy *udphy) +{ + /* configure phy reference clock */ + return __regmap_multi_reg_write(udphy->pma_regmap, + rk3588_udphy_24m_refclk_cfg, + ARRAY_SIZE(rk3588_udphy_24m_refclk_cfg)); +} + +static int rk3588_udphy_status_check(struct rockchip_udphy *udphy) +{ + unsigned int val; + int ret; + + if (!(udphy->mode & UDPHY_MODE_USB)) + return 0; + + /* LCPLL check */ + ret = regmap_read_poll_timeout(udphy->pma_regmap, + CMN_ANA_LCPLL_DONE_OFFSET, + val, (val & CMN_ANA_LCPLL_AFC_DONE) && + (val & CMN_ANA_LCPLL_LOCK_DONE), + 200, 100); + if (ret) { + dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); + return ret; + } + + if (!udphy->flip) { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN0_MON_RX_CDR_DONE_OFFSET, + val, + val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, + 200, 100); + if (ret) + dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); + } else { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN2_MON_RX_CDR_DONE_OFFSET, + val, + val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, + 200, 100); + if (ret) + dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); + } + + return 0; +} + +static int rk3588_udphy_init(struct rockchip_udphy *udphy) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + int ret; + + /* enable rx lfps for usb */ + if (udphy->mode & UDPHY_MODE_USB) + grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); + + /* Step 1: power on pma and deassert apb rstn */ + grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); + + udphy_reset_deassert(&udphy->rst_pma_apb); + udphy_reset_deassert(&udphy->rst_pcs_apb); + + /* Step 2: set init sequence and phy refclk */ + ret = __regmap_multi_reg_write(udphy->pma_regmap, + rk3588_udphy_init_sequence, + ARRAY_SIZE(rk3588_udphy_init_sequence)); + if (ret) { + dev_err(udphy->dev, "init sequence set error %d\n", ret); + goto assert_apb; + } + + ret = rk3588_udphy_refclk_set(udphy); + if (ret) { + dev_err(udphy->dev, "refclk set error %d\n", ret); + goto assert_apb; + } + + /* Step 3: configure lane mux */ + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, + CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_MUX_N(3), + udphy->lane_mux_sel[3]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(2), + udphy->lane_mux_sel[2]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(1), + udphy->lane_mux_sel[1]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(0), + udphy->lane_mux_sel[0]) | + FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); + + /* Step 4: deassert init rstn and wait for 200ns from datasheet */ + if (udphy->mode & UDPHY_MODE_USB) + udphy_reset_deassert(&udphy->rst_init); + + if (udphy->mode & UDPHY_MODE_DP) { + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_INIT_RSTN, + FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); + } + + udelay(1); + + /* Step 5: deassert cmn/lane rstn */ + if (udphy->mode & UDPHY_MODE_USB) { + udphy_reset_deassert(&udphy->rst_cmn); + udphy_reset_deassert(&udphy->rst_lane); + } + + /* Step 6: wait for lock done of pll */ + ret = rk3588_udphy_status_check(udphy); + if (ret) + goto assert_phy; + + return 0; + +assert_phy: + udphy_reset_assert(&udphy->rst_init); + udphy_reset_assert(&udphy->rst_cmn); + udphy_reset_assert(&udphy->rst_lane); + +assert_apb: + udphy_reset_assert(&udphy->rst_pma_apb); + udphy_reset_assert(&udphy->rst_pcs_apb); + + return ret; +} + +static int rk3588_udphy_dplane_enable(struct rockchip_udphy *udphy, int dp_lanes) +{ + int i; + u32 val = 0; + + for (i = 0; i < dp_lanes; i++) + val |= BIT(udphy->dp_lane_sel[i]); + + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); + + if (!dp_lanes) + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); + + return 0; +} + +static int rk3588_udphy_dplane_select(struct rockchip_udphy *udphy) +{ + u32 value = 0; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + value |= 2 << udphy->dp_lane_sel[2] * 2; + value |= 3 << udphy->dp_lane_sel[3] * 2; + case UDPHY_MODE_DP_USB: + value |= 0 << udphy->dp_lane_sel[0] * 2; + value |= 1 << udphy->dp_lane_sel[1] * 2; + break; + case UDPHY_MODE_USB: + break; + default: + break; + } + + regmap_write(udphy->vogrf, udphy->id ? RK3588_GRF_VO0_CON2 : RK3588_GRF_VO0_CON0, + ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | + FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | + FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); + + return 0; +} + +static int rk3588_dp_phy_set_rate(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp) +{ + u32 val; + int ret; + + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); + + switch (dp->LinkRate) { + case 1620: + udphy->bw = DP_BW_RBR; + break; + case 2700: + udphy->bw = DP_BW_HBR; + break; + case 5400: + udphy->bw = DP_BW_HBR2; + break; + case 8100: + udphy->bw = DP_BW_HBR3; + break; + default: + return -EINVAL; + } + + regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, + FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); + regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, + FIELD_PREP(CMN_ROPLL_SSC_EN, dp->EnableSpreadSpectrum)); + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, + FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); + + ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, + FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && + FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), + 0, 1000); + if (ret) { + printf("ROPLL is not lock\n"); + return ret; + } + + return 0; +} + +static void rk3588_dp_phy_set_voltage(struct rockchip_udphy *udphy, u8 bw, + u32 voltage, u32 pre, u32 lane) +{ + u32 offset = 0x800 * lane; + u32 val; + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + const struct dp_tx_drv_ctrl (*dp_ctrl)[4]; + + dp_ctrl = cfg->dp_tx_ctrl_cfg[bw]; + val = dp_ctrl[voltage][pre].trsv_reg0204; + regmap_write(udphy->pma_regmap, 0x0810 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0205; + regmap_write(udphy->pma_regmap, 0x0814 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0206; + regmap_write(udphy->pma_regmap, 0x0818 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0207; + regmap_write(udphy->pma_regmap, 0x081c + offset, val); +} + +static int rk3588_dp_phy_set_voltages(struct rockchip_udphy *udphy, + DP_PHY_CONFIGURATION *dp) +{ + u32 i, lane; + + for (i = 0; i < dp->LaneCount; i++) { + lane = udphy->dp_lane_sel[i]; + switch (dp->LinkRate) { + case 1620: + case 2700: + regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, + udphy->lane_mux_sel[lane])); + break; + case 5400: + case 8100: + regmap_update_bits(udphy->pma_regmap, TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); + break; + } + + rk3588_dp_phy_set_voltage(udphy, udphy->bw, dp->LaneVoltageSwingLevels[i], dp->LanePreEmphasisLevels[i], lane); + } + + return 0; +} + +EFI_STATUS +EFIAPI +DpPhyPowerOn ( + IN DP_PHY_PROTOCOL *This + ) +{ + struct rockchip_udphy *udphy; + int ret; + + udphy = ROCKCHIP_UDPHY_FROM_DP_PHY_PROTOCOL (This); + + ret = rockchip_dpphy_power_on (udphy); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DpPhyPowerOff ( + IN DP_PHY_PROTOCOL *This + ) +{ + struct rockchip_udphy *udphy; + int ret; + + udphy = ROCKCHIP_UDPHY_FROM_DP_PHY_PROTOCOL (This); + + ret = rockchip_dpphy_power_off (udphy); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DpPhyConfigure ( + IN DP_PHY_PROTOCOL *This, + IN DP_PHY_CONFIGURATION *Configuration + ) +{ + struct rockchip_udphy *udphy; + int ret; + + udphy = ROCKCHIP_UDPHY_FROM_DP_PHY_PROTOCOL (This); + + ret = rockchip_dpphy_configure (udphy, Configuration); + if (ret) + return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; +} + +EFI_STATUS +UsbDpPhySetup ( + IN struct rockchip_udphy *UdPhy, + IN UINT8 *DpLaneMux, + IN UINTN DpNumLanes, + IN UINT32 Usb3State + ) +{ + EFI_STATUS Status; + int ret = 0; + + // treat default byte array definition as NULL + if (DpNumLanes == 1 && DpLaneMux[0] == 0) { + DpLaneMux = NULL; + } + + UdPhy->hs = Usb3State == USBDP_PHY_USB3_STATE_DISABLED; + + ret = udphy_parse_lane_mux_data(UdPhy, DpLaneMux, DpNumLanes); + if (ret) { + DEBUG ((DEBUG_ERROR, "%a: udphy_parse_lane_mux_data errno %d\n", __func__, ret)); + return EFI_INVALID_PARAMETER; + } + ret = udphy_clk_init(UdPhy); + if (ret) { + DEBUG ((DEBUG_ERROR, "%a: udphy_clk_init errno %d\n", __func__, ret)); + return EFI_DEVICE_ERROR; + } + ret = udphy_reset_init(UdPhy); + if (ret) { + DEBUG ((DEBUG_ERROR, "%a: udphy_reset_init errno %d\n", __func__, ret)); + return EFI_DEVICE_ERROR; + } + ret = rockchip_u3phy_init (UdPhy); + if (ret) { + DEBUG ((DEBUG_ERROR, "%a: rockchip_u3phy_init errno %d\n", __func__, ret)); + return EFI_DEVICE_ERROR; + } + + if (UdPhy->mode & UDPHY_MODE_DP) { + UdPhy->Signature = UDPHY_SIGNATURE; + UdPhy->DpPhyProtocol.PowerOn = DpPhyPowerOn; + UdPhy->DpPhyProtocol.PowerOff = DpPhyPowerOff; + UdPhy->DpPhyProtocol.Configure = DpPhyConfigure; + UdPhy->DpPhyProtocol.Id = UdPhy->id; + + Status = gBS->InstallMultipleProtocolInterfaces (&UdPhy->Handle, + &gDpPhyProtocolGuid, &UdPhy->DpPhyProtocol, + NULL); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to install DP PHY protocol. Status=%r\n", + __func__, Status)); + return Status; + } + } + + return EFI_SUCCESS; +} + +static const struct rockchip_udphy_cfg rk3588_udphy_cfgs = { + .grfcfg = { + /* u2phy-grf */ + .bvalid_phy_con = { 0x0008, 1, 0, 0x2, 0x3 }, + .bvalid_grf_con = { 0x0010, 3, 2, 0x2, 0x3 }, + + /* usb-grf */ + .usb3otg0_cfg = { 0x001c, 15, 0, 0x1100, 0x0188 }, + .usb3otg1_cfg = { 0x0034, 15, 0, 0x1100, 0x0188 }, + + /* usbdpphy-grf */ + .low_pwrn = { 0x0004, 13, 13, 0, 1 }, + .rx_lfps = { 0x0004, 14, 14, 0, 1 }, + }, + .dp_tx_ctrl_cfg = { + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, + .combophy_init = rk3588_udphy_init, + .dp_phy_set_rate = rk3588_dp_phy_set_rate, + .dp_phy_set_voltages = rk3588_dp_phy_set_voltages, + .dplane_enable = rk3588_udphy_dplane_enable, + .dplane_select = rk3588_udphy_dplane_select, +}; + +static struct rockchip_udphy usbdp_phy[] = { + { + .pma_regmap = 0xfed80000 + UDPHY_PMA, + .u2phygrf = 0xfd5d0000, + .udphygrf = 0xfd5c8000, + .usbgrf = 0xfd5ac000, + .vogrf = 0xfd5a6000, + + .rst_init = { 0xA08, 8 }, + .rst_cmn = { 0xA08, 9 }, + .rst_lane = { 0xA08, 10 }, + .rst_pcs_apb = { 0xA08, 11 }, + .rst_pma_apb = { 0xB20, 2 }, + + .max_link_rate = 8100, + + .id = 0, + + .cfgs = &rk3588_udphy_cfgs, + }, + { + .pma_regmap = 0xfed90000 + UDPHY_PMA, + .u2phygrf = 0xfd5d4000, + .udphygrf = 0xfd5cc000, + .usbgrf = 0xfd5ac000, + .vogrf = 0xfd5a6000, + + .rst_init = { 0xA08, 15 }, + .rst_cmn = { 0xA0C, 0 }, + .rst_lane = { 0xA0C, 1 }, + .rst_pcs_apb = { 0xA0C, 2 }, + .rst_pma_apb = { 0xB20, 4 }, + + .max_link_rate = 8100, + + .id = 1, + + .cfgs = &rk3588_udphy_cfgs, + }, +}; + +EFI_STATUS +EFIAPI +UsbDpPhyDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (PcdGetBool (PcdUsbDpPhy0Supported)) { + UsbDpPhySetup (&usbdp_phy[0], + PcdGetPtr (PcdDp0LaneMux), + PcdGetSize (PcdDp0LaneMux), + PcdGet32 (PcdUsbDpPhy0Usb3State) + ); + } + + if (PcdGetBool (PcdUsbDpPhy1Supported)) { + UsbDpPhySetup (&usbdp_phy[1], + PcdGetPtr (PcdDp1LaneMux), + PcdGetSize (PcdDp1LaneMux), + PcdGet32 (PcdUsbDpPhy1Usb3State) + ); + } + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf new file mode 100644 index 0000000..82fc1bc --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf @@ -0,0 +1,48 @@ +#/** @file +# +# Rockchip USB/DP Combo PHY Driver +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = UsbDpPhyDxe + FILE_GUID = 6fbd6b56-e302-4560-85f4-0e78fb731922 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UsbDpPhyDxeInitialize + +[Sources.common] + UsbDpPhyDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + IoLib + TimerLib + RockchipPlatformLib + +[Protocols] + gDpPhyProtocolGuid ## PRODUCES + +[Pcd] + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported + gRK3588TokenSpaceGuid.PcdDp0LaneMux + gRK3588TokenSpaceGuid.PcdDp1LaneMux + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Usb3State + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Usb3State + +[Depex] + gRockchipPlatformConfigAppliedProtocolGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/errno.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/errno.h new file mode 100644 index 0000000..3767df3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/errno.h @@ -0,0 +1,168 @@ +#ifndef _LINUX_ERRNO_H +#define _LINUX_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ + +#define ENOSYS 38 /* Invalid system call number */ + +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + +#define ERFKILL 132 /* Operation not possible due to RF-kill */ + +#define EHWPOISON 133 /* Memory page has hardware error */ + +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 /* restart if no handler.. */ +#define ENOIOCTLCMD 515 /* No ioctl command */ +#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */ +#define EPROBE_DEFER 517 /* Driver requests probe retry */ +#define EOPENSTALE 518 /* open found a stale dentry */ + +/* Defined for the NFSv3 protocol */ +#define EBADHANDLE 521 /* Illegal NFS file handle */ +#define ENOTSYNC 522 /* Update synchronization mismatch */ +#define EBADCOOKIE 523 /* Cookie is stale */ +#define ENOTSUPP 524 /* Operation is not supported */ +#define ETOOSMALL 525 /* Buffer or request is too small */ +#define ESERVERFAULT 526 /* An untranslatable error occurred */ +#define EBADTYPE 527 /* Type not supported by server */ +#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ +#define EIOCBQUEUED 529 /* iocb queued, will get completion event */ +#define ERECALLCONFLICT 530 /* conflict with recalled state */ + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/uboot-env.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/uboot-env.h new file mode 100644 index 0000000..c8b26e0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/uboot-env.h @@ -0,0 +1,85 @@ +#ifndef _UBOOT_ENV_H +#define _UBOOT_ENV_H + +#include "errno.h" + +#define __maybe_unused + +typedef UINT8 u8; +typedef UINT32 u32; +typedef UINT64 u64; +typedef unsigned int uint; +typedef UINTN ulong; +typedef BOOLEAN bool; + +#define true TRUE +#define false FALSE + +#define udelay(x) MicroSecondDelay (x) + +#define dev_err(dev, args...) DEBUG ((DEBUG_ERROR, args)) +#define dev_info(dev, args...) DEBUG ((DEBUG_INFO, args)) +#define dev_dbg(dev, args...) DEBUG ((DEBUG_INFO, args)) +#define printf(args...) DEBUG ((DEBUG_INFO, args)) + +#define BITS_PER_LONG (sizeof(UINTN) * 8) +#define GENMASK(h, l) \ + (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +#define BIT(x) (1 << (x)) + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define FIELD_PREP(_mask, _val) \ + ({ \ + ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + }) + +#define FIELD_GET(_mask, _reg) \ + ({ \ + (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + }) + +#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, \ + timeout_ms) \ +({ \ + int __ret; \ + for (;;) { \ + __ret = regmap_read((map), (addr), &(val)); \ + if (__ret) \ + break; \ + if (cond) \ + break; \ + if ((sleep_us)) \ + udelay((sleep_us)); \ + } \ + __ret ?: ((cond) ? 0 : -ETIMEDOUT); \ +}) + +static inline int regmap_write(UINTN map, uint offset, uint val) +{ + MmioWrite32 (map + offset, val); + return 0; +} + +static inline int regmap_read(UINTN map, uint offset, uint *valp) +{ + *valp = MmioRead32 (map + offset); + return 0; +} + +static inline int regmap_update_bits(UINTN map, uint offset, uint mask, uint val) +{ + uint reg; + int ret; + + ret = regmap_read(map, offset, ®); + if (ret) + return ret; + + reg &= ~mask; + + return regmap_write(map, offset, reg | (val & mask)); +} + +#endif // _UBOOT_ENV_H diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/AcpiTables.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/AcpiTables.h new file mode 100644 index 0000000..b525f89 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/AcpiTables.h @@ -0,0 +1,126 @@ +/** @file + * + * RK3588 defines for constructing ACPI tables + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2020, Pete Batard + * Copyright (c) 2019, ARM Ltd. All rights reserved. + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __ACPITABLES_H__ +#define __ACPITABLES_H__ + +#include +#include +#include +#include + +#define EFI_ACPI_OEM_ID {'R','K','C','P',' ',' '} + +#define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64 ('R','K','3','5','8','8',' ',' ') + +#define EFI_ACPI_OEM_REVISION 0x00000000 +#define EFI_ACPI_CREATOR_ID SIGNATURE_32 ('E','D','K','2') +#define EFI_ACPI_CREATOR_REVISION 0x00000000 +#define EFI_ACPI_VENDOR_ID SIGNATURE_32 ('R','K','C','P') + +// A macro to initialise the common header part of EFI ACPI tables as defined by +// EFI_ACPI_DESCRIPTION_HEADER structure. +#define ACPI_HEADER(Signature, Type, Revision) { \ + Signature, /* UINT32 Signature */ \ + sizeof (Type), /* UINT32 Length */ \ + Revision, /* UINT8 Revision */ \ + 0, /* UINT8 Checksum */ \ + EFI_ACPI_OEM_ID, /* UINT8 OemId[6] */ \ + EFI_ACPI_OEM_TABLE_ID, /* UINT64 OemTableId */ \ + EFI_ACPI_OEM_REVISION, /* UINT32 OemRevision */ \ + EFI_ACPI_CREATOR_ID, /* UINT32 CreatorId */ \ + EFI_ACPI_CREATOR_REVISION /* UINT32 CreatorRevision */ \ + } + +#define EFI_ACPI_6_0_GIC_REDISTRIBUTOR_INIT(RedisRegionAddr, RedisDiscLength) \ + { \ + EFI_ACPI_6_0_GICR, \ + sizeof (EFI_ACPI_6_0_GICR_STRUCTURE), \ + 0, \ + RedisRegionAddr, \ + RedisDiscLength \ + } + +#define EFI_ACPI_6_0_GIC_ITS_FRAME_INIT(Id, PhysAddress) \ + { \ + EFI_ACPI_6_0_GIC_ITS, \ + sizeof (EFI_ACPI_6_0_GIC_ITS_STRUCTURE), \ + 0, \ + Id, \ + PhysAddress, \ + 0 \ + } + +// +// Device resource helpers +// +#define QWORDMEMORY_BUF(Index, ResourceType) \ + QWordMemory (ResourceType,, \ + MinFixed, MaxFixed, NonCacheable, ReadWrite, \ + 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index) + +#define QWORDIO_BUF(Index, ResourceType) \ + QWordIO (ResourceType, \ + MinFixed, MaxFixed, PosDecode, EntireRange, \ + 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index) + +#define DWORDMEMORY_BUF(Index, ResourceType) \ + DWordMemory (ResourceType,, \ + MinFixed, MaxFixed, NonCacheable, ReadWrite, \ + 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index) + +#define WORDBUSNUMBER_BUF(Index, ResourceType) \ + WordBusNumber (ResourceType, \ + MinFixed, MaxFixed, PosDecode, \ + 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index) + +#define QWORD_SET(Index, Minimum, Length, Translation) \ + CreateQWordField (RBUF, RB ## Index._MIN, MI ## Index) \ + CreateQWordField (RBUF, RB ## Index._MAX, MA ## Index) \ + CreateQWordField (RBUF, RB ## Index._TRA, TR ## Index) \ + CreateQWordField (RBUF, RB ## Index._LEN, LE ## Index) \ + LE ## Index = Length \ + MI ## Index = Minimum \ + TR ## Index = Translation \ + MA ## Index = MI ## Index + LE ## Index - 1 + +#define DWORD_SET(Index, Minimum, Length, Translation) \ + CreateDWordField (RBUF, RB ## Index._MIN, MI ## Index) \ + CreateDWordField (RBUF, RB ## Index._MAX, MA ## Index) \ + CreateDWordField (RBUF, RB ## Index._TRA, TR ## Index) \ + CreateDWordField (RBUF, RB ## Index._LEN, LE ## Index) \ + LE ## Index = Length \ + MI ## Index = Minimum \ + TR ## Index = Translation \ + MA ## Index = MI ## Index + LE ## Index - 1 + +#define WORD_SET(Index, Minimum, Length, Translation) \ + CreateWordField (RBUF, RB ## Index._MIN, MI ## Index) \ + CreateWordField (RBUF, RB ## Index._MAX, MA ## Index) \ + CreateWordField (RBUF, RB ## Index._TRA, TR ## Index) \ + CreateWordField (RBUF, RB ## Index._LEN, LE ## Index) \ + LE ## Index = Length \ + MI ## Index = Minimum \ + TR ## Index = Translation \ + MA ## Index = MI ## Index + LE ## Index - 1 + +#pragma pack(push, 1) +typedef struct { + EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER Header; + EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE MainEntries[NUM_PCIE_CONTROLLER]; + EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE RootPortEntries[NUM_PCIE_CONTROLLER]; +} RK3588_MCFG_TABLE; +#pragma pack(pop) + +#endif // __ACPITABLES_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/GpioLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/GpioLib.h new file mode 100644 index 0000000..e82a947 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/GpioLib.h @@ -0,0 +1,143 @@ +/** @file + * + * Copyright (c) 2021, Jared McNeill + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef GPIOLIB_H__ +#define GPIOLIB_H__ + +#define GPIO_PIN_PA0 0 +#define GPIO_PIN_PA1 1 +#define GPIO_PIN_PA2 2 +#define GPIO_PIN_PA3 3 +#define GPIO_PIN_PA4 4 +#define GPIO_PIN_PA5 5 +#define GPIO_PIN_PA6 6 +#define GPIO_PIN_PA7 7 +#define GPIO_PIN_PB0 8 +#define GPIO_PIN_PB1 9 +#define GPIO_PIN_PB2 10 +#define GPIO_PIN_PB3 11 +#define GPIO_PIN_PB4 12 +#define GPIO_PIN_PB5 13 +#define GPIO_PIN_PB6 14 +#define GPIO_PIN_PB7 15 +#define GPIO_PIN_PC0 16 +#define GPIO_PIN_PC1 17 +#define GPIO_PIN_PC2 18 +#define GPIO_PIN_PC3 19 +#define GPIO_PIN_PC4 20 +#define GPIO_PIN_PC5 21 +#define GPIO_PIN_PC6 22 +#define GPIO_PIN_PC7 23 +#define GPIO_PIN_PD0 24 +#define GPIO_PIN_PD1 25 +#define GPIO_PIN_PD2 26 +#define GPIO_PIN_PD3 27 +#define GPIO_PIN_PD4 28 +#define GPIO_PIN_PD5 29 +#define GPIO_PIN_PD6 30 +#define GPIO_PIN_PD7 31 + +typedef enum { + GPIO_PIN_INPUT = 0, + GPIO_PIN_OUTPUT = 1 +} GPIO_PIN_DIRECTION; + +typedef enum { + GPIO_PIN_PULL_NONE = 0, + GPIO_PIN_PULL_UP = 1, + GPIO_PIN_PULL_DOWN = 2 +} GPIO_PIN_PULL; + +typedef enum { + GPIO_PIN_DRIVE_DEFAULT = 0xFF, + GPIO_PIN_DRIVE_DISABLE = 0x0, + GPIO_PIN_DRIVE_0 = 0x1, + GPIO_PIN_DRIVE_1 = 0x3, + GPIO_PIN_DRIVE_2 = 0x7, + GPIO_PIN_DRIVE_3 = 0xF, + GPIO_PIN_DRIVE_4 = 0x1F, + GPIO_PIN_DRIVE_5 = 0x3F +} GPIO_PIN_DRIVE; + +typedef enum { + GPIO_PIN_INPUT_DEFAULT = 0xFF, + GPIO_PIN_INPUT_DISABLE = 0x0, + GPIO_PIN_INPUT_NON_SCHMITT = 0x1, + GPIO_PIN_INPUT_SCHMITT = 0x2 +} GPIO_PIN_INPUT_ENABLE; + +typedef struct { + CONST char *Name; + UINT8 Group; + UINT8 Pin; + UINT8 Function; + GPIO_PIN_PULL Pull; + GPIO_PIN_DRIVE Drive; +} GPIO_IOMUX_CONFIG; + +VOID +GpioPinSetDirection ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_DIRECTION Direction + ); + +VOID +GpioPinWrite ( + IN UINT8 Group, + IN UINT8 Pin, + IN BOOLEAN Value + ); + +BOOLEAN +GpioPinRead ( + IN UINT8 Group, + IN UINT8 Pin + ); + +BOOLEAN +GpioPinReadActual ( + IN UINT8 Group, + IN UINT8 Pin + ); + +VOID +GpioPinSetFunction ( + IN UINT8 Group, + IN UINT8 Pin, + IN UINT8 Function + ); + +VOID +GpioPinSetPull ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_PULL Pull + ); + +VOID +GpioPinSetDrive ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_DRIVE Drive + ); + +VOID +GpioPinSetInput ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_INPUT_ENABLE InputEnable + ); + +VOID +GpioSetIomuxConfig ( + IN CONST GPIO_IOMUX_CONFIG *Configs, + IN UINT32 NumConfigs + ); + +#endif /* GPIOLIB_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Pcie30PhyLib.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Pcie30PhyLib.h new file mode 100755 index 0000000..4370afe --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Pcie30PhyLib.h @@ -0,0 +1,17 @@ +/** @file + * + * Copyright (c) 2023, Jared McNeill + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef PCIE30PHYLIB_H__ +#define PCIE30PHYLIB_H__ + +EFI_STATUS +Pcie30PhyInit ( + VOID + ); + +#endif /* PCIE30PHYLIB_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Mem.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Mem.h new file mode 100644 index 0000000..fe14133 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Mem.h @@ -0,0 +1,28 @@ +/** @file + * + * Copyright (c) 2021, Andrey Warkentin + * Copyright (c) 2019, Pete Batard + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef RK3588_MEM_H__ +#define RK3588_MEM_H__ + +#define RK3588_MEM_UNMAPPED_REGION 0 +#define RK3588_MEM_BASIC_REGION 1 +#define RK3588_MEM_RUNTIME_REGION 2 +#define RK3588_MEM_RESERVED_REGION 3 + +typedef struct { + CONST CHAR16* Name; + UINTN Type; +} RK3588_MEMORY_REGION_INFO; + +VOID +Rk3588PlatformGetVirtualMemoryInfo ( + IN RK3588_MEMORY_REGION_INFO** MemoryInfo + ); + +#endif /* RK3588_MEM_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Pcie.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Pcie.h new file mode 100644 index 0000000..52b9aad --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Library/Rk3588Pcie.h @@ -0,0 +1,67 @@ +/** @file +* +* Copyright (c) 2023, Molly Sophia +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef RK3588PCIE_H +#define RK3588PCIE_H + +BOOLEAN +IsPcieNumEnabled( + UINTN PcieNum + ); + +VOID +PciePinmuxInit( + UINTN PcieNum, + UINTN MuxNum + ); + +// +// PCIe 3x4 is the first PCIe controller in memory, the others +// immediately follow it in the order of the segments below. +// + +#define NUM_PCIE_CONTROLLER 5 + +/* + * All pcie controllers supports PCIe 3.0 + * Here we name them using their device tree name in the linux kernel source + */ +#define PCIE_SEGMENT_PCIE30X4 0 +#define PCIE_SEGMENT_PCIE30X2 1 +#define PCIE_SEGMENT_PCIE20L0 2 +#define PCIE_SEGMENT_PCIE20L1 3 +#define PCIE_SEGMENT_PCIE20L2 4 + +#define PCIE_3X4_APB_BASE 0xfe150000 +#define PCIE_3X4_DBI_BASE 0xa40000000ULL +#define PCIE_3X4_CFG_BASE 0x900000000ULL +#define PCIE_3X4_MEM_BASE 0xf0000000 + +#define PCIE_APB_SIZE SIZE_64KB +#define PCIE_DBI_SIZE SIZE_4MB +#define PCIE_CFG_SIZE SIZE_1GB +#define PCIE_MEM_SIZE SIZE_16MB + +#define PCIE_MEM64_OFFSET 0x10000000ULL + +#define PCIE_APB_BASE(Segment) (PCIE_3X4_APB_BASE + (Segment * PCIE_APB_SIZE)) +#define PCIE_DBI_BASE(Segment) (PCIE_3X4_DBI_BASE + (Segment * 1ULL * PCIE_DBI_SIZE)) +#define PCIE_CFG_BASE(Segment) (PCIE_3X4_CFG_BASE + (Segment * 1ULL * PCIE_CFG_SIZE)) + +#define PCIE_MEM_BASE(Segment) (PCIE_3X4_MEM_BASE + (Segment * PCIE_MEM_SIZE)) +#define PCIE_MEM64_BASE(Segment) (PCIE_CFG_BASE(Segment) + PCIE_MEM64_OFFSET) + +#define PCIE_IO_BASE 0x0000 +#define PCIE_IO_SIZE SIZE_64KB +#define PCIE_IO_XLATE(Segment) (PCIE_CFG_BASE(Segment) + PCIE_CFG_SIZE - PCIE_IO_SIZE) + +#define PCIE_MEM64_SIZE (PCIE_CFG_SIZE - PCIE_IO_SIZE - PCIE_MEM64_OFFSET) + +#define PCIE_BUS_LIMIT 252 // limited by CFG1 iATU window size + +#endif diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588.h new file mode 100644 index 0000000..1bcf6cb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588.h @@ -0,0 +1,5519 @@ +#ifndef __RK3588_H +#define __RK3588_H +#ifdef __cplusplus + extern "C" { +#endif +/****************************************************************************************/ +/* */ +/* Module Structure Section */ +/* */ +/****************************************************************************************/ +#ifndef __ASSEMBLY__ +/* DCACHE Register Structure Define */ +struct DCACHE_REG { + __IO uint32_t CACHE_CTRL; /* Address Offset: 0x0000 */ + __IO uint32_t CACHE_MAINTAIN[2]; /* Address Offset: 0x0004 */ + __IO uint32_t STB_TIMEOUT_CTRL; /* Address Offset: 0x000C */ + uint32_t RESERVED0010[4]; /* Address Offset: 0x0010 */ + __IO uint32_t CACHE_INT_EN; /* Address Offset: 0x0020 */ + __IO uint32_t CACHE_INT_ST; /* Address Offset: 0x0024 */ + __IO uint32_t CACHE_ERR_HADDR; /* Address Offset: 0x0028 */ + uint32_t RESERVED002C; /* Address Offset: 0x002C */ + __I uint32_t CACHE_STATUS; /* Address Offset: 0x0030 */ + uint32_t RESERVED0034[3]; /* Address Offset: 0x0034 */ + __I uint32_t PMU_RD_NUM_CNT; /* Address Offset: 0x0040 */ + __I uint32_t PMU_WR_NUM_CNT; /* Address Offset: 0x0044 */ + __I uint32_t PMU_SRAM_RD_HIT_CNT; /* Address Offset: 0x0048 */ + __I uint32_t PMU_HB_RD_HIT_CNT; /* Address Offset: 0x004C */ + __IO uint32_t PMU_STB_RD_HIT_CNT; /* Address Offset: 0x0050 */ + __I uint32_t PMU_RD_HIT_CNT; /* Address Offset: 0x0054 */ + __I uint32_t PMU_WR_HIT_CNT; /* Address Offset: 0x0058 */ + __I uint32_t PMU_RD_MISS_PENALTY_CNT; /* Address Offset: 0x005C */ + __I uint32_t PMU_WR_MISS_PENALTY_CNT; /* Address Offset: 0x0060 */ + __I uint32_t PMU_RD_LAT_CNT; /* Address Offset: 0x0064 */ + __I uint32_t PMU_WR_LAT_CNT; /* Address Offset: 0x0068 */ + uint32_t RESERVED006C[33]; /* Address Offset: 0x006C */ + __IO uint32_t REVISION; /* Address Offset: 0x00F0 */ +}; +/* ICACHE Register Structure Define */ +struct ICACHE_REG { + __IO uint32_t CACHE_CTRL; /* Address Offset: 0x0000 */ + __IO uint32_t CACHE_MAINTAIN[2]; /* Address Offset: 0x0004 */ + __IO uint32_t STB_TIMEOUT_CTRL; /* Address Offset: 0x000C */ + uint32_t RESERVED0010[4]; /* Address Offset: 0x0010 */ + __IO uint32_t CACHE_INT_EN; /* Address Offset: 0x0020 */ + __IO uint32_t CACHE_INT_ST; /* Address Offset: 0x0024 */ + __IO uint32_t CACHE_ERR_HADDR; /* Address Offset: 0x0028 */ + uint32_t RESERVED002C; /* Address Offset: 0x002C */ + __I uint32_t CACHE_STATUS; /* Address Offset: 0x0030 */ + uint32_t RESERVED0034[3]; /* Address Offset: 0x0034 */ + __I uint32_t PMU_RD_NUM_CNT; /* Address Offset: 0x0040 */ + __I uint32_t PMU_WR_NUM_CNT; /* Address Offset: 0x0044 */ + __I uint32_t PMU_SRAM_RD_HIT_CNT; /* Address Offset: 0x0048 */ + __I uint32_t PMU_HB_RD_HIT_CNT; /* Address Offset: 0x004C */ + __IO uint32_t PMU_STB_RD_HIT_CNT; /* Address Offset: 0x0050 */ + __I uint32_t PMU_RD_HIT_CNT; /* Address Offset: 0x0054 */ + __I uint32_t PMU_WR_HIT_CNT; /* Address Offset: 0x0058 */ + __I uint32_t PMU_RD_MISS_PENALTY_CNT; /* Address Offset: 0x005C */ + __I uint32_t PMU_WR_MISS_PENALTY_CNT; /* Address Offset: 0x0060 */ + __I uint32_t PMU_RD_LAT_CNT; /* Address Offset: 0x0064 */ + __I uint32_t PMU_WR_LAT_CNT; /* Address Offset: 0x0068 */ + uint32_t RESERVED006C[33]; /* Address Offset: 0x006C */ + __IO uint32_t REVISION; /* Address Offset: 0x00F0 */ +}; +/* PMU1_IOC Register Structure Define */ +struct PMU1_IOC_REG { + __IO uint32_t GPIO0A_IOMUX_SEL_L; /* Address Offset: 0x0000 */ + __IO uint32_t GPIO0A_IOMUX_SEL_H; /* Address Offset: 0x0004 */ + __IO uint32_t GPIO0B_IOMUX_SEL_L; /* Address Offset: 0x0008 */ + uint32_t RESERVED000C; /* Address Offset: 0x000C */ + __IO uint32_t GPIO0A_DS_L; /* Address Offset: 0x0010 */ + __IO uint32_t GPIO0A_DS_H; /* Address Offset: 0x0014 */ + __IO uint32_t GPIO0B_DS_L; /* Address Offset: 0x0018 */ + uint32_t RESERVED001C; /* Address Offset: 0x001C */ + __IO uint32_t GPIO0A_P; /* Address Offset: 0x0020 */ + __IO uint32_t GPIO0B_P; /* Address Offset: 0x0024 */ + __IO uint32_t GPIO0A_IE; /* Address Offset: 0x0028 */ + __IO uint32_t GPIO0B_IE; /* Address Offset: 0x002C */ + __IO uint32_t GPIO0A_SMT; /* Address Offset: 0x0030 */ + __IO uint32_t GPIO0B_SMT; /* Address Offset: 0x0034 */ + __IO uint32_t GPIO0A_PDIS; /* Address Offset: 0x0038 */ + __IO uint32_t GPIO0B_PDIS; /* Address Offset: 0x003C */ + __IO uint32_t XIN_CON; /* Address Offset: 0x0040 */ +}; +/* PMU2_IOC Register Structure Define */ +struct PMU2_IOC_REG { + __IO uint32_t GPIO0B_IOMUX_SEL_H; /* Address Offset: 0x0000 */ + __IO uint32_t GPIO0C_IOMUX_SEL_L; /* Address Offset: 0x0004 */ + __IO uint32_t GPIO0C_IOMUX_SEL_H; /* Address Offset: 0x0008 */ + __IO uint32_t GPIO0D_IOMUX_SEL_L; /* Address Offset: 0x000C */ + __IO uint32_t GPIO0D_IOMUX_SEL_H; /* Address Offset: 0x0010 */ + __IO uint32_t GPIO0B_DS_H; /* Address Offset: 0x0014 */ + __IO uint32_t GPIO0C_DS_L; /* Address Offset: 0x0018 */ + __IO uint32_t GPIO0C_DS_H; /* Address Offset: 0x001C */ + __IO uint32_t GPIO0D_DS_L; /* Address Offset: 0x0020 */ + __IO uint32_t GPIO0D_DS_H; /* Address Offset: 0x0024 */ + __IO uint32_t GPIO0B_P; /* Address Offset: 0x0028 */ + __IO uint32_t GPIO0C_P; /* Address Offset: 0x002C */ + __IO uint32_t GPIO0D_P; /* Address Offset: 0x0030 */ + __IO uint32_t GPIO0B_IE; /* Address Offset: 0x0034 */ + __IO uint32_t GPIO0C_IE; /* Address Offset: 0x0038 */ + __IO uint32_t GPIO0D_IE; /* Address Offset: 0x003C */ + __IO uint32_t GPIO0B_SMT; /* Address Offset: 0x0040 */ + __IO uint32_t GPIO0C_SMT; /* Address Offset: 0x0044 */ + __IO uint32_t GPIO0D_SMT; /* Address Offset: 0x0048 */ + __IO uint32_t GPIO0B_PDIS; /* Address Offset: 0x004C */ + __IO uint32_t GPIO0C_PDIS; /* Address Offset: 0x0050 */ + __IO uint32_t GPIO0D_PDIS; /* Address Offset: 0x0054 */ +}; +/* BUS_IOC Register Structure Define */ +struct BUS_IOC_REG { + uint32_t RESERVED0000[3]; /* Address Offset: 0x0000 */ + __IO uint32_t GPIO0B_IOMUX_SEL_H; /* Address Offset: 0x000C */ + __IO uint32_t GPIO0C_IOMUX_SEL_L; /* Address Offset: 0x0010 */ + __IO uint32_t GPIO0C_IOMUX_SEL_H; /* Address Offset: 0x0014 */ + __IO uint32_t GPIO0D_IOMUX_SEL_L; /* Address Offset: 0x0018 */ + __IO uint32_t GPIO0D_IOMUX_SEL_H; /* Address Offset: 0x001C */ + __IO uint32_t GPIO1A_IOMUX_SEL_L; /* Address Offset: 0x0020 */ + __IO uint32_t GPIO1A_IOMUX_SEL_H; /* Address Offset: 0x0024 */ + __IO uint32_t GPIO1B_IOMUX_SEL_L; /* Address Offset: 0x0028 */ + __IO uint32_t GPIO1B_IOMUX_SEL_H; /* Address Offset: 0x002C */ + __IO uint32_t GPIO1C_IOMUX_SEL_L; /* Address Offset: 0x0030 */ + __IO uint32_t GPIO1C_IOMUX_SEL_H; /* Address Offset: 0x0034 */ + __IO uint32_t GPIO1D_IOMUX_SEL_L; /* Address Offset: 0x0038 */ + __IO uint32_t GPIO1D_IOMUX_SEL_H; /* Address Offset: 0x003C */ + __IO uint32_t GPIO2A_IOMUX_SEL_L; /* Address Offset: 0x0040 */ + __IO uint32_t GPIO2A_IOMUX_SEL_H; /* Address Offset: 0x0044 */ + __IO uint32_t GPIO2B_IOMUX_SEL_L; /* Address Offset: 0x0048 */ + __IO uint32_t GPIO2B_IOMUX_SEL_H; /* Address Offset: 0x004C */ + __IO uint32_t GPIO2C_IOMUX_SEL_L; /* Address Offset: 0x0050 */ + __IO uint32_t GPIO2C_IOMUX_SEL_H; /* Address Offset: 0x0054 */ + __IO uint32_t GPIO2D_IOMUX_SEL_L; /* Address Offset: 0x0058 */ + __IO uint32_t GPIO2D_IOMUX_SEL_H; /* Address Offset: 0x005C */ + __IO uint32_t GPIO3A_IOMUX_SEL_L; /* Address Offset: 0x0060 */ + __IO uint32_t GPIO3A_IOMUX_SEL_H; /* Address Offset: 0x0064 */ + __IO uint32_t GPIO3B_IOMUX_SEL_L; /* Address Offset: 0x0068 */ + __IO uint32_t GPIO3B_IOMUX_SEL_H; /* Address Offset: 0x006C */ + __IO uint32_t GPIO3C_IOMUX_SEL_L; /* Address Offset: 0x0070 */ + __IO uint32_t GPIO3C_IOMUX_SEL_H; /* Address Offset: 0x0074 */ + __IO uint32_t GPIO3D_IOMUX_SEL_L; /* Address Offset: 0x0078 */ + __IO uint32_t GPIO3D_IOMUX_SEL_H; /* Address Offset: 0x007C */ + __IO uint32_t GPIO4A_IOMUX_SEL_L; /* Address Offset: 0x0080 */ + __IO uint32_t GPIO4A_IOMUX_SEL_H; /* Address Offset: 0x0084 */ + __IO uint32_t GPIO4B_IOMUX_SEL_L; /* Address Offset: 0x0088 */ + __IO uint32_t GPIO4B_IOMUX_SEL_H; /* Address Offset: 0x008C */ + __IO uint32_t GPIO4C_IOMUX_SEL_L; /* Address Offset: 0x0090 */ + __IO uint32_t GPIO4C_IOMUX_SEL_H; /* Address Offset: 0x0094 */ + __IO uint32_t GPIO4D_IOMUX_SEL_L; /* Address Offset: 0x0098 */ + __IO uint32_t GPIO4D_IOMUX_SEL_H; /* Address Offset: 0x009C */ +}; +/* UART Register Structure Define */ +struct UART_REG { + union { + __I uint32_t RBR; /* Address Offset: 0x0000 */ + __IO uint32_t DLL; /* Address Offset: 0x0000 */ + __O uint32_t THR; /* Address Offset: 0x0000 */ + }; + union { + __IO uint32_t DLH; /* Address Offset: 0x0004 */ + __IO uint32_t IER; /* Address Offset: 0x0004 */ + }; + union { + __O uint32_t FCR; /* Address Offset: 0x0008 */ + __I uint32_t IIR; /* Address Offset: 0x0008 */ + }; + __IO uint32_t LCR; /* Address Offset: 0x000C */ + __IO uint32_t MCR; /* Address Offset: 0x0010 */ + __I uint32_t LSR; /* Address Offset: 0x0014 */ + __I uint32_t MSR; /* Address Offset: 0x0018 */ + __IO uint32_t SCR; /* Address Offset: 0x001C */ + uint32_t RESERVED0020[4]; /* Address Offset: 0x0020 */ + union { + __I uint32_t SRBR; /* Address Offset: 0x0030 */ + __O uint32_t STHR; /* Address Offset: 0x0030 */ + }; + uint32_t RESERVED0034[15]; /* Address Offset: 0x0034 */ + __IO uint32_t FAR; /* Address Offset: 0x0070 */ + __I uint32_t TFR; /* Address Offset: 0x0074 */ + __O uint32_t RFW; /* Address Offset: 0x0078 */ + __I uint32_t USR; /* Address Offset: 0x007C */ + __I uint32_t TFL; /* Address Offset: 0x0080 */ + __I uint32_t RFL; /* Address Offset: 0x0084 */ + __O uint32_t SRR; /* Address Offset: 0x0088 */ + __IO uint32_t SRTS; /* Address Offset: 0x008C */ + __IO uint32_t SBCR; /* Address Offset: 0x0090 */ + __IO uint32_t SDMAM; /* Address Offset: 0x0094 */ + __IO uint32_t SFE; /* Address Offset: 0x0098 */ + __IO uint32_t SRT; /* Address Offset: 0x009C */ + __IO uint32_t STET; /* Address Offset: 0x00A0 */ + __IO uint32_t HTX; /* Address Offset: 0x00A4 */ + __O uint32_t DMASA; /* Address Offset: 0x00A8 */ + uint32_t RESERVED00AC[18]; /* Address Offset: 0x00AC */ + __I uint32_t CPR; /* Address Offset: 0x00F4 */ + __I uint32_t UCV; /* Address Offset: 0x00F8 */ + __I uint32_t CTR; /* Address Offset: 0x00FC */ +}; +/* WDT Register Structure Define */ +struct WDT_REG { + __IO uint32_t CR; /* Address Offset: 0x0000 */ + __IO uint32_t TORR; /* Address Offset: 0x0004 */ + __I uint32_t CCVR; /* Address Offset: 0x0008 */ + __O uint32_t CRR; /* Address Offset: 0x000C */ + __I uint32_t STAT; /* Address Offset: 0x0010 */ + __I uint32_t EOI; /* Address Offset: 0x0014 */ +}; +/* TIMER Register Structure Define */ +struct TIMER_REG { + __IO uint32_t LOAD_COUNT[2]; /* Address Offset: 0x0000 */ + __I uint32_t CURRENT_VALUE[2]; /* Address Offset: 0x0008 */ + __IO uint32_t CONTROLREG; /* Address Offset: 0x0010 */ + uint32_t RESERVED0014; /* Address Offset: 0x0014 */ + __IO uint32_t INTSTATUS; /* Address Offset: 0x0018 */ +}; +/* FSPI Register Structure Define */ +struct FSPI_REG { + __IO uint32_t CTRL0; /* Address Offset: 0x0000 */ + __IO uint32_t IMR; /* Address Offset: 0x0004 */ + __IO uint32_t ICLR; /* Address Offset: 0x0008 */ + __IO uint32_t FTLR; /* Address Offset: 0x000C */ + __IO uint32_t RCVR; /* Address Offset: 0x0010 */ + __IO uint32_t AX0; /* Address Offset: 0x0014 */ + __IO uint32_t ABIT0; /* Address Offset: 0x0018 */ + __IO uint32_t ISR; /* Address Offset: 0x001C */ + __IO uint32_t FSR; /* Address Offset: 0x0020 */ + __I uint32_t SR; /* Address Offset: 0x0024 */ + __I uint32_t RISR; /* Address Offset: 0x0028 */ + __I uint32_t VER; /* Address Offset: 0x002C */ + __IO uint32_t QOP; /* Address Offset: 0x0030 */ + __IO uint32_t EXT_CTRL; /* Address Offset: 0x0034 */ + uint32_t RESERVED0038; /* Address Offset: 0x0038 */ + __IO uint32_t DLL_CTRL0; /* Address Offset: 0x003C */ + uint32_t RESERVED0040; /* Address Offset: 0x0040 */ + __IO uint32_t EXT_AX; /* Address Offset: 0x0044 */ + __IO uint32_t SCLK_INATM_CNT; /* Address Offset: 0x0048 */ + uint32_t RESERVED004C; /* Address Offset: 0x004C */ + __O uint32_t XMMC_WCMD0; /* Address Offset: 0x0050 */ + __O uint32_t XMMC_RCMD0; /* Address Offset: 0x0054 */ + __IO uint32_t XMMC_CTRL; /* Address Offset: 0x0058 */ + __IO uint32_t MODE; /* Address Offset: 0x005C */ + __IO uint32_t DEVRGN; /* Address Offset: 0x0060 */ + __IO uint32_t DEVSIZE0; /* Address Offset: 0x0064 */ + __IO uint32_t TME0; /* Address Offset: 0x0068 */ + uint32_t RESERVED006C; /* Address Offset: 0x006C */ + __IO uint32_t XMMC_RX_WTMRK; /* Address Offset: 0x0070 */ + uint32_t RESERVED0074[3]; /* Address Offset: 0x0074 */ + __IO uint32_t DMATR; /* Address Offset: 0x0080 */ + __IO uint32_t DMAADDR; /* Address Offset: 0x0084 */ + __IO uint32_t LEN_CTRL; /* Address Offset: 0x0088 */ + __IO uint32_t LEN_EXT; /* Address Offset: 0x008C */ + uint32_t RESERVED0090; /* Address Offset: 0x0090 */ + __IO uint32_t XMMCSR; /* Address Offset: 0x0094 */ + uint32_t RESERVED0098[26]; /* Address Offset: 0x0098 */ + __O uint32_t CMD; /* Address Offset: 0x0100 */ + __O uint32_t ADDR; /* Address Offset: 0x0104 */ + __IO uint32_t DATA; /* Address Offset: 0x0108 */ + uint32_t RESERVED010C[61]; /* Address Offset: 0x010C */ + __IO uint32_t CTRL1; /* Address Offset: 0x0200 */ + uint32_t RESERVED0204[4]; /* Address Offset: 0x0204 */ + __IO uint32_t AX1; /* Address Offset: 0x0214 */ + __IO uint32_t ABIT1; /* Address Offset: 0x0218 */ + uint32_t RESERVED021C[8]; /* Address Offset: 0x021C */ + __IO uint32_t DLL_CTRL1; /* Address Offset: 0x023C */ + uint32_t RESERVED0240[4]; /* Address Offset: 0x0240 */ + __O uint32_t XMMC_WCMD1; /* Address Offset: 0x0250 */ + __O uint32_t XMMC_RCMD1; /* Address Offset: 0x0254 */ + uint32_t RESERVED0258[3]; /* Address Offset: 0x0258 */ + __IO uint32_t DEVSIZE1; /* Address Offset: 0x0264 */ + __IO uint32_t TME1; /* Address Offset: 0x0268 */ +}; +/* SPI Register Structure Define */ +struct SPI_REG { + __IO uint32_t CTRLR[2]; /* Address Offset: 0x0000 */ + __IO uint32_t ENR; /* Address Offset: 0x0008 */ + __IO uint32_t SER; /* Address Offset: 0x000C */ + __IO uint32_t BAUDR; /* Address Offset: 0x0010 */ + __IO uint32_t TXFTLR; /* Address Offset: 0x0014 */ + __IO uint32_t RXFTLR; /* Address Offset: 0x0018 */ + __I uint32_t TXFLR; /* Address Offset: 0x001C */ + __I uint32_t RXFLR; /* Address Offset: 0x0020 */ + __I uint32_t SR; /* Address Offset: 0x0024 */ + __IO uint32_t IPR; /* Address Offset: 0x0028 */ + __IO uint32_t IMR; /* Address Offset: 0x002C */ + __IO uint32_t ISR; /* Address Offset: 0x0030 */ + __IO uint32_t RISR; /* Address Offset: 0x0034 */ + __O uint32_t ICR; /* Address Offset: 0x0038 */ + __IO uint32_t DMACR; /* Address Offset: 0x003C */ + __IO uint32_t DMATDLR; /* Address Offset: 0x0040 */ + __IO uint32_t DMARDLR; /* Address Offset: 0x0044 */ + uint32_t RESERVED0048; /* Address Offset: 0x0048 */ + __IO uint32_t TIMEOUT; /* Address Offset: 0x004C */ + __IO uint32_t BYPASS; /* Address Offset: 0x0050 */ + uint32_t RESERVED0054[235]; /* Address Offset: 0x0054 */ + __O uint32_t TXDR; /* Address Offset: 0x0400 */ + uint32_t RESERVED0404[255]; /* Address Offset: 0x0404 */ + __I uint32_t RXDR; /* Address Offset: 0x0800 */ +}; +/* MBOX Register Structure Define */ +struct MBOX_CMD_DAT { + __IO uint32_t CMD; + __IO uint32_t DATA; +}; +struct MBOX_REG { + __IO uint32_t A2B_INTEN; /* Address Offset: 0x0000 */ + __IO uint32_t A2B_STATUS; /* Address Offset: 0x0004 */ + struct MBOX_CMD_DAT A2B[4]; /* Address Offset: 0x0008 */ + __IO uint32_t B2A_INTEN; /* Address Offset: 0x0028 */ + __IO uint32_t B2A_STATUS; /* Address Offset: 0x002C */ + struct MBOX_CMD_DAT B2A[4]; /* Address Offset: 0x0030 */ + uint32_t RESERVED0050[44]; /* Address Offset: 0x0050 */ + __IO uint32_t ATOMIC_LOCK[32]; /* Address Offset: 0x0100 */ +}; +/* INTMUX Register Structure Define */ +struct INTMUX_REG { +}; +/* INTMUX0_ Register Structure Define */ +struct INTMUX0__REG { +}; +/* CRU Register Structure Define */ +struct CRU_REG { + uint32_t RESERVED0000[88]; /* Address Offset: 0x0000 */ + __IO uint32_t V0PLL_CON[7]; /* Address Offset: 0x0160 */ + uint32_t RESERVED017C; /* Address Offset: 0x017C */ + __IO uint32_t AUPLL_CON[7]; /* Address Offset: 0x0180 */ + uint32_t RESERVED019C; /* Address Offset: 0x019C */ + __IO uint32_t CPLL_CON[7]; /* Address Offset: 0x01A0 */ + uint32_t RESERVED01BC; /* Address Offset: 0x01BC */ + __IO uint32_t GPLL_CON[7]; /* Address Offset: 0x01C0 */ + uint32_t RESERVED01DC; /* Address Offset: 0x01DC */ + __IO uint32_t NPLL_CON[7]; /* Address Offset: 0x01E0 */ + uint32_t RESERVED01FC[33]; /* Address Offset: 0x01FC */ + __IO uint32_t MODE_CON00; /* Address Offset: 0x0280 */ + uint32_t RESERVED0284[31]; /* Address Offset: 0x0284 */ + __IO uint32_t CRU_CLKSEL_CON[178]; /* Address Offset: 0x0300 */ + uint32_t RESERVED05C8[142]; /* Address Offset: 0x05C8 */ + __IO uint32_t CRU_CLKGATE_CON[78]; /* Address Offset: 0x0800 */ + uint32_t RESERVED0938[51]; /* Address Offset: 0x0938 */ + __IO uint32_t CRU_SOFTRST_CON[77]; /* Address Offset: 0x0A04 */ + uint32_t RESERVED0B38[50]; /* Address Offset: 0x0B38 */ + __IO uint32_t GLB_CNT_TH; /* Address Offset: 0x0C00 */ + __IO uint32_t GLBRST_ST; /* Address Offset: 0x0C04 */ + __IO uint32_t GLB_SRST_FST_VALUE; /* Address Offset: 0x0C08 */ + __IO uint32_t GLB_SRST_SND_VALUE; /* Address Offset: 0x0C0C */ + __IO uint32_t GLB_RST_CON; /* Address Offset: 0x0C10 */ + uint32_t RESERVED0C14[4]; /* Address Offset: 0x0C14 */ + __IO uint32_t SDIO_CON[2]; /* Address Offset: 0x0C24 */ + uint32_t RESERVED0C2C; /* Address Offset: 0x0C2C */ + __IO uint32_t SDMMC_CON[2]; /* Address Offset: 0x0C30 */ + __IO uint32_t PHYREF_ALT_GATE_CON; /* Address Offset: 0x0C38 */ + __IO uint32_t CM0_GATEMASK_CON; /* Address Offset: 0x0C3C */ + uint32_t RESERVED0C40[25]; /* Address Offset: 0x0C40 */ + __IO uint32_t QCHANNEL_CON01; /* Address Offset: 0x0CA4 */ +}; +/* BIGCORE0CRU Register Structure Define */ +struct BIGCORE0CRU_REG { + __IO uint32_t B0PLL_CON[7]; /* Address Offset: 0x0000 */ + uint32_t RESERVED001C[153]; /* Address Offset: 0x001C */ + __IO uint32_t MODE_CON00; /* Address Offset: 0x0280 */ + uint32_t RESERVED0284[31]; /* Address Offset: 0x0284 */ + __IO uint32_t CLKSEL_CON[3]; /* Address Offset: 0x0300 */ + uint32_t RESERVED030C[317]; /* Address Offset: 0x030C */ + __IO uint32_t GATE_CON[2]; /* Address Offset: 0x0800 */ + __IO uint32_t SOFTRST_CON[2]; /* Address Offset: 0x0A00 */ + __IO uint32_t SMOTH_DIVFREE_CON04; /* Address Offset: 0x0CC0 */ + __IO uint32_t SMOTH_DIVFREE_CON05; /* Address Offset: 0x0CC4 */ + __IO uint32_t AUTOCS_CLK_CORE_B01_I_CON0; /* Address Offset: 0x0D00 */ + __IO uint32_t AUTOCS_CLK_CORE_B01_I_CON1; /* Address Offset: 0x0D04 */ +}; +/* BIGCORE1CRU Register Structure Define */ +struct BIGCORE1CRU_REG { + uint32_t RESERVED0000[8]; /* Address Offset: 0x0000 */ + __IO uint32_t B1PLL_CON[7]; /* Address Offset: 0x0020 */ + uint32_t RESERVED003C[145]; /* Address Offset: 0x003C */ + __IO uint32_t MODE_CON00; /* Address Offset: 0x0280 */ + uint32_t RESERVED0284[31]; /* Address Offset: 0x0284 */ + __IO uint32_t CLKSEL_CON[3]; /* Address Offset: 0x0300 */ + uint32_t RESERVED030C[317]; /* Address Offset: 0x030C */ + __IO uint32_t GATE_CON[2]; /* Address Offset: 0x0800 */ + __IO uint32_t SOFTRST_CON[2]; /* Address Offset: 0x0A00 */ + __IO uint32_t SMOTH_DIVFREE_CON06; /* Address Offset: 0x0CC0 */ + __IO uint32_t SMOTH_DIVFREE_CON07; /* Address Offset: 0x0CC4 */ + __IO uint32_t AUTOCS_CLK_CORE_B23_I_CON0; /* Address Offset: 0x0D00 */ + __IO uint32_t AUTOCS_CLK_CORE_B23_I_CON1; /* Address Offset: 0x0D04 */ +}; +/* DSUCRU Register Structure Define */ +struct DSUCRU_REG { + uint32_t RESERVED0000[16]; /* Address Offset: 0x0000 */ + __IO uint32_t LPLL_CON[7]; /* Address Offset: 0x0040 */ + uint32_t RESERVED005C[137]; /* Address Offset: 0x005C */ + __IO uint32_t MODE_CON00; /* Address Offset: 0x0280 */ + uint32_t RESERVED0284[31]; /* Address Offset: 0x0284 */ + __IO uint32_t CLKSEL_CON[8]; /* Address Offset: 0x0300 */ + uint32_t RESERVED0320[312]; /* Address Offset: 0x0320 */ + __IO uint32_t GATE_CON[4]; /* Address Offset: 0x0800 */ + uint32_t RESERVED0810[124]; /* Address Offset: 0x0810 */ + __IO uint32_t SOFTRST_CON[4]; /* Address Offset: 0x0A00 */ + uint32_t RESERVED0A10[188]; /* Address Offset: 0x0A10 */ + __IO uint32_t AUTOCS_ACLK_M_DSU_BIU_CON0; /* Address Offset: 0x0D00 */ + __IO uint32_t AUTOCS_ACLK_M_DSU_BIU_CON1; /* Address Offset: 0x0D04 */ + __IO uint32_t AUTOCS_ACLK_S_DSU_BIU_CON0; /* Address Offset: 0x0D08 */ + __IO uint32_t AUTOCS_ACLK_S_DSU_BIU_CON1; /* Address Offset: 0x0D0C */ + __IO uint32_t AUTOCS_ACLK_MP_DSU_BIU_CON0; /* Address Offset: 0x0D10 */ + __IO uint32_t AUTOCS_ACLK_MP_DSU_BIU_CON1; /* Address Offset: 0x0D14 */ + __IO uint32_t AUTOCS_SCLK_DSU_SRC_CON0; /* Address Offset: 0x0D18 */ + __IO uint32_t AUTOCS_SCLK_DSU_SRC_CON1; /* Address Offset: 0x0D1C */ + __IO uint32_t AUTOCS_CLK_CORE_L_CON0; /* Address Offset: 0x0D20 */ + __IO uint32_t AUTOCS_CLK_CORE_L_CON1; /* Address Offset: 0x0D24 */ + uint32_t RESERVED0D28[118]; /* Address Offset: 0x0D28 */ + __IO uint32_t QCHANNEL_CON00; /* Address Offset: 0x0F00 */ + uint32_t RESERVED0F04[3]; /* Address Offset: 0x0F04 */ + __IO uint32_t SMOTH_DIVFREE_CON00; /* Address Offset: 0x0F10 */ + __IO uint32_t SMOTH_DIVFREE_CON01; /* Address Offset: 0x0F14 */ + __IO uint32_t SMOTH_DIVFREE_CON02; /* Address Offset: 0x0F18 */ + __IO uint32_t SMOTH_DIVFREE_CON03; /* Address Offset: 0x0F1C */ +}; +/* PHPTOPCRU Register Structure Define */ +struct PHPTOPCRU_REG { + uint32_t RESERVED0000[128]; /* Address Offset: 0x0000 */ + __IO uint32_t PPLL_CON[7]; /* Address Offset: 0x0200 */ + uint32_t RESERVED021C[377]; /* Address Offset: 0x021C */ + __IO uint32_t GATE_CON00; /* Address Offset: 0x0800 */ + uint32_t RESERVED0804[127]; /* Address Offset: 0x0804 */ + __IO uint32_t SOFTRST_CON00; /* Address Offset: 0x0A00 */ +}; +/* PMU1CRU Register Structure Define */ +struct PMU1CRU_REG { + uint32_t RESERVED0000[192]; /* Address Offset: 0x0000 */ + __IO uint32_t PMU_CLKSEL_CON[18]; /* Address Offset: 0x0300 */ + uint32_t RESERVED0348[302]; /* Address Offset: 0x0348 */ + __IO uint32_t PMU_CLKGATE_CON[6]; /* Address Offset: 0x0800 */ + uint32_t RESERVED0818[122]; /* Address Offset: 0x0818 */ + __IO uint32_t PMU_SOFTRST_CON[6]; /* Address Offset: 0x0A00 */ + uint32_t RESERVED0A18[186]; /* Address Offset: 0x0A18 */ + __IO uint32_t AUTOCS_HCLK_PMU_CM0_ROOT_I_CON0; /* Address Offset: 0x0D00 */ + __IO uint32_t AUTOCS_HCLK_PMU_CM0_ROOT_I_CON1; /* Address Offset: 0x0D04 */ +}; +#endif /* __ASSEMBLY__ */ +/****************************************************************************************/ +/* */ +/* Module Address Section */ +/* */ +/****************************************************************************************/ +/* Memory Base */ +#define DCACHE_BASE 0xF6F10000U /* DCACHE base address */ +#define ICACHE_BASE 0xF6F10000U /* ICACHE base address */ +#define PMU1_IOC_BASE 0xFD5F0000U /* PMU1_IOC base address */ +#define PMU2_IOC_BASE 0xFD5F4000U /* PMU2_IOC base address */ +#define BUS_IOC_BASE 0xFD5F8000U /* BUS_IOC base address */ +#define CRU_BASE 0xFD7C0000U /* CRU base address */ +#define BIGCORE0CRU_BASE 0xFD810000U /* BIGCORE0CRU base address */ +#define BIGCORE1CRU_BASE 0xFD812000U /* BIGCORE1CRU base address */ +#define DSUCRU_BASE 0xFD818000U /* DSUCRU base address */ +#define PHPTOPCRU_BASE 0xFD7C8000U /* PHPTOPCRU base address */ +#define PMU1CRU_BASE 0xFD7F0000U /* PMU1CRU base address */ +#define UART0_BASE 0xFD890000U /* UART0 base address */ +#define SYS_PMU_BASE 0xFD8D8000U /* SYS_PMU base address */ +#define WDTPMU_BASE 0xFD8E0000U /* WDTPMU base address */ +#define TIMERPMU_BASE 0xFD8F0000U /* TIMERPMU base address */ +#define WDTNPU_BASE 0xFDAF8000U /* WDTNPU base address */ +#define TIMERNPU_BASE 0xFDB00000U /* TIMERNPU base address */ +#define WDTDDR_BASE 0xFE110000U /* WDTDDR base address */ +#define TIMERDDR_BASE 0xFE118000U /* TIMERDDR base address */ +#define FSPI_BASE 0xFE2B0000U /* FSPI base address */ +#define SPI0_BASE 0xFEB00000U /* SPI0 base address */ +#define SPI1_BASE 0xFEB10000U /* SPI1 base address */ +#define SPI2_BASE 0xFEB20000U /* SPI2 base address */ +#define UART1_BASE 0xFEB40000U /* UART1 base address */ +#define UART2_BASE 0xFEB50000U /* UART2 base address */ +#define UART3_BASE 0xFEB60000U /* UART3 base address */ +#define UART4_BASE 0xFEB70000U /* UART4 base address */ +#define UART5_BASE 0xFEB80000U /* UART5 base address */ +#define UART6_BASE 0xFEB90000U /* UART6 base address */ +#define UART7_BASE 0xFEBA0000U /* UART7 base address */ +#define UART8_BASE 0xFEBB0000U /* UART8 base address */ +#define UART9_BASE 0xFEBC0000U /* UART9 base address */ +#define MBOX0_BASE 0xFEC60000U /* MBOX0 base address */ +#define MBOX1_BASE 0xFEC70000U /* MBOX1 base address */ +#define MBOX2_BASE 0xFECE0000U /* MBOX2 base address */ +#define INTMUX0_PMU_BASE 0xFECF0000U /* INTMUX0_PMU base address */ +#define INTMUX1_PMU_BASE 0xFECF4000U /* INTMUX1_PMU base address */ +#define INTMUX0_DDR_BASE 0xFECF8000U /* INTMUX0_DDR base address */ +#define INTMUX1_DDR_BASE 0xFECFC000U /* INTMUX1_DDR base address */ +/****************************************************************************************/ +/* */ +/* Module Variable Section */ +/* */ +/****************************************************************************************/ +/* Module Variable Define */ + +#define DCACHE ((struct DCACHE_REG *) DCACHE_BASE) +#define ICACHE ((struct ICACHE_REG *) ICACHE_BASE) +#define PMU1_IOC ((struct PMU1_IOC_REG *) PMU1_IOC_BASE) +#define PMU2_IOC ((struct PMU2_IOC_REG *) PMU2_IOC_BASE) +#define BUS_IOC ((struct BUS_IOC_REG *) BUS_IOC_BASE) +#define CRU ((struct CRU_REG *) CRU_BASE) +#define BIGCORE0CRU ((struct BIGCORE0CRU_REG *) BIGCORE0CRU_BASE) +#define BIGCORE1CRU ((struct BIGCORE1CRU_REG *) BIGCORE1CRU_BASE) +#define DSUCRU ((struct DSUCRU_REG *) DSUCRU_BASE) +#define PHPTOPCRU ((struct PHPTOPCRU_REG *) PHPTOPCRU_BASE) +#define PMU1CRU ((struct PMU1CRU_REG *) PMU1CRU_BASE) +#define UART0 ((struct UART_REG *) UART0_BASE) +#define WDTPMU ((struct WDTPMU_REG *) WDTPMU_BASE) +#define TIMERPMU ((struct TIMERPMU_REG *) TIMERPMU_BASE) +#define WDTNPU ((struct WDTNPU_REG *) WDTNPU_BASE) +#define TIMERNPU ((struct TIMERNPU_REG *) TIMERNPU_BASE) +#define WDTDDR ((struct WDTDDR_REG *) WDTDDR_BASE) +#define TIMERDDR ((struct TIMERDDR_REG *) TIMERDDR_BASE) +#define FSPI ((struct FSPI_REG *) FSPI_BASE) +#define SPI0 ((struct SPI_REG *) SPI0_BASE) +#define SPI1 ((struct SPI_REG *) SPI1_BASE) +#define SPI2 ((struct SPI_REG *) SPI2_BASE) +#define UART1 ((struct UART_REG *) UART1_BASE) +#define UART2 ((struct UART_REG *) UART2_BASE) +#define UART3 ((struct UART_REG *) UART3_BASE) +#define UART4 ((struct UART_REG *) UART4_BASE) +#define UART5 ((struct UART_REG *) UART5_BASE) +#define UART6 ((struct UART_REG *) UART6_BASE) +#define UART7 ((struct UART_REG *) UART7_BASE) +#define UART8 ((struct UART_REG *) UART8_BASE) +#define UART9 ((struct UART_REG *) UART9_BASE) +#define MBOX0 ((struct MBOX_REG *) MBOX0_BASE) +#define MBOX1 ((struct MBOX_REG *) MBOX1_BASE) +#define MBOX2 ((struct MBOX_REG *) MBOX2_BASE) +#define INTMUX0_PMU ((struct INTMUX0_PMU_REG *) INTMUX0_PMU_BASE) +#define INTMUX1_PMU ((struct INTMUX1_PMU_REG *) INTMUX1_PMU_BASE) +#define INTMUX0_DDR ((struct INTMUX0_DDR_REG *) INTMUX0_DDR_BASE) +#define INTMUX1_DDR ((struct INTMUX1_DDR_REG *) INTMUX1_DDR_BASE) + +#define IS_DCACHE_INSTANCE(instance) ((instance) == DCACHE) +#define IS_ICACHE_INSTANCE(instance) ((instance) == ICACHE) +#define IS_PMU1_IOC_INSTANCE(instance) ((instance) == PMU1_IOC) +#define IS_PMU2_IOC_INSTANCE(instance) ((instance) == PMU2_IOC) +#define IS_BUS_IOC_INSTANCE(instance) ((instance) == BUS_IOC) +#define IS_CRU_INSTANCE(instance) ((instance) == CRU) +#define IS_BIGCORE0CRU_INSTANCE(instance) ((instance) == BIGCORE0CRU) +#define IS_BIGCORE1CRU_INSTANCE(instance) ((instance) == BIGCORE1CRU) +#define IS_DSUCRU_INSTANCE(instance) ((instance) == DSUCRU) +#define IS_PHPTOPCRU_INSTANCE(instance) ((instance) == PHPTOPCRU) +#define IS_PMU1CRU_INSTANCE(instance) ((instance) == PMU1CRU) +#define IS_WDTPMU_INSTANCE(instance) ((instance) == WDTPMU) +#define IS_TIMERPMU_INSTANCE(instance) ((instance) == TIMERPMU) +#define IS_WDTNPU_INSTANCE(instance) ((instance) == WDTNPU) +#define IS_TIMERNPU_INSTANCE(instance) ((instance) == TIMERNPU) +#define IS_WDTDDR_INSTANCE(instance) ((instance) == WDTDDR) +#define IS_TIMERDDR_INSTANCE(instance) ((instance) == TIMERDDR) +#define IS_FSPI_INSTANCE(instance) ((instance) == FSPI) +#define IS_INTMUX0_PMU_INSTANCE(instance) ((instance) == INTMUX0_PMU) +#define IS_INTMUX1_PMU_INSTANCE(instance) ((instance) == INTMUX1_PMU) +#define IS_INTMUX0_DDR_INSTANCE(instance) ((instance) == INTMUX0_DDR) +#define IS_INTMUX1_DDR_INSTANCE(instance) ((instance) == INTMUX1_DDR) +#define IS_UART_INSTANCE(instance) (((instance) == UART0) || ((instance) == UART1) || ((instance) == UART2) || ((instance) == UART3) || ((instance) == UART4) || ((instance) == UART5) || ((instance) == UART6) || ((instance) == UART7) || ((instance) == UART8) || ((instance) == UART9)) +#define IS_SPI_INSTANCE(instance) (((instance) == SPI0) || ((instance) == SPI1) || ((instance) == SPI2)) +#define IS_MBOX_INSTANCE(instance) (((instance) == MBOX0) || ((instance) == MBOX1) || ((instance) == MBOX2)) +/****************************************************************************************/ +/* */ +/* Register Bitmap Section */ +/* */ +/****************************************************************************************/ +/*****************************************CRU*****************************************/ +#define CRU_CLKSEL_CON_OFFSET 0x300 +#define CRU_CLKGATE_CON_OFFSET 0x800 +#define CRU_SOFTRST_CON_OFFSET 0xA00 + +/*****************************************DCACHE*****************************************/ +/* CACHE_CTRL */ +#define DCACHE_CACHE_CTRL_OFFSET (0x0U) +#define DCACHE_CACHE_CTRL_CACHE_EN_SHIFT (0U) +#define DCACHE_CACHE_CTRL_CACHE_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_EN_SHIFT) /* 0x00000001 */ +#define DCACHE_CACHE_CTRL_CACHE_WT_EN_SHIFT (1U) +#define DCACHE_CACHE_CTRL_CACHE_WT_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_WT_EN_SHIFT) /* 0x00000002 */ +#define DCACHE_CACHE_CTRL_CACHE_HB_EN_SHIFT (2U) +#define DCACHE_CACHE_CTRL_CACHE_HB_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_HB_EN_SHIFT) /* 0x00000004 */ +#define DCACHE_CACHE_CTRL_CACHE_STB_EN_SHIFT (3U) +#define DCACHE_CACHE_CTRL_CACHE_STB_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_STB_EN_SHIFT) /* 0x00000008 */ +#define DCACHE_CACHE_CTRL_CACHE_FLUSH_SHIFT (4U) +#define DCACHE_CACHE_CTRL_CACHE_FLUSH_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_FLUSH_SHIFT) /* 0x00000010 */ +#define DCACHE_CACHE_CTRL_CACHE_PMU_EN_SHIFT (5U) +#define DCACHE_CACHE_CTRL_CACHE_PMU_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_PMU_EN_SHIFT) /* 0x00000020 */ +#define DCACHE_CACHE_CTRL_CACHE_BYPASS_SHIFT (6U) +#define DCACHE_CACHE_CTRL_CACHE_BYPASS_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_BYPASS_SHIFT) /* 0x00000040 */ +#define DCACHE_CACHE_CTRL_STB_TIMEOUT_EN_SHIFT (7U) +#define DCACHE_CACHE_CTRL_STB_TIMEOUT_EN_MASK (0x1U << DCACHE_CACHE_CTRL_STB_TIMEOUT_EN_SHIFT) /* 0x00000080 */ +#define DCACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_SHIFT (8U) +#define DCACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_MASK (0x7U << DCACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_SHIFT) /* 0x00000700 */ +#define DCACHE_CACHE_CTRL_CACHE_MPU_MODE_SHIFT (12U) +#define DCACHE_CACHE_CTRL_CACHE_MPU_MODE_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_MPU_MODE_SHIFT) /* 0x00001000 */ +#define DCACHE_CACHE_CTRL_CACHE_PF_EN_SHIFT (13U) +#define DCACHE_CACHE_CTRL_CACHE_PF_EN_MASK (0x1U << DCACHE_CACHE_CTRL_CACHE_PF_EN_SHIFT) /* 0x00002000 */ +/* CACHE_MAINTAIN0 */ +#define DCACHE_CACHE_MAINTAIN0_OFFSET (0x4U) +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_VALID_SHIFT (0U) +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_VALID_MASK (0x1U << DCACHE_CACHE_MAINTAIN0_CACHE_M_VALID_SHIFT) /* 0x00000001 */ +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_CMD_SHIFT (1U) +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_CMD_MASK (0x3U << DCACHE_CACHE_MAINTAIN0_CACHE_M_CMD_SHIFT) /* 0x00000006 */ +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_SHIFT (5U) +#define DCACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_MASK (0x7FFFFFFU << DCACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_SHIFT) /* 0xFFFFFFE0 */ +/* CACHE_MAINTAIN1 */ +#define DCACHE_CACHE_MAINTAIN1_OFFSET (0x8U) +#define DCACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_SHIFT (0U) +#define DCACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_MASK (0xFFFFU << DCACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_SHIFT) /* 0x0000FFFF */ +/* STB_TIMEOUT_CTRL */ +#define DCACHE_STB_TIMEOUT_CTRL_OFFSET (0xCU) +#define DCACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_SHIFT (0U) +#define DCACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_MASK (0x7FFFFU << DCACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_SHIFT) /* 0x0007FFFF */ +/* CACHE_INT_EN */ +#define DCACHE_CACHE_INT_EN_OFFSET (0x20U) +#define DCACHE_CACHE_INT_EN_ERR_RECORD_EN_SHIFT (0U) +#define DCACHE_CACHE_INT_EN_ERR_RECORD_EN_MASK (0x1U << DCACHE_CACHE_INT_EN_ERR_RECORD_EN_SHIFT) /* 0x00000001 */ +/* CACHE_INT_ST */ +#define DCACHE_CACHE_INT_ST_OFFSET (0x24U) +#define DCACHE_CACHE_INT_ST_AHB_ERROR_STATUS_SHIFT (0U) +#define DCACHE_CACHE_INT_ST_AHB_ERROR_STATUS_MASK (0x1U << DCACHE_CACHE_INT_ST_AHB_ERROR_STATUS_SHIFT) /* 0x00000001 */ +/* CACHE_ERR_HADDR */ +#define DCACHE_CACHE_ERR_HADDR_OFFSET (0x28U) +#define DCACHE_CACHE_ERR_HADDR_STATUS_HADDR_SHIFT (0U) +#define DCACHE_CACHE_ERR_HADDR_STATUS_HADDR_MASK (0x1U << DCACHE_CACHE_ERR_HADDR_STATUS_HADDR_SHIFT) /* 0x00000001 */ +/* CACHE_STATUS */ +#define DCACHE_CACHE_STATUS_OFFSET (0x30U) +#define DCACHE_CACHE_STATUS (0x0U) +#define DCACHE_CACHE_STATUS_CACHE_INIT_FINISH_SHIFT (0U) +#define DCACHE_CACHE_STATUS_CACHE_INIT_FINISH_MASK (0x1U << DCACHE_CACHE_STATUS_CACHE_INIT_FINISH_SHIFT) /* 0x00000001 */ +#define DCACHE_CACHE_STATUS_CACHE_M_BUSY_SHIFT (1U) +#define DCACHE_CACHE_STATUS_CACHE_M_BUSY_MASK (0x1U << DCACHE_CACHE_STATUS_CACHE_M_BUSY_SHIFT) /* 0x00000002 */ +#define DCACHE_CACHE_STATUS_CACHE_FLUSH_DONE_SHIFT (2U) +#define DCACHE_CACHE_STATUS_CACHE_FLUSH_DONE_MASK (0x1U << DCACHE_CACHE_STATUS_CACHE_FLUSH_DONE_SHIFT) /* 0x00000004 */ +/* PMU_RD_NUM_CNT */ +#define DCACHE_PMU_RD_NUM_CNT_OFFSET (0x40U) +#define DCACHE_PMU_RD_NUM_CNT (0x0U) +#define DCACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_SHIFT (0U) +#define DCACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_NUM_CNT */ +#define DCACHE_PMU_WR_NUM_CNT_OFFSET (0x44U) +#define DCACHE_PMU_WR_NUM_CNT (0x0U) +#define DCACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_SHIFT (0U) +#define DCACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_SRAM_RD_HIT_CNT */ +#define DCACHE_PMU_SRAM_RD_HIT_CNT_OFFSET (0x48U) +#define DCACHE_PMU_SRAM_RD_HIT_CNT (0x0U) +#define DCACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_SHIFT (0U) +#define DCACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_HB_RD_HIT_CNT */ +#define DCACHE_PMU_HB_RD_HIT_CNT_OFFSET (0x4CU) +#define DCACHE_PMU_HB_RD_HIT_CNT (0x0U) +#define DCACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_SHIFT (0U) +#define DCACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_STB_RD_HIT_CNT */ +#define DCACHE_PMU_STB_RD_HIT_CNT_OFFSET (0x50U) +#define DCACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_SHIFT (0U) +#define DCACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_HIT_CNT */ +#define DCACHE_PMU_RD_HIT_CNT_OFFSET (0x54U) +#define DCACHE_PMU_RD_HIT_CNT (0x0U) +#define DCACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_SHIFT (0U) +#define DCACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_HIT_CNT */ +#define DCACHE_PMU_WR_HIT_CNT_OFFSET (0x58U) +#define DCACHE_PMU_WR_HIT_CNT (0x0U) +#define DCACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_SHIFT (0U) +#define DCACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_MISS_PENALTY_CNT */ +#define DCACHE_PMU_RD_MISS_PENALTY_CNT_OFFSET (0x5CU) +#define DCACHE_PMU_RD_MISS_PENALTY_CNT (0x0U) +#define DCACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_SHIFT (0U) +#define DCACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_MISS_PENALTY_CNT */ +#define DCACHE_PMU_WR_MISS_PENALTY_CNT_OFFSET (0x60U) +#define DCACHE_PMU_WR_MISS_PENALTY_CNT (0x0U) +#define DCACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_SHIFT (0U) +#define DCACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_LAT_CNT */ +#define DCACHE_PMU_RD_LAT_CNT_OFFSET (0x64U) +#define DCACHE_PMU_RD_LAT_CNT (0x0U) +#define DCACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_SHIFT (0U) +#define DCACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_LAT_CNT */ +#define DCACHE_PMU_WR_LAT_CNT_OFFSET (0x68U) +#define DCACHE_PMU_WR_LAT_CNT (0x0U) +#define DCACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_SHIFT (0U) +#define DCACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_MASK (0xFFFFFFFFU << DCACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* REVISION */ +#define DCACHE_REVISION_OFFSET (0xF0U) +#define DCACHE_REVISION_REVISION_SHIFT (0U) +#define DCACHE_REVISION_REVISION_MASK (0xFFFFFFFFU << DCACHE_REVISION_REVISION_SHIFT) /* 0xFFFFFFFF */ +/*****************************************ICACHE*****************************************/ +/* CACHE_CTRL */ +#define ICACHE_CACHE_CTRL_OFFSET (0x0U) +#define ICACHE_CACHE_CTRL_CACHE_EN_SHIFT (0U) +#define ICACHE_CACHE_CTRL_CACHE_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_EN_SHIFT) /* 0x00000001 */ +#define ICACHE_CACHE_CTRL_CACHE_WT_EN_SHIFT (1U) +#define ICACHE_CACHE_CTRL_CACHE_WT_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_WT_EN_SHIFT) /* 0x00000002 */ +#define ICACHE_CACHE_CTRL_CACHE_HB_EN_SHIFT (2U) +#define ICACHE_CACHE_CTRL_CACHE_HB_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_HB_EN_SHIFT) /* 0x00000004 */ +#define ICACHE_CACHE_CTRL_CACHE_STB_EN_SHIFT (3U) +#define ICACHE_CACHE_CTRL_CACHE_STB_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_STB_EN_SHIFT) /* 0x00000008 */ +#define ICACHE_CACHE_CTRL_CACHE_FLUSH_SHIFT (4U) +#define ICACHE_CACHE_CTRL_CACHE_FLUSH_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_FLUSH_SHIFT) /* 0x00000010 */ +#define ICACHE_CACHE_CTRL_CACHE_PMU_EN_SHIFT (5U) +#define ICACHE_CACHE_CTRL_CACHE_PMU_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_PMU_EN_SHIFT) /* 0x00000020 */ +#define ICACHE_CACHE_CTRL_CACHE_BYPASS_SHIFT (6U) +#define ICACHE_CACHE_CTRL_CACHE_BYPASS_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_BYPASS_SHIFT) /* 0x00000040 */ +#define ICACHE_CACHE_CTRL_STB_TIMEOUT_EN_SHIFT (7U) +#define ICACHE_CACHE_CTRL_STB_TIMEOUT_EN_MASK (0x1U << ICACHE_CACHE_CTRL_STB_TIMEOUT_EN_SHIFT) /* 0x00000080 */ +#define ICACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_SHIFT (8U) +#define ICACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_MASK (0x7U << ICACHE_CACHE_CTRL_CACHE_ENTRY_THRESH_SHIFT) /* 0x00000700 */ +#define ICACHE_CACHE_CTRL_CACHE_MPU_MODE_SHIFT (12U) +#define ICACHE_CACHE_CTRL_CACHE_MPU_MODE_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_MPU_MODE_SHIFT) /* 0x00001000 */ +#define ICACHE_CACHE_CTRL_CACHE_PF_EN_SHIFT (13U) +#define ICACHE_CACHE_CTRL_CACHE_PF_EN_MASK (0x1U << ICACHE_CACHE_CTRL_CACHE_PF_EN_SHIFT) /* 0x00002000 */ +/* CACHE_MAINTAIN0 */ +#define ICACHE_CACHE_MAINTAIN0_OFFSET (0x4U) +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_VALID_SHIFT (0U) +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_VALID_MASK (0x1U << ICACHE_CACHE_MAINTAIN0_CACHE_M_VALID_SHIFT) /* 0x00000001 */ +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_CMD_SHIFT (1U) +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_CMD_MASK (0x3U << ICACHE_CACHE_MAINTAIN0_CACHE_M_CMD_SHIFT) /* 0x00000006 */ +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_SHIFT (5U) +#define ICACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_MASK (0x7FFFFFFU << ICACHE_CACHE_MAINTAIN0_CACHE_M_ADDR_SHIFT) /* 0xFFFFFFE0 */ +/* CACHE_MAINTAIN1 */ +#define ICACHE_CACHE_MAINTAIN1_OFFSET (0x8U) +#define ICACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_SHIFT (0U) +#define ICACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_MASK (0xFFFFU << ICACHE_CACHE_MAINTAIN1_CACHE_M_OFFSET_SHIFT) /* 0x0000FFFF */ +/* STB_TIMEOUT_CTRL */ +#define ICACHE_STB_TIMEOUT_CTRL_OFFSET (0xCU) +#define ICACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_SHIFT (0U) +#define ICACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_MASK (0x7FFFFU << ICACHE_STB_TIMEOUT_CTRL_STB_TIMEOUT_VALUE_SHIFT) /* 0x0007FFFF */ +/* CACHE_INT_EN */ +#define ICACHE_CACHE_INT_EN_OFFSET (0x20U) +#define ICACHE_CACHE_INT_EN_ERR_RECORD_EN_SHIFT (0U) +#define ICACHE_CACHE_INT_EN_ERR_RECORD_EN_MASK (0x1U << ICACHE_CACHE_INT_EN_ERR_RECORD_EN_SHIFT) /* 0x00000001 */ +/* CACHE_INT_ST */ +#define ICACHE_CACHE_INT_ST_OFFSET (0x24U) +#define ICACHE_CACHE_INT_ST_AHB_ERROR_STATUS_SHIFT (0U) +#define ICACHE_CACHE_INT_ST_AHB_ERROR_STATUS_MASK (0x1U << ICACHE_CACHE_INT_ST_AHB_ERROR_STATUS_SHIFT) /* 0x00000001 */ +/* CACHE_ERR_HADDR */ +#define ICACHE_CACHE_ERR_HADDR_OFFSET (0x28U) +#define ICACHE_CACHE_ERR_HADDR_STATUS_HADDR_SHIFT (0U) +#define ICACHE_CACHE_ERR_HADDR_STATUS_HADDR_MASK (0x1U << ICACHE_CACHE_ERR_HADDR_STATUS_HADDR_SHIFT) /* 0x00000001 */ +/* CACHE_STATUS */ +#define ICACHE_CACHE_STATUS_OFFSET (0x30U) +#define ICACHE_CACHE_STATUS (0x0U) +#define ICACHE_CACHE_STATUS_CACHE_INIT_FINISH_SHIFT (0U) +#define ICACHE_CACHE_STATUS_CACHE_INIT_FINISH_MASK (0x1U << ICACHE_CACHE_STATUS_CACHE_INIT_FINISH_SHIFT) /* 0x00000001 */ +#define ICACHE_CACHE_STATUS_CACHE_M_BUSY_SHIFT (1U) +#define ICACHE_CACHE_STATUS_CACHE_M_BUSY_MASK (0x1U << ICACHE_CACHE_STATUS_CACHE_M_BUSY_SHIFT) /* 0x00000002 */ +#define ICACHE_CACHE_STATUS_CACHE_FLUSH_DONE_SHIFT (2U) +#define ICACHE_CACHE_STATUS_CACHE_FLUSH_DONE_MASK (0x1U << ICACHE_CACHE_STATUS_CACHE_FLUSH_DONE_SHIFT) /* 0x00000004 */ +/* PMU_RD_NUM_CNT */ +#define ICACHE_PMU_RD_NUM_CNT_OFFSET (0x40U) +#define ICACHE_PMU_RD_NUM_CNT (0x0U) +#define ICACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_SHIFT (0U) +#define ICACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_RD_NUM_CNT_PMU_RD_NUM_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_NUM_CNT */ +#define ICACHE_PMU_WR_NUM_CNT_OFFSET (0x44U) +#define ICACHE_PMU_WR_NUM_CNT (0x0U) +#define ICACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_SHIFT (0U) +#define ICACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_WR_NUM_CNT_PMU_WR_NUM_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_SRAM_RD_HIT_CNT */ +#define ICACHE_PMU_SRAM_RD_HIT_CNT_OFFSET (0x48U) +#define ICACHE_PMU_SRAM_RD_HIT_CNT (0x0U) +#define ICACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_SHIFT (0U) +#define ICACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_SRAM_RD_HIT_CNT_PMU_SRAM_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_HB_RD_HIT_CNT */ +#define ICACHE_PMU_HB_RD_HIT_CNT_OFFSET (0x4CU) +#define ICACHE_PMU_HB_RD_HIT_CNT (0x0U) +#define ICACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_SHIFT (0U) +#define ICACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_HB_RD_HIT_CNT_PMU_HB_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_STB_RD_HIT_CNT */ +#define ICACHE_PMU_STB_RD_HIT_CNT_OFFSET (0x50U) +#define ICACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_SHIFT (0U) +#define ICACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_STB_RD_HIT_CNT_PMU_STB_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_HIT_CNT */ +#define ICACHE_PMU_RD_HIT_CNT_OFFSET (0x54U) +#define ICACHE_PMU_RD_HIT_CNT (0x0U) +#define ICACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_SHIFT (0U) +#define ICACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_RD_HIT_CNT_PMU_RD_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_HIT_CNT */ +#define ICACHE_PMU_WR_HIT_CNT_OFFSET (0x58U) +#define ICACHE_PMU_WR_HIT_CNT (0x0U) +#define ICACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_SHIFT (0U) +#define ICACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_WR_HIT_CNT_PMU_WR_HIT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_MISS_PENALTY_CNT */ +#define ICACHE_PMU_RD_MISS_PENALTY_CNT_OFFSET (0x5CU) +#define ICACHE_PMU_RD_MISS_PENALTY_CNT (0x0U) +#define ICACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_SHIFT (0U) +#define ICACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_RD_MISS_PENALTY_CNT_PMU_RD_MISS_PENALTY_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_MISS_PENALTY_CNT */ +#define ICACHE_PMU_WR_MISS_PENALTY_CNT_OFFSET (0x60U) +#define ICACHE_PMU_WR_MISS_PENALTY_CNT (0x0U) +#define ICACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_SHIFT (0U) +#define ICACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_WR_MISS_PENALTY_CNT_PMU_WR_MISS_PENALTY_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_RD_LAT_CNT */ +#define ICACHE_PMU_RD_LAT_CNT_OFFSET (0x64U) +#define ICACHE_PMU_RD_LAT_CNT (0x0U) +#define ICACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_SHIFT (0U) +#define ICACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_RD_LAT_CNT_PMU_RD_LAT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* PMU_WR_LAT_CNT */ +#define ICACHE_PMU_WR_LAT_CNT_OFFSET (0x68U) +#define ICACHE_PMU_WR_LAT_CNT (0x0U) +#define ICACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_SHIFT (0U) +#define ICACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_MASK (0xFFFFFFFFU << ICACHE_PMU_WR_LAT_CNT_PMU_RD_LAT_CNT_SHIFT) /* 0xFFFFFFFF */ +/* REVISION */ +#define ICACHE_REVISION_OFFSET (0xF0U) +#define ICACHE_REVISION_REVISION_SHIFT (0U) +#define ICACHE_REVISION_REVISION_MASK (0xFFFFFFFFU << ICACHE_REVISION_REVISION_SHIFT) /* 0xFFFFFFFF */ +/****************************************PMU1_IOC****************************************/ +/* GPIO0A_IOMUX_SEL_L */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_OFFSET (0x0U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A0_SEL_SHIFT (0U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A0_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A0_SEL_SHIFT) /* 0x0000000F */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A1_SEL_SHIFT (4U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A1_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A1_SEL_SHIFT) /* 0x000000F0 */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A2_SEL_SHIFT (8U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A2_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A2_SEL_SHIFT) /* 0x00000F00 */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A3_SEL_SHIFT (12U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A3_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_L_GPIO0A3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0A_IOMUX_SEL_H */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_OFFSET (0x4U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A4_SEL_SHIFT (0U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A4_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A4_SEL_SHIFT) /* 0x0000000F */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A5_SEL_SHIFT (4U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A5_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A5_SEL_SHIFT) /* 0x000000F0 */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A6_SEL_SHIFT (8U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A6_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A6_SEL_SHIFT) /* 0x00000F00 */ +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A7_SEL_SHIFT (12U) +#define PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A7_SEL_MASK (0xFU << PMU1_IOC_GPIO0A_IOMUX_SEL_H_GPIO0A7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0B_IOMUX_SEL_L */ +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_OFFSET (0x8U) +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B0_SEL_SHIFT (0U) +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B0_SEL_MASK (0xFU << PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B0_SEL_SHIFT) /* 0x0000000F */ +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B1_SEL_SHIFT (4U) +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B1_SEL_MASK (0xFU << PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B1_SEL_SHIFT) /* 0x000000F0 */ +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B2_SEL_SHIFT (8U) +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B2_SEL_MASK (0xFU << PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B2_SEL_SHIFT) /* 0x00000F00 */ +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B3_SEL_SHIFT (12U) +#define PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B3_SEL_MASK (0xFU << PMU1_IOC_GPIO0B_IOMUX_SEL_L_GPIO0B3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0A_DS_L */ +#define PMU1_IOC_GPIO0A_DS_L_OFFSET (0x10U) +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A0_DS_SHIFT (0U) +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A0_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_L_GPIO0A0_DS_SHIFT) /* 0x00000003 */ +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A1_DS_SHIFT (4U) +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A1_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_L_GPIO0A1_DS_SHIFT) /* 0x00000030 */ +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A2_DS_SHIFT (8U) +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A2_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_L_GPIO0A2_DS_SHIFT) /* 0x00000300 */ +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A3_DS_SHIFT (12U) +#define PMU1_IOC_GPIO0A_DS_L_GPIO0A3_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_L_GPIO0A3_DS_SHIFT) /* 0x00003000 */ +/* GPIO0A_DS_H */ +#define PMU1_IOC_GPIO0A_DS_H_OFFSET (0x14U) +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A4_DS_SHIFT (0U) +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A4_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_H_GPIO0A4_DS_SHIFT) /* 0x00000003 */ +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A5_DS_SHIFT (4U) +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A5_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_H_GPIO0A5_DS_SHIFT) /* 0x00000030 */ +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A6_DS_SHIFT (8U) +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A6_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_H_GPIO0A6_DS_SHIFT) /* 0x00000300 */ +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A7_DS_SHIFT (12U) +#define PMU1_IOC_GPIO0A_DS_H_GPIO0A7_DS_MASK (0x3U << PMU1_IOC_GPIO0A_DS_H_GPIO0A7_DS_SHIFT) /* 0x00003000 */ +/* GPIO0B_DS_L */ +#define PMU1_IOC_GPIO0B_DS_L_OFFSET (0x18U) +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B0_DS_SHIFT (0U) +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B0_DS_MASK (0x3U << PMU1_IOC_GPIO0B_DS_L_GPIO0B0_DS_SHIFT) /* 0x00000003 */ +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B1_DS_SHIFT (4U) +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B1_DS_MASK (0x3U << PMU1_IOC_GPIO0B_DS_L_GPIO0B1_DS_SHIFT) /* 0x00000030 */ +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B2_DS_SHIFT (8U) +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B2_DS_MASK (0x3U << PMU1_IOC_GPIO0B_DS_L_GPIO0B2_DS_SHIFT) /* 0x00000300 */ +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B3_DS_SHIFT (12U) +#define PMU1_IOC_GPIO0B_DS_L_GPIO0B3_DS_MASK (0x3U << PMU1_IOC_GPIO0B_DS_L_GPIO0B3_DS_SHIFT) /* 0x00003000 */ +/* GPIO0A_P */ +#define PMU1_IOC_GPIO0A_P_OFFSET (0x20U) +#define PMU1_IOC_GPIO0A_P_GPIO0A0_PE_SHIFT (0U) +#define PMU1_IOC_GPIO0A_P_GPIO0A0_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A0_PE_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A0_PS_SHIFT (1U) +#define PMU1_IOC_GPIO0A_P_GPIO0A0_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A0_PS_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A1_PE_SHIFT (2U) +#define PMU1_IOC_GPIO0A_P_GPIO0A1_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A1_PE_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A1_PS_SHIFT (3U) +#define PMU1_IOC_GPIO0A_P_GPIO0A1_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A1_PS_SHIFT) /* 0x00000008 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A2_PE_SHIFT (4U) +#define PMU1_IOC_GPIO0A_P_GPIO0A2_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A2_PE_SHIFT) /* 0x00000010 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A2_PS_SHIFT (5U) +#define PMU1_IOC_GPIO0A_P_GPIO0A2_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A2_PS_SHIFT) /* 0x00000020 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A3_PE_SHIFT (6U) +#define PMU1_IOC_GPIO0A_P_GPIO0A3_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A3_PE_SHIFT) /* 0x00000040 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A3_PS_SHIFT (7U) +#define PMU1_IOC_GPIO0A_P_GPIO0A3_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A3_PS_SHIFT) /* 0x00000080 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A4_PE_SHIFT (8U) +#define PMU1_IOC_GPIO0A_P_GPIO0A4_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A4_PE_SHIFT) /* 0x00000100 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A4_PS_SHIFT (9U) +#define PMU1_IOC_GPIO0A_P_GPIO0A4_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A4_PS_SHIFT) /* 0x00000200 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A5_PE_SHIFT (10U) +#define PMU1_IOC_GPIO0A_P_GPIO0A5_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A5_PE_SHIFT) /* 0x00000400 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A5_PS_SHIFT (11U) +#define PMU1_IOC_GPIO0A_P_GPIO0A5_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A5_PS_SHIFT) /* 0x00000800 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A6_PE_SHIFT (12U) +#define PMU1_IOC_GPIO0A_P_GPIO0A6_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A6_PE_SHIFT) /* 0x00001000 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A6_PS_SHIFT (13U) +#define PMU1_IOC_GPIO0A_P_GPIO0A6_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A6_PS_SHIFT) /* 0x00002000 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A7_PE_SHIFT (14U) +#define PMU1_IOC_GPIO0A_P_GPIO0A7_PE_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A7_PE_SHIFT) /* 0x00004000 */ +#define PMU1_IOC_GPIO0A_P_GPIO0A7_PS_SHIFT (15U) +#define PMU1_IOC_GPIO0A_P_GPIO0A7_PS_MASK (0x1U << PMU1_IOC_GPIO0A_P_GPIO0A7_PS_SHIFT) /* 0x00008000 */ +/* GPIO0B_P */ +#define PMU1_IOC_GPIO0B_P_OFFSET (0x24U) +#define PMU1_IOC_GPIO0B_P_GPIO0B0_PE_SHIFT (0U) +#define PMU1_IOC_GPIO0B_P_GPIO0B0_PE_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B0_PE_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B0_PS_SHIFT (1U) +#define PMU1_IOC_GPIO0B_P_GPIO0B0_PS_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B0_PS_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B1_PE_SHIFT (2U) +#define PMU1_IOC_GPIO0B_P_GPIO0B1_PE_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B1_PE_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B1_PS_SHIFT (3U) +#define PMU1_IOC_GPIO0B_P_GPIO0B1_PS_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B1_PS_SHIFT) /* 0x00000008 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B2_PE_SHIFT (4U) +#define PMU1_IOC_GPIO0B_P_GPIO0B2_PE_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B2_PE_SHIFT) /* 0x00000010 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B2_PS_SHIFT (5U) +#define PMU1_IOC_GPIO0B_P_GPIO0B2_PS_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B2_PS_SHIFT) /* 0x00000020 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B3_PE_SHIFT (6U) +#define PMU1_IOC_GPIO0B_P_GPIO0B3_PE_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B3_PE_SHIFT) /* 0x00000040 */ +#define PMU1_IOC_GPIO0B_P_GPIO0B3_PS_SHIFT (7U) +#define PMU1_IOC_GPIO0B_P_GPIO0B3_PS_MASK (0x1U << PMU1_IOC_GPIO0B_P_GPIO0B3_PS_SHIFT) /* 0x00000080 */ +/* GPIO0A_IE */ +#define PMU1_IOC_GPIO0A_IE_OFFSET (0x28U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A0_IE_SHIFT (0U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A0_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A0_IE_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A1_IE_SHIFT (1U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A1_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A1_IE_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A2_IE_SHIFT (2U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A2_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A2_IE_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A3_IE_SHIFT (3U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A3_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A3_IE_SHIFT) /* 0x00000008 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A4_IE_SHIFT (4U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A4_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A4_IE_SHIFT) /* 0x00000010 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A5_IE_SHIFT (5U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A5_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A5_IE_SHIFT) /* 0x00000020 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A6_IE_SHIFT (6U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A6_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A6_IE_SHIFT) /* 0x00000040 */ +#define PMU1_IOC_GPIO0A_IE_GPIO0A7_IE_SHIFT (7U) +#define PMU1_IOC_GPIO0A_IE_GPIO0A7_IE_MASK (0x1U << PMU1_IOC_GPIO0A_IE_GPIO0A7_IE_SHIFT) /* 0x00000080 */ +/* GPIO0B_IE */ +#define PMU1_IOC_GPIO0B_IE_OFFSET (0x2CU) +#define PMU1_IOC_GPIO0B_IE_GPIO0B0_IE_SHIFT (0U) +#define PMU1_IOC_GPIO0B_IE_GPIO0B0_IE_MASK (0x1U << PMU1_IOC_GPIO0B_IE_GPIO0B0_IE_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0B_IE_GPIO0B1_IE_SHIFT (1U) +#define PMU1_IOC_GPIO0B_IE_GPIO0B1_IE_MASK (0x1U << PMU1_IOC_GPIO0B_IE_GPIO0B1_IE_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0B_IE_GPIO0B2_IE_SHIFT (2U) +#define PMU1_IOC_GPIO0B_IE_GPIO0B2_IE_MASK (0x1U << PMU1_IOC_GPIO0B_IE_GPIO0B2_IE_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0B_IE_GPIO0B3_IE_SHIFT (3U) +#define PMU1_IOC_GPIO0B_IE_GPIO0B3_IE_MASK (0x1U << PMU1_IOC_GPIO0B_IE_GPIO0B3_IE_SHIFT) /* 0x00000008 */ +/* GPIO0A_SMT */ +#define PMU1_IOC_GPIO0A_SMT_OFFSET (0x30U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A0_SMT_SHIFT (0U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A0_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A0_SMT_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A1_SMT_SHIFT (1U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A1_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A1_SMT_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A2_SMT_SHIFT (2U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A2_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A2_SMT_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A3_SMT_SHIFT (3U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A3_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A3_SMT_SHIFT) /* 0x00000008 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A4_SMT_SHIFT (4U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A4_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A4_SMT_SHIFT) /* 0x00000010 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A5_SMT_SHIFT (5U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A5_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A5_SMT_SHIFT) /* 0x00000020 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A6_SMT_SHIFT (6U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A6_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A6_SMT_SHIFT) /* 0x00000040 */ +#define PMU1_IOC_GPIO0A_SMT_GPIO0A7_SMT_SHIFT (7U) +#define PMU1_IOC_GPIO0A_SMT_GPIO0A7_SMT_MASK (0x1U << PMU1_IOC_GPIO0A_SMT_GPIO0A7_SMT_SHIFT) /* 0x00000080 */ +/* GPIO0B_SMT */ +#define PMU1_IOC_GPIO0B_SMT_OFFSET (0x34U) +#define PMU1_IOC_GPIO0B_SMT_GPIO0B0_SMT_SHIFT (0U) +#define PMU1_IOC_GPIO0B_SMT_GPIO0B0_SMT_MASK (0x1U << PMU1_IOC_GPIO0B_SMT_GPIO0B0_SMT_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0B_SMT_GPIO0B1_SMT_SHIFT (1U) +#define PMU1_IOC_GPIO0B_SMT_GPIO0B1_SMT_MASK (0x1U << PMU1_IOC_GPIO0B_SMT_GPIO0B1_SMT_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0B_SMT_GPIO0B2_SMT_SHIFT (2U) +#define PMU1_IOC_GPIO0B_SMT_GPIO0B2_SMT_MASK (0x1U << PMU1_IOC_GPIO0B_SMT_GPIO0B2_SMT_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0B_SMT_GPIO0B3_SMT_SHIFT (3U) +#define PMU1_IOC_GPIO0B_SMT_GPIO0B3_SMT_MASK (0x1U << PMU1_IOC_GPIO0B_SMT_GPIO0B3_SMT_SHIFT) /* 0x00000008 */ +/* GPIO0A_PDIS */ +#define PMU1_IOC_GPIO0A_PDIS_OFFSET (0x38U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A0_PULL_DIS_SHIFT (0U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A0_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A0_PULL_DIS_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A1_PULL_DIS_SHIFT (1U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A1_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A1_PULL_DIS_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A2_PULL_DIS_SHIFT (2U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A2_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A2_PULL_DIS_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A3_PULL_DIS_SHIFT (3U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A3_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A3_PULL_DIS_SHIFT) /* 0x00000008 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A4_PULL_DIS_SHIFT (4U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A4_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A4_PULL_DIS_SHIFT) /* 0x00000010 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A5_PULL_DIS_SHIFT (5U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A5_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A5_PULL_DIS_SHIFT) /* 0x00000020 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A6_PULL_DIS_SHIFT (6U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A6_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A6_PULL_DIS_SHIFT) /* 0x00000040 */ +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A7_PULL_DIS_SHIFT (7U) +#define PMU1_IOC_GPIO0A_PDIS_GPIO0A7_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0A_PDIS_GPIO0A7_PULL_DIS_SHIFT) /* 0x00000080 */ +/* GPIO0B_PDIS */ +#define PMU1_IOC_GPIO0B_PDIS_OFFSET (0x3CU) +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B0_PULL_DIS_SHIFT (0U) +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B0_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0B_PDIS_GPIO0B0_PULL_DIS_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B1_PULL_DIS_SHIFT (1U) +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B1_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0B_PDIS_GPIO0B1_PULL_DIS_SHIFT) /* 0x00000002 */ +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B2_PULL_DIS_SHIFT (2U) +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B2_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0B_PDIS_GPIO0B2_PULL_DIS_SHIFT) /* 0x00000004 */ +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B3_PULL_DIS_SHIFT (3U) +#define PMU1_IOC_GPIO0B_PDIS_GPIO0B3_PULL_DIS_MASK (0x1U << PMU1_IOC_GPIO0B_PDIS_GPIO0B3_PULL_DIS_SHIFT) /* 0x00000008 */ +/* XIN_CON */ +#define PMU1_IOC_XIN_CON_OFFSET (0x40U) +#define PMU1_IOC_XIN_CON_XIN_OSC_EN_SHIFT (0U) +#define PMU1_IOC_XIN_CON_XIN_OSC_EN_MASK (0x1U << PMU1_IOC_XIN_CON_XIN_OSC_EN_SHIFT) /* 0x00000001 */ +#define PMU1_IOC_XIN_CON_XIN_OSC_SF_SHIFT (2U) +#define PMU1_IOC_XIN_CON_XIN_OSC_SF_MASK (0x3U << PMU1_IOC_XIN_CON_XIN_OSC_SF_SHIFT) /* 0x0000000C */ +/****************************************PMU2_IOC****************************************/ +/* GPIO0B_IOMUX_SEL_H */ +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_OFFSET (0x0U) +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_SHIFT (4U) +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_MASK (0xFU << PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_SHIFT) /* 0x000000F0 */ +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_SHIFT (8U) +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_MASK (0xFU << PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_SHIFT) /* 0x00000F00 */ +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_SHIFT (12U) +#define PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_MASK (0xFU << PMU2_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0C_IOMUX_SEL_L */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_OFFSET (0x4U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_SHIFT (0U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_SHIFT) /* 0x0000000F */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C1_SEL_SHIFT (4U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C1_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C1_SEL_SHIFT) /* 0x000000F0 */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C2_SEL_SHIFT (8U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C2_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C2_SEL_SHIFT) /* 0x00000F00 */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C3_SEL_SHIFT (12U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C3_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0C_IOMUX_SEL_H */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_OFFSET (0x8U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_SHIFT (0U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_SHIFT) /* 0x0000000F */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_SHIFT (4U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_SHIFT) /* 0x000000F0 */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_SHIFT (8U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_SHIFT) /* 0x00000F00 */ +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_SHIFT (12U) +#define PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_MASK (0xFU << PMU2_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0D_IOMUX_SEL_L */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_OFFSET (0xCU) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_SHIFT (0U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_SHIFT) /* 0x0000000F */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_SHIFT (4U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_SHIFT) /* 0x000000F0 */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_SHIFT (8U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_SHIFT) /* 0x00000F00 */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_SHIFT (12U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0D_IOMUX_SEL_H */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_OFFSET (0x10U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_SHIFT (0U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_SHIFT) /* 0x0000000F */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_SHIFT (4U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_SHIFT) /* 0x000000F0 */ +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D6_SEL_SHIFT (8U) +#define PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D6_SEL_MASK (0xFU << PMU2_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D6_SEL_SHIFT) /* 0x00000F00 */ +/* GPIO0B_DS_H */ +#define PMU2_IOC_GPIO0B_DS_H_OFFSET (0x14U) +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B5_DS_SHIFT (4U) +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B5_DS_MASK (0x7U << PMU2_IOC_GPIO0B_DS_H_GPIO0B5_DS_SHIFT) /* 0x00000070 */ +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B6_DS_SHIFT (8U) +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B6_DS_MASK (0x7U << PMU2_IOC_GPIO0B_DS_H_GPIO0B6_DS_SHIFT) /* 0x00000700 */ +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B7_DS_SHIFT (12U) +#define PMU2_IOC_GPIO0B_DS_H_GPIO0B7_DS_MASK (0x7U << PMU2_IOC_GPIO0B_DS_H_GPIO0B7_DS_SHIFT) /* 0x00007000 */ +/* GPIO0C_DS_L */ +#define PMU2_IOC_GPIO0C_DS_L_OFFSET (0x18U) +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C0_DS_SHIFT (0U) +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C0_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_L_GPIO0C0_DS_SHIFT) /* 0x00000007 */ +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C1_DS_SHIFT (4U) +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C1_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_L_GPIO0C1_DS_SHIFT) /* 0x00000070 */ +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C2_DS_SHIFT (8U) +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C2_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_L_GPIO0C2_DS_SHIFT) /* 0x00000700 */ +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C3_DS_SHIFT (12U) +#define PMU2_IOC_GPIO0C_DS_L_GPIO0C3_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_L_GPIO0C3_DS_SHIFT) /* 0x00007000 */ +/* GPIO0C_DS_H */ +#define PMU2_IOC_GPIO0C_DS_H_OFFSET (0x1CU) +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C4_DS_SHIFT (0U) +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C4_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_H_GPIO0C4_DS_SHIFT) /* 0x00000007 */ +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C5_DS_SHIFT (4U) +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C5_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_H_GPIO0C5_DS_SHIFT) /* 0x00000070 */ +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C6_DS_SHIFT (8U) +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C6_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_H_GPIO0C6_DS_SHIFT) /* 0x00000700 */ +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C7_DS_SHIFT (12U) +#define PMU2_IOC_GPIO0C_DS_H_GPIO0C7_DS_MASK (0x7U << PMU2_IOC_GPIO0C_DS_H_GPIO0C7_DS_SHIFT) /* 0x00007000 */ +/* GPIO0D_DS_L */ +#define PMU2_IOC_GPIO0D_DS_L_OFFSET (0x20U) +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D0_DS_SHIFT (0U) +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D0_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_L_GPIO0D0_DS_SHIFT) /* 0x00000007 */ +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D1_DS_SHIFT (4U) +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D1_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_L_GPIO0D1_DS_SHIFT) /* 0x00000070 */ +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D2_DS_SHIFT (8U) +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D2_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_L_GPIO0D2_DS_SHIFT) /* 0x00000700 */ +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D3_DS_SHIFT (12U) +#define PMU2_IOC_GPIO0D_DS_L_GPIO0D3_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_L_GPIO0D3_DS_SHIFT) /* 0x00007000 */ +/* GPIO0D_DS_H */ +#define PMU2_IOC_GPIO0D_DS_H_OFFSET (0x24U) +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D4_DS_SHIFT (0U) +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D4_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_H_GPIO0D4_DS_SHIFT) /* 0x00000007 */ +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D5_DS_SHIFT (4U) +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D5_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_H_GPIO0D5_DS_SHIFT) /* 0x00000070 */ +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D6_DS_SHIFT (8U) +#define PMU2_IOC_GPIO0D_DS_H_GPIO0D6_DS_MASK (0x7U << PMU2_IOC_GPIO0D_DS_H_GPIO0D6_DS_SHIFT) /* 0x00000700 */ +/* GPIO0B_P */ +#define PMU2_IOC_GPIO0B_P_OFFSET (0x28U) +#define PMU2_IOC_GPIO0B_P_GPIO0B5_PE_SHIFT (10U) +#define PMU2_IOC_GPIO0B_P_GPIO0B5_PE_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B5_PE_SHIFT) /* 0x00000400 */ +#define PMU2_IOC_GPIO0B_P_GPIO0B5_PS_SHIFT (11U) +#define PMU2_IOC_GPIO0B_P_GPIO0B5_PS_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B5_PS_SHIFT) /* 0x00000800 */ +#define PMU2_IOC_GPIO0B_P_GPIO0B6_PE_SHIFT (12U) +#define PMU2_IOC_GPIO0B_P_GPIO0B6_PE_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B6_PE_SHIFT) /* 0x00001000 */ +#define PMU2_IOC_GPIO0B_P_GPIO0B6_PS_SHIFT (13U) +#define PMU2_IOC_GPIO0B_P_GPIO0B6_PS_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B6_PS_SHIFT) /* 0x00002000 */ +#define PMU2_IOC_GPIO0B_P_GPIO0B7_PE_SHIFT (14U) +#define PMU2_IOC_GPIO0B_P_GPIO0B7_PE_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B7_PE_SHIFT) /* 0x00004000 */ +#define PMU2_IOC_GPIO0B_P_GPIO0B7_PS_SHIFT (15U) +#define PMU2_IOC_GPIO0B_P_GPIO0B7_PS_MASK (0x1U << PMU2_IOC_GPIO0B_P_GPIO0B7_PS_SHIFT) /* 0x00008000 */ +/* GPIO0C_P */ +#define PMU2_IOC_GPIO0C_P_OFFSET (0x2CU) +#define PMU2_IOC_GPIO0C_P_GPIO0C0_PE_SHIFT (0U) +#define PMU2_IOC_GPIO0C_P_GPIO0C0_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C0_PE_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C0_PS_SHIFT (1U) +#define PMU2_IOC_GPIO0C_P_GPIO0C0_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C0_PS_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C1_PE_SHIFT (2U) +#define PMU2_IOC_GPIO0C_P_GPIO0C1_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C1_PE_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C1_PS_SHIFT (3U) +#define PMU2_IOC_GPIO0C_P_GPIO0C1_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C1_PS_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C2_PE_SHIFT (4U) +#define PMU2_IOC_GPIO0C_P_GPIO0C2_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C2_PE_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C2_PS_SHIFT (5U) +#define PMU2_IOC_GPIO0C_P_GPIO0C2_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C2_PS_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C3_PE_SHIFT (6U) +#define PMU2_IOC_GPIO0C_P_GPIO0C3_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C3_PE_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C3_PS_SHIFT (7U) +#define PMU2_IOC_GPIO0C_P_GPIO0C3_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C3_PS_SHIFT) /* 0x00000080 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C4_PE_SHIFT (8U) +#define PMU2_IOC_GPIO0C_P_GPIO0C4_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C4_PE_SHIFT) /* 0x00000100 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C4_PS_SHIFT (9U) +#define PMU2_IOC_GPIO0C_P_GPIO0C4_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C4_PS_SHIFT) /* 0x00000200 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C5_PE_SHIFT (10U) +#define PMU2_IOC_GPIO0C_P_GPIO0C5_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C5_PE_SHIFT) /* 0x00000400 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C5_PS_SHIFT (11U) +#define PMU2_IOC_GPIO0C_P_GPIO0C5_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C5_PS_SHIFT) /* 0x00000800 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C6_PE_SHIFT (12U) +#define PMU2_IOC_GPIO0C_P_GPIO0C6_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C6_PE_SHIFT) /* 0x00001000 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C6_PS_SHIFT (13U) +#define PMU2_IOC_GPIO0C_P_GPIO0C6_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C6_PS_SHIFT) /* 0x00002000 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C7_PE_SHIFT (14U) +#define PMU2_IOC_GPIO0C_P_GPIO0C7_PE_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C7_PE_SHIFT) /* 0x00004000 */ +#define PMU2_IOC_GPIO0C_P_GPIO0C7_PS_SHIFT (15U) +#define PMU2_IOC_GPIO0C_P_GPIO0C7_PS_MASK (0x1U << PMU2_IOC_GPIO0C_P_GPIO0C7_PS_SHIFT) /* 0x00008000 */ +/* GPIO0D_P */ +#define PMU2_IOC_GPIO0D_P_OFFSET (0x30U) +#define PMU2_IOC_GPIO0D_P_GPIO0D0_PE_SHIFT (0U) +#define PMU2_IOC_GPIO0D_P_GPIO0D0_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D0_PE_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D0_PS_SHIFT (1U) +#define PMU2_IOC_GPIO0D_P_GPIO0D0_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D0_PS_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D1_PE_SHIFT (2U) +#define PMU2_IOC_GPIO0D_P_GPIO0D1_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D1_PE_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D1_PS_SHIFT (3U) +#define PMU2_IOC_GPIO0D_P_GPIO0D1_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D1_PS_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D2_PE_SHIFT (4U) +#define PMU2_IOC_GPIO0D_P_GPIO0D2_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D2_PE_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D2_PS_SHIFT (5U) +#define PMU2_IOC_GPIO0D_P_GPIO0D2_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D2_PS_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D3_PE_SHIFT (6U) +#define PMU2_IOC_GPIO0D_P_GPIO0D3_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D3_PE_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D3_PS_SHIFT (7U) +#define PMU2_IOC_GPIO0D_P_GPIO0D3_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D3_PS_SHIFT) /* 0x00000080 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D4_PE_SHIFT (8U) +#define PMU2_IOC_GPIO0D_P_GPIO0D4_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D4_PE_SHIFT) /* 0x00000100 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D4_PS_SHIFT (9U) +#define PMU2_IOC_GPIO0D_P_GPIO0D4_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D4_PS_SHIFT) /* 0x00000200 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D5_PE_SHIFT (10U) +#define PMU2_IOC_GPIO0D_P_GPIO0D5_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D5_PE_SHIFT) /* 0x00000400 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D5_PS_SHIFT (11U) +#define PMU2_IOC_GPIO0D_P_GPIO0D5_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D5_PS_SHIFT) /* 0x00000800 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D6_PE_SHIFT (12U) +#define PMU2_IOC_GPIO0D_P_GPIO0D6_PE_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D6_PE_SHIFT) /* 0x00001000 */ +#define PMU2_IOC_GPIO0D_P_GPIO0D6_PS_SHIFT (13U) +#define PMU2_IOC_GPIO0D_P_GPIO0D6_PS_MASK (0x1U << PMU2_IOC_GPIO0D_P_GPIO0D6_PS_SHIFT) /* 0x00002000 */ +/* GPIO0B_IE */ +#define PMU2_IOC_GPIO0B_IE_OFFSET (0x34U) +#define PMU2_IOC_GPIO0B_IE_GPIO0B5_IE_SHIFT (5U) +#define PMU2_IOC_GPIO0B_IE_GPIO0B5_IE_MASK (0x1U << PMU2_IOC_GPIO0B_IE_GPIO0B5_IE_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0B_IE_GPIO0B6_IE_SHIFT (6U) +#define PMU2_IOC_GPIO0B_IE_GPIO0B6_IE_MASK (0x1U << PMU2_IOC_GPIO0B_IE_GPIO0B6_IE_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0B_IE_GPIO0B7_IE_SHIFT (7U) +#define PMU2_IOC_GPIO0B_IE_GPIO0B7_IE_MASK (0x1U << PMU2_IOC_GPIO0B_IE_GPIO0B7_IE_SHIFT) /* 0x00000080 */ +/* GPIO0C_IE */ +#define PMU2_IOC_GPIO0C_IE_OFFSET (0x38U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C0_IE_SHIFT (0U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C0_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C0_IE_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C1_IE_SHIFT (1U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C1_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C1_IE_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C2_IE_SHIFT (2U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C2_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C2_IE_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C3_IE_SHIFT (3U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C3_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C3_IE_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C4_IE_SHIFT (4U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C4_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C4_IE_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C5_IE_SHIFT (5U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C5_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C5_IE_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C6_IE_SHIFT (6U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C6_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C6_IE_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0C_IE_GPIO0C7_IE_SHIFT (7U) +#define PMU2_IOC_GPIO0C_IE_GPIO0C7_IE_MASK (0x1U << PMU2_IOC_GPIO0C_IE_GPIO0C7_IE_SHIFT) /* 0x00000080 */ +/* GPIO0D_IE */ +#define PMU2_IOC_GPIO0D_IE_OFFSET (0x3CU) +#define PMU2_IOC_GPIO0D_IE_GPIO0D0_IE_SHIFT (0U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D0_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D0_IE_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D1_IE_SHIFT (1U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D1_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D1_IE_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D2_IE_SHIFT (2U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D2_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D2_IE_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D3_IE_SHIFT (3U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D3_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D3_IE_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D4_IE_SHIFT (4U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D4_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D4_IE_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D5_IE_SHIFT (5U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D5_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D5_IE_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0D_IE_GPIO0D6_IE_SHIFT (6U) +#define PMU2_IOC_GPIO0D_IE_GPIO0D6_IE_MASK (0x1U << PMU2_IOC_GPIO0D_IE_GPIO0D6_IE_SHIFT) /* 0x00000040 */ +/* GPIO0B_SMT */ +#define PMU2_IOC_GPIO0B_SMT_OFFSET (0x40U) +#define PMU2_IOC_GPIO0B_SMT_GPIO0B5_SMT_SHIFT (5U) +#define PMU2_IOC_GPIO0B_SMT_GPIO0B5_SMT_MASK (0x1U << PMU2_IOC_GPIO0B_SMT_GPIO0B5_SMT_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0B_SMT_GPIO0B6_SMT_SHIFT (6U) +#define PMU2_IOC_GPIO0B_SMT_GPIO0B6_SMT_MASK (0x1U << PMU2_IOC_GPIO0B_SMT_GPIO0B6_SMT_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0B_SMT_GPIO0B7_SMT_SHIFT (7U) +#define PMU2_IOC_GPIO0B_SMT_GPIO0B7_SMT_MASK (0x1U << PMU2_IOC_GPIO0B_SMT_GPIO0B7_SMT_SHIFT) /* 0x00000080 */ +/* GPIO0C_SMT */ +#define PMU2_IOC_GPIO0C_SMT_OFFSET (0x44U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C0_SMT_SHIFT (0U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C0_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C0_SMT_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C1_SMT_SHIFT (1U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C1_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C1_SMT_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C2_SMT_SHIFT (2U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C2_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C2_SMT_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C3_SMT_SHIFT (3U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C3_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C3_SMT_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C4_SMT_SHIFT (4U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C4_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C4_SMT_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C5_SMT_SHIFT (5U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C5_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C5_SMT_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C6_SMT_SHIFT (6U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C6_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C6_SMT_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0C_SMT_GPIO0C7_SMT_SHIFT (7U) +#define PMU2_IOC_GPIO0C_SMT_GPIO0C7_SMT_MASK (0x1U << PMU2_IOC_GPIO0C_SMT_GPIO0C7_SMT_SHIFT) /* 0x00000080 */ +/* GPIO0D_SMT */ +#define PMU2_IOC_GPIO0D_SMT_OFFSET (0x48U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D0_SMT_SHIFT (0U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D0_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D0_SMT_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D1_SMT_SHIFT (1U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D1_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D1_SMT_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D2_SMT_SHIFT (2U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D2_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D2_SMT_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D3_SMT_SHIFT (3U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D3_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D3_SMT_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D4_SMT_SHIFT (4U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D4_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D4_SMT_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D5_SMT_SHIFT (5U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D5_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D5_SMT_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0D_SMT_GPIO0D6_SMT_SHIFT (6U) +#define PMU2_IOC_GPIO0D_SMT_GPIO0D6_SMT_MASK (0x1U << PMU2_IOC_GPIO0D_SMT_GPIO0D6_SMT_SHIFT) /* 0x00000040 */ +/* GPIO0B_PDIS */ +#define PMU2_IOC_GPIO0B_PDIS_OFFSET (0x4CU) +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B5_PULL_DIS_SHIFT (5U) +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B5_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0B_PDIS_GPIO0B5_PULL_DIS_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B6_PULL_DIS_SHIFT (6U) +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B6_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0B_PDIS_GPIO0B6_PULL_DIS_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B7_PULL_DIS_SHIFT (7U) +#define PMU2_IOC_GPIO0B_PDIS_GPIO0B7_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0B_PDIS_GPIO0B7_PULL_DIS_SHIFT) /* 0x00000080 */ +/* GPIO0C_PDIS */ +#define PMU2_IOC_GPIO0C_PDIS_OFFSET (0x50U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C0_PULL_DIS_SHIFT (0U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C0_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C0_PULL_DIS_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C1_PULL_DIS_SHIFT (1U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C1_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C1_PULL_DIS_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C2_PULL_DIS_SHIFT (2U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C2_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C2_PULL_DIS_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C3_PULL_DIS_SHIFT (3U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C3_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C3_PULL_DIS_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C4_PULL_DIS_SHIFT (4U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C4_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C4_PULL_DIS_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C5_PULL_DIS_SHIFT (5U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C5_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C5_PULL_DIS_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C6_PULL_DIS_SHIFT (6U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C6_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C6_PULL_DIS_SHIFT) /* 0x00000040 */ +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C7_PULL_DIS_SHIFT (7U) +#define PMU2_IOC_GPIO0C_PDIS_GPIO0C7_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0C_PDIS_GPIO0C7_PULL_DIS_SHIFT) /* 0x00000080 */ +/* GPIO0D_PDIS */ +#define PMU2_IOC_GPIO0D_PDIS_OFFSET (0x54U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D0_PULL_DIS_SHIFT (0U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D0_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D0_PULL_DIS_SHIFT) /* 0x00000001 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D1_PULL_DIS_SHIFT (1U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D1_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D1_PULL_DIS_SHIFT) /* 0x00000002 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D2_PULL_DIS_SHIFT (2U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D2_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D2_PULL_DIS_SHIFT) /* 0x00000004 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D3_PULL_DIS_SHIFT (3U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D3_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D3_PULL_DIS_SHIFT) /* 0x00000008 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D4_PULL_DIS_SHIFT (4U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D4_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D4_PULL_DIS_SHIFT) /* 0x00000010 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D5_PULL_DIS_SHIFT (5U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D5_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D5_PULL_DIS_SHIFT) /* 0x00000020 */ +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D6_PULL_DIS_SHIFT (6U) +#define PMU2_IOC_GPIO0D_PDIS_GPIO0D6_PULL_DIS_MASK (0x1U << PMU2_IOC_GPIO0D_PDIS_GPIO0D6_PULL_DIS_SHIFT) /* 0x00000040 */ +/****************************************BUS_IOC*****************************************/ +/* GPIO0B_IOMUX_SEL_H */ +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_OFFSET (0xCU) +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_MASK (0xFU << BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_MASK (0xFU << BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_MASK (0xFU << BUS_IOC_GPIO0B_IOMUX_SEL_H_GPIO0B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0C_IOMUX_SEL_L */ +#define BUS_IOC_GPIO0C_IOMUX_SEL_L_OFFSET (0x10U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_MASK (0xFU << BUS_IOC_GPIO0C_IOMUX_SEL_L_GPIO0C0_SEL_SHIFT) /* 0x0000000F */ +/* GPIO0C_IOMUX_SEL_H */ +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_OFFSET (0x14U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_MASK (0xFU << BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_MASK (0xFU << BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_MASK (0xFU << BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_MASK (0xFU << BUS_IOC_GPIO0C_IOMUX_SEL_H_GPIO0C7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0D_IOMUX_SEL_L */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_OFFSET (0x18U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_L_GPIO0D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO0D_IOMUX_SEL_H */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_H_OFFSET (0x1CU) +#define BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_MASK (0xFU << BUS_IOC_GPIO0D_IOMUX_SEL_H_GPIO0D5_SEL_SHIFT) /* 0x000000F0 */ +/* GPIO1A_IOMUX_SEL_L */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_OFFSET (0x20U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A0_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A1_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A2_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A3_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_L_GPIO1A3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1A_IOMUX_SEL_H */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_OFFSET (0x24U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A4_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A5_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A6_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A7_SEL_MASK (0xFU << BUS_IOC_GPIO1A_IOMUX_SEL_H_GPIO1A7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1B_IOMUX_SEL_L */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_OFFSET (0x28U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B0_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B1_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B2_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B3_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_L_GPIO1B3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1B_IOMUX_SEL_H */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_OFFSET (0x2CU) +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B4_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B5_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B6_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B7_SEL_MASK (0xFU << BUS_IOC_GPIO1B_IOMUX_SEL_H_GPIO1B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1C_IOMUX_SEL_L */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_OFFSET (0x30U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C0_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C1_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C2_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C3_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_L_GPIO1C3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1C_IOMUX_SEL_H */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_OFFSET (0x34U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C4_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C5_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C6_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C7_SEL_MASK (0xFU << BUS_IOC_GPIO1C_IOMUX_SEL_H_GPIO1C7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1D_IOMUX_SEL_L */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_OFFSET (0x38U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D0_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D1_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D2_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D3_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_L_GPIO1D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO1D_IOMUX_SEL_H */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_OFFSET (0x3CU) +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D4_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D5_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D6_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D7_SEL_MASK (0xFU << BUS_IOC_GPIO1D_IOMUX_SEL_H_GPIO1D7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2A_IOMUX_SEL_L */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_OFFSET (0x40U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A0_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A1_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A2_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A3_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_L_GPIO2A3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2A_IOMUX_SEL_H */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_H_OFFSET (0x44U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A6_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A7_SEL_MASK (0xFU << BUS_IOC_GPIO2A_IOMUX_SEL_H_GPIO2A7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2B_IOMUX_SEL_L */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_OFFSET (0x48U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B0_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B1_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B2_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B3_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_L_GPIO2B3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2B_IOMUX_SEL_H */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_OFFSET (0x4CU) +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B4_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B5_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B6_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B7_SEL_MASK (0xFU << BUS_IOC_GPIO2B_IOMUX_SEL_H_GPIO2B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2C_IOMUX_SEL_L */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_OFFSET (0x50U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C0_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C1_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C2_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C3_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_L_GPIO2C3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2C_IOMUX_SEL_H */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_H_OFFSET (0x54U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C4_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C5_SEL_MASK (0xFU << BUS_IOC_GPIO2C_IOMUX_SEL_H_GPIO2C5_SEL_SHIFT) /* 0x000000F0 */ +/* GPIO2D_IOMUX_SEL_L */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_OFFSET (0x58U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D0_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D1_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D2_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D3_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_L_GPIO2D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO2D_IOMUX_SEL_H */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_OFFSET (0x5CU) +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D4_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D5_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D6_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D7_SEL_MASK (0xFU << BUS_IOC_GPIO2D_IOMUX_SEL_H_GPIO2D7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3A_IOMUX_SEL_L */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_OFFSET (0x60U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A0_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A1_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A2_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A3_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_L_GPIO3A3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3A_IOMUX_SEL_H */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_OFFSET (0x64U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A4_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A5_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A6_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A7_SEL_MASK (0xFU << BUS_IOC_GPIO3A_IOMUX_SEL_H_GPIO3A7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3B_IOMUX_SEL_L */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_OFFSET (0x68U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B0_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B1_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B2_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B3_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_L_GPIO3B3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3B_IOMUX_SEL_H */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_OFFSET (0x6CU) +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B4_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B5_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B6_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B7_SEL_MASK (0xFU << BUS_IOC_GPIO3B_IOMUX_SEL_H_GPIO3B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3C_IOMUX_SEL_L */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_OFFSET (0x70U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C0_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C1_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C2_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C3_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_L_GPIO3C3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3C_IOMUX_SEL_H */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_OFFSET (0x74U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C4_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C5_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C6_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C7_SEL_MASK (0xFU << BUS_IOC_GPIO3C_IOMUX_SEL_H_GPIO3C7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3D_IOMUX_SEL_L */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_OFFSET (0x78U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D0_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D1_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D2_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D3_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_L_GPIO3D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO3D_IOMUX_SEL_H */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_H_OFFSET (0x7CU) +#define BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D4_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D5_SEL_MASK (0xFU << BUS_IOC_GPIO3D_IOMUX_SEL_H_GPIO3D5_SEL_SHIFT) /* 0x000000F0 */ +/* GPIO4A_IOMUX_SEL_L */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_OFFSET (0x80U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A0_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A1_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A2_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A3_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_L_GPIO4A3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4A_IOMUX_SEL_H */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_OFFSET (0x84U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A4_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A5_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A6_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A7_SEL_MASK (0xFU << BUS_IOC_GPIO4A_IOMUX_SEL_H_GPIO4A7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4B_IOMUX_SEL_L */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_OFFSET (0x88U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B0_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B1_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B2_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B3_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_L_GPIO4B3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4B_IOMUX_SEL_H */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_OFFSET (0x8CU) +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B4_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B5_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B6_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B6_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B7_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B7_SEL_MASK (0xFU << BUS_IOC_GPIO4B_IOMUX_SEL_H_GPIO4B7_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4C_IOMUX_SEL_L */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_OFFSET (0x90U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C0_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C1_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C2_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C3_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_L_GPIO4C3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4C_IOMUX_SEL_H */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_OFFSET (0x94U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C4_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C5_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C5_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C6_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C6_SEL_MASK (0xFU << BUS_IOC_GPIO4C_IOMUX_SEL_H_GPIO4C6_SEL_SHIFT) /* 0x00000F00 */ +/* GPIO4D_IOMUX_SEL_L */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_OFFSET (0x98U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D0_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D0_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D0_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D1_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D1_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D1_SEL_SHIFT) /* 0x000000F0 */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D2_SEL_SHIFT (8U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D2_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D2_SEL_SHIFT) /* 0x00000F00 */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D3_SEL_SHIFT (12U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D3_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_L_GPIO4D3_SEL_SHIFT) /* 0x0000F000 */ +/* GPIO4D_IOMUX_SEL_H */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_H_OFFSET (0x9CU) +#define BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D4_SEL_SHIFT (0U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D4_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D4_SEL_SHIFT) /* 0x0000000F */ +#define BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D5_SEL_SHIFT (4U) +#define BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D5_SEL_MASK (0xFU << BUS_IOC_GPIO4D_IOMUX_SEL_H_GPIO4D5_SEL_SHIFT) /* 0x000000F0 */ +/******************************************UART******************************************/ +/* RBR */ +#define UART_RBR_OFFSET (0x0U) +#define UART_RBR (0x0U) +#define UART_RBR_DATA_INPUT_SHIFT (0U) +#define UART_RBR_DATA_INPUT_MASK (0xFFU << UART_RBR_DATA_INPUT_SHIFT) /* 0x000000FF */ +/* DLL */ +#define UART_DLL_OFFSET (0x0U) +#define UART_DLL_BAUD_RATE_DIVISOR_L_SHIFT (0U) +#define UART_DLL_BAUD_RATE_DIVISOR_L_MASK (0xFFU << UART_DLL_BAUD_RATE_DIVISOR_L_SHIFT) /* 0x000000FF */ +/* THR */ +#define UART_THR_OFFSET (0x0U) +#define UART_THR_DATA_OUTPUT_SHIFT (0U) +#define UART_THR_DATA_OUTPUT_MASK (0xFFU << UART_THR_DATA_OUTPUT_SHIFT) /* 0x000000FF */ +/* DLH */ +#define UART_DLH_OFFSET (0x4U) +#define UART_DLH_BAUD_RATE_DIVISOR_H_SHIFT (0U) +#define UART_DLH_BAUD_RATE_DIVISOR_H_MASK (0xFFU << UART_DLH_BAUD_RATE_DIVISOR_H_SHIFT) /* 0x000000FF */ +/* IER */ +#define UART_IER_OFFSET (0x4U) +#define UART_IER_RECEIVE_DATA_AVAILABLE_INT_EN_SHIFT (0U) +#define UART_IER_RECEIVE_DATA_AVAILABLE_INT_EN_MASK (0x1U << UART_IER_RECEIVE_DATA_AVAILABLE_INT_EN_SHIFT) /* 0x00000001 */ +#define UART_IER_TRANS_HOLD_EMPTY_INT_EN_SHIFT (1U) +#define UART_IER_TRANS_HOLD_EMPTY_INT_EN_MASK (0x1U << UART_IER_TRANS_HOLD_EMPTY_INT_EN_SHIFT) /* 0x00000002 */ +#define UART_IER_RECEIVE_LINE_STATUS_INT_EN_SHIFT (2U) +#define UART_IER_RECEIVE_LINE_STATUS_INT_EN_MASK (0x1U << UART_IER_RECEIVE_LINE_STATUS_INT_EN_SHIFT) /* 0x00000004 */ +#define UART_IER_MODEM_STATUS_INT_EN_SHIFT (3U) +#define UART_IER_MODEM_STATUS_INT_EN_MASK (0x1U << UART_IER_MODEM_STATUS_INT_EN_SHIFT) /* 0x00000008 */ +#define UART_IER_PROG_THRE_INT_EN_SHIFT (7U) +#define UART_IER_PROG_THRE_INT_EN_MASK (0x1U << UART_IER_PROG_THRE_INT_EN_SHIFT) /* 0x00000080 */ +/* FCR */ +#define UART_FCR_OFFSET (0x8U) +#define UART_FCR_FIFO_EN_SHIFT (0U) +#define UART_FCR_FIFO_EN_MASK (0x1U << UART_FCR_FIFO_EN_SHIFT) /* 0x00000001 */ +#define UART_FCR_RCVR_FIFO_RESET_SHIFT (1U) +#define UART_FCR_RCVR_FIFO_RESET_MASK (0x1U << UART_FCR_RCVR_FIFO_RESET_SHIFT) /* 0x00000002 */ +#define UART_FCR_XMIT_FIFO_RESET_SHIFT (2U) +#define UART_FCR_XMIT_FIFO_RESET_MASK (0x1U << UART_FCR_XMIT_FIFO_RESET_SHIFT) /* 0x00000004 */ +#define UART_FCR_DMA_MODE_SHIFT (3U) +#define UART_FCR_DMA_MODE_MASK (0x1U << UART_FCR_DMA_MODE_SHIFT) /* 0x00000008 */ +#define UART_FCR_TX_EMPTY_TRIGGER_SHIFT (4U) +#define UART_FCR_TX_EMPTY_TRIGGER_MASK (0x3U << UART_FCR_TX_EMPTY_TRIGGER_SHIFT) /* 0x00000030 */ +#define UART_FCR_RCVR_TRIGGER_SHIFT (6U) +#define UART_FCR_RCVR_TRIGGER_MASK (0x3U << UART_FCR_RCVR_TRIGGER_SHIFT) /* 0x000000C0 */ +/* IIR */ +#define UART_IIR_OFFSET (0x8U) +#define UART_IIR (0x1U) +#define UART_IIR_INT_ID_SHIFT (0U) +#define UART_IIR_INT_ID_MASK (0xFU << UART_IIR_INT_ID_SHIFT) /* 0x0000000F */ +#define UART_IIR_FIFOS_EN_SHIFT (6U) +#define UART_IIR_FIFOS_EN_MASK (0x3U << UART_IIR_FIFOS_EN_SHIFT) /* 0x000000C0 */ +/* LCR */ +#define UART_LCR_OFFSET (0xCU) +#define UART_LCR_DATA_LENGTH_SEL_SHIFT (0U) +#define UART_LCR_DATA_LENGTH_SEL_MASK (0x3U << UART_LCR_DATA_LENGTH_SEL_SHIFT) /* 0x00000003 */ +#define UART_LCR_STOP_BITS_NUM_SHIFT (2U) +#define UART_LCR_STOP_BITS_NUM_MASK (0x1U << UART_LCR_STOP_BITS_NUM_SHIFT) /* 0x00000004 */ +#define UART_LCR_PARITY_EN_SHIFT (3U) +#define UART_LCR_PARITY_EN_MASK (0x1U << UART_LCR_PARITY_EN_SHIFT) /* 0x00000008 */ +#define UART_LCR_EVEN_PARITY_SEL_SHIFT (4U) +#define UART_LCR_EVEN_PARITY_SEL_MASK (0x1U << UART_LCR_EVEN_PARITY_SEL_SHIFT) /* 0x00000010 */ +#define UART_LCR_STICK_PARITY_SHIFT (5U) +#define UART_LCR_STICK_PARITY_MASK (0x1U << UART_LCR_STICK_PARITY_SHIFT) /* 0x00000020 */ +#define UART_LCR_BREAK_CTRL_SHIFT (6U) +#define UART_LCR_BREAK_CTRL_MASK (0x1U << UART_LCR_BREAK_CTRL_SHIFT) /* 0x00000040 */ +#define UART_LCR_DIV_LAT_ACCESS_SHIFT (7U) +#define UART_LCR_DIV_LAT_ACCESS_MASK (0x1U << UART_LCR_DIV_LAT_ACCESS_SHIFT) /* 0x00000080 */ +/* MCR */ +#define UART_MCR_OFFSET (0x10U) +#define UART_MCR_DATA_TERMINAL_READY_SHIFT (0U) +#define UART_MCR_DATA_TERMINAL_READY_MASK (0x1U << UART_MCR_DATA_TERMINAL_READY_SHIFT) /* 0x00000001 */ +#define UART_MCR_REQ_TO_SEND_SHIFT (1U) +#define UART_MCR_REQ_TO_SEND_MASK (0x1U << UART_MCR_REQ_TO_SEND_SHIFT) /* 0x00000002 */ +#define UART_MCR_OUT1_SHIFT (2U) +#define UART_MCR_OUT1_MASK (0x1U << UART_MCR_OUT1_SHIFT) /* 0x00000004 */ +#define UART_MCR_OUT2_SHIFT (3U) +#define UART_MCR_OUT2_MASK (0x1U << UART_MCR_OUT2_SHIFT) /* 0x00000008 */ +#define UART_MCR_LOOPBACK_SHIFT (4U) +#define UART_MCR_LOOPBACK_MASK (0x1U << UART_MCR_LOOPBACK_SHIFT) /* 0x00000010 */ +#define UART_MCR_AUTO_FLOW_CTRL_EN_SHIFT (5U) +#define UART_MCR_AUTO_FLOW_CTRL_EN_MASK (0x1U << UART_MCR_AUTO_FLOW_CTRL_EN_SHIFT) /* 0x00000020 */ +#define UART_MCR_SIR_MODE_EN_SHIFT (6U) +#define UART_MCR_SIR_MODE_EN_MASK (0x1U << UART_MCR_SIR_MODE_EN_SHIFT) /* 0x00000040 */ +/* LSR */ +#define UART_LSR_OFFSET (0x14U) +#define UART_LSR (0x60U) +#define UART_LSR_DATA_READY_SHIFT (0U) +#define UART_LSR_DATA_READY_MASK (0x1U << UART_LSR_DATA_READY_SHIFT) /* 0x00000001 */ +#define UART_LSR_OVERRUN_ERROR_SHIFT (1U) +#define UART_LSR_OVERRUN_ERROR_MASK (0x1U << UART_LSR_OVERRUN_ERROR_SHIFT) /* 0x00000002 */ +#define UART_LSR_PARITY_ERROR_SHIFT (2U) +#define UART_LSR_PARITY_ERROR_MASK (0x1U << UART_LSR_PARITY_ERROR_SHIFT) /* 0x00000004 */ +#define UART_LSR_FRAMING_ERROR_SHIFT (3U) +#define UART_LSR_FRAMING_ERROR_MASK (0x1U << UART_LSR_FRAMING_ERROR_SHIFT) /* 0x00000008 */ +#define UART_LSR_BREAK_INT_SHIFT (4U) +#define UART_LSR_BREAK_INT_MASK (0x1U << UART_LSR_BREAK_INT_SHIFT) /* 0x00000010 */ +#define UART_LSR_TRANS_HOLD_REG_EMPTY_SHIFT (5U) +#define UART_LSR_TRANS_HOLD_REG_EMPTY_MASK (0x1U << UART_LSR_TRANS_HOLD_REG_EMPTY_SHIFT) /* 0x00000020 */ +#define UART_LSR_TRANS_EMPTY_SHIFT (6U) +#define UART_LSR_TRANS_EMPTY_MASK (0x1U << UART_LSR_TRANS_EMPTY_SHIFT) /* 0x00000040 */ +#define UART_LSR_RECEIVER_FIFO_ERROR_SHIFT (7U) +#define UART_LSR_RECEIVER_FIFO_ERROR_MASK (0x1U << UART_LSR_RECEIVER_FIFO_ERROR_SHIFT) /* 0x00000080 */ +/* MSR */ +#define UART_MSR_OFFSET (0x18U) +#define UART_MSR (0x0U) +#define UART_MSR_DELTA_CLEAR_TO_SEND_SHIFT (0U) +#define UART_MSR_DELTA_CLEAR_TO_SEND_MASK (0x1U << UART_MSR_DELTA_CLEAR_TO_SEND_SHIFT) /* 0x00000001 */ +#define UART_MSR_DELTA_DATA_SET_READY_SHIFT (1U) +#define UART_MSR_DELTA_DATA_SET_READY_MASK (0x1U << UART_MSR_DELTA_DATA_SET_READY_SHIFT) /* 0x00000002 */ +#define UART_MSR_TRAILING_EDGE_RING_INDICATOR_SHIFT (2U) +#define UART_MSR_TRAILING_EDGE_RING_INDICATOR_MASK (0x1U << UART_MSR_TRAILING_EDGE_RING_INDICATOR_SHIFT) /* 0x00000004 */ +#define UART_MSR_DELTA_DATA_CARRIER_DETECT_SHIFT (3U) +#define UART_MSR_DELTA_DATA_CARRIER_DETECT_MASK (0x1U << UART_MSR_DELTA_DATA_CARRIER_DETECT_SHIFT) /* 0x00000008 */ +#define UART_MSR_CLEAR_TO_SEND_SHIFT (4U) +#define UART_MSR_CLEAR_TO_SEND_MASK (0x1U << UART_MSR_CLEAR_TO_SEND_SHIFT) /* 0x00000010 */ +#define UART_MSR_DATA_SET_READY_SHIFT (5U) +#define UART_MSR_DATA_SET_READY_MASK (0x1U << UART_MSR_DATA_SET_READY_SHIFT) /* 0x00000020 */ +#define UART_MSR_RING_INDICATOR_SHIFT (6U) +#define UART_MSR_RING_INDICATOR_MASK (0x1U << UART_MSR_RING_INDICATOR_SHIFT) /* 0x00000040 */ +#define UART_MSR_DATA_CARRIOR_DETECT_SHIFT (7U) +#define UART_MSR_DATA_CARRIOR_DETECT_MASK (0x1U << UART_MSR_DATA_CARRIOR_DETECT_SHIFT) /* 0x00000080 */ +/* SCR */ +#define UART_SCR_OFFSET (0x1CU) +#define UART_SCR_TEMP_STORE_SPACE_SHIFT (0U) +#define UART_SCR_TEMP_STORE_SPACE_MASK (0xFFU << UART_SCR_TEMP_STORE_SPACE_SHIFT) /* 0x000000FF */ +/* SRBR */ +#define UART_SRBR_OFFSET (0x30U) +#define UART_SRBR (0x0U) +#define UART_SRBR_SHADOW_RBR_SHIFT (0U) +#define UART_SRBR_SHADOW_RBR_MASK (0xFFU << UART_SRBR_SHADOW_RBR_SHIFT) /* 0x000000FF */ +/* STHR */ +#define UART_STHR_OFFSET (0x30U) +#define UART_STHR_SHADOW_THR_SHIFT (0U) +#define UART_STHR_SHADOW_THR_MASK (0xFFU << UART_STHR_SHADOW_THR_SHIFT) /* 0x000000FF */ +/* FAR */ +#define UART_FAR_OFFSET (0x70U) +#define UART_FAR_FIFO_ACCESS_TEST_EN_SHIFT (0U) +#define UART_FAR_FIFO_ACCESS_TEST_EN_MASK (0x1U << UART_FAR_FIFO_ACCESS_TEST_EN_SHIFT) /* 0x00000001 */ +/* TFR */ +#define UART_TFR_OFFSET (0x74U) +#define UART_TFR (0x0U) +#define UART_TFR_TRANS_FIFO_READ_SHIFT (0U) +#define UART_TFR_TRANS_FIFO_READ_MASK (0xFFU << UART_TFR_TRANS_FIFO_READ_SHIFT) /* 0x000000FF */ +/* RFW */ +#define UART_RFW_OFFSET (0x78U) +#define UART_RFW_RECEIVE_FIFO_WRITE_SHIFT (0U) +#define UART_RFW_RECEIVE_FIFO_WRITE_MASK (0xFFU << UART_RFW_RECEIVE_FIFO_WRITE_SHIFT) /* 0x000000FF */ +#define UART_RFW_RECEIVE_FIFO_PARITY_ERROR_SHIFT (8U) +#define UART_RFW_RECEIVE_FIFO_PARITY_ERROR_MASK (0x1U << UART_RFW_RECEIVE_FIFO_PARITY_ERROR_SHIFT) /* 0x00000100 */ +#define UART_RFW_RECEIVE_FIFO_FRAMING_ERROR_SHIFT (9U) +#define UART_RFW_RECEIVE_FIFO_FRAMING_ERROR_MASK (0x1U << UART_RFW_RECEIVE_FIFO_FRAMING_ERROR_SHIFT) /* 0x00000200 */ +/* USR */ +#define UART_USR_OFFSET (0x7CU) +#define UART_USR (0x6U) +#define UART_USR_UART_BUSY_SHIFT (0U) +#define UART_USR_UART_BUSY_MASK (0x1U << UART_USR_UART_BUSY_SHIFT) /* 0x00000001 */ +#define UART_USR_TRANS_FIFO_NOT_FULL_SHIFT (1U) +#define UART_USR_TRANS_FIFO_NOT_FULL_MASK (0x1U << UART_USR_TRANS_FIFO_NOT_FULL_SHIFT) /* 0x00000002 */ +#define UART_USR_TRASN_FIFO_EMPTY_SHIFT (2U) +#define UART_USR_TRASN_FIFO_EMPTY_MASK (0x1U << UART_USR_TRASN_FIFO_EMPTY_SHIFT) /* 0x00000004 */ +#define UART_USR_RECEIVE_FIFO_NOT_EMPTY_SHIFT (3U) +#define UART_USR_RECEIVE_FIFO_NOT_EMPTY_MASK (0x1U << UART_USR_RECEIVE_FIFO_NOT_EMPTY_SHIFT) /* 0x00000008 */ +#define UART_USR_RECEIVE_FIFO_FULL_SHIFT (4U) +#define UART_USR_RECEIVE_FIFO_FULL_MASK (0x1U << UART_USR_RECEIVE_FIFO_FULL_SHIFT) /* 0x00000010 */ +/* TFL */ +#define UART_TFL_OFFSET (0x80U) +#define UART_TFL (0x0U) +#define UART_TFL_TRANS_FIFO_LEVEL_SHIFT (0U) +#define UART_TFL_TRANS_FIFO_LEVEL_MASK (0x3FU << UART_TFL_TRANS_FIFO_LEVEL_SHIFT) /* 0x0000003F */ +/* RFL */ +#define UART_RFL_OFFSET (0x84U) +#define UART_RFL (0x0U) +#define UART_RFL_RECEIVE_FIFO_LEVEL_SHIFT (0U) +#define UART_RFL_RECEIVE_FIFO_LEVEL_MASK (0x3FU << UART_RFL_RECEIVE_FIFO_LEVEL_SHIFT) /* 0x0000003F */ +/* SRR */ +#define UART_SRR_OFFSET (0x88U) +#define UART_SRR_UART_RESET_SHIFT (0U) +#define UART_SRR_UART_RESET_MASK (0x1U << UART_SRR_UART_RESET_SHIFT) /* 0x00000001 */ +#define UART_SRR_RCVR_FIFO_RESET_SHIFT (1U) +#define UART_SRR_RCVR_FIFO_RESET_MASK (0x1U << UART_SRR_RCVR_FIFO_RESET_SHIFT) /* 0x00000002 */ +#define UART_SRR_XMIT_FIFO_RESET_SHIFT (2U) +#define UART_SRR_XMIT_FIFO_RESET_MASK (0x1U << UART_SRR_XMIT_FIFO_RESET_SHIFT) /* 0x00000004 */ +/* SRTS */ +#define UART_SRTS_OFFSET (0x8CU) +#define UART_SRTS_SHADOW_REQ_TO_SEND_SHIFT (0U) +#define UART_SRTS_SHADOW_REQ_TO_SEND_MASK (0x1U << UART_SRTS_SHADOW_REQ_TO_SEND_SHIFT) /* 0x00000001 */ +/* SBCR */ +#define UART_SBCR_OFFSET (0x90U) +#define UART_SBCR_SHADOW_BREAK_CTRL_SHIFT (0U) +#define UART_SBCR_SHADOW_BREAK_CTRL_MASK (0x1U << UART_SBCR_SHADOW_BREAK_CTRL_SHIFT) /* 0x00000001 */ +/* SDMAM */ +#define UART_SDMAM_OFFSET (0x94U) +#define UART_SDMAM_SHADOW_DMA_MODE_SHIFT (0U) +#define UART_SDMAM_SHADOW_DMA_MODE_MASK (0x1U << UART_SDMAM_SHADOW_DMA_MODE_SHIFT) /* 0x00000001 */ +/* SFE */ +#define UART_SFE_OFFSET (0x98U) +#define UART_SFE_SHADOW_FIFO_EN_SHIFT (0U) +#define UART_SFE_SHADOW_FIFO_EN_MASK (0x1U << UART_SFE_SHADOW_FIFO_EN_SHIFT) /* 0x00000001 */ +/* SRT */ +#define UART_SRT_OFFSET (0x9CU) +#define UART_SRT_SHADOW_RCVR_TRIGGER_SHIFT (0U) +#define UART_SRT_SHADOW_RCVR_TRIGGER_MASK (0x3U << UART_SRT_SHADOW_RCVR_TRIGGER_SHIFT) /* 0x00000003 */ +/* STET */ +#define UART_STET_OFFSET (0xA0U) +#define UART_STET_SHADOW_TX_EMPTY_TRIGGER_SHIFT (0U) +#define UART_STET_SHADOW_TX_EMPTY_TRIGGER_MASK (0x3U << UART_STET_SHADOW_TX_EMPTY_TRIGGER_SHIFT) /* 0x00000003 */ +/* HTX */ +#define UART_HTX_OFFSET (0xA4U) +#define UART_HTX_HALT_TX_EN_SHIFT (0U) +#define UART_HTX_HALT_TX_EN_MASK (0x1U << UART_HTX_HALT_TX_EN_SHIFT) /* 0x00000001 */ +/* DMASA */ +#define UART_DMASA_OFFSET (0xA8U) +#define UART_DMASA_DMA_SOFTWARE_ACK_SHIFT (0U) +#define UART_DMASA_DMA_SOFTWARE_ACK_MASK (0x1U << UART_DMASA_DMA_SOFTWARE_ACK_SHIFT) /* 0x00000001 */ +/* CPR */ +#define UART_CPR_OFFSET (0xF4U) +#define UART_CPR (0x43FF2U) +#define UART_CPR_APB_DATA_WIDTH_SHIFT (0U) +#define UART_CPR_APB_DATA_WIDTH_MASK (0x3U << UART_CPR_APB_DATA_WIDTH_SHIFT) /* 0x00000003 */ +#define UART_CPR_AFCE_MODE_SHIFT (4U) +#define UART_CPR_AFCE_MODE_MASK (0x1U << UART_CPR_AFCE_MODE_SHIFT) /* 0x00000010 */ +#define UART_CPR_THRE_MODE_SHIFT (5U) +#define UART_CPR_THRE_MODE_MASK (0x1U << UART_CPR_THRE_MODE_SHIFT) /* 0x00000020 */ +#define UART_CPR_SIR_MODE_SHIFT (6U) +#define UART_CPR_SIR_MODE_MASK (0x1U << UART_CPR_SIR_MODE_SHIFT) /* 0x00000040 */ +#define UART_CPR_SIR_LP_MODE_SHIFT (7U) +#define UART_CPR_SIR_LP_MODE_MASK (0x1U << UART_CPR_SIR_LP_MODE_SHIFT) /* 0x00000080 */ +#define UART_CPR_NEW_FEAT_SHIFT (8U) +#define UART_CPR_NEW_FEAT_MASK (0x1U << UART_CPR_NEW_FEAT_SHIFT) /* 0x00000100 */ +#define UART_CPR_FIFO_ACCESS_SHIFT (9U) +#define UART_CPR_FIFO_ACCESS_MASK (0x1U << UART_CPR_FIFO_ACCESS_SHIFT) /* 0x00000200 */ +#define UART_CPR_FIFO_STAT_SHIFT (10U) +#define UART_CPR_FIFO_STAT_MASK (0x1U << UART_CPR_FIFO_STAT_SHIFT) /* 0x00000400 */ +#define UART_CPR_SHADOW_SHIFT (11U) +#define UART_CPR_SHADOW_MASK (0x1U << UART_CPR_SHADOW_SHIFT) /* 0x00000800 */ +#define UART_CPR_UART_ADD_ENCODED_PARAMS_SHIFT (12U) +#define UART_CPR_UART_ADD_ENCODED_PARAMS_MASK (0x1U << UART_CPR_UART_ADD_ENCODED_PARAMS_SHIFT) /* 0x00001000 */ +#define UART_CPR_DMA_EXTRA_SHIFT (13U) +#define UART_CPR_DMA_EXTRA_MASK (0x1U << UART_CPR_DMA_EXTRA_SHIFT) /* 0x00002000 */ +#define UART_CPR_FIFO_MODE_SHIFT (16U) +#define UART_CPR_FIFO_MODE_MASK (0xFFU << UART_CPR_FIFO_MODE_SHIFT) /* 0x00FF0000 */ +/* UCV */ +#define UART_UCV_OFFSET (0xF8U) +#define UART_UCV (0x3430322AU) +#define UART_UCV_VER_SHIFT (0U) +#define UART_UCV_VER_MASK (0xFFFFFFFFU << UART_UCV_VER_SHIFT) /* 0xFFFFFFFF */ +/* CTR */ +#define UART_CTR_OFFSET (0xFCU) +#define UART_CTR (0x44570110U) +#define UART_CTR_PERIPHERAL_ID_SHIFT (0U) +#define UART_CTR_PERIPHERAL_ID_MASK (0xFFFFFFFFU << UART_CTR_PERIPHERAL_ID_SHIFT) /* 0xFFFFFFFF */ +/******************************************WDT*******************************************/ +/* CR */ +#define WDT_CR_OFFSET (0x0U) +#define WDT_CR_EN_SHIFT (0U) +#define WDT_CR_EN_MASK (0x1U << WDT_CR_EN_SHIFT) /* 0x00000001 */ +#define WDT_CR_RESP_MODE_SHIFT (1U) +#define WDT_CR_RESP_MODE_MASK (0x1U << WDT_CR_RESP_MODE_SHIFT) /* 0x00000002 */ +#define WDT_CR_RST_PLUSE_LENGTH_SHIFT (2U) +#define WDT_CR_RST_PLUSE_LENGTH_MASK (0x7U << WDT_CR_RST_PLUSE_LENGTH_SHIFT) /* 0x0000001C */ +/* TORR */ +#define WDT_TORR_OFFSET (0x4U) +#define WDT_TORR_TIMEOUT_PERIOD_SHIFT (0U) +#define WDT_TORR_TIMEOUT_PERIOD_MASK (0xFU << WDT_TORR_TIMEOUT_PERIOD_SHIFT) /* 0x0000000F */ +/* CCVR */ +#define WDT_CCVR_OFFSET (0x8U) +#define WDT_CCVR (0xFFFFU) +#define WDT_CCVR_CUR_CNT_SHIFT (0U) +#define WDT_CCVR_CUR_CNT_MASK (0xFFFFFFFFU << WDT_CCVR_CUR_CNT_SHIFT) /* 0xFFFFFFFF */ +/* CRR */ +#define WDT_CRR_OFFSET (0xCU) +#define WDT_CRR_CNT_RESTART_SHIFT (0U) +#define WDT_CRR_CNT_RESTART_MASK (0xFFU << WDT_CRR_CNT_RESTART_SHIFT) /* 0x000000FF */ +/* STAT */ +#define WDT_STAT_OFFSET (0x10U) +#define WDT_STAT (0x0U) +#define WDT_STAT_STATUS_SHIFT (0U) +#define WDT_STAT_STATUS_MASK (0x1U << WDT_STAT_STATUS_SHIFT) /* 0x00000001 */ +/* EOI */ +#define WDT_EOI_OFFSET (0x14U) +#define WDT_EOI (0x0U) +#define WDT_EOI_INT_CLR_SHIFT (0U) +#define WDT_EOI_INT_CLR_MASK (0x1U << WDT_EOI_INT_CLR_SHIFT) /* 0x00000001 */ +/*****************************************TIMER******************************************/ +/* LOAD_COUNT0 */ +#define TIMER_LOAD_COUNT0_OFFSET (0x0U) +#define TIMER_LOAD_COUNT0_COUNT0_SHIFT (0U) +#define TIMER_LOAD_COUNT0_COUNT0_MASK (0xFFFFFFFFU << TIMER_LOAD_COUNT0_COUNT0_SHIFT) /* 0xFFFFFFFF */ +/* LOAD_COUNT1 */ +#define TIMER_LOAD_COUNT1_OFFSET (0x4U) +#define TIMER_LOAD_COUNT1_COUNT1_SHIFT (0U) +#define TIMER_LOAD_COUNT1_COUNT1_MASK (0xFFFFFFFFU << TIMER_LOAD_COUNT1_COUNT1_SHIFT) /* 0xFFFFFFFF */ +/* CURRENT_VALUE0 */ +#define TIMER_CURRENT_VALUE0_OFFSET (0x8U) +#define TIMER_CURRENT_VALUE0 (0x0U) +#define TIMER_CURRENT_VALUE0_CURRENT_VALUE0_SHIFT (0U) +#define TIMER_CURRENT_VALUE0_CURRENT_VALUE0_MASK (0xFFFFFFFFU << TIMER_CURRENT_VALUE0_CURRENT_VALUE0_SHIFT) /* 0xFFFFFFFF */ +/* CURRENT_VALUE1 */ +#define TIMER_CURRENT_VALUE1_OFFSET (0xCU) +#define TIMER_CURRENT_VALUE1 (0x0U) +#define TIMER_CURRENT_VALUE1_CURRENT_VALUE1_SHIFT (0U) +#define TIMER_CURRENT_VALUE1_CURRENT_VALUE1_MASK (0xFFFFFFFFU << TIMER_CURRENT_VALUE1_CURRENT_VALUE1_SHIFT) /* 0xFFFFFFFF */ +/* CONTROLREG */ +#define TIMER_CONTROLREG_OFFSET (0x10U) +#define TIMER_CONTROLREG_TIMER_ENABLE_SHIFT (0U) +#define TIMER_CONTROLREG_TIMER_ENABLE_MASK (0x1U << TIMER_CONTROLREG_TIMER_ENABLE_SHIFT) /* 0x00000001 */ +#define TIMER_CONTROLREG_TIMER_MODE_SHIFT (1U) +#define TIMER_CONTROLREG_TIMER_MODE_MASK (0x1U << TIMER_CONTROLREG_TIMER_MODE_SHIFT) /* 0x00000002 */ +#define TIMER_CONTROLREG_TIMER_INT_MASK_SHIFT (2U) +#define TIMER_CONTROLREG_TIMER_INT_MASK_MASK (0x1U << TIMER_CONTROLREG_TIMER_INT_MASK_SHIFT) /* 0x00000004 */ +/* INTSTATUS */ +#define TIMER_INTSTATUS_OFFSET (0x18U) +#define TIMER_INTSTATUS_INT_PD_SHIFT (0U) +#define TIMER_INTSTATUS_INT_PD_MASK (0x1U << TIMER_INTSTATUS_INT_PD_SHIFT) /* 0x00000001 */ +/******************************************FSPI******************************************/ +/* CTRL0 */ +#define FSPI_CTRL0_OFFSET (0x0U) +#define FSPI_CTRL0_SPIM_SHIFT (0U) +#define FSPI_CTRL0_SPIM_MASK (0x1U << FSPI_CTRL0_SPIM_SHIFT) /* 0x00000001 */ +#define FSPI_CTRL0_SHIFTPHASE_SHIFT (1U) +#define FSPI_CTRL0_SHIFTPHASE_MASK (0x1U << FSPI_CTRL0_SHIFTPHASE_SHIFT) /* 0x00000002 */ +#define FSPI_CTRL0_IDLE_CYCLE_SHIFT (4U) +#define FSPI_CTRL0_IDLE_CYCLE_MASK (0xFU << FSPI_CTRL0_IDLE_CYCLE_SHIFT) /* 0x000000F0 */ +#define FSPI_CTRL0_CMDB_SHIFT (8U) +#define FSPI_CTRL0_CMDB_MASK (0x3U << FSPI_CTRL0_CMDB_SHIFT) /* 0x00000300 */ +#define FSPI_CTRL0_ADRB_SHIFT (10U) +#define FSPI_CTRL0_ADRB_MASK (0x3U << FSPI_CTRL0_ADRB_SHIFT) /* 0x00000C00 */ +#define FSPI_CTRL0_DATB_SHIFT (12U) +#define FSPI_CTRL0_DATB_MASK (0x3U << FSPI_CTRL0_DATB_SHIFT) /* 0x00003000 */ +/* IMR */ +#define FSPI_IMR_OFFSET (0x4U) +#define FSPI_IMR_RXFM_SHIFT (0U) +#define FSPI_IMR_RXFM_MASK (0x1U << FSPI_IMR_RXFM_SHIFT) /* 0x00000001 */ +#define FSPI_IMR_RXUM_SHIFT (1U) +#define FSPI_IMR_RXUM_MASK (0x1U << FSPI_IMR_RXUM_SHIFT) /* 0x00000002 */ +#define FSPI_IMR_TXOM_SHIFT (2U) +#define FSPI_IMR_TXOM_MASK (0x1U << FSPI_IMR_TXOM_SHIFT) /* 0x00000004 */ +#define FSPI_IMR_TXEM_SHIFT (3U) +#define FSPI_IMR_TXEM_MASK (0x1U << FSPI_IMR_TXEM_SHIFT) /* 0x00000008 */ +#define FSPI_IMR_TRANSM_SHIFT (4U) +#define FSPI_IMR_TRANSM_MASK (0x1U << FSPI_IMR_TRANSM_SHIFT) /* 0x00000010 */ +#define FSPI_IMR_AHBM_SHIFT (5U) +#define FSPI_IMR_AHBM_MASK (0x1U << FSPI_IMR_AHBM_SHIFT) /* 0x00000020 */ +#define FSPI_IMR_NSPIM_SHIFT (6U) +#define FSPI_IMR_NSPIM_MASK (0x1U << FSPI_IMR_NSPIM_SHIFT) /* 0x00000040 */ +#define FSPI_IMR_DMAM_SHIFT (7U) +#define FSPI_IMR_DMAM_MASK (0x1U << FSPI_IMR_DMAM_SHIFT) /* 0x00000080 */ +/* ICLR */ +#define FSPI_ICLR_OFFSET (0x8U) +#define FSPI_ICLR_RXFC_SHIFT (0U) +#define FSPI_ICLR_RXFC_MASK (0x1U << FSPI_ICLR_RXFC_SHIFT) /* 0x00000001 */ +#define FSPI_ICLR_RXUC_SHIFT (1U) +#define FSPI_ICLR_RXUC_MASK (0x1U << FSPI_ICLR_RXUC_SHIFT) /* 0x00000002 */ +#define FSPI_ICLR_TXOC_SHIFT (2U) +#define FSPI_ICLR_TXOC_MASK (0x1U << FSPI_ICLR_TXOC_SHIFT) /* 0x00000004 */ +#define FSPI_ICLR_TXEC_SHIFT (3U) +#define FSPI_ICLR_TXEC_MASK (0x1U << FSPI_ICLR_TXEC_SHIFT) /* 0x00000008 */ +#define FSPI_ICLR_TRANSC_SHIFT (4U) +#define FSPI_ICLR_TRANSC_MASK (0x1U << FSPI_ICLR_TRANSC_SHIFT) /* 0x00000010 */ +#define FSPI_ICLR_AHBC_SHIFT (5U) +#define FSPI_ICLR_AHBC_MASK (0x1U << FSPI_ICLR_AHBC_SHIFT) /* 0x00000020 */ +#define FSPI_ICLR_NSPIC_SHIFT (6U) +#define FSPI_ICLR_NSPIC_MASK (0x1U << FSPI_ICLR_NSPIC_SHIFT) /* 0x00000040 */ +#define FSPI_ICLR_DMAC_SHIFT (7U) +#define FSPI_ICLR_DMAC_MASK (0x1U << FSPI_ICLR_DMAC_SHIFT) /* 0x00000080 */ +/* FTLR */ +#define FSPI_FTLR_OFFSET (0xCU) +#define FSPI_FTLR_TXFTLR_SHIFT (0U) +#define FSPI_FTLR_TXFTLR_MASK (0xFFU << FSPI_FTLR_TXFTLR_SHIFT) /* 0x000000FF */ +#define FSPI_FTLR_RXFTLR_SHIFT (8U) +#define FSPI_FTLR_RXFTLR_MASK (0xFFU << FSPI_FTLR_RXFTLR_SHIFT) /* 0x0000FF00 */ +/* RCVR */ +#define FSPI_RCVR_OFFSET (0x10U) +#define FSPI_RCVR_RCVR_SHIFT (0U) +#define FSPI_RCVR_RCVR_MASK (0x1U << FSPI_RCVR_RCVR_SHIFT) /* 0x00000001 */ +/* AX0 */ +#define FSPI_AX0_OFFSET (0x14U) +#define FSPI_AX0_AX_SHIFT (0U) +#define FSPI_AX0_AX_MASK (0xFFU << FSPI_AX0_AX_SHIFT) /* 0x000000FF */ +/* ABIT0 */ +#define FSPI_ABIT0_OFFSET (0x18U) +#define FSPI_ABIT0_ABIT_SHIFT (0U) +#define FSPI_ABIT0_ABIT_MASK (0x1FU << FSPI_ABIT0_ABIT_SHIFT) /* 0x0000001F */ +/* ISR */ +#define FSPI_ISR_OFFSET (0x1CU) +#define FSPI_ISR_RXFS_SHIFT (0U) +#define FSPI_ISR_RXFS_MASK (0x1U << FSPI_ISR_RXFS_SHIFT) /* 0x00000001 */ +#define FSPI_ISR_RXUS_SHIFT (1U) +#define FSPI_ISR_RXUS_MASK (0x1U << FSPI_ISR_RXUS_SHIFT) /* 0x00000002 */ +#define FSPI_ISR_TXOS_SHIFT (2U) +#define FSPI_ISR_TXOS_MASK (0x1U << FSPI_ISR_TXOS_SHIFT) /* 0x00000004 */ +#define FSPI_ISR_TXES_SHIFT (3U) +#define FSPI_ISR_TXES_MASK (0x1U << FSPI_ISR_TXES_SHIFT) /* 0x00000008 */ +#define FSPI_ISR_TRANSS_SHIFT (4U) +#define FSPI_ISR_TRANSS_MASK (0x1U << FSPI_ISR_TRANSS_SHIFT) /* 0x00000010 */ +#define FSPI_ISR_AHBS_SHIFT (5U) +#define FSPI_ISR_AHBS_MASK (0x1U << FSPI_ISR_AHBS_SHIFT) /* 0x00000020 */ +#define FSPI_ISR_NSPIS_SHIFT (6U) +#define FSPI_ISR_NSPIS_MASK (0x1U << FSPI_ISR_NSPIS_SHIFT) /* 0x00000040 */ +#define FSPI_ISR_DMAS_SHIFT (7U) +#define FSPI_ISR_DMAS_MASK (0x1U << FSPI_ISR_DMAS_SHIFT) /* 0x00000080 */ +/* FSR */ +#define FSPI_FSR_OFFSET (0x20U) +#define FSPI_FSR_TXFS_SHIFT (0U) +#define FSPI_FSR_TXFS_MASK (0x1U << FSPI_FSR_TXFS_SHIFT) /* 0x00000001 */ +#define FSPI_FSR_TXES_SHIFT (1U) +#define FSPI_FSR_TXES_MASK (0x1U << FSPI_FSR_TXES_SHIFT) /* 0x00000002 */ +#define FSPI_FSR_RXES_SHIFT (2U) +#define FSPI_FSR_RXES_MASK (0x1U << FSPI_FSR_RXES_SHIFT) /* 0x00000004 */ +#define FSPI_FSR_RXFS_SHIFT (3U) +#define FSPI_FSR_RXFS_MASK (0x1U << FSPI_FSR_RXFS_SHIFT) /* 0x00000008 */ +#define FSPI_FSR_TXWLVL_SHIFT (8U) +#define FSPI_FSR_TXWLVL_MASK (0x1FU << FSPI_FSR_TXWLVL_SHIFT) /* 0x00001F00 */ +#define FSPI_FSR_RXWLVL_SHIFT (16U) +#define FSPI_FSR_RXWLVL_MASK (0x1FU << FSPI_FSR_RXWLVL_SHIFT) /* 0x001F0000 */ +/* SR */ +#define FSPI_SR_OFFSET (0x24U) +#define FSPI_SR (0x0U) +#define FSPI_SR_SR_SHIFT (0U) +#define FSPI_SR_SR_MASK (0x1U << FSPI_SR_SR_SHIFT) /* 0x00000001 */ +/* RISR */ +#define FSPI_RISR_OFFSET (0x28U) +#define FSPI_RISR (0x0U) +#define FSPI_RISR_RXFS_SHIFT (0U) +#define FSPI_RISR_RXFS_MASK (0x1U << FSPI_RISR_RXFS_SHIFT) /* 0x00000001 */ +#define FSPI_RISR_RXUS_SHIFT (1U) +#define FSPI_RISR_RXUS_MASK (0x1U << FSPI_RISR_RXUS_SHIFT) /* 0x00000002 */ +#define FSPI_RISR_TXOS_SHIFT (2U) +#define FSPI_RISR_TXOS_MASK (0x1U << FSPI_RISR_TXOS_SHIFT) /* 0x00000004 */ +#define FSPI_RISR_TXES_SHIFT (3U) +#define FSPI_RISR_TXES_MASK (0x1U << FSPI_RISR_TXES_SHIFT) /* 0x00000008 */ +#define FSPI_RISR_TRANSS_SHIFT (4U) +#define FSPI_RISR_TRANSS_MASK (0x1U << FSPI_RISR_TRANSS_SHIFT) /* 0x00000010 */ +#define FSPI_RISR_AHBS_SHIFT (5U) +#define FSPI_RISR_AHBS_MASK (0x1U << FSPI_RISR_AHBS_SHIFT) /* 0x00000020 */ +#define FSPI_RISR_NSPIS_SHIFT (6U) +#define FSPI_RISR_NSPIS_MASK (0x1U << FSPI_RISR_NSPIS_SHIFT) /* 0x00000040 */ +#define FSPI_RISR_DMAS_SHIFT (7U) +#define FSPI_RISR_DMAS_MASK (0x1U << FSPI_RISR_DMAS_SHIFT) /* 0x00000080 */ +/* VER */ +#define FSPI_VER_OFFSET (0x2CU) +#define FSPI_VER (0x5U) +#define FSPI_VER_VER_SHIFT (0U) +#define FSPI_VER_VER_MASK (0xFFFFU << FSPI_VER_VER_SHIFT) /* 0x0000FFFF */ +/* QOP */ +#define FSPI_QOP_OFFSET (0x30U) +#define FSPI_QOP_SO123_SHIFT (0U) +#define FSPI_QOP_SO123_MASK (0x1U << FSPI_QOP_SO123_SHIFT) /* 0x00000001 */ +#define FSPI_QOP_SO123BP_SHIFT (1U) +#define FSPI_QOP_SO123BP_MASK (0x1U << FSPI_QOP_SO123BP_SHIFT) /* 0x00000002 */ +/* EXT_CTRL */ +#define FSPI_EXT_CTRL_OFFSET (0x34U) +#define FSPI_EXT_CTRL_CS_DESEL_CTRL_SHIFT (0U) +#define FSPI_EXT_CTRL_CS_DESEL_CTRL_MASK (0xFU << FSPI_EXT_CTRL_CS_DESEL_CTRL_SHIFT) /* 0x0000000F */ +#define FSPI_EXT_CTRL_SWITCH_IO_DUMM_CNT_SHIFT (4U) +#define FSPI_EXT_CTRL_SWITCH_IO_DUMM_CNT_MASK (0xFU << FSPI_EXT_CTRL_SWITCH_IO_DUMM_CNT_SHIFT) /* 0x000000F0 */ +#define FSPI_EXT_CTRL_SWITCH_IO_O2I_CNT_SHIFT (8U) +#define FSPI_EXT_CTRL_SWITCH_IO_O2I_CNT_MASK (0xFU << FSPI_EXT_CTRL_SWITCH_IO_O2I_CNT_SHIFT) /* 0x00000F00 */ +#define FSPI_EXT_CTRL_TRANS_INT_MODE_SHIFT (13U) +#define FSPI_EXT_CTRL_TRANS_INT_MODE_MASK (0x1U << FSPI_EXT_CTRL_TRANS_INT_MODE_SHIFT) /* 0x00002000 */ +#define FSPI_EXT_CTRL_SR_GEN_MODE_SHIFT (14U) +#define FSPI_EXT_CTRL_SR_GEN_MODE_MASK (0x1U << FSPI_EXT_CTRL_SR_GEN_MODE_SHIFT) /* 0x00004000 */ +/* DLL_CTRL0 */ +#define FSPI_DLL_CTRL0_OFFSET (0x3CU) +#define FSPI_DLL_CTRL0_SMP_DLL_CFG_SHIFT (0U) +#define FSPI_DLL_CTRL0_SMP_DLL_CFG_MASK (0x1FFU << FSPI_DLL_CTRL0_SMP_DLL_CFG_SHIFT) /* 0x000001FF */ +#define FSPI_DLL_CTRL0_SCLK_SMP_SEL_SHIFT (15U) +#define FSPI_DLL_CTRL0_SCLK_SMP_SEL_MASK (0x1U << FSPI_DLL_CTRL0_SCLK_SMP_SEL_SHIFT) /* 0x00008000 */ +/* EXT_AX */ +#define FSPI_EXT_AX_OFFSET (0x44U) +#define FSPI_EXT_AX_AX_CANCEL_PAT_SHIFT (0U) +#define FSPI_EXT_AX_AX_CANCEL_PAT_MASK (0xFFU << FSPI_EXT_AX_AX_CANCEL_PAT_SHIFT) /* 0x000000FF */ +#define FSPI_EXT_AX_AX_SETUP_PAT_SHIFT (8U) +#define FSPI_EXT_AX_AX_SETUP_PAT_MASK (0xFFU << FSPI_EXT_AX_AX_SETUP_PAT_SHIFT) /* 0x0000FF00 */ +/* SCLK_INATM_CNT */ +#define FSPI_SCLK_INATM_CNT_OFFSET (0x48U) +#define FSPI_SCLK_INATM_CNT_SCLK_INATM_CNT_SHIFT (0U) +#define FSPI_SCLK_INATM_CNT_SCLK_INATM_CNT_MASK (0xFFFFFFFFU << FSPI_SCLK_INATM_CNT_SCLK_INATM_CNT_SHIFT) /* 0xFFFFFFFF */ +/* XMMC_WCMD0 */ +#define FSPI_XMMC_WCMD0_OFFSET (0x50U) +#define FSPI_XMMC_WCMD0_CMD_SHIFT (0U) +#define FSPI_XMMC_WCMD0_CMD_MASK (0xFFU << FSPI_XMMC_WCMD0_CMD_SHIFT) /* 0x000000FF */ +#define FSPI_XMMC_WCMD0_DUMM_SHIFT (8U) +#define FSPI_XMMC_WCMD0_DUMM_MASK (0xFU << FSPI_XMMC_WCMD0_DUMM_SHIFT) /* 0x00000F00 */ +#define FSPI_XMMC_WCMD0_CONT_SHIFT (13U) +#define FSPI_XMMC_WCMD0_CONT_MASK (0x1U << FSPI_XMMC_WCMD0_CONT_SHIFT) /* 0x00002000 */ +#define FSPI_XMMC_WCMD0_ADDRB_SHIFT (14U) +#define FSPI_XMMC_WCMD0_ADDRB_MASK (0x3U << FSPI_XMMC_WCMD0_ADDRB_SHIFT) /* 0x0000C000 */ +/* XMMC_RCMD0 */ +#define FSPI_XMMC_RCMD0_OFFSET (0x54U) +#define FSPI_XMMC_RCMD0_CMD_SHIFT (0U) +#define FSPI_XMMC_RCMD0_CMD_MASK (0xFFU << FSPI_XMMC_RCMD0_CMD_SHIFT) /* 0x000000FF */ +#define FSPI_XMMC_RCMD0_DUMM_SHIFT (8U) +#define FSPI_XMMC_RCMD0_DUMM_MASK (0xFU << FSPI_XMMC_RCMD0_DUMM_SHIFT) /* 0x00000F00 */ +#define FSPI_XMMC_RCMD0_CONT_SHIFT (13U) +#define FSPI_XMMC_RCMD0_CONT_MASK (0x1U << FSPI_XMMC_RCMD0_CONT_SHIFT) /* 0x00002000 */ +#define FSPI_XMMC_RCMD0_ADDRB_SHIFT (14U) +#define FSPI_XMMC_RCMD0_ADDRB_MASK (0x3U << FSPI_XMMC_RCMD0_ADDRB_SHIFT) /* 0x0000C000 */ +/* XMMC_CTRL */ +#define FSPI_XMMC_CTRL_OFFSET (0x58U) +#define FSPI_XMMC_CTRL_DEV_HWEN_SHIFT (5U) +#define FSPI_XMMC_CTRL_DEV_HWEN_MASK (0x1U << FSPI_XMMC_CTRL_DEV_HWEN_SHIFT) /* 0x00000020 */ +#define FSPI_XMMC_CTRL_PFT_EN_SHIFT (6U) +#define FSPI_XMMC_CTRL_PFT_EN_MASK (0x1U << FSPI_XMMC_CTRL_PFT_EN_SHIFT) /* 0x00000040 */ +/* MODE */ +#define FSPI_MODE_OFFSET (0x5CU) +#define FSPI_MODE_XMMC_MODE_EN_SHIFT (0U) +#define FSPI_MODE_XMMC_MODE_EN_MASK (0x1U << FSPI_MODE_XMMC_MODE_EN_SHIFT) /* 0x00000001 */ +/* DEVRGN */ +#define FSPI_DEVRGN_OFFSET (0x60U) +#define FSPI_DEVRGN_RSIZE_SHIFT (0U) +#define FSPI_DEVRGN_RSIZE_MASK (0x1FU << FSPI_DEVRGN_RSIZE_SHIFT) /* 0x0000001F */ +#define FSPI_DEVRGN_DEC_CTRL_SHIFT (8U) +#define FSPI_DEVRGN_DEC_CTRL_MASK (0x3U << FSPI_DEVRGN_DEC_CTRL_SHIFT) /* 0x00000300 */ +/* DEVSIZE0 */ +#define FSPI_DEVSIZE0_OFFSET (0x64U) +#define FSPI_DEVSIZE0_DSIZE_SHIFT (0U) +#define FSPI_DEVSIZE0_DSIZE_MASK (0x1FU << FSPI_DEVSIZE0_DSIZE_SHIFT) /* 0x0000001F */ +/* TME0 */ +#define FSPI_TME0_OFFSET (0x68U) +#define FSPI_TME0_SCLK_INATM_EN_SHIFT (1U) +#define FSPI_TME0_SCLK_INATM_EN_MASK (0x1U << FSPI_TME0_SCLK_INATM_EN_SHIFT) /* 0x00000002 */ +/* XMMC_RX_WTMRK */ +#define FSPI_XMMC_RX_WTMRK_OFFSET (0x70U) +#define FSPI_XMMC_RX_WTMRK_RX_FULL_WTMRK_SHIFT (0U) +#define FSPI_XMMC_RX_WTMRK_RX_FULL_WTMRK_MASK (0xFFU << FSPI_XMMC_RX_WTMRK_RX_FULL_WTMRK_SHIFT) /* 0x000000FF */ +/* DMATR */ +#define FSPI_DMATR_OFFSET (0x80U) +#define FSPI_DMATR_DMATR_SHIFT (0U) +#define FSPI_DMATR_DMATR_MASK (0x1U << FSPI_DMATR_DMATR_SHIFT) /* 0x00000001 */ +/* DMAADDR */ +#define FSPI_DMAADDR_OFFSET (0x84U) +#define FSPI_DMAADDR_DMAADDR_SHIFT (0U) +#define FSPI_DMAADDR_DMAADDR_MASK (0xFFFFFFFFU << FSPI_DMAADDR_DMAADDR_SHIFT) /* 0xFFFFFFFF */ +/* LEN_CTRL */ +#define FSPI_LEN_CTRL_OFFSET (0x88U) +#define FSPI_LEN_CTRL_TRB_SEL_SHIFT (0U) +#define FSPI_LEN_CTRL_TRB_SEL_MASK (0x1U << FSPI_LEN_CTRL_TRB_SEL_SHIFT) /* 0x00000001 */ +/* LEN_EXT */ +#define FSPI_LEN_EXT_OFFSET (0x8CU) +#define FSPI_LEN_EXT_TRB_EXT_SHIFT (0U) +#define FSPI_LEN_EXT_TRB_EXT_MASK (0xFFFFFFFFU << FSPI_LEN_EXT_TRB_EXT_SHIFT) /* 0xFFFFFFFF */ +/* XMMCSR */ +#define FSPI_XMMCSR_OFFSET (0x94U) +#define FSPI_XMMCSR_SLOPOVER0_SHIFT (0U) +#define FSPI_XMMCSR_SLOPOVER0_MASK (0x1U << FSPI_XMMCSR_SLOPOVER0_SHIFT) /* 0x00000001 */ +#define FSPI_XMMCSR_SLOPOVER1_SHIFT (1U) +#define FSPI_XMMCSR_SLOPOVER1_MASK (0x1U << FSPI_XMMCSR_SLOPOVER1_SHIFT) /* 0x00000002 */ +/* CMD */ +#define FSPI_CMD_OFFSET (0x100U) +#define FSPI_CMD_CMD_SHIFT (0U) +#define FSPI_CMD_CMD_MASK (0xFFU << FSPI_CMD_CMD_SHIFT) /* 0x000000FF */ +#define FSPI_CMD_DUMM_SHIFT (8U) +#define FSPI_CMD_DUMM_MASK (0xFU << FSPI_CMD_DUMM_SHIFT) /* 0x00000F00 */ +#define FSPI_CMD_WR_SHIFT (12U) +#define FSPI_CMD_WR_MASK (0x1U << FSPI_CMD_WR_SHIFT) /* 0x00001000 */ +#define FSPI_CMD_CONT_SHIFT (13U) +#define FSPI_CMD_CONT_MASK (0x1U << FSPI_CMD_CONT_SHIFT) /* 0x00002000 */ +#define FSPI_CMD_ADDRB_SHIFT (14U) +#define FSPI_CMD_ADDRB_MASK (0x3U << FSPI_CMD_ADDRB_SHIFT) /* 0x0000C000 */ +#define FSPI_CMD_TRB_SHIFT (16U) +#define FSPI_CMD_TRB_MASK (0x3FFFU << FSPI_CMD_TRB_SHIFT) /* 0x3FFF0000 */ +#define FSPI_CMD_CS_SHIFT (30U) +#define FSPI_CMD_CS_MASK (0x3U << FSPI_CMD_CS_SHIFT) /* 0xC0000000 */ +/* ADDR */ +#define FSPI_ADDR_OFFSET (0x104U) +#define FSPI_ADDR_ADDR_SHIFT (0U) +#define FSPI_ADDR_ADDR_MASK (0xFFFFFFFFU << FSPI_ADDR_ADDR_SHIFT) /* 0xFFFFFFFF */ +/* DATA */ +#define FSPI_DATA_OFFSET (0x108U) +#define FSPI_DATA_DATA_SHIFT (0U) +#define FSPI_DATA_DATA_MASK (0xFFFFFFFFU << FSPI_DATA_DATA_SHIFT) /* 0xFFFFFFFF */ +/* CTRL1 */ +#define FSPI_CTRL1_OFFSET (0x200U) +#define FSPI_CTRL1_SPIM_SHIFT (0U) +#define FSPI_CTRL1_SPIM_MASK (0x1U << FSPI_CTRL1_SPIM_SHIFT) /* 0x00000001 */ +#define FSPI_CTRL1_SHIFTPHASE_SHIFT (1U) +#define FSPI_CTRL1_SHIFTPHASE_MASK (0x1U << FSPI_CTRL1_SHIFTPHASE_SHIFT) /* 0x00000002 */ +#define FSPI_CTRL1_IDLE_CYCLE_SHIFT (4U) +#define FSPI_CTRL1_IDLE_CYCLE_MASK (0xFU << FSPI_CTRL1_IDLE_CYCLE_SHIFT) /* 0x000000F0 */ +#define FSPI_CTRL1_CMDB_SHIFT (8U) +#define FSPI_CTRL1_CMDB_MASK (0x3U << FSPI_CTRL1_CMDB_SHIFT) /* 0x00000300 */ +#define FSPI_CTRL1_ADRB_SHIFT (10U) +#define FSPI_CTRL1_ADRB_MASK (0x3U << FSPI_CTRL1_ADRB_SHIFT) /* 0x00000C00 */ +#define FSPI_CTRL1_DATB_SHIFT (12U) +#define FSPI_CTRL1_DATB_MASK (0x3U << FSPI_CTRL1_DATB_SHIFT) /* 0x00003000 */ +/* AX1 */ +#define FSPI_AX1_OFFSET (0x214U) +#define FSPI_AX1_AX_SHIFT (0U) +#define FSPI_AX1_AX_MASK (0xFFU << FSPI_AX1_AX_SHIFT) /* 0x000000FF */ +/* ABIT1 */ +#define FSPI_ABIT1_OFFSET (0x218U) +#define FSPI_ABIT1_ABIT_SHIFT (0U) +#define FSPI_ABIT1_ABIT_MASK (0x1FU << FSPI_ABIT1_ABIT_SHIFT) /* 0x0000001F */ +/* DLL_CTRL1 */ +#define FSPI_DLL_CTRL1_OFFSET (0x23CU) +#define FSPI_DLL_CTRL1_SMP_DLL_CFG_SHIFT (0U) +#define FSPI_DLL_CTRL1_SMP_DLL_CFG_MASK (0x1FFU << FSPI_DLL_CTRL1_SMP_DLL_CFG_SHIFT) /* 0x000001FF */ +#define FSPI_DLL_CTRL1_SCLK_SMP_SEL_SHIFT (15U) +#define FSPI_DLL_CTRL1_SCLK_SMP_SEL_MASK (0x1U << FSPI_DLL_CTRL1_SCLK_SMP_SEL_SHIFT) /* 0x00008000 */ +/* XMMC_WCMD1 */ +#define FSPI_XMMC_WCMD1_OFFSET (0x250U) +#define FSPI_XMMC_WCMD1_CMD_SHIFT (0U) +#define FSPI_XMMC_WCMD1_CMD_MASK (0xFFU << FSPI_XMMC_WCMD1_CMD_SHIFT) /* 0x000000FF */ +#define FSPI_XMMC_WCMD1_DUMM_SHIFT (8U) +#define FSPI_XMMC_WCMD1_DUMM_MASK (0xFU << FSPI_XMMC_WCMD1_DUMM_SHIFT) /* 0x00000F00 */ +#define FSPI_XMMC_WCMD1_CONT_SHIFT (13U) +#define FSPI_XMMC_WCMD1_CONT_MASK (0x1U << FSPI_XMMC_WCMD1_CONT_SHIFT) /* 0x00002000 */ +#define FSPI_XMMC_WCMD1_ADDRB_SHIFT (14U) +#define FSPI_XMMC_WCMD1_ADDRB_MASK (0x3U << FSPI_XMMC_WCMD1_ADDRB_SHIFT) /* 0x0000C000 */ +/* XMMC_RCMD1 */ +#define FSPI_XMMC_RCMD1_OFFSET (0x254U) +#define FSPI_XMMC_RCMD1_CMD_SHIFT (0U) +#define FSPI_XMMC_RCMD1_CMD_MASK (0xFFU << FSPI_XMMC_RCMD1_CMD_SHIFT) /* 0x000000FF */ +#define FSPI_XMMC_RCMD1_DUMM_SHIFT (8U) +#define FSPI_XMMC_RCMD1_DUMM_MASK (0xFU << FSPI_XMMC_RCMD1_DUMM_SHIFT) /* 0x00000F00 */ +#define FSPI_XMMC_RCMD1_CONT_SHIFT (13U) +#define FSPI_XMMC_RCMD1_CONT_MASK (0x1U << FSPI_XMMC_RCMD1_CONT_SHIFT) /* 0x00002000 */ +#define FSPI_XMMC_RCMD1_ADDRB_SHIFT (14U) +#define FSPI_XMMC_RCMD1_ADDRB_MASK (0x3U << FSPI_XMMC_RCMD1_ADDRB_SHIFT) /* 0x0000C000 */ +/* DEVSIZE1 */ +#define FSPI_DEVSIZE1_OFFSET (0x264U) +#define FSPI_DEVSIZE1_DSIZE_SHIFT (0U) +#define FSPI_DEVSIZE1_DSIZE_MASK (0x1FU << FSPI_DEVSIZE1_DSIZE_SHIFT) /* 0x0000001F */ +/* TME1 */ +#define FSPI_TME1_OFFSET (0x268U) +#define FSPI_TME1_SCLK_INATM_EN_SHIFT (1U) +#define FSPI_TME1_SCLK_INATM_EN_MASK (0x1U << FSPI_TME1_SCLK_INATM_EN_SHIFT) /* 0x00000002 */ +/******************************************SPI*******************************************/ +/* CTRLR0 */ +#define SPI_CTRLR0_OFFSET (0x0U) +#define SPI_CTRLR0_DFS_SHIFT (0U) +#define SPI_CTRLR0_DFS_MASK (0x3U << SPI_CTRLR0_DFS_SHIFT) /* 0x00000003 */ +#define SPI_CTRLR0_CFS_SHIFT (2U) +#define SPI_CTRLR0_CFS_MASK (0xFU << SPI_CTRLR0_CFS_SHIFT) /* 0x0000003C */ +#define SPI_CTRLR0_SCPH_SHIFT (6U) +#define SPI_CTRLR0_SCPH_MASK (0x1U << SPI_CTRLR0_SCPH_SHIFT) /* 0x00000040 */ +#define SPI_CTRLR0_SCPOL_SHIFT (7U) +#define SPI_CTRLR0_SCPOL_MASK (0x1U << SPI_CTRLR0_SCPOL_SHIFT) /* 0x00000080 */ +#define SPI_CTRLR0_CSM_SHIFT (8U) +#define SPI_CTRLR0_CSM_MASK (0x3U << SPI_CTRLR0_CSM_SHIFT) /* 0x00000300 */ +#define SPI_CTRLR0_SSD_SHIFT (10U) +#define SPI_CTRLR0_SSD_MASK (0x1U << SPI_CTRLR0_SSD_SHIFT) /* 0x00000400 */ +#define SPI_CTRLR0_EM_SHIFT (11U) +#define SPI_CTRLR0_EM_MASK (0x1U << SPI_CTRLR0_EM_SHIFT) /* 0x00000800 */ +#define SPI_CTRLR0_FBM_SHIFT (12U) +#define SPI_CTRLR0_FBM_MASK (0x1U << SPI_CTRLR0_FBM_SHIFT) /* 0x00001000 */ +#define SPI_CTRLR0_BHT_SHIFT (13U) +#define SPI_CTRLR0_BHT_MASK (0x1U << SPI_CTRLR0_BHT_SHIFT) /* 0x00002000 */ +#define SPI_CTRLR0_RSD_SHIFT (14U) +#define SPI_CTRLR0_RSD_MASK (0x3U << SPI_CTRLR0_RSD_SHIFT) /* 0x0000C000 */ +#define SPI_CTRLR0_FRF_SHIFT (16U) +#define SPI_CTRLR0_FRF_MASK (0x3U << SPI_CTRLR0_FRF_SHIFT) /* 0x00030000 */ +#define SPI_CTRLR0_XFM_SHIFT (18U) +#define SPI_CTRLR0_XFM_MASK (0x3U << SPI_CTRLR0_XFM_SHIFT) /* 0x000C0000 */ +#define SPI_CTRLR0_OPM_SHIFT (20U) +#define SPI_CTRLR0_OPM_MASK (0x1U << SPI_CTRLR0_OPM_SHIFT) /* 0x00100000 */ +#define SPI_CTRLR0_MTM_SHIFT (21U) +#define SPI_CTRLR0_MTM_MASK (0x1U << SPI_CTRLR0_MTM_SHIFT) /* 0x00200000 */ +#define SPI_CTRLR0_SOI_SHIFT (23U) +#define SPI_CTRLR0_SOI_MASK (0x3U << SPI_CTRLR0_SOI_SHIFT) /* 0x01800000 */ +#define SPI_CTRLR0_LBK_SHIFT (25U) +#define SPI_CTRLR0_LBK_MASK (0x1U << SPI_CTRLR0_LBK_SHIFT) /* 0x02000000 */ +/* CTRLR1 */ +#define SPI_CTRLR1_OFFSET (0x4U) +#define SPI_CTRLR1_NDM_SHIFT (0U) +#define SPI_CTRLR1_NDM_MASK (0xFFFFFFFFU << SPI_CTRLR1_NDM_SHIFT) /* 0xFFFFFFFF */ +/* ENR */ +#define SPI_ENR_OFFSET (0x8U) +#define SPI_ENR_ENR_SHIFT (0U) +#define SPI_ENR_ENR_MASK (0x1U << SPI_ENR_ENR_SHIFT) /* 0x00000001 */ +/* SER */ +#define SPI_SER_OFFSET (0xCU) +#define SPI_SER_SER_SHIFT (0U) +#define SPI_SER_SER_MASK (0x3U << SPI_SER_SER_SHIFT) /* 0x00000003 */ +/* BAUDR */ +#define SPI_BAUDR_OFFSET (0x10U) +#define SPI_BAUDR_BAUDR_SHIFT (0U) +#define SPI_BAUDR_BAUDR_MASK (0xFFFFU << SPI_BAUDR_BAUDR_SHIFT) /* 0x0000FFFF */ +/* TXFTLR */ +#define SPI_TXFTLR_OFFSET (0x14U) +#define SPI_TXFTLR_XFTLR_SHIFT (0U) +#define SPI_TXFTLR_XFTLR_MASK (0x3FU << SPI_TXFTLR_XFTLR_SHIFT) /* 0x0000003F */ +/* RXFTLR */ +#define SPI_RXFTLR_OFFSET (0x18U) +#define SPI_RXFTLR_RXFTLR_SHIFT (0U) +#define SPI_RXFTLR_RXFTLR_MASK (0x3FU << SPI_RXFTLR_RXFTLR_SHIFT) /* 0x0000003F */ +/* TXFLR */ +#define SPI_TXFLR_OFFSET (0x1CU) +#define SPI_TXFLR (0x0U) +#define SPI_TXFLR_TXFLR_SHIFT (0U) +#define SPI_TXFLR_TXFLR_MASK (0x7FU << SPI_TXFLR_TXFLR_SHIFT) /* 0x0000007F */ +/* RXFLR */ +#define SPI_RXFLR_OFFSET (0x20U) +#define SPI_RXFLR (0x0U) +#define SPI_RXFLR_RXFLR_SHIFT (0U) +#define SPI_RXFLR_RXFLR_MASK (0x7FU << SPI_RXFLR_RXFLR_SHIFT) /* 0x0000007F */ +/* SR */ +#define SPI_SR_OFFSET (0x24U) +#define SPI_SR (0x4CU) +#define SPI_SR_BSF_SHIFT (0U) +#define SPI_SR_BSF_MASK (0x1U << SPI_SR_BSF_SHIFT) /* 0x00000001 */ +#define SPI_SR_TFF_SHIFT (1U) +#define SPI_SR_TFF_MASK (0x1U << SPI_SR_TFF_SHIFT) /* 0x00000002 */ +#define SPI_SR_TFE_SHIFT (2U) +#define SPI_SR_TFE_MASK (0x1U << SPI_SR_TFE_SHIFT) /* 0x00000004 */ +#define SPI_SR_RFE_SHIFT (3U) +#define SPI_SR_RFE_MASK (0x1U << SPI_SR_RFE_SHIFT) /* 0x00000008 */ +#define SPI_SR_RFF_SHIFT (4U) +#define SPI_SR_RFF_MASK (0x1U << SPI_SR_RFF_SHIFT) /* 0x00000010 */ +#define SPI_SR_STB_SHIFT (5U) +#define SPI_SR_STB_MASK (0x1U << SPI_SR_STB_SHIFT) /* 0x00000020 */ +#define SPI_SR_SSI_SHIFT (6U) +#define SPI_SR_SSI_MASK (0x1U << SPI_SR_SSI_SHIFT) /* 0x00000040 */ +/* IPR */ +#define SPI_IPR_OFFSET (0x28U) +#define SPI_IPR_IPR_SHIFT (0U) +#define SPI_IPR_IPR_MASK (0x1U << SPI_IPR_IPR_SHIFT) /* 0x00000001 */ +/* IMR */ +#define SPI_IMR_OFFSET (0x2CU) +#define SPI_IMR_TFEIM_SHIFT (0U) +#define SPI_IMR_TFEIM_MASK (0x1U << SPI_IMR_TFEIM_SHIFT) /* 0x00000001 */ +#define SPI_IMR_TFOIM_SHIFT (1U) +#define SPI_IMR_TFOIM_MASK (0x1U << SPI_IMR_TFOIM_SHIFT) /* 0x00000002 */ +#define SPI_IMR_RFUIM_SHIFT (2U) +#define SPI_IMR_RFUIM_MASK (0x1U << SPI_IMR_RFUIM_SHIFT) /* 0x00000004 */ +#define SPI_IMR_RFOIM_SHIFT (3U) +#define SPI_IMR_RFOIM_MASK (0x1U << SPI_IMR_RFOIM_SHIFT) /* 0x00000008 */ +#define SPI_IMR_RFFIM_SHIFT (4U) +#define SPI_IMR_RFFIM_MASK (0x1U << SPI_IMR_RFFIM_SHIFT) /* 0x00000010 */ +#define SPI_IMR_TOIM_SHIFT (5U) +#define SPI_IMR_TOIM_MASK (0x1U << SPI_IMR_TOIM_SHIFT) /* 0x00000020 */ +#define SPI_IMR_SSPIM_SHIFT (6U) +#define SPI_IMR_SSPIM_MASK (0x1U << SPI_IMR_SSPIM_SHIFT) /* 0x00000040 */ +#define SPI_IMR_TXFIM_SHIFT (7U) +#define SPI_IMR_TXFIM_MASK (0x1U << SPI_IMR_TXFIM_SHIFT) /* 0x00000080 */ +/* ISR */ +#define SPI_ISR_OFFSET (0x30U) +#define SPI_ISR_TFEIS_SHIFT (0U) +#define SPI_ISR_TFEIS_MASK (0x1U << SPI_ISR_TFEIS_SHIFT) /* 0x00000001 */ +#define SPI_ISR_TFOIS_SHIFT (1U) +#define SPI_ISR_TFOIS_MASK (0x1U << SPI_ISR_TFOIS_SHIFT) /* 0x00000002 */ +#define SPI_ISR_RFUIS_SHIFT (2U) +#define SPI_ISR_RFUIS_MASK (0x1U << SPI_ISR_RFUIS_SHIFT) /* 0x00000004 */ +#define SPI_ISR_RFOIS_SHIFT (3U) +#define SPI_ISR_RFOIS_MASK (0x1U << SPI_ISR_RFOIS_SHIFT) /* 0x00000008 */ +#define SPI_ISR_RFFIS_SHIFT (4U) +#define SPI_ISR_RFFIS_MASK (0x1U << SPI_ISR_RFFIS_SHIFT) /* 0x00000010 */ +#define SPI_ISR_TOIS_SHIFT (5U) +#define SPI_ISR_TOIS_MASK (0x1U << SPI_ISR_TOIS_SHIFT) /* 0x00000020 */ +#define SPI_ISR_SSPIS_SHIFT (6U) +#define SPI_ISR_SSPIS_MASK (0x1U << SPI_ISR_SSPIS_SHIFT) /* 0x00000040 */ +#define SPI_ISR_TXFIS_SHIFT (7U) +#define SPI_ISR_TXFIS_MASK (0x1U << SPI_ISR_TXFIS_SHIFT) /* 0x00000080 */ +/* RISR */ +#define SPI_RISR_OFFSET (0x34U) +#define SPI_RISR_TFERIS_SHIFT (0U) +#define SPI_RISR_TFERIS_MASK (0x1U << SPI_RISR_TFERIS_SHIFT) /* 0x00000001 */ +#define SPI_RISR_TFORIS_SHIFT (1U) +#define SPI_RISR_TFORIS_MASK (0x1U << SPI_RISR_TFORIS_SHIFT) /* 0x00000002 */ +#define SPI_RISR_RFURIS_SHIFT (2U) +#define SPI_RISR_RFURIS_MASK (0x1U << SPI_RISR_RFURIS_SHIFT) /* 0x00000004 */ +#define SPI_RISR_RFORIS_SHIFT (3U) +#define SPI_RISR_RFORIS_MASK (0x1U << SPI_RISR_RFORIS_SHIFT) /* 0x00000008 */ +#define SPI_RISR_RFFRIS_SHIFT (4U) +#define SPI_RISR_RFFRIS_MASK (0x1U << SPI_RISR_RFFRIS_SHIFT) /* 0x00000010 */ +#define SPI_RISR_TORIS_SHIFT (5U) +#define SPI_RISR_TORIS_MASK (0x1U << SPI_RISR_TORIS_SHIFT) /* 0x00000020 */ +#define SPI_RISR_SSPRIS_SHIFT (6U) +#define SPI_RISR_SSPRIS_MASK (0x1U << SPI_RISR_SSPRIS_SHIFT) /* 0x00000040 */ +#define SPI_RISR_TXFRIS_SHIFT (7U) +#define SPI_RISR_TXFRIS_MASK (0x1U << SPI_RISR_TXFRIS_SHIFT) /* 0x00000080 */ +/* ICR */ +#define SPI_ICR_OFFSET (0x38U) +#define SPI_ICR_CCI_SHIFT (0U) +#define SPI_ICR_CCI_MASK (0x1U << SPI_ICR_CCI_SHIFT) /* 0x00000001 */ +#define SPI_ICR_CRFUI_SHIFT (1U) +#define SPI_ICR_CRFUI_MASK (0x1U << SPI_ICR_CRFUI_SHIFT) /* 0x00000002 */ +#define SPI_ICR_CRFOI_SHIFT (2U) +#define SPI_ICR_CRFOI_MASK (0x1U << SPI_ICR_CRFOI_SHIFT) /* 0x00000004 */ +#define SPI_ICR_CTFOI_SHIFT (3U) +#define SPI_ICR_CTFOI_MASK (0x1U << SPI_ICR_CTFOI_SHIFT) /* 0x00000008 */ +#define SPI_ICR_CTOI_SHIFT (4U) +#define SPI_ICR_CTOI_MASK (0x1U << SPI_ICR_CTOI_SHIFT) /* 0x00000010 */ +#define SPI_ICR_CSSPI_SHIFT (5U) +#define SPI_ICR_CSSPI_MASK (0x1U << SPI_ICR_CSSPI_SHIFT) /* 0x00000020 */ +#define SPI_ICR_CTXFI_SHIFT (6U) +#define SPI_ICR_CTXFI_MASK (0x1U << SPI_ICR_CTXFI_SHIFT) /* 0x00000040 */ +/* DMACR */ +#define SPI_DMACR_OFFSET (0x3CU) +#define SPI_DMACR_RDE_SHIFT (0U) +#define SPI_DMACR_RDE_MASK (0x1U << SPI_DMACR_RDE_SHIFT) /* 0x00000001 */ +#define SPI_DMACR_TDE_SHIFT (1U) +#define SPI_DMACR_TDE_MASK (0x1U << SPI_DMACR_TDE_SHIFT) /* 0x00000002 */ +/* DMATDLR */ +#define SPI_DMATDLR_OFFSET (0x40U) +#define SPI_DMATDLR_TDL_SHIFT (0U) +#define SPI_DMATDLR_TDL_MASK (0x3FU << SPI_DMATDLR_TDL_SHIFT) /* 0x0000003F */ +/* DMARDLR */ +#define SPI_DMARDLR_OFFSET (0x44U) +#define SPI_DMARDLR_RDL_SHIFT (0U) +#define SPI_DMARDLR_RDL_MASK (0x3FU << SPI_DMARDLR_RDL_SHIFT) /* 0x0000003F */ +/* TIMEOUT */ +#define SPI_TIMEOUT_OFFSET (0x4CU) +#define SPI_TIMEOUT_TOV_SHIFT (0U) +#define SPI_TIMEOUT_TOV_MASK (0xFFFFU << SPI_TIMEOUT_TOV_SHIFT) /* 0x0000FFFF */ +#define SPI_TIMEOUT_TOE_SHIFT (16U) +#define SPI_TIMEOUT_TOE_MASK (0x1U << SPI_TIMEOUT_TOE_SHIFT) /* 0x00010000 */ +/* BYPASS */ +#define SPI_BYPASS_OFFSET (0x50U) +#define SPI_BYPASS_BYEN_SHIFT (0U) +#define SPI_BYPASS_BYEN_MASK (0x1U << SPI_BYPASS_BYEN_SHIFT) /* 0x00000001 */ +#define SPI_BYPASS_FBM_SHIFT (1U) +#define SPI_BYPASS_FBM_MASK (0x1U << SPI_BYPASS_FBM_SHIFT) /* 0x00000002 */ +#define SPI_BYPASS_END_SHIFT (2U) +#define SPI_BYPASS_END_MASK (0x1U << SPI_BYPASS_END_SHIFT) /* 0x00000004 */ +#define SPI_BYPASS_RXCP_SHIFT (3U) +#define SPI_BYPASS_RXCP_MASK (0x1U << SPI_BYPASS_RXCP_SHIFT) /* 0x00000008 */ +#define SPI_BYPASS_TXCP_SHIFT (4U) +#define SPI_BYPASS_TXCP_MASK (0x1U << SPI_BYPASS_TXCP_SHIFT) /* 0x00000010 */ +/* TXDR */ +#define SPI_TXDR_OFFSET (0x400U) +#define SPI_TXDR_TXDR_SHIFT (0U) +#define SPI_TXDR_TXDR_MASK (0xFFFFU << SPI_TXDR_TXDR_SHIFT) /* 0x0000FFFF */ +/* RXDR */ +#define SPI_RXDR_OFFSET (0x800U) +#define SPI_RXDR (0x0U) +#define SPI_RXDR_RXDR_SHIFT (0U) +#define SPI_RXDR_RXDR_MASK (0xFFFFU << SPI_RXDR_RXDR_SHIFT) /* 0x0000FFFF */ +/******************************************MBOX******************************************/ +/* A2B_INTEN */ +#define MBOX_A2B_INTEN_OFFSET (0x0U) +#define MBOX_A2B_INTEN_INT0_SHIFT (0U) +#define MBOX_A2B_INTEN_INT0_MASK (0x1U << MBOX_A2B_INTEN_INT0_SHIFT) /* 0x00000001 */ +#define MBOX_A2B_INTEN_INT1_SHIFT (1U) +#define MBOX_A2B_INTEN_INT1_MASK (0x1U << MBOX_A2B_INTEN_INT1_SHIFT) /* 0x00000002 */ +#define MBOX_A2B_INTEN_INT2_SHIFT (2U) +#define MBOX_A2B_INTEN_INT2_MASK (0x1U << MBOX_A2B_INTEN_INT2_SHIFT) /* 0x00000004 */ +#define MBOX_A2B_INTEN_INT3_SHIFT (3U) +#define MBOX_A2B_INTEN_INT3_MASK (0x1U << MBOX_A2B_INTEN_INT3_SHIFT) /* 0x00000008 */ +/* A2B_STATUS */ +#define MBOX_A2B_STATUS_OFFSET (0x4U) +#define MBOX_A2B_STATUS_INT0_SHIFT (0U) +#define MBOX_A2B_STATUS_INT0_MASK (0x1U << MBOX_A2B_STATUS_INT0_SHIFT) /* 0x00000001 */ +#define MBOX_A2B_STATUS_INT1_SHIFT (1U) +#define MBOX_A2B_STATUS_INT1_MASK (0x1U << MBOX_A2B_STATUS_INT1_SHIFT) /* 0x00000002 */ +#define MBOX_A2B_STATUS_INT2_SHIFT (2U) +#define MBOX_A2B_STATUS_INT2_MASK (0x1U << MBOX_A2B_STATUS_INT2_SHIFT) /* 0x00000004 */ +#define MBOX_A2B_STATUS_INT3_SHIFT (3U) +#define MBOX_A2B_STATUS_INT3_MASK (0x1U << MBOX_A2B_STATUS_INT3_SHIFT) /* 0x00000008 */ +/* A2B_CMD_0 */ +#define MBOX_A2B_CMD_0_OFFSET (0x8U) +#define MBOX_A2B_CMD_0_COMMAND_SHIFT (0U) +#define MBOX_A2B_CMD_0_COMMAND_MASK (0xFFFFFFFFU << MBOX_A2B_CMD_0_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* A2B_DAT_0 */ +#define MBOX_A2B_DAT_0_OFFSET (0xCU) +#define MBOX_A2B_DAT_0_DATA_SHIFT (0U) +#define MBOX_A2B_DAT_0_DATA_MASK (0xFFFFFFFFU << MBOX_A2B_DAT_0_DATA_SHIFT) /* 0xFFFFFFFF */ +/* A2B_CMD_1 */ +#define MBOX_A2B_CMD_1_OFFSET (0x10U) +#define MBOX_A2B_CMD_1_COMMAND_SHIFT (0U) +#define MBOX_A2B_CMD_1_COMMAND_MASK (0xFFFFFFFFU << MBOX_A2B_CMD_1_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* A2B_DAT_1 */ +#define MBOX_A2B_DAT_1_OFFSET (0x14U) +#define MBOX_A2B_DAT_1_DATA_SHIFT (0U) +#define MBOX_A2B_DAT_1_DATA_MASK (0xFFFFFFFFU << MBOX_A2B_DAT_1_DATA_SHIFT) /* 0xFFFFFFFF */ +/* A2B_CMD_2 */ +#define MBOX_A2B_CMD_2_OFFSET (0x18U) +#define MBOX_A2B_CMD_2_COMMAND_SHIFT (0U) +#define MBOX_A2B_CMD_2_COMMAND_MASK (0xFFFFFFFFU << MBOX_A2B_CMD_2_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* A2B_DAT_2 */ +#define MBOX_A2B_DAT_2_OFFSET (0x1CU) +#define MBOX_A2B_DAT_2_DATA_SHIFT (0U) +#define MBOX_A2B_DAT_2_DATA_MASK (0xFFFFFFFFU << MBOX_A2B_DAT_2_DATA_SHIFT) /* 0xFFFFFFFF */ +/* A2B_CMD_3 */ +#define MBOX_A2B_CMD_3_OFFSET (0x20U) +#define MBOX_A2B_CMD_3_COMMAND_SHIFT (0U) +#define MBOX_A2B_CMD_3_COMMAND_MASK (0xFFFFFFFFU << MBOX_A2B_CMD_3_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* A2B_DAT_3 */ +#define MBOX_A2B_DAT_3_OFFSET (0x24U) +#define MBOX_A2B_DAT_3_DATA_SHIFT (0U) +#define MBOX_A2B_DAT_3_DATA_MASK (0xFFFFFFFFU << MBOX_A2B_DAT_3_DATA_SHIFT) /* 0xFFFFFFFF */ +/* B2A_INTEN */ +#define MBOX_B2A_INTEN_OFFSET (0x28U) +#define MBOX_B2A_INTEN_INT0_SHIFT (0U) +#define MBOX_B2A_INTEN_INT0_MASK (0x1U << MBOX_B2A_INTEN_INT0_SHIFT) /* 0x00000001 */ +#define MBOX_B2A_INTEN_INT1_SHIFT (1U) +#define MBOX_B2A_INTEN_INT1_MASK (0x1U << MBOX_B2A_INTEN_INT1_SHIFT) /* 0x00000002 */ +#define MBOX_B2A_INTEN_INT2_SHIFT (2U) +#define MBOX_B2A_INTEN_INT2_MASK (0x1U << MBOX_B2A_INTEN_INT2_SHIFT) /* 0x00000004 */ +#define MBOX_B2A_INTEN_INT3_SHIFT (3U) +#define MBOX_B2A_INTEN_INT3_MASK (0x1U << MBOX_B2A_INTEN_INT3_SHIFT) /* 0x00000008 */ +/* B2A_STATUS */ +#define MBOX_B2A_STATUS_OFFSET (0x2CU) +#define MBOX_B2A_STATUS_INT0_SHIFT (0U) +#define MBOX_B2A_STATUS_INT0_MASK (0x1U << MBOX_B2A_STATUS_INT0_SHIFT) /* 0x00000001 */ +#define MBOX_B2A_STATUS_INT1_SHIFT (1U) +#define MBOX_B2A_STATUS_INT1_MASK (0x1U << MBOX_B2A_STATUS_INT1_SHIFT) /* 0x00000002 */ +#define MBOX_B2A_STATUS_INT2_SHIFT (2U) +#define MBOX_B2A_STATUS_INT2_MASK (0x1U << MBOX_B2A_STATUS_INT2_SHIFT) /* 0x00000004 */ +#define MBOX_B2A_STATUS_INT3_SHIFT (3U) +#define MBOX_B2A_STATUS_INT3_MASK (0x1U << MBOX_B2A_STATUS_INT3_SHIFT) /* 0x00000008 */ +/* B2A_CMD_0 */ +#define MBOX_B2A_CMD_0_OFFSET (0x30U) +#define MBOX_B2A_CMD_0_COMMAND_SHIFT (0U) +#define MBOX_B2A_CMD_0_COMMAND_MASK (0xFFFFFFFFU << MBOX_B2A_CMD_0_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* B2A_DAT_0 */ +#define MBOX_B2A_DAT_0_OFFSET (0x34U) +#define MBOX_B2A_DAT_0_DATA_SHIFT (0U) +#define MBOX_B2A_DAT_0_DATA_MASK (0xFFFFFFFFU << MBOX_B2A_DAT_0_DATA_SHIFT) /* 0xFFFFFFFF */ +/* B2A_CMD_1 */ +#define MBOX_B2A_CMD_1_OFFSET (0x38U) +#define MBOX_B2A_CMD_1_COMMAND_SHIFT (0U) +#define MBOX_B2A_CMD_1_COMMAND_MASK (0xFFFFFFFFU << MBOX_B2A_CMD_1_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* B2A_DAT_1 */ +#define MBOX_B2A_DAT_1_OFFSET (0x3CU) +#define MBOX_B2A_DAT_1_DATA_SHIFT (0U) +#define MBOX_B2A_DAT_1_DATA_MASK (0xFFFFFFFFU << MBOX_B2A_DAT_1_DATA_SHIFT) /* 0xFFFFFFFF */ +/* B2A_CMD_2 */ +#define MBOX_B2A_CMD_2_OFFSET (0x40U) +#define MBOX_B2A_CMD_2_COMMAND_SHIFT (0U) +#define MBOX_B2A_CMD_2_COMMAND_MASK (0xFFFFFFFFU << MBOX_B2A_CMD_2_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* B2A_DAT_2 */ +#define MBOX_B2A_DAT_2_OFFSET (0x44U) +#define MBOX_B2A_DAT_2_DATA_SHIFT (0U) +#define MBOX_B2A_DAT_2_DATA_MASK (0xFFFFFFFFU << MBOX_B2A_DAT_2_DATA_SHIFT) /* 0xFFFFFFFF */ +/* B2A_CMD_3 */ +#define MBOX_B2A_CMD_3_OFFSET (0x48U) +#define MBOX_B2A_CMD_3_COMMAND_SHIFT (0U) +#define MBOX_B2A_CMD_3_COMMAND_MASK (0xFFFFFFFFU << MBOX_B2A_CMD_3_COMMAND_SHIFT) /* 0xFFFFFFFF */ +/* B2A_DAT_3 */ +#define MBOX_B2A_DAT_3_OFFSET (0x4CU) +#define MBOX_B2A_DAT_3_DATA_SHIFT (0U) +#define MBOX_B2A_DAT_3_DATA_MASK (0xFFFFFFFFU << MBOX_B2A_DAT_3_DATA_SHIFT) /* 0xFFFFFFFF */ +/* ATOMIC_LOCK_00 */ +#define MBOX_ATOMIC_LOCK_00_OFFSET (0x100U) +#define MBOX_ATOMIC_LOCK_00_ATOMIC_LOCK_00_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_00_ATOMIC_LOCK_00_MASK (0x1U << MBOX_ATOMIC_LOCK_00_ATOMIC_LOCK_00_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_01 */ +#define MBOX_ATOMIC_LOCK_01_OFFSET (0x104U) +#define MBOX_ATOMIC_LOCK_01_ATOMIC_LOCK_01_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_01_ATOMIC_LOCK_01_MASK (0x1U << MBOX_ATOMIC_LOCK_01_ATOMIC_LOCK_01_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_02 */ +#define MBOX_ATOMIC_LOCK_02_OFFSET (0x108U) +#define MBOX_ATOMIC_LOCK_02_ATOMIC_LOCK_02_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_02_ATOMIC_LOCK_02_MASK (0x1U << MBOX_ATOMIC_LOCK_02_ATOMIC_LOCK_02_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_03 */ +#define MBOX_ATOMIC_LOCK_03_OFFSET (0x10CU) +#define MBOX_ATOMIC_LOCK_03_ATOMIC_LOCK_03_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_03_ATOMIC_LOCK_03_MASK (0x1U << MBOX_ATOMIC_LOCK_03_ATOMIC_LOCK_03_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_04 */ +#define MBOX_ATOMIC_LOCK_04_OFFSET (0x110U) +#define MBOX_ATOMIC_LOCK_04_ATOMIC_LOCK_04_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_04_ATOMIC_LOCK_04_MASK (0x1U << MBOX_ATOMIC_LOCK_04_ATOMIC_LOCK_04_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_05 */ +#define MBOX_ATOMIC_LOCK_05_OFFSET (0x114U) +#define MBOX_ATOMIC_LOCK_05_ATOMIC_LOCK_05_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_05_ATOMIC_LOCK_05_MASK (0x1U << MBOX_ATOMIC_LOCK_05_ATOMIC_LOCK_05_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_06 */ +#define MBOX_ATOMIC_LOCK_06_OFFSET (0x118U) +#define MBOX_ATOMIC_LOCK_06_ATOMIC_LOCK_06_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_06_ATOMIC_LOCK_06_MASK (0x1U << MBOX_ATOMIC_LOCK_06_ATOMIC_LOCK_06_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_07 */ +#define MBOX_ATOMIC_LOCK_07_OFFSET (0x11CU) +#define MBOX_ATOMIC_LOCK_07_ATOMIC_LOCK_07_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_07_ATOMIC_LOCK_07_MASK (0x1U << MBOX_ATOMIC_LOCK_07_ATOMIC_LOCK_07_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_08 */ +#define MBOX_ATOMIC_LOCK_08_OFFSET (0x120U) +#define MBOX_ATOMIC_LOCK_08_ATOMIC_LOCK_08_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_08_ATOMIC_LOCK_08_MASK (0x1U << MBOX_ATOMIC_LOCK_08_ATOMIC_LOCK_08_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_09 */ +#define MBOX_ATOMIC_LOCK_09_OFFSET (0x124U) +#define MBOX_ATOMIC_LOCK_09_ATOMIC_LOCK_09_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_09_ATOMIC_LOCK_09_MASK (0x1U << MBOX_ATOMIC_LOCK_09_ATOMIC_LOCK_09_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_10 */ +#define MBOX_ATOMIC_LOCK_10_OFFSET (0x128U) +#define MBOX_ATOMIC_LOCK_10_ATOMIC_LOCK_10_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_10_ATOMIC_LOCK_10_MASK (0x1U << MBOX_ATOMIC_LOCK_10_ATOMIC_LOCK_10_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_11 */ +#define MBOX_ATOMIC_LOCK_11_OFFSET (0x12CU) +#define MBOX_ATOMIC_LOCK_11_ATOMIC_LOCK_11_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_11_ATOMIC_LOCK_11_MASK (0x1U << MBOX_ATOMIC_LOCK_11_ATOMIC_LOCK_11_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_12 */ +#define MBOX_ATOMIC_LOCK_12_OFFSET (0x130U) +#define MBOX_ATOMIC_LOCK_12_ATOMIC_LOCK_12_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_12_ATOMIC_LOCK_12_MASK (0x1U << MBOX_ATOMIC_LOCK_12_ATOMIC_LOCK_12_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_13 */ +#define MBOX_ATOMIC_LOCK_13_OFFSET (0x134U) +#define MBOX_ATOMIC_LOCK_13_ATOMIC_LOCK_13_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_13_ATOMIC_LOCK_13_MASK (0x1U << MBOX_ATOMIC_LOCK_13_ATOMIC_LOCK_13_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_14 */ +#define MBOX_ATOMIC_LOCK_14_OFFSET (0x138U) +#define MBOX_ATOMIC_LOCK_14_ATOMIC_LOCK_14_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_14_ATOMIC_LOCK_14_MASK (0x1U << MBOX_ATOMIC_LOCK_14_ATOMIC_LOCK_14_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_15 */ +#define MBOX_ATOMIC_LOCK_15_OFFSET (0x13CU) +#define MBOX_ATOMIC_LOCK_15_ATOMIC_LOCK_15_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_15_ATOMIC_LOCK_15_MASK (0x1U << MBOX_ATOMIC_LOCK_15_ATOMIC_LOCK_15_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_16 */ +#define MBOX_ATOMIC_LOCK_16_OFFSET (0x140U) +#define MBOX_ATOMIC_LOCK_16_ATOMIC_LOCK_16_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_16_ATOMIC_LOCK_16_MASK (0x1U << MBOX_ATOMIC_LOCK_16_ATOMIC_LOCK_16_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_17 */ +#define MBOX_ATOMIC_LOCK_17_OFFSET (0x144U) +#define MBOX_ATOMIC_LOCK_17_ATOMIC_LOCK_17_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_17_ATOMIC_LOCK_17_MASK (0x1U << MBOX_ATOMIC_LOCK_17_ATOMIC_LOCK_17_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_18 */ +#define MBOX_ATOMIC_LOCK_18_OFFSET (0x148U) +#define MBOX_ATOMIC_LOCK_18_ATOMIC_LOCK_18_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_18_ATOMIC_LOCK_18_MASK (0x1U << MBOX_ATOMIC_LOCK_18_ATOMIC_LOCK_18_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_19 */ +#define MBOX_ATOMIC_LOCK_19_OFFSET (0x14CU) +#define MBOX_ATOMIC_LOCK_19_ATOMIC_LOCK_19_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_19_ATOMIC_LOCK_19_MASK (0x1U << MBOX_ATOMIC_LOCK_19_ATOMIC_LOCK_19_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_20 */ +#define MBOX_ATOMIC_LOCK_20_OFFSET (0x150U) +#define MBOX_ATOMIC_LOCK_20_ATOMIC_LOCK_20_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_20_ATOMIC_LOCK_20_MASK (0x1U << MBOX_ATOMIC_LOCK_20_ATOMIC_LOCK_20_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_21 */ +#define MBOX_ATOMIC_LOCK_21_OFFSET (0x154U) +#define MBOX_ATOMIC_LOCK_21_ATOMIC_LOCK_21_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_21_ATOMIC_LOCK_21_MASK (0x1U << MBOX_ATOMIC_LOCK_21_ATOMIC_LOCK_21_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_22 */ +#define MBOX_ATOMIC_LOCK_22_OFFSET (0x158U) +#define MBOX_ATOMIC_LOCK_22_ATOMIC_LOCK_22_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_22_ATOMIC_LOCK_22_MASK (0x1U << MBOX_ATOMIC_LOCK_22_ATOMIC_LOCK_22_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_23 */ +#define MBOX_ATOMIC_LOCK_23_OFFSET (0x15CU) +#define MBOX_ATOMIC_LOCK_23_ATOMIC_LOCK_23_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_23_ATOMIC_LOCK_23_MASK (0x1U << MBOX_ATOMIC_LOCK_23_ATOMIC_LOCK_23_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_24 */ +#define MBOX_ATOMIC_LOCK_24_OFFSET (0x160U) +#define MBOX_ATOMIC_LOCK_24_ATOMIC_LOCK_24_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_24_ATOMIC_LOCK_24_MASK (0x1U << MBOX_ATOMIC_LOCK_24_ATOMIC_LOCK_24_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_25 */ +#define MBOX_ATOMIC_LOCK_25_OFFSET (0x164U) +#define MBOX_ATOMIC_LOCK_25_ATOMIC_LOCK_25_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_25_ATOMIC_LOCK_25_MASK (0x1U << MBOX_ATOMIC_LOCK_25_ATOMIC_LOCK_25_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_26 */ +#define MBOX_ATOMIC_LOCK_26_OFFSET (0x168U) +#define MBOX_ATOMIC_LOCK_26_ATOMIC_LOCK_26_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_26_ATOMIC_LOCK_26_MASK (0x1U << MBOX_ATOMIC_LOCK_26_ATOMIC_LOCK_26_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_27 */ +#define MBOX_ATOMIC_LOCK_27_OFFSET (0x16CU) +#define MBOX_ATOMIC_LOCK_27_ATOMIC_LOCK_27_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_27_ATOMIC_LOCK_27_MASK (0x1U << MBOX_ATOMIC_LOCK_27_ATOMIC_LOCK_27_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_28 */ +#define MBOX_ATOMIC_LOCK_28_OFFSET (0x170U) +#define MBOX_ATOMIC_LOCK_28_ATOMIC_LOCK_28_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_28_ATOMIC_LOCK_28_MASK (0x1U << MBOX_ATOMIC_LOCK_28_ATOMIC_LOCK_28_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_29 */ +#define MBOX_ATOMIC_LOCK_29_OFFSET (0x174U) +#define MBOX_ATOMIC_LOCK_29_ATOMIC_LOCK_29_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_29_ATOMIC_LOCK_29_MASK (0x1U << MBOX_ATOMIC_LOCK_29_ATOMIC_LOCK_29_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_30 */ +#define MBOX_ATOMIC_LOCK_30_OFFSET (0x178U) +#define MBOX_ATOMIC_LOCK_30_ATOMIC_LOCK_30_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_30_ATOMIC_LOCK_30_MASK (0x1U << MBOX_ATOMIC_LOCK_30_ATOMIC_LOCK_30_SHIFT) /* 0x00000001 */ +/* ATOMIC_LOCK_31 */ +#define MBOX_ATOMIC_LOCK_31_OFFSET (0x17CU) +#define MBOX_ATOMIC_LOCK_31_ATOMIC_LOCK_31_SHIFT (0U) +#define MBOX_ATOMIC_LOCK_31_ATOMIC_LOCK_31_MASK (0x1U << MBOX_ATOMIC_LOCK_31_ATOMIC_LOCK_31_SHIFT) /* 0x00000001 */ +/*****************************************INTMUX*****************************************/ + +/********Name=SOFTRST_CON01,Offset=0xA04********/ +#define SRST_A_TOP_NIU 19U +#define SRST_P_TOP_NIU 20U +#define SRST_A_LOW_TOP_NIU 21U +#define SRST_P_CSIPHY0 22U +#define SRST_SCAN_CSIPHY0 23U +#define SRST_P_CSIPHY1 24U +#define SRST_SCAN_CSIPHY1 25U +#define SRST_A_TOP_M500_NIU 31U +/********Name=SOFTRST_CON02,Offset=0xA08********/ +#define SRST_A_TOP_M400_NIU 32U +#define SRST_A_TOP_S200_NIU 33U +#define SRST_A_TOP_S400_NIU 34U +#define SRST_A_TOP_M300_NIU 35U +#define SRST_USBDP_COMBO_PHY0_INIT 40U +#define SRST_USBDP_COMBO_PHY0_CMN 41U +#define SRST_USBDP_COMBO_PHY0_LANE 42U +#define SRST_USBDP_COMBO_PHY0_PCS 43U +#define SRST_USBDP_COMBO_PHY1_INIT 47U +/********Name=SOFTRST_CON03,Offset=0xA0C********/ +#define SRST_USBDP_COMBO_PHY1_CMN 48U +#define SRST_USBDP_COMBO_PHY1_LANE 49U +#define SRST_USBDP_COMBO_PHY1_PCS 50U +#define SRST_SCAN_DCPHY0 59U +#define SRST_P_MIPI_DCPHY0 62U +#define SRST_P_MIPI_DCPHY0_GRF 63U +/********Name=SOFTRST_CON04,Offset=0xA10********/ +#define SRST_SCAN_DCPHY1 64U +#define SRST_P_MIPI_DCPHY1 67U +#define SRST_P_MIPI_DCPHY1_GRF 68U +#define SRST_P_APB2ASB_SLV_CDPHY 69U +#define SRST_P_APB2ASB_SLV_CSIPHY 70U +#define SRST_P_APB2ASB_SLV_VCCIO3_5 71U +#define SRST_P_APB2ASB_SLV_VCCIO6 72U +#define SRST_P_APB2ASB_SLV_EMMCIO 73U +#define SRST_P_APB2ASB_SLV_IOC_TOP 74U +#define SRST_P_APB2ASB_SLV_IOC_RIGHT 75U +/********Name=SOFTRST_CON05,Offset=0xA14********/ +#define SRST_P_CRU 80U +#define SRST_NPOR_PAD 81U +#define SRST_NPOR_TM_DECODER 82U +#define SRST_A_CHANNEL_SECURE2VO1USB 87U +#define SRST_A_CHANNEL_SECURE2CENTER 88U +#define SRST_H_CHANNEL_SECURE2VO1USB 94U +#define SRST_H_CHANNEL_SECURE2CENTER 95U +/********Name=SOFTRST_CON06,Offset=0xA18********/ +#define SRST_P_CHANNEL_SECURE2VO1USB 96U +#define SRST_P_CHANNEL_SECURE2CENTER 97U +/********Name=SOFTRST_CON07,Offset=0xA1C********/ +#define SRST_H_AUDIO_NIU 114U +#define SRST_P_AUDIO_NIU 115U +#define SRST_H_I2S0_8CH 116U +#define SRST_M_I2S0_8CH_TX 119U +#define SRST_M_I2S0_8CH_RX 122U +#define SRST_P_ACDCDIG 123U +#define SRST_H_I2S2_2CH 124U +#define SRST_H_I2S3_2CH 125U +/********Name=SOFTRST_CON08,Offset=0xA20********/ +#define SRST_M_I2S2_2CH 128U +#define SRST_M_I2S3_2CH 131U +#define SRST_DAC_ACDCDIG 132U +#define SRST_H_SPDIF0 142U +/********Name=SOFTRST_CON09,Offset=0xA24********/ +#define SRST_M_SPDIF0 145U +#define SRST_H_SPDIF1 146U +#define SRST_M_SPDIF1 149U +#define SRST_H_PDM1 150U +#define SRST_PDM1 151U +/********Name=SOFTRST_CON10,Offset=0xA28********/ +#define SRST_A_BUS_NIU 161U +#define SRST_P_BUS_NIU 162U +#define SRST_A_GIC 163U +#define SRST_A_GIC_DBG 164U +#define SRST_A_DMAC0 165U +#define SRST_A_DMAC1 166U +#define SRST_A_DMAC2 167U +#define SRST_P_I2C1 168U +#define SRST_P_I2C2 169U +#define SRST_P_I2C3 170U +#define SRST_P_I2C4 171U +#define SRST_P_I2C5 172U +#define SRST_P_I2C6 173U +#define SRST_P_I2C7 174U +#define SRST_P_I2C8 175U +/********Name=SOFTRST_CON11,Offset=0xA2C********/ +#define SRST_I2C1 176U +#define SRST_I2C2 177U +#define SRST_I2C3 178U +#define SRST_I2C4 179U +#define SRST_I2C5 180U +#define SRST_I2C6 181U +#define SRST_I2C7 182U +#define SRST_I2C8 183U +#define SRST_P_CAN0 184U +#define SRST_CAN0 185U +#define SRST_P_CAN1 186U +#define SRST_CAN1 187U +#define SRST_P_CAN2 188U +#define SRST_CAN2 189U +#define SRST_P_SARADC 190U +/********Name=SOFTRST_CON12,Offset=0xA30********/ +#define SRST_P_TSADC 192U +#define SRST_TSADC 193U +#define SRST_P_UART1 194U +#define SRST_P_UART2 195U +#define SRST_P_UART3 196U +#define SRST_P_UART4 197U +#define SRST_P_UART5 198U +#define SRST_P_UART6 199U +#define SRST_P_UART7 200U +#define SRST_P_UART8 201U +#define SRST_P_UART9 202U +#define SRST_S_UART1 205U +/********Name=SOFTRST_CON13,Offset=0xA34********/ +#define SRST_S_UART2 208U +#define SRST_S_UART3 211U +#define SRST_S_UART4 214U +#define SRST_S_UART5 217U +#define SRST_S_UART6 220U +#define SRST_S_UART7 223U +/********Name=SOFTRST_CON14,Offset=0xA38********/ +#define SRST_S_UART8 226U +#define SRST_S_UART9 229U +#define SRST_P_SPI0 230U +#define SRST_P_SPI1 231U +#define SRST_P_SPI2 232U +#define SRST_P_SPI3 233U +#define SRST_P_SPI4 234U +#define SRST_SPI0 235U +#define SRST_SPI1 236U +#define SRST_SPI2 237U +#define SRST_SPI3 238U +#define SRST_SPI4 239U +/********Name=SOFTRST_CON15,Offset=0xA3C********/ +#define SRST_P_WDT0 240U +#define SRST_T_WDT0 241U +#define SRST_P_SYS_GRF 242U +#define SRST_P_PWM1 243U +#define SRST_PWM1 244U +#define SRST_P_PWM2 246U +#define SRST_PWM2 247U +#define SRST_P_PWM3 249U +#define SRST_PWM3 250U +#define SRST_P_BUSTIMER0 252U +#define SRST_P_BUSTIMER1 253U +#define SRST_BUSTIMER0 255U +/********Name=SOFTRST_CON16,Offset=0xA40********/ +#define SRST_BUSTIMER1 256U +#define SRST_BUSTIMER2 257U +#define SRST_BUSTIMER3 258U +#define SRST_BUSTIMER4 259U +#define SRST_BUSTIMER5 260U +#define SRST_BUSTIMER6 261U +#define SRST_BUSTIMER7 262U +#define SRST_BUSTIMER8 263U +#define SRST_BUSTIMER9 264U +#define SRST_BUSTIMER10 265U +#define SRST_BUSTIMER11 266U +#define SRST_P_MAILBOX0 267U +#define SRST_P_MAILBOX1 268U +#define SRST_P_MAILBOX2 269U +#define SRST_P_GPIO1 270U +#define SRST_DB_GPIO1 271U +/********Name=SOFTRST_CON17,Offset=0xA44********/ +#define SRST_P_GPIO2 272U +#define SRST_DB_GPIO2 273U +#define SRST_P_GPIO3 274U +#define SRST_DB_GPIO3 275U +#define SRST_P_GPIO4 276U +#define SRST_DB_GPIO4 277U +#define SRST_A_DECOM 278U +#define SRST_P_DECOM 279U +#define SRST_D_DECOM 280U +#define SRST_P_TOP 281U +#define SRST_A_GICADB_CORE2GIC_BUS 282U +#define SRST_A_GICADB_GIC2CORE_BUS 283U +#define SRST_P_DFT2APB 284U +#define SRST_P_APB2ASB_MST_TOP 285U +#define SRST_P_APB2ASB_MST_CDPHY 286U +#define SRST_P_APB2ASB_MST_BOT_RIGHT 287U +/********Name=SOFTRST_CON18,Offset=0xA48********/ +#define SRST_P_APB2ASB_MST_IOC_TOP 288U +#define SRST_P_APB2ASB_MST_IOC_RIGHT 289U +#define SRST_P_APB2ASB_MST_CSIPHY 290U +#define SRST_P_APB2ASB_MST_VCCIO3_5 291U +#define SRST_P_APB2ASB_MST_VCCIO6 292U +#define SRST_P_APB2ASB_MST_EMMCIO 293U +#define SRST_A_SPINLOCK 294U +#define SRST_P_OTPC_TM 295U +#define SRST_OTPC_TM 296U +#define SRST_P_OTPC_NS 297U +#define SRST_OTPC_NS 298U +#define SRST_OTPC_ARB 299U +#define SRST_P_JDBCK_DFT 302U +#define SRST_JDBCK_DFT 303U +/********Name=SOFTRST_CON19,Offset=0xA4C********/ +#define SRST_P_BUSIOC 304U +#define SRST_BISRINTF 306U +#define SRST_P_PMUCM0_INTMUX 308U +#define SRST_P_DDRCM0_INTMUX 309U +/********Name=SOFTRST_CON20,Offset=0xA50********/ +#define SRST_P_DDR_DFICTL_CH0 320U +#define SRST_P_DDR_MON_CH0 321U +#define SRST_P_DDR_STANDBY_CH0 322U +#define SRST_P_DDR_UPCTL_CH0 323U +#define SRST_TM_DDR_MON_CH0 324U +#define SRST_P_DDR_GRF_CH01 325U +#define SRST_DFI_CH0 326U +#define SRST_SBR_CH0 327U +#define SRST_DDR_UPCTL_CH0 328U +#define SRST_DDR_DFICTL_CH0 329U +#define SRST_DDR_MON_CH0 330U +#define SRST_DDR_STANDBY_CH0 331U +#define SRST_A_DDR_UPCTL_CH0 332U +#define SRST_P_DDR_DFICTL_CH1 333U +#define SRST_P_DDR_MON_CH1 334U +#define SRST_P_DDR_STANDBY_CH1 335U +/********Name=SOFTRST_CON21,Offset=0xA54********/ +#define SRST_P_DDR_UPCTL_CH1 336U +#define SRST_TM_DDR_MON_CH1 337U +#define SRST_DFI_CH1 338U +#define SRST_SBR_CH1 339U +#define SRST_DDR_UPCTL_CH1 340U +#define SRST_DDR_DFICTL_CH1 341U +#define SRST_DDR_MON_CH1 342U +#define SRST_DDR_STANDBY_CH1 343U +#define SRST_A_DDR_UPCTL_CH1 344U +#define SRST_A_DDR01_MSCH0 349U +#define SRST_A_DDR01_RS_MSCH0 350U +#define SRST_A_DDR01_FRS_MSCH0 351U +/********Name=SOFTRST_CON22,Offset=0xA58********/ +#define SRST_A_DDR01_SCRAMBLE0 352U +#define SRST_A_DDR01_FRS_SCRAMBLE0 353U +#define SRST_A_DDR01_MSCH1 354U +#define SRST_A_DDR01_RS_MSCH1 355U +#define SRST_A_DDR01_FRS_MSCH1 356U +#define SRST_A_DDR01_SCRAMBLE1 357U +#define SRST_A_DDR01_FRS_SCRAMBLE1 358U +#define SRST_P_DDR01_MSCH0 359U +#define SRST_P_DDR01_MSCH1 360U +/********Name=SOFTRST_CON23,Offset=0xA5C********/ +#define SRST_P_DDR_DFICTL_CH2 368U +#define SRST_P_DDR_MON_CH2 369U +#define SRST_P_DDR_STANDBY_CH2 370U +#define SRST_P_DDR_UPCTL_CH2 371U +#define SRST_TM_DDR_MON_CH2 372U +#define SRST_P_DDR_GRF_CH23 373U +#define SRST_DFI_CH2 374U +#define SRST_SBR_CH2 375U +#define SRST_DDR_UPCTL_CH2 376U +#define SRST_DDR_DFICTL_CH2 377U +#define SRST_DDR_MON_CH2 378U +#define SRST_DDR_STANDBY_CH2 379U +#define SRST_A_DDR_UPCTL_CH2 380U +#define SRST_P_DDR_DFICTL_CH3 381U +#define SRST_P_DDR_MON_CH3 382U +#define SRST_P_DDR_STANDBY_CH3 383U +/********Name=SOFTRST_CON24,Offset=0xA60********/ +#define SRST_P_DDR_UPCTL_CH3 384U +#define SRST_TM_DDR_MON_CH3 385U +#define SRST_DFI_CH3 386U +#define SRST_SBR_CH3 387U +#define SRST_DDR_UPCTL_CH3 388U +#define SRST_DDR_DFICTL_CH3 389U +#define SRST_DDR_MON_CH3 390U +#define SRST_DDR_STANDBY_CH3 391U +#define SRST_A_DDR_UPCTL_CH3 392U +#define SRST_A_DDR23_MSCH2 397U +#define SRST_A_DDR23_RS_MSCH2 398U +#define SRST_A_DDR23_FRS_MSCH2 399U +/********Name=SOFTRST_CON25,Offset=0xA64********/ +#define SRST_A_DDR23_SCRAMBLE2 400U +#define SRST_A_DDR23_FRS_SCRAMBLE2 401U +#define SRST_A_DDR23_MSCH3 402U +#define SRST_A_DDR23_RS_MSCH3 403U +#define SRST_A_DDR23_FRS_MSCH3 404U +#define SRST_A_DDR23_SCRAMBLE3 405U +#define SRST_A_DDR23_FRS_SCRAMBLE3 406U +#define SRST_P_DDR23_MSCH2 407U +#define SRST_P_DDR23_MSCH3 408U +/********Name=SOFTRST_CON26,Offset=0xA68********/ +#define SRST_ISP1 419U +#define SRST_ISP1_VICAP 420U +#define SRST_A_ISP1_NIU 422U +#define SRST_H_ISP1_NIU 424U +/********Name=SOFTRST_CON27,Offset=0xA6C********/ +#define SRST_A_RKNN1 432U +#define SRST_A_RKNN1_NIU 433U +#define SRST_H_RKNN1 434U +#define SRST_H_RKNN1_NIU 435U +/********Name=SOFTRST_CON28,Offset=0xA70********/ +#define SRST_A_RKNN2 448U +#define SRST_A_RKNN2_NIU 449U +#define SRST_H_RKNN2 450U +#define SRST_H_RKNN2_NIU 451U +/********Name=SOFTRST_CON29,Offset=0xA74********/ +#define SRST_A_RKNN_DSU0 467U +#define SRST_P_NPUTOP_NIU 469U +#define SRST_P_NPU_TIMER 470U +#define SRST_NPUTIMER0 472U +#define SRST_NPUTIMER1 473U +#define SRST_P_NPU_WDT 474U +#define SRST_T_NPU_WDT 475U +#define SRST_P_PVTM1 476U +#define SRST_P_NPU_GRF 477U +#define SRST_PVTM1 478U +/********Name=SOFTRST_CON30,Offset=0xA78********/ +#define SRST_NPU_PVTPLL 480U +#define SRST_H_NPU_CM0_NIU 482U +#define SRST_F_NPU_CM0_CORE 483U +#define SRST_T_NPU_CM0_JTAG 484U +#define SRST_A_RKNN0 486U +#define SRST_A_RKNN0_NIU 487U +#define SRST_H_RKNN0 488U +#define SRST_H_RKNN0_NIU 489U +/********Name=SOFTRST_CON31,Offset=0xA7C********/ +#define SRST_H_NVM_NIU 498U +#define SRST_A_NVM_NIU 499U +#define SRST_H_EMMC 500U +#define SRST_A_EMMC 501U +#define SRST_C_EMMC 502U +#define SRST_B_EMMC 503U +#define SRST_T_EMMC 504U +#define SRST_S_SFC 505U +#define SRST_H_SFC 506U +#define SRST_H_SFC_XIP 507U +/********Name=SOFTRST_CON32,Offset=0xA80********/ +#define SRST_P_GRF 513U +#define SRST_P_DEC_NIU 514U +#define SRST_P_PHP_NIU 517U +#define SRST_A_PCIE_GRIDGE 520U +#define SRST_A_PHP_NIU 521U +#define SRST_A_GMAC0 522U +#define SRST_A_GMAC1 523U +#define SRST_A_PCIE_NIU 524U +#define SRST_PCIE0_POWER_UP 525U +#define SRST_PCIE1_POWER_UP 526U +#define SRST_PCIE2_POWER_UP 527U +/********Name=SOFTRST_CON33,Offset=0xA84********/ +#define SRST_PCIE3_POWER_UP 528U +#define SRST_PCIE4_POWER_UP 529U +#define SRST_P_PCIE0 540U +#define SRST_P_PCIE1 541U +#define SRST_P_PCIE2 542U +#define SRST_P_PCIE3 543U +/********Name=SOFTRST_CON34,Offset=0xA88********/ +#define SRST_P_PCIE4 544U +#define SRST_A_PHP_GIC_ITS 550U +#define SRST_A_MMU_PCIE 551U +#define SRST_A_MMU_PHP 552U +#define SRST_A_MMU_NIU 553U +/********Name=SOFTRST_CON35,Offset=0xA8C********/ +#define SRST_A_USB3OTG2 567U +/********Name=SOFTRST_CON37,Offset=0xA94********/ +#define SRST_PMALIVE0 596U +#define SRST_PMALIVE1 597U +#define SRST_PMALIVE2 598U +#define SRST_A_SATA0 599U +#define SRST_A_SATA1 600U +#define SRST_A_SATA2 601U +#define SRST_RXOOB0 602U +#define SRST_RXOOB1 603U +#define SRST_RXOOB2 604U +#define SRST_ASIC0 605U +#define SRST_ASIC1 606U +#define SRST_ASIC2 607U +/********Name=SOFTRST_CON40,Offset=0xAA0********/ +#define SRST_A_RKVDEC_CCU 642U +#define SRST_H_RKVDEC0 643U +#define SRST_A_RKVDEC0 644U +#define SRST_H_RKVDEC0_NIU 645U +#define SRST_A_RKVDEC0_NIU 646U +#define SRST_RKVDEC0_CA 647U +#define SRST_RKVDEC0_HEVC_CA 648U +#define SRST_RKVDEC0_CORE 649U +/********Name=SOFTRST_CON41,Offset=0xAA4********/ +#define SRST_H_RKVDEC1 658U +#define SRST_A_RKVDEC1 659U +#define SRST_H_RKVDEC1_NIU 660U +#define SRST_A_RKVDEC1_NIU 661U +#define SRST_RKVDEC1_CA 662U +#define SRST_RKVDEC1_HEVC_CA 663U +#define SRST_RKVDEC1_CORE 664U +/********Name=SOFTRST_CON42,Offset=0xAA8********/ +#define SRST_A_USB_NIU 674U +#define SRST_H_USB_NIU 675U +#define SRST_A_USB3OTG0 676U +#define SRST_A_USB3OTG1 679U +#define SRST_H_HOST0 682U +#define SRST_H_HOST_ARB0 683U +#define SRST_H_HOST1 684U +#define SRST_H_HOST_ARB1 685U +#define SRST_A_USB_GRF 686U +#define SRST_C_USB2P0_HOST0 687U +/********Name=SOFTRST_CON43,Offset=0xAAC********/ +#define SRST_C_USB2P0_HOST1 688U +#define SRST_HOST_UTMI0 689U +#define SRST_HOST_UTMI1 690U +/********Name=SOFTRST_CON44,Offset=0xAB0********/ +#define SRST_A_VDPU_NIU 708U +#define SRST_A_VDPU_LOW_NIU 709U +#define SRST_H_VDPU_NIU 710U +#define SRST_A_JPEG_DECODER_NIU 711U +#define SRST_A_VPU 712U +#define SRST_H_VPU 713U +#define SRST_A_JPEG_ENCODER0 714U +#define SRST_H_JPEG_ENCODER0 715U +#define SRST_A_JPEG_ENCODER1 716U +#define SRST_H_JPEG_ENCODER1 717U +#define SRST_A_JPEG_ENCODER2 718U +#define SRST_H_JPEG_ENCODER2 719U +/********Name=SOFTRST_CON45,Offset=0xAB4********/ +#define SRST_A_JPEG_ENCODER3 720U +#define SRST_H_JPEG_ENCODER3 721U +#define SRST_A_JPEG_DECODER 722U +#define SRST_H_JPEG_DECODER 723U +#define SRST_H_IEP2P0 724U +#define SRST_A_IEP2P0 725U +#define SRST_IEP2P0_CORE 726U +#define SRST_H_RGA2 727U +#define SRST_A_RGA2 728U +#define SRST_RGA2_CORE 729U +#define SRST_H_RGA3_0 730U +#define SRST_A_RGA3_0 731U +#define SRST_RGA3_0_CORE 732U +/********Name=SOFTRST_CON47,Offset=0xABC********/ +#define SRST_H_RKVENC0_NIU 754U +#define SRST_A_RKVENC0_NIU 755U +#define SRST_H_RKVENC0 756U +#define SRST_A_RKVENC0 757U +#define SRST_RKVENC0_CORE 758U +/********Name=SOFTRST_CON48,Offset=0xAC0********/ +#define SRST_H_RKVENC1_NIU 770U +#define SRST_A_RKVENC1_NIU 771U +#define SRST_H_RKVENC1 772U +#define SRST_A_RKVENC1 773U +#define SRST_RKVENC1_CORE 774U +/********Name=SOFTRST_CON49,Offset=0xAC4********/ +#define SRST_A_VI_NIU 787U +#define SRST_H_VI_NIU 788U +#define SRST_P_VI_NIU 789U +#define SRST_D_VICAP 790U +#define SRST_A_VICAP 791U +#define SRST_H_VICAP 792U +#define SRST_ISP0 794U +#define SRST_ISP0_VICAP 795U +/********Name=SOFTRST_CON50,Offset=0xAC8********/ +#define SRST_FISHEYE0 800U +#define SRST_FISHEYE1 803U +#define SRST_P_CSI_HOST_0 804U +#define SRST_P_CSI_HOST_1 805U +#define SRST_P_CSI_HOST_2 806U +#define SRST_P_CSI_HOST_3 807U +#define SRST_P_CSI_HOST_4 808U +#define SRST_P_CSI_HOST_5 809U +/********Name=SOFTRST_CON51,Offset=0xACC********/ +#define SRST_CSIHOST0_VICAP 820U +#define SRST_CSIHOST1_VICAP 821U +#define SRST_CSIHOST2_VICAP 822U +#define SRST_CSIHOST3_VICAP 823U +#define SRST_CSIHOST4_VICAP 824U +#define SRST_CSIHOST5_VICAP 825U +#define SRST_CIFIN 829U +/********Name=SOFTRST_CON52,Offset=0xAD0********/ +#define SRST_A_VOP_NIU 836U +#define SRST_A_VOP_LOW_NIU 837U +#define SRST_H_VOP_NIU 838U +#define SRST_P_VOP_NIU 839U +#define SRST_H_VOP 840U +#define SRST_A_VOP 841U +#define SRST_D_VOP0 845U +#define SRST_D_VOP2HDMI_BRIDGE0 846U +#define SRST_D_VOP2HDMI_BRIDGE1 847U +/********Name=SOFTRST_CON53,Offset=0xAD4********/ +#define SRST_D_VOP1 848U +#define SRST_D_VOP2 849U +#define SRST_D_VOP3 850U +#define SRST_P_VOPGRF 851U +#define SRST_P_DSIHOST0 852U +#define SRST_P_DSIHOST1 853U +#define SRST_DSIHOST0 854U +#define SRST_DSIHOST1 855U +#define SRST_VOP_PMU 856U +#define SRST_P_VOP_CHANNEL_NIU 857U +/********Name=SOFTRST_CON55,Offset=0xADC********/ +#define SRST_H_VO0_NIU 885U +#define SRST_H_VO0_S_NIU 886U +#define SRST_P_VO0_NIU 887U +#define SRST_P_VO0_S_NIU 888U +#define SRST_A_HDCP0_NIU 889U +#define SRST_P_VO0GRF 890U +#define SRST_H_HDCP_KEY0 891U +#define SRST_A_HDCP0 892U +#define SRST_H_HDCP0 893U +#define SRST_P_HDCP0 894U +#define SRST_HDCP0 895U +/********Name=SOFTRST_CON56,Offset=0xAE0********/ +#define SRST_A_TRNG0 896U +#define SRST_P_TRNG0 897U +#define SRST_DP0 904U +#define SRST_DP1 905U +#define SRST_H_I2S4_8CH 906U +#define SRST_M_I2S4_8CH_TX 909U +#define SRST_H_I2S8_8CH 910U +/********Name=SOFTRST_CON57,Offset=0xAE4********/ +#define SRST_M_I2S8_8CH_TX 913U +#define SRST_H_SPDIF2_DP0 914U +#define SRST_M_SPDIF2_DP0 918U +#define SRST_H_SPDIF5_DP1 919U +#define SRST_M_SPDIF5_DP1 923U +/********Name=SOFTRST_CON59,Offset=0xAEC********/ +#define SRST_A_HDCP1_NIU 950U +#define SRST_A_HDMIRX_NIU 951U +#define SRST_A_VO1_NIU 952U +#define SRST_H_VOP1_NIU 953U +#define SRST_H_VOP1_S_NIU 954U +#define SRST_P_VOP1_NIU 955U +#define SRST_P_VO1GRF 956U +#define SRST_P_VO1_S_NIU 957U +/********Name=SOFTRST_CON60,Offset=0xAF0********/ +#define SRST_H_I2S7_8CH 960U +#define SRST_M_I2S7_8CH_RX 963U +#define SRST_H_HDCP_KEY1 964U +#define SRST_A_HDCP1 965U +#define SRST_H_HDCP1 966U +#define SRST_HDCP1 968U +#define SRST_P_TRNG1 970U +#define SRST_P_HDMITX0 971U +/********Name=SOFTRST_CON61,Offset=0xAF4********/ +#define SRST_HDMITX0_REF 976U +#define SRST_P_HDMITX1 978U +#define SRST_HDMITX1_REF 983U +#define SRST_A_HDMIRX 985U +#define SRST_P_HDMIRX 986U +#define SRST_HDMIRX_REF 987U +/********Name=SOFTRST_CON62,Offset=0xAF8********/ +#define SRST_P_EDP0 992U +#define SRST_EDP0_24M 993U +#define SRST_P_EDP1 995U +#define SRST_EDP1_24M 996U +#define SRST_M_I2S5_8CH_TX 1000U +#define SRST_H_I2S5_8CH 1004U +#define SRST_M_I2S6_8CH_TX 1007U +/********Name=SOFTRST_CON63,Offset=0xAFC********/ +#define SRST_M_I2S6_8CH_RX 1010U +#define SRST_H_I2S6_8CH 1011U +#define SRST_H_SPDIF3 1012U +#define SRST_M_SPDIF3 1015U +#define SRST_H_SPDIF4 1016U +#define SRST_M_SPDIF4 1019U +#define SRST_H_SPDIFRX0 1020U +#define SRST_M_SPDIFRX0 1021U +#define SRST_H_SPDIFRX1 1022U +#define SRST_M_SPDIFRX1 1023U +/********Name=SOFTRST_CON64,Offset=0xB00********/ +#define SRST_H_SPDIFRX2 1024U +#define SRST_M_SPDIFRX2 1025U +#define SRST_LINKSYM_HDMITXPHY0 1036U +#define SRST_LINKSYM_HDMITXPHY1 1037U +#define SRST_VO1_BRIDGE0 1038U +#define SRST_VO1_BRIDGE1 1039U +/********Name=SOFTRST_CON65,Offset=0xB04********/ +#define SRST_H_I2S9_8CH 1040U +#define SRST_M_I2S9_8CH_RX 1043U +#define SRST_H_I2S10_8CH 1044U +#define SRST_M_I2S10_8CH_RX 1047U +#define SRST_P_S_HDMIRX 1048U +/********Name=SOFTRST_CON66,Offset=0xB08********/ +#define SRST_GPU 1060U +#define SRST_SYS_GPU 1061U +#define SRST_A_S_GPU_NIU 1064U +#define SRST_A_M0_GPU_NIU 1065U +#define SRST_A_M1_GPU_NIU 1066U +#define SRST_A_M2_GPU_NIU 1067U +#define SRST_A_M3_GPU_NIU 1068U +#define SRST_P_GPU_NIU 1070U +#define SRST_P_PVTM2 1071U +/********Name=SOFTRST_CON67,Offset=0xB0C********/ +#define SRST_PVTM2 1072U +#define SRST_P_GPU_GRF 1074U +#define SRST_GPU_PVTPLL 1075U +#define SRST_PO_GPU_JTAG 1076U +/********Name=SOFTRST_CON68,Offset=0xB10********/ +#define SRST_A_AV1_NIU 1089U +#define SRST_A_AV1 1090U +#define SRST_P_AV1_NIU 1092U +#define SRST_P_AV1 1093U +/********Name=SOFTRST_CON69,Offset=0xB14********/ +#define SRST_A_DDR_NIU 1108U +#define SRST_A_DMA2DDR 1109U +#define SRST_A_DDR_SHAREMEM 1110U +#define SRST_A_DDR_SHAREMEM_NIU 1111U +#define SRST_A_CENTER_S200_NIU 1114U +#define SRST_A_CENTER_S400_NIU 1115U +#define SRST_H_AHB2APB 1116U +#define SRST_H_CENTER_NIU 1117U +#define SRST_F_DDR_CM0_CORE 1118U +/********Name=SOFTRST_CON70,Offset=0xB18********/ +#define SRST_DDR_TIMER0 1120U +#define SRST_DDR_TIMER1 1121U +#define SRST_T_WDT_DDR 1122U +#define SRST_T_DDR_CM0_JTAG 1123U +#define SRST_P_CENTER_GRF 1125U +#define SRST_P_AHB2APB 1126U +#define SRST_P_WDT 1127U +#define SRST_P_TIMER 1128U +#define SRST_P_DMA2DDR 1129U +#define SRST_P_SHAREMEM 1130U +#define SRST_P_CENTER_NIU 1131U +#define SRST_P_CENTER_CHANNEL_NIU 1132U +/********Name=SOFTRST_CON72,Offset=0xB20********/ +#define SRST_P_USBDPGRF0 1153U +#define SRST_P_USBDPPHY0 1154U +#define SRST_P_USBDPGRF1 1155U +#define SRST_P_USBDPPHY1 1156U +#define SRST_P_HDPTX0 1157U +#define SRST_P_HDPTX1 1158U +#define SRST_P_APB2ASB_SLV_BOT_RIGHT 1159U +#define SRST_P_USB2PHY_U3_0_GRF0 1160U +#define SRST_P_USB2PHY_U3_1_GRF0 1161U +#define SRST_P_USB2PHY_U2_0_GRF0 1162U +#define SRST_P_USB2PHY_U2_1_GRF0 1163U +#define SRST_SCAN_HDPTX0_ROPLL 1164U +#define SRST_SCAN_HDPTX0_LCPLL 1165U +#define SRST_SCAN_HDPTX0 1166U +#define SRST_SCAN_HDPTX1_ROPLL 1167U +/********Name=SOFTRST_CON73,Offset=0xB24********/ +#define SRST_SCAN_HDPTX1_LCPLL 1168U +#define SRST_SCAN_HDPTX1 1169U +#define SRST_SCAN_HDPTX0_HDMIRXPHY_SET 1170U +#define SRST_SCAN_USBDP_COMBO_PHY0 1171U +#define SRST_SCAN_USBDP_COMBO_PHY0_LCPLL 1172U +#define SRST_SCAN_USBDP_COMBO_PHY0_ROPLL 1173U +#define SRST_SCAN_USBDP_COMBO_PHY0_PCS_HS 1174U +#define SRST_SCAN_USBDP_COMBO_PHY1 1175U +#define SRST_SCAN_USBDP_COMBO_PHY1_LCPLL 1176U +#define SRST_SCAN_USBDP_COMBO_PHY1_ROPLL 1177U +#define SRST_SCAN_USBDP_COMBO_PHY1_PCS_HS 1178U +#define SRST_HDMIHDP0 1180U +#define SRST_HDMIHDP1 1181U +/********Name=SOFTRST_CON74,Offset=0xB28********/ +#define SRST_A_VO1USB_TOP_NIU 1185U +#define SRST_H_VO1USB_TOP_NIU 1187U +/********Name=SOFTRST_CON75,Offset=0xB2C********/ +#define SRST_H_SDIO_NIU 1201U +#define SRST_H_SDIO 1202U +#define SRST_SDIO 1203U +/********Name=SOFTRST_CON76,Offset=0xB30********/ +#define SRST_H_RGA3_NIU 1218U +#define SRST_A_RGA3_NIU 1219U +#define SRST_H_RGA3_1 1220U +#define SRST_A_RGA3_1 1221U +#define SRST_RGA3_1_CORE 1222U +/********Name=SOFTRST_CON77,Offset=0xB34********/ +#define SRST_REF_PIPE_PHY0 1238U +#define SRST_REF_PIPE_PHY1 1239U +#define SRST_REF_PIPE_PHY2 1240U +/********Name=PMU1SOFTRST_CON00,Offset=0xA00********/ +#define SRST_H_PMU1_NIU 26U +#define SRST_P_PMU1_NIU 27U +#define SRST_H_PMU_CM0_NIU 28U +#define SRST_F_PMU_CM0_CORE 29U +#define SRST_T_PMU1_CM0_JTAG 30U +/********Name=PMU1SOFTRST_CON01,Offset=0xA04********/ +#define SRST_DDR_FAIL_SAFE 17U +#define SRST_P_CRU_PMU1 18U +#define SRST_P_PMU1_GRF 20U +#define SRST_P_PMU1_IOC 21U +#define SRST_P_PMU1WDT 22U +#define SRST_T_PMU1WDT 23U +#define SRST_P_PMU1TIMER 24U +#define SRST_PMU1TIMER0 26U +#define SRST_PMU1TIMER1 27U +#define SRST_P_PMU1PWM 28U +#define SRST_PMU1PWM 29U +/********Name=PMU1SOFTRST_CON02,Offset=0xA08********/ +#define SRST_P_I2C0 17U +#define SRST_I2C0 18U +#define SRST_S_UART0 21U +#define SRST_P_UART0 22U +#define SRST_H_I2S1_8CH 23U +#define SRST_M_I2S1_8CH_TX 26U +#define SRST_M_I2S1_8CH_RX 29U +#define SRST_H_PDM0 30U +#define SRST_PDM0 31U +/********Name=PMU1SOFTRST_CON03,Offset=0xA0C********/ +#define SRST_H_VAD 16U +#define SRST_HDPTX0_INIT 27U +#define SRST_HDPTX0_CMN 28U +#define SRST_HDPTX0_LANE 29U +#define SRST_HDPTX1_INIT 31U +/********Name=PMU1SOFTRST_CON04,Offset=0xA10********/ +#define SRST_HDPTX1_CMN 16U +#define SRST_HDPTX1_LANE 17U +#define SRST_M_MIPI_DCPHY0 19U +#define SRST_S_MIPI_DCPHY0 20U +#define SRST_M_MIPI_DCPHY1 21U +#define SRST_S_MIPI_DCPHY1 22U +#define SRST_OTGPHY_U3_0 23U +#define SRST_OTGPHY_U3_1 24U +#define SRST_OTGPHY_U2_0 25U +#define SRST_OTGPHY_U2_1 26U +/********Name=PMU1SOFTRST_CON05,Offset=0xA14********/ +#define SRST_P_PMU0GRF 19U +#define SRST_P_PMU0IOC 20U +#define SRST_P_GPIO0 21U +#define SRST_DB_GPIO0 22U + +/********Name=GATE_CON00,Offset=0x800********/ +#define CLK_MATRIX_50M_SRC_GATE 0U +#define CLK_MATRIX_100M_SRC_GATE 1U +#define CLK_MATRIX_150M_SRC_GATE 2U +#define CLK_MATRIX_200M_SRC_GATE 3U +#define CLK_MATRIX_250M_SRC_GATE 4U +#define CLK_MATRIX_300M_SRC_GATE 5U +#define CLK_MATRIX_350M_SRC_GATE 6U +#define CLK_MATRIX_400M_SRC_GATE 7U +#define CLK_MATRIX_450M_SRC_GATE 8U +#define CLK_MATRIX_500M_SRC_GATE 9U +#define CLK_MATRIX_600M_SRC_GATE 10U +#define CLK_MATRIX_650M_SRC_GATE 11U +#define CLK_MATRIX_700M_SRC_GATE 12U +#define CLK_MATRIX_800M_SRC_GATE 13U +#define CLK_MATRIX_1000M_SRC_GATE 14U +#define CLK_MATRIX_1200M_SRC_GATE 15U +/********Name=GATE_CON01,Offset=0x804********/ +#define ACLK_TOP_ROOT_GATE 16U +#define PCLK_TOP_ROOT_GATE 17U +#define ACLK_LOW_TOP_ROOT_GATE 18U +#define ACLK_TOP_NIU_GATE 19U +#define PCLK_TOP_NIU_GATE 20U +#define ACLK_LOW_TOP_NIU_GATE 21U +#define PCLK_CSIPHY0_GATE 22U +#define PCLK_CSIPHY1_GATE 24U +#define ACLK_TOP_M300_ROOT_GATE 26U +#define ACLK_TOP_M500_ROOT_GATE 27U +#define ACLK_TOP_M400_ROOT_GATE 28U +#define ACLK_TOP_S200_ROOT_GATE 29U +#define ACLK_TOP_S400_ROOT_GATE 30U +#define ACLK_TOP_M500_NIU_GATE 31U +/********Name=GATE_CON02,Offset=0x808********/ +#define ACLK_TOP_M400_NIU_GATE 32U +#define ACLK_TOP_S200_NIU_GATE 33U +#define ACLK_TOP_S400_NIU_GATE 34U +#define ACLK_TOP_M300_NIU_GATE 35U +#define CLK_TESTOUT_TOP_GATE 36U +#define CLK_TESTOUT_GRP0_GATE 38U +#define CLK_USBDP_COMBO_PHY0_IMMORTAL_GATE 40U +#define CLK_USBDP_COMBO_PHY1_IMMORTAL_GATE 47U +/********Name=GATE_CON03,Offset=0x80C********/ +#define PCLK_MIPI_DCPHY0_GATE 62U +#define PCLK_MIPI_DCPHY0_GRF_GATE 63U +/********Name=GATE_CON04,Offset=0x810********/ +#define PCLK_MIPI_DCPHY1_GATE 67U +#define PCLK_MIPI_DCPHY1_GRF_GATE 68U +#define PCLK_APB2ASB_SLV_CDPHY_GATE 69U +#define PCLK_APB2ASB_SLV_CSIPHY_GATE 70U +#define PCLK_APB2ASB_SLV_VCCIO3_5_GATE 71U +#define PCLK_APB2ASB_SLV_VCCIO6_GATE 72U +#define PCLK_APB2ASB_SLV_EMMCIO_GATE 73U +#define PCLK_APB2ASB_SLV_IOC_TOP_GATE 74U +#define PCLK_APB2ASB_SLV_IOC_RIGHT_GATE 75U +/********Name=GATE_CON05,Offset=0x814********/ +#define PCLK_CRU_GATE 80U +#define XIN_OSC0_PAD_GATE 81U +#define XIN_OSC0_TMDECODER_GATE 82U +#define MCLK_GMAC0_OUT_GATE 83U +#define REFCLKO25M_ETH0_OUT_GATE 84U +#define REFCLKO25M_ETH1_OUT_GATE 85U +#define CLK_CIFOUT_OUT_GATE 86U +#define ACLK_CHANNEL_SECURE2VO1USB_GATE 87U +#define ACLK_CHANNEL_SECURE2CENTER_GATE 88U +#define CLK_MIPI_CAMERAOUT_M0_GATE 89U +#define CLK_MIPI_CAMERAOUT_M1_GATE 90U +#define CLK_MIPI_CAMERAOUT_M2_GATE 91U +#define CLK_MIPI_CAMERAOUT_M3_GATE 92U +#define CLK_MIPI_CAMERAOUT_M4_GATE 93U +#define HCLK_CHANNEL_SECURE2VO1USB_GATE 94U +#define HCLK_CHANNEL_SECURE2CENTER_GATE 95U +/********Name=GATE_CON06,Offset=0x818********/ +#define PCLK_CHANNEL_SECURE2VO1USB_GATE 96U +#define PCLK_CHANNEL_SECURE2CENTER_GATE 97U +/********Name=GATE_CON07,Offset=0x81C********/ +#define HCLK_AUDIO_ROOT_GATE 112U +#define PCLK_AUDIO_ROOT_GATE 113U +#define HCLK_AUDIO_NIU_GATE 114U +#define PCLK_AUDIO_NIU_GATE 115U +#define HCLK_I2S0_8CH_GATE 116U +#define CLK_I2S0_8CH_TX_GATE 117U +#define CLK_I2S0_8CH_FRAC_TX_GATE 118U +#define MCLK_I2S0_8CH_TX_GATE 119U +#define CLK_I2S0_8CH_RX_GATE 120U +#define CLK_I2S0_8CH_FRAC_RX_GATE 121U +#define MCLK_I2S0_8CH_RX_GATE 122U +#define PCLK_ACDCDIG_GATE 123U +#define HCLK_I2S2_2CH_GATE 124U +#define HCLK_I2S3_2CH_GATE 125U +#define CLK_I2S2_2CH_GATE 126U +#define CLK_I2S2_2CH_FRAC_GATE 127U +/********Name=GATE_CON08,Offset=0x820********/ +#define MCLK_I2S2_2CH_GATE 128U +#define CLK_I2S3_2CH_GATE 129U +#define CLK_I2S3_2CH_FRAC_GATE 130U +#define MCLK_I2S3_2CH_GATE 131U +#define CLK_DAC_ACDCDIG_GATE 132U +#define HCLK_SPDIF0_GATE 142U +#define CLK_SPDIF0_GATE 143U +/********Name=GATE_CON09,Offset=0x824********/ +#define CLK_SPDIF0_FRAC_GATE 144U +#define MCLK_SPDIF0_GATE 145U +#define HCLK_SPDIF1_GATE 146U +#define CLK_SPDIF1_GATE 147U +#define CLK_SPDIF1_FRAC_GATE 148U +#define MCLK_SPDIF1_GATE 149U +#define HCLK_PDM1_GATE 150U +#define MCLK_PDM1_GATE 151U +#define MBIST_CLK_MCLK_PDM1_GATE 152U +#define MBIST_CLK_CLK_ACDCDIG_GATE 153U +/********Name=GATE_CON10,Offset=0x828********/ +#define ACLK_BUS_ROOT_GATE 160U +#define ACLK_BUS_NIU_GATE 161U +#define PCLK_BUS_NIU_GATE 162U +#define ACLK_GIC_GATE 163U +#define ACLK_DMAC0_GATE 165U +#define ACLK_DMAC1_GATE 166U +#define ACLK_DMAC2_GATE 167U +#define PCLK_I2C1_GATE 168U +#define PCLK_I2C2_GATE 169U +#define PCLK_I2C3_GATE 170U +#define PCLK_I2C4_GATE 171U +#define PCLK_I2C5_GATE 172U +#define PCLK_I2C6_GATE 173U +#define PCLK_I2C7_GATE 174U +#define PCLK_I2C8_GATE 175U +/********Name=GATE_CON11,Offset=0x82C********/ +#define CLK_I2C1_GATE 176U +#define CLK_I2C2_GATE 177U +#define CLK_I2C3_GATE 178U +#define CLK_I2C4_GATE 179U +#define CLK_I2C5_GATE 180U +#define CLK_I2C6_GATE 181U +#define CLK_I2C7_GATE 182U +#define CLK_I2C8_GATE 183U +#define PCLK_CAN0_GATE 184U +#define CLK_CAN0_GATE 185U +#define PCLK_CAN1_GATE 186U +#define CLK_CAN1_GATE 187U +#define PCLK_CAN2_GATE 188U +#define CLK_CAN2_GATE 189U +#define PCLK_SARADC_GATE 190U +#define CLK_SARADC_GATE 191U +/********Name=GATE_CON12,Offset=0x830********/ +#define PCLK_TSADC_GATE 192U +#define CLK_TSADC_GATE 193U +#define PCLK_UART1_GATE 194U +#define PCLK_UART2_GATE 195U +#define PCLK_UART3_GATE 196U +#define PCLK_UART4_GATE 197U +#define PCLK_UART5_GATE 198U +#define PCLK_UART6_GATE 199U +#define PCLK_UART7_GATE 200U +#define PCLK_UART8_GATE 201U +#define PCLK_UART9_GATE 202U +#define CLK_UART1_GATE 203U +#define CLK_UART1_FRAC_GATE 204U +#define SCLK_UART1_GATE 205U +#define CLK_UART2_GATE 206U +#define CLK_UART2_FRAC_GATE 207U +/********Name=GATE_CON13,Offset=0x834********/ +#define SCLK_UART2_GATE 208U +#define CLK_UART3_GATE 209U +#define CLK_UART3_FRAC_GATE 210U +#define SCLK_UART3_GATE 211U +#define CLK_UART4_GATE 212U +#define CLK_UART4_FRAC_GATE 213U +#define SCLK_UART4_GATE 214U +#define CLK_UART5_GATE 215U +#define CLK_UART5_FRAC_GATE 216U +#define SCLK_UART5_GATE 217U +#define CLK_UART6_GATE 218U +#define CLK_UART6_FRAC_GATE 219U +#define SCLK_UART6_GATE 220U +#define CLK_UART7_GATE 221U +#define CLK_UART7_FRAC_GATE 222U +#define SCLK_UART7_GATE 223U +/********Name=GATE_CON14,Offset=0x838********/ +#define CLK_UART8_GATE 224U +#define CLK_UART8_FRAC_GATE 225U +#define SCLK_UART8_GATE 226U +#define CLK_UART9_GATE 227U +#define CLK_UART9_FRAC_GATE 228U +#define SCLK_UART9_GATE 229U +#define PCLK_SPI0_GATE 230U +#define PCLK_SPI1_GATE 231U +#define PCLK_SPI2_GATE 232U +#define PCLK_SPI3_GATE 233U +#define PCLK_SPI4_GATE 234U +#define CLK_SPI0_GATE 235U +#define CLK_SPI1_GATE 236U +#define CLK_SPI2_GATE 237U +#define CLK_SPI3_GATE 238U +#define CLK_SPI4_GATE 239U +/********Name=GATE_CON15,Offset=0x83C********/ +#define PCLK_WDT0_GATE 240U +#define TCLK_WDT0_GATE 241U +#define PCLK_SYS_GRF_GATE 242U +#define PCLK_PWM1_GATE 243U +#define CLK_PWM1_GATE 244U +#define CLK_PWM1_CAPTURE_GATE 245U +#define PCLK_PWM2_GATE 246U +#define CLK_PWM2_GATE 247U +#define CLK_PWM2_CAPTURE_GATE 248U +#define PCLK_PWM3_GATE 249U +#define CLK_PWM3_GATE 250U +#define CLK_PWM3_CAPTURE_GATE 251U +#define PCLK_BUSTIMER0_GATE 252U +#define PCLK_BUSTIMER1_GATE 253U +#define CLK_BUSTIMER_ROOT_GATE 254U +#define CLK_BUSTIMER0_GATE 255U +/********Name=GATE_CON16,Offset=0x840********/ +#define CLK_BUSTIMER1_GATE 256U +#define CLK_BUSTIMER2_GATE 257U +#define CLK_BUSTIMER3_GATE 258U +#define CLK_BUSTIMER4_GATE 259U +#define CLK_BUSTIMER5_GATE 260U +#define CLK_BUSTIMER6_GATE 261U +#define CLK_BUSTIMER7_GATE 262U +#define CLK_BUSTIMER8_GATE 263U +#define CLK_BUSTIMER9_GATE 264U +#define CLK_BUSTIMER10_GATE 265U +#define CLK_BUSTIMER11_GATE 266U +#define PCLK_MAILBOX0_GATE 267U +#define PCLK_MAILBOX1_GATE 268U +#define PCLK_MAILBOX2_GATE 269U +#define PCLK_GPIO1_GATE 270U +#define DBCLK_GPIO1_GATE 271U +/********Name=GATE_CON17,Offset=0x844********/ +#define PCLK_GPIO2_GATE 272U +#define DBCLK_GPIO2_GATE 273U +#define PCLK_GPIO3_GATE 274U +#define DBCLK_GPIO3_GATE 275U +#define PCLK_GPIO4_GATE 276U +#define DBCLK_GPIO4_GATE 277U +#define ACLK_DECOM_GATE 278U +#define PCLK_DECOM_GATE 279U +#define DCLK_DECOM_GATE 280U +#define PCLK_TOP_GATE 281U +#define ACLK_GICADB_CORE2GIC_BUS_GATE 282U +#define ACLK_GICADB_GIC2CORE_BUS_GATE 283U +#define PCLK_DFT2APB_GATE 284U +#define PCLK_APB2ASB_MST_TOP_GATE 285U +#define PCLK_APB2ASB_MST_CDPHY_GATE 286U +#define PCLK_APB2ASB_MST_BOT_RIGHT_GATE 287U +/********Name=GATE_CON18,Offset=0x848********/ +#define PCLK_APB2ASB_MST_IOC_TOP_GATE 288U +#define PCLK_APB2ASB_MST_IOC_RIGHT_GATE 289U +#define PCLK_APB2ASB_MST_CSIPHY_GATE 290U +#define PCLK_APB2ASB_MST_VCCIO3_5_GATE 291U +#define PCLK_APB2ASB_MST_VCCIO6_GATE 292U +#define PCLK_APB2ASB_MST_EMMCIO_GATE 293U +#define ACLK_SPINLOCK_GATE 294U +#define PCLK_OTPC_TM_GATE 295U +#define CLK_OTPC_TM_GATE 296U +#define PCLK_OTPC_NS_GATE 297U +#define CLK_OTPC_NS_GATE 298U +#define CLK_OTPC_ARB_GATE 299U +#define CLK_OTPC_AUTO_RD_GATE 300U +#define CLK_OTP_PHY_GATE 301U +#define PCLK_JDBCK_DFT_GATE 302U +#define CLK_JDBCK_DFT_GATE 303U +/********Name=GATE_CON19,Offset=0x84C********/ +#define PCLK_BUSIOC_GATE 304U +#define CLK_BISRINTF_PLLSRC_GATE 305U +#define CLK_BISRINTF_GATE 306U +#define PCLK_PMU2_GATE 307U +#define PCLK_PMUCM0_INTMUX_GATE 308U +#define PCLK_DDRCM0_INTMUX_GATE 309U +#define MBIST_CLK_ACLK_DECOM_GATE 310U +/********Name=GATE_CON20,Offset=0x850********/ +#define PCLK_DDR_DFICTL_CH0_GATE 320U +#define PCLK_DDR_MON_CH0_GATE 321U +#define PCLK_DDR_STANDBY_CH0_GATE 322U +#define PCLK_DDR_UPCTL_CH0_GATE 323U +#define TMCLK_DDR_MON_CH0_GATE 324U +#define PCLK_DDR_GRF_CH01_GATE 325U +#define CLK_DFI_CH0_GATE 326U +#define CLK_SBR_CH0_GATE 327U +#define CLK_DDR_UPCTL_CH0_GATE 328U +#define CLK_DDR_DFICTL_CH0_GATE 329U +#define CLK_DDR_MON_CH0_GATE 330U +#define CLK_DDR_STANDBY_CH0_GATE 331U +#define ACLK_DDR_UPCTL_CH0_GATE 332U +#define PCLK_DDR_DFICTL_CH1_GATE 333U +#define PCLK_DDR_MON_CH1_GATE 334U +#define PCLK_DDR_STANDBY_CH1_GATE 335U +/********Name=GATE_CON21,Offset=0x854********/ +#define PCLK_DDR_UPCTL_CH1_GATE 336U +#define TMCLK_DDR_MON_CH1_GATE 337U +#define CLK_DFI_CH1_GATE 338U +#define CLK_SBR_CH1_GATE 339U +#define CLK_DDR_UPCTL_CH1_GATE 340U +#define CLK_DDR_DFICTL_CH1_GATE 341U +#define CLK_DDR_MON_CH1_GATE 342U +#define CLK_DDR_STANDBY_CH1_GATE 343U +#define ACLK_DDR_UPCTL_CH1_GATE 344U +#define MBIST_CLK_CLK_DDR_UPCTRL_CH0_GATE 345U +#define MBIST_CLK_CLK_DDR_UPCTRL_CH1_GATE 346U +#define MBIST_CLK_ACLK_DDR01_MSCH_CH0_GATE 347U +#define MBIST_CLK_ACLK_DDR01_MSCH_CH1_GATE 348U +#define ACLK_DDR01_MSCH0_GATE 349U +#define ACLK_DDR01_RS_MSCH0_GATE 350U +#define ACLK_DDR01_FRS_MSCH0_GATE 351U +/********Name=GATE_CON22,Offset=0x858********/ +#define ACLK_DDR01_SCRAMBLE0_GATE 352U +#define ACLK_DDR01_FRS_SCRAMBLE0_GATE 353U +#define ACLK_DDR01_MSCH1_GATE 354U +#define ACLK_DDR01_RS_MSCH1_GATE 355U +#define ACLK_DDR01_FRS_MSCH1_GATE 356U +#define ACLK_DDR01_SCRAMBLE1_GATE 357U +#define ACLK_DDR01_FRS_SCRAMBLE1_GATE 358U +#define PCLK_DDR01_MSCH0_GATE 359U +#define PCLK_DDR01_MSCH1_GATE 360U +#define CLK_TESTOUT_DDR01_GATE 361U +/********Name=GATE_CON23,Offset=0x85C********/ +#define PCLK_DDR_DFICTL_CH2_GATE 368U +#define PCLK_DDR_MON_CH2_GATE 369U +#define PCLK_DDR_STANDBY_CH2_GATE 370U +#define PCLK_DDR_UPCTL_CH2_GATE 371U +#define TMCLK_DDR_MON_CH2_GATE 372U +#define PCLK_DDR_GRF_CH23_GATE 373U +#define CLK_DFI_CH2_GATE 374U +#define CLK_SBR_CH2_GATE 375U +#define CLK_DDR_UPCTL_CH2_GATE 376U +#define CLK_DDR_DFICTL_CH2_GATE 377U +#define CLK_DDR_MON_CH2_GATE 378U +#define CLK_DDR_STANDBY_CH2_GATE 379U +#define ACLK_DDR_UPCTL_CH2_GATE 380U +#define PCLK_DDR_DFICTL_CH3_GATE 381U +#define PCLK_DDR_MON_CH3_GATE 382U +#define PCLK_DDR_STANDBY_CH3_GATE 383U +/********Name=GATE_CON24,Offset=0x860********/ +#define PCLK_DDR_UPCTL_CH3_GATE 384U +#define TMCLK_DDR_MON_CH3_GATE 385U +#define CLK_DFI_CH3_GATE 386U +#define CLK_SBR_CH3_GATE 387U +#define CLK_DDR_UPCTL_CH3_GATE 388U +#define CLK_DDR_DFICTL_CH3_GATE 389U +#define CLK_DDR_MON_CH3_GATE 390U +#define CLK_DDR_STANDBY_CH3_GATE 391U +#define ACLK_DDR_UPCTL_CH3_GATE 392U +#define MBIST_CLK_CLK_DDR_UPCTRL_CH2_GATE 393U +#define MBIST_CLK_CLK_DDR_UPCTRL_CH3_GATE 394U +#define MBIST_CLK_ACLK_DDR23_MSCH_CH2_GATE 395U +#define MBIST_CLK_ACLK_DDR23_MSCH_CH3_GATE 396U +#define ACLK_DDR23_MSCH2_GATE 397U +#define ACLK_DDR23_RS_MSCH2_GATE 398U +#define ACLK_DDR23_FRS_MSCH2_GATE 399U +/********Name=GATE_CON25,Offset=0x864********/ +#define ACLK_DDR23_SCRAMBLE2_GATE 400U +#define ACLK_DDR23_FRS_SCRAMBLE2_GATE 401U +#define ACLK_DDR23_MSCH3_GATE 402U +#define ACLK_DDR23_RS_MSCH3_GATE 403U +#define ACLK_DDR23_FRS_MSCH3_GATE 404U +#define ACLK_DDR23_SCRAMBLE3_GATE 405U +#define ACLK_DDR23_FRS_SCRAMBLE3_GATE 406U +#define PCLK_DDR23_MSCH2_GATE 407U +#define PCLK_DDR23_MSCH3_GATE 408U +#define CLK_TESTOUT_DDR23_GATE 409U +/********Name=GATE_CON26,Offset=0x868********/ +#define ACLK_ISP1_ROOT_GATE 416U +#define HCLK_ISP1_ROOT_GATE 417U +#define CLK_ISP1_CORE_GATE 418U +#define CLK_ISP1_CORE_MARVIN_GATE 419U +#define CLK_ISP1_CORE_VICAP_GATE 420U +#define ACLK_ISP1_GATE 421U +#define ACLK_ISP1_NIU_GATE 422U +#define HCLK_ISP1_GATE 423U +#define HCLK_ISP1_NIU_GATE 424U +#define MBIST_CLK_CLK_ISP1_CORE_GATE 425U +#define MBIST_CLK_ACLK_ISP1_GATE 426U +#define MBIST_CLK_HCLK_ISP1_GATE 427U +/********Name=GATE_CON27,Offset=0x86C********/ +#define ACLK_RKNN1_GATE 432U +#define ACLK_RKNN1_NIU_GATE 433U +#define HCLK_RKNN1_GATE 434U +#define HCLK_RKNN1_NIU_GATE 435U +/********Name=GATE_CON28,Offset=0x870********/ +#define ACLK_RKNN2_GATE 448U +#define ACLK_RKNN2_NIU_GATE 449U +#define HCLK_RKNN2_GATE 450U +#define HCLK_RKNN2_NIU_GATE 451U +/********Name=GATE_CON29,Offset=0x874********/ +#define HCLK_RKNN_ROOT_GATE 464U +#define CLK_RKNN_DSU0_DF_GATE 465U +#define CLK_TESTOUT_NPU_GATE 466U +#define CLK_RKNN_DSU0_GATE 467U +#define PCLK_NPUTOP_ROOT_GATE 468U +#define PCLK_NPUTOP_NIU_GATE 469U +#define PCLK_NPU_TIMER_GATE 470U +#define CLK_NPUTIMER_ROOT_GATE 471U +#define CLK_NPUTIMER0_GATE 472U +#define CLK_NPUTIMER1_GATE 473U +#define PCLK_NPU_WDT_GATE 474U +#define TCLK_NPU_WDT_GATE 475U +#define PCLK_PVTM1_GATE 476U +#define PCLK_NPU_GRF_GATE 477U +#define CLK_PVTM1_GATE 478U +#define CLK_NPU_PVTM_GATE 479U +/********Name=GATE_CON30,Offset=0x878********/ +#define CLK_NPU_PVTPLL_GATE 480U +#define HCLK_NPU_CM0_ROOT_GATE 481U +#define HCLK_NPU_CM0_NIU_GATE 482U +#define FCLK_NPU_CM0_CORE_GATE 483U +#define CLK_NPU_CM0_RTC_GATE 485U +#define ACLK_RKNN0_GATE 486U +#define ACLK_RKNN0_NIU_GATE 487U +#define HCLK_RKNN0_GATE 488U +#define HCLK_RKNN0_NIU_GATE 489U +/********Name=GATE_CON31,Offset=0x87C********/ +#define HCLK_NVM_ROOT_GATE 496U +#define ACLK_NVM_ROOT_GATE 497U +#define HCLK_NVM_NIU_GATE 498U +#define ACLK_NVM_NIU_GATE 499U +#define HCLK_EMMC_GATE 500U +#define ACLK_EMMC_GATE 501U +#define CCLK_EMMC_GATE 502U +#define BCLK_EMMC_GATE 503U +#define TMCLK_EMMC_GATE 504U +#define SCLK_SFC_GATE 505U +#define HCLK_SFC_GATE 506U +#define HCLK_SFC_XIP_GATE 507U +#define MBIST_CLK_EMMC_GATE 508U +/********Name=GATE_CON32,Offset=0x880********/ +#define PCLK_PHP_ROOT_GATE 512U +#define PCLK_GRF_GATE 513U +#define PCLK_DEC_NIU_GATE 514U +#define PCLK_GMAC0_GATE 515U +#define PCLK_GMAC1_GATE 516U +#define PCLK_PHP_NIU_GATE 517U +#define ACLK_PCIE_ROOT_GATE 518U +#define ACLK_PHP_ROOT_GATE 519U +#define ACLK_PCIE_GRIDGE_GATE 520U +#define ACLK_PHP_NIU_GATE 521U +#define ACLK_GMAC0_GATE 522U +#define ACLK_GMAC1_GATE 523U +#define ACLK_PCIE_NIU_GATE 524U +#define ACLK_PCIE_DBI0_GATE 525U +#define ACLK_PCIE_DBI1_GATE 526U +#define ACLK_PCIE_DBI2_GATE 527U +/********Name=GATE_CON33,Offset=0x884********/ +#define ACLK_PCIE_DBI3_GATE 528U +#define ACLK_PCIE_DBI4_GATE 529U +#define ACLK_PCIE_MSTR0_GATE 530U +#define ACLK_PCIE_MSTR1_GATE 531U +#define ACLK_PCIE_MSTR2_GATE 532U +#define ACLK_PCIE_MSTR3_GATE 533U +#define ACLK_PCIE_MSTR4_GATE 534U +#define ACLK_PCIE_SLV0_GATE 535U +#define ACLK_PCIE_SLV1_GATE 536U +#define ACLK_PCIE_SLV2_GATE 537U +#define ACLK_PCIE_SLV3_GATE 538U +#define ACLK_PCIE_SLV4_GATE 539U +#define PCLK_PCIE0_GATE 540U +#define PCLK_PCIE1_GATE 541U +#define PCLK_PCIE2_GATE 542U +#define PCLK_PCIE3_GATE 543U +/********Name=GATE_CON34,Offset=0x888********/ +#define PCLK_PCIE4_GATE 544U +#define CLK_PCIE_AUX0_GATE 545U +#define CLK_PCIE_AUX1_GATE 546U +#define CLK_PCIE_AUX2_GATE 547U +#define CLK_PCIE_AUX3_GATE 548U +#define CLK_PCIE_AUX4_GATE 549U +#define ACLK_PHP_GIC_ITS_GATE 550U +#define ACLK_MMU_PCIE_GATE 551U +#define ACLK_MMU_PHP_GATE 552U +#define ACLK_MMU_NIU_GATE 553U +#define CLK_GMAC0_PTP_REF_GATE 554U +#define CLK_GMAC1_PTP_REF_GATE 555U +/********Name=GATE_CON35,Offset=0x88C********/ +#define CLK_GMAC_125M_CRU_GATE 565U +#define CLK_GMAC_50M_CRU_GATE 566U +#define ACLK_USB3OTG2_GATE 567U +#define SUSPEND_CLK_USB3OTG2_GATE 568U +#define REF_CLK_USB3OTG2_GATE 569U +#define CLK_UTMI_OTG2_GATE 570U +#define MBIST_CLK_ACLK_SATA0_GATE 571U +#define MBIST_CLK_ACLK_SATA1_GATE 572U +#define MBIST_CLK_ACLK_SATA2_GATE 573U +#define MBIST_CLK_CLK_PCIE4L_PIPE_GATE 574U +#define MBIST_CLK_ACLK_PCIE_MSTR0_GATE 575U +/********Name=GATE_CON36,Offset=0x890********/ +#define MBIST_CLK_ACLK_PCIE_SLV0_GATE 576U +#define MBIST_CLK_CLK_PCIE2L_PIPE_GATE 577U +#define MBIST_CLK_ACLK_PCIE_MSTR1_GATE 578U +#define MBIST_CLK_ACLK_PCIE_SLV1_GATE 579U +#define MBIST_CLK_CLK_PCIE1L0_PIPE_GATE 580U +#define MBIST_CLK_ACLK_PCIE_MSTR2_GATE 581U +#define MBIST_CLK_ACLK_PCIE_SLV2_GATE 582U +#define MBIST_CLK_CLK_PCIE1L1_PIPE_GATE 583U +#define MBIST_CLK_ACLK_PCIE_MSTR3_GATE 584U +#define MBIST_CLK_ACLK_PCIE_SLV3_GATE 585U +#define MBIST_CLK_CLK_PCIE1L2_PIPE_GATE 586U +#define MBIST_CLK_ACLK_PCIE_MSTR4_GATE 587U +#define MBIST_CLK_ACLK_PCIE_SLV4_GATE 588U +#define MBIST_CLK_ACLK_GMAC0_GATE 589U +#define MBIST_CLK_ACLK_GMAC1_GATE 590U +#define MBIST_CLK_ACLK_USB3OTG2_GATE 591U +/********Name=GATE_CON37,Offset=0x894********/ +#define CLK_PIPEPHY0_REF_GATE 592U +#define CLK_PIPEPHY1_REF_GATE 593U +#define CLK_PIPEPHY2_REF_GATE 594U +#define CLK_PMALIVE0_GATE 596U +#define CLK_PMALIVE1_GATE 597U +#define CLK_PMALIVE2_GATE 598U +#define ACLK_SATA0_GATE 599U +#define ACLK_SATA1_GATE 600U +#define ACLK_SATA2_GATE 601U +#define CLK_RXOOB0_GATE 602U +#define CLK_RXOOB1_GATE 603U +#define CLK_RXOOB2_GATE 604U +/********Name=GATE_CON38,Offset=0x898********/ +#define CLK_PIPEPHY0_PIPE_G_GATE 611U +#define CLK_PIPEPHY1_PIPE_G_GATE 612U +#define CLK_PIPEPHY2_PIPE_G_GATE 613U +#define CLK_PIPEPHY0_PIPE_ASIC_G_GATE 614U +#define CLK_PIPEPHY1_PIPE_ASIC_G_GATE 615U +#define CLK_PIPEPHY2_PIPE_ASIC_G_GATE 616U +#define CLK_PIPEPHY2_PIPE_U3_G_GATE 617U +#define CLK_PCIE1L2_PIPE_GATE 621U +#define CLK_PCIE1L0_PIPE_GATE 622U +#define CLK_PCIE1L1_PIPE_GATE 623U +/********Name=GATE_CON39,Offset=0x89C********/ +#define CLK_PCIE4L_PIPE_GATE 624U +#define CLK_PCIE2L_PIPE_GATE 625U +/********Name=GATE_CON40,Offset=0x8A0********/ +#define HCLK_RKVDEC0_ROOT_GATE 640U +#define ACLK_RKVDEC0_ROOT_GATE 641U +#define ACLK_RKVDEC_CCU_GATE 642U +#define HCLK_RKVDEC0_GATE 643U +#define ACLK_RKVDEC0_GATE 644U +#define HCLK_RKVDEC0_NIU_GATE 645U +#define ACLK_RKVDEC0_NIU_GATE 646U +#define CLK_RKVDEC0_CA_GATE 647U +#define CLK_RKVDEC0_HEVC_CA_GATE 648U +#define CLK_RKVDEC0_CORE_GATE 649U +#define MBIST_CLK_ACLK_RKVDEC0_GATE 650U +#define MBIST_CLK_CLK_RKVDEC0_HEVC_CA_GATE 651U +#define MBIST_CLK_CLK_RKVDEC0_CORE_GATE 652U +#define MBIST_CLK_CLK_RKVDEC0_CA_GATE 653U +/********Name=GATE_CON41,Offset=0x8A4********/ +#define HCLK_RKVDEC1_ROOT_GATE 656U +#define ACLK_RKVDEC1_ROOT_GATE 657U +#define HCLK_RKVDEC1_GATE 658U +#define ACLK_RKVDEC1_GATE 659U +#define HCLK_RKVDEC1_NIU_GATE 660U +#define ACLK_RKVDEC1_NIU_GATE 661U +#define CLK_RKVDEC1_CA_GATE 662U +#define CLK_RKVDEC1_HEVC_CA_GATE 663U +#define CLK_RKVDEC1_CORE_GATE 664U +#define MBIST_CLK_ACLK_RKVDEC1_GATE 665U +#define MBIST_CLK_CLK_RKVDEC1_HEVC_CA_GATE 666U +#define MBIST_CLK_CLK_RKVDEC1_CORE_GATE 667U +#define MBIST_CLK_CLK_RKVDEC1_CA_GATE 668U +/********Name=GATE_CON42,Offset=0x8A8********/ +#define ACLK_USB_ROOT_GATE 672U +#define HCLK_USB_ROOT_GATE 673U +#define ACLK_USB_NIU_GATE 674U +#define HCLK_USB_NIU_GATE 675U +#define ACLK_USB3OTG0_GATE 676U +#define SUSPEND_CLK_USB3OTG0_GATE 677U +#define REF_CLK_USB3OTG0_GATE 678U +#define ACLK_USB3OTG1_GATE 679U +#define SUSPEND_CLK_USB3OTG1_GATE 680U +#define REF_CLK_USB3OTG1_GATE 681U +#define HCLK_HOST0_GATE 682U +#define HCLK_HOST_ARB0_GATE 683U +#define HCLK_HOST1_GATE 684U +#define HCLK_HOST_ARB1_GATE 685U +#define ACLK_USB_GRF_GATE 686U +#define UTMI_OHCI_CLK48_HOST0_GATE 687U +/********Name=GATE_CON43,Offset=0x8AC********/ +#define UTMI_OHCI_CLK48_HOST1_GATE 688U +#define MBIST_CLK_HCLK_HOST0_GATE 691U +#define MBIST_CLK_HCLK_HOST1_GATE 692U +#define MBIST_CLK_ACLK_USB3OTG0_GATE 693U +#define MBIST_CLK_ACLK_USB3OTG1_GATE 694U +/********Name=GATE_CON44,Offset=0x8B0********/ +#define ACLK_VDPU_ROOT_GATE 704U +#define ACLK_VDPU_LOW_ROOT_GATE 705U +#define HCLK_VDPU_ROOT_GATE 706U +#define ACLK_JPEG_DECODER_ROOT_GATE 707U +#define ACLK_VDPU_NIU_GATE 708U +#define ACLK_VDPU_LOW_NIU_GATE 709U +#define HCLK_VDPU_NIU_GATE 710U +#define ACLK_JPEG_DECODER_NIU_GATE 711U +#define ACLK_VPU_GATE 712U +#define HCLK_VPU_GATE 713U +#define ACLK_JPEG_ENCODER0_GATE 714U +#define HCLK_JPEG_ENCODER0_GATE 715U +#define ACLK_JPEG_ENCODER1_GATE 716U +#define HCLK_JPEG_ENCODER1_GATE 717U +#define ACLK_JPEG_ENCODER2_GATE 718U +#define HCLK_JPEG_ENCODER2_GATE 719U +/********Name=GATE_CON45,Offset=0x8B4********/ +#define ACLK_JPEG_ENCODER3_GATE 720U +#define HCLK_JPEG_ENCODER3_GATE 721U +#define ACLK_JPEG_DECODER_GATE 722U +#define HCLK_JPEG_DECODER_GATE 723U +#define HCLK_IEP2P0_GATE 724U +#define ACLK_IEP2P0_GATE 725U +#define CLK_IEP2P0_CORE_GATE 726U +#define HCLK_RGA2_GATE 727U +#define ACLK_RGA2_GATE 728U +#define CLK_RGA2_CORE_GATE 729U +#define HCLK_RGA3_0_GATE 730U +#define ACLK_RGA3_0_GATE 731U +#define CLK_RGA3_0_CORE_GATE 732U +#define MBIST_CLK_ACLK_RGA3_0_GATE 733U +#define MBIST_CLK_CLK_RGA3_0_CORE_GATE 734U +#define MBIST_CLK_CLK_RGA2_GATE 735U +/********Name=GATE_CON46,Offset=0x8B8********/ +#define MBIST_CLK_ACLK_IEP2P0_GATE 736U +#define MBIST_CLK_CLK_IEP2P0_CORE_GATE 737U +#define MBIST_CLK_ACLK_JPEG_ENCODER0_GATE 738U +#define MBIST_CLK_ACLK_JPEG_ENCODER1_GATE 739U +#define MBIST_CLK_ACLK_JPEG_ENCODER2_GATE 740U +#define MBIST_CLK_ACLK_JPEG_ENCODER3_GATE 741U +#define MBIST_CLK_ACLK_JPEG_DECODER_GATE 742U +#define MBIST_CLK_ACLK_VPU_GATE 743U +/********Name=GATE_CON47,Offset=0x8BC********/ +#define HCLK_RKVENC0_ROOT_GATE 752U +#define ACLK_RKVENC0_ROOT_GATE 753U +#define HCLK_RKVENC0_NIU_GATE 754U +#define ACLK_RKVENC0_NIU_GATE 755U +#define HCLK_RKVENC0_GATE 756U +#define ACLK_RKVENC0_GATE 757U +#define CLK_RKVENC0_CORE_GATE 758U +/********Name=GATE_CON48,Offset=0x8C0********/ +#define HCLK_RKVENC1_ROOT_GATE 768U +#define ACLK_RKVENC1_ROOT_GATE 769U +#define HCLK_RKVENC1_NIU_GATE 770U +#define ACLK_RKVENC1_NIU_GATE 771U +#define HCLK_RKVENC1_GATE 772U +#define ACLK_RKVENC1_GATE 773U +#define CLK_RKVENC1_CORE_GATE 774U +/********Name=GATE_CON49,Offset=0x8C4********/ +#define ACLK_VI_ROOT_GATE 784U +#define HCLK_VI_ROOT_GATE 785U +#define PCLK_VI_ROOT_GATE 786U +#define ACLK_VI_NIU_GATE 787U +#define HCLK_VI_NIU_GATE 788U +#define PCLK_VI_NIU_GATE 789U +#define DCLK_VICAP_GATE 790U +#define ACLK_VICAP_GATE 791U +#define HCLK_VICAP_GATE 792U +#define CLK_ISP0_CORE_GATE 793U +#define CLK_ISP0_CORE_MARVIN_GATE 794U +#define CLK_ISP0_CORE_VICAP_GATE 795U +#define ACLK_ISP0_GATE 796U +#define HCLK_ISP0_GATE 797U +#define ACLK_FISHEYE0_GATE 798U +#define HCLK_FISHEYE0_GATE 799U +/********Name=GATE_CON50,Offset=0x8C8********/ +#define CLK_FISHEYE0_CORE_GATE 800U +#define ACLK_FISHEYE1_GATE 801U +#define HCLK_FISHEYE1_GATE 802U +#define CLK_FISHEYE1_CORE_GATE 803U +#define PCLK_CSI_HOST_0_GATE 804U +#define PCLK_CSI_HOST_1_GATE 805U +#define PCLK_CSI_HOST_2_GATE 806U +#define PCLK_CSI_HOST_3_GATE 807U +#define PCLK_CSI_HOST_4_GATE 808U +#define PCLK_CSI_HOST_5_GATE 809U +#define MBIST_CLK_CLK_ISP0_CORE_GATE 810U +#define MBIST_CLK_ACLK_ISP0_GATE 811U +#define MBIST_CLK_ACLK_VICAP_GATE 812U +#define MBIST_CLK_VICAP_CLK_ISP0_CORE_GATE 813U +#define MBIST_CLK_VICAP_CLK_ISP1_CORE_GATE 814U +#define MBIST_CLK_ACLK_FISHEYE0_GATE 815U +/********Name=GATE_CON51,Offset=0x8CC********/ +#define MBIST_CLK_CLK_FISHEYE0_CORE_GATE 816U +#define MBIST_CLK_ACLK_FISHEYE1_GATE 817U +#define MBIST_CLK_CLK_FISHEYE1_CORE_GATE 818U +#define MBIST_CLK_DCLK_VICAP_GATE 819U +#define CLK_CSIHOST0_VICAP_GATE 820U +#define CLK_CSIHOST1_VICAP_GATE 821U +#define CLK_CSIHOST2_VICAP_GATE 822U +#define CLK_CSIHOST3_VICAP_GATE 823U +#define CLK_CSIHOST4_VICAP_GATE 824U +#define CLK_CSIHOST5_VICAP_GATE 825U +#define ICLK_CSIHOST01_GATE 826U +#define ICLK_CSIHOST0_GATE 827U +#define ICLK_CSIHOST1_GATE 828U +/********Name=GATE_CON52,Offset=0x8D0********/ +#define ACLK_VOP_ROOT_GATE 832U +#define ACLK_VOP_LOW_ROOT_GATE 833U +#define HCLK_VOP_ROOT_GATE 834U +#define PCLK_VOP_ROOT_GATE 835U +#define ACLK_VOP_NIU_GATE 836U +#define ACLK_VOP_LOW_NIU_GATE 837U +#define HCLK_VOP_NIU_GATE 838U +#define PCLK_VOP_NIU_GATE 839U +#define HCLK_VOP_GATE 840U +#define ACLK_VOP_GATE 841U +#define DCLK_VOP0_SRC_GATE 842U +#define DCLK_VOP1_SRC_GATE 843U +#define DCLK_VOP2_SRC_GATE 844U +#define DCLK_VOP0_GATE 845U +/********Name=GATE_CON53,Offset=0x8D4********/ +#define DCLK_VOP1_GATE 848U +#define DCLK_VOP2_GATE 849U +#define DCLK_VOP3_GATE 850U +#define PCLK_VOPGRF_GATE 851U +#define PCLK_DSIHOST0_GATE 852U +#define PCLK_DSIHOST1_GATE 853U +#define CLK_DSIHOST0_GATE 854U +#define CLK_DSIHOST1_GATE 855U +#define CLK_VOP_PMU_GATE 856U +#define PCLK_VOP_CHANNEL_NIU_GATE 857U +#define ACLK_VOP_DOBY_GATE 858U +#define MBIST_CLK_DCLK_VOP0_GATE 859U +#define MBIST_CLK_DCLK_VOP1_GATE 860U +#define MBIST_CLK_DCLK_VOP2_GATE 861U +#define MBIST_CLK_DCLK_VOP3_GATE 862U +#define MBIST_CLK_ACLK_VOP_GATE 863U +/********Name=GATE_CON54,Offset=0x8D8********/ +#define MBIST_CLK_CLK_DSIHOST0_GATE 864U +#define MBIST_CLK_CLK_DSIHOST1_GATE 865U +#define MBIST_CLK_VOP_DSC_GATE 866U +/********Name=GATE_CON55,Offset=0x8DC********/ +#define ACLK_VO0_ROOT_GATE 880U +#define HCLK_VO0_ROOT_GATE 881U +#define HCLK_VO0_S_ROOT_GATE 882U +#define PCLK_VO0_ROOT_GATE 883U +#define PCLK_VO0_S_ROOT_GATE 884U +#define HCLK_VO0_NIU_GATE 885U +#define HCLK_VO0_S_NIU_GATE 886U +#define PCLK_VO0_NIU_GATE 887U +#define PCLK_VO0_S_NIU_GATE 888U +#define ACLK_HDCP0_NIU_GATE 889U +#define PCLK_VO0GRF_GATE 890U +#define HCLK_HDCP_KEY0_GATE 891U +#define ACLK_HDCP0_GATE 892U +#define HCLK_HDCP0_GATE 893U +#define PCLK_HDCP0_GATE 894U +/********Name=GATE_CON56,Offset=0x8E0********/ +#define ACLK_TRNG0_GATE 896U +#define PCLK_TRNG0_GATE 897U +#define CLK_AUX16MHZ_0_GATE 898U +#define CLK_AUX16MHZ_1_GATE 899U +#define PCLK_DP0_GATE 900U +#define PCLK_DP1_GATE 901U +#define PCLK_S_DP0_GATE 902U +#define PCLK_S_DP1_GATE 903U +#define CLK_DP0_GATE 904U +#define CLK_DP1_GATE 905U +#define HCLK_I2S4_8CH_GATE 906U +#define CLK_I2S4_8CH_TX_GATE 907U +#define CLK_I2S4_8CH_FRAC_TX_GATE 908U +#define MCLK_I2S4_8CH_TX_GATE 909U +#define HCLK_I2S8_8CH_GATE 910U +#define CLK_I2S8_8CH_TX_GATE 911U +/********Name=GATE_CON57,Offset=0x8E4********/ +#define CLK_I2S8_8CH_FRAC_TX_GATE 912U +#define MCLK_I2S8_8CH_TX_GATE 913U +#define HCLK_SPDIF2_DP0_GATE 914U +#define CLK_SPDIF2_DP0_GATE 915U +#define CLK_SPDIF2_DP0_FRAC_GATE 916U +#define MCLK_SPDIF2_DP0_GATE 917U +#define MCLK_SPDIF2_GATE 918U +#define HCLK_SPDIF5_DP1_GATE 919U +#define CLK_SPDIF5_DP1_GATE 920U +#define CLK_SPDIF5_DP1_FRAC_GATE 921U +#define MCLK_SPDIF5_DP1_GATE 922U +#define MCLK_SPDIF5_GATE 923U +#define MBIST_CLK_CLK_DP0_600M_GATE 924U +#define MBIST_CLK_CLK_DP0_300M_GATE 925U +#define MBIST_CLK_CLK_DP0_100M_GATE 926U +#define MBIST_CLK_CLK_DP1_600M_GATE 927U +/********Name=GATE_CON58,Offset=0x8E8********/ +#define MBIST_CLK_CLK_DP1_300M_GATE 928U +#define MBIST_CLK_CLK_DP1_100M_GATE 929U +#define MBIST_CLK_ACLK_HDCP0_GATE 930U +/********Name=GATE_CON59,Offset=0x8EC********/ +#define ACLK_HDCP1_ROOT_GATE 944U +#define ACLK_HDMIRX_ROOT_GATE 945U +#define HCLK_VO1_ROOT_GATE 946U +#define HCLK_VO1_S_ROOT_GATE 947U +#define PCLK_VO1_ROOT_GATE 948U +#define PCLK_VO1_S_ROOT_GATE 949U +#define ACLK_HDCP1_NIU_GATE 950U +#define ACLK_HDMIRX_NIU_GATE 951U +#define ACLK_VO1_NIU_GATE 952U +#define HCLK_VO1_NIU_GATE 953U +#define HCLK_VO1_S_NIU_GATE 954U +#define PCLK_VO1_NIU_GATE 955U +#define PCLK_VO1GRF_GATE 956U +#define PCLK_VO1_S_NIU_GATE 957U +#define PCLK_S_EDP0_GATE 958U +#define PCLK_S_EDP1_GATE 959U +/********Name=GATE_CON60,Offset=0x8F0********/ +#define HCLK_I2S7_8CH_GATE 960U +#define CLK_I2S7_8CH_RX_GATE 961U +#define CLK_I2S7_8CH_FRAC_RX_GATE 962U +#define MCLK_I2S7_8CH_RX_GATE 963U +#define HCLK_HDCP_KEY1_GATE 964U +#define ACLK_HDCP1_GATE 965U +#define HCLK_HDCP1_GATE 966U +#define PCLK_HDCP1_GATE 967U +#define ACLK_TRNG1_GATE 969U +#define PCLK_TRNG1_GATE 970U +#define PCLK_HDMITX0_GATE 971U +#define CLK_HDMITX0_EARC_GATE 975U +/********Name=GATE_CON61,Offset=0x8F4********/ +#define CLK_HDMITX0_REF_GATE 976U +#define PCLK_HDMITX1_GATE 978U +#define CLK_HDMITX1_EARC_GATE 982U +#define CLK_HDMITX1_REF_GATE 983U +#define ACLK_HDMIRX_GATE 985U +#define PCLK_HDMIRX_GATE 986U +#define CLK_HDMIRX_REF_GATE 987U +#define CLK_HDMIRX_AUD_SRC_GATE 988U +#define CLK_HDMIRX_AUD_FRAC_GATE 989U +#define CLK_HDMIRX_AUD_GATE 990U +#define CLK_HDMIRX_TMDSQP_GATE 991U +/********Name=GATE_CON62,Offset=0x8F8********/ +#define PCLK_EDP0_GATE 992U +#define CLK_EDP0_24M_GATE 993U +#define CLK_EDP0_200M_GATE 994U +#define PCLK_EDP1_GATE 995U +#define CLK_EDP1_24M_GATE 996U +#define CLK_EDP1_200M_GATE 997U +#define CLK_I2S5_8CH_TX_GATE 998U +#define CLK_I2S5_8CH_FRAC_TX_GATE 999U +#define MCLK_I2S5_8CH_TX_GATE 1000U +#define HCLK_I2S5_8CH_GATE 1004U +#define CLK_I2S6_8CH_TX_GATE 1005U +#define CLK_I2S6_8CH_FRAC_TX_GATE 1006U +#define MCLK_I2S6_8CH_TX_GATE 1007U +/********Name=GATE_CON63,Offset=0x8FC********/ +#define CLK_I2S6_8CH_RX_GATE 1008U +#define CLK_I2S6_8CH_FRAC_RX_GATE 1009U +#define MCLK_I2S6_8CH_RX_GATE 1010U +#define HCLK_I2S6_8CH_GATE 1011U +#define HCLK_SPDIF3_GATE 1012U +#define CLK_SPDIF3_GATE 1013U +#define CLK_SPDIF3_FRAC_GATE 1014U +#define MCLK_SPDIF3_GATE 1015U +#define HCLK_SPDIF4_GATE 1016U +#define CLK_SPDIF4_GATE 1017U +#define CLK_SPDIF4_FRAC_GATE 1018U +#define MCLK_SPDIF4_GATE 1019U +#define HCLK_SPDIFRX0_GATE 1020U +#define MCLK_SPDIFRX0_GATE 1021U +#define HCLK_SPDIFRX1_GATE 1022U +#define MCLK_SPDIFRX1_GATE 1023U +/********Name=GATE_CON64,Offset=0x900********/ +#define HCLK_SPDIFRX2_GATE 1024U +#define MCLK_SPDIFRX2_GATE 1025U +#define MBIST_CLK_ACLK_HDCP1_GATE 1026U +#define MBIST_CLK_CLK_HDMITX0_VID_GATE 1027U +#define MBIST_CLK_CLK_HDMITX0_LINK_GATE 1028U +#define MBIST_CLK_CLK_HDMITX1_VID_GATE 1029U +#define MBIST_CLK_CLK_HDMITX1_LINK_GATE 1030U +#define MBIST_CLK_CLK_HDMIRX_TMDSQP_GATE 1031U +#define MBIST_CLK_CLK_HDMIRX_REF_GATE 1032U +#define MBIST_CLK_ACLK_HDMIRX_GATE 1033U +#define MBIST_CLK_PCLK_EDP0_GATE 1034U +#define MBIST_CLK_PCLK_EDP1_GATE 1035U +#define DCLK_VOP2HDMI_BRIDGE0_VO1_GATE 1038U +#define DCLK_VOP2HDMI_BRIDGE1_VO1_GATE 1039U +/********Name=GATE_CON65,Offset=0x904********/ +#define HCLK_I2S9_8CH_GATE 1040U +#define CLK_I2S9_8CH_RX_GATE 1041U +#define CLK_I2S9_8CH_FRAC_RX_GATE 1042U +#define MCLK_I2S9_8CH_RX_GATE 1043U +#define HCLK_I2S10_8CH_GATE 1044U +#define CLK_I2S10_8CH_RX_GATE 1045U +#define CLK_I2S10_8CH_FRAC_RX_GATE 1046U +#define MCLK_I2S10_8CH_RX_GATE 1047U +#define PCLK_S_HDMIRX_GATE 1048U +#define CLK_HDMITRX_REFSRC_GATE 1049U +/********Name=GATE_CON66,Offset=0x908********/ +#define CLK_GPU_SRC_DF_GATE 1057U +#define CLK_TESTOUT_GPU_GATE 1058U +#define CLK_GPU_SRC_GATE 1059U +#define CLK_GPU_GATE 1060U +#define CLK_GPU_COREGROUP_GATE 1062U +#define CLK_GPU_STACKS_GATE 1063U +#define ACLK_S_GPU_NIU_GATE 1064U +#define ACLK_M0_GPU_NIU_GATE 1065U +#define ACLK_M1_GPU_NIU_GATE 1066U +#define ACLK_M2_GPU_NIU_GATE 1067U +#define ACLK_M3_GPU_NIU_GATE 1068U +#define PCLK_GPU_ROOT_GATE 1069U +#define PCLK_GPU_NIU_GATE 1070U +#define PCLK_PVTM2_GATE 1071U +/********Name=GATE_CON67,Offset=0x90C********/ +#define CLK_PVTM2_GATE 1072U +#define CLK_GPU_PVTM_GATE 1073U +#define PCLK_GPU_GRF_GATE 1074U +#define CLK_GPU_PVTPLL_GATE 1075U +/********Name=GATE_CON68,Offset=0x910********/ +#define ACLK_AV1_ROOT_GATE 1088U +#define ACLK_AV1_NIU_GATE 1089U +#define ACLK_AV1_GATE 1090U +#define PCLK_AV1_ROOT_GATE 1091U +#define PCLK_AV1_NIU_GATE 1092U +#define PCLK_AV1_GATE 1093U +/********Name=GATE_CON69,Offset=0x914********/ +#define ACLK_CENTER_ROOT_GATE 1104U +#define ACLK_CENTER_LOW_ROOT_GATE 1105U +#define HCLK_CENTER_ROOT_GATE 1106U +#define PCLK_CENTER_ROOT_GATE 1107U +#define ACLK_DDR_NIU_GATE 1108U +#define ACLK_DMA2DDR_GATE 1109U +#define ACLK_DDR_SHAREMEM_GATE 1110U +#define ACLK_DDR_SHAREMEM_NIU_GATE 1111U +#define ACLK_CENTER_S200_ROOT_GATE 1112U +#define ACLK_CENTER_S400_ROOT_GATE 1113U +#define ACLK_CENTER_S200_NIU_GATE 1114U +#define ACLK_CENTER_S400_NIU_GATE 1115U +#define HCLK_AHB2APB_GATE 1116U +#define HCLK_CENTER_NIU_GATE 1117U +#define FCLK_DDR_CM0_CORE_GATE 1118U +#define CLK_DDR_TIMER_ROOT_GATE 1119U +/********Name=GATE_CON70,Offset=0x918********/ +#define CLK_DDR_TIMER0_GATE 1120U +#define CLK_DDR_TIMER1_GATE 1121U +#define TCLK_WDT_DDR_GATE 1122U +#define CLK_DDR_CM0_RTC_GATE 1124U +#define PCLK_CENTER_GRF_GATE 1125U +#define PCLK_AHB2APB_GATE 1126U +#define PCLK_WDT_GATE 1127U +#define PCLK_TIMER_GATE 1128U +#define PCLK_DMA2DDR_GATE 1129U +#define PCLK_SHAREMEM_GATE 1130U +#define PCLK_CENTER_NIU_GATE 1131U +#define PCLK_CENTER_CHANNEL_NIU_GATE 1132U +#define MBIST_CLK_CLK_DDR_CM0_CORE_GATE 1133U +#define MBIST_CLK_SCLK_DDR_SHAREMEM_GATE 1134U +#define MBIST_CLK_ACLK_DMA2DDR_GATE 1135U +/********Name=GATE_CON71,Offset=0x91C********/ +#define MBIST_CLK_ACLK_NSPI_GATE 1136U +/********Name=GATE_CON72,Offset=0x920********/ +#define PCLK_USBDPGRF0_GATE 1153U +#define PCLK_USBDPPHY0_GATE 1154U +#define PCLK_USBDPGRF1_GATE 1155U +#define PCLK_USBDPPHY1_GATE 1156U +#define PCLK_HDPTX0_GATE 1157U +#define PCLK_HDPTX1_GATE 1158U +#define PCLK_APB2ASB_SLV_BOT_RIGHT_GATE 1159U +#define PCLK_USB2PHY_U3_0_GRF0_GATE 1160U +#define PCLK_USB2PHY_U3_1_GRF0_GATE 1161U +#define PCLK_USB2PHY_U2_0_GRF0_GATE 1162U +#define PCLK_USB2PHY_U2_1_GRF0_GATE 1163U +/********Name=GATE_CON73,Offset=0x924********/ +#define MBIST_CLK_HDMIRXPHY_GATE 1179U +#define CLK_HDMIHDP0_GATE 1180U +#define CLK_HDMIHDP1_GATE 1181U +/********Name=GATE_CON74,Offset=0x928********/ +#define ACLK_VO1USB_TOP_ROOT_GATE 1184U +#define ACLK_VO1USB_TOP_NIU_GATE 1185U +#define HCLK_VO1USB_TOP_ROOT_GATE 1186U +#define HCLK_VO1USB_TOP_NIU_GATE 1187U +/********Name=GATE_CON75,Offset=0x92C********/ +#define HCLK_SDIO_ROOT_GATE 1200U +#define HCLK_SDIO_NIU_GATE 1201U +#define HCLK_SDIO_GATE 1202U +#define CCLK_SRC_SDIO_GATE 1203U +#define MBIST_CLK_SDIO_GATE 1204U +/********Name=GATE_CON76,Offset=0x930********/ +#define ACLK_RGA3_ROOT_GATE 1216U +#define HCLK_RGA3_ROOT_GATE 1217U +#define HCLK_RGA3_NIU_GATE 1218U +#define ACLK_RGA3_NIU_GATE 1219U +#define HCLK_RGA3_1_GATE 1220U +#define ACLK_RGA3_1_GATE 1221U +#define CLK_RGA3_1_CORE_GATE 1222U +#define MBIST_CLK_ACLK_RGA3_1_GATE 1223U +#define MBIST_CLK_CLK_RGA3_1_CORE_GATE 1224U +/********Name=GATE_CON77,Offset=0x934********/ +#define CLK_REF_PIPE_PHY0_OSC_SRC_GATE 1232U +#define CLK_REF_PIPE_PHY1_OSC_SRC_GATE 1233U +#define CLK_REF_PIPE_PHY2_OSC_SRC_GATE 1234U +#define CLK_REF_PIPE_PHY0_PLL_SRC_GATE 1235U +#define CLK_REF_PIPE_PHY1_PLL_SRC_GATE 1236U +#define CLK_REF_PIPE_PHY2_PLL_SRC_GATE 1237U + +/********Name=PMU1GATE_CON00,Offset=0x800********/ +#define CLK_MATRIX_PMU1_50M_SRC_GATE 16U +#define CLK_MATRIX_PMU1_100M_SRC_GATE 17U +#define CLK_MATRIX_PMU1_200M_SRC_GATE 18U +#define CLK_MATRIX_PMU1_300M_SRC_GATE 19U +#define CLK_MATRIX_PMU1_400M_SRC_GATE 20U +#define HCLK_PMU1_ROOT_I_GATE 21U +#define HCLK_PMU1_ROOT_GATE 22U +#define PCLK_PMU1_ROOT_I_GATE 23U +#define HCLK_PMU_CM0_ROOT_I_GATE 24U +#define HCLK_PMU_CM0_ROOT_GATE 25U +#define HCLK_PMU1_NIU_GATE 26U +#define PCLK_PMU1_NIU_GATE 27U +#define HCLK_PMU_CM0_NIU_GATE 28U +#define FCLK_PMU_CM0_CORE_GATE 29U +#define CLK_PMU_CM0_RTC_GATE 31U +/********Name=PMU1GATE_CON01,Offset=0x804********/ +#define PCLK_PMU1_GATE 16U +#define CLK_DDR_FAIL_SAFE_GATE 17U +#define PCLK_PMU1_CRU_GATE 18U +#define CLK_PMU1_GATE 19U +#define PCLK_PMU1_GRF_GATE 20U +#define PCLK_PMU1_IOC_GATE 21U +#define PCLK_PMU1WDT_GATE 22U +#define TCLK_PMU1WDT_GATE 23U +#define PCLK_PMU1TIMER_GATE 24U +#define CLK_PMU1TIMER_ROOT_GATE 25U +#define CLK_PMU1TIMER0_GATE 26U +#define CLK_PMU1TIMER1_GATE 27U +#define PCLK_PMU1PWM_GATE 28U +#define CLK_PMU1PWM_GATE 29U +#define CLK_PMU1PWM_CAPTURE_GATE 30U +/********Name=PMU1GATE_CON02,Offset=0x808********/ +#define PCLK_I2C0_GATE 17U +#define CLK_I2C0_GATE 18U +#define CLK_UART0_GATE 19U +#define CLK_UART0_FRAC_GATE 20U +#define SCLK_UART0_GATE 21U +#define PCLK_UART0_GATE 22U +#define HCLK_I2S1_8CH_GATE 23U +#define CLK_I2S1_8CH_TX_GATE 24U +#define CLK_I2S1_8CH_FRAC_TX_GATE 25U +#define MCLK_I2S1_8CH_TX_GATE 26U +#define CLK_I2S1_8CH_RX_GATE 27U +#define CLK_I2S1_8CH_FRAC_RX_GATE 28U +#define MCLK_I2S1_8CH_RX_GATE 29U +#define HCLK_PDM0_GATE 30U +#define MCLK_PDM0_GATE 31U +/********Name=PMU1GATE_CON03,Offset=0x80C********/ +#define HCLK_VAD_GATE 16U +#define CLK_USBDP_COMBO_PHY0_REF_XTAL_GATE 21U +#define CLK_HDPTX0_REF_XTAL_GATE 27U +/********Name=PMU1GATE_CON04,Offset=0x810********/ +#define CLK_REF_MIPI_DCPHY0_GATE 19U +#define CLK_OTGPHY_U3_0_GATE 23U +#define CLK_CR_PARA_GATE 27U +/********Name=PMU1GATE_CON05,Offset=0x814********/ +#define PCLK_PMU0_ROOT_GATE 16U +#define CLK_PMU0_GATE 17U +#define PCLK_PMU0_GATE 18U +#define PCLK_PMU0GRF_GATE 19U +#define PCLK_PMU0IOC_GATE 20U +#define PCLK_GPIO0_GATE 21U +#define DBCLK_GPIO0_GATE 22U + +/********Name=CLKSEL_CON00,Offset=0x300********/ +#define CLK_MATRIX_50M_SRC_DIV 0x05000000U +#define CLK_MATRIX_100M_SRC_DIV 0x05060000U +/********Name=CLKSEL_CON01,Offset=0x304********/ +#define CLK_MATRIX_150M_SRC_DIV 0x05000001U +#define CLK_MATRIX_200M_SRC_DIV 0x05060001U +/********Name=CLKSEL_CON02,Offset=0x308********/ +#define CLK_MATRIX_250M_SRC_DIV 0x05000002U +#define CLK_MATRIX_300M_SRC_DIV 0x05060002U +/********Name=CLKSEL_CON03,Offset=0x30C********/ +#define CLK_MATRIX_350M_SRC_DIV 0x05000003U +#define CLK_MATRIX_400M_SRC_DIV 0x05060003U +/********Name=CLKSEL_CON04,Offset=0x310********/ +#define CLK_MATRIX_450M_SRC_DIV 0x05000004U +#define CLK_MATRIX_500M_SRC_DIV 0x05060004U +/********Name=CLKSEL_CON05,Offset=0x314********/ +#define CLK_MATRIX_600M_SRC_DIV 0x05000005U +#define CLK_MATRIX_650M_SRC_DIV 0x05060005U +/********Name=CLKSEL_CON06,Offset=0x318********/ +#define CLK_MATRIX_700M_SRC_DIV 0x05000006U +#define CLK_MATRIX_800M_SRC_DIV 0x05060006U +/********Name=CLKSEL_CON07,Offset=0x31C********/ +#define CLK_MATRIX_1000M_SRC_DIV 0x05000007U +#define CLK_MATRIX_1200M_SRC_DIV 0x05070007U +/********Name=CLKSEL_CON08,Offset=0x320********/ +#define ACLK_TOP_ROOT_DIV 0x05000008U +#define ACLK_LOW_TOP_ROOT_DIV 0x05090008U +/********Name=CLKSEL_CON09,Offset=0x324********/ +/********Name=CLKSEL_CON10,Offset=0x328********/ +#define CLK_TESTOUT_TOP_DIV 0x0600000AU +/********Name=CLKSEL_CON100,Offset=0x490********/ +#define CLK_RGA2_CORE_DIV 0x05000064U +#define CLK_RGA3_0_CORE_DIV 0x05080064U +/********Name=CLKSEL_CON102,Offset=0x498********/ +#define ACLK_RKVENC0_ROOT_DIV 0x05020066U +#define CLK_RKVENC0_CORE_DIV 0x05090066U +/********Name=CLKSEL_CON104,Offset=0x4A0********/ +#define ACLK_RKVENC1_ROOT_DIV 0x05020068U +#define CLK_RKVENC1_CORE_DIV 0x05090068U +/********Name=CLKSEL_CON106,Offset=0x4A8********/ +#define ACLK_VI_ROOT_DIV 0x0500006AU +/********Name=CLKSEL_CON107,Offset=0x4AC********/ +#define DCLK_VICAP_DIV 0x0500006BU +#define CLK_ISP0_CORE_DIV 0x0506006BU +/********Name=CLKSEL_CON108,Offset=0x4B0********/ +#define CLK_FISHEYE0_CORE_DIV 0x0500006CU +#define CLK_FISHEYE1_CORE_DIV 0x0507006CU +/********Name=CLKSEL_CON110,Offset=0x4B8********/ +#define ACLK_VOP_ROOT_DIV 0x0500006EU +/********Name=CLKSEL_CON111,Offset=0x4BC********/ +#define DCLK_VOP0_SRC_DIV 0x0700006FU +#define DCLK_VOP1_SRC_DIV 0x0509006FU +/********Name=CLKSEL_CON112,Offset=0x4C0********/ +#define DCLK_VOP2_SRC_DIV 0x05000070U +/********Name=CLKSEL_CON113,Offset=0x4C4********/ +#define DCLK_VOP3_DIV 0x07000071U +/********Name=CLKSEL_CON114,Offset=0x4C8********/ +#define CLK_DSIHOST0_DIV 0x07000072U +/********Name=CLKSEL_CON115,Offset=0x4CC********/ +#define CLK_DSIHOST1_DIV 0x07000073U +/********Name=CLKSEL_CON116,Offset=0x4D0********/ +#define ACLK_VO0_ROOT_DIV 0x05000074U +/********Name=CLKSEL_CON117,Offset=0x4D4********/ +#define CLK_AUX16MHZ_0_DIV 0x08000075U +#define CLK_AUX16MHZ_1_DIV 0x08080075U +/********Name=CLKSEL_CON118,Offset=0x4D8********/ +#define CLK_I2S4_8CH_TX_SRC_DIV 0x05000076U +/********Name=CLKSEL_CON119,Offset=0x4DC********/ +#define CLK_I2S4_8CH_TX_FRAC_DIV 0x20000077U +/********Name=CLKSEL_CON120,Offset=0x4E0********/ +#define CLK_I2S8_8CH_TX_SRC_DIV 0x05030078U +/********Name=CLKSEL_CON121,Offset=0x4E4********/ +#define CLK_I2S8_8CH_TX_FRAC_DIV 0x20000079U +/********Name=CLKSEL_CON122,Offset=0x4E8********/ +#define CLK_SPDIF2_DP0_SRC_DIV 0x0503007AU +/********Name=CLKSEL_CON123,Offset=0x4EC********/ +#define CLK_SPDIF2_DP0_FRAC_DIV 0x2000007BU +/********Name=CLKSEL_CON124,Offset=0x4F0********/ +#define CLK_SPDIF5_DP1_SRC_DIV 0x0502007CU +/********Name=CLKSEL_CON125,Offset=0x4F4********/ +#define CLK_SPDIF5_DP1_FRAC_DIV 0x2000007DU +/********Name=CLKSEL_CON126,Offset=0x4F8********/ +/********Name=CLKSEL_CON128,Offset=0x500********/ +#define ACLK_HDCP1_ROOT_DIV 0x05000080U +#define ACLK_HDMIRX_ROOT_DIV 0x05070080U +/********Name=CLKSEL_CON129,Offset=0x504********/ +#define CLK_I2S7_8CH_RX_SRC_DIV 0x05060081U +/********Name=CLKSEL_CON130,Offset=0x508********/ +#define CLK_I2S7_8CH_RX_FRAC_DIV 0x20000082U +/********Name=CLKSEL_CON131,Offset=0x50C********/ +/********Name=CLKSEL_CON133,Offset=0x514********/ +#define CLK_HDMITX0_EARC_DIV 0x05010085U +/********Name=CLKSEL_CON136,Offset=0x520********/ +#define CLK_HDMITX1_EARC_DIV 0x05010088U +/********Name=CLKSEL_CON138,Offset=0x528********/ +#define CLK_HDMIRX_AUD_SRC_DIV 0x0800008AU +/********Name=CLKSEL_CON139,Offset=0x52C********/ +#define CLK_HDMIRX_AUD_FRAC_DIV 0x2000008BU +/********Name=CLKSEL_CON140,Offset=0x530********/ +#define CLK_I2S5_8CH_TX_SRC_DIV 0x0505008CU +/********Name=CLKSEL_CON141,Offset=0x534********/ +#define CLK_I2S5_8CH_TX_FRAC_DIV 0x2000008DU +/********Name=CLKSEL_CON142,Offset=0x538********/ +/********Name=CLKSEL_CON144,Offset=0x540********/ +#define CLK_I2S6_8CH_TX_SRC_DIV 0x05030090U +/********Name=CLKSEL_CON145,Offset=0x544********/ +#define CLK_I2S6_8CH_TX_FRAC_DIV 0x20000091U +/********Name=CLKSEL_CON146,Offset=0x548********/ +#define CLK_I2S6_8CH_RX_SRC_DIV 0x05020092U +/********Name=CLKSEL_CON147,Offset=0x54C********/ +#define CLK_I2S6_8CH_RX_FRAC_DIV 0x20000093U +/********Name=CLKSEL_CON148,Offset=0x550********/ +#define CLK_SPDIF3_SRC_DIV 0x05040094U +/********Name=CLKSEL_CON149,Offset=0x554********/ +#define CLK_SPDIF3_FRAC_DIV 0x20000095U +/********Name=CLKSEL_CON15,Offset=0x33C********/ +#define MCLK_GMAC0_OUT_DIV 0x0700000FU +#define REFCLKO25M_ETH0_OUT_DIV 0x0708000FU +/********Name=CLKSEL_CON150,Offset=0x558********/ +#define CLK_SPDIF4_SRC_DIV 0x05020096U +/********Name=CLKSEL_CON151,Offset=0x55C********/ +#define CLK_SPDIF4_FRAC_DIV 0x20000097U +/********Name=CLKSEL_CON152,Offset=0x560********/ +#define MCLK_SPDIFRX0_DIV 0x05020098U +#define MCLK_SPDIFRX1_DIV 0x05090098U +/********Name=CLKSEL_CON153,Offset=0x564********/ +#define MCLK_SPDIFRX2_DIV 0x05000099U +#define CLK_I2S9_8CH_RX_SRC_DIV 0x05070099U +/********Name=CLKSEL_CON154,Offset=0x568********/ +#define CLK_I2S9_8CH_RX_FRAC_DIV 0x2000009AU +/********Name=CLKSEL_CON155,Offset=0x56C********/ +#define CLK_I2S10_8CH_RX_SRC_DIV 0x0503009BU +/********Name=CLKSEL_CON156,Offset=0x570********/ +#define CLK_I2S10_8CH_RX_FRAC_DIV 0x2000009CU +/********Name=CLKSEL_CON157,Offset=0x574********/ +#define CLK_HDMITRX_REFSRC_DIV 0x0502009DU +/********Name=CLKSEL_CON158,Offset=0x578********/ +#define CLK_GPU_SRC_T_DIV 0x0500009EU +#define CLK_TESTOUT_GPU_DIV 0x0508009EU +/********Name=CLKSEL_CON159,Offset=0x57C********/ +#define CLK_GPU_STACKS_DIV 0x0500009FU +#define ACLK_S_GPU_NIU_DIV 0x0505009FU +#define ACLK_M0_GPU_NIU_DIV 0x050A009FU +/********Name=CLKSEL_CON16,Offset=0x340********/ +#define REFCLKO25M_ETH1_OUT_DIV 0x07000010U +/********Name=CLKSEL_CON160,Offset=0x580********/ +#define ACLK_M1_GPU_NIU_DIV 0x050000A0U +#define ACLK_M2_GPU_NIU_DIV 0x050500A0U +#define ACLK_M3_GPU_NIU_DIV 0x050A00A0U +/********Name=CLKSEL_CON161,Offset=0x584********/ +/********Name=CLKSEL_CON163,Offset=0x58C********/ +#define ACLK_AV1_ROOT_DIV 0x050000A3U +/********Name=CLKSEL_CON165,Offset=0x594********/ +/********Name=CLKSEL_CON166,Offset=0x598********/ +#define CLK_DDR_CM0_RTC_DIV 0x050000A6U +/********Name=CLKSEL_CON17,Offset=0x344********/ +#define CLK_CIFOUT_OUT_DIV 0x08000011U +/********Name=CLKSEL_CON170,Offset=0x5A8********/ +#define ACLK_VO1USB_TOP_ROOT_DIV 0x050000AAU +/********Name=CLKSEL_CON172,Offset=0x5B0********/ +#define CCLK_SRC_SDIO_DIV 0x060200ACU +/********Name=CLKSEL_CON174,Offset=0x5B8********/ +#define ACLK_RGA3_ROOT_DIV 0x050000AEU +#define CLK_RGA3_1_CORE_DIV 0x050900AEU +/********Name=CLKSEL_CON176,Offset=0x5C0********/ +#define CLK_REF_PIPE_PHY0_PLL_SRC_DIV 0x060000B0U +#define CLK_REF_PIPE_PHY1_PLL_SRC_DIV 0x060600B0U +/********Name=CLKSEL_CON177,Offset=0x5C4********/ +#define CLK_REF_PIPE_PHY2_PLL_SRC_DIV 0x060000B1U +/********Name=CLKSEL_CON18,Offset=0x348********/ +#define CLK_MIPI_CAMARAOUT_M0_DIV 0x08000012U +/********Name=CLKSEL_CON19,Offset=0x34C********/ +#define CLK_MIPI_CAMARAOUT_M1_DIV 0x08000013U +/********Name=CLKSEL_CON20,Offset=0x350********/ +#define CLK_MIPI_CAMARAOUT_M2_DIV 0x08000014U +/********Name=CLKSEL_CON21,Offset=0x354********/ +#define CLK_MIPI_CAMARAOUT_M3_DIV 0x08000015U +/********Name=CLKSEL_CON22,Offset=0x358********/ +#define CLK_MIPI_CAMARAOUT_M4_DIV 0x08000016U +/********Name=CLKSEL_CON24,Offset=0x360********/ +#define CLK_I2S0_8CH_TX_SRC_DIV 0x05040018U +/********Name=CLKSEL_CON25,Offset=0x364********/ +#define CLK_I2S0_8CH_TX_FRAC_DIV 0x20000019U +/********Name=CLKSEL_CON26,Offset=0x368********/ +#define CLK_I2S0_8CH_RX_SRC_DIV 0x0502001AU +/********Name=CLKSEL_CON27,Offset=0x36C********/ +#define CLK_I2S0_8CH_RX_FRAC_DIV 0x2000001BU +/********Name=CLKSEL_CON28,Offset=0x370********/ +#define CLK_I2S2_2CH_SRC_DIV 0x0504001CU +/********Name=CLKSEL_CON29,Offset=0x374********/ +#define CLK_I2S2_2CH_FRAC_DIV 0x2000001DU +/********Name=CLKSEL_CON30,Offset=0x378********/ +#define CLK_I2S3_2CH_SRC_DIV 0x0503001EU +/********Name=CLKSEL_CON31,Offset=0x37C********/ +#define CLK_I2S3_2CH_FRAC_DIV 0x2000001FU +/********Name=CLKSEL_CON32,Offset=0x380********/ +#define CLK_SPDIF0_SRC_DIV 0x05030020U +/********Name=CLKSEL_CON33,Offset=0x384********/ +#define CLK_SPDIF0_FRAC_DIV 0x20000021U +/********Name=CLKSEL_CON34,Offset=0x388********/ +#define CLK_SPDIF1_SRC_DIV 0x05020022U +/********Name=CLKSEL_CON35,Offset=0x38C********/ +#define CLK_SPDIF1_FRAC_DIV 0x20000023U +/********Name=CLKSEL_CON36,Offset=0x390********/ +#define MCLK_PDM1_DIV 0x05020024U +/********Name=CLKSEL_CON38,Offset=0x398********/ +#define ACLK_BUS_ROOT_DIV 0x05000026U +/********Name=CLKSEL_CON39,Offset=0x39C********/ +#define CLK_CAN0_DIV 0x05000027U +#define CLK_CAN1_DIV 0x05060027U +/********Name=CLKSEL_CON40,Offset=0x3A0********/ +#define CLK_CAN2_DIV 0x05000028U +#define CLK_SARADC_DIV 0x08060028U +/********Name=CLKSEL_CON41,Offset=0x3A4********/ +#define CLK_TSADC_DIV 0x08000029U +#define CLK_UART1_SRC_DIV 0x05090029U +/********Name=CLKSEL_CON42,Offset=0x3A8********/ +#define CLK_UART1_FRAC_DIV 0x2000002AU +/********Name=CLKSEL_CON43,Offset=0x3AC********/ +#define CLK_UART2_SRC_DIV 0x0502002BU +/********Name=CLKSEL_CON44,Offset=0x3B0********/ +#define CLK_UART2_FRAC_DIV 0x2000002CU +/********Name=CLKSEL_CON45,Offset=0x3B4********/ +#define CLK_UART3_SRC_DIV 0x0502002DU +/********Name=CLKSEL_CON46,Offset=0x3B8********/ +#define CLK_UART3_FRAC_DIV 0x2000002EU +/********Name=CLKSEL_CON47,Offset=0x3BC********/ +#define CLK_UART4_SRC_DIV 0x0502002FU +/********Name=CLKSEL_CON48,Offset=0x3C0********/ +#define CLK_UART4_FRAC_DIV 0x20000030U +/********Name=CLKSEL_CON49,Offset=0x3C4********/ +#define CLK_UART5_SRC_DIV 0x05020031U +/********Name=CLKSEL_CON50,Offset=0x3C8********/ +#define CLK_UART5_FRAC_DIV 0x20000032U +/********Name=CLKSEL_CON51,Offset=0x3CC********/ +#define CLK_UART6_SRC_DIV 0x05020033U +/********Name=CLKSEL_CON52,Offset=0x3D0********/ +#define CLK_UART6_FRAC_DIV 0x20000034U +/********Name=CLKSEL_CON53,Offset=0x3D4********/ +#define CLK_UART7_SRC_DIV 0x05020035U +/********Name=CLKSEL_CON54,Offset=0x3D8********/ +#define CLK_UART7_FRAC_DIV 0x20000036U +/********Name=CLKSEL_CON55,Offset=0x3DC********/ +#define CLK_UART8_SRC_DIV 0x05020037U +/********Name=CLKSEL_CON56,Offset=0x3E0********/ +#define CLK_UART8_FRAC_DIV 0x20000038U +/********Name=CLKSEL_CON57,Offset=0x3E4********/ +#define CLK_UART9_SRC_DIV 0x05020039U +/********Name=CLKSEL_CON58,Offset=0x3E8********/ +#define CLK_UART9_FRAC_DIV 0x2000003AU +/********Name=CLKSEL_CON59,Offset=0x3EC********/ +/********Name=CLKSEL_CON60,Offset=0x3F0********/ +#define DBCLK_GPIO1_DIV 0x0503003CU +#define DBCLK_GPIO2_DIV 0x0509003CU +/********Name=CLKSEL_CON61,Offset=0x3F4********/ +#define DBCLK_GPIO3_DIV 0x0500003DU +#define DBCLK_GPIO4_DIV 0x0506003DU +/********Name=CLKSEL_CON62,Offset=0x3F8********/ +#define DCLK_DECOM_DIV 0x0500003EU +#define CLK_BISRINTF_PLLSRC_DIV 0x0506003EU +/********Name=CLKSEL_CON63,Offset=0x3FC********/ +#define CLK_TESTOUT_DDR01_DIV 0x0600003FU +/********Name=CLKSEL_CON65,Offset=0x404********/ +#define CLK_TESTOUT_DDR23_DIV 0x06000041U +/********Name=CLKSEL_CON67,Offset=0x40C********/ +#define ACLK_ISP1_ROOT_DIV 0x05000043U +#define CLK_ISP1_CORE_DIV 0x05090043U +/********Name=CLKSEL_CON73,Offset=0x424********/ +#define CLK_RKNN_DSU0_SRC_T_DIV 0x05020049U +#define CLK_TESTOUT_NPU_DIV 0x050A0049U +/********Name=CLKSEL_CON74,Offset=0x428********/ +#define CLK_NPU_CM0_RTC_DIV 0x0507004AU +/********Name=CLKSEL_CON77,Offset=0x434********/ +#define ACLK_NVM_ROOT_DIV 0x0502004DU +#define CCLK_EMMC_DIV 0x0608004DU +/********Name=CLKSEL_CON78,Offset=0x438********/ +#define BCLK_EMMC_DIV 0x0500004EU +#define SCLK_SFC_DIV 0x0606004EU +/********Name=CLKSEL_CON80,Offset=0x440********/ +#define ACLK_PCIE_ROOT_DIV 0x05020050U +#define ACLK_PHP_ROOT_DIV 0x05080050U +/********Name=CLKSEL_CON81,Offset=0x444********/ +#define CLK_GMAC0_PTP_REF_DIV 0x06000051U +#define CLK_GMAC1_PTP_REF_DIV 0x06070051U +/********Name=CLKSEL_CON82,Offset=0x448********/ +#define CLK_RXOOB0_DIV 0x07000052U +#define CLK_RXOOB1_DIV 0x07080052U +/********Name=CLKSEL_CON83,Offset=0x44C********/ +#define CLK_RXOOB2_DIV 0x07000053U +#define CLK_GMAC_125M_CRU_I_DIV 0x07080053U +/********Name=CLKSEL_CON84,Offset=0x450********/ +#define CLK_GMAC_50M_CRU_I_DIV 0x07000054U +#define CLK_UTMI_OTG2_DIV 0x04080054U +/********Name=CLKSEL_CON85,Offset=0x454********/ +#define CLK_GMAC0_TX_125M_O_DIV 0x06000055U +#define CLK_GMAC1_TX_125M_O_DIV 0x06060055U +/********Name=CLKSEL_CON89,Offset=0x464********/ +#define ACLK_RKVDEC0_ROOT_DIV 0x05020059U +#define ACLK_RKVDEC_CCU_DIV 0x05090059U +/********Name=CLKSEL_CON90,Offset=0x468********/ +#define CLK_RKVDEC0_CA_DIV 0x0500005AU +#define CLK_RKVDEC0_HEVC_CA_DIV 0x0506005AU +/********Name=CLKSEL_CON91,Offset=0x46C********/ +#define CLK_RKVDEC0_CORE_DIV 0x0500005BU +/********Name=CLKSEL_CON93,Offset=0x474********/ +#define ACLK_RKVDEC1_ROOT_DIV 0x0502005DU +#define CLK_RKVDEC1_CA_DIV 0x0509005DU +/********Name=CLKSEL_CON94,Offset=0x478********/ +#define CLK_RKVDEC1_HEVC_CA_DIV 0x0500005EU +#define CLK_RKVDEC1_CORE_DIV 0x0507005EU +/********Name=CLKSEL_CON96,Offset=0x480********/ +#define ACLK_USB_ROOT_DIV 0x05000060U +/********Name=CLKSEL_CON98,Offset=0x488********/ +#define ACLK_VDPU_ROOT_DIV 0x05000062U +/********Name=CLKSEL_CON99,Offset=0x48C********/ +#define ACLK_JPEG_DECODER_ROOT_DIV 0x05000063U +#define CLK_IEP2P0_CORE_DIV 0x05070063U +/********Name=PMU1CLKSEL_CON00,Offset=0x300********/ +#define CLK_MATRIX_PMU1_50M_SRC_DIV 0x04000000U +#define CLK_MATRIX_PMU1_100M_SRC_DIV 0x03040000U +#define CLK_MATRIX_PMU1_200M_SRC_DIV 0x03070000U +#define CLK_MATRIX_PMU1_300M_SRC_DIV 0x050A0000U +/********Name=PMU1CLKSEL_CON01,Offset=0x304********/ +#define CLK_MATRIX_PMU1_400M_SRC_DIV 0x05000001U +/********Name=PMU1CLKSEL_CON02,Offset=0x308********/ +#define CLK_PMU_CM0_RTC_DIV 0x05000002U +/********Name=PMU1CLKSEL_CON03,Offset=0x30C********/ +#define CLK_UART0_SRC_DIV 0x05070003U +/********Name=PMU1CLKSEL_CON04,Offset=0x310********/ +#define CLK_UART0_FRAC_DIV 0x20000004U +/********Name=PMU1CLKSEL_CON05,Offset=0x314********/ +#define CLK_I2S1_8CH_TX_SRC_DIV 0x05020005U +/********Name=PMU1CLKSEL_CON06,Offset=0x318********/ +#define CLK_I2S1_8CH_TX_FRAC_DIV 0x20000006U +/********Name=PMU1CLKSEL_CON07,Offset=0x31C********/ +#define CLK_I2S1_8CH_RX_SRC_DIV 0x05020007U +/********Name=PMU1CLKSEL_CON08,Offset=0x320********/ +#define CLK_I2S1_8CH_RX_FRAC_DIV 0x20000008U +/********Name=PMU1CLKSEL_CON09,Offset=0x324********/ +#define CLK_USBDP_COMBO_PHY0_REF_XTAL_DIV 0x05050009U +/********Name=PMU1CLKSEL_CON12,Offset=0x330********/ +#define CLK_HDPTX0_REF_XTAL_DIV 0x0506000CU +/********Name=PMU1CLKSEL_CON14,Offset=0x338********/ +#define CLK_REF_MIPI_DCPHY0_DIV 0x0700000EU +#define CLK_OTGPHY_U3_0_DIV 0x0509000EU +/********Name=PMU1CLKSEL_CON15,Offset=0x33C********/ +#define CLK_CR_PARA_DIV 0x0500000FU +/********Name=PMU1CLKSEL_CON17,Offset=0x344********/ +/********Name=PMU1SCLKSEL_CON00,Offset=0x300********/ +/********Name=PMU1SCLKSEL_CON02,Offset=0x308********/ +#define XIN_OSC0_DIV_DIV 0x20000001U + +/********Name=CLKSEL_CON00,Offset=0x300********/ +#define CLK_MATRIX_50M_SRC_SEL 0x01050000U +#define CLK_MATRIX_50M_SRC_SEL_CLK_CPLL_MUX 0U +#define CLK_MATRIX_100M_SRC_SEL 0x010B0000U +#define CLK_MATRIX_100M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON01,Offset=0x304********/ +#define CLK_MATRIX_150M_SRC_SEL 0x01050001U +#define CLK_MATRIX_150M_SRC_SEL_CLK_CPLL_MUX 0U +#define CLK_MATRIX_200M_SRC_SEL 0x010B0001U +#define CLK_MATRIX_200M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON02,Offset=0x308********/ +#define CLK_MATRIX_250M_SRC_SEL 0x01050002U +#define CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX 0U +#define CLK_MATRIX_300M_SRC_SEL 0x010B0002U +#define CLK_MATRIX_300M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON03,Offset=0x30C********/ +#define CLK_MATRIX_350M_SRC_SEL 0x01050003U +#define CLK_MATRIX_350M_SRC_SEL_CLK_SPLL_MUX 0U +#define CLK_MATRIX_400M_SRC_SEL 0x010B0003U +#define CLK_MATRIX_400M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON04,Offset=0x310********/ +#define CLK_MATRIX_450M_SRC_SEL 0x01050004U +#define CLK_MATRIX_450M_SRC_SEL_CLK_CPLL_MUX 0U +#define CLK_MATRIX_500M_SRC_SEL 0x010B0004U +#define CLK_MATRIX_500M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON05,Offset=0x314********/ +#define CLK_MATRIX_600M_SRC_SEL 0x01050005U +#define CLK_MATRIX_600M_SRC_SEL_CLK_CPLL_MUX 0U +#define CLK_MATRIX_650M_SRC_SEL 0x010B0005U +#define CLK_MATRIX_650M_SRC_SEL_CLK_LPLL_MUX 0U +/********Name=CLKSEL_CON06,Offset=0x318********/ +#define CLK_MATRIX_700M_SRC_SEL 0x01050006U +#define CLK_MATRIX_700M_SRC_SEL_CLK_SPLL_MUX 0U +#define CLK_MATRIX_800M_SRC_SEL 0x010B0006U +#define CLK_MATRIX_800M_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON07,Offset=0x31C********/ +#define CLK_MATRIX_1000M_SRC_SEL 0x02050007U +#define CLK_MATRIX_1000M_SRC_SEL_CLK_V0PLL_MUX 0U +#define CLK_MATRIX_1200M_SRC_SEL 0x010C0007U +#define CLK_MATRIX_1200M_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON08,Offset=0x320********/ +#define ACLK_TOP_ROOT_SEL 0x02050008U +#define ACLK_TOP_ROOT_SEL_CLK_AUPLL_MUX 0U +#define PCLK_TOP_ROOT_SEL 0x02070008U +#define PCLK_TOP_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_LOW_TOP_ROOT_SEL 0x010E0008U +#define ACLK_LOW_TOP_ROOT_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON09,Offset=0x324********/ +#define ACLK_TOP_M300_ROOT_SEL 0x02000009U +#define ACLK_TOP_M300_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_TOP_M500_ROOT_SEL 0x02020009U +#define ACLK_TOP_M500_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_TOP_M400_ROOT_SEL 0x02040009U +#define ACLK_TOP_M400_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_TOP_S200_ROOT_SEL 0x02060009U +#define ACLK_TOP_S200_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_TOP_S400_ROOT_SEL 0x02080009U +#define ACLK_TOP_S400_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON10,Offset=0x328********/ +#define CLK_TESTOUT_TOP_SEL 0x0306000AU +#define CLK_TESTOUT_TOP_SEL_CLK_DEEPSLOW 0U +#define CLK_TESTOUT_SEL 0x0309000AU +#define CLK_TESTOUT_SEL_CLK_TESTOUT_DDR23 0U +#define CLK_TESTOUT_GRP0_SEL 0x030C000AU +#define CLK_TESTOUT_GRP0_SEL_CLK_TESTOUT_NPU 0U +/********Name=CLKSEL_CON100,Offset=0x490********/ +#define CLK_RGA2_CORE_SEL 0x03050064U +#define CLK_RGA2_CORE_SEL_CLK_SPLL_MUX 0U +#define CLK_RGA3_0_CORE_SEL 0x030D0064U +#define CLK_RGA3_0_CORE_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON102,Offset=0x498********/ +#define HCLK_RKVENC0_ROOT_SEL 0x02000066U +#define HCLK_RKVENC0_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_RKVENC0_ROOT_SEL 0x02070066U +#define ACLK_RKVENC0_ROOT_SEL_CLK_NPLL_MUX 0U +#define CLK_RKVENC0_CORE_SEL 0x020E0066U +#define CLK_RKVENC0_CORE_SEL_CLK_NPLL_MUX 0U +/********Name=CLKSEL_CON104,Offset=0x4A0********/ +#define HCLK_RKVENC1_ROOT_SEL 0x02000068U +#define HCLK_RKVENC1_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_RKVENC1_ROOT_SEL 0x02070068U +#define ACLK_RKVENC1_ROOT_SEL_CLK_NPLL_MUX 0U +#define CLK_RKVENC1_CORE_SEL 0x020E0068U +#define CLK_RKVENC1_CORE_SEL_CLK_NPLL_MUX 0U +/********Name=CLKSEL_CON106,Offset=0x4A8********/ +#define ACLK_VI_ROOT_SEL 0x0305006AU +#define ACLK_VI_ROOT_SEL_CLK_SPLL_MUX 0U +#define HCLK_VI_ROOT_SEL 0x0208006AU +#define HCLK_VI_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VI_ROOT_SEL 0x020A006AU +#define PCLK_VI_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON107,Offset=0x4AC********/ +#define DCLK_VICAP_SEL 0x0105006BU +#define DCLK_VICAP_SEL_CLK_CPLL_MUX 0U +#define CLK_ISP0_CORE_SEL 0x020B006BU +#define CLK_ISP0_CORE_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON108,Offset=0x4B0********/ +#define CLK_FISHEYE0_CORE_SEL 0x0205006CU +#define CLK_FISHEYE0_CORE_SEL_CLK_SPLL_MUX 0U +#define CLK_FISHEYE1_CORE_SEL 0x020C006CU +#define CLK_FISHEYE1_CORE_SEL_CLK_SPLL_MUX 0U +#define ICLK_CSIHOST01_SEL 0x020E006CU +#define ICLK_CSIHOST01_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON110,Offset=0x4B8********/ +#define ACLK_VOP_ROOT_SEL 0x0305006EU +#define ACLK_VOP_ROOT_SEL_CLK_SPLL_MUX 0U +#define ACLK_VOP_LOW_ROOT_SEL 0x0208006EU +#define ACLK_VOP_LOW_ROOT_SEL_XIN_OSC0_FUNC 0U +#define HCLK_VOP_ROOT_SEL 0x020A006EU +#define HCLK_VOP_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VOP_ROOT_SEL 0x020C006EU +#define PCLK_VOP_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON111,Offset=0x4BC********/ +#define DCLK_VOP0_SRC_SEL 0x0207006FU +#define DCLK_VOP0_SRC_SEL_CLK_AUPLL_MUX 0U +#define DCLK_VOP1_SRC_SEL 0x020E006FU +#define DCLK_VOP1_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON112,Offset=0x4C0********/ +#define DCLK_VOP2_SRC_SEL 0x02050070U +#define DCLK_VOP2_SRC_SEL_CLK_AUPLL_MUX 0U +#define DCLK_VOP0_SEL 0x02070070U +#define DCLK_VOP0_SEL_CLK_HDMIPHY_PIXEL1_O 0U +#define DCLK_VOP1_SEL 0x02090070U +#define DCLK_VOP1_SEL_CLK_HDMIPHY_PIXEL1_O 0U +#define DCLK_VOP2_SEL 0x020B0070U +#define DCLK_VOP2_SEL_CLK_HDMIPHY_PIXEL1_O 0U +/********Name=CLKSEL_CON113,Offset=0x4C4********/ +#define DCLK_VOP3_SEL 0x02070071U +#define DCLK_VOP3_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON114,Offset=0x4C8********/ +#define CLK_DSIHOST0_SEL 0x02070072U +#define CLK_DSIHOST0_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON115,Offset=0x4CC********/ +#define CLK_DSIHOST1_SEL 0x02070073U +#define CLK_DSIHOST1_SEL_CLK_SPLL_MUX 0U +#define ACLK_VOP_SUB_SRC_SEL 0x01090073U +#define ACLK_VOP_SUB_SRC_SEL_ACLK_VOP_DIV2_SRC 0U +/********Name=CLKSEL_CON116,Offset=0x4D0********/ +#define ACLK_VO0_ROOT_SEL 0x01050074U +#define ACLK_VO0_ROOT_SEL_CLK_CPLL_MUX 0U +#define HCLK_VO0_ROOT_SEL 0x02060074U +#define HCLK_VO0_ROOT_SEL_XIN_OSC0_FUNC 0U +#define HCLK_VO0_S_ROOT_SEL 0x02080074U +#define HCLK_VO0_S_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VO0_ROOT_SEL 0x020A0074U +#define PCLK_VO0_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VO0_S_ROOT_SEL 0x020C0074U +#define PCLK_VO0_S_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON117,Offset=0x4D4********/ +/********Name=CLKSEL_CON118,Offset=0x4D8********/ +#define CLK_I2S4_8CH_TX_SRC_SEL 0x01050076U +#define CLK_I2S4_8CH_TX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON119,Offset=0x4DC********/ +/********Name=CLKSEL_CON120,Offset=0x4E0********/ +#define MCLK_I2S4_8CH_TX_SEL 0x02000078U +#define MCLK_I2S4_8CH_TX_SEL_XIN_OSC0_HALF 0U +#define I2S4_8CH_MCLKOUT_SEL 0x01020078U +#define I2S4_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S8_8CH_TX_SRC_SEL 0x01080078U +#define CLK_I2S8_8CH_TX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON121,Offset=0x4E4********/ +/********Name=CLKSEL_CON122,Offset=0x4E8********/ +#define MCLK_I2S8_8CH_TX_SEL 0x0200007AU +#define MCLK_I2S8_8CH_TX_SEL_XIN_OSC0_HALF 0U +#define I2S8_8CH_MCLKOUT_SEL 0x0102007AU +#define I2S8_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF2_DP0_SRC_SEL 0x0108007AU +#define CLK_SPDIF2_DP0_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON123,Offset=0x4EC********/ +/********Name=CLKSEL_CON124,Offset=0x4F0********/ +#define MCLK_4X_SPDIF2_DP0_SEL 0x0200007CU +#define MCLK_4X_SPDIF2_DP0_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF5_DP1_SRC_SEL 0x0107007CU +#define CLK_SPDIF5_DP1_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON125,Offset=0x4F4********/ +/********Name=CLKSEL_CON126,Offset=0x4F8********/ +#define MCLK_4X_SPDIF5_DP1_SEL 0x0200007EU +#define MCLK_4X_SPDIF5_DP1_SEL_XIN_OSC0_HALF 0U +/********Name=CLKSEL_CON128,Offset=0x500********/ +#define ACLK_HDCP1_ROOT_SEL 0x02050080U +#define ACLK_HDCP1_ROOT_SEL_CLK_HDMITRX_REFSRC 0U +#define ACLK_HDMIRX_ROOT_SEL 0x010C0080U +#define ACLK_HDMIRX_ROOT_SEL_CLK_CPLL_MUX 0U +#define HCLK_VO1_ROOT_SEL 0x020D0080U +#define HCLK_VO1_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON129,Offset=0x504********/ +#define HCLK_VO1_S_ROOT_SEL 0x02000081U +#define HCLK_VO1_S_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VO1_ROOT_SEL 0x02020081U +#define PCLK_VO1_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_VO1_S_ROOT_SEL 0x02040081U +#define PCLK_VO1_S_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_I2S7_8CH_RX_SRC_SEL 0x010B0081U +#define CLK_I2S7_8CH_RX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON130,Offset=0x508********/ +/********Name=CLKSEL_CON131,Offset=0x50C********/ +#define MCLK_I2S7_8CH_RX_SEL 0x02000083U +#define MCLK_I2S7_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define I2S7_8CH_MCLKOUT_SEL 0x01020083U +#define I2S7_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +/********Name=CLKSEL_CON133,Offset=0x514********/ +#define CLK_HDMITX0_EARC_SEL 0x01060085U +#define CLK_HDMITX0_EARC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON136,Offset=0x520********/ +#define CLK_HDMITX1_EARC_SEL 0x01060088U +#define CLK_HDMITX1_EARC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON138,Offset=0x528********/ +#define CLK_HDMIRX_AUD_SRC_SEL 0x0108008AU +#define CLK_HDMIRX_AUD_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON139,Offset=0x52C********/ +/********Name=CLKSEL_CON140,Offset=0x530********/ +#define CLK_HDMIRX_AUD_SEL 0x0100008CU +#define CLK_HDMIRX_AUD_SEL_CLK_HDMIRX_AUD_FRAC 0U +#define CLK_EDP0_200M_SEL 0x0201008CU +#define CLK_EDP0_200M_SEL_XIN_OSC0_FUNC 0U +#define CLK_EDP1_200M_SEL 0x0203008CU +#define CLK_EDP1_200M_SEL_XIN_OSC0_FUNC 0U +#define CLK_I2S5_8CH_TX_SRC_SEL 0x010A008CU +#define CLK_I2S5_8CH_TX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON141,Offset=0x534********/ +/********Name=CLKSEL_CON142,Offset=0x538********/ +#define MCLK_I2S5_8CH_TX_SEL 0x0200008EU +#define MCLK_I2S5_8CH_TX_SEL_XIN_OSC0_HALF 0U +/********Name=CLKSEL_CON144,Offset=0x540********/ +#define I2S5_8CH_MCLKOUT_SEL 0x01020090U +#define I2S5_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S6_8CH_TX_SRC_SEL 0x01080090U +#define CLK_I2S6_8CH_TX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON145,Offset=0x544********/ +/********Name=CLKSEL_CON146,Offset=0x548********/ +#define MCLK_I2S6_8CH_TX_SEL 0x02000092U +#define MCLK_I2S6_8CH_TX_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S6_8CH_RX_SRC_SEL 0x01070092U +#define CLK_I2S6_8CH_RX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON147,Offset=0x54C********/ +/********Name=CLKSEL_CON148,Offset=0x550********/ +#define MCLK_I2S6_8CH_RX_SEL 0x02000094U +#define MCLK_I2S6_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define I2S6_8CH_MCLKOUT_SEL 0x02020094U +#define I2S6_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF3_SRC_SEL 0x01090094U +#define CLK_SPDIF3_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON149,Offset=0x554********/ +/********Name=CLKSEL_CON15,Offset=0x33C********/ +#define MCLK_GMAC0_OUT_SEL 0x0107000FU +#define MCLK_GMAC0_OUT_SEL_CLK_CPLL_MUX 0U +#define REFCLKO25M_ETH0_OUT_SEL 0x010F000FU +#define REFCLKO25M_ETH0_OUT_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON150,Offset=0x558********/ +#define MCLK_SPDIF3_SEL 0x02000096U +#define MCLK_SPDIF3_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF4_SRC_SEL 0x01070096U +#define CLK_SPDIF4_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON151,Offset=0x55C********/ +/********Name=CLKSEL_CON152,Offset=0x560********/ +#define MCLK_SPDIF4_SEL 0x02000098U +#define MCLK_SPDIF4_SEL_XIN_OSC0_HALF 0U +#define MCLK_SPDIFRX0_SEL 0x02070098U +#define MCLK_SPDIFRX0_SEL_CLK_AUPLL_MUX 0U +#define MCLK_SPDIFRX1_SEL 0x020E0098U +#define MCLK_SPDIFRX1_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON153,Offset=0x564********/ +#define MCLK_SPDIFRX2_SEL 0x02050099U +#define MCLK_SPDIFRX2_SEL_CLK_AUPLL_MUX 0U +#define CLK_I2S9_8CH_RX_SRC_SEL 0x010C0099U +#define CLK_I2S9_8CH_RX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON154,Offset=0x568********/ +/********Name=CLKSEL_CON155,Offset=0x56C********/ +#define MCLK_I2S9_8CH_RX_SEL 0x0200009BU +#define MCLK_I2S9_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S10_8CH_RX_SRC_SEL 0x0108009BU +#define CLK_I2S10_8CH_RX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON156,Offset=0x570********/ +/********Name=CLKSEL_CON157,Offset=0x574********/ +#define MCLK_I2S10_8CH_RX_SEL 0x0200009DU +#define MCLK_I2S10_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define CLK_HDMITRX_REFSRC_SEL 0x0107009DU +#define CLK_HDMITRX_REFSRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON158,Offset=0x578********/ +#define CLK_GPU_SRC_T_SEL 0x0305009EU +#define CLK_GPU_SRC_T_SEL_CLK_SPLL_MUX 0U +#define CLK_TESTOUT_GPU_SEL 0x010D009EU +#define CLK_TESTOUT_GPU_SEL_CLK_GPU_PVTPLL 0U +#define CLK_GPU_SRC_SEL 0x010E009EU +#define CLK_GPU_SRC_SEL_CLK_GPU_PVTPLL 0U +/********Name=CLKSEL_CON159,Offset=0x57C********/ +/********Name=CLKSEL_CON16,Offset=0x340********/ +#define REFCLKO25M_ETH1_OUT_SEL 0x01070010U +#define REFCLKO25M_ETH1_OUT_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON160,Offset=0x580********/ +/********Name=CLKSEL_CON161,Offset=0x584********/ +#define PCLK_GPU_ROOT_SEL 0x020000A1U +#define PCLK_GPU_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_GPU_PVTPLL_SEL 0x010200A1U +#define CLK_GPU_PVTPLL_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON163,Offset=0x58C********/ +#define ACLK_AV1_ROOT_SEL 0x020500A3U +#define ACLK_AV1_ROOT_SEL_CLK_AUPLL_MUX 0U +#define PCLK_AV1_ROOT_SEL 0x020700A3U +#define PCLK_AV1_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON165,Offset=0x594********/ +#define ACLK_CENTER_ROOT_SEL 0x020000A5U +#define ACLK_CENTER_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_CENTER_LOW_ROOT_SEL 0x020200A5U +#define ACLK_CENTER_LOW_ROOT_SEL_XIN_OSC0_FUNC 0U +#define HCLK_CENTER_ROOT_SEL 0x020400A5U +#define HCLK_CENTER_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_CENTER_ROOT_SEL 0x020600A5U +#define PCLK_CENTER_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_CENTER_S200_ROOT_SEL 0x020800A5U +#define ACLK_CENTER_S200_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_CENTER_S400_ROOT_SEL 0x020A00A5U +#define ACLK_CENTER_S400_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_DDR_TIMER_ROOT_SEL 0x010C00A5U +#define CLK_DDR_TIMER_ROOT_SEL_CLK_MATRIX_100M_SRC 0U +/********Name=CLKSEL_CON166,Offset=0x598********/ +#define CLK_DDR_CM0_RTC_SEL 0x010500A6U +#define CLK_DDR_CM0_RTC_SEL_CLK_DEEPSLOW 0U +/********Name=CLKSEL_CON17,Offset=0x344********/ +#define CLK_CIFOUT_OUT_SEL 0x02080011U +#define CLK_CIFOUT_OUT_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON170,Offset=0x5A8********/ +#define ACLK_VO1USB_TOP_ROOT_SEL 0x010500AAU +#define ACLK_VO1USB_TOP_ROOT_SEL_CLK_CPLL_MUX 0U +#define HCLK_VO1USB_TOP_ROOT_SEL 0x020600AAU +#define HCLK_VO1USB_TOP_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON172,Offset=0x5B0********/ +#define HCLK_SDIO_ROOT_SEL 0x020000ACU +#define HCLK_SDIO_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CCLK_SRC_SDIO_SEL 0x020800ACU +#define CCLK_SRC_SDIO_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON174,Offset=0x5B8********/ +#define ACLK_RGA3_ROOT_SEL 0x020500AEU +#define ACLK_RGA3_ROOT_SEL_CLK_AUPLL_MUX 0U +#define HCLK_RGA3_ROOT_SEL 0x020700AEU +#define HCLK_RGA3_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_RGA3_1_CORE_SEL 0x020E00AEU +#define CLK_RGA3_1_CORE_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON176,Offset=0x5C0********/ +/********Name=CLKSEL_CON177,Offset=0x5C4********/ +#define CLK_REF_PIPE_PHY0_SEL 0x010600B1U +#define CLK_REF_PIPE_PHY0_SEL_CLK_REF_PIPE_PHY0_PLL_SRC 0U +#define CLK_REF_PIPE_PHY1_SEL 0x010700B1U +#define CLK_REF_PIPE_PHY1_SEL_CLK_REF_PIPE_PHY1_PLL_SRC 0U +#define CLK_REF_PIPE_PHY2_SEL 0x010800B1U +#define CLK_REF_PIPE_PHY2_SEL_CLK_REF_PIPE_PHY2_PLL_SRC 0U +/********Name=CLKSEL_CON18,Offset=0x348********/ +#define CLK_MIPI_CAMARAOUT_M0_SEL 0x02080012U +#define CLK_MIPI_CAMARAOUT_M0_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON19,Offset=0x34C********/ +#define CLK_MIPI_CAMARAOUT_M1_SEL 0x02080013U +#define CLK_MIPI_CAMARAOUT_M1_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON20,Offset=0x350********/ +#define CLK_MIPI_CAMARAOUT_M2_SEL 0x02080014U +#define CLK_MIPI_CAMARAOUT_M2_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON21,Offset=0x354********/ +#define CLK_MIPI_CAMARAOUT_M3_SEL 0x02080015U +#define CLK_MIPI_CAMARAOUT_M3_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON22,Offset=0x358********/ +#define CLK_MIPI_CAMARAOUT_M4_SEL 0x02080016U +#define CLK_MIPI_CAMARAOUT_M4_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON24,Offset=0x360********/ +#define HCLK_AUDIO_ROOT_SEL 0x02000018U +#define HCLK_AUDIO_ROOT_SEL_XIN_OSC0_FUNC 0U +#define PCLK_AUDIO_ROOT_SEL 0x02020018U +#define PCLK_AUDIO_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_I2S0_8CH_TX_SRC_SEL 0x01090018U +#define CLK_I2S0_8CH_TX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON25,Offset=0x364********/ +/********Name=CLKSEL_CON26,Offset=0x368********/ +#define MCLK_I2S0_8CH_TX_SEL 0x0200001AU +#define MCLK_I2S0_8CH_TX_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S0_8CH_RX_SRC_SEL 0x0107001AU +#define CLK_I2S0_8CH_RX_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON27,Offset=0x36C********/ +/********Name=CLKSEL_CON28,Offset=0x370********/ +#define MCLK_I2S0_8CH_RX_SEL 0x0200001CU +#define MCLK_I2S0_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define I2S0_8CH_MCLKOUT_SEL 0x0202001CU +#define I2S0_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S2_2CH_SRC_SEL 0x0109001CU +#define CLK_I2S2_2CH_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON29,Offset=0x374********/ +/********Name=CLKSEL_CON30,Offset=0x378********/ +#define MCLK_I2S2_2CH_SEL 0x0200001EU +#define MCLK_I2S2_2CH_SEL_XIN_OSC0_HALF 0U +#define I2S2_2CH_MCLKOUT_SEL 0x0102001EU +#define I2S2_2CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_I2S3_2CH_SRC_SEL 0x0108001EU +#define CLK_I2S3_2CH_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON31,Offset=0x37C********/ +/********Name=CLKSEL_CON32,Offset=0x380********/ +#define MCLK_I2S3_2CH_SEL 0x02000020U +#define MCLK_I2S3_2CH_SEL_XIN_OSC0_HALF 0U +#define I2S3_2CH_MCLKOUT_SEL 0x01020020U +#define I2S3_2CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF0_SRC_SEL 0x01080020U +#define CLK_SPDIF0_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON33,Offset=0x384********/ +/********Name=CLKSEL_CON34,Offset=0x388********/ +#define MCLK_SPDIF0_SEL 0x02000022U +#define MCLK_SPDIF0_SEL_XIN_OSC0_HALF 0U +#define CLK_SPDIF1_SRC_SEL 0x01070022U +#define CLK_SPDIF1_SRC_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON35,Offset=0x38C********/ +/********Name=CLKSEL_CON36,Offset=0x390********/ +#define MCLK_SPDIF1_SEL 0x02000024U +#define MCLK_SPDIF1_SEL_XIN_OSC0_HALF 0U +#define MCLK_PDM1_SEL 0x02070024U +#define MCLK_PDM1_SEL_CLK_AUPLL_MUX 0U +/********Name=CLKSEL_CON38,Offset=0x398********/ +#define ACLK_BUS_ROOT_SEL 0x01050026U +#define ACLK_BUS_ROOT_SEL_CLK_CPLL_MUX 0U +#define CLK_I2C1_SEL 0x01060026U +#define CLK_I2C1_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C2_SEL 0x01070026U +#define CLK_I2C2_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C3_SEL 0x01080026U +#define CLK_I2C3_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C4_SEL 0x01090026U +#define CLK_I2C4_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C5_SEL 0x010A0026U +#define CLK_I2C5_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C6_SEL 0x010B0026U +#define CLK_I2C6_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C7_SEL 0x010C0026U +#define CLK_I2C7_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_I2C8_SEL 0x010D0026U +#define CLK_I2C8_SEL_CLK_MATRIX_100M_SRC 0U +/********Name=CLKSEL_CON39,Offset=0x39C********/ +#define CLK_CAN0_SEL 0x01050027U +#define CLK_CAN0_SEL_CLK_CPLL_MUX 0U +#define CLK_CAN1_SEL 0x010B0027U +#define CLK_CAN1_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON40,Offset=0x3A0********/ +#define CLK_CAN2_SEL 0x01050028U +#define CLK_CAN2_SEL_CLK_CPLL_MUX 0U +#define CLK_SARADC_SEL 0x010E0028U +#define CLK_SARADC_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON41,Offset=0x3A4********/ +#define CLK_TSADC_SEL 0x01080029U +#define CLK_TSADC_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART1_SRC_SEL 0x010E0029U +#define CLK_UART1_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON42,Offset=0x3A8********/ +/********Name=CLKSEL_CON43,Offset=0x3AC********/ +#define SCLK_UART1_SEL 0x0200002BU +#define SCLK_UART1_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART2_SRC_SEL 0x0107002BU +#define CLK_UART2_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON44,Offset=0x3B0********/ +/********Name=CLKSEL_CON45,Offset=0x3B4********/ +#define SCLK_UART2_SEL 0x0200002DU +#define SCLK_UART2_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART3_SRC_SEL 0x0107002DU +#define CLK_UART3_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON46,Offset=0x3B8********/ +/********Name=CLKSEL_CON47,Offset=0x3BC********/ +#define SCLK_UART3_SEL 0x0200002FU +#define SCLK_UART3_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART4_SRC_SEL 0x0107002FU +#define CLK_UART4_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON48,Offset=0x3C0********/ +/********Name=CLKSEL_CON49,Offset=0x3C4********/ +#define SCLK_UART4_SEL 0x02000031U +#define SCLK_UART4_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART5_SRC_SEL 0x01070031U +#define CLK_UART5_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON50,Offset=0x3C8********/ +/********Name=CLKSEL_CON51,Offset=0x3CC********/ +#define SCLK_UART5_SEL 0x02000033U +#define SCLK_UART5_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART6_SRC_SEL 0x01070033U +#define CLK_UART6_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON52,Offset=0x3D0********/ +/********Name=CLKSEL_CON53,Offset=0x3D4********/ +#define SCLK_UART6_SEL 0x02000035U +#define SCLK_UART6_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART7_SRC_SEL 0x01070035U +#define CLK_UART7_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON54,Offset=0x3D8********/ +/********Name=CLKSEL_CON55,Offset=0x3DC********/ +#define SCLK_UART7_SEL 0x02000037U +#define SCLK_UART7_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART8_SRC_SEL 0x01070037U +#define CLK_UART8_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON56,Offset=0x3E0********/ +/********Name=CLKSEL_CON57,Offset=0x3E4********/ +#define SCLK_UART8_SEL 0x02000039U +#define SCLK_UART8_SEL_XIN_OSC0_FUNC 0U +#define CLK_UART9_SRC_SEL 0x01070039U +#define CLK_UART9_SRC_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON58,Offset=0x3E8********/ +/********Name=CLKSEL_CON59,Offset=0x3EC********/ +#define SCLK_UART9_SEL 0x0200003BU +#define SCLK_UART9_SEL_XIN_OSC0_FUNC 0U +#define CLK_SPI0_SEL 0x0202003BU +#define CLK_SPI0_SEL_XIN_OSC0_FUNC 0U +#define CLK_SPI1_SEL 0x0204003BU +#define CLK_SPI1_SEL_XIN_OSC0_FUNC 0U +#define CLK_SPI2_SEL 0x0206003BU +#define CLK_SPI2_SEL_XIN_OSC0_FUNC 0U +#define CLK_SPI3_SEL 0x0208003BU +#define CLK_SPI3_SEL_XIN_OSC0_FUNC 0U +#define CLK_SPI4_SEL 0x020A003BU +#define CLK_SPI4_SEL_XIN_OSC0_FUNC 0U +#define CLK_PWM1_SEL 0x020C003BU +#define CLK_PWM1_SEL_XIN_OSC0_FUNC 0U +#define CLK_PWM2_SEL 0x020E003BU +#define CLK_PWM2_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON60,Offset=0x3F0********/ +#define CLK_PWM3_SEL 0x0200003CU +#define CLK_PWM3_SEL_XIN_OSC0_FUNC 0U +#define CLK_BUS_TIMER_ROOT_SEL 0x0102003CU +#define CLK_BUS_TIMER_ROOT_SEL_CLK_MATRIX_100M_SRC 0U +#define DBCLK_GPIO1_SEL 0x0108003CU +#define DBCLK_GPIO1_SEL_CLK_DEEPSLOW 0U +#define DBCLK_GPIO2_SEL 0x010E003CU +#define DBCLK_GPIO2_SEL_CLK_DEEPSLOW 0U +/********Name=CLKSEL_CON61,Offset=0x3F4********/ +#define DBCLK_GPIO3_SEL 0x0105003DU +#define DBCLK_GPIO3_SEL_CLK_DEEPSLOW 0U +#define DBCLK_GPIO4_SEL 0x010B003DU +#define DBCLK_GPIO4_SEL_CLK_DEEPSLOW 0U +/********Name=CLKSEL_CON62,Offset=0x3F8********/ +#define DCLK_DECOM_SEL 0x0105003EU +#define DCLK_DECOM_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON63,Offset=0x3FC********/ +#define CLK_TESTOUT_DDR01_SEL 0x0106003FU +#define CLK_TESTOUT_DDR01_SEL_CLK_DFI_CH1 0U +/********Name=CLKSEL_CON65,Offset=0x404********/ +#define CLK_TESTOUT_DDR23_SEL 0x01060041U +#define CLK_TESTOUT_DDR23_SEL_CLK_DFI_CH3 0U +/********Name=CLKSEL_CON67,Offset=0x40C********/ +#define ACLK_ISP1_ROOT_SEL 0x02050043U +#define ACLK_ISP1_ROOT_SEL_CLK_SPLL_MUX 0U +#define HCLK_ISP1_ROOT_SEL 0x02070043U +#define HCLK_ISP1_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_ISP1_CORE_SEL 0x020E0043U +#define CLK_ISP1_CORE_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON73,Offset=0x424********/ +#define HCLK_RKNN_ROOT_SEL 0x02000049U +#define HCLK_RKNN_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_RKNN_DSU0_SRC_T_SEL 0x03070049U +#define CLK_RKNN_DSU0_SRC_T_SEL_CLK_SPLL_MUX 0U +#define CLK_TESTOUT_NPU_SEL 0x010F0049U +#define CLK_TESTOUT_NPU_SEL_CLK_NPU_PVTPLL 0U +/********Name=CLKSEL_CON74,Offset=0x428********/ +#define CLK_RKNN_DSU0_SEL 0x0100004AU +#define CLK_RKNN_DSU0_SEL_CLK_NPU_PVTPLL 0U +#define PCLK_NPUTOP_ROOT_SEL 0x0201004AU +#define PCLK_NPUTOP_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_NPUTIMER_ROOT_SEL 0x0103004AU +#define CLK_NPUTIMER_ROOT_SEL_CLK_MATRIX_100M_SRC 0U +#define CLK_NPU_PVTPLL_SEL 0x0104004AU +#define CLK_NPU_PVTPLL_SEL_XIN_OSC0_FUNC 0U +#define HCLK_NPU_CM0_ROOT_SEL 0x0205004AU +#define HCLK_NPU_CM0_ROOT_SEL_XIN_OSC0_FUNC 0U +#define CLK_NPU_CM0_RTC_SEL 0x010C004AU +#define CLK_NPU_CM0_RTC_SEL_CLK_DEEPSLOW 0U +/********Name=CLKSEL_CON77,Offset=0x434********/ +#define HCLK_NVM_ROOT_SEL 0x0200004DU +#define HCLK_NVM_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_NVM_ROOT_SEL 0x0107004DU +#define ACLK_NVM_ROOT_SEL_CLK_CPLL_MUX 0U +#define CCLK_EMMC_SEL 0x020E004DU +#define CCLK_EMMC_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON78,Offset=0x438********/ +#define BCLK_EMMC_SEL 0x0105004EU +#define BCLK_EMMC_SEL_CLK_CPLL_MUX 0U +#define SCLK_SFC_SEL 0x020C004EU +#define SCLK_SFC_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON80,Offset=0x440********/ +#define PCLK_PHP_ROOT_SEL 0x02000050U +#define PCLK_PHP_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_PCIE_ROOT_SEL 0x01070050U +#define ACLK_PCIE_ROOT_SEL_CLK_CPLL_MUX 0U +#define ACLK_PHP_ROOT_SEL 0x010D0050U +#define ACLK_PHP_ROOT_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON81,Offset=0x444********/ +#define CLK_GMAC0_PTP_REF_SEL 0x01060051U +#define CLK_GMAC0_PTP_REF_SEL_CLK_GMAC0_PTPREFO 0U +#define CLK_GMAC1_PTP_REF_SEL 0x010D0051U +#define CLK_GMAC1_PTP_REF_SEL_CLK_GMAC1_PTPREFO 0U +/********Name=CLKSEL_CON82,Offset=0x448********/ +#define CLK_RXOOB0_SEL 0x01070052U +#define CLK_RXOOB0_SEL_CLK_CPLL_MUX 0U +#define CLK_RXOOB1_SEL 0x010F0052U +#define CLK_RXOOB1_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON83,Offset=0x44C********/ +#define CLK_RXOOB2_SEL 0x01070053U +#define CLK_RXOOB2_SEL_CLK_CPLL_MUX 0U +#define CLK_GMAC_125M_CRU_I_SEL 0x010F0053U +#define CLK_GMAC_125M_CRU_I_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON84,Offset=0x450********/ +#define CLK_GMAC_50M_CRU_I_SEL 0x01070054U +#define CLK_GMAC_50M_CRU_I_SEL_CLK_CPLL_MUX 0U +#define CLK_UTMI_OTG2_SEL 0x020C0054U +#define CLK_UTMI_OTG2_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON85,Offset=0x454********/ +/********Name=CLKSEL_CON89,Offset=0x464********/ +#define HCLK_RKVDEC0_ROOT_SEL 0x02000059U +#define HCLK_RKVDEC0_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_RKVDEC0_ROOT_SEL 0x02070059U +#define ACLK_RKVDEC0_ROOT_SEL_CLK_SPLL_MUX 0U +#define ACLK_RKVDEC_CCU_SEL 0x020E0059U +#define ACLK_RKVDEC_CCU_SEL_CLK_SPLL_MUX 0U +/********Name=CLKSEL_CON90,Offset=0x468********/ +#define CLK_RKVDEC0_CA_SEL 0x0105005AU +#define CLK_RKVDEC0_CA_SEL_CLK_CPLL_MUX 0U +#define CLK_RKVDEC0_HEVC_CA_SEL 0x020B005AU +#define CLK_RKVDEC0_HEVC_CA_SEL_CLK_MATRIX_1000M_SRC 0U +/********Name=CLKSEL_CON91,Offset=0x46C********/ +#define CLK_RKVDEC0_CORE_SEL 0x0105005BU +#define CLK_RKVDEC0_CORE_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON93,Offset=0x474********/ +#define HCLK_RKVDEC1_ROOT_SEL 0x0200005DU +#define HCLK_RKVDEC1_ROOT_SEL_XIN_OSC0_FUNC 0U +#define ACLK_RKVDEC1_ROOT_SEL 0x0207005DU +#define ACLK_RKVDEC1_ROOT_SEL_CLK_NPLL_MUX 0U +#define CLK_RKVDEC1_CA_SEL 0x010E005DU +#define CLK_RKVDEC1_CA_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON94,Offset=0x478********/ +#define CLK_RKVDEC1_HEVC_CA_SEL 0x0205005EU +#define CLK_RKVDEC1_HEVC_CA_SEL_CLK_MATRIX_1000M_SRC 0U +#define CLK_RKVDEC1_CORE_SEL 0x010C005EU +#define CLK_RKVDEC1_CORE_SEL_CLK_CPLL_MUX 0U +/********Name=CLKSEL_CON96,Offset=0x480********/ +#define ACLK_USB_ROOT_SEL 0x01050060U +#define ACLK_USB_ROOT_SEL_CLK_CPLL_MUX 0U +#define HCLK_USB_ROOT_SEL 0x02060060U +#define HCLK_USB_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON98,Offset=0x488********/ +#define ACLK_VDPU_ROOT_SEL 0x02050062U +#define ACLK_VDPU_ROOT_SEL_CLK_AUPLL_MUX 0U +#define ACLK_VDPU_LOW_ROOT_SEL 0x02070062U +#define ACLK_VDPU_LOW_ROOT_SEL_XIN_OSC0_FUNC 0U +#define HCLK_VDPU_ROOT_SEL 0x02090062U +#define HCLK_VDPU_ROOT_SEL_XIN_OSC0_FUNC 0U +/********Name=CLKSEL_CON99,Offset=0x48C********/ +#define ACLK_JPEG_DECODER_ROOT_SEL 0x02050063U +#define ACLK_JPEG_DECODER_ROOT_SEL_CLK_SPLL_MUX 0U +#define CLK_IEP2P0_CORE_SEL 0x010C0063U +#define CLK_IEP2P0_CORE_SEL_CLK_CPLL_MUX 0U + +/********Name=PMU1CLKSEL_CON00,Offset=0x300********/ +#define CLK_MATRIX_PMU1_300M_SRC_SEL 0x010F0000U +#define CLK_MATRIX_PMU1_300M_SRC_SEL_XIN_OSC0_FUNC 0U +/********Name=PMU1CLKSEL_CON01,Offset=0x304********/ +#define CLK_MATRIX_PMU1_400M_SRC_SEL 0x01050001U +#define CLK_MATRIX_PMU1_400M_SRC_SEL_XIN_OSC0_FUNC 0U +#define HCLK_PMU1_ROOT_I_SEL 0x02060001U +#define HCLK_PMU1_ROOT_I_SEL_XIN_OSC0_FUNC 0U +#define PCLK_PMU1_ROOT_I_SEL 0x02080001U +#define PCLK_PMU1_ROOT_I_SEL_XIN_OSC0_FUNC 0U +#define HCLK_PMU_CM0_ROOT_I_SEL 0x020A0001U +#define HCLK_PMU_CM0_ROOT_I_SEL_XIN_OSC0_FUNC 0U +/********Name=PMU1CLKSEL_CON02,Offset=0x308********/ +#define CLK_PMU_CM0_RTC_SEL 0x01050002U +#define CLK_PMU_CM0_RTC_SEL_CLK_DEEPSLOW 0U +#define TCLK_PMU1WDT_SEL 0x01060002U +#define TCLK_PMU1WDT_SEL_CLK_DEEPSLOW 0U +#define CLK_PMU1TIMER_ROOT_SEL 0x02070002U +#define CLK_PMU1TIMER_ROOT_SEL_CLK_MATRIX_PMU1_100M_SRC 0U +#define CLK_PMU1PWM_SEL 0x02090002U +#define CLK_PMU1PWM_SEL_XIN_OSC0_FUNC 0U +/********Name=PMU1CLKSEL_CON03,Offset=0x30C********/ +#define CLK_I2C0_SEL 0x01060003U +#define CLK_I2C0_SEL_CLK_MATRIX_PMU1_100M_SRC 0U +/********Name=PMU1CLKSEL_CON04,Offset=0x310********/ +/********Name=PMU1CLKSEL_CON05,Offset=0x314********/ +#define SCLK_UART0_SEL 0x02000005U +#define SCLK_UART0_SEL_XIN_OSC0_FUNC 0U +/********Name=PMU1CLKSEL_CON06,Offset=0x318********/ +/********Name=PMU1CLKSEL_CON07,Offset=0x31C********/ +#define MCLK_I2S1_8CH_TX_SEL 0x02000007U +#define MCLK_I2S1_8CH_TX_SEL_XIN_OSC0_HALF 0U +/********Name=PMU1CLKSEL_CON08,Offset=0x320********/ +/********Name=PMU1CLKSEL_CON09,Offset=0x324********/ +#define MCLK_I2S1_8CH_RX_SEL 0x02000009U +#define MCLK_I2S1_8CH_RX_SEL_XIN_OSC0_HALF 0U +#define I2S1_8CH_MCLKOUT_SEL 0x02020009U +#define I2S1_8CH_MCLKOUT_SEL_XIN_OSC0_HALF 0U +#define MCLK_PDM0_SEL 0x01040009U +#define MCLK_PDM0_SEL_CLK_MATRIX_PMU1_200M_SRC 0U +#define CLK_USBDP_COMBO_PHY0_REF_XTAL_SEL 0x010A0009U +#define CLK_USBDP_COMBO_PHY0_REF_XTAL_SEL_CLK_PPLL 0U +/********Name=PMU1CLKSEL_CON12,Offset=0x330********/ +#define CLK_HDPTX0_REF_XTAL_SEL 0x010B000CU +#define CLK_HDPTX0_REF_XTAL_SEL_CLK_PPLL 0U +/********Name=PMU1CLKSEL_CON14,Offset=0x338********/ +#define CLK_REF_MIPI_DCPHY0_SEL 0x0207000EU +#define CLK_REF_MIPI_DCPHY0_SEL_CLK_SPLL_MUX 0U +#define CLK_OTGPHY_U3_0_SEL 0x010E000EU +#define CLK_OTGPHY_U3_0_SEL_CLK_PPLL 0U +/********Name=PMU1CLKSEL_CON15,Offset=0x33C********/ +#define CLK_CR_PARA_SEL 0x0205000FU +#define CLK_CR_PARA_SEL_CLK_SPLL_MUX 0U +/********Name=PMU1CLKSEL_CON17,Offset=0x344********/ +#define DBCLK_GPIO0_SEL 0x01000011U +#define DBCLK_GPIO0_SEL_CLK_DEEPSLOW 0U + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __RK3588_H */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588RegsPeri.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588RegsPeri.h new file mode 100644 index 0000000..3cf9fe2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/RK3588RegsPeri.h @@ -0,0 +1,13 @@ +/** @file +* +* Copyright (c) 2021, Rockchip Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __RK3588_REGS_PERI_H__ +#define __RK3588_REGS_PERI_H__ + + +#endif /* __RK3588_REGS_PERI_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/ScmiDefinitions.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/ScmiDefinitions.h new file mode 100644 index 0000000..9b17fde --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/ScmiDefinitions.h @@ -0,0 +1,55 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RK3588_SCMI_DEFINITIONS_H__ +#define __RK3588_SCMI_DEFINITIONS_H__ + +#define SCMI_CLK_CPUL 0 +#define SCMI_CLK_DSU 1 +#define SCMI_CLK_CPUB01 2 +#define SCMI_CLK_CPUB23 3 +#define SCMI_CLK_DDR 4 +#define SCMI_CLK_GPU 5 +#define SCMI_CLK_NPU 6 +#define SCMI_CLK_SBUS 7 +#define SCMI_PCLK_SBUS 8 +#define SCMI_CCLK_SD 9 +#define SCMI_DCLK_SD 10 +#define SCMI_ACLK_SECURE_NS 11 +#define SCMI_HCLK_SECURE_NS 12 +#define SCMI_TCLK_WDT 13 +#define SCMI_KEYLADDER_CORE 14 +#define SCMI_KEYLADDER_RNG 15 +#define SCMI_ACLK_SECURE_S 16 +#define SCMI_HCLK_SECURE_S 17 +#define SCMI_PCLK_SECURE_S 18 +#define SCMI_CRYPTO_RNG 19 +#define SCMI_CRYPTO_CORE 20 +#define SCMI_CRYPTO_PKA 21 +#define SCMI_SPLL 22 +#define SCMI_HCLK_SD 23 +#define SCMI_CRYPTO_RNG_S 24 +#define SCMI_CRYPTO_CORE_S 25 +#define SCMI_CRYPTO_PKA_S 26 +#define SCMI_A_CRYPTO_S 27 +#define SCMI_H_CRYPTO_S 28 +#define SCMI_P_CRYPTO_S 29 +#define SCMI_A_KEYLADDER_S 30 +#define SCMI_H_KEYLADDER_S 31 +#define SCMI_P_KEYLADDER_S 32 +#define SCMI_TRNG_S 33 +#define SCMI_H_TRNG_S 34 +#define SCMI_P_OTPC_S 35 +#define SCMI_OTPC_S 36 +#define SCMI_OTP_PHY 37 +#define SCMI_OTPC_AUTO_RD 38 +#define SCMI_OTPC_ARB 39 +#define SCMI_CCLK_EMMC 40 + +#endif // __RK3588_SCMI_DEFINITIONS_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Soc.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Soc.h new file mode 100644 index 0000000..8c1ec31 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/Soc.h @@ -0,0 +1,86 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SOC_H +#define __SOC_H +#ifdef __cplusplus + extern "C" { +#endif +#define uint8_t UINT8 +#define uint16_t UINT16 +#define uint32_t UINT32 +#define uint64_t UINT64 +#define HAL_ASSERT ASSERT +#define HAL_CPUDelayUs MicroSecondDelay +#define __WEAK +#define HAL_DivU64 DivU64x32 +/* IO definitions (access restrictions to peripheral registers) */ +/*!< brief Defines 'read only' permissions */ +#ifdef __cplusplus + #define __I volatile +#else + #define __I volatile const +#endif +/*!< brief Defines 'write only' permissions */ +#define __O volatile +/*!< brief Defines 'read / write' permissions */ +#define __IO volatile + +/**< Write the register */ +#define WRITE_REG(REG, VAL) ((*(volatile uint32_t *)&(REG)) = (VAL)) +/**< Read the register */ +#define READ_REG(REG) ((*(volatile const uint32_t *)&(REG))) +#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) +/* ================================================================================ */ +/* ================ Processor and Core Peripheral Section ================ */ +/* ================================================================================ */ +#include "RK3588.h" +#define RK3588_PERIPH_BASE 0xF0000000 +#define RK3588_PERIPH_SZ 0x10000000 + +#define I2C_BASE(id) ((id == 0) ? 0xFD880000 : \ + (id <= 5) ? (0xFEA90000 + ((id - 1) * 0x10000)) : \ + (id <= 8) ? (0xFEC80000 + ((id - 6) * 0x10000)) : 0) +#define I2C_COUNT 9 + +/******************************************CRU*******************************************/ +#define PLL_INPUT_OSC_RATE (24 * 1000 * 1000) + +typedef enum { + PLL_LPLL = 0, + PLL_B0PLL, + PLL_B1PLL, + PLL_CPLL, + PLL_GPLL, + PLL_NPLL, + PLL_V0PLL, + PLL_PPLL, + PLL_AUPLL, + CCLK_EMMC, + SCLK_SFC, + CCLK_SRC_SDIO, + BCLK_EMMC, + CLK_REF_PIPE_PHY0, + CLK_REF_PIPE_PHY1, + CLK_REF_PIPE_PHY2, + DCLK_VOP2_SRC, + CLK_I2S0_8CH_TX_SRC, + MCLK_I2S0_8CH_TX, + MCLK_I2S1_8CH_TX, + CLK_COUNT +} RK3588_CLOCK_IDS; + +typedef enum { + RESET_COUNT = 0 +} RK3588_RESET_IDS; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __SOC_H */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/VarStoreData.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/VarStoreData.h new file mode 100644 index 0000000..d7166de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Include/VarStoreData.h @@ -0,0 +1,97 @@ +/** @file + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __VARSTORE_DATA_H__ +#define __VARSTORE_DATA_H__ + +#define CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT 0 +#define CPU_PERF_CLUSTER_CLOCK_PRESET_MIN 1 +#define CPU_PERF_CLUSTER_CLOCK_PRESET_MAX 2 +#define CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM 3 +typedef struct { + UINT32 Preset; +} CPU_PERF_CLUSTER_CLOCK_PRESET_VARSTORE_DATA; + +typedef struct { + UINT32 Mhz; +} CPU_PERF_CLUSTER_CLOCK_CUSTOM_VARSTORE_DATA; + +#define CPU_PERF_CLUSTER_VOLTAGE_MODE_AUTO 0 +#define CPU_PERF_CLUSTER_VOLTAGE_MODE_CUSTOM 1 +typedef struct { + UINT32 Mode; +} CPU_PERF_CLUSTER_VOLTAGE_MODE_VARSTORE_DATA; + +typedef struct { + UINT32 Microvolts; +} CPU_PERF_CLUSTER_VOLTAGE_CUSTOM_VARSTORE_DATA; + +#define COMBO_PHY_MODE_UNCONNECTED 0 +#define COMBO_PHY_MODE_PCIE 1 +#define COMBO_PHY_MODE_SATA 2 +#define COMBO_PHY_MODE_USB3 3 +typedef struct { + UINT32 Mode; +} COMBO_PHY_MODE_VARSTORE_DATA; + +#define PCIE30_STATE_DISABLED 0 +#define PCIE30_STATE_ENABLED 1 +typedef struct { + UINT32 State; +} PCIE30_STATE_VARSTORE_DATA; + +#define PCIE30_PHY_MODE_AGGREGATION 4 +#define PCIE30_PHY_MODE_NANBNB 0 +#define PCIE30_PHY_MODE_NANBBI 1 +#define PCIE30_PHY_MODE_NABINB 2 +#define PCIE30_PHY_MODE_NABIBI 3 +typedef struct { + UINT8 Mode; +} PCIE30_PHY_MODE_VARSTORE_DATA; + +#define CONFIG_TABLE_MODE_ACPI 0x00000001 +#define CONFIG_TABLE_MODE_FDT 0x00000002 +#define CONFIG_TABLE_MODE_ACPI_FDT 0x00000003 +typedef struct { + UINT32 Mode; +} CONFIG_TABLE_MODE_VARSTORE_DATA; + +#define ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV 0x00000001 +#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6 0x00000002 +#define ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON 0x00000004 +#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV 0x00000003 +#define ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON 0x00000006 +typedef struct { + UINT32 Mode; +} ACPI_PCIE_ECAM_COMPAT_MODE_VARSTORE_DATA; + +typedef struct { + UINT8 State; +} FDT_SUPPORT_OVERRIDES_VARSTORE_DATA; + +#define COOLING_FAN_STATE_DISABLED 0 +#define COOLING_FAN_STATE_ENABLED 1 +typedef struct { + UINT32 State; +} COOLING_FAN_STATE_VARSTORE_DATA; + +typedef struct { + UINT32 Percentage; +} COOLING_FAN_SPEED_VARSTORE_DATA; + +#define USBDP_PHY_USB3_STATE_DISABLED 0 +#define USBDP_PHY_USB3_STATE_ENABLED 1 +typedef struct { + UINT32 State; +} USBDP_PHY_USB3_STATE_VARSTORE_DATA; + +typedef struct { + UINT64 Value; +} DEBUG_SERIAL_PORT_BAUD_RATE_VARSTORE_DATA; + +#endif // __VARSTORE_DATA_H__ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.c new file mode 100644 index 0000000..685da37 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.c @@ -0,0 +1,63 @@ +/** @file + * + * DwcSdhciDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include + +#define NS_CRU_BASE 0xFD7C0000 +#define CRU_CLKSEL_CON77 0x0434 + +#define EMMC_CLOCK_BASE (NS_CRU_BASE + CRU_CLKSEL_CON77) + +EFI_STATUS +EFIAPI +DwcSdhciSetClockRate ( + IN UINTN Frequency + ) +{ + UINT32 CClkEmmcSel, Div; + + if (Frequency >= 200000000) { + CClkEmmcSel = 0; + Div = 6; + } else if (Frequency >= 150000000) { + CClkEmmcSel = 0; + Div = 8; + } else if (Frequency >= 100000000) { + CClkEmmcSel = 0; + Div = 12; + } else if (Frequency >= 50000000) { + CClkEmmcSel = 0; + Div = 24; + } else if (Frequency >= 24000000) { + CClkEmmcSel = 2; + Div = 1; + } else { /* 375KHZ*/ + CClkEmmcSel = 2; + Div = 64; + } + + MmioWrite32(EMMC_CLOCK_BASE, ((( 0x3 << 14 )|( 0x3F << 8 )) << 16 ) | + ( CClkEmmcSel << 14 ) | + (( Div - 1 ) << 8)); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +DwcSdhciSetIoMux ( + VOID + ) +{ + SdhciEmmcIoMux (); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.inf new file mode 100644 index 0000000..cf867a0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.inf @@ -0,0 +1,28 @@ +#/** @file +# +# DwcSdhciDxe platform helper library. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = DwcSdhciPlatformLib + FILE_GUID = a3d2126b-6110-4bc5-8b96-c95ac9858b04 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DwcSdhciPlatformLib + +[Sources] + DwcSdhciPlatformLib.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + IoLib + RockchipPlatformLib diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.c new file mode 100644 index 0000000..f156184 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.c @@ -0,0 +1,339 @@ +/** @file + * + * RK3588 GPIO Library. + * + * Copyright (c) 2021, Jared McNeill + * Copyright (c) 2023, Molly Sophia + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +#include +#include +#include +#include +#include + +#define GRF_GPIO_IOMUX_REG(Pin) (((Pin) / 4) * 4) +#define GRF_GPIO_IOMUX_SHIFT(Pin) (((Pin) % 4) * 4) +#define GRF_GPIO_IOMUX_MASK(Pin) (0xFU << (GRF_GPIO_IOMUX_SHIFT(Pin) + 16)) + +#define GRF_GPIO_P_REG(Pin) (((Pin) / 8) * 4) +#define GRF_GPIO_P_SHIFT(Pin) (((Pin) % 8) * 2) +#define GRF_GPIO_P_MASK(Pin) (0x3U << (GRF_GPIO_P_SHIFT (Pin) + 16)) + +#define GRF_GPIO_DS_REG(Pin) (((Pin) / 4) * 4) +#define GRF_GPIO_DS_SHIFT(Pin) (((Pin) % 4) * 4) +#define GRF_GPIO_DS_MASK(Pin) (0xFFU << (GRF_GPIO_DS_SHIFT (Pin) + 16)) + +#define GRF_GPIO_IE_REG(Pin) (((Pin) / 8) * 4) +#define GRF_GPIO_IE_SHIFT(Pin) (((Pin) % 8) * 2) +#define GRF_GPIO_IE_MASK(Pin) (0x3U << (GRF_GPIO_IE_SHIFT (Pin) + 16)) + +#define GPIO_SWPORT_DR(Pin) ((Pin) < 16 ? 0x0000 : 0x0004) +#define GPIO_SWPORT_DDR(Pin) ((Pin) < 16 ? 0x0008 : 0x000C) + +#define GPIO_WRITE_MASK(Pin) (1U << (((Pin) % 16) + 16)) +#define GPIO_VALUE_MASK(Pin, Value) ((UINT32)Value << ((Pin) % 16)) + +#define GPIO_EXT_PORT 0x0070 + +#define GPIO_NGROUPS 5 + +#define PMU1_IOC_BASE (0xFD5F0000U) +#define PMU2_IOC_BASE (PMU1_IOC_BASE + 0x4000) +#define BUS_IOC_BASE (PMU1_IOC_BASE + 0x8000) +#define VCCIO1_4_IOC_BASE (PMU1_IOC_BASE + 0x9000) +#define VCCIO3_5_IOC_BASE (PMU1_IOC_BASE + 0xA000) +#define VCCIO2_IOC_BASE (PMU1_IOC_BASE + 0xB000) +#define VCCIO6_IOC_BASE (PMU1_IOC_BASE + 0xC000) +#define EMMC_IOC_BASE (PMU1_IOC_BASE + 0xD000) + +typedef struct { + UINT8 Group; + UINT8 Pin; + EFI_PHYSICAL_ADDRESS Addr; +} GPIO_REG; + +STATIC GPIO_REG mDsReg[] = { + {0, GPIO_PIN_PA0, PMU1_IOC_BASE + 0x0010}, + {0, GPIO_PIN_PA4, PMU1_IOC_BASE + 0x0014}, + {0, GPIO_PIN_PB0, PMU1_IOC_BASE + 0x0018}, + {0, GPIO_PIN_PB4, PMU2_IOC_BASE + 0x0014}, + {0, GPIO_PIN_PC0, PMU2_IOC_BASE + 0x0018}, + {0, GPIO_PIN_PC4, PMU2_IOC_BASE + 0x001C}, + {0, GPIO_PIN_PD0, PMU2_IOC_BASE + 0x0020}, + {0, GPIO_PIN_PD4, PMU2_IOC_BASE + 0x0024}, + {1, GPIO_PIN_PA0, VCCIO1_4_IOC_BASE + 0x0020}, + {1, GPIO_PIN_PA4, VCCIO1_4_IOC_BASE + 0x0024}, + {1, GPIO_PIN_PB0, VCCIO1_4_IOC_BASE + 0x0028}, + {1, GPIO_PIN_PB4, VCCIO1_4_IOC_BASE + 0x002C}, + {1, GPIO_PIN_PC0, VCCIO1_4_IOC_BASE + 0x0030}, + {1, GPIO_PIN_PC4, VCCIO1_4_IOC_BASE + 0x0034}, + {1, GPIO_PIN_PD0, VCCIO1_4_IOC_BASE + 0x0038}, + {1, GPIO_PIN_PD4, VCCIO1_4_IOC_BASE + 0x003C}, + {2, GPIO_PIN_PA0, EMMC_IOC_BASE + 0x0040}, + {2, GPIO_PIN_PA4, VCCIO3_5_IOC_BASE + 0x0044}, + {2, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x0048}, + {2, GPIO_PIN_PB4, VCCIO3_5_IOC_BASE + 0x004C}, + {2, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x0050}, + {2, GPIO_PIN_PC4, VCCIO3_5_IOC_BASE + 0x0054}, + {2, GPIO_PIN_PD0, EMMC_IOC_BASE + 0x0058}, + {2, GPIO_PIN_PD4, EMMC_IOC_BASE + 0x005C}, + {3, GPIO_PIN_PA0, VCCIO3_5_IOC_BASE + 0x0060}, + {3, GPIO_PIN_PA4, VCCIO3_5_IOC_BASE + 0x0064}, + {3, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x0068}, + {3, GPIO_PIN_PB4, VCCIO3_5_IOC_BASE + 0x006C}, + {3, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x0070}, + {3, GPIO_PIN_PC4, VCCIO3_5_IOC_BASE + 0x0074}, + {3, GPIO_PIN_PD0, VCCIO3_5_IOC_BASE + 0x0078}, + {3, GPIO_PIN_PD4, VCCIO3_5_IOC_BASE + 0x007C}, + {4, GPIO_PIN_PA0, VCCIO6_IOC_BASE + 0x0080}, + {4, GPIO_PIN_PA4, VCCIO6_IOC_BASE + 0x0084}, + {4, GPIO_PIN_PB0, VCCIO6_IOC_BASE + 0x0088}, + {4, GPIO_PIN_PB4, VCCIO6_IOC_BASE + 0x008C}, + {4, GPIO_PIN_PC0, VCCIO6_IOC_BASE + 0x0090}, + {4, GPIO_PIN_PC2, VCCIO3_5_IOC_BASE + 0x0090}, + {4, GPIO_PIN_PC4, VCCIO3_5_IOC_BASE + 0x0094}, + {4, GPIO_PIN_PD0, VCCIO2_IOC_BASE + 0x0098}, +}; + +STATIC GPIO_REG mPullReg[] = { + {0, GPIO_PIN_PA0, PMU1_IOC_BASE + 0x0020}, + {0, GPIO_PIN_PB0, PMU1_IOC_BASE + 0x0024}, + {0, GPIO_PIN_PB5, PMU2_IOC_BASE + 0x0028}, + {0, GPIO_PIN_PC0, PMU2_IOC_BASE + 0x002C}, + {0, GPIO_PIN_PD0, PMU2_IOC_BASE + 0x0030}, + {1, GPIO_PIN_PA0, VCCIO1_4_IOC_BASE + 0x0110}, + {1, GPIO_PIN_PB0, VCCIO1_4_IOC_BASE + 0x0114}, + {1, GPIO_PIN_PC0, VCCIO1_4_IOC_BASE + 0x0118}, + {1, GPIO_PIN_PD0, VCCIO1_4_IOC_BASE + 0x011C}, + {2, GPIO_PIN_PA0, EMMC_IOC_BASE + 0x0120}, + {2, GPIO_PIN_PA4, VCCIO3_5_IOC_BASE + 0x0120}, + {2, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x0124}, + {2, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x0128}, + {2, GPIO_PIN_PD0, EMMC_IOC_BASE + 0x012C}, + {3, GPIO_PIN_PA0, VCCIO3_5_IOC_BASE + 0x0130}, + {3, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x0134}, + {3, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x0138}, + {3, GPIO_PIN_PD0, VCCIO3_5_IOC_BASE + 0x013C}, + {4, GPIO_PIN_PA0, VCCIO6_IOC_BASE + 0x0140}, + {4, GPIO_PIN_PB0, VCCIO6_IOC_BASE + 0x0144}, + {4, GPIO_PIN_PC0, VCCIO6_IOC_BASE + 0x0148}, + {4, GPIO_PIN_PC2, VCCIO3_5_IOC_BASE + 0x0148}, + {4, GPIO_PIN_PD0, VCCIO2_IOC_BASE + 0x014C}, +}; + +STATIC GPIO_REG mIEReg[] = { + {0, GPIO_PIN_PA0, PMU1_IOC_BASE + 0x0028}, + {0, GPIO_PIN_PB0, PMU1_IOC_BASE + 0x002C}, + {0, GPIO_PIN_PB5, PMU2_IOC_BASE + 0x0034}, + {0, GPIO_PIN_PC0, PMU2_IOC_BASE + 0x0038}, + {0, GPIO_PIN_PD0, PMU2_IOC_BASE + 0x003C}, + {1, GPIO_PIN_PA0, VCCIO1_4_IOC_BASE + 0x0180}, + {1, GPIO_PIN_PB0, VCCIO1_4_IOC_BASE + 0x0184}, + {1, GPIO_PIN_PC0, VCCIO1_4_IOC_BASE + 0x0188}, + {1, GPIO_PIN_PD0, VCCIO1_4_IOC_BASE + 0x018C}, + {2, GPIO_PIN_PA0, EMMC_IOC_BASE + 0x0190}, + {2, GPIO_PIN_PA4, VCCIO3_5_IOC_BASE + 0x0190}, + {2, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x0194}, + {2, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x0198}, + {2, GPIO_PIN_PD0, EMMC_IOC_BASE + 0x019C}, + {3, GPIO_PIN_PA0, VCCIO3_5_IOC_BASE + 0x01A0}, + {3, GPIO_PIN_PB0, VCCIO3_5_IOC_BASE + 0x01A4}, + {3, GPIO_PIN_PC0, VCCIO3_5_IOC_BASE + 0x01A8}, + {3, GPIO_PIN_PD0, VCCIO3_5_IOC_BASE + 0x01AC}, + {4, GPIO_PIN_PA0, VCCIO6_IOC_BASE + 0x01B0}, + {4, GPIO_PIN_PB0, VCCIO6_IOC_BASE + 0x01B4}, + {4, GPIO_PIN_PC0, VCCIO6_IOC_BASE + 0x01B8}, + {4, GPIO_PIN_PC2, VCCIO3_5_IOC_BASE + 0x01B8}, + {4, GPIO_PIN_PD0, VCCIO2_IOC_BASE + 0x01BC}, +}; + +#define GPIO_BASE(n) ((n) == 0 ? 0xFD8A0000UL : (0xFEC20000UL + ((n) - 1) * 0x10000)) + +VOID +GpioPinSetDirection ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_DIRECTION Direction + ) +{ + DEBUG((DEBUG_INFO, "GpioPinSetDirection Group:%d Pin:%d Direction:%d\n", + Group, Pin, Direction)); + MmioWrite32 (GPIO_BASE (Group) + GPIO_SWPORT_DDR (Pin), + GPIO_WRITE_MASK (Pin) | GPIO_VALUE_MASK (Pin, Direction)); +} + +VOID +GpioPinWrite ( + IN UINT8 Group, + IN UINT8 Pin, + IN BOOLEAN Value + ) +{ + DEBUG((DEBUG_VERBOSE, "GpioPinWrite Group:%d Pin:%d Value:%d\n", + Group, Pin, Value)); + MmioWrite32 (GPIO_BASE (Group) + GPIO_SWPORT_DR (Pin), + GPIO_WRITE_MASK (Pin) | GPIO_VALUE_MASK (Pin, Value)); +} + +BOOLEAN +GpioPinRead ( + IN UINT8 Group, + IN UINT8 Pin + ) +{ + CONST UINT32 Value = MmioRead32 (GPIO_BASE (Group) + GPIO_SWPORT_DR (Pin)); + return (Value & GPIO_VALUE_MASK (Pin, 1)) != 0; +} + +BOOLEAN +GpioPinReadActual ( + IN UINT8 Group, + IN UINT8 Pin + ) +{ + CONST UINT32 Value = MmioRead32 (GPIO_BASE (Group) + GPIO_EXT_PORT); + return (Value & (1 << Pin)) != 0; +} + +VOID +GpioPinSetFunction ( + IN UINT8 Group, + IN UINT8 Pin, + IN UINT8 Function + ) +{ + ASSERT (Group < GPIO_NGROUPS); + + EFI_PHYSICAL_ADDRESS Reg; + UINT32 Value = GRF_GPIO_IOMUX_MASK (Pin) | ((UINT32)Function << GRF_GPIO_IOMUX_SHIFT (Pin)); + + DEBUG ((DEBUG_INFO, "GpioPinSetFunction Group:%d Pin:%d Function:%d\n", Group, Pin, Function)); + + if(Group == 0) { + if(Pin >= GPIO_PIN_PB4) { + if(Function >= 8) { + Reg = PMU2_IOC_BASE - 0xC + GRF_GPIO_IOMUX_REG(Pin); + Value = GRF_GPIO_IOMUX_MASK (Pin) | ((UINT32)8 << GRF_GPIO_IOMUX_SHIFT (Pin)); + MmioWrite32(Reg, Value); + + Reg = BUS_IOC_BASE + GRF_GPIO_IOMUX_REG(Pin); + Value = GRF_GPIO_IOMUX_MASK (Pin) | ((UINT32)Function << GRF_GPIO_IOMUX_SHIFT (Pin)); + MmioWrite32(Reg, Value); + } else { + Reg = PMU2_IOC_BASE - 0xC + GRF_GPIO_IOMUX_REG(Pin); + Value = GRF_GPIO_IOMUX_MASK (Pin) | ((UINT32)Function << GRF_GPIO_IOMUX_SHIFT (Pin)); + MmioWrite32(Reg, Value); + + Reg = BUS_IOC_BASE + GRF_GPIO_IOMUX_REG(Pin); + Value = GRF_GPIO_IOMUX_MASK (Pin); + MmioWrite32(Reg, Value); + } + DEBUG ((DEBUG_VERBOSE, "Reg - Value: 0x%lX = 0x%08X\n", Reg, Value)); + return; + } else { + Reg = PMU1_IOC_BASE + GRF_GPIO_IOMUX_REG(Pin); + } + } else { + Reg = BUS_IOC_BASE + Group * 0x20 + GRF_GPIO_IOMUX_REG(Pin); + } + + DEBUG ((DEBUG_VERBOSE, "Reg - Value: 0x%lX = 0x%08X\n", Reg, Value)); + MmioWrite32 (Reg, Value); +} + +VOID +GpioPinSetPull ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_PULL Pull + ) +{ + ASSERT (Group < GPIO_NGROUPS); + + INTN Idx; + EFI_PHYSICAL_ADDRESS Reg; + CONST UINT32 Value = GRF_GPIO_P_MASK (Pin) | ((UINT32)Pull << GRF_GPIO_P_SHIFT (Pin)); + + for(Idx = ARRAY_SIZE(mPullReg) - 1; Idx >= 0; Idx--) { + if(Group == mPullReg[Idx].Group && Pin >= mPullReg[Idx].Pin) { + Reg = mPullReg[Idx].Addr + GRF_GPIO_P_REG(Pin - mPullReg[Idx].Pin); + } + } + + DEBUG ((DEBUG_INFO, "GpioPinSetPull Group:%d Pin:%d Pull:%d\n", Group, Pin, Pull)); + DEBUG ((DEBUG_VERBOSE, "Reg - Value: 0x%lX = 0x%08X\n", Reg, Value)); + + MmioWrite32 (Reg, Value); +} + +VOID +GpioPinSetDrive ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_DRIVE Drive + ) +{ + ASSERT (Group < GPIO_NGROUPS); + + INTN Idx; + EFI_PHYSICAL_ADDRESS Reg; + CONST UINT32 Value = GRF_GPIO_DS_MASK (Pin) | ((UINT32)Drive << GRF_GPIO_DS_SHIFT (Pin)); + + for(Idx = ARRAY_SIZE(mDsReg) - 1; Idx >= 0; Idx--) { + if(Group == mDsReg[Idx].Group && Pin >= mDsReg[Idx].Pin) { + Reg = mDsReg[Idx].Addr + GRF_GPIO_DS_REG(Pin - mDsReg[Idx].Pin); + } + } + + DEBUG ((DEBUG_INFO, "GpioPinSetDrive Group:%d Pin:%d Drive:%d\n", Group, Pin, Drive)); + DEBUG ((DEBUG_VERBOSE, "Reg - Value: 0x%lX = 0x%08X\n", Reg, Value)); + + MmioWrite32 (Reg, Value); +} + +VOID +GpioPinSetInput ( + IN UINT8 Group, + IN UINT8 Pin, + IN GPIO_PIN_INPUT_ENABLE InputEnable + ) +{ + ASSERT (Group < GPIO_NGROUPS); + + INTN Idx; + EFI_PHYSICAL_ADDRESS Reg; + CONST UINT32 Value = GRF_GPIO_IE_MASK (Pin) | ((UINT32)InputEnable << GRF_GPIO_IE_SHIFT (Pin)); + + for(Idx = ARRAY_SIZE(mIEReg) - 1; Idx >= 0; Idx--) { + if(Group == mIEReg[Idx].Group && Pin >= mIEReg[Idx].Pin) { + Reg = mIEReg[Idx].Addr + GRF_GPIO_IE_REG(Pin - mIEReg[Idx].Pin); + } + } + + DEBUG ((DEBUG_INFO, "GpioPinSetInput Group:%d Pin:%d InputEnable:%d\n", Group, Pin, InputEnable)); + DEBUG ((DEBUG_VERBOSE, "Reg - Value: 0x%lX = 0x%08X\n", Reg, Value)); + + MmioWrite32 (Reg, Value); +} + +VOID +GpioSetIomuxConfig ( + IN CONST GPIO_IOMUX_CONFIG *Configs, + IN UINT32 NumConfigs + ) +{ + UINT32 Index; + + for (Index = 0; Index < NumConfigs; Index++) { + CONST GPIO_IOMUX_CONFIG *Mux = &Configs[Index]; + DEBUG ((DEBUG_INFO, "GPIO: IOMUX for pin '%a'\n", Mux->Name)); + GpioPinSetFunction (Mux->Group, Mux->Pin, Mux->Function); + GpioPinSetPull (Mux->Group, Mux->Pin, Mux->Pull); + if (Mux->Drive != GPIO_PIN_DRIVE_DEFAULT) { + GpioPinSetDrive (Mux->Group, Mux->Pin, Mux->Drive); + } + } +} \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.inf new file mode 100644 index 0000000..9cb1305 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.inf @@ -0,0 +1,35 @@ +#/** @file +# +# RK3566/RK3568 GPIO Library. +# +# Copyright (c) 2021, Jared McNeill +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = GpioLib + FILE_GUID = FD6DFA94-101B-4DE3-8F55-D4CC1E1E642A + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = GpioLib + +[Sources] + GpioLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + +[FixedPcd] + +[Guids] diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.c new file mode 100644 index 0000000..6583960 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.c @@ -0,0 +1,164 @@ +/** @file + * + * Copyright (c) 2021, Andrei Warkentin + * Copyright (c) 2011-2015, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +VOID +BuildMemoryTypeInformationHob ( + VOID + ); + +STATIC +VOID +InitMmu ( + IN ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable + ) +{ + RETURN_STATUS Status; + + //Note: Because we called PeiServicesInstallPeiMemory() before to call InitMmu() the MMU Page Table + // resides in DRAM (even at the top of DRAM as it is the first permanent memory allocation) + Status = ArmConfigureMmu (MemoryTable, NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error: Failed to enable MMU\n")); + } +} + +STATIC +VOID +AddBasicMemoryRegion ( + IN ARM_MEMORY_REGION_DESCRIPTOR *Desc +) +{ + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_TESTED, + Desc->PhysicalBase, + Desc->Length + ); +} + +STATIC +VOID +AddRuntimeServicesRegion ( + IN ARM_MEMORY_REGION_DESCRIPTOR *Desc +) +{ + AddBasicMemoryRegion (Desc); + + BuildMemoryAllocationHob ( + Desc->PhysicalBase, + Desc->Length, + EfiRuntimeServicesData + ); +} + +STATIC +VOID +AddUnmappedMemoryRegion ( + IN ARM_MEMORY_REGION_DESCRIPTOR *Desc + ) +{ + // Do nothing +} + +STATIC +VOID +AddReservedMemoryRegion ( + IN ARM_MEMORY_REGION_DESCRIPTOR *Desc + ) +{ + AddBasicMemoryRegion (Desc); + + BuildMemoryAllocationHob ( + Desc->PhysicalBase, + Desc->Length, + EfiReservedMemoryType + ); +} + +void (*AddRegion[]) (IN ARM_MEMORY_REGION_DESCRIPTOR *Desc) = { + AddUnmappedMemoryRegion, + AddBasicMemoryRegion, + AddRuntimeServicesRegion, + AddReservedMemoryRegion, + }; + +/*++ + +Routine Description: + + + +Arguments: + + FileHandle - Handle of the file being invoked. + PeiServices - Describes the list of possible PEI Services. + +Returns: + + Status - EFI_SUCCESS if the boot mode could be set + +--*/ +EFI_STATUS +EFIAPI +MemoryPeim ( + IN EFI_PHYSICAL_ADDRESS UefiMemoryBase, + IN UINT64 UefiMemorySize + ) +{ + ARM_MEMORY_REGION_DESCRIPTOR *MemoryTable; + RK3588_MEMORY_REGION_INFO *MemoryInfo; + UINTN Index; + + DEBUG ((DEBUG_INFO, "%s\n", __FUNCTION__)); + + // Get Virtual Memory Map from the Platform Library + ArmPlatformGetVirtualMemoryMap (&MemoryTable); + + // Get additional info not provided by MemoryTable + Rk3588PlatformGetVirtualMemoryInfo (&MemoryInfo); + + // Register each memory region + for (Index = 0; MemoryTable[Index].Length != 0; Index++) { + ASSERT (MemoryInfo[Index].Type < ARRAY_SIZE (AddRegion)); + DEBUG ((DEBUG_INFO, "%s:\n" + "\tPhysicalBase: 0x%lX\n" + "\tVirtualBase: 0x%lX\n" + "\tLength: 0x%lX\n", + MemoryInfo[Index].Name, + MemoryTable[Index].PhysicalBase, + MemoryTable[Index].VirtualBase, + MemoryTable[Index].Length)); + AddRegion[MemoryInfo[Index].Type] (&MemoryTable[Index]); + } + + // Build Memory Allocation Hob + InitMmu (MemoryTable); + + if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) { + // Optional feature that helps prevent EFI memory map fragmentation. + BuildMemoryTypeInformationHob (); + } + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf new file mode 100644 index 0000000..f0bd07e --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf @@ -0,0 +1,45 @@ +#/** @file +# +# Copyright (c) 2021, Andrei Warkentin +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = MemoryInitPeiLib + FILE_GUID = 4bbc9c10-a100-43fb-8311-332ba497d1b4 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemoryInitPeiLib|SEC PEIM + +[Sources] + MemoryInitPeiLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + DebugLib + HobLib + ArmMmuLib + ArmPlatformLib + +[Guids] + gEfiMemoryTypeInformationGuid + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob + +[Pcd] + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + +[Depex] + TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.c new file mode 100644 index 0000000..79a3d81 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.c @@ -0,0 +1,98 @@ +/** @file + * + * RK3588 OTP Library. + * + * Copyright (c) 2022, Jared McNeill + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include + +#define OTP_BASE 0xfecc0000 + +#define RK3588_OTPC_AUTO_CTRL (OTP_BASE + 0x0004) +#define RK3588_ADDR_SHIFT 16 +#define RK3588_BURST_SHIFT 8 +#define RK3588_OTPC_AUTO_EN (OTP_BASE + 0x0008) +#define RK3588_AUTO_EN BIT0 +#define RK3588_OTPC_DOUT0 (OTP_BASE + 0x0020) +#define RK3588_OTPC_INT_ST (OTP_BASE + 0x0084) +#define RK3588_RD_DONE BIT1 + +#define RK3588_BLOCK_SIZE 4 +#define RK3588_NO_SECURE_OFFSET 0x300 + +VOID +OtpRead ( + IN UINT16 Offset, + IN UINT16 Length, + OUT UINT8 *Data + ) +{ + UINT32 Addr; + UINT16 AddrOffset; + UINT16 BytesRemaining; + UINT32 Value; + UINTN Retry; + + Addr = (Offset / RK3588_BLOCK_SIZE) + RK3588_NO_SECURE_OFFSET; + AddrOffset = Offset % RK3588_BLOCK_SIZE; + BytesRemaining = Length; + Retry = 100000; + + while (BytesRemaining > 0) { + MmioWrite32 (RK3588_OTPC_AUTO_CTRL, Addr << RK3588_ADDR_SHIFT | 1 << RK3588_BURST_SHIFT); + MmioWrite32 (RK3588_OTPC_AUTO_EN, RK3588_AUTO_EN); + while ((MmioRead32 (RK3588_OTPC_INT_ST) & RK3588_RD_DONE) == 0) { + MicroSecondDelay (1); + if (--Retry == 0) { + DEBUG ((DEBUG_WARN, "OTP read timeout!\n")); + break; + } + } + MmioWrite32 (RK3588_OTPC_INT_ST, RK3588_RD_DONE); + + Value = MmioRead32 (RK3588_OTPC_DOUT0); + + while (AddrOffset < RK3588_BLOCK_SIZE && BytesRemaining > 0) { + *Data++ = (Value >> (8 * AddrOffset)) & 0xFF; + AddrOffset++; + BytesRemaining--; + } + + AddrOffset = 0; + Addr++; + } +} + +VOID +OtpReadCpuCode ( + OUT UINT16 *CpuCode + ) +{ + OtpRead (0x02, 0x2, (UINT8*)CpuCode); +} + +VOID +OtpReadId ( + OUT UINT8 Id[16] + ) +{ + OtpRead (0x07, 0x10, Id); +} + +VOID +OtpReadCpuVersion ( + OUT UINT8 *Version + ) +{ + OtpRead (0x1c, 0x1, Version); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.inf new file mode 100644 index 0000000..c5b03e2 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.inf @@ -0,0 +1,35 @@ +#/** @file +# +# RK3588 OTP Library. +# +# Copyright (c) 2022, Jared McNeill +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = OtpLib + FILE_GUID = 412C6116-58A9-4512-B98E-0EF837D1D622 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = OtpLib + +[Sources] + OtpLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + TimerLib + +[Guids] diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.c new file mode 100755 index 0000000..8dbfef4 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.c @@ -0,0 +1,117 @@ +/** @file + * + * RK3588 PCIe PHY Library. + * + * Copyright (c) 2023, David Gwynne + * Copyright (c) 2023, Jared McNeill + * Copyright (c) 2023, Molly Sophia + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCIE30_PHY_GRF 0xfd5b8000 +/* PCIEPHY_GRF */ +#define GRF_PCIE30_PHY_CON(n) (PCIE30_PHY_GRF + 0x0000 + (n) * 0x4) /* 0 .. 9 */ +#define GRF_PCIE30_PHY_STATUS(n) (PCIE30_PHY_GRF + 0x0080 + (n) * 0x4) /* 0 .. 2 */ +#define GRF_PCIE30_PHY_PRT0_CON(n) (PCIE30_PHY_GRF + 0x0100 + (n) * 0x4) /* 0 .. 39 */ +/* CON1 and CON9 */ +#define GRF_PCIE30PHY_DA_OCM_MASK BIT15 +#define GRF_PCIE30PHY_DA_OCM BIT15 +/* CON5 */ +#define GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT 0 +#define GRF_PCIE30PHY_LANE0_LINK_NUM_MASK (0xfU << GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT) +/* CON6 */ +#define GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT 0 +#define GRF_PCIE30PHY_LANE1_LINK_NUM_MASK (0xfU << GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT) + +/* STATUS0 */ +#define GRF_PCIE30PHY_SRAM_INIT_DONE BIT14 + +#define SOFTRST_INDEX 27 +#define SOFTRST_BIT 14 + +STATIC +VOID +GrfUpdateRegister ( + IN EFI_PHYSICAL_ADDRESS Reg, + IN UINT32 Mask, + IN UINT32 Val + ) +{ + ASSERT ((Mask & ~0xFFFF) == 0); + ASSERT ((Val & ~0xFFFF) == 0); + ASSERT ((Mask & Val) == Val); + + MmioWrite32 (Reg, (Mask << 16) | Val); +} + +EFI_STATUS +Pcie30PhyInit ( + VOID + ) +{ + // UINTN Retry; + + DEBUG ((DEBUG_INFO, "PCIe30: PHY init\n")); + DEBUG ((DEBUG_INFO, "PCIe30: PHY mode %d\n", PcdGet8(PcdPcie30PhyMode))); + + // MicroSecondDelay(100000); + + /* Disable power domain */ + MmioWrite32(0xFD8D8150, 0x1 << 23 | 0x1 << 21); // PD_PCIE & PD_PHP + + /* Phy mode: from pcd Pcie30PhyMode */ + MmioWrite32(GRF_PCIE30_PHY_CON(0), (0x7 << 16) | PcdGet8(PcdPcie30PhyMode)); + + MmioWrite32(0xFD7C8A00, (0x1 << 10) | (0x1 << 26)); + + /* Deassert PCIe PMA output clamp mode */ + MmioWrite32(GRF_PCIE30_PHY_CON(0), (0x1 << 8) | (0x1 << 24)); + + /* Deassert PHY Reset */ + MmioWrite32(0xFD7C8A00, (0x1 << 26)); + + // /* Enable clocks */ + // PmuCruEnableClock (2, 13); + // PmuCruEnableClock (2, 14); + // CruEnableClock (33, 8); + + // /* Assert reset */ + // CruAssertSoftReset (SOFTRST_INDEX, SOFTRST_BIT); + // gBS->Stall (1000); + + // MicroSecondDelay (1); + + // GrfUpdateRegister (GRF_PCIE30_PHY_CON (9), GRF_PCIE30PHY_DA_OCM_MASK, GRF_PCIE30PHY_DA_OCM); + // GrfUpdateRegister (GRF_PCIE30_PHY_CON (5), GRF_PCIE30PHY_LANE0_LINK_NUM_MASK, PCIE30PHY_LANE0_LINK_NUM); + // GrfUpdateRegister (GRF_PCIE30_PHY_CON (6), GRF_PCIE30PHY_LANE1_LINK_NUM_MASK, PCIE30PHY_LANE1_LINK_NUM); + // GrfUpdateRegister (GRF_PCIE30_PHY_CON (1), GRF_PCIE30PHY_DA_OCM_MASK, GRF_PCIE30PHY_DA_OCM); + + // /* De-assert reset */ + // CruDeassertSoftReset (SOFTRST_INDEX, SOFTRST_BIT); + + // for (Retry = 500; Retry > 0; Retry--) { + // MicroSecondDelay (100); + + // if ((MmioRead32 (GRF_PCIE30_PHY_STATUS (0)) & GRF_PCIE30PHY_SRAM_INIT_DONE) != 0) { + // break; + // } + // } + // if (Retry == 0) { + // DEBUG ((DEBUG_WARN, "PCIe30: Failed to enable PCIe 3.0 PHY\n")); + // return EFI_TIMEOUT; + // } + + DEBUG ((DEBUG_INFO, "PCIe30: PHY init complete\n")); + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.inf new file mode 100755 index 0000000..84e1874 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.inf @@ -0,0 +1,41 @@ +#/** @file +# +# RK3588 PCIe 3.0 PHY Library. +# +# Copyright (c) 2023, Jared McNeill +# Copyright (c) 2023, Molly Sophia +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = Pcie30PhyLib + FILE_GUID = FF2358C0-1F45-4A8F-971F-891FFDE25C81 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Pcie30PhyLib + +[Sources] + Pcie30PhyLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + TimerLib + CruLib + +[FixedPcd] + +[Pcd] + gRK3588TokenSpaceGuid.PcdPcie30PhyMode + +[Guids] diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/PlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/PlatformLib.inf new file mode 100644 index 0000000..c6fa162 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/PlatformLib.inf @@ -0,0 +1,73 @@ +#/** @file +# +# Copyright (c) 2021, Jared McNeill +# Copyright (c) 2017-2021, Andrei Warkentin +# Copyright (c) 2014-2016, Linaro Limited. All rights reserved. +# Copyright (c) 2011-2019, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = PlatformLib + FILE_GUID = ADAB50A9-04BE-4B17-9CBF-17B781B3CB00 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmPlatformLib|SEC PEIM + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + Silicon/Rockchip/RockchipPkg.dec + +[LibraryClasses] + ArmLib + BaseVariableLib + FdtLib + IoLib + MemoryAllocationLib + PcdLib + PrintLib + SdramLib + SerialPortLib + +[Sources.common] + Rk3588.c + Rk3588Mem.c + +[Sources.AARCH64] + Rk3588Helper.S + +[FixedPcd] + gArmTokenSpaceGuid.PcdFvBaseAddress + gArmTokenSpaceGuid.PcdFvSize + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gArmTokenSpaceGuid.PcdGicDistributorBase + gArmTokenSpaceGuid.PcdGicRedistributorsBase + gArmPlatformTokenSpaceGuid.PcdCoreCount + gArmTokenSpaceGuid.PcdArmPrimaryCoreMask + gArmTokenSpaceGuid.PcdArmPrimaryCore + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + +[PatchPcd] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate + +[Ppis] + gArmMpCoreInfoPpiGuid + +[Guids] + gRK3588DxeFormSetGuid diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588.c new file mode 100644 index 0000000..d991409 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588.c @@ -0,0 +1,120 @@ +/** @file + * + * Copyright (c) 2014-2016, Linaro Limited. All rights reserved. + * Copyright (c) 2014, Red Hat, Inc. + * Copyright (c) 2011-2013, ARM Limited. All rights reserved. + * + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include + +#include + +/** + Return the current Boot Mode + + This function returns the boot reason on the platform + + @return Return the current Boot Mode of the platform + +**/ +EFI_BOOT_MODE +ArmPlatformGetBootMode ( + VOID + ) +{ + return BOOT_WITH_FULL_CONFIGURATION; +} + +/** + This function is called by PrePeiCore, in the SEC phase. +**/ +RETURN_STATUS +ArmPlatformInitialize ( + IN UINTN MpId + ) +{ + EFI_STATUS Status; + UINTN Size; + UINT64 BaudRate; + + Size = sizeof (UINT64); + Status = BaseGetVariable ( + L"DebugSerialPortBaudRate", + &gRK3588DxeFormSetGuid, + NULL, + &Size, + &BaudRate + ); + if (EFI_ERROR (Status) || BaudRate == 0) { + return RETURN_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "%a: Setting baud rate to %lu\n", __func__, BaudRate)); + + PatchPcdSet64 (PcdUartDefaultBaudRate, BaudRate); + SerialPortInitialize (); + + return RETURN_SUCCESS; +} + +VOID +ArmPlatformInitializeSystemMemory ( + VOID + ) +{ +} + +STATIC ARM_CORE_INFO mRk3588InfoTable[] = { + { 0x0, 0x000 }, // Cluster 0, Core 0 + { 0x0, 0x100 }, // Cluster 0, Core 1 + { 0x0, 0x200 }, // Cluster 0, Core 2 + { 0x0, 0x300 }, // Cluster 0, Core 3 + { 0x0, 0x400 }, // Cluster 0, Core 4 + { 0x0, 0x500 }, // Cluster 0, Core 5 + { 0x0, 0x600 }, // Cluster 0, Core 6 + { 0x0, 0x700 }, // Cluster 0, Core 7 +}; + +STATIC +EFI_STATUS +PrePeiCoreGetMpCoreInfo ( + OUT UINTN *CoreCount, + OUT ARM_CORE_INFO **ArmCoreTable + ) +{ + // Only support one cluster + *CoreCount = sizeof (mRk3588InfoTable) / sizeof (ARM_CORE_INFO); + *ArmCoreTable = mRk3588InfoTable; + + return EFI_SUCCESS; +} + +STATIC ARM_MP_CORE_INFO_PPI mMpCoreInfoPpi = { + PrePeiCoreGetMpCoreInfo +}; +STATIC EFI_PEI_PPI_DESCRIPTOR mPlatformPpiTable[] = { + { + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gArmMpCoreInfoPpiGuid, + &mMpCoreInfoPpi + } +}; + +VOID +ArmPlatformGetPlatformPpiList ( + OUT UINTN *PpiListSize, + OUT EFI_PEI_PPI_DESCRIPTOR **PpiList + ) +{ + *PpiListSize = sizeof (mPlatformPpiTable); + *PpiList = mPlatformPpiTable; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Helper.S b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Helper.S new file mode 100644 index 0000000..74862b8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Helper.S @@ -0,0 +1,45 @@ +/** @file + * + * Copyright (c) 2020-2021, Andrei Warkentin + * Copyright (c) 2019-2020, Pete Batard + * Copyright (c) 2016, Linaro Limited. All rights reserved. + * Copyright (c) 2011-2020, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include + +ASM_FUNC (ArmPlatformPeiBootAction) + ret + +//UINTN +//ArmPlatformGetPrimaryCoreMpId ( +// VOID +// ); +ASM_FUNC (ArmPlatformGetPrimaryCoreMpId) + MOV32 (w0, FixedPcdGet32 (PcdArmPrimaryCore)) + ret + +//UINTN +//ArmPlatformIsPrimaryCore ( +// IN UINTN MpId +// ); +ASM_FUNC (ArmPlatformIsPrimaryCore) + mov x0, #1 + ret + +//UINTN +//ArmPlatformGetCorePosition ( +// IN UINTN MpId +// ); +// With this function: CorePos = (ClusterId * 4) + CoreId +ASM_FUNC (ArmPlatformGetCorePosition) + and x1, x0, #ARM_CORE_MASK + and x0, x0, #ARM_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Mem.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Mem.c new file mode 100644 index 0000000..b8b67e0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/PlatformLib/Rk3588Mem.c @@ -0,0 +1,192 @@ +/** @file + * + * Copyright (c) 2021, Jared McNeill + * Copyright (c) 2017-2021, Andrey Warkentin + * Copyright (c) 2019, Pete Batard + * Copyright (c) 2014, Linaro Limited. All rights reserved. + * Copyright (c) 2013-2018, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include + +UINT64 mSystemMemoryBase = FixedPcdGet64 (PcdSystemMemoryBase); +STATIC UINT64 mSystemMemorySize = FixedPcdGet64 (PcdSystemMemorySize); + +// The total number of descriptors, including the final "end-of-table" descriptor. +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 12 + +STATIC BOOLEAN VirtualMemoryInfoInitialized = FALSE; +STATIC RK3588_MEMORY_REGION_INFO VirtualMemoryInfo[MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS]; + +#define VariablesBase FixedPcdGet64(PcdFlashNvStorageVariableBase64) + +#define VariablesSize (FixedPcdGet32(PcdFlashNvStorageVariableSize) + \ + FixedPcdGet32(PcdFlashNvStorageFtwWorkingSize) + \ + FixedPcdGet32(PcdFlashNvStorageFtwSpareSize)) + +/** + Return the Virtual Memory Map of your platform + + This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU + on your platform. + + @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR + describing a Physical-to-Virtual Memory + mapping. This array must be ended by a + zero-filled entry + +**/ +VOID +ArmPlatformGetVirtualMemoryMap ( + IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap + ) +{ + UINTN Index = 0; + ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; + + mSystemMemorySize = SdramGetMemorySize (); + DEBUG ((DEBUG_INFO, "RAM: 0x%ll08X (Size 0x%ll08X)\n", mSystemMemoryBase, mSystemMemorySize)); + + VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages + (EFI_SIZE_TO_PAGES (sizeof (ARM_MEMORY_REGION_DESCRIPTOR) * + MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS)); + if (VirtualMemoryTable == NULL) { + return; + } + + // + // TF-A Region + // Must be unmapped for the shared memory to retain its attributes. + // + VirtualMemoryTable[Index].PhysicalBase = 0x00000000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x200000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED; + VirtualMemoryInfo[Index].Type = RK3588_MEM_UNMAPPED_REGION; + VirtualMemoryInfo[Index++].Name = L"TF-A + Shared Memory"; + + // Firmware Volume + VirtualMemoryTable[Index].PhysicalBase = FixedPcdGet64 (PcdFvBaseAddress); + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = FixedPcdGet32 (PcdFvSize); + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_RESERVED_REGION; + VirtualMemoryInfo[Index++].Name = L"UEFI FV"; + + // Variable Volume + VirtualMemoryTable[Index].PhysicalBase = VariablesBase; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = VariablesSize; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_RUNTIME_REGION; + VirtualMemoryInfo[Index++].Name = L"Variable Store"; + + // Base System RAM (< OP-TEE) + VirtualMemoryTable[Index].PhysicalBase = VariablesBase + VariablesSize; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = MIN (mSystemMemorySize, 0x08400000 - VirtualMemoryTable[Index].PhysicalBase); + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_BASIC_REGION; + VirtualMemoryInfo[Index++].Name = L"System RAM (< OP-TEE)"; + + // OP-TEE Region + VirtualMemoryTable[Index].PhysicalBase = 0x08400000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x1000000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_RESERVED_REGION; + VirtualMemoryInfo[Index++].Name = L"OP-TEE"; + + // Base System RAM (< 4GB) + VirtualMemoryTable[Index].PhysicalBase = 0x08400000 + 0x1000000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = MIN (mSystemMemorySize, 0xF0000000 - VirtualMemoryTable[Index].PhysicalBase); + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_BASIC_REGION; + VirtualMemoryInfo[Index++].Name = L"System RAM (< 4GB)"; + + // MMIO + VirtualMemoryTable[Index].PhysicalBase = 0xF0000000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x10000000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + VirtualMemoryInfo[Index].Type = RK3588_MEM_UNMAPPED_REGION; + VirtualMemoryInfo[Index++].Name = L"MMIO"; + + if (mSystemMemorySize > 0x100000000UL) { + // Base System RAM >= 4GB + VirtualMemoryTable[Index].PhysicalBase = 0x100000000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = mSystemMemorySize - 0x100000000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; + VirtualMemoryInfo[Index].Type = RK3588_MEM_BASIC_REGION; + VirtualMemoryInfo[Index++].Name = L"System RAM >= 4GB"; + } + + // MMIO > 32GB + VirtualMemoryTable[Index].PhysicalBase = 0x0000000900000000UL; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x0000000141400000UL; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; + VirtualMemoryInfo[Index].Type = RK3588_MEM_UNMAPPED_REGION; + VirtualMemoryInfo[Index++].Name = L"MMIO > 32GB"; + + if (mSystemMemoryBase + mSystemMemorySize > 0x3fc000000UL) { + // Bad memory range 1 + VirtualMemoryTable[Index].PhysicalBase = 0x3fc000000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x500000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED; + VirtualMemoryInfo[Index].Type = RK3588_MEM_RESERVED_REGION; + VirtualMemoryInfo[Index++].Name = L"BAD1"; + + // Bad memory range 2 + VirtualMemoryTable[Index].PhysicalBase = 0x3fff00000; + VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; + VirtualMemoryTable[Index].Length = 0x100000; + VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED; + VirtualMemoryInfo[Index].Type = RK3588_MEM_RESERVED_REGION; + VirtualMemoryInfo[Index++].Name = L"BAD2"; + } + + // End of Table + VirtualMemoryTable[Index].PhysicalBase = 0; + VirtualMemoryTable[Index].VirtualBase = 0; + VirtualMemoryTable[Index].Length = 0; + VirtualMemoryTable[Index++].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0; + + ASSERT(Index <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS); + + *VirtualMemoryMap = VirtualMemoryTable; + VirtualMemoryInfoInitialized = TRUE; +} + +/** + Return additional memory info not populated by the above call. + + This call should follow the one to ArmPlatformGetVirtualMemoryMap (). + +**/ +VOID +Rk3588PlatformGetVirtualMemoryInfo ( + IN RK3588_MEMORY_REGION_INFO** MemoryInfo + ) +{ + ASSERT (VirtualMemoryInfo != NULL); + + if (!VirtualMemoryInfoInitialized) { + DEBUG ((DEBUG_ERROR, + "ArmPlatformGetVirtualMemoryMap must be called before Rk3588PlatformGetVirtualMemoryInfo.\n")); + return; + } + + *MemoryInfo = VirtualMemoryInfo; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.c new file mode 100755 index 0000000..b38baa0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.c @@ -0,0 +1,655 @@ +/** @file + + Copyright 2017, 2020 NXP + Copyright 2021-2023, Jared McNeill + Copyright 2023, Molly Sophia + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PciHostBridgeInit.h" + +/* APB Registers */ +#define PCIE_CLIENT_GENERAL_CON 0x0000 +#define DEVICE_TYPE_SHIFT 4 +#define DEVICE_TYPE_MASK (0xFU << DEVICE_TYPE_SHIFT) +#define DEVICE_TYPE_RC (4 << DEVICE_TYPE_SHIFT) +#define LINK_REQ_RST_GRT BIT3 +#define LTSSM_ENABLE BIT2 +#define PCIE_CLIENT_INTR_MASK_LEGACY 0x001C +#define PCIE_CLIENT_POWER_CON 0x002C +#define APP_CLK_REQ_N BIT0 +#define CLK_REQ_N_BYPASS BIT12 +#define CLK_REQ_N_CON BIT13 +#define PCIE_CLIENT_GENERAL_DEBUG_INIT 0x0104 +#define PCIE_CLIENT_HOT_RESET_CTRL 0x0180 +#define APP_LSSTM_ENABLE_ENHANCE BIT4 +#define PCIE_CLIENT_LTSSM_STATUS 0x0300 +#define RDLH_LINK_UP BIT17 +#define SMLH_LINK_UP BIT16 +#define SMLH_LTSSM_STATE_MASK 0x3f +#define SMLH_LTSSM_STATE_LINK_UP 0x11 + +/* DBI Registers */ +#define PCI_COMMAND 0x0004 +#define PCI_DEVICE_CLASS 0x000A +#define PCI_BAR0 0x0010 +#define PCI_BAR1 0x0014 +#define PCIE_LINK_CAPABILITY 0x007C +#define PCIE_LINK_STATUS 0x0080 +#define LINK_STATUS_WIDTH_SHIFT 20 +#define LINK_STATUS_WIDTH_MASK (0xFU << LINK_STATUS_WIDTH_SHIFT) +#define LINK_STATUS_SPEED_SHIFT 16 +#define LINK_STATUS_SPEED_MASK (0xFU << LINK_STATUS_SPEED_SHIFT) +#define PCIE_LINK_CTL_2 0x00A0 +#define PL_PORT_LINK_CTRL_OFF 0x0710 +#define LINK_CAPABLE_SHIFT 16 +#define LINK_CAPABLE_MASK (0x3FU << LINK_CAPABLE_SHIFT) +#define FAST_LINK_MODE BIT7 +#define DLL_LINK_EN BIT5 +#define PL_GEN2_CTRL_OFF 0x080C +#define DIRECT_SPEED_CHANGE BIT17 +#define NUM_OF_LANES_SHIFT 8 +#define NUM_OF_LANES_MASK (0x1FU << NUM_OF_LANES_SHIFT) +#define PL_MISC_CONTROL_1_OFF 0x08BC +#define DBI_RO_WR_EN BIT0 + +#define PCIE_TYPE0_HDR_DBI2_OFFSET 0x100000 + +/* ATU Registers */ +#define ATU_CAP_BASE 0x300000 +#define IATU_REGION_CTRL_OUTBOUND(n) (ATU_CAP_BASE + ((n) << 9)) +#define IATU_REGION_CTRL_INBOUND(n) (ATU_CAP_BASE + ((n) << 9) + 0x100) +#define IATU_REGION_CTRL_1_OFF 0x000 +#define IATU_TYPE_MEM 0 +#define IATU_TYPE_IO 2 +#define IATU_TYPE_CFG0 4 +#define IATU_TYPE_CFG1 5 +#define IATU_REGION_CTRL_2_OFF 0x004 +#define IATU_ENABLE BIT31 +#define IATU_CFG_SHIFT_MODE BIT28 +#define IATU_LWR_BASE_ADDR_OFF 0x008 +#define IATU_UPPER_BASE_ADDR_OFF 0x00C +#define IATU_LIMIT_ADDR_OFF 0x010 +#define IATU_LWR_TARGET_ADDR_OFF 0x014 +#define IATU_UPPER_TARGET_ADDR_OFF 0x018 + +BOOLEAN +IsPcieNumEnabled( + UINTN PcieNum + ) +{ + BOOLEAN Enabled = FALSE; + + /* + * According to TRM Part 1 6.19.2 PCIe3PHY_GRF_CMN_CON0, + * if pcie l4(PCIE30X4) bifurcation enabled (phymode & 0b01), pcie3phy lane 1 is connected to 1l0 + * if pcie l2(PCIE30X2) bifurcation enabled (phymode & 0b10), pcie3phy lane 3 is connected to 1l1 + */ + switch (PcieNum) + { + case PCIE_SEGMENT_PCIE30X4: + Enabled = (FixedPcdGetBool (PcdPcie30Supported) && PcdGet32 (PcdPcie30State) == PCIE30_STATE_ENABLED); + break; + + case PCIE_SEGMENT_PCIE30X2: + Enabled = (PcdGet8 (PcdPcie30PhyMode) != PCIE30_PHY_MODE_AGGREGATION); + break; + + case PCIE_SEGMENT_PCIE20L0: + Enabled = (PcdGet32(PcdComboPhy1Mode) == COMBO_PHY_MODE_PCIE); + break; + + case PCIE_SEGMENT_PCIE20L1: + Enabled = (PcdGet32(PcdComboPhy2Mode) == COMBO_PHY_MODE_PCIE); + break; + + case PCIE_SEGMENT_PCIE20L2: + Enabled = (PcdGet32(PcdComboPhy0Mode) == COMBO_PHY_MODE_PCIE); + break; + + default: + break; + } + + return Enabled; +} + +STATIC CONST GPIO_IOMUX_CONFIG mPcie30x1_0_IomuxConfigs[][3] = { + { + { "pcie30x1_0_clkreqnm0", 0, GPIO_PIN_PC0, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_wakenm0", 0, GPIO_PIN_PC4, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_perstnm0", 0, GPIO_PIN_PC5, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, + { + { "pcie30x1_0_clkreqnm1", 4, GPIO_PIN_PA3, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_wakenm1", 4, GPIO_PIN_PA4, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_perstnm1", 4, GPIO_PIN_PA5, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, + { + { "pcie30x1_0_clkreqnm2", 1, GPIO_PIN_PB5, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_wakenm2", 1, GPIO_PIN_PB3, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_0_perstnm2", 1, GPIO_PIN_PB4, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, +}; + +STATIC CONST GPIO_IOMUX_CONFIG mPcie30x1_1_IomuxConfigs[][3] = { + { + { "pcie30x1_1_clkreqnm0", 0, GPIO_PIN_PB5, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_wakenm0", 0, GPIO_PIN_PB6, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_perstnm0", 0, GPIO_PIN_PB7, 12, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, + { + { "pcie30x1_1_clkreqnm1", 4, GPIO_PIN_PA0, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_wakenm1", 4, GPIO_PIN_PA1, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_perstnm1", 4, GPIO_PIN_PA2, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, + { + { "pcie30x1_1_clkreqnm2", 1, GPIO_PIN_PA0, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_wakenm2", 1, GPIO_PIN_PA1, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie30x1_1_perstnm2", 1, GPIO_PIN_PA7, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, +}; + +STATIC CONST GPIO_IOMUX_CONFIG mPcie20x1_2_IomuxConfigs[][3] = { + { + { "pcie20x1_2_clkreqnm0", 3, GPIO_PIN_PC7, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie20x1_2_wakenm0", 3, GPIO_PIN_PD0, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie20x1_2_perstnm0", 3, GPIO_PIN_PD1, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, + { + { "pcie20x1_2_clkreqnm1", 4, GPIO_PIN_PB7, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie20x1_2_wakenm1", 4, GPIO_PIN_PC0, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + { "pcie20x1_2_perstnm1", 4, GPIO_PIN_PC1, 4, GPIO_PIN_PULL_NONE, GPIO_PIN_DRIVE_DEFAULT }, + }, +}; + +STATIC BOOLEAN PcieSupportClkreq[NUM_PCIE_CONTROLLER] = { + FALSE, FALSE, FALSE, FALSE, FALSE +}; + +VOID +PciePinmuxInit( + UINTN PcieNum, + UINTN MuxNum + ) +{ + ASSERT(PcieNum < NUM_PCIE_CONTROLLER); + switch(PcieNum) { + case PCIE_SEGMENT_PCIE20L0: + ASSERT(MuxNum < 3); + GpioSetIomuxConfig(&mPcie30x1_0_IomuxConfigs[MuxNum][0], 3); + break; + case PCIE_SEGMENT_PCIE20L1: + ASSERT(MuxNum < 3); + GpioSetIomuxConfig(&mPcie30x1_1_IomuxConfigs[MuxNum][0], 3); + break; + case PCIE_SEGMENT_PCIE20L2: + ASSERT(MuxNum < 2); + GpioSetIomuxConfig(&mPcie20x1_2_IomuxConfigs[MuxNum][0], 3); + break; + + default: + return; + } + PcieSupportClkreq[PcieNum] = TRUE; +} + +STATIC +VOID +PciSetupClocks ( + IN UINTN Segment + ) +{ + MmioWrite32(0xFD7C8800, (0x1 << 17)|(0x1 << 25)); // pclk_phptop_cru_en + MmioWrite32(0xFD7C0880, 0xffff0000); //CRU_GATE_CON32 + switch(Segment) { + case PCIE_SEGMENT_PCIE30X4: + MmioWrite32(0xFD7C8A00, (0x1 << 24)|(0x1 << 26)); //PHPTOPCRU_SOFTRST_CON00 + MmioWrite32(0xFD7C8800, (0x1 << 24)); //PHPTOPCRU_GATE_CON00 + MmioWrite32(0xFD7C0A80, (0x1 << 29)); //CRU_SOFTRST_CON32:resetn_pcie_4l_power_up + MmioWrite32(0xFD7C089c, (0x1 << 16)); //CRU_GATE_CON39:clk_pcie_4l_pipe_en + MmioWrite32(0xFD7C0888, (0x1 << 17)); //CRU_GATE_CON34:clk_pcie_4l_aux_en + MmioWrite32(0xFD7C0884, (0x1 << 28)|(0x1 << 23)|(0x1 << 18)); //CRU_GATE_CON33:pclk_pcie_4l_en,aclk_pcie_4l_slv_en,aclk_pcie_4l_mstr_en + break; + case PCIE_SEGMENT_PCIE30X2: + MmioWrite32(0xFD7C0A80, (0x1 << 30)); //CRU_SOFTRST_CON32:resetn_pcie_2l_power_up + MmioWrite32(0xFD7C089c, (0x1 << 17)); //CRU_GATE_CON39:clk_pcie_2l_pipe_en + MmioWrite32(0xFD7C0888, (0x1 << 18)); //CRU_GATE_CON34:clk_pcie_2l_aux_en + MmioWrite32(0xFD7C0884, (0x1 << 29)|(0x1 << 24)|(0x1 << 19)); //CRU_GATE_CON33:pclk_pcie_2l_en,aclk_pcie_2l_slv_en,aclk_pcie_2l_mstr_en + break; + case PCIE_SEGMENT_PCIE20L2: //phy0 + MmioWrite32(0xFD7C8A00, (0x1 << 21)|(0x1 << 18)); //PHPTOPCRU_SOFTRST_CON00 + MmioWrite32(0xFD7C8800, (0x1 << 21)|(0x1 << 18)); //PHPTOPCRU_GATE_CON00 + MmioWrite32(0xFD7C0A84, (0x1 << 17)); //CRU_SOFTRST_CON33:resetn_pcie_1l2_power_up + MmioWrite32(0xFD7C0898, (0x1 << 29)); //CRU_GATE_CON38:clk_pcie_1l2_pipe_en + MmioWrite32(0xFD7C0888, (0x1 << 21)|(0x1 << 16)); //CRU_GATE_CON34:clk_pcie_1l2_aux_en,pclk_pcie_1l2_en + MmioWrite32(0xFD7C0884, (0x1 << 27)|(0x1 << 22)); //CRU_GATE_CON33:aclk_pcie_1l2_slv_en,aclk_pcie_1l2_mstr_en + break; + case PCIE_SEGMENT_PCIE20L0: //phy1 + MmioWrite32(0xFD7C8A00, (0x1 << 22)|(0x1 << 19)); //PHPTOPCRU_SOFTRST_CON00 + MmioWrite32(0xFD7C8800, (0x1 << 22)|(0x1 << 19)); //PHPTOPCRU_GATE_CON00 + MmioWrite32(0xFD7C0A80, (0x1 << 31)); //CRU_SOFTRST_CON32:resetn_pcie_1l0_power_up + MmioWrite32(0xFD7C0898, (0x1 << 30)); //CRU_GATE_CON38:clk_pcie_1l0_pipe_en + MmioWrite32(0xFD7C0888, (0x1 << 19)); //CRU_GATE_CON34:clk_pcie_1l0_aux_en + MmioWrite32(0xFD7C0884, (0x1 << 30)|(0x1 << 25)|(0x1 << 20)); //CRU_GATE_CON33:pclk_pcie_1l0_en,aclk_pcie_1l0_slv_en,aclk_pcie_1l0_mstr_en + break; + case PCIE_SEGMENT_PCIE20L1: //phy2 + MmioWrite32(0xFD7C8A00, (0x1 << 23)|(0x1 << 20)); //PHPTOPCRU_SOFTRST_CON00 + MmioWrite32(0xFD7C8800, (0x1 << 23)|(0x1 << 20)); //PHPTOPCRU_GATE_CON00 + MmioWrite32(0xFD7C0A84, (0x1 << 16)); //CRU_SOFTRST_CON33:resetn_pcie_1l1_power_up + MmioWrite32(0xFD7C0898, (0x1 << 31)); //CRU_GATE_CON38:clk_pcie_1l1_pipe_en + MmioWrite32(0xFD7C0888, (0x1 << 20)); //CRU_GATE_CON34:clk_pcie_1l1_aux_en + MmioWrite32(0xFD7C0884, (0x1 << 31)|(0x1 << 26)|(0x1 << 21)); //CRU_GATE_CON33:pclk_pcie_1l1_en,aclk_pcie_1l1_slv_en,aclk_pcie_1l1_mstr_en + break; + default: + break; + } + +} + +STATIC +VOID +PciSetRcMode ( + IN UINTN Segment, + IN EFI_PHYSICAL_ADDRESS ApbBase + ) +{ + MmioWrite32 (ApbBase + PCIE_CLIENT_INTR_MASK_LEGACY, 0xFFFF0000); + MmioWrite32 (ApbBase + PCIE_CLIENT_HOT_RESET_CTRL, + (APP_LSSTM_ENABLE_ENHANCE << 16) | APP_LSSTM_ENABLE_ENHANCE); + + if(PcieSupportClkreq[Segment]) { + MmioWrite32 (ApbBase + PCIE_CLIENT_POWER_CON, (APP_CLK_REQ_N << 16) | APP_CLK_REQ_N); + } else { + MmioWrite32 (ApbBase + PCIE_CLIENT_POWER_CON, APP_CLK_REQ_N << 16); + MmioWrite32 (ApbBase + PCIE_CLIENT_POWER_CON, ((CLK_REQ_N_BYPASS|CLK_REQ_N_CON) << 16) | CLK_REQ_N_BYPASS); + // Maybe also disable PCIE L1SS capabilities here? + } + MmioWrite32 (ApbBase + PCIE_CLIENT_GENERAL_CON, + (DEVICE_TYPE_MASK << 16) | DEVICE_TYPE_RC); +} + +STATIC +VOID +PciSetupBars ( + IN EFI_PHYSICAL_ADDRESS DbiBase + ) +{ + MmioWrite16 (DbiBase + PCI_DEVICE_CLASS, (PCI_CLASS_BRIDGE << 8) | PCI_CLASS_BRIDGE_P2P); + + // Disable BAR0 + BAR1 of root port as they're invalid. + MmioWrite32 (DbiBase + PCIE_TYPE0_HDR_DBI2_OFFSET + PCI_BAR0, 0x0); + MmioWrite32 (DbiBase + PCIE_TYPE0_HDR_DBI2_OFFSET + PCI_BAR1, 0x0); +} + +STATIC +VOID +PciDirectSpeedChange ( + IN EFI_PHYSICAL_ADDRESS DbiBase + ) +{ + DEBUG ((DEBUG_INIT, "PCIe: SetupBars: Speed change\n")); + /* Initiate a speed change to Gen2 or Gen3 after the link is initialized as Gen1 speed. */ + MmioOr32 (DbiBase + PL_GEN2_CTRL_OFF, DIRECT_SPEED_CHANGE); +} + +STATIC +VOID +PciSetupLinkSpeed ( + IN EFI_PHYSICAL_ADDRESS DbiBase, + IN UINT32 Speed, + IN UINT32 NumLanes + ) +{ + /* Select target link speed */ + MmioAndThenOr32 (DbiBase + PCIE_LINK_CTL_2, ~0xFU, Speed); + MmioAndThenOr32 (DbiBase + PCIE_LINK_CAPABILITY, ~0xFU, Speed); + + /* Disable fast link mode, select number of lanes, and enable link initialization */ + MmioAndThenOr32 (DbiBase + PL_PORT_LINK_CTRL_OFF, + ~(LINK_CAPABLE_MASK | FAST_LINK_MODE), + DLL_LINK_EN | (((NumLanes * 2) - 1) << LINK_CAPABLE_SHIFT)); + + /* Select link width */ + MmioAndThenOr32 (DbiBase + PL_GEN2_CTRL_OFF, ~NUM_OF_LANES_MASK, + NumLanes << NUM_OF_LANES_SHIFT); +} + +STATIC +VOID +PciGetLinkSpeedWidth ( + IN EFI_PHYSICAL_ADDRESS DbiBase, + OUT UINT32 *Speed, + OUT UINT32 *Width + ) +{ + UINT32 Val; + + Val = MmioRead32 (DbiBase + PCIE_LINK_STATUS); + *Speed = (Val & LINK_STATUS_SPEED_MASK) >> LINK_STATUS_SPEED_SHIFT; + *Width = (Val & LINK_STATUS_WIDTH_MASK) >> LINK_STATUS_WIDTH_SHIFT; +} + +STATIC +VOID +PciPrintLinkSpeedWidth ( + IN UINT32 Speed, + IN UINT32 Width + ) +{ + char LinkSpeedBuf[6]; + + switch (Speed) { + case 0: + AsciiStrCpyS (LinkSpeedBuf, sizeof (LinkSpeedBuf) - 1, "1.25"); + break; + case 1: + AsciiStrCpyS (LinkSpeedBuf, sizeof (LinkSpeedBuf) - 1, "2.5"); + break; + case 2: + AsciiStrCpyS (LinkSpeedBuf, sizeof (LinkSpeedBuf) - 1, "5.0"); + break; + case 3: + AsciiStrCpyS (LinkSpeedBuf, sizeof (LinkSpeedBuf) - 1, "8.0"); + break; + case 4: + AsciiStrCpyS (LinkSpeedBuf, sizeof (LinkSpeedBuf) - 1, "16.0"); + break; + default: + AsciiSPrint (LinkSpeedBuf, sizeof (LinkSpeedBuf), "%u.%u", + (Speed * 25) / 10, (Speed * 25) % 10); + break; + } + DEBUG ((DEBUG_INIT, "PCIe: Link up (x%u, %a GT/s)\n", Width, LinkSpeedBuf)); +} + +STATIC +VOID +PciEnableLtssm ( + IN EFI_PHYSICAL_ADDRESS ApbBase, + IN BOOLEAN Enable + ) +{ + UINT32 Val; + + Val = (LINK_REQ_RST_GRT | LTSSM_ENABLE) << 16; + Val |= LINK_REQ_RST_GRT; + if (Enable) { + Val |= LTSSM_ENABLE; + } + + MmioWrite32 (ApbBase + PCIE_CLIENT_GENERAL_CON, Val); +} + +STATIC +BOOLEAN +PciIsLinkUp ( + IN EFI_PHYSICAL_ADDRESS ApbBase + ) +{ + STATIC UINT32 LastVal = 0xFFFFFFFF; + UINT32 Val; + + Val = MmioRead32 (ApbBase + PCIE_CLIENT_LTSSM_STATUS); + if (Val != LastVal) { + DEBUG ((DEBUG_INIT, "PCIe: PciIsLinkUp(): LTSSM_STATUS=0x%08X\n", Val)); + LastVal = Val; + } + + if ((Val & RDLH_LINK_UP) == 0) { + return FALSE; + } + if ((Val & SMLH_LINK_UP) == 0) { + return FALSE; + } + + return (Val & SMLH_LTSSM_STATE_MASK) == SMLH_LTSSM_STATE_LINK_UP; +} + +STATIC +VOID +PciSetupAtu ( + IN EFI_PHYSICAL_ADDRESS DbiBase, + IN UINT32 Index, + IN UINT32 Type, + IN UINT64 CpuBase, + IN UINT64 BusBase, + IN UINT64 Length + ) +{ + UINT32 Ctrl2Off = IATU_ENABLE; + + if (Type == IATU_TYPE_CFG0 || Type == IATU_TYPE_CFG1) { + Ctrl2Off |= IATU_CFG_SHIFT_MODE; + } + + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_LWR_BASE_ADDR_OFF, + (UINT32)CpuBase); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_UPPER_BASE_ADDR_OFF, + (UINT32)(CpuBase >> 32)); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_LIMIT_ADDR_OFF, + (UINT32)(CpuBase + Length - 1)); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_LWR_TARGET_ADDR_OFF, + (UINT32)BusBase); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_UPPER_TARGET_ADDR_OFF, + (UINT32)(BusBase >> 32)); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_REGION_CTRL_1_OFF, + Type); + MmioWrite32 (DbiBase + IATU_REGION_CTRL_OUTBOUND (Index) + IATU_REGION_CTRL_2_OFF, + Ctrl2Off); + + gBS->Stall (10000); +} + +STATIC +VOID +PciValidateCfg0 ( + IN UINT32 Segment, + IN EFI_PHYSICAL_ADDRESS Cfg0Base + ) +{ + EFI_STATUS Status; + + // + // Check if the downstream device appears mirrored (due to 64 KB iATU granularity) + // and needs to have config acesses shifted for single device ECAM mode in ACPI. + // + // Warning: + // Bus hang ups have been observed when doing CFG0 cycles to 01:01.0 (+0x8000) + // for some devices that have working filtering and aren't mirrored (e.g. VIA VL805). + // + // Checking 01:01.0 before 01:00.0 and then never again seems fine, at least for UEFI. + // In single-device ECAM mode, an OS is going to scan the entire affected bus again, so + // there's still a risk of locking up the system, but we can't do anything about it. + // + if (MmioRead32 (Cfg0Base + 0x8000) == 0xffffffff + && MmioRead32 (Cfg0Base) != 0xffffffff) { + Status = PcdSet32S (PcdPcieEcamCompliantSegmentsMask, + PcdGet32 (PcdPcieEcamCompliantSegmentsMask) | (1 << Segment)); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "PCIe: Working CFG0 TLP filtering for connected device!\n")); + } +} + +#define NUM_SEGMENTS 5 +#define NUM_MODES 5 + +STATIC struct { + UINT32 Speed; + UINT32 Width; +} LinkSpeedWidthMap[NUM_MODES][NUM_SEGMENTS] = { + /* NANBNB */ { + { 3, 2 }, + { 3, 2 }, + { 2, 1 }, + { 2, 1 }, + { 2, 1 }, + }, + /* NANBBI */ { + { 3, 1 }, + { 3, 2 }, + { 3, 1 }, + { 2, 1 }, + { 2, 1 }, + }, + /* NABINB */ { + { 3, 2 }, + { 3, 1 }, + { 2, 1 }, + { 3, 1 }, + { 2, 1 }, + }, + /* NABIBI */ { + { 3, 1 }, + { 3, 1 }, + { 3, 1 }, + { 3, 1 }, + { 2, 1 }, + }, + /* AGGREGATION */ { + { 3, 4 }, + { 0, 0 }, + { 2, 1 }, + { 2, 1 }, + { 2, 1 }, + }, +}; + +EFI_STATUS +InitializePciHost ( + UINT32 Segment + ) +{ + EFI_PHYSICAL_ADDRESS ApbBase = PCIE_APB_BASE (Segment); + EFI_PHYSICAL_ADDRESS DbiBase = PCIE_DBI_BASE (Segment); + EFI_PHYSICAL_ADDRESS PcieBase = PCIE_CFG_BASE (Segment); + UINTN Retry; + UINT32 LinkSpeed; + UINT32 LinkWidth; + UINT64 Cfg0Base; + UINT64 Cfg0Size; + UINT64 Cfg1Base; + UINT64 Cfg1Size; + UINT64 PciIoBase; + UINT64 PciIoSize; + UINT8 Pcie30PhyMode; + + Pcie30PhyMode = PcdGet8 (PcdPcie30PhyMode); + if (Pcie30PhyMode >= NUM_MODES) { + /* If one modified this to some strange value, this will make all things about to work */ + DEBUG ((DEBUG_WARN, "PCIe: Invalid PCIe 3.0 PHY mode %u, use NANBNB(x2x2)\n", Pcie30PhyMode)); + Pcie30PhyMode = PCIE30_PHY_MODE_NANBNB; + } + if (Segment >= NUM_SEGMENTS) { + DEBUG ((DEBUG_WARN, "PCIe: Invalid segment %u\n", Segment)); + return EFI_INVALID_PARAMETER; + } + + LinkSpeed = LinkSpeedWidthMap[Pcie30PhyMode][Segment].Speed; + LinkWidth = LinkSpeedWidthMap[Pcie30PhyMode][Segment].Width; + if (LinkSpeed == 0 || LinkWidth == 0) { + /* should never here */ + DEBUG ((DEBUG_WARN, "PCIe: Segment %u not enabled\n", Segment)); + return EFI_UNSUPPORTED; + } + + /* Log settings */ + DEBUG ((DEBUG_INIT, "\nPCIe: Segment %u\n", Segment)); + DEBUG ((DEBUG_INIT, "PCIe: PciExpressBaseAddress 0x%lx\n", PcieBase)); + DEBUG ((DEBUG_INIT, "PCIe: ApbBase 0x%lx\n", ApbBase)); + DEBUG ((DEBUG_INIT, "PCIe: DbiBase 0x%lx\n", DbiBase)); + DEBUG ((DEBUG_INIT, "PCIe: NumLanes %u\n", LinkWidth)); + DEBUG ((DEBUG_INIT, "PCIe: LinkSpeed %u\n", LinkSpeed)); + + PcieIoInit(Segment); + PciePowerEn(Segment, TRUE); + gBS->Stall (100000); + + if (Segment == PCIE_SEGMENT_PCIE30X4 || Segment == PCIE_SEGMENT_PCIE30X2) { + /* Configure PCIe 3.0 PHY */ + Pcie30PhyInit (); + } + + /* Combo PHY for PCIe 2.0 is configured earlier by RK3588Dxe */ + + DEBUG ((DEBUG_INIT, "PCIe: Setup clocks\n")); + PciSetupClocks (Segment); + + DEBUG ((DEBUG_INIT, "PCIe: Switching to RC mode\n")); + PciSetRcMode (Segment, ApbBase); + + /* Allow writing RO registers through the DBI */ + DEBUG ((DEBUG_INIT, "PCIe: Enabling DBI access\n")); + MmioOr32 (DbiBase + PL_MISC_CONTROL_1_OFF, DBI_RO_WR_EN); + + DEBUG ((DEBUG_INIT, "PCIe: Setup BARs\n")); + PciSetupBars (DbiBase); + + DEBUG ((DEBUG_INIT, "PCIe: Setup iATU\n")); + Cfg0Base = SIZE_1MB; + Cfg0Size = SIZE_64KB; + Cfg1Base = SIZE_2MB; + Cfg1Size = 0x10000000UL - (SIZE_2MB + SIZE_64KB); + PciIoBase = 0x2FFF0000UL; + PciIoSize = SIZE_64KB; + + PciSetupAtu (DbiBase, 0, IATU_TYPE_CFG0, PcieBase + Cfg0Base, Cfg0Base, Cfg0Size); + PciSetupAtu (DbiBase, 1, IATU_TYPE_CFG1, PcieBase + Cfg1Base, Cfg1Base, Cfg1Size); + PciSetupAtu (DbiBase, 2, IATU_TYPE_IO, PcieBase + PciIoBase, 0, PciIoSize); + + DEBUG ((DEBUG_INIT, "PCIe: Set link speed\n")); + PciSetupLinkSpeed (DbiBase, LinkSpeed, LinkWidth); + PciDirectSpeedChange (DbiBase); + + /* Disallow writing RO registers through the DBI */ + MmioAnd32 (DbiBase + PL_MISC_CONTROL_1_OFF, ~DBI_RO_WR_EN); + + DEBUG ((DEBUG_INIT, "PCIe: Assert reset\n")); + PciePeReset(Segment, TRUE); + + DEBUG ((DEBUG_INIT, "PCIe: Start LTSSM\n")); + + PciEnableLtssm (ApbBase, TRUE); + + gBS->Stall (100000); + DEBUG ((DEBUG_INIT, "PCIe: Deassert reset\n")); + PciePeReset(Segment, FALSE); + + /* Wait for link up */ + DEBUG ((DEBUG_INIT, "PCIe: Waiting for link up...\n")); + for (Retry = 20; Retry != 0; Retry--) { + if (PciIsLinkUp (ApbBase)) { + break; + } + gBS->Stall (100000); + } + if (Retry == 0) { + DEBUG ((DEBUG_WARN, "PCIe: Link up timeout!\n")); + return EFI_TIMEOUT; + } + + PciGetLinkSpeedWidth (DbiBase, &LinkSpeed, &LinkWidth); + PciPrintLinkSpeedWidth (LinkSpeed, LinkWidth); + + PciValidateCfg0 (Segment, PcieBase + Cfg0Base); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.h new file mode 100755 index 0000000..0c9da37 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeInit.h @@ -0,0 +1,18 @@ +/** @file + + Copyright 2021-2023, Jared McNeill + Copyright 2023, Molly Sophia + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef PCIHOSTBRIDGEINIT_H__ +#define PCIHOSTBRIDGEINIT_H__ + +EFI_STATUS +InitializePciHost ( + UINT32 Segment + ); + +#endif /* PCIHOSTBRIDGEINIT_H__ */ \ No newline at end of file diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeLib.c new file mode 100755 index 0000000..fa0cba5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/PciHostBridgeLib.c @@ -0,0 +1,295 @@ +/** @file + PCI Host Bridge Library instance for Rockchip Rk3588 + + Copyright (c) 2023, Molly Sophia + Copyright (c) 2021, Jared McNeill + Copyright (c) 2016, Linaro Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "PciHostBridgeInit.h" + + +#pragma pack(1) +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; +#pragma pack () + +STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[] = { + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)sizeof (ACPI_HID_DEVICE_PATH), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCIe + PCIE_SEGMENT_PCIE30X4 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)sizeof (ACPI_HID_DEVICE_PATH), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCIe + PCIE_SEGMENT_PCIE30X2 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)sizeof (ACPI_HID_DEVICE_PATH), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCIe + PCIE_SEGMENT_PCIE20L0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)sizeof (ACPI_HID_DEVICE_PATH), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCIe + PCIE_SEGMENT_PCIE20L1 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, + { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8)sizeof (ACPI_HID_DEVICE_PATH), + (UINT8)(sizeof (ACPI_HID_DEVICE_PATH) >> 8) + } + }, + EISA_PNP_ID (0x0A08), // PCIe + PCIE_SEGMENT_PCIE20L2 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } + }, +}; + +GLOBAL_REMOVE_IF_UNREFERENCED +CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = { + L"Mem", L"I/O", L"Bus" +}; + +PCI_ROOT_BRIDGE mPciRootBridges[NUM_PCIE_CONTROLLER]; + +/** + Return all the root bridge instances in an array. + + @param Count Return the count of root bridge instances. + + @return All the root bridge instances in an array. + The array should be passed into PciHostBridgeFreeRootBridges() + when it's not used. +**/ +PCI_ROOT_BRIDGE * +EFIAPI +PciHostBridgeGetRootBridges ( + UINTN *Count + ) +{ + EFI_STATUS Status; + UINTN Idx; + UINTN Loop; + + for(Idx = 0, Loop = 0; Idx < NUM_PCIE_CONTROLLER; Idx++) { + if(IsPcieNumEnabled(Idx) == FALSE) + continue; + + Status = InitializePciHost(Idx); + if (EFI_ERROR (Status)) + continue; + + mPciRootBridges[Loop].Segment = Idx; + mPciRootBridges[Loop].Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | + EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO | + EFI_PCI_ATTRIBUTE_ISA_IO_16 | + EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | \ + EFI_PCI_ATTRIBUTE_VGA_MEMORY | \ + EFI_PCI_ATTRIBUTE_VGA_IO_16 | \ + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; + mPciRootBridges[Loop].Attributes = mPciRootBridges[Loop].Supports; + mPciRootBridges[Loop].DmaAbove4G = TRUE; + mPciRootBridges[Loop].NoExtendedConfigSpace = FALSE; + mPciRootBridges[Loop].ResourceAssigned = FALSE; + mPciRootBridges[Loop].AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | + EFI_PCI_HOST_BRIDGE_MEM64_DECODE; + + mPciRootBridges[Loop].Bus.Base = 0; + mPciRootBridges[Loop].Bus.Limit = PCIE_BUS_LIMIT; + + mPciRootBridges[Loop].Io.Base = PCIE_IO_BASE; + mPciRootBridges[Loop].Io.Limit = mPciRootBridges[Loop].Io.Base + PCIE_IO_SIZE - 1; + mPciRootBridges[Loop].Io.Translation = MAX_UINT64 - PCIE_IO_XLATE(Idx) + 1; + + mPciRootBridges[Loop].Mem.Base = PCIE_MEM_BASE(Idx); + mPciRootBridges[Loop].Mem.Limit = mPciRootBridges[Loop].Mem.Base + PCIE_MEM_SIZE - 1; + + mPciRootBridges[Loop].MemAbove4G.Base = PCIE_MEM64_BASE(Idx); + mPciRootBridges[Loop].MemAbove4G.Limit = mPciRootBridges[Loop].MemAbove4G.Base + PCIE_MEM64_SIZE - 1; + + mPciRootBridges[Loop].PMem.Base = MAX_UINT64; + mPciRootBridges[Loop].PMem.Limit = 0; + mPciRootBridges[Loop].PMemAbove4G.Base = MAX_UINT64; + mPciRootBridges[Loop].PMemAbove4G.Limit = 0; + mPciRootBridges[Loop].DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&mEfiPciRootBridgeDevicePath[Idx]; + + DEBUG((DEBUG_INFO, "0x%llx 0x%llx 0x%llx\n", mPciRootBridges[Loop].Mem.Base, mPciRootBridges[Loop].MemAbove4G.Base,mPciRootBridges[Loop].Io.Translation)); + Loop++; + } + + *Count = Loop; + if(Loop == 0) return NULL; + + return mPciRootBridges; +} + +/** + Free the root bridge instances array returned from PciHostBridgeGetRootBridges(). + + @param Bridges The root bridge instances array. + @param Count The count of the array. +**/ +VOID +EFIAPI +PciHostBridgeFreeRootBridges ( + PCI_ROOT_BRIDGE *Bridges, + UINTN Count + ) +{ + // FreePool (Bridges); +} + +/** + Inform the platform that the resource conflict happens. + + @param HostBridgeHandle Handle of the Host Bridge. + @param Configuration Pointer to PCI I/O and PCI memory resource + descriptors. The Configuration contains the resources + for all the root bridges. The resource for each root + bridge is terminated with END descriptor and an + additional END is appended indicating the end of the + entire resources. The resource descriptor field + values follow the description in + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL + .SubmitResources(). +**/ +VOID +EFIAPI +PciHostBridgeResourceConflict ( + EFI_HANDLE HostBridgeHandle, + VOID *Configuration + ) +{ + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; + UINTN RootBridgeIndex; + DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n")); + + RootBridgeIndex = 0; + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { + DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); + for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) { + ASSERT (Descriptor->ResType < + (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) / + sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0]) + ) + ); + DEBUG ((DEBUG_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n", + mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType], + Descriptor->AddrLen, Descriptor->AddrRangeMax + )); + if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ((DEBUG_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n", + Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag, + ((Descriptor->SpecificFlag & + EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE + ) != 0) ? L" (Prefetchable)" : L"" + )); + } + } + // + // Skip the END descriptor for root bridge + // + ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR); + Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( + (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1 + ); + } +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/Rk3588PciHostBridgeLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/Rk3588PciHostBridgeLib.inf new file mode 100755 index 0000000..133a3ad --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/Rk3588PciHostBridgeLib.inf @@ -0,0 +1,56 @@ +## @file +# PCI Host Bridge Library instance for Rockchip RK356x +# +# Copyright (c) 2016, Linaro Ltd. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Rk3588PciHostBridgeLib + FILE_GUID = 643CA097-12B2-4B84-AF76-FF478D3D45C3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciHostBridgeLib + +# +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + PciHostBridgeLib.c + PciHostBridgeInit.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + DebugLib + DevicePathLib + MemoryAllocationLib + CruLib + GpioLib + Pcie30PhyLib + +[FixedPcd] + gRK3588TokenSpaceGuid.PcdPcie30Supported + +[Pcd] + gRK3588TokenSpaceGuid.PcdComboPhy0Mode + gRK3588TokenSpaceGuid.PcdComboPhy1Mode + gRK3588TokenSpaceGuid.PcdComboPhy2Mode + + gRK3588TokenSpaceGuid.PcdPcie30State + gRK3588TokenSpaceGuid.PcdPcie30PhyMode + + gRK3588TokenSpaceGuid.PcdPcieEcamCompliantSegmentsMask diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/PciSegmentLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/PciSegmentLib.c new file mode 100755 index 0000000..95d566a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/PciSegmentLib.c @@ -0,0 +1,1415 @@ +/** @file + PCI Segment Library for Rockchip RK356x + + Copyright (c) 2023, Molly Sophia + Copyright (c) 2021, Jared McNeill + Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.
    + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +typedef enum { + PciCfgWidthUint8 = 0, + PciCfgWidthUint16, + PciCfgWidthUint32, + PciCfgWidthMax +} PCI_CFG_WIDTH; + +/** + Assert the validity of a PCI Segment address. + A valid PCI Segment address should not contain 1's in bits 28..31 and 48..63 + + @param A The address to validate. + @param M Additional bits to assert to be zero. + +**/ +#define ASSERT_INVALID_PCI_SEGMENT_ADDRESS(A,M) \ + ASSERT (((A) & (0xffff0000f0000000ULL | (M))) == 0) + +#define GET_SEG_NUM(Address) ((Address >> 32) & 0xFFFF) +#define GET_BUS_NUM(Address) ((Address >> 20) & 0xFF) +#define GET_DEV_NUM(Address) ((Address >> 15) & 0x1F) +#define GET_FUNC_NUM(Address) ((Address >> 12) & 0x07) +#define GET_REG_NUM(Address) ((Address) & 0xFFF) + +STATIC +UINT64 +PciSegmentLibGetConfigBase ( + IN UINT64 Address + ) +{ + UINT16 Segment; + UINT8 Bus; + UINT16 Device; + + Segment = GET_SEG_NUM (Address); + Bus = GET_BUS_NUM (Address); + Device = GET_DEV_NUM (Address); + + ASSERT (Segment < NUM_PCIE_CONTROLLER); + + // DEBUG ((DEBUG_ERROR, "PciSegmentLibGetConfigBase: Address=0x%lX, Bus=%d, Segment=%d\n", + // Address, Bus, Segment)); + + // Ignore more than one device on bus 0 and 1 to hide duplicates/ghosts. + if (Device > 0 && (Bus == 0 || Bus == 1)) { + return 0xffffffff; + } + + // The root port is not part of the main config space. + if(Bus == 0) { + return PCIE_DBI_BASE (Segment); + } + + // Here starts the not-quite-compliant ECAM space. + return PCIE_CFG_BASE (Segment); +} + +/** + Internal worker function to read a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function and + Register. + @param Width The width of data to read + + @return The value read from the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibReadWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width + ) +{ + UINT64 Base; + + Base = PciSegmentLibGetConfigBase (Address); + + if(Base == 0xFFFFFFFF) + return Base; + + // DEBUG ((DEBUG_ERROR, "PciSegmentLibReadWorker: Address=0x%lX, Base=0x%lX, Width=%u\n", + // Address, Base, Width)); + + switch (Width) { + case PciCfgWidthUint8: + return MmioRead8 (Base + (UINT32)Address); + case PciCfgWidthUint16: + return MmioRead16 (Base + (UINT32)Address); + case PciCfgWidthUint32: + return MmioRead32 (Base + (UINT32)Address); + default: + ASSERT (FALSE); + } + + return 0; +} + +/** + Internal worker function to writes a PCI configuration register. + + @param Address The address that encodes the PCI Bus, Device, Function and + Register. + @param Width The width of data to write + @param Data The value to write. + + @return The value written to the PCI configuration register. + +**/ +STATIC +UINT32 +PciSegmentLibWriteWorker ( + IN UINT64 Address, + IN PCI_CFG_WIDTH Width, + IN UINT32 Data + ) +{ + UINT64 Base; + + Base = PciSegmentLibGetConfigBase (Address); + + if(Base == 0xFFFFFFFF) + return Base; + + // DEBUG ((DEBUG_ERROR, "PciSegmentLibWriteWorker: Address=0x%lX, Base=0x%lX, Width=%u\n", + // Address, Base, Width)); + + switch (Width) { + case PciCfgWidthUint8: + MmioWrite8 (Base + (UINT32)Address, Data); + break; + case PciCfgWidthUint16: + MmioWrite16 (Base + (UINT32)Address, Data); + break; + case PciCfgWidthUint32: + MmioWrite32 (Base + (UINT32)Address, Data); + break; + default: + ASSERT (FALSE); + } + + return Data; +} + +/** + Register a PCI device so PCI configuration registers may be accessed after + SetVirtualAddressMap(). + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Bus, Device, Function and + Register. + + @retval RETURN_SUCCESS The PCI device was registered for runtime access. + @retval RETURN_UNSUPPORTED An attempt was made to call this function + after ExitBootServices(). + @retval RETURN_UNSUPPORTED The resources required to access the PCI device + at runtime could not be mapped. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + complete the registration. + +**/ +RETURN_STATUS +EFIAPI +PciSegmentRegisterForRuntimeAccess ( + IN UINTN Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + return RETURN_UNSUPPORTED; +} + +/** + Reads an 8-bit PCI configuration register. + + Reads and returns the 8-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, + and Register. + + @return The 8-bit PCI configuration register specified by Address. + +**/ +UINT8 +EFIAPI +PciSegmentRead8 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8) PciSegmentLibReadWorker (Address, PciCfgWidthUint8); +} + +/** + Writes an 8-bit PCI configuration register. + + Writes the 8-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentWrite8 ( + IN UINT64 Address, + IN UINT8 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 0); + + return (UINT8) PciSegmentLibWriteWorker (Address, PciCfgWidthUint8, Value); +} + +/** + Performs a bitwise OR of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentOr8 ( + IN UINT64 Address, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) | OrData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAnd8 ( + IN UINT64 Address, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) (PciSegmentRead8 (Address) & AndData)); +} + +/** + Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit value, + followed a bitwise OR with another 8-bit value. + + Reads the 8-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 8-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentAndThenOr8 ( + IN UINT64 Address, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 (Address, (UINT8) ((PciSegmentRead8 (Address) & AndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in an 8-bit PCI configuration register. The bit field is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..7. + + @return The value of the bit field read from the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldRead8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead8 (PciSegmentRead8 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of the + 8-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..7. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldWrite8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 Value + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldWrite8 (PciSegmentRead8 (Address), StartBit, EndBit, Value) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and + writes the result back to the bit field in the 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, performs a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 8-bit PCI configuration register + specified by Address. The value written to the PCI configuration register is + returned. This function must guarantee that all PCI read and write operations + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..7. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldOr8 (PciSegmentRead8 (Address), StartBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in an 8-bit PCI configuration register, performs a bitwise + AND, and writes the result back to the bit field in the 8-bit register. + + Reads the 8-bit PCI configuration register specified by Address, performs a + bitwise AND between the read result and the value specified by AndData, and + writes the result to the 8-bit PCI configuration register specified by + Address. The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are + serialized. Extra left bits in AndData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAnd8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAnd8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in an 8-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 8-bit port. + + Reads the 8-bit PCI configuration register specified by Address, performs a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 8-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that all PCI + read and write operations are serialized. Extra left bits in both AndData and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..7. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..7. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT8 +EFIAPI +PciSegmentBitFieldAndThenOr8 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT8 AndData, + IN UINT8 OrData + ) +{ + return PciSegmentWrite8 ( + Address, + BitFieldAndThenOr8 (PciSegmentRead8 (Address), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 16-bit PCI configuration register. + + Reads and returns the 16-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + + @return The 16-bit PCI configuration register specified by Address. + +**/ +UINT16 +EFIAPI +PciSegmentRead16 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16) PciSegmentLibReadWorker (Address, PciCfgWidthUint16); +} + +/** + Writes a 16-bit PCI configuration register. + + Writes the 16-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT16 +EFIAPI +PciSegmentWrite16 ( + IN UINT64 Address, + IN UINT16 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 1); + + return (UINT16) PciSegmentLibWriteWorker (Address, PciCfgWidthUint16, Value); +} + +/** + Performs a bitwise OR of a 16-bit PCI configuration register with + a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, performs a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 16-bit PCI configuration register + specified by Address. The value written to the PCI configuration register is + returned. This function must guarantee that all PCI read and write operations + are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function and + Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentOr16 ( + IN UINT64 Address, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) | OrData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + and writes the result to the 16-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAnd16 ( + IN UINT64 Address, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) (PciSegmentRead16 (Address) & AndData)); +} + +/** + Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit value, + followed a bitwise OR with another 16-bit value. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 16-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentAndThenOr16 ( + IN UINT64 Address, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 (Address, (UINT16) ((PciSegmentRead16 (Address) & AndData) | OrData)); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 16-bit PCI configuration register. The bit field is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..15. + + @return The value of the bit field read from the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldRead16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead16 (PciSegmentRead16 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of the + 16-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..15. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldWrite16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 Value + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldWrite16 (PciSegmentRead16 (Address), StartBit, EndBit, Value) + ); +} + +/** + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 16-bit PCI configuration register specified by Address. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..15. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldOr16 (PciSegmentRead16 (Address), StartBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, + and writes the result back to the bit field in the 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 16-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 16-bit boundary, then ASSERT(). + If StartBit is greater than 7, then ASSERT(). + If EndBit is greater than 7, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param StartBit The ordinal of the least significant bit in the bit field. + The ordinal of the least significant bit in a byte is bit 0. + @param EndBit The ordinal of the most significant bit in the bit field. + The ordinal of the most significant bit in a byte is bit 7. + @param AndData The value to AND with the read value from the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAnd16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAnd16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 16-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 16-bit port. + + Reads the 16-bit PCI configuration register specified by Address, performs a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 16-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that all PCI + read and write operations are serialized. Extra left bits in both AndData and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 15, then ASSERT(). + If EndBit is greater than 15, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..15. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..15. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT16 +EFIAPI +PciSegmentBitFieldAndThenOr16 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT16 AndData, + IN UINT16 OrData + ) +{ + return PciSegmentWrite16 ( + Address, + BitFieldAndThenOr16 (PciSegmentRead16 (Address), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a 32-bit PCI configuration register. + + Reads and returns the 32-bit PCI configuration register specified by Address. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, + and Register. + + @return The 32-bit PCI configuration register specified by Address. + +**/ +UINT32 +EFIAPI +PciSegmentRead32 ( + IN UINT64 Address + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibReadWorker (Address, PciCfgWidthUint32); +} + +/** + Writes a 32-bit PCI configuration register. + + Writes the 32-bit PCI configuration register specified by Address with the value specified by Value. + Value is returned. This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, + Function, and Register. + @param Value The value to write. + + @return The parameter of Value. + +**/ +UINT32 +EFIAPI +PciSegmentWrite32 ( + IN UINT64 Address, + IN UINT32 Value + ) +{ + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (Address, 3); + + return PciSegmentLibWriteWorker (Address, PciCfgWidthUint32, Value); +} + +/** + Performs a bitwise OR of a 32-bit PCI configuration register with a 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise OR between the read result and the value specified by OrData, + and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, and Register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentOr32 ( + IN UINT64 Address, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) | OrData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAnd32 ( + IN UINT64 Address, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 (Address, PciSegmentRead32 (Address) & AndData); +} + +/** + Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit value, + followed a bitwise OR with another 32-bit value. + + Reads the 32-bit PCI configuration register specified by Address, + performs a bitwise AND between the read result and the value specified by AndData, + performs a bitwise OR between the result of the AND operation and the value specified by OrData, + and writes the result to the 32-bit PCI configuration register specified by Address. + The value written to the PCI configuration register is returned. + This function must guarantee that all PCI read and write operations are serialized. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + + @param Address The address that encodes the PCI Segment, Bus, Device, Function, + and Register. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the PCI configuration register. + + @return The value written to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentAndThenOr32 ( + IN UINT64 Address, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 (Address, (PciSegmentRead32 (Address) & AndData) | OrData); +} + +/** + Reads a bit field of a PCI configuration register. + + Reads the bit field in a 32-bit PCI configuration register. The bit field is + specified by the StartBit and the EndBit. The value of the bit field is + returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + + @param Address The PCI configuration register to read. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..31. + + @return The value of the bit field read from the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldRead32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit + ) +{ + return BitFieldRead32 (PciSegmentRead32 (Address), StartBit, EndBit); +} + +/** + Writes a bit field to a PCI configuration register. + + Writes Value to the bit field of the PCI configuration register. The bit + field is specified by the StartBit and the EndBit. All other bits in the + destination PCI configuration register are preserved. The new value of the + 32-bit register is returned. + + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..31. + @param Value The new value of the bit field. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldWrite32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 Value + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldWrite32 (PciSegmentRead32 (Address), StartBit, EndBit, Value) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and + writes the result back to the bit field in the 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, performs a + bitwise OR between the read result and the value specified by + OrData, and writes the result to the 32-bit PCI configuration register + specified by Address. The value written to the PCI configuration register is + returned. This function must guarantee that all PCI read and write operations + are serialized. Extra left bits in OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..31. + @param OrData The value to OR with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldOr32 (PciSegmentRead32 (Address), StartBit, EndBit, OrData) + ); +} + +/** + Reads a bit field in a 32-bit PCI configuration register, performs a bitwise + AND, and writes the result back to the bit field in the 32-bit register. + + + Reads the 32-bit PCI configuration register specified by Address, performs a bitwise + AND between the read result and the value specified by AndData, and writes the result + to the 32-bit PCI configuration register specified by Address. The value written to + the PCI configuration register is returned. This function must guarantee that all PCI + read and write operations are serialized. Extra left bits in AndData are stripped. + If any reserved bits in Address are set, then ASSERT(). + If Address is not aligned on a 32-bit boundary, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAnd32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAnd32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData) + ); +} + +/** + Reads a bit field in a 32-bit port, performs a bitwise AND followed by a + bitwise OR, and writes the result back to the bit field in the + 32-bit port. + + Reads the 32-bit PCI configuration register specified by Address, performs a + bitwise AND followed by a bitwise OR between the read result and + the value specified by AndData, and writes the result to the 32-bit PCI + configuration register specified by Address. The value written to the PCI + configuration register is returned. This function must guarantee that all PCI + read and write operations are serialized. Extra left bits in both AndData and + OrData are stripped. + + If any reserved bits in Address are set, then ASSERT(). + If StartBit is greater than 31, then ASSERT(). + If EndBit is greater than 31, then ASSERT(). + If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + + @param Address The PCI configuration register to write. + @param StartBit The ordinal of the least significant bit in the bit field. + Range 0..31. + @param EndBit The ordinal of the most significant bit in the bit field. + Range 0..31. + @param AndData The value to AND with the PCI configuration register. + @param OrData The value to OR with the result of the AND operation. + + @return The value written back to the PCI configuration register. + +**/ +UINT32 +EFIAPI +PciSegmentBitFieldAndThenOr32 ( + IN UINT64 Address, + IN UINTN StartBit, + IN UINTN EndBit, + IN UINT32 AndData, + IN UINT32 OrData + ) +{ + return PciSegmentWrite32 ( + Address, + BitFieldAndThenOr32 (PciSegmentRead32 (Address), StartBit, EndBit, AndData, OrData) + ); +} + +/** + Reads a range of PCI configuration registers into a caller supplied buffer. + + Reads the range of PCI configuration registers specified by StartAddress and + Size into the buffer specified by Buffer. This function only allows the PCI + configuration registers from a single PCI function to be read. Size is + returned. When possible 32-bit PCI configuration read cycles are used to read + from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit + and 16-bit PCI configuration read cycles may be used at the beginning and the + end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer receiving the data read. + + @return Size + +**/ +UINTN +EFIAPI +PciSegmentReadBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + OUT VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return Size; + } + + ASSERT (Buffer != NULL); + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Read a byte if StartAddress is byte aligned + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*)Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Read a word if StartAddress is word aligned + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Read as many double words as possible + // + WriteUnaligned32 (Buffer, PciSegmentRead32 (StartAddress)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*)Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Read the last remaining word if exist + // + WriteUnaligned16 (Buffer, PciSegmentRead16 (StartAddress)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Read the last remaining byte if exist + // + *(volatile UINT8 *)Buffer = PciSegmentRead8 (StartAddress); + } + + return ReturnValue; +} + + +/** + Copies the data in a caller supplied buffer to a specified range of PCI + configuration space. + + Writes the range of PCI configuration registers specified by StartAddress and + Size from the buffer specified by Buffer. This function only allows the PCI + configuration registers from a single PCI function to be written. Size is + returned. When possible 32-bit PCI configuration write cycles are used to + write from StartAdress to StartAddress + Size. Due to alignment restrictions, + 8-bit and 16-bit PCI configuration write cycles may be used at the beginning + and the end of the range. + + If any reserved bits in StartAddress are set, then ASSERT(). + If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). + If Size > 0 and Buffer is NULL, then ASSERT(). + + @param StartAddress The starting address that encodes the PCI Segment, Bus, + Device, Function and Register. + @param Size The size in bytes of the transfer. + @param Buffer The pointer to a buffer containing the data to write. + + @return The parameter of Size. + +**/ +UINTN +EFIAPI +PciSegmentWriteBuffer ( + IN UINT64 StartAddress, + IN UINTN Size, + IN VOID *Buffer + ) +{ + UINTN ReturnValue; + + ASSERT_INVALID_PCI_SEGMENT_ADDRESS (StartAddress, 0); + ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); + + if (Size == 0) { + return 0; + } + + ASSERT (Buffer != NULL); + + // + // Save Size for return + // + ReturnValue = Size; + + if ((StartAddress & BIT0) != 0) { + // + // Write a byte if StartAddress is byte aligned + // + PciSegmentWrite8 (StartAddress, *(UINT8*)Buffer); + StartAddress += sizeof (UINT8); + Size -= sizeof (UINT8); + Buffer = (UINT8*)Buffer + 1; + } + + if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { + // + // Write a word if StartAddress is word aligned + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + while (Size >= sizeof (UINT32)) { + // + // Write as many double words as possible + // + PciSegmentWrite32 (StartAddress, ReadUnaligned32 (Buffer)); + StartAddress += sizeof (UINT32); + Size -= sizeof (UINT32); + Buffer = (UINT32*)Buffer + 1; + } + + if (Size >= sizeof (UINT16)) { + // + // Write the last remaining word if exist + // + PciSegmentWrite16 (StartAddress, ReadUnaligned16 (Buffer)); + StartAddress += sizeof (UINT16); + Size -= sizeof (UINT16); + Buffer = (UINT16*)Buffer + 1; + } + + if (Size >= sizeof (UINT8)) { + // + // Write the last remaining byte if exist + // + PciSegmentWrite8 (StartAddress, *(UINT8*)Buffer); + } + + return ReturnValue; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.inf new file mode 100755 index 0000000..5e748c0 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.inf @@ -0,0 +1,41 @@ +## @file +# Instance of PCI Segment Library based on PCI Library. +# +# PCI Segment Library that layers on top of the PCI Library +# +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
    +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Rk3588PciSegmentLib + MODULE_UNI_FILE = Rk3588PciSegmentLib.uni + FILE_GUID = 5EDF4444-F65F-4CE8-9CC6-25CBFD488FAD + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PciSegmentLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PciSegmentLib.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + BaseLib + PciLib + DebugLib + +[FixedPcd] diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.uni b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.uni new file mode 100755 index 0000000..dae73de --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.uni @@ -0,0 +1,16 @@ +// /** @file +// Instance of PCI Segment Library based on PCI Library. +// +// PCI Segment Library that layers on top of the PCI Library which only +// supports segment 0 PCI configuration access. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
    +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Instance of PCI Segment Library based on PCI Library." + +#string STR_MODULE_DESCRIPTION #language en-US "PCI Segment Library that layers on top of the PCI Library." diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.c new file mode 100644 index 0000000..c0f68f8 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.c @@ -0,0 +1,66 @@ +/** @file + * + * RkSdmmcDxe platform helper library. + * + * Copyright (c) 2023, Mario Bălănică + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCMI_CCLK_SD 9 + +EFI_STATUS +EFIAPI +RkSdmmcSetClockRate ( + IN UINTN Frequency + ) +{ + EFI_STATUS Status; + SCMI_CLOCK_PROTOCOL *ClockProtocol; + EFI_GUID ClockProtocolGuid = ARM_SCMI_CLOCK_PROTOCOL_GUID; + + Status = gBS->LocateProtocol (&ClockProtocolGuid, + NULL, + (VOID **) &ClockProtocol); + ASSERT (!EFI_ERROR (Status)); + + Status = ClockProtocol->RateSet (ClockProtocol, SCMI_CCLK_SD, Frequency); + ASSERT (!EFI_ERROR (Status)); + + return Status; +} + +VOID +EFIAPI +RkSdmmcSetIoMux ( + VOID + ) +{ +#define SYS_GRF_SOC_CON6 (0xFD58C000 + 0x0318) + + // Clear force_jtag (SD slot is muxed with JTAG) + MmioWrite32(SYS_GRF_SOC_CON6, 0x40000000); + + GpioPinSetDirection (0, GPIO_PIN_PA4, GPIO_PIN_INPUT); + SdmmcIoMux (); +} + +RKSDMMC_CARD_PRESENCE_STATE +EFIAPI +RkSdmmcGetCardPresenceState ( + VOID + ) +{ + return GpioPinReadActual (0, GPIO_PIN_PA4) ? RkSdmmcCardNotPresent + : RkSdmmcCardPresent; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf new file mode 100644 index 0000000..89eb1eb --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf @@ -0,0 +1,33 @@ +#/** @file +# +# RkSdmmcDxe platform helper library. +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = RkSdmmcPlatformLib + FILE_GUID = b9039d6e-6d84-4f32-bfc5-9c328ed3e660 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RkSdmmcPlatformLib + +[Sources] + RkSdmmcPlatformLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + Silicon/Rockchip/RockchipPkg.dec + Silicon/Rockchip/RK3588/RK3588.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + GpioLib + IoLib + RockchipPlatformLib diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon/RK3588CruLib.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon/RK3588CruLib.c new file mode 100644 index 0000000..e4c708b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/Library/RockchipPlatformLibCommon/RK3588CruLib.c @@ -0,0 +1,480 @@ +/** @file + * + * Copyright (c) 2024, Mario Bălănică + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "Include/Library/CruLib.h" +#include +/** @addtogroup RK_HAL_Driver + * @{ + */ + +/** @addtogroup CRU + * @{ + */ + +/** @defgroup CRU_Private_Definition Private Definition + * @{ + */ +/********************* Private MACRO Definition ******************************/ +/********************* Private Structure Definition **************************/ + +static struct PLL_CONFIG PLL_TABLE[] = { + /* _mhz, _refDiv, _fbDiv, _postdDv1, _postDiv2, _dsmpd, _frac */ + RK3588_PLL_RATE(1680000000, 2, 280, 1, 0), + RK3588_PLL_RATE(1512000000, 2, 252, 1, 0), + RK3588_PLL_RATE(1416000000, 2, 236, 1, 0), + RK3588_PLL_RATE(1188000000, 2, 198, 1, 0), + RK3588_PLL_RATE(1008000000, 2, 336, 2, 0), + RK3588_PLL_RATE(1000000000, 3, 500, 2, 0), + RK3588_PLL_RATE(983040000, 4, 655, 2, 23592), + RK3588_PLL_RATE(816000000, 2, 272, 2, 0), + RK3588_PLL_RATE(786432000, 2, 262, 2, 9437), + RK3588_PLL_RATE(100000000, 3, 400, 5, 0), + { /* sentinel */ }, +}; + +static struct PLL_SETUP LPLL = { + .conOffset0 = &(DSUCRU->LPLL_CON[0]), + .conOffset1 = &(DSUCRU->LPLL_CON[1]), + .conOffset2 = &(DSUCRU->LPLL_CON[2]), + .conOffset3 = &(DSUCRU->LPLL_CON[3]), + .conOffset6 = &(DSUCRU->LPLL_CON[6]), + .modeOffset = &(DSUCRU->MODE_CON00), + .modeShift = 0, + .lockShift = 15, + .modeMask = 0x3, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP B0PLL = { + .conOffset0 = &(BIGCORE0CRU->B0PLL_CON[0]), + .conOffset1 = &(BIGCORE0CRU->B0PLL_CON[1]), + .conOffset2 = &(BIGCORE0CRU->B0PLL_CON[2]), + .conOffset3 = &(BIGCORE0CRU->B0PLL_CON[3]), + .conOffset6 = &(BIGCORE0CRU->B0PLL_CON[6]), + .modeOffset = &(BIGCORE0CRU->MODE_CON00), + .modeShift = 0, + .lockShift = 15, + .modeMask = 0x3, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP B1PLL = { + .conOffset0 = &(BIGCORE1CRU->B1PLL_CON[0]), + .conOffset1 = &(BIGCORE1CRU->B1PLL_CON[1]), + .conOffset2 = &(BIGCORE1CRU->B1PLL_CON[2]), + .conOffset3 = &(BIGCORE1CRU->B1PLL_CON[3]), + .conOffset6 = &(BIGCORE1CRU->B1PLL_CON[6]), + .modeOffset = &(BIGCORE1CRU->MODE_CON00), + .modeShift = 0, + .lockShift = 15, + .modeMask = 0x3, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP CPLL = { + .conOffset0 = &(CRU->CPLL_CON[0]), + .conOffset1 = &(CRU->CPLL_CON[1]), + .conOffset2 = &(CRU->CPLL_CON[2]), + .conOffset3 = &(CRU->CPLL_CON[3]), + .conOffset6 = &(CRU->CPLL_CON[6]), + .modeOffset = &(CRU->MODE_CON00), + .modeShift = 8, + .lockShift = 15, + .modeMask = 0x3 << 8, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP GPLL = { + .conOffset0 = &(CRU->GPLL_CON[0]), + .conOffset1 = &(CRU->GPLL_CON[1]), + .conOffset2 = &(CRU->GPLL_CON[2]), + .conOffset3 = &(CRU->GPLL_CON[3]), + .conOffset6 = &(CRU->GPLL_CON[6]), + .modeOffset = &(CRU->MODE_CON00), + .modeShift = 2, + .lockShift = 15, + .modeMask = 0x3 << 2, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP NPLL = { + .conOffset0 = &(CRU->NPLL_CON[0]), + .conOffset1 = &(CRU->NPLL_CON[1]), + .conOffset2 = &(CRU->NPLL_CON[2]), + .conOffset3 = &(CRU->NPLL_CON[3]), + .conOffset6 = &(CRU->NPLL_CON[6]), + .modeOffset = &(CRU->MODE_CON00), + .modeShift = 0, + .lockShift = 15, + .modeMask = 0x3 << 0, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP V0PLL = { + .conOffset0 = &(CRU->V0PLL_CON[0]), + .conOffset1 = &(CRU->V0PLL_CON[1]), + .conOffset2 = &(CRU->V0PLL_CON[2]), + .conOffset3 = &(CRU->V0PLL_CON[3]), + .conOffset6 = &(CRU->V0PLL_CON[6]), + .modeOffset = &(CRU->MODE_CON00), + .modeShift = 4, + .lockShift = 15, + .modeMask = 0x3 << 4, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP AUPLL = { + .conOffset0 = &(CRU->AUPLL_CON[0]), + .conOffset1 = &(CRU->AUPLL_CON[1]), + .conOffset2 = &(CRU->AUPLL_CON[2]), + .conOffset3 = &(CRU->AUPLL_CON[3]), + .conOffset6 = &(CRU->AUPLL_CON[6]), + .modeOffset = &(CRU->MODE_CON00), + .modeShift = 6, + .lockShift = 15, + .modeMask = 0x3 << 6, + .rateTable = PLL_TABLE, +}; + +static struct PLL_SETUP PPLL = { + .conOffset0 = &(PHPTOPCRU->PPLL_CON[0]), + .conOffset1 = &(PHPTOPCRU->PPLL_CON[1]), + .conOffset2 = &(PHPTOPCRU->PPLL_CON[2]), + .conOffset3 = &(PHPTOPCRU->PPLL_CON[3]), + .conOffset6 = &(PHPTOPCRU->PPLL_CON[6]), + .lockShift = 15, + .rateTable = PLL_TABLE, +}; + +static CRU_CLOCK Clocks[CLK_COUNT] = { + CRU_CLOCK_INIT (CCLK_EMMC, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CCLK_EMMC_SEL, + CRU_CLKSEL_CON_OFFSET, CCLK_EMMC_DIV, + CRU_CLKGATE_CON_OFFSET, CCLK_EMMC_GATE), + CRU_CLOCK_INIT (SCLK_SFC, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, SCLK_SFC_SEL, + CRU_CLKSEL_CON_OFFSET, SCLK_SFC_DIV, + CRU_CLKGATE_CON_OFFSET, SCLK_SFC_GATE), + CRU_CLOCK_INIT (CCLK_SRC_SDIO, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CCLK_SRC_SDIO_SEL, + CRU_CLKSEL_CON_OFFSET, CCLK_SRC_SDIO_DIV, + CRU_CLKGATE_CON_OFFSET, CCLK_SRC_SDIO_GATE), + CRU_CLOCK_INIT (BCLK_EMMC, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, BCLK_EMMC_SEL, + CRU_CLKSEL_CON_OFFSET, BCLK_EMMC_DIV, + CRU_CLKGATE_CON_OFFSET, BCLK_EMMC_GATE), + CRU_CLOCK_INIT (CLK_REF_PIPE_PHY0, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY0_SEL, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY0_PLL_SRC_DIV, + CRU_CLKGATE_CON_OFFSET, CLK_REF_PIPE_PHY0_PLL_SRC_GATE), + CRU_CLOCK_INIT (CLK_REF_PIPE_PHY1, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY1_SEL, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY1_PLL_SRC_DIV, + CRU_CLKGATE_CON_OFFSET, CLK_REF_PIPE_PHY1_PLL_SRC_GATE), + CRU_CLOCK_INIT (CLK_REF_PIPE_PHY2, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY2_SEL, + CRU_CLKSEL_CON_OFFSET, CLK_REF_PIPE_PHY2_PLL_SRC_DIV, + CRU_CLKGATE_CON_OFFSET, CLK_REF_PIPE_PHY2_PLL_SRC_GATE), + CRU_CLOCK_INIT (DCLK_VOP2_SRC, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, DCLK_VOP2_SRC_SEL, + CRU_CLKSEL_CON_OFFSET, DCLK_VOP2_SRC_DIV, + CRU_CLKGATE_CON_OFFSET, DCLK_VOP2_SRC_GATE), + CRU_CLOCK_INIT (CLK_I2S0_8CH_TX_SRC, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, CLK_I2S0_8CH_TX_SRC_SEL, + CRU_CLKSEL_CON_OFFSET, CLK_I2S0_8CH_TX_SRC_DIV, + CRU_CLKGATE_CON_OFFSET, CLK_I2S0_8CH_TX_GATE), + CRU_CLOCK_NODIV_INIT (MCLK_I2S0_8CH_TX, CRU_BASE, + CRU_CLKSEL_CON_OFFSET, MCLK_I2S0_8CH_TX_SEL, + CRU_CLKGATE_CON_OFFSET, MCLK_I2S0_8CH_TX_GATE), + CRU_CLOCK_NODIV_INIT (MCLK_I2S1_8CH_TX, PMU1CRU_BASE, + CRU_CLKSEL_CON_OFFSET, MCLK_I2S1_8CH_TX_SEL, + CRU_CLKGATE_CON_OFFSET, MCLK_I2S1_8CH_TX_GATE), +}; + +static CRU_RESET Resets[RESET_COUNT] = { + // TO-DO +}; + +/********************* Private Variable Definition ***************************/ + +static uint32_t s_lpllFreq; +static uint32_t s_cpllFreq = 1500 * 1000 * 1000; +static uint32_t s_gpllFreq = 1188 * 1000 * 1000; +static uint32_t s_npllFreq; +static uint32_t s_v0pllFreq; +static uint32_t s_ppllFreq; +static uint32_t s_aupllFreq; + +/********************* Private Function Definition ***************************/ + +/** @} */ +/********************* Public Function Definition ****************************/ + +CRU_CLOCK * +EFIAPI +HAL_CRU_ClkGetById(uint32_t clockId) +{ + ASSERT (clockId < CLK_COUNT); + if (clockId >= CLK_COUNT) { + return NULL; + } + return &Clocks[clockId]; +} + +CRU_RESET * +EFIAPI +HAL_CRU_RstGetById(uint32_t resetId) +{ + ASSERT (resetId < RESET_COUNT); + if (resetId >= RESET_COUNT) { + return NULL; + } + return &Resets[resetId]; +} + +/** + * @brief Get clk freq. + * @param clockId: CLOCK_Name id. + * @return rate. + * @attention these APIs allow direct use in the HAL layer. + */ +uint32_t +EFIAPI +HAL_CRU_ClkGetFreq(uint32_t clockId) +{ + uint32_t pRate = 0, freq; + + if (!s_cpllFreq) { + s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL); + } + + if (!s_v0pllFreq) { + s_v0pllFreq = HAL_CRU_GetPllV1Freq(&V0PLL); + } + + switch (clockId) { + case PLL_LPLL: + freq = HAL_CRU_GetPllV1Freq(&LPLL); + s_lpllFreq = freq; + + return freq; + case PLL_B0PLL: + freq = HAL_CRU_GetPllV1Freq(&B0PLL); + + return freq; + case PLL_B1PLL: + freq = HAL_CRU_GetPllV1Freq(&B1PLL); + + return freq; + case PLL_CPLL: + freq = HAL_CRU_GetPllV1Freq(&CPLL); + s_cpllFreq = freq; + + return freq; + case PLL_NPLL: + freq = HAL_CRU_GetPllV1Freq(&NPLL); + s_npllFreq = freq; + + return freq; + case PLL_V0PLL: + freq = HAL_CRU_GetPllV1Freq(&V0PLL); + s_v0pllFreq = freq; + + return freq; + case PLL_AUPLL: + freq = HAL_CRU_GetPllV1Freq(&AUPLL); + s_aupllFreq = freq; + + return freq; + case PLL_PPLL: + freq = HAL_CRU_GetPllV1Freq(&PPLL); + s_ppllFreq = freq; + + return freq; + case PLL_GPLL: + freq = HAL_CRU_GetPllV1Freq(&GPLL); + s_gpllFreq = freq; + + return s_gpllFreq; + case CCLK_EMMC: + case SCLK_SFC: + case CCLK_SRC_SDIO: + if (HAL_CRU_ClkGetMux(clockId) == 0) { + pRate = s_gpllFreq; + } else if (HAL_CRU_ClkGetMux(clockId) == 1) { + pRate = s_cpllFreq; + } else if (HAL_CRU_ClkGetMux(clockId) == 2) { + pRate = PLL_INPUT_OSC_RATE; + } + + return pRate / HAL_CRU_ClkGetDiv(clockId) ; + case BCLK_EMMC: + if (HAL_CRU_ClkGetMux(clockId) == 0) { + pRate = s_gpllFreq; + } else if (HAL_CRU_ClkGetMux(clockId) == 1) { + pRate = s_cpllFreq; + } + + return pRate / HAL_CRU_ClkGetDiv(clockId) ; + case CLK_REF_PIPE_PHY0: + case CLK_REF_PIPE_PHY1: + case CLK_REF_PIPE_PHY2: + if (HAL_CRU_ClkGetMux(clockId) == 0) { + return PLL_INPUT_OSC_RATE; + } else if (HAL_CRU_ClkGetMux(clockId) == 1) { + return s_ppllFreq / HAL_CRU_ClkGetDiv(clockId) ; + } + + case DCLK_VOP2_SRC: + ASSERT (HAL_CRU_ClkGetMux(clockId) == 2); + pRate = s_v0pllFreq; + break; + default: + break; + } + + freq = pRate / HAL_CRU_ClkGetDiv(clockId); + + return freq; +} + +#define RK3588_VOP_PLL_LIMIT_FREQ 600000000 + +/** + * @brief Set clk freq. + * @param clockId: CLOCK_Name id. + * @param rate: clk rate. + * @return HAL_Status. + * @attention these APIs allow direct use in the HAL layer. + */ +HAL_Status +EFIAPI +HAL_CRU_ClkSetFreq(uint32_t clockId, uint32_t rate) +{ + HAL_Status error = HAL_OK; + uint32_t mux = 0, div = 0, pRate = 0; + + if (!s_cpllFreq) { + s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL); + } + + if (!s_v0pllFreq) { + s_v0pllFreq = HAL_CRU_GetPllV1Freq(&V0PLL); + } + + switch (clockId) { + case PLL_LPLL: + error = HAL_CRU_SetPllV1Freq(&LPLL, rate); + s_lpllFreq = HAL_CRU_GetPllV1Freq(&LPLL); + + return error; + case PLL_B0PLL: + error = HAL_CRU_SetPllV1Freq(&B0PLL, rate); + + return error; + case PLL_B1PLL: + error = HAL_CRU_SetPllV1Freq(&B1PLL, rate); + + return error; + case PLL_CPLL: + error = HAL_CRU_SetPllV1Freq(&CPLL, rate); + s_cpllFreq = HAL_CRU_GetPllV1Freq(&CPLL); + + return error; + case PLL_PPLL: + error = HAL_CRU_SetPllV1Freq(&PPLL, rate); + s_ppllFreq = HAL_CRU_GetPllV1Freq(&PPLL); + + return error; + case PLL_GPLL: + error = HAL_CRU_SetPllV1Freq(&GPLL, rate); + DEBUG ((DEBUG_INIT, "GPLL set rate: %d %x\n", rate, error)); + s_gpllFreq = HAL_CRU_GetPllV1Freq(&GPLL); + return error; + case PLL_NPLL: + error = HAL_CRU_SetPllV1Freq(&NPLL, rate); + s_npllFreq = HAL_CRU_GetPllV1Freq(&NPLL); + + return error; + case PLL_AUPLL: + error = HAL_CRU_SetPllV1Freq(&AUPLL, rate); + s_aupllFreq = HAL_CRU_GetPllV1Freq(&AUPLL); + + return error; + case PLL_V0PLL: + error = HAL_CRU_SetPllV1Freq(&V0PLL, rate); + s_v0pllFreq = HAL_CRU_GetPllV1Freq(&V0PLL); + + return error; + + case CCLK_EMMC: + case SCLK_SFC: + case CCLK_SRC_SDIO: + if (PLL_INPUT_OSC_RATE % rate == 0) { + pRate = PLL_INPUT_OSC_RATE; + mux = 2; + } else if (s_cpllFreq % rate == 0){ + pRate = s_cpllFreq; + mux = 1; + } else { + pRate = s_gpllFreq; + mux = 0; + } + break; + case BCLK_EMMC: + if (s_cpllFreq % rate == 0){ + pRate = s_cpllFreq; + mux = 1; + } else { + pRate = s_gpllFreq; + mux = 0; + } + break; + + case CLK_REF_PIPE_PHY0: + case CLK_REF_PIPE_PHY1: + case CLK_REF_PIPE_PHY2: + if (rate == PLL_INPUT_OSC_RATE) { + HAL_CRU_ClkSetMux(clockId, 0); + HAL_CRU_ClkSetDiv(clockId, 0); + } else { + div = HAL_DIV_ROUND_UP(s_ppllFreq, rate); + HAL_CRU_ClkSetDiv(clockId, div); + HAL_CRU_ClkSetMux(clockId, 1); + } + return HAL_OK; + + case DCLK_VOP2_SRC: + HAL_CRU_ClkSetMux(clockId, 2); + + if (s_v0pllFreq >= RK3588_VOP_PLL_LIMIT_FREQ && s_v0pllFreq % rate == 0) { + div = HAL_DIV_ROUND_UP(s_v0pllFreq, rate); + HAL_CRU_ClkSetDiv(clockId, div); + } else { + div = HAL_DIV_ROUND_UP(RK3588_VOP_PLL_LIMIT_FREQ, rate); + HAL_CRU_ClkSetDiv(clockId, div); + error = HAL_CRU_ClkSetFreq(PLL_V0PLL, div * rate); + } + return error; + default: + break; + } + + div = HAL_DIV_ROUND_UP(pRate, rate); + + HAL_CRU_ClkSetMux(clockId, mux); + HAL_CRU_ClkSetDiv(clockId, div); + + return HAL_OK; +} +/** @} */ + +/** @} */ + +/** @} */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.dec b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.dec new file mode 100644 index 0000000..2c2c56b --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.dec @@ -0,0 +1,98 @@ +## @file +# +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010019 + PACKAGE_NAME = RK3588 + PACKAGE_GUID = 26e6ce4a-45e7-11ec-9726-f42a7dcb925d + PACKAGE_VERSION = 0.1 + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ +[Includes.common] + Include # Root include for the package + +[Guids.common] + gRK3588TokenSpaceGuid = { 0x32594b40, 0x45e7, 0x11ec, { 0xbb, 0xc1, 0xf4, 0x2a, 0x7d, 0xcb, 0x92, 0x5d } } + gRK3588DxeFormSetGuid = { 0x10f41c33, 0xa468, 0x42cd, { 0x85, 0xee, 0x70, 0x43, 0x21, 0x3f, 0x73, 0xa3 } } + +[PcdsFixedAtBuild] + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|0|UINT32|0x00010001 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|0|UINT32|0x00010002 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|0|UINT32|0x00010003 + + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE|BOOLEAN|0x00010101 + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE|BOOLEAN|0x00010102 + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE|BOOLEAN|0x00010103 + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|0|UINT32|0x00010104 + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|0|UINT32|0x00010105 + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|0|UINT32|0x00010106 + + gRK3588TokenSpaceGuid.PcdPcie30Supported|FALSE|BOOLEAN|0x00010201 + gRK3588TokenSpaceGuid.PcdPcie30PhyModeDefault|4|UINT8|0x00010202 + + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatModeDefault|0|UINT32|0x00010301 + + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|FALSE|BOOLEAN|0x10401 + + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Supported|FALSE|BOOLEAN|0x00010501 + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Supported|FALSE|BOOLEAN|0x00010502 + gRK3588TokenSpaceGuid.PcdDp0LaneMux|{ 0x0 }|VOID*|0x00010503 + gRK3588TokenSpaceGuid.PcdDp1LaneMux|{ 0x0 }|VOID*|0x00010504 + + gRK3588TokenSpaceGuid.PcdGmac0Supported|FALSE|BOOLEAN|0x00010601 + gRK3588TokenSpaceGuid.PcdGmac1Supported|FALSE|BOOLEAN|0x00010602 + gRK3588TokenSpaceGuid.PcdGmac0TxDelay|0|UINT8|0x00010603 + gRK3588TokenSpaceGuid.PcdGmac0RxDelay|0|UINT8|0x00010604 + gRK3588TokenSpaceGuid.PcdGmac1TxDelay|0|UINT8|0x00010605 + gRK3588TokenSpaceGuid.PcdGmac1RxDelay|0|UINT8|0x00010606 + + gRK3588TokenSpaceGuid.PcdI2S0Supported|FALSE|BOOLEAN|0x00010701 + gRK3588TokenSpaceGuid.PcdI2S1Supported|FALSE|BOOLEAN|0x00010702 + +[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] + gRK3588TokenSpaceGuid.PcdCPULClusterClockPreset|0|UINT32|0x00000001 + gRK3588TokenSpaceGuid.PcdCPULClusterClockCustom|0|UINT32|0x00000002 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPreset|0|UINT32|0x00000003 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockCustom|0|UINT32|0x00000004 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPreset|0|UINT32|0x00000005 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockCustom|0|UINT32|0x00000006 + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageMode|0|UINT32|0x00000007 + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageCustom|0|UINT32|0x00000008 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageMode|0|UINT32|0x00000009 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageCustom|0|UINT32|0x0000000A + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageMode|0|UINT32|0x0000000B + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageCustom|0|UINT32|0x0000000C + + gRK3588TokenSpaceGuid.PcdComboPhy0Mode|0|UINT32|0x00000101 + gRK3588TokenSpaceGuid.PcdComboPhy1Mode|0|UINT32|0x00000102 + gRK3588TokenSpaceGuid.PcdComboPhy2Mode|0|UINT32|0x00000103 + + gRK3588TokenSpaceGuid.PcdPcie30State|0|UINT32|0x00000201 + gRK3588TokenSpaceGuid.PcdPcie30PhyMode|0|UINT8|0x00000202 + + gRK3588TokenSpaceGuid.PcdConfigTableMode|0|UINT32|0x00000300 + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatMode|0|UINT32|0x00000301 + gRK3588TokenSpaceGuid.PcdFdtSupportOverrides|0|UINT8|0x00000351 + + gRK3588TokenSpaceGuid.PcdCoolingFanState|0|UINT32|0x00000401 + gRK3588TokenSpaceGuid.PcdCoolingFanSpeed|0|UINT32|0x00000402 + + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Usb3State|0|UINT32|0x00000501 + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Usb3State|0|UINT32|0x00000502 + +[PcdsDynamicEx] + gRK3588TokenSpaceGuid.PcdPcieEcamCompliantSegmentsMask|0|UINT32|0x20000001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf new file mode 100644 index 0000000..5452655 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588.fdf @@ -0,0 +1,178 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# FD Section +# The [FD] Section is made up of the definition statements and a +# description of what goes into the Flash Device Image. Each FD section +# defines one flash "device" image. A flash device image may be one of +# the following: Removable media bootable image (like a boot floppy +# image,) an Option ROM image (that would be "flashed" into an add-in +# card,) a System "Flash" image (that would be burned into a system's +# flash) or an Update ("Capsule") image that will be used to update and +# existing system flash. +# +################################################################################ + +[FD.NOR_FLASH_IMAGE] +BaseAddress = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in NOR Flash. +Size = 0x00800000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device +ErasePolarity = 1 + +# This one is tricky, it must be: BlockSize * NumBlocks = Size +BlockSize = 0x00001000 +NumBlocks = 0x800 + +################################################################################ +# +# Following are lists of FD Region layout which correspond to the locations of different +# images within the flash device. +# +# Regions must be defined in ascending order and may not overlap. +# +# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by +# the pipe "|" character, followed by the size of the region, also in hex with the leading +# "0x" characters. Like: +# Offset|Size +# PcdOffsetCName|PcdSizeCName +# RegionType +# +################################################################################ +0x00200000|0x00500000 +gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize +FV = BL33_AP_UEFI + +# NV_VARIABLE_STORE +0x007C0000|0x00010000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + +# NV_FTW_WORKING header +0x007D0000|0x00010000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + +# NV_FTW_WORKING data +0x007E0000|0x00010000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +################################################################################ +# +# FV Section +# +# [FV] section is used to define what components or modules are placed within a flash +# device file. This section also defines order the components and modules are positioned +# within the image. The [FV] section consists of define statements, set statements and +# module statements. +# +################################################################################ + +[FV.FvMain] +BlockSize = 0x40 +NumBlocks = 0 # This FV gets compressed so make it just big enough +FvAlignment = 8 # FV alignment and FV attributes setting. +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE + + # + # Prioritized components, ignoring dependency expressions + # + APRIORI DXE { +!include Silicon/Rockchip/FvMainAprioriDxe.fdf.inc + } + + # + # Common components + # +!include Silicon/Rockchip/FvMainModules.fdf.inc + + # + # General platform manager + # + INF Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf + + # + # PCI Support + # +!if $(RK3588_PCIE_ENABLE) == TRUE + INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf + INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf + INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf + INF MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf + INF EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf +!endif + + # + # USB/DP PHY Driver + # + INF Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf + + # + # GMAC Init Driver + # + INF Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf + + # + # ACPI Support + # + INF Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf + + # + # Device Tree Support + # + INF Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf + + # + # Custom platform components + # +!include $(RK_PLATFORM_FVMAIN_MODULES) + +[FV.BL33_AP_UEFI] +FvAlignment = 8 +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE + + # + # Common PEI components + # +!include Silicon/Rockchip/FvCompactModules.fdf.inc + + FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { + SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE { + SECTION FV_IMAGE = FVMAIN + } + } + +!include Silicon/Rockchip/FvRules.fdf.inc diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc new file mode 100644 index 0000000..985206a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Base.dsc.inc @@ -0,0 +1,374 @@ +## @file +# +# Copyright (c) 2014-2018, Linaro Limited. All rights reserved. +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + DEFINE CONFIG_NO_DEBUGLIB = FALSE + + # + # Shared Defines + # - must be kept in sync with their associated headers + # - values must be hexadecimal if used in byte array PCDs + # + + # + # Silicon/Rockchip/RK3588/Include/VarStoreData.h + # + DEFINE CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT = 0 + DEFINE CPU_PERF_CLUSTER_CLOCK_PRESET_MIN = 1 + DEFINE CPU_PERF_CLUSTER_CLOCK_PRESET_MAX = 2 + DEFINE CPU_PERF_CLUSTER_CLOCK_PRESET_CUSTOM = 3 + + DEFINE COMBO_PHY_MODE_UNCONNECTED = 0 + DEFINE COMBO_PHY_MODE_PCIE = 1 + DEFINE COMBO_PHY_MODE_SATA = 2 + DEFINE COMBO_PHY_MODE_USB3 = 3 + + DEFINE COOLING_FAN_STATE_DISABLED = 0 + DEFINE COOLING_FAN_STATE_ENABLED = 1 + + DEFINE USBDP_PHY_USB3_STATE_DISABLED = 0 + DEFINE USBDP_PHY_USB3_STATE_ENABLED = 1 + + DEFINE CONFIG_TABLE_MODE_ACPI = 0x00000001 + DEFINE CONFIG_TABLE_MODE_FDT = 0x00000002 + DEFINE CONFIG_TABLE_MODE_ACPI_FDT = 0x00000003 + + DEFINE ACPI_PCIE_ECAM_COMPAT_MODE_SINGLE_DEV = 0x00000001 + DEFINE ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6 = 0x00000002 + DEFINE ACPI_PCIE_ECAM_COMPAT_MODE_GRAVITON = 0x00000004 + DEFINE ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV = 0x00000003 + DEFINE ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_GRAVITON = 0x00000006 + + # + # Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/CpuPerformance.h + # + DEFINE SCMI_CLK_CPUL = 0x0 + DEFINE SCMI_CLK_CPUB01 = 0x2 + DEFINE SCMI_CLK_CPUB23 = 0x3 + + # + # Default peripheral support flags + # +!ifndef RK_STATUS_LED_ENABLE + DEFINE RK_STATUS_LED_ENABLE = TRUE +!endif +!ifndef RK_NOR_FLASH_ENABLE + DEFINE RK_NOR_FLASH_ENABLE = TRUE +!endif +!ifndef RK_860X_REGULATOR_ENABLE + DEFINE RK_860X_REGULATOR_ENABLE = TRUE +!endif +!ifndef RK_SD_ENABLE + DEFINE RK_SD_ENABLE = TRUE +!endif +!ifndef RK_EMMC_ENABLE + DEFINE RK_EMMC_ENABLE = TRUE +!endif +!ifndef RK_AHCI_ENABLE + DEFINE RK_AHCI_ENABLE = TRUE +!endif +!ifndef RK_DW_HDMI_QP_ENABLE + DEFINE RK_DW_HDMI_QP_ENABLE = TRUE +!endif + + # + # RK3588-specific flags + # +!ifndef RK3588_PCIE_ENABLE + DEFINE RK3588_PCIE_ENABLE = TRUE +!endif + + # + # Base platform description + # +!include Silicon/Rockchip/Rockchip.dsc.inc + +################################################################################ +# +# Library Class section - list of all common Library Classes needed by RK3588 platforms. +# +################################################################################ + +[LibraryClasses.common] + # ACPI helpers + AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf + + # Debug UART library + SerialPortLib|Silicon/Rockchip/Library/Dw8250SerialPortLib/DebugDw8250SerialPortLib.inf + + # SoC and memory descriptors + ArmPlatformLib|Silicon/Rockchip/RK3588/Library/PlatformLib/PlatformLib.inf + + # PCI Support +!if $(RK3588_PCIE_ENABLE) == TRUE + PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf + PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf + PciSegmentLib|Silicon/Rockchip/RK3588/Library/Rk3588PciSegmentLib/Rk3588PciSegmentLib.inf + PciHostBridgeLib|Silicon/Rockchip/RK3588/Library/Rk3588PciHostBridgeLib/Rk3588PciHostBridgeLib.inf + Pcie30PhyLib|Silicon/Rockchip/RK3588/Library/Pcie30PhyLib/Pcie30PhyLib.inf +!endif + + # RkSdmmcDxe dependencies + RkSdmmcPlatformLib|Silicon/Rockchip/RK3588/Library/RkSdmmcPlatformLib/RkSdmmcPlatformLib.inf + + # DwcSdhciDxe dependencies + DwcSdhciPlatformLib|Silicon/Rockchip/RK3588/Library/DwcSdhciPlatformLib/DwcSdhciPlatformLib.inf + + # Other SoC-specific libraries + OtpLib|Silicon/Rockchip/RK3588/Library/OtpLib/OtpLib.inf + GpioLib|Silicon/Rockchip/RK3588/Library/GpioLib/GpioLib.inf + +[LibraryClasses.common.SEC] + MemoryInitPeiLib|Silicon/Rockchip/RK3588/Library/MemoryInitPeiLib/MemoryInitPeiLib.inf + +################################################################################################### +# BuildOptions Section - Define the module specific tool chain flags that should be used as +# the default flags for a module. These flags are appended to any +# standard flags that are defined by the build process. +################################################################################################### + +[BuildOptions] + GCC:*_*_*_PLATFORM_FLAGS = -I$(WORKSPACE)/Silicon/Rockchip/RK3588/Include -I$(WORKSPACE)/Silicon/Rockchip/Include + +################################################################################ +# +# Pcd Section - list of all common EDK II PCD Entries used by RK3588 platforms. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # System Memory (1GB) + gArmTokenSpaceGuid.PcdSystemMemoryBase|0x00000000 + gArmTokenSpaceGuid.PcdSystemMemorySize|0x40000000 + + # RK3588 CPU profile + gArmPlatformTokenSpaceGuid.PcdCoreCount|8 + gArmPlatformTokenSpaceGuid.PcdClusterCount|1 + + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdProcessorName|"Rockchip RK3588 variant" + gRockchipTokenSpaceGuid.PcdPlatformName|"Generic RK3588 platform" + gRockchipTokenSpaceGuid.PcdMemoryVendorName|"TBD" + + # I2C + gRockchipTokenSpaceGuid.PcdI2cClockFrequency|198000000 + gRockchipTokenSpaceGuid.PcdI2cBaudRate|100000 + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMinVoltages|{ UINT32(550000), UINT32(550000) } + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMaxVoltages|{ UINT32(1050000), UINT32(1050000) } + + # UART2 - Serial Terminal + DEFINE SERIAL_BASE = 0xFEB50000 # UART2 + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|$(SERIAL_BASE) + gHisiTokenSpaceGuid.PcdSerialPortSendDelay|500000 + gHisiTokenSpaceGuid.PcdUartClkInHz|24000000 + + # SPI - SPI2 for test + gRockchipTokenSpaceGuid.SpiRK806BaseAddr|0xFEB20000 + + # NOR FLASH + gRockchipTokenSpaceGuid.FspiBaseAddr|0xFE2B0000 + + # CRU + gRockchipTokenSpaceGuid.CruBaseAddr|0xFD7C0000 + + # + # ARM General Interrupt Controller + # + gArmTokenSpaceGuid.PcdGicDistributorBase|0xfe600000 + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0xfe600000 + gArmTokenSpaceGuid.PcdGicRedistributorsBase|0xfe680000 + + # GUID of the UI app + gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 } + + gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE + + gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod|1000 + + # + # DesignWare SD Controller (MSHC) + # + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress|0xfe2c0000 + + # + # DesignWare SD/eMMC Controller (SDHCI) + # + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress|0xfe2e0000 + + # + # USB2 EHCI + OHCI companion controllers + # + gRockchipTokenSpaceGuid.PcdEhciBaseAddress|0xfc800000 + gRockchipTokenSpaceGuid.PcdNumEhciController|2 + gRockchipTokenSpaceGuid.PcdEhciSize|0x40000 + gRockchipTokenSpaceGuid.PcdOhciSize|0x40000 + + # + # DWC3 controller + # + gRockchipTokenSpaceGuid.PcdDwc3Size|0x400000 + + # + # Display + # + gRockchipTokenSpaceGuid.PcdLcdPixelFormat|0x00000001 + gRockchipTokenSpaceGuid.PcdEdpId|0x00000000 #edp0 + #gRockchipTokenSpaceGuid.PcdEdpId|0x00000001 #edp1 + gRockchipTokenSpaceGuid.PcdHdmiId|0x00000000 #hdmi0 + #gRockchipTokenSpaceGuid.PcdHdmiId|0x00000001 #hdmi1 + gRockchipTokenSpaceGuid.PcdHdmiDDCI2CPinMux|0x00000000 #hdmitx_i2c_m0 + + # + # CPU Performance default values + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault|$(CPU_PERF_CLUSTER_CLOCK_PRESET_BOOTDEFAULT) + + # + # Cooling Fan definitions + # + gRK3588TokenSpaceGuid.PcdHasOnBoardFanOutput|FALSE + + # + # PCIe/SATA/USB Combo PIPE PHY support flags and default values + # + gRK3588TokenSpaceGuid.PcdComboPhy0Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy1Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy2Switchable|FALSE + gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault|$(COMBO_PHY_MODE_UNCONNECTED) + gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault|$(COMBO_PHY_MODE_UNCONNECTED) + gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault|$(COMBO_PHY_MODE_UNCONNECTED) + + # + # PCI Express 3.0 support flags and default values + # + gRK3588TokenSpaceGuid.PcdPcie30Supported|FALSE + gRK3588TokenSpaceGuid.PcdPcie30PhyModeDefault|4 # AGGREGATION + + # + # ACPI support flags and default values + # + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatModeDefault|$(ACPI_PCIE_ECAM_COMPAT_MODE_NXPMX6_SINGLE_DEV) + +[PcdsPatchableInModule] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|1500000 + +[PcdsDynamicDefault.common] + # + # Display + # + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|0 + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|0 + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow|0 + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn|0 + +[PcdsDynamicHii.common.DEFAULT] + # + # CPU Performance + # + gRK3588TokenSpaceGuid.PcdCPULClusterClockPreset|L"CpuPerf_CPULClusterClockPreset"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdCPULClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPULClusterClockCustom|L"CpuPerf_CPULClusterClockCustom"|gRK3588DxeFormSetGuid|0x0|1800 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPreset|L"CpuPerf_CPUB01ClusterClockPreset"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPUB01ClusterClockCustom|L"CpuPerf_CPUB01ClusterClockCustom"|gRK3588DxeFormSetGuid|0x0|2400 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPreset|L"CpuPerf_CPUB23ClusterClockPreset"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockPresetDefault + gRK3588TokenSpaceGuid.PcdCPUB23ClusterClockCustom|L"CpuPerf_CPUB23ClusterClockCustom"|gRK3588DxeFormSetGuid|0x0|2400 + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageMode|L"CpuPerf_CPULClusterVoltageMode"|gRK3588DxeFormSetGuid|0x0|0 + gRK3588TokenSpaceGuid.PcdCPULClusterVoltageCustom|L"CpuPerf_CPULClusterVoltageCustom"|gRK3588DxeFormSetGuid|0x0|950000 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageMode|L"CpuPerf_CPUB01ClusterVoltageMode"|gRK3588DxeFormSetGuid|0x0|0 + gRK3588TokenSpaceGuid.PcdCPUB01ClusterVoltageCustom|L"CpuPerf_CPUB01ClusterVoltageCustom"|gRK3588DxeFormSetGuid|0x0|1000000 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageMode|L"CpuPerf_CPUB23ClusterVoltageMode"|gRK3588DxeFormSetGuid|0x0|0 + gRK3588TokenSpaceGuid.PcdCPUB23ClusterVoltageCustom|L"CpuPerf_CPUB23ClusterVoltageCustom"|gRK3588DxeFormSetGuid|0x0|1000000 + + # + # PCIe/SATA/USB Combo PIPE PHY + # + gRK3588TokenSpaceGuid.PcdComboPhy0Mode|L"ComboPhy0Mode"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdComboPhy0ModeDefault + gRK3588TokenSpaceGuid.PcdComboPhy1Mode|L"ComboPhy1Mode"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdComboPhy1ModeDefault + gRK3588TokenSpaceGuid.PcdComboPhy2Mode|L"ComboPhy2Mode"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdComboPhy2ModeDefault + + # + # PCI Express 3.0 + # + gRK3588TokenSpaceGuid.PcdPcie30State|L"Pcie30State"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdPcie30Supported + gRK3588TokenSpaceGuid.PcdPcie30PhyMode|L"Pcie30PhyMode"|gRK3588DxeFormSetGuid|0x0|4 # AGGREGATION + + # + # ACPI / Device Tree + # + gRK3588TokenSpaceGuid.PcdConfigTableMode|L"ConfigTableMode"|gRK3588DxeFormSetGuid|0x0|$(CONFIG_TABLE_MODE_ACPI) + gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatMode|L"AcpiPcieEcamCompatMode"|gRK3588DxeFormSetGuid|0x0|gRK3588TokenSpaceGuid.PcdAcpiPcieEcamCompatModeDefault + gRK3588TokenSpaceGuid.PcdFdtSupportOverrides|L"FdtSupportOverrides"|gRK3588DxeFormSetGuid|0x0|FALSE + + # + # Cooling Fan + # + gRK3588TokenSpaceGuid.PcdCoolingFanState|L"CoolingFanState"|gRK3588DxeFormSetGuid|0x0|1 + gRK3588TokenSpaceGuid.PcdCoolingFanSpeed|L"CoolingFanSpeed"|gRK3588DxeFormSetGuid|0x0|50 + + # + # USB/DP PHY + # + gRK3588TokenSpaceGuid.PcdUsbDpPhy0Usb3State|L"UsbDpPhy0Usb3State"|gRK3588DxeFormSetGuid|0x0|$(USBDP_PHY_USB3_STATE_ENABLED) + gRK3588TokenSpaceGuid.PcdUsbDpPhy1Usb3State|L"UsbDpPhy1Usb3State"|gRK3588DxeFormSetGuid|0x0|$(USBDP_PHY_USB3_STATE_ENABLED) + +################################################################################ +# +# Components Section - list of all common EDK II Modules needed by RK3588 platforms. +# +################################################################################ +[Components.common] + # + # PEI Phase modules + # + ArmPlatformPkg/PrePi/PeiUniCore.inf { + + # Full UART library + SerialPortLib|Silicon/Rockchip/Library/Dw8250SerialPortLib/Dw8250SerialPortLib.inf + } + + # General platform manager + Silicon/Rockchip/RK3588/Drivers/RK3588Dxe/RK3588Dxe.inf + + # + # PCI Support + # +!if $(RK3588_PCIE_ENABLE) == TRUE + ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf + MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf + MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf + EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf + MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf +!endif + + # + # USB/DP PHY Driver + # + Silicon/Rockchip/RK3588/Drivers/UsbDpPhyDxe/UsbDpPhyDxe.inf + + # + # GMAC Init Driver + # + Silicon/Rockchip/RK3588/Drivers/GmacPlatformDxe/GmacPlatformDxe.inf + + # + # ACPI Support + # + Silicon/Rockchip/RK3588/Drivers/AcpiPlatformDxe/AcpiPlatformDxe.inf + + # + # Device Tree Support + # + Silicon/Rockchip/RK3588/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc new file mode 100644 index 0000000..41872f5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588Platform.dsc.inc @@ -0,0 +1,29 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +!include Silicon/Rockchip/RK3588/RK3588Base.dsc.inc + +################################################################################ +# +# Pcd Section - list of all common EDK II PCD Entries used by RK3588 platforms. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdProcessorName|"Rockchip RK3588" + + # + # DWC3 controller + # + gRockchipTokenSpaceGuid.PcdDwc3BaseAddresses|{ UINT32(0xfc000000), UINT32(0xfc400000), UINT32(0xfcd00000) } + + # + # PCI Express 3.0 support flags and default values + # + gRK3588TokenSpaceGuid.PcdPcie30Supported|TRUE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc new file mode 100644 index 0000000..3e64a03 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RK3588/RK3588SPlatform.dsc.inc @@ -0,0 +1,29 @@ +## @file +# +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +!include Silicon/Rockchip/RK3588/RK3588Base.dsc.inc + +################################################################################ +# +# Pcd Section - list of all common EDK II PCD Entries used by RK3588S platforms. +# +################################################################################ + +[PcdsFixedAtBuild.common] + # SMBIOS platform config + gRockchipTokenSpaceGuid.PcdProcessorName|"Rockchip RK3588S" + + # + # DWC3 controller + # + gRockchipTokenSpaceGuid.PcdDwc3BaseAddresses|{ UINT32(0xfc000000), UINT32(0xfcd00000) } + + # + # PCI Express 3.0 support flags and default values + # + gRK3588TokenSpaceGuid.PcdPcie30Supported|FALSE diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Rockchip.dsc.inc b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Rockchip.dsc.inc new file mode 100644 index 0000000..3c6ebaf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/Rockchip.dsc.inc @@ -0,0 +1,795 @@ +## @file +# +# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + # DEBUG_INIT 0x00000001 // Initialization + # DEBUG_WARN 0x00000002 // Warnings + # DEBUG_LOAD 0x00000004 // Load events + # DEBUG_FS 0x00000008 // EFI File system + # DEBUG_POOL 0x00000010 // Alloc & Free (pool) + # DEBUG_PAGE 0x00000020 // Alloc & Free (page) + # DEBUG_INFO 0x00000040 // Informational debug messages + # DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers + # DEBUG_VARIABLE 0x00000100 // Variable + # DEBUG_BM 0x00000400 // Boot Manager + # DEBUG_BLKIO 0x00001000 // BlkIo Driver + # DEBUG_NET 0x00004000 // SNP Driver + # DEBUG_UNDI 0x00010000 // UNDI Driver + # DEBUG_LOADFILE 0x00020000 // LoadFile + # DEBUG_EVENT 0x00080000 // Event messages + # DEBUG_GCD 0x00100000 // Global Coherency Database changes + # DEBUG_CACHE 0x00200000 // Memory range cachability changes + # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may + # // significantly impact boot performance + # DEBUG_ERROR 0x80000000 // Error + # + DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000047 + + # + # Modules that can get too noisy on the DEBUG_INFO channel + # are excluded from it in the DEBUG_PRINT_INFO_MODULE_EXCLUDE + # bitmask below. + # + DEFINE DEBUG_MODULE_DXEMAIN = 0x00000010 + DEFINE DEBUG_MODULE_USBBUSDXE = 0x00000020 + DEFINE DEBUG_MODULE_PARTITIONDXE = 0x00000040 + DEFINE DEBUG_MODULE_SNPDXE = 0x00000100 + DEFINE DEBUG_MODULE_MNPDXE = 0x00000200 + + DEFINE DEBUG_PRINT_INFO_MODULE_EXCLUDE = 0x00000370 + + DEFINE DEBUG_PRINT_ERROR_LEVEL_NO_INFO = $(DEBUG_PRINT_ERROR_LEVEL) & ~0x00000040 + + # + # DEBUG_ASSERT_ENABLED 0x01 + # DEBUG_PRINT_ENABLED 0x02 + # DEBUG_CODE_ENABLED 0x04 + # CLEAR_MEMORY_ENABLED 0x08 + # ASSERT_BREAKPOINT_ENABLED 0x10 + # ASSERT_DEADLOOP_ENABLED 0x20 + # +!if $(TARGET) == RELEASE + DEFINE DEBUG_PROPERTY_MASK = 0x00 +!else + DEFINE DEBUG_PROPERTY_MASK = 0x0f +!endif + +################################################################################ +# +# Library Class section - list of all common Library Classes needed by Rockchip platforms. +# +################################################################################ + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses.common] +!if $(TARGET) == RELEASE + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf +!else + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf +!endif + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf + + OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf + + # UiApp dependencies + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + + # BDS dependencies + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf + PlatformBootManagerLib|Silicon/Rockchip/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf + CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf + + # USB Requirements + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf + + # SCMI Mailbox Transport Layer + ArmMtlLib|Silicon/Rockchip/Library/RkMtlLib/RkMtlLib.inf + + # SMC/HVC dependencies + ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf + ArmHvcLib|ArmPkg/Library/ArmHvcLib/ArmHvcLib.inf + ArmMonitorLib|ArmPkg/Library/ArmMonitorLib/ArmMonitorLib.inf + + # + # Secure Boot dependencies + # +!if $(SECURE_BOOT_ENABLE) == TRUE + TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf + AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf + SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf + SecureBootVariableProvisionLib|SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.inf + PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf + + # re-use the UserPhysicalPresent() dummy implementation from the ovmf tree + PlatformSecureLib|OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf +!else + TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf +!endif + + # VariableRuntimeDxe Requirements + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf + + # RTC dependencies + TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf + + DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf + + # + # Allow dynamic PCDs + # + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + + # ARM Architectural Libraries + CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf + DefaultExceptionHandlerLib|ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf + CpuExceptionHandlerLib|ArmPkg/Library/ArmExceptionLib/ArmExceptionLib.inf + ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf + ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf + ArmGicArchLib|ArmPkg/Library/ArmGicArchLib/ArmGicArchLib.inf + ArmPlatformStackLib|ArmPlatformPkg/Library/ArmPlatformStackLib/ArmPlatformStackLib.inf + ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf + ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf + ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf + TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf + + # UART libraries + # SerialPortLib|Silicon/Rockchip/Library/SerialPortLib/SerialPortLib.inf # Modified + # UartLib|Silicon/Rockchip/Library/SerialPortLib/UartLib.inf + + # Runtime reset helper + ResetSystemLib|Silicon/Rockchip/Library/ResetSystemLib/ResetSystemLib.inf + + # + # Uncomment (and comment out the next line) For RealView Debugger. The Standard IO window + # in the debugger will show load and unload commands for symbols. You can cut and paste this + # into the command window to load symbols. We should be able to use a script to do this, but + # the version of RVD I have does not support scripts accessing system memory. + # + #PeCoffExtraActionLib|ArmPkg/Library/RvdPeCoffExtraActionLib/RvdPeCoffExtraActionLib.inf + #PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf + + DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf + DebugAgentTimerLib|EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf + + SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf + + # Flattened Device Tree (FDT) access library + FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf + + VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf + + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf + + NonDiscoverableDeviceRegistrationLib|MdeModulePkg/Library/NonDiscoverableDeviceRegistrationLib/NonDiscoverableDeviceRegistrationLib.inf + + # UEFI Shell dependencies + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + RngLib|MdeModulePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + ArmTrngLib|ArmPkg/Library/ArmTrngLib/ArmTrngLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf + EdkiiSystemCapsuleLib|SignedCapsulePkg/Library/EdkiiSystemCapsuleLib/EdkiiSystemCapsuleLib.inf + IniParsingLib|SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf + TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf + #PlatformFlashAccessLib|Silicon/Rockchip/Library/PlatformFlashAccessLib/PlatformFlashAccessLibDxe.inf + + ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf + + # + # It is not possible to prevent the ARM compiler for generic intrinsic functions. + # This library provides the instrinsic functions generate by a given compiler. + # And NULL mean link this library into all ARM images. + # + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # Add support for GCC stack protector + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + + # RkSdmmcDxe dependencies + RkSdmmcPlatformLib|Silicon/Rockchip/Library/RkSdmmcPlatformLibNull/RkSdmmcPlatformLibNull.inf + + # DwcSdhciDxe dependencies + DwcSdhciPlatformLib|Silicon/Rockchip/Library/DwcSdhciPlatformLibNull/DwcSdhciPlatformLibNull.inf + + # + # Rockchip libraries + # + RkAtagsLib|Silicon/Rockchip/Library/RkAtagsLib/RkAtagsLib.inf + SdramLib|Silicon/Rockchip/Library/SdramLib/SdramLib.inf + CruLib|Silicon/Rockchip/Library/CruLib/CruLib.inf + SpiLib|Silicon/Rockchip/Library/SpiLib/SpiLib.inf + RK806|Silicon/Rockchip/Library/SpiLib/RK806.inf + PWMLib|Silicon/Rockchip/Library/PWMLib/PWMLib.inf + RockchipDisplayLib|Silicon/Rockchip/Library/DisplayLib/RockchipDisplayLib.inf + + BaseVariableLib|Silicon/Rockchip/Library/BaseVariableLib/BaseVariableLib.inf + +[LibraryClasses.common.SEC] + ArmGicArchLib|ArmPkg/Library/ArmGicArchSecLib/ArmGicArchSecLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf + ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf + MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf + PlatformPeiLib|ArmPlatformPkg/PlatformPei/PlatformPeiLib.inf + PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf + +[LibraryClasses.common.PEI_CORE] + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf + PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf + OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf + + PeiServicesTablePointerLib|ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + +[LibraryClasses.common.PEIM] + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf + OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeiResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf + ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf + + PeiServicesTablePointerLib|ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + + ## Fixed compile error after upgrade to 14.10 + PlatformPeiLib|ArmPlatformPkg/PlatformPei/PlatformPeiLib.inf + PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf + ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + +[LibraryClasses.common.DXE_CORE] + HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf + MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf + DxeCoreEntryPoint|MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + PerformanceLib|MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf + +[LibraryClasses.common.DXE_DRIVER] + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + +[LibraryClasses.common.UEFI_DRIVER,LibraryClasses.common.UEFI_APPLICATION] + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + +[LibraryClasses.common.UEFI_DRIVER] + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf + +[LibraryClasses.common.DXE_RUNTIME_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf + CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf +!ifndef CONFIG_NO_DEBUGLIB + DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf +!endif +!if $(TARGET) != RELEASE + DebugLib|MdePkg/Library/DxeRuntimeDebugLibSerialPort/DxeRuntimeDebugLibSerialPort.inf +!endif + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf +FspiLib|Silicon/Rockchip/Library/FspiLib/FspiLib.inf + +!if $(SECURE_BOOT_ENABLE) == TRUE + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf +!endif + +[LibraryClasses.AARCH64] + ArmGenericTimerCounterLib|ArmPkg/Library/ArmGenericTimerPhyCounterLib/ArmGenericTimerPhyCounterLib.inf + +################################################################################################### +# BuildOptions Section - Define the module specific tool chain flags that should be used as +# the default flags for a module. These flags are appended to any +# standard flags that are defined by the build process. +################################################################################################### + +[BuildOptions] +# RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG + *_*_*_CC_FLAGS = -DDEFAULT_DARK + GCC:*_*_AARCH64_CC_FLAGS = -Wno-error=uninitialized -Wno-error=stringop-overflow -Wno-error=unused-function -Wno-error=unused-variable + +[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] + GCC:*_*_ARM_DLINK_FLAGS = -z common-page-size=0x1000 + GCC:*_*_AARCH64_DLINK_FLAGS = -z common-page-size=0x10000 + +################################################################################ +# +# Pcd Section - list of all common EDK II PCD Entries used by Rockchip platforms. +# +################################################################################ + +[PcdsFeatureFlag.common] + gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|TRUE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|TRUE + + # Use the Vector Table location in CpuDxe. We will not copy the Vector Table at PcdCpuVectorBaseAddress + gArmTokenSpaceGuid.PcdRelocateVectorTable|FALSE + + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|TRUE + + gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE + + gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE + + gArmTokenSpaceGuid.PcdArmGicV3WithV2Legacy|FALSE + + # If TRUE, Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe. + # It could be set FALSE to save size. + gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE + +[PcdsFixedAtBuild.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString|L"$(FIRMWARE_VER)" + + # + # IO is mapped to memory space, so we use the same size of + # PcdPrePiCpuMemorySize + # + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|44 + gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000 + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF + gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask|1 + gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0 + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320 + gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4 + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|$(DEBUG_PROPERTY_MASK) + + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL) + + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06 + + # + # Optional feature to help prevent EFI memory map fragments + # Turned on and off via: PcdPrePiProduceMemoryTypeInformationHob + # Values are in EFI Pages (4K). DXE Core will make sure that + # at least this much of each type of memory can be allocated + # from a single memory range. This way you only end up with + # maximum of two fragements for each type in the memory map + # (the memory used, and the free memory that was prereserved + # but not used). + # + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0 +!if $(SECURE_BOOT_ENABLE) == TRUE + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|600 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|400 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|1500 +!else + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|50 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|20 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|400 +!endif + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|20000 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|20 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0 + + # Set timer interrupt to be triggerred in 1ms to avoid missing + # serial terminal input characters. + gEmbeddedTokenSpaceGuid.PcdTimerPeriod|10000 + gArmTokenSpaceGuid.PcdVFPEnabled|1 + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultReceiveFifoDepth|32 + + # + # Variable store - default values + # + #gRockchipTokenSpaceGuid.PcdSpiMemoryBase|0xF9000000 + #gRockchipTokenSpaceGuid.PcdSpiMemoryMapped|TRUE + #gRockchipTokenSpaceGuid.PcdSpiVariableOffset|0x3C0000 + #gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00010000 + #gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x00010000 + #gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x00010000 + +!if $(SECURE_BOOT_ENABLE) == TRUE + # override the default values from SecurityPkg to ensure images from all sources are verified in secure boot + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x04 + gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x04 + gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x04 +!endif + + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800 + +[PcdsDynamicHii.common.DEFAULT] + gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEfiGlobalVariableGuid|0x0|10 # Variable: L"Timeout" + +################################################################################ +# +# Components Section - list of all common EDK II Modules needed by Rockchip platforms. +# +# Should match the components declared in FvCompactModules and FvMainModules. +# +################################################################################ +[Components.common] + # + # PEI Phase modules + # + ArmPlatformPkg/PrePi/PeiUniCore.inf + + # + # DXE + # + MdeModulePkg/Core/Dxe/DxeMain.inf { + + NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf + + +!if $(DEBUG_PRINT_INFO_MODULE_EXCLUDE) & $(DEBUG_MODULE_DXEMAIN) + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL_NO_INFO) +!endif + } + MdeModulePkg/Universal/PCD/Dxe/Pcd.inf + + # + # Architectural Protocols + # + ArmPkg/Drivers/CpuDxe/CpuDxe.inf + MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf +!if $(SECURE_BOOT_ENABLE) == TRUE + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf { + + NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf + } + SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + SecurityPkg/EnrollFromDefaultKeysApp/EnrollFromDefaultKeysApp.inf + SecurityPkg/VariableAuthenticated/SecureBootDefaultKeysDxe/SecureBootDefaultKeysDxe.inf +!else + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf +!endif + MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf + EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf { + +!if $(RK_RTC8563_ENABLE) == TRUE + RealTimeClockLib|Silicon/NXP/Library/Pcf8563RealTimeClockLib/Pcf8563RealTimeClockLib.inf +!else + RealTimeClockLib|EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf +!endif + } + EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf + MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf { + + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + } + SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf + SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf + + # + # Status LED support + # +!if $(RK_STATUS_LED_ENABLE) == TRUE + Silicon/Rockchip/Drivers/StatusLedDxe/StatusLedDxe.inf +!endif + + # + # Non-volatile FVB support + # +!if $(RK_NOR_FLASH_ENABLE) == TRUE + Silicon/Rockchip/Drivers/NorFlashDxe/NorFlashDxe.inf +!endif + Silicon/Rockchip/Drivers/RkFvbDxe/RkFvbDxe.inf + MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf + + # + # Multiple Console IO support + # + MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf + MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf + MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf + MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf + MdeModulePkg/Universal/SerialDxe/SerialDxe.inf + + # + # Arm GIC + # + ArmPkg/Drivers/ArmGic/ArmGicDxe.inf + + # + # Timer + # + ArmPkg/Drivers/TimerDxe/TimerDxe.inf + MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf + + # + # SCMI Support + # + ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf + + # + # ACPI Support + # + MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf { + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|$(DEBUG_PROPERTY_MASK) & ~0x04 + } + MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + + # + # SMBIOS Support + # + MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf + Silicon/Rockchip/Drivers/PlatformSmbiosDxe/PlatformSmbiosDxe.inf + + # + # I2C Bus & Devices + # + MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.inf + Silicon/Rockchip/Drivers/I2c/I2cDxe/I2cDxe.inf +!if $(RK_860X_REGULATOR_ENABLE) == TRUE + Silicon/Rockchip/Drivers/I2c/Rk860xRegulatorDxe/Rk860xRegulatorDxe.inf +!endif +!if $(RK_RTC8563_ENABLE) == TRUE + Silicon/Rockchip/Drivers/Rtc8563PlatformDxe/Rtc8563PlatformDxe.inf +!endif +!if $(RK_PCA9555_ENABLE) == TRUE + Silicon/Rockchip/Drivers/Pca9555Dxe/Pca9555Dxe.inf +!endif + # Silicon/Rockchip/Drivers/I2c/I2cDemoDxe/I2cDemoDxe.inf + + # + # Display Support + # + Silicon/Rockchip/Drivers/Vop2Dxe/Vop2Dxe.inf + # Silicon/Rockchip/Library/DisplayLib/AnalogixDpLib.inf +!if $(RK_DW_HDMI_QP_ENABLE) == TRUE + Silicon/Rockchip/Library/DisplayLib/DwHdmiQpLib.inf +!endif + Silicon/Rockchip/Library/DisplayLib/DwDpLib.inf + Silicon/Rockchip/Library/DisplayLib/DwMipiDsi2Lib.inf + Silicon/Rockchip/Drivers/LcdGraphicsOutputDxe/LcdGraphicsOutputDxe.inf + + # + # USB Support + # + MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf + MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + Silicon/Rockchip/Drivers/OhciDxe/OhciDxe.inf + + # USB controllers installer + Silicon/Rockchip/Drivers/UsbHcdInitDxe/UsbHcd.inf + + MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf { + +!if $(DEBUG_PRINT_INFO_MODULE_EXCLUDE) & $(DEBUG_MODULE_USBBUSDXE) + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL_NO_INFO) +!endif + } + MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf + MdeModulePkg/Bus/Usb/UsbMouseDxe/UsbMouseDxe.inf + MdeModulePkg/Bus/Usb/UsbMouseAbsolutePointerDxe/UsbMouseAbsolutePointerDxe.inf + + # + # PCI Support + # + MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf + + # + # SD/eMMC upper layer drivers + # +!if $(RK_SD_ENABLE) == TRUE || $(RK_EMMC_ENABLE) == TRUE + MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf + MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf +!endif + + # + # SD Support + # +!if $(RK_SD_ENABLE) == TRUE + Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf + Silicon/Rockchip/Drivers/RkSdmmcDxe/RkSdmmcDxe.inf +!endif + + # + # eMMC Support + # +!if $(RK_EMMC_ENABLE) == TRUE + MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf + Silicon/Rockchip/Drivers/DwcSdhciDxe/DwcSdhciDxe.inf +!endif + + # + # AHCI Support + # +!if $(RK_AHCI_ENABLE) == TRUE + MdeModulePkg/Bus/Pci/SataControllerDxe/SataControllerDxe.inf + MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf +!endif + + # + # FAT filesystem + GPT/MBR partitioning + # + MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf + MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf { + +!if $(DEBUG_PRINT_INFO_MODULE_EXCLUDE) & $(DEBUG_MODULE_PARTITIONDXE) + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL_NO_INFO) +!endif + } + FatPkg/EnhancedFatDxe/Fat.inf + MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf + + # + # RAM Disk Support + # + MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf + + # + # UEFI Network Stack + # +!include NetworkPkg/Network.dsc.inc + +!if $(NETWORK_ENABLE) == TRUE + +!if $(NETWORK_SNP_ENABLE) == TRUE + NetworkPkg/SnpDxe/SnpDxe.inf { + +!if $(DEBUG_PRINT_INFO_MODULE_EXCLUDE) & $(DEBUG_MODULE_SNPDXE) + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL_NO_INFO) +!endif + } +!endif + + NetworkPkg/MnpDxe/MnpDxe.inf { + +!if $(DEBUG_PRINT_INFO_MODULE_EXCLUDE) & $(DEBUG_MODULE_MNPDXE) + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|$(DEBUG_PRINT_ERROR_LEVEL_NO_INFO) +!endif + } + + # + # Realtek PCIe UNDI Driver + # + Drivers/Realtek/Bus/Pcie/PcieNetworking/RtkUndiDxe.inf + + # + # Realtek USB UNDI Driver + # + Drivers/Realtek/Bus/Usb/UsbNetworking/RtkUsbUndiDxe.inf + + # + # AX88772 Ethernet Driver for Apple Ethernet Adapter + # + Drivers/ASIX/Bus/Usb/UsbNetworking/Ax88772c/Ax88772c.inf +!endif + + # + # Bds + # + MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf + MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf + MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf + MdeModulePkg/Application/UiApp/UiApp.inf { + + NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf + NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf + NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf + NULL|Silicon/Rockchip/Library/PlatformBootDescriptionLib/PlatformBootDescriptionLib.inf + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + } + + # + # UEFI applications + # + ShellPkg/Application/Shell/Shell.inf { + + ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf + NULL|Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf + NULL|Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf + NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf + HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000 + } +!ifdef $(INCLUDE_TFTP_COMMAND) + ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf +!endif #$(INCLUDE_TFTP_COMMAND) + + # I2C Demo application + # Silicon/Rockchip/Applications/I2cDemoTest/I2cDemoTest.inf + + # SPI Flash Cmd application + # Silicon/Rockchip/Applications/SpiTool/SpiFlashCmd.inf diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RockchipPkg.dec b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RockchipPkg.dec new file mode 100644 index 0000000..440d6ae --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Rockchip/RockchipPkg.dec @@ -0,0 +1,96 @@ +## @file +# +# Copyright (c) 2021-2022, Rockchip Limited. All rights reserved. +# Copyright (c) 2023, Mario Bălănică +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = RockchipPkg + PACKAGE_GUID = 633b6754-2c95-11ec-b78c-f42a7dcb925d + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[Protocols] + gUniNorFlashProtocolGuid = { 0x86F305EA, 0xDFAC, 0x4A6B, { 0x92, 0x77, 0x47, 0x31, 0x2E, 0xCE, 0x42, 0xA } } + gRockchipI2cDemoProtocolGuid = { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b } } + gRk860xRegulatorProtocolGuid = { 0xb9ef9018, 0x2096, 0x4bf5, { 0x94, 0xb2, 0x70, 0x32, 0xb9, 0xa9, 0xa4, 0x29 } } + gRockchipCrtcProtocolGuid = { 0xC128406A, 0x99D9, 0x11EC, { 0x99, 0x27, 0xF4, 0x2A, 0x7D, 0xCB, 0x92, 0x5D } } + gRockchipConnectorProtocolGuid = { 0x50439CB6, 0x9B85, 0x11EC, { 0x95, 0x73, 0xF4, 0x2A, 0x7D, 0xCB, 0x92, 0x5D } } + gOhciDeviceProtocolGuid = { 0x54bce5e6, 0xbaae, 0x488a, { 0x82, 0x67, 0xc0, 0x85, 0x7f, 0xb4, 0xe8, 0x05 } } + gRockchipI2cMasterProtocolGuid = { 0x7b4af789, 0x43d2, 0x44a5, { 0xa0, 0xb3, 0x3f, 0xa5, 0xde, 0xd7, 0xa1, 0x27 } } + gRockchipPlatformConfigAppliedProtocolGuid = { 0xdf0e9b10, 0xcbd6, 0x496f, { 0x83, 0xd6, 0xef, 0xbb, 0x96, 0x9c, 0xe5, 0x3d } } + gDpPhyProtocolGuid = { 0xb4bcf881, 0xc8b3, 0x46d7, { 0xaf, 0xbe, 0x5a, 0x2d, 0x94, 0x9d, 0x93, 0xc3 } } + gPca95xxProtocolGuid = { 0x7e91391b, 0xa23c, 0x4a51, { 0x9d, 0xf7, 0xf6, 0x74, 0xef, 0x1d, 0x51, 0x1b } } + gRockchipDsiPanelProtocolGuid = { 0x07a5d05c, 0x3216, 0x49fc, { 0xb4, 0x22, 0x28, 0x9d, 0x38, 0xd5, 0xdf, 0x7e } } + +[Guids] + gRockchipTokenSpaceGuid = { 0xc620b83a, 0x3175, 0x11ec, { 0x95, 0xb4, 0xf4, 0x2a, 0x7d, 0xcb, 0x92, 0x5d } } + gShellSfHiiGuid = { 0x03a67756, 0x8cde, 0x4638, { 0x82, 0x34, 0x4a, 0x0f, 0x6d, 0x58, 0x81, 0x39 } } + gShellI2cDemoHiiGuid = { 0xb2f4c714, 0x147f, 0x4ff7, { 0x82, 0x1b, 0xce, 0x7b, 0x91, 0x7f, 0x5f, 0x2f } } + gRockchipEventResetGuid = { 0x4ecbd617, 0xc2a6, 0x4d4c, { 0x80, 0x4e, 0x53, 0x38, 0x3b, 0x98, 0x7d, 0x75 } } + gRockchipEventPlatformBmAfterConsoleGuid = { 0xf1272c11, 0xb418, 0x40ca, { 0x88, 0x26, 0x11, 0x94, 0xd7, 0xb7, 0x30, 0x4a } } + +[PcdsFixedAtBuild] + gRockchipTokenSpaceGuid.PcdProcessorName|"Unknown"|VOID*|0x00000001 + gRockchipTokenSpaceGuid.PcdPlatformName|"Unknown"|VOID*|0x00000002 + gRockchipTokenSpaceGuid.PcdPlatformVendorName|"Unknown"|VOID*|0x00000003 + gRockchipTokenSpaceGuid.PcdBoardName|"Unknown"|VOID*|0x00000004 + gRockchipTokenSpaceGuid.PcdBoardVendorName|"Unknown"|VOID*|0x00000005 + gRockchipTokenSpaceGuid.PcdProductUrl|"Unknown"|VOID*|0x00000006 + gRockchipTokenSpaceGuid.PcdMemoryVendorName|"Unknown"|VOID*|0x00000007 + gRockchipTokenSpaceGuid.PcdFamilyName|"Unknown"|VOID*|0x00000008 + gRockchipTokenSpaceGuid.PcdDeviceTreeName|"Unknown"|VOID*|0x00000009 + + gRockchipTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x0 }|VOID*|0x02000001 + gRockchipTokenSpaceGuid.PcdI2cSlaveBuses|{ 0x0 }|VOID*|0x02000002 + gRockchipTokenSpaceGuid.PcdI2cSlaveBusesRuntimeSupport|{ 0x0 }|VOID*|0x02000003 + gRockchipTokenSpaceGuid.PcdI2cClockFrequency|0|UINT32|0x02000004 + gRockchipTokenSpaceGuid.PcdI2cBaudRate|0|UINT32|0x02000005 + gRockchipTokenSpaceGuid.PcdI2cDemoAddresses|{ 0x0 }|VOID*|0x02000007 + gRockchipTokenSpaceGuid.PcdI2cDemoBuses|{ 0x0 }|VOID*|0x02000008 + gRockchipTokenSpaceGuid.PcdRk860xRegulatorAddresses|{ 0x0 }|VOID*|0x02000009 + gRockchipTokenSpaceGuid.PcdRk860xRegulatorBuses|{ 0x0 }|VOID*|0x0200000A + gRockchipTokenSpaceGuid.PcdRk860xRegulatorTags|{ 0x0 }|VOID*|0x0200000B + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMinVoltages|{ 0x0 }|VOID*|0x0200000C + gRockchipTokenSpaceGuid.PcdRk860xRegulatorMaxVoltages|{ 0x0 }|VOID*|0x0200000D + gRockchipTokenSpaceGuid.PcdRtc8563Bus|0|UINT8|0x0200000E + + gRockchipTokenSpaceGuid.PcdRkSdmmcBaseAddress|0x0|UINT32|0x40000030 + gRockchipTokenSpaceGuid.PcdRkSdmmcCardDetectBroken|FALSE|BOOLEAN|0x40000031 + + gRockchipTokenSpaceGuid.PcdDwcSdhciBaseAddress|0x0|UINT32|0x40000035 + gRockchipTokenSpaceGuid.PcdDwcSdhciForceHighSpeed|FALSE|BOOLEAN|0x40000036 + gRockchipTokenSpaceGuid.PcdDwcSdhciDisableHs400|FALSE|BOOLEAN|0x40000037 + + gRockchipTokenSpaceGuid.SpiRK806BaseAddr|0|UINT32|0x21200002 + + gRockchipTokenSpaceGuid.PcdEhciBaseAddress|0|UINT32|0x50000060 + gRockchipTokenSpaceGuid.PcdNumEhciController|0|UINT32|0x50000061 + gRockchipTokenSpaceGuid.PcdEhciSize|0|UINT32|0x50000062 + gRockchipTokenSpaceGuid.PcdOhciSize|0|UINT32|0x50000063 + + gRockchipTokenSpaceGuid.PcdDwc3BaseAddresses|{ 0x0 }|VOID*|0x50000069 + gRockchipTokenSpaceGuid.PcdDwc3Size|0|UINT32|0x50000071 + + gRockchipTokenSpaceGuid.FspiBaseAddr|0|UINT64|0x21200003 + gRockchipTokenSpaceGuid.CruBaseAddr|0|UINT64|0x21200008 + + gRockchipTokenSpaceGuid.PcdNvStoragePreferSpiFlash|FALSE|BOOLEAN|0x21200009 + + gRockchipTokenSpaceGuid.PcdLcdPixelFormat|0|UINT32|0x32000001 + gRockchipTokenSpaceGuid.PcdEdpId|0|UINT32|0x32000003 + gRockchipTokenSpaceGuid.PcdHdmiId|0|UINT32|0x32000004 + gRockchipTokenSpaceGuid.PcdHdmiDDCI2CPinMux|0|UINT32|0x32000005 + + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxBase|0x0010f000|UINT64|0x00001000 + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSize|0x100|UINT32|0x00001001 + gRockchipTokenSpaceGuid.PcdRkMtlMailBoxSmcId|0x82000010|UINT32|0x00010002 + + gRockchipTokenSpaceGuid.PcdPca9555Address|0|UINT8|0x03000001 + gRockchipTokenSpaceGuid.PcdPca9555Bus|0|UINT8|0x03000002 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec new file mode 100644 index 0000000..9354ebf --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/DesignWarePkg.dec @@ -0,0 +1,25 @@ +#/** @file +# Framework Module Development Environment Industry Standards +# +# This Package provides headers and libraries that conform to EFI/PI Industry standards. +# Copyright (c) 2007-2021, Intel Corporation. All rights reserved. +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved. +# Copyright (c) 2018, Linaro. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +#**/ + +[Defines] + DEC_SPECIFICATION = 0x00010019 + PACKAGE_NAME = DesignWarePkg + PACKAGE_GUID = e73097ce-1fe2-41a6-a930-3136bc6d23ef + PACKAGE_VERSION = 0.1 + +[Includes] + Include + +[Guids.common] + gDwMmcHcNonDiscoverableDeviceGuid = { 0x971ab768, 0xd733, 0x41be, { 0xac, 0x9e, 0x82, 0x36, 0x10, 0x94, 0xc9, 0x3c }} + +[Protocols.common] + gPlatformDwMmcProtocolGuid = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85, 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/ComponentName.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/ComponentName.c new file mode 100644 index 0000000..7076963 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/ComponentName.c @@ -0,0 +1,207 @@ +/** @file + UEFI Component Name(2) protocol implementation for Designware SD/MMC host + controller driver. + + Copyright (c) 2015-2021, Intel Corporation. All rights reserved. + Copyright (c) 2018, Linaro Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "DwMmcHcDxe.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName = { + DwMmcHcComponentNameGetDriverName, + DwMmcHcComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DwMmcHcComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DwMmcHcComponentNameGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcDriverNameTable[] = { + { "eng;en", L"Designware Sd/Mmc Host Controller Driver" }, + { NULL , NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcControllerNameTable[] = { + { "eng;en", L"Designware Sd/Mmc Host Controller" }, + { NULL , NULL } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mDwMmcHcDriverNameTable, + DriverName, + (BOOLEAN)(This == &gDwMmcHcComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + if (Language == NULL || ControllerName == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllerHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gDwMmcHcDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mDwMmcHcControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gDwMmcHcComponentName) + ); +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.c new file mode 100644 index 0000000..ff6d75a --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.c @@ -0,0 +1,1294 @@ +/** @file + This driver is used to manage Designware SD/MMC host controller. + + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use. + + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved. + Copyright (C) 2016 Marvell International Ltd. All rigths reserved. + Copyright (C) 2018, Linaro Ltd. All rigths reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "DwMmcHcDxe.h" + +// +// Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = { + DwMmcHcDriverBindingSupported, + DwMmcHcDriverBindingStart, + DwMmcHcDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Template for Designware SD/MMC host controller private data. +// +DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = { + DW_MMC_HC_PRIVATE_SIGNATURE, // Signature + NULL, // ControllerHandle + 0x0, // Mmio base address + { // PassThru + sizeof (UINT32), + DwMmcPassThruPassThru, + DwMmcPassThruGetNextSlot, + DwMmcPassThruBuildDevicePath, + DwMmcPassThruGetSlotNumber, + DwMmcPassThruResetDevice + }, + NULL, // PlatformDwMmc + 0, // PreviousSlot + NULL, // TimerEvent + NULL, // ConnectEvent + // Queue + INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue), + { // Slot + {0, UnknownSlot, 0, 0, 0} + }, + { // Capability + {0} + }, + { // MaxCurrent + 0 + }, + 0 // ControllerVersion +}; + +SD_DEVICE_PATH mSdDpTemplate = { + { + MESSAGING_DEVICE_PATH, + MSG_SD_DP, + { + (UINT8) (sizeof (SD_DEVICE_PATH)), + (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8) + } + }, + 0 +}; + +EMMC_DEVICE_PATH mEmmcDpTemplate = { + { + MESSAGING_DEVICE_PATH, + MSG_EMMC_DP, + { + (UINT8) (sizeof (EMMC_DEVICE_PATH)), + (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8) + } + }, + 0 +}; + +// +// Prioritized function list to detect card type. +// User could add other card detection logic here. +// +DWMMC_CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = { + EmmcIdentification, + SdCardIdentification, + NULL +}; + +/** + The entry point for SD host controller driver, used to install this driver on the ImageHandle. + + @param[in] ImageHandle The firmware allocated handle for this driver image. + @param[in] SystemTable Pointer to the EFI system table. + + @retval EFI_SUCCESS Driver loaded. + @retval other Driver not loaded. + +**/ +EFI_STATUS +EFIAPI +InitializeDwMmcHcDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gDwMmcHcDriverBinding, + ImageHandle, + &gDwMmcHcComponentName, + &gDwMmcHcComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Call back function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +ProcessAsyncTaskList ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + LIST_ENTRY *Link; + DW_MMC_HC_TRB *Trb; + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + BOOLEAN InfiniteWait; + EFI_EVENT TrbEvent; + + Private = (DW_MMC_HC_PRIVATE_DATA *)Context; + + // + // Check if the first entry in the async I/O queue is done or not. + // + Status = EFI_SUCCESS; + Trb = NULL; + Link = GetFirstNode (&Private->Queue); + if (!IsNull (&Private->Queue, Link)) { + Trb = DW_MMC_HC_TRB_FROM_THIS (Link); + if (!Private->Slot[Trb->Slot].MediaPresent) { + Status = EFI_NO_MEDIA; + goto Done; + } + if (!Trb->Started) { + // + // Check whether the cmd/data line is ready for transfer. + // + Status = DwMmcCheckTrbEnv (Private, Trb); + if (!EFI_ERROR (Status)) { + Trb->Started = TRUE; + Status = DwMmcExecTrb (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + } else { + goto Done; + } + } + Status = DwMmcCheckTrbResult (Private, Trb); + } + +Done: + if ((Trb != NULL) && (Status == EFI_NOT_READY)) { + Packet = Trb->Packet; + if (Packet->Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + if ((!InfiniteWait) && (Trb->Timeout-- == 0)) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = EFI_TIMEOUT; + TrbEvent = Trb->Event; + DwMmcFreeTrb (Trb); + DEBUG (( + DEBUG_VERBOSE, + "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", + TrbEvent + )); + gBS->SignalEvent (TrbEvent); + return; + } + } + if ((Trb != NULL) && (Status != EFI_NOT_READY)) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = Status; + TrbEvent = Trb->Event; + DwMmcFreeTrb (Trb); + DEBUG (( + DEBUG_VERBOSE, + "ProcessAsyncTaskList(): Signal Event %p with %r\n", + TrbEvent, + Status + )); + gBS->SignalEvent (TrbEvent); + } + return; +} + +/** + Sd removable device enumeration callback function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +DwMmcHcEnumerateDevice ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + EFI_STATUS Status; + BOOLEAN MediaPresent; + BOOLEAN MediaChanged; + UINT32 RoutineNum; + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine; + UINTN Index; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + DW_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + Private = (DW_MMC_HC_PRIVATE_DATA *)Context; + + if ((Private->Slot[0].Enable) && + (Private->Slot[0].SlotType == RemovableSlot)) { + Status = DwMmcHcCardDetect ( + Private->DevBase, + Private->ControllerHandle, + 0, + &MediaPresent + ); + + MediaChanged = Private->Slot[0].MediaPresent != MediaPresent; + + if (MediaChanged && !MediaPresent) { + DEBUG (( + DEBUG_INFO, + "DwMmcHcEnumerateDevice: device disconnected at %p\n", + Private->DevBase + )); + Private->Slot[0].MediaPresent = FALSE; + // + // Signal all async task events at the slot with EFI_NO_MEDIA status. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + Trb = DW_MMC_HC_TRB_FROM_THIS (Link); + if (Trb->Slot == 0) { + RemoveEntryList (Link); + Trb->Packet->TransactionStatus = EFI_NO_MEDIA; + gBS->SignalEvent (Trb->Event); + DwMmcFreeTrb (Trb); + } + } + gBS->RestoreTPL (OldTpl); + // + // Notify the upper layer the connect state change through + // ReinstallProtocolInterface. + // + gBS->ReinstallProtocolInterface ( + Private->ControllerHandle, + &gEfiSdMmcPassThruProtocolGuid, + &Private->PassThru, + &Private->PassThru + ); + } + if (MediaChanged && MediaPresent) { + DEBUG (( + DEBUG_INFO, + "DwMmcHcEnumerateDevice: device connected at %p\n", + Private->DevBase + )); + // + // Initialize slot and start identification process for the new + // attached device + // + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]); + if (EFI_ERROR (Status)) { + return; + } + // + // Reset the specified slot of the SD/MMC Pci Host Controller + // + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]); + if (EFI_ERROR (Status)) { + return; + } + + Private->Slot[0].MediaPresent = TRUE; + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / + sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE); + for (Index = 0; Index < RoutineNum; Index++) { + Routine = &mCardTypeDetectRoutineTable[Index]; + if (*Routine != NULL) { + Status = (*Routine) (Private); + if (!EFI_ERROR (Status)) { + break; + } + } + } + // + // This card doesn't get initialized correctly. + // + if (Index == RoutineNum) { + return; + } + + // + // Notify the upper layer the connect state change through + // ReinstallProtocolInterface. + // + gBS->ReinstallProtocolInterface ( + Private->ControllerHandle, + &gEfiSdMmcPassThruProtocolGuid, + &Private->PassThru, + &Private->PassThru + ); + } + } + + return; +} + +/** + Reset the specified SD/MMC host controller and enable all interrupts. + + @param[in] DevBase The Mmio Device Base Address. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +DwMmcHcReset ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT32 BlkSize; + + // + // Enable all interrupt after reset all. + // + Status = DwMmcHcEnableInterrupt (DevBase); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", Status)); + return Status; + } + Status = DwMmcHcInitTimeoutCtrl (DevBase); + if (EFI_ERROR (Status)) { + return Status; + } + + BlkSize = DW_MMC_BLOCK_SIZE; + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); + + Status = DwMmcHcInitClockFreq (DevBase, Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = DwMmcHcSetBusWidth (DevBase, FALSE, 1); + + return Status; +} + +/** + Tests to see if this driver supports a given controller. If a child device + is provided, it further tests to see if this driver supports creating a + handle for the specified child device. + + This function checks to see if the driver specified by This supports the + device specified by ControllerHandle. Drivers will typically use the device + path attached to ControllerHandle and/or the services from the bus I/O + abstraction attached to ControllerHandle to determine if the driver supports + ControllerHandle. This function may be called many times during platform + initialization. In order to reduce boot times, the tests performed by this + function must be very small, and take as little time as possible to execute. + This function must not change the state of any hardware devices, and this + function must be aware that the device specified by ControllerHandle may + already be managed by the same driver or a different driver. This function + must match its calls to AllocatePages() with FreePages(), AllocatePool() with + FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle + may have been previously started by the same driver, if a protocol is already + in the opened state, then it must not be closed with CloseProtocol(). This is + required to guarantee the state of ControllerHandle is not modified by this + function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the controller to test. This + handle must support a protocol interface that + supplies an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a + device path. This parameter is ignored by + device drivers, and is optional for bus + drivers. For bus drivers, if this parameter + is not NULL, then the bus driver must deter- + mine if the bus controller specified by + ControllerHandle and the child controller + specified by RemainingDevicePath are both + supported by this bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the + driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by the driver specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by a different driver or an application that + requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the + driver specified by This. +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + NON_DISCOVERABLE_DEVICE *Dev; + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; + + ParentDevicePath = NULL; + + Status = gBS->LocateProtocol ( + &gPlatformDwMmcProtocolGuid, + NULL, + (VOID **) &PlatformDwMmc + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID *) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + // + // EFI_ALREADY_STARTED is also an error. + // + return Status; + } + // + // Close the protocol because we don't use it here. + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Now test the EdkiiNonDiscoverableDeviceProtocol. + // + Status = gBS->OpenProtocol ( + Controller, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **) &Dev, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CompareGuid (Dev->Type, &gDwMmcHcNonDiscoverableDeviceGuid)) { + Status = EFI_SUCCESS; + } else { + Status = EFI_UNSUPPORTED; + } + + gBS->CloseProtocol ( + Controller, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; +} + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service + ConnectController(). + As a result, much of the error checking on the parameters to Start() has + been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system + behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a + naturally aligned EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver + specified by This must have been called with the same calling parameters, + and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the controller to start. This + handle must support a protocol interface + that supplies an I/O abstraction to the + driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a + device path. This parameter is ignored by + device drivers, and is optional for bus + drivers. + For a bus driver, if this parameter is NULL, + then handles for all the children of + Controller are created by this driver. + If this parameter is not NULL and the first + Device Path Node is not the End of Device + Path Node, then only the handle for the + child device specified by the first Device + Path Node of RemainingDevicePath is created + by this driver. + If the first Device Path Node of + RemainingDevicePath is the End of Device Path + Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a + device error. Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + DW_MMC_HC_PRIVATE_DATA *Private; + + NON_DISCOVERABLE_DEVICE *Dev; + + BOOLEAN MediaPresent; + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine; + UINT8 Index; + UINT32 RoutineNum; + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; + + Status = gBS->LocateProtocol ( + &gPlatformDwMmcProtocolGuid, + NULL, + (VOID **) &PlatformDwMmc + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEdkiiNonDiscoverableDeviceProtocolGuid, + (VOID **) &Dev, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); + return Status; + } + + Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), &gDwMmcHcTemplate); + if (Private == NULL) { + DEBUG ((DEBUG_ERROR, "err %d", __LINE__)); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Private->ControllerHandle = Controller; + Private->DevBase = Dev->Resources[0].AddrRangeMin; + Private->PlatformDwMmc = PlatformDwMmc; + InitializeListHead (&Private->Queue); + + Status = Private->PlatformDwMmc->GetCapability (Controller, 0, &Private->Capability[0]); + + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Private->Capability[0].BaseClkFreq == 0) { + goto Done; + } + + DumpCapabilityReg (0, &Private->Capability[0]); + + Status = DwMmcHcCardDetect (Private->DevBase, Controller, 0, &Private->Slot[0].MediaPresent); + + // + // Initialize slot and start identification process for the new attached device + // + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Reset HC + // + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]); + if (EFI_ERROR (Status)) { + goto Done; + } + + Private->Slot[0].SlotType = Private->Capability[0].SlotType; + Private->Slot[0].CardType = Private->Capability[0].CardType; + Private->Slot[0].Enable = TRUE; + + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE); + for (Index = 0; Index < RoutineNum; Index++) { + Routine = &mCardTypeDetectRoutineTable[Index]; + if (*Routine != NULL) { + Status = (*Routine) (Private); + if (!EFI_ERROR (Status)) { + break; + } + } + } + + // + // Start the asynchronous I/O monitor + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ProcessAsyncTaskList, + Private, + &Private->TimerEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, DW_MMC_HC_ASYNC_TIMER); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Start the Sd removable device connection enumeration + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DwMmcHcEnumerateDevice, + Private, + &Private->ConnectEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, DW_MMC_HC_ENUM_TIMER); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSdMmcPassThruProtocolGuid, + &(Private->PassThru), + NULL + ); + + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", Status, Controller)); + +Done: + if (EFI_ERROR (Status)) { + if ((Private != NULL) && (Private->TimerEvent != NULL)) { + gBS->CloseEvent (Private->TimerEvent); + } + + if ((Private != NULL) && (Private->ConnectEvent != NULL)) { + gBS->CloseEvent (Private->ConnectEvent); + } + + if (Private != NULL) { + FreePool (Private); + } + } + + return Status; +} + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service + DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been + moved into this common boot service. It is legal to call Stop() from other + locations, but the following calling restrictions must be followed or the + system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous + call to this same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in + this driver's Start() function, and the Start() function must have called + OpenProtocol() on ControllerHandle with an Attribute of + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle + must support a bus specific I/O protocol for the + driver to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in + ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be + NULL if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device + error. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + DW_MMC_HC_PRIVATE_DATA *Private; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + DW_MMC_HC_TRB *Trb; + + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n")); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + (VOID**) &PassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); + // + // Close Non-Blocking timer and free Task list. + // + if (Private->TimerEvent != NULL) { + gBS->CloseEvent (Private->TimerEvent); + Private->TimerEvent = NULL; + } + if (Private->ConnectEvent != NULL) { + gBS->CloseEvent (Private->ConnectEvent); + Private->ConnectEvent = NULL; + } + // + // As the timer is closed, there is no needs to use TPL lock to + // protect the critical region "queue". + // + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + RemoveEntryList (Link); + Trb = DW_MMC_HC_TRB_FROM_THIS (Link); + Trb->Packet->TransactionStatus = EFI_ABORTED; + gBS->SignalEvent (Trb->Event); + DwMmcFreeTrb (Trb); + } + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + &(Private->PassThru) + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool (Private); + + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", Status)); + + return Status; +} + +/** + Sends SD command to an SD card that is attached to the SD controller. + + The PassThru() function sends the SD command specified by Packet to the SD + card specified by Slot. + + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is + returned. + + If Slot is not in a valid range for the SD controller, then + EFI_INVALID_PARAMETER is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are + NULL, EFI_INVALID_PARAMETER is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot The slot number of the SD card to send the + command to. + @param[in,out] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If + Event is not NULL, then nonblocking I/O is + performed, and Event will be signaled when the + Packet completes. + + @retval EFI_SUCCESS The SD Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + the SD command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is + invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both + InDataBuffer and OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the SD Command Packet + is not supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength + exceeds the limit supported by SD card + ( i.e. if the number of bytes exceed the Last + LBA). + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruPassThru ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +{ + EFI_STATUS Status; + DW_MMC_HC_PRIVATE_DATA *Private; + DW_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + if ((This == NULL) || (Packet == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This); + + if (!Private->Slot[Slot].Enable) { + return EFI_INVALID_PARAMETER; + } + + if (!Private->Slot[Slot].MediaPresent) { + return EFI_NO_MEDIA; + } + + Trb = DwMmcCreateTrb (Private, Slot, Packet, Event); + if (Trb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Immediately return for async I/O. + // + if (Event != NULL) { + return EFI_SUCCESS; + } + + // + // Wait async I/O list is empty before execute sync I/O operation. + // + while (TRUE) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (IsListEmpty (&Private->Queue)) { + gBS->RestoreTPL (OldTpl); + break; + } + gBS->RestoreTPL (OldTpl); + } + + Status = DwMmcWaitTrbEnv (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = DwMmcExecTrb (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = DwMmcWaitTrbResult (Private, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: + if (Trb != NULL) { + DwMmcFreeTrb (Trb); + } + + return Status; +} + +/** + Used to retrieve next slot numbers supported by the SD controller. The + function returns information about all available slots (populated or + not-populated). + + The GetNextSlot() function retrieves the next slot number on an SD controller. + If on input Slot is 0xFF, then the slot number of the first slot on the SD + controller is returned. + + If Slot is a slot number that was returned on a previous call to + GetNextSlot(), then the slot number of the next slot on the SD controller is + returned. + + If Slot is not 0xFF and Slot was not returned on a previous call to + GetNextSlot(), EFI_INVALID_PARAMETER is returned. + + If Slot is the slot number of the last slot on the SD controller, then + EFI_NOT_FOUND is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL + instance. + @param[in,out] Slot On input, a pointer to a slot number on the SD + controller. + On output, a pointer to the next slot number on + the SD controller. + An input value of 0xFF retrieves the first slot + number on the SD controller. + + @retval EFI_SUCCESS The next slot number on the SD controller was + returned in Slot. + @retval EFI_NOT_FOUND There are no more slots on this SD controller. + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a + previous call to GetNextSlot(). + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruGetNextSlot ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 *Slot + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + + if ((This == NULL) || (Slot == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This); + + if (*Slot == 0xFF) { + if (Private->Slot[0].Enable) { + *Slot = 0; + Private->PreviousSlot = 0; + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; + } else if (*Slot == Private->PreviousSlot) { + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } +} + +/** + Used to allocate and build a device path node for an SD card on the SD + controller. + + The BuildDevicePath() function allocates and builds a single device node + for the SD card specified by Slot. + + If the SD card specified by Slot is not present on the SD controller, then + EFI_NOT_FOUND is returned. + + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. + + If there are not enough resources to allocate the device path node, then + EFI_OUT_OF_RESOURCES is returned. + + Otherwise, DevicePath is allocated with the boot service AllocatePool(), + the contents of DevicePath are initialized to describe the SD card specified + by Slot, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot Specifies the slot number of the SD card for + which a device path node is to be allocated and + built. + @param[in,out] DevicePath A pointer to a single device path node that + describes the SD card specified by Slot. This + function is responsible for allocating the + buffer DevicePath with the boot service + AllocatePool(). It is the caller's responsi- + bility to free DevicePath when the caller is + finished with DevicePath. + + @retval EFI_SUCCESS The device path node that describes the SD card + specified by Slot was allocated and returned in + DevicePath. + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on + the SD controller. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate + DevicePath. + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruBuildDevicePath ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + SD_DEVICE_PATH *SdNode; + EMMC_DEVICE_PATH *EmmcNode; + + if ((This == NULL) || (DevicePath == NULL) || (Slot >= DW_MMC_HC_MAX_SLOT)) { + return EFI_INVALID_PARAMETER; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This); + + if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) { + return EFI_NOT_FOUND; + } + + if (Private->Slot[Slot].CardType == SdCardType) { + SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate); + if (SdNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + SdNode->SlotNumber = Slot; + + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode; + } else if (Private->Slot[Slot].CardType == EmmcCardType) { + EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate); + if (EmmcNode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + EmmcNode->SlotNumber = Slot; + + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode; + } else { + // + // Currently we only support SD and EMMC two device nodes. + // + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + This function retrieves an SD card slot number based on the input device path. + + The GetSlotNumber() function retrieves slot number for the SD card specified + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is + returned. + + If DevicePath is not a device path node type that the SD Pass Thru driver + supports, EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] DevicePath A pointer to the device path node that describes + a SD card on the SD controller. + @param[out] Slot On return, points to the slot number of an SD + card on the SD controller. + + @retval EFI_SUCCESS SD card slot number is returned in Slot. + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that + the SD Pass Thru driver supports. + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruGetSlotNumber ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT8 *Slot + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + SD_DEVICE_PATH *SdNode; + EMMC_DEVICE_PATH *EmmcNode; + UINT8 SlotNumber; + + if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This); + + // + // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH + // + if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || + ((DevicePath->SubType != MSG_SD_DP) && + (DevicePath->SubType != MSG_EMMC_DP)) || + (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) || + (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) { + return EFI_UNSUPPORTED; + } + + if (DevicePath->SubType == MSG_SD_DP) { + SdNode = (SD_DEVICE_PATH *) DevicePath; + SlotNumber = SdNode->SlotNumber; + } else { + EmmcNode = (EMMC_DEVICE_PATH *) DevicePath; + SlotNumber = EmmcNode->SlotNumber; + } + + if (SlotNumber >= DW_MMC_HC_MAX_SLOT) { + return EFI_NOT_FOUND; + } + + if (Private->Slot[SlotNumber].Enable) { + *Slot = SlotNumber; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +/** + Resets an SD card that is connected to the SD controller. + + The ResetDevice() function resets the SD card specified by Slot. + + If this SD controller does not support a device reset operation, + EFI_UNSUPPORTED is returned. + + If Slot is not in a valid slot number for this SD controller, + EFI_INVALID_PARAMETER is returned. + + If the device reset operation is completed, EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot Specifies the slot number of the SD card to be + reset. + + @retval EFI_SUCCESS The SD card specified by Slot was reset. + @retval EFI_UNSUPPORTED The SD controller does not support a device + reset operation. + @retval EFI_INVALID_PARAMETER Slot number is invalid. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_DEVICE_ERROR The reset command failed due to a device error + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruResetDevice ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot + ) +{ + DW_MMC_HC_PRIVATE_DATA *Private; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + DW_MMC_HC_TRB *Trb; + EFI_TPL OldTpl; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This); + + if (!Private->Slot[Slot].Enable) { + return EFI_INVALID_PARAMETER; + } + + if (!Private->Slot[Slot].MediaPresent) { + return EFI_NO_MEDIA; + } + + // + // Free all async I/O requests in the queue + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + for (Link = GetFirstNode (&Private->Queue); + !IsNull (&Private->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Private->Queue, Link); + RemoveEntryList (Link); + Trb = DW_MMC_HC_TRB_FROM_THIS (Link); + Trb->Packet->TransactionStatus = EFI_ABORTED; + gBS->SignalEvent (Trb->Event); + DwMmcFreeTrb (Trb); + } + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.h new file mode 100644 index 0000000..101bc92 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.h @@ -0,0 +1,810 @@ +/** @file + + Provides some data structure definitions used by the Designware SD/MMC + host controller driver. + + Copyright (c) 2015, Intel Corporation. All rights reserved. + Copyright (C) 2018, Linaro Ltd. All rigths reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _DW_MMC_HC_DXE_H_ +#define _DW_MMC_HC_DXE_H_ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "DwMmcHci.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2; +extern EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding; + +#define DW_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('d', 'w', 's', 'd') + +#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \ + CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru, DW_MMC_HC_PRIVATE_SIGNATURE) + +// +// Generic time out value, 1 microsecond as unit. +// +#define DW_MMC_HC_GENERIC_TIMEOUT (1 * 1000 * 1000) + +// +// SD/MMC async transfer timer interval, set by experience. +// The unit is 100us, takes 1ms as interval. +// +#define DW_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1) +// +// SD/MMC removable device enumeration timer interval, set by experience. +// The unit is 100us, takes 100ms as interval. +// +#define DW_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100) + +typedef struct { + BOOLEAN Enable; + EFI_SD_MMC_SLOT_TYPE SlotType; + BOOLEAN MediaPresent; + BOOLEAN Initialized; + SD_MMC_CARD_TYPE CardType; +} DW_MMC_HC_SLOT; + +typedef struct { + UINTN Signature; + + EFI_HANDLE ControllerHandle; + + // Mmio base address + UINTN DevBase; + + EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru; + + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; + // + // The field is used to record the previous slot in GetNextSlot(). + // + UINT8 PreviousSlot; + // + // For Non-blocking operation. + // + EFI_EVENT TimerEvent; + // + // For Sd removable device enumeration. + // + EFI_EVENT ConnectEvent; + LIST_ENTRY Queue; + + DW_MMC_HC_SLOT Slot[DW_MMC_HC_MAX_SLOT]; + DW_MMC_HC_SLOT_CAP Capability[DW_MMC_HC_MAX_SLOT]; + UINT64 MaxCurrent[DW_MMC_HC_MAX_SLOT]; + + UINT32 ControllerVersion; +} DW_MMC_HC_PRIVATE_DATA; + +#define DW_MMC_HC_TRB_SIG SIGNATURE_32 ('D', 'T', 'R', 'B') + +// +// TRB (Transfer Request Block) contains information for the cmd request. +// +typedef struct { + UINT32 Signature; + LIST_ENTRY TrbList; + + UINT8 Slot; + UINT16 BlockSize; + + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + VOID *Data; + UINT32 DataLen; + BOOLEAN Read; + EFI_PHYSICAL_ADDRESS DataPhy; + VOID *DataMap; + DW_MMC_HC_TRANSFER_MODE Mode; + + EFI_EVENT Event; + BOOLEAN Started; + UINT64 Timeout; + + DW_MMC_HC_DMA_DESC_LINE *DmaDesc; + EFI_PHYSICAL_ADDRESS DmaDescPhy; + UINT32 DmaDescPages; + VOID *DmaMap; + + BOOLEAN UseFifo; + BOOLEAN UseBE; // Big-endian + + DW_MMC_HC_PRIVATE_DATA *Private; +} DW_MMC_HC_TRB; + +#define DW_MMC_HC_TRB_FROM_THIS(a) \ + CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG) + +// +// Task for Non-blocking mode. +// +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + + UINT8 Slot; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + BOOLEAN IsStart; + EFI_EVENT Event; + UINT64 RetryTimes; + BOOLEAN InfiniteWait; + VOID *Map; + VOID *MapAddress; +} DW_MMC_HC_QUEUE; + +// +// Prototypes +// +/** + Execute card identification procedure. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + + @retval EFI_SUCCESS The card is identified correctly. + @retval Others The card can't be identified. + +**/ +typedef +EFI_STATUS +(*DWMMC_CARD_TYPE_DETECT_ROUTINE) ( + IN DW_MMC_HC_PRIVATE_DATA *Private + ); + +/** + Sends SD command to an SD card that is attached to the SD controller. + + The PassThru() function sends the SD command specified by Packet to the SD + card specified by Slot. + + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is + returned. + + If Slot is not in a valid range for the SD controller, then + EFI_INVALID_PARAMETER is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are + NULL, EFI_INVALID_PARAMETER is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot The slot number of the SD card to send the + command to. + @param[in,out] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If + Event is not NULL, then nonblocking I/O is + performed, and Event will be signaled when the + Packet completes. + + @retval EFI_SUCCESS The SD Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send + the SD command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is + invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both + InDataBuffer and OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the SD Command Packet + is not supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength + exceeds the limit supported by SD card ( i.e. if + the number of bytes exceed the Last LBA). + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruPassThru ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ); + +/** + Used to retrieve next slot numbers supported by the SD controller. The + function returns information about all available slots (populated or + not-populated). + + The GetNextSlot() function retrieves the next slot number on an SD controller. + If on input Slot is 0xFF, then the slot number of the first slot on the SD + controller is returned. + + If Slot is a slot number that was returned on a previous call to + GetNextSlot(), then the slot number of the next slot on the SD controller is + returned. + + If Slot is not 0xFF and Slot was not returned on a previous call to + GetNextSlot(), EFI_INVALID_PARAMETER is returned. + + If Slot is the slot number of the last slot on the SD controller, then + EFI_NOT_FOUND is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL + instance. + @param[in,out] Slot On input, a pointer to a slot number on the SD + controller. + On output, a pointer to the next slot number on + the SD controller. + An input value of 0xFF retrieves the first slot + number on the SD controller. + + @retval EFI_SUCCESS The next slot number on the SD controller was + returned in Slot. + @retval EFI_NOT_FOUND There are no more slots on this SD controller. + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a + previous call to GetNextSlot(). + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruGetNextSlot ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN OUT UINT8 *Slot + ); + +/** + Used to allocate and build a device path node for an SD card on the SD + controller. + + The BuildDevicePath() function allocates and builds a single device node + for the SD + card specified by Slot. + + If the SD card specified by Slot is not present on the SD controller, then + EFI_NOT_FOUND is returned. + + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. + + If there are not enough resources to allocate the device path node, then + EFI_OUT_OF_RESOURCES is returned. + + Otherwise, DevicePath is allocated with the boot service AllocatePool(), the + contents of DevicePath are initialized to describe the SD card specified by + Slot, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot Specifies the slot number of the SD card for + which a device path node is to be allocated and + built. + @param[in,out] DevicePath A pointer to a single device path node that + describes the SD card specified by Slot. This + function is responsible for allocating the + buffer DevicePath with the boot service + AllocatePool(). It is the caller's responsibi- + lity to free DevicePath when the caller is + finished with DevicePath. + + @retval EFI_SUCCESS The device path node that describes the SD card + specified by Slot was allocated and returned in + DevicePath. + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on + the SD controller. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate + DevicePath. + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruBuildDevicePath ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +/** + This function retrieves an SD card slot number based on the input device path. + + The GetSlotNumber() function retrieves slot number for the SD card specified + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is + returned. + + If DevicePath is not a device path node type that the SD Pass Thru driver + supports, EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] DevicePath A pointer to the device path node that describes + a SD card on the SD controller. + @param[out] Slot On return, points to the slot number of an SD + card on the SD controller. + + @retval EFI_SUCCESS SD card slot number is returned in Slot. + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL. + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that + the SD Pass Thru driver supports. + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruGetSlotNumber ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT8 *Slot + ); + +/** + Resets an SD card that is connected to the SD controller. + + The ResetDevice() function resets the SD card specified by Slot. + + If this SD controller does not support a device reset operation, + EFI_UNSUPPORTED is returned. + + If Slot is not in a valid slot number for this SD controller, + EFI_INVALID_PARAMETER is returned. + + If the device reset operation is completed, EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot Specifies the slot number of the SD card to be + reset. + + @retval EFI_SUCCESS The SD card specified by Slot was reset. + @retval EFI_UNSUPPORTED The SD controller does not support a device + reset operation. + @retval EFI_INVALID_PARAMETER Slot number is invalid. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_DEVICE_ERROR The reset command failed due to a device error + +**/ +EFI_STATUS +EFIAPI +DwMmcPassThruResetDevice ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This, + IN UINT8 Slot + ); + +// +// Driver model protocol interfaces +// +/** + Tests to see if this driver supports a given controller. If a child device is + provided, it further tests to see if this driver supports creating a handle + for the specified child device. + + This function checks to see if the driver specified by This supports the + device specified by ControllerHandle. Drivers will typically use the device + path attached to ControllerHandle and/or the services from the bus I/O + abstraction attached to ControllerHandle to determine if the driver supports + ControllerHandle. This function may be called many times during platform + initialization. In order to reduce boot times, the tests performed by this + function must be very small, and take as little time as possible to execute. + This function must not change the state of any hardware devices, and this + function must be aware that the device specified by ControllerHandle may + already be managed by the same driver or a different driver. This function + must match its calls to AllocatePages() with FreePages(), AllocatePool() with + FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if + a protocol is already in the opened state, then it must not be closed with + CloseProtocol(). This is required to guarantee the state of ControllerHandle + is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the controller to test. This + handle must support a protocol interface that + supplies an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a + device path. This parameter is ignored by + device drivers, and is optional for bus + drivers. For bus drivers, if this parameter + is not NULL, then the bus driver must deter- + mine if the bus controller specified by + ControllerHandle and the child controller + specified by RemainingDevicePath are both + supported by this bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the + driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by the driver specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed + by a different driver or an application that + requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the + driver specified by This. +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service + ConnectController(). + As a result, much of the error checking on the parameters to Start() has been + moved into this common boot service. It is legal to call Start() from other + locations, + but the following calling restrictions must be followed or the system behavior + will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a natural- + ly aligned EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified + by This must have been called with the same calling parameters, and + Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle The handle of the controller to start. This + handle must support a protocol interface that + supplies an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a + device path. This parameter is ignored by + device drivers, and is optional for bus dri- + vers. For a bus driver, if this parameter is + NULL, then handles for all the children of + Controller are created by this driver. + If this parameter is not NULL and the first + Device Path Node is not the End of Device + Path Node, then only the handle for the + child device specified by the first Device + Path Node of RemainingDevicePath is created + by this driver. + If the first Device Path Node of + RemainingDevicePath is the End of Device Path + Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a + device error. Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service + DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been + moved into this common boot service. It is legal to call Stop() from other + locations, but the following calling restrictions must be followed or the + system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous + call to this same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in + this driver's Start() function, and the Start() function must have called + OpenProtocol() on ControllerHandle with an Attribute of + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL + instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle + must support a bus specific I/O protocol for the + driver to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in + ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be + NULL if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device + error. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + Create a new TRB for the SD/MMC cmd request. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command + to. + @param[in] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. + If Event is not NULL, then nonblocking I/O is + performed, and Event will be signaled when the + Packet completes. + + @return Created Trb or NULL. + +**/ +DW_MMC_HC_TRB * +DwMmcCreateTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event + ); + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + +**/ +VOID +DwMmcFreeTrb ( + IN DW_MMC_HC_TRB *Trb + ); + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +DwMmcCheckTrbEnv ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ); + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +DwMmcWaitTrbEnv ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ); + +/** + Execute the specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the + host controller. + +**/ +EFI_STATUS +DwMmcExecTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ); + +/** + Check the TRB execution result. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +DwMmcCheckTrbResult ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ); + +/** + Wait for the TRB execution result. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +DwMmcWaitTrbResult ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ); + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcIdentification ( + IN DW_MMC_HC_PRIVATE_DATA *Private + ); + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +SdCardIdentification ( + IN DW_MMC_HC_PRIVATE_DATA *Private + ); + +#endif /* _DW_MMC_HC_DXE_H_ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf new file mode 100644 index 0000000..930a0a3 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf @@ -0,0 +1,67 @@ +## @file +# DwSdMmcHcDxe driver is used to manage those host controllers which comply with +# Designware SD Host Controller. +# +# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds +# to specified devices from upper layer. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved. +# Copyright (C) 2016, Marvell International Ltd. All rights reserved. +# Copyright (c) 2018, Linaro Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DwMmcHcDxe + MODULE_UNI_FILE = DwMmcHcDxe.uni + FILE_GUID = 9be4d260-208c-4efe-a524-0b5d3bf77f9d + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeDwMmcHcDxe + +[Sources] + ComponentName.c + DwMmcHcDxe.c + DwMmcHcDxe.h + DwMmcHci.c + DwMmcHci.h + EmmcDevice.c + SdDevice.c + +[Packages] + ArmPkg/ArmPkg.dec + Silicon/Synopsys/DesignWare/DesignWarePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + CacheMaintenanceLib + DebugLib + DevicePathLib + DmaLib + MemoryAllocationLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEdkiiNonDiscoverableDeviceProtocolGuid + gEfiDevicePathProtocolGuid ## TO_START + gEfiPciIoProtocolGuid ## TO_START + gEfiSdMmcPassThruProtocolGuid ## BY_START + gPlatformDwMmcProtocolGuid + +[Guids] + gDwMmcHcNonDiscoverableDeviceGuid + +[UserExtensions.TianoCore."ExtraFiles"] + DwMmcHcDxeExtra.uni diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.c new file mode 100644 index 0000000..6b122d5 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.c @@ -0,0 +1,1647 @@ +/** @file + This driver is used to manage Designware SD/MMC PCI host controllers. + + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use. + + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.
    + Copyright (c) 2018, Linaro Ltd. All rights reserved.
    + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "DwMmcHcDxe.h" + +/** + Dump the content of SD/MMC host controller's Capability Register. + + @param[in] Slot The slot number of the SD card to send the + command to. + @param[in] Capability The buffer to store the capability data. + +**/ +VOID +DumpCapabilityReg ( + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP *Capability + ) +{ + // + // Dump Capability Data + // + DEBUG (( + DEBUG_INFO, + " == Slot [%d] Capability is 0x%x ==\n", + Slot, + Capability + )); + DEBUG (( + DEBUG_INFO, + " Base Clk Freq %dKHz\n", + Capability->BaseClkFreq + )); + DEBUG (( + DEBUG_INFO, + " BusWidth %d\n", + Capability->BusWidth + )); + DEBUG (( + DEBUG_INFO, + " HighSpeed Support %a\n", + Capability->HighSpeed ? "TRUE" : "FALSE" + )); + DEBUG (( + DEBUG_INFO, + " Voltage 1.8 %a\n", + Capability->Voltage18 ? "TRUE" : "FALSE" + )); + DEBUG (( + DEBUG_INFO, + " 64-bit Sys Bus %a\n", + Capability->SysBus64 ? "TRUE" : "FALSE" + )); + DEBUG ((DEBUG_INFO, " SlotType ")); + if (Capability->SlotType == 0x00) { + DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot")); + } else if (Capability->SlotType == 0x01) { + DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot")); + } else if (Capability->SlotType == 0x02) { + DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot")); + } else { + DEBUG ((DEBUG_INFO, "%a\n", "Reserved")); + } + DEBUG (( + DEBUG_INFO, + " SDR50 Support %a\n", + Capability->Sdr50 ? "TRUE" : "FALSE" + )); + DEBUG (( + DEBUG_INFO, + " SDR104 Support %a\n", + Capability->Sdr104 ? "TRUE" : "FALSE" + )); + DEBUG (( + DEBUG_INFO, + " DDR50 Support %a\n", + Capability->Ddr50 ? "TRUE" : "FALSE" + )); + return; +} + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] DevIo The DEVICE IO protocol instance. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcEnableInterrupt ( + UINTN DevBase + ) +{ + UINT32 IntStatus; + UINT32 IdIntEn; + UINT32 IdSts; + + // + // Enable all bits in Interrupt Mask Register + // + IntStatus = 0; + MmioWrite32 (DevBase + DW_MMC_INTMASK, IntStatus); + + // + // Clear status in Interrupt Status Register + // + IntStatus = ~0; + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); + + IdIntEn = ~0; + MmioWrite32 (DevBase + DW_MMC_IDINTEN, IdIntEn); + + IdSts = ~0; + MmioWrite32 (DevBase + DW_MMC_IDSTS, IdSts); + + return EFI_SUCCESS; +} + +EFI_STATUS +DwMmcHcGetCapability ( + IN UINTN DevBase, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT DW_MMC_HC_SLOT_CAP *Capacity + ) +{ + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; + EFI_STATUS Status; + + if (Capacity == NULL) { + return EFI_INVALID_PARAMETER; + } + Status = gBS->LocateProtocol ( + &gPlatformDwMmcProtocolGuid, + NULL, + (VOID **) &PlatformDwMmc + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PlatformDwMmc->GetCapability (Controller, Slot, Capacity); + return Status; +} + +/** + Detect whether there is a SD/MMC card attached at the specified SD/MMC host + controller slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command + to. + @param[out] MediaPresent The pointer to the media present boolean value. + + @retval EFI_SUCCESS There is no media change happened. + @retval EFI_MEDIA_CHANGED There is media change happened. + @retval Others The detection fails. + +**/ +EFI_STATUS +DwMmcHcCardDetect ( + IN UINTN DevBase, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT BOOLEAN *MediaPresent + ) +{ + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc; + EFI_STATUS Status; + + if (MediaPresent == NULL) { + return EFI_INVALID_PARAMETER; + } + Status = gBS->LocateProtocol ( + &gPlatformDwMmcProtocolGuid, + NULL, + (VOID **) &PlatformDwMmc + ); + if (EFI_ERROR (Status)) { + return Status; + } + *MediaPresent = PlatformDwMmc->CardDetect (Controller, Slot); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +DwMmcHcUpdateClock ( + IN UINTN DevBase + ) +{ + UINT32 Cmd; + UINT32 IntStatus; + + Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY | + BIT_CMD_START; + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); + + while (1) { + Cmd = MmioRead32 (DevBase + DW_MMC_CMD); + + if (!(Cmd & CMD_START_BIT)) { + break; + } + + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS); + + if (IntStatus & DW_MMC_INT_HLE) { + DEBUG (( + DEBUG_ERROR, + "DwMmcHcUpdateClock: failed to update mmc clock frequency\n" + )); + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; +} + +/** + Stop SD/MMC card clock. + + @param[in] DevIo The DEVICE IO protocol instance. + + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. + @retval Others Fail to stop SD/MMC clock. + +**/ +EFI_STATUS +DwMmcHcStopClock ( + IN UINTN DevBase + ) +{ + EFI_STATUS Status; + UINT32 ClkEna; + + // + // Disable MMC clock first + // + ClkEna = 0; + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna); + + Status = DwMmcHcUpdateClock (DevBase); + if (EFI_ERROR (Status)) { + return Status; + } + return Status; +} + +/** + SD/MMC card clock supply. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcClockSupply ( + IN UINTN DevBase, + IN UINT64 ClockFreq, + IN DW_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT32 BaseClkFreq; + UINT32 SettingFreq; + UINT32 Divisor; + UINT32 Remainder; + UINT32 MmcStatus; + UINT32 ClkEna; + UINT32 ClkSrc; + + // + // Calculate a divisor for SD clock frequency + // + ASSERT (Capability.BaseClkFreq != 0); + + BaseClkFreq = Capability.BaseClkFreq; + if (ClockFreq == 0) { + return EFI_INVALID_PARAMETER; + } + + if (ClockFreq > BaseClkFreq) { + ClockFreq = BaseClkFreq; + } + + // + // Calculate the divisor of base frequency. + // + Divisor = 0; + SettingFreq = BaseClkFreq; + while (ClockFreq < SettingFreq) { + Divisor++; + + SettingFreq = BaseClkFreq / (2 * Divisor); + Remainder = BaseClkFreq % (2 * Divisor); + if ((ClockFreq == SettingFreq) && (Remainder == 0)) { + break; + } + if ((ClockFreq == SettingFreq) && (Remainder != 0)) { + SettingFreq ++; + } + } + + DEBUG (( + DEBUG_INFO, + "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n", + BaseClkFreq, + Divisor, + ClockFreq + )); + + // + // Wait until MMC is idle + // + do { + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS); + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); + + do { + Status = DwMmcHcStopClock (DevBase); + } while (EFI_ERROR (Status)); + + do { + ClkSrc = 0; + MmioWrite32 (DevBase + DW_MMC_CLKSRC, ClkSrc); + // + // Set clock divisor + // + MmioWrite32 (DevBase + DW_MMC_CLKDIV, Divisor); + // + // Enable MMC clock + // + ClkEna = 1; + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna); + + Status = DwMmcHcUpdateClock (DevBase); + } while (EFI_ERROR (Status)); + + return EFI_SUCCESS; +} + +/** + Set the SD/MMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] IsDdr A boolean to indicate it's dual data rate or not. + @param[in] BusWidth The bus width used by the SD/MMC device, it must be + 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +DwMmcHcSetBusWidth ( + IN UINTN DevBase, + IN BOOLEAN IsDdr, + IN UINT16 BusWidth + ) +{ + UINT32 Ctype; + UINT32 Uhs; + + switch (BusWidth) { + case 1: + Ctype = MMC_1BIT_MODE; + break; + case 4: + Ctype = MMC_4BIT_MODE; + break; + case 8: + Ctype = MMC_8BIT_MODE; + break; + default: + return EFI_INVALID_PARAMETER; + } + MmioWrite32 (DevBase + DW_MMC_CTYPE, Ctype); + + Uhs = MmioRead32 (DevBase + DW_MMC_UHSREG); + + if (IsDdr) { + Uhs |= UHS_DDR_MODE; + } else { + Uhs &= ~(UHS_DDR_MODE); + } + + MmioWrite32 (DevBase + DW_MMC_UHSREG, Uhs); + + return EFI_SUCCESS; +} + +/** + Supply SD/MMC card with lowest clock frequency at initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitClockFreq ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + UINT32 InitFreq; + + // + // Calculate a divisor for SD clock frequency + // + if (Capability.BaseClkFreq == 0) { + // + // Don't support get Base Clock Frequency information via another method + // + return EFI_UNSUPPORTED; + } + // + // Supply 400KHz clock frequency at initialization phase. + // + InitFreq = DWMMC_INIT_CLOCK_FREQ; + Status = DwMmcHcClockSupply (DevBase, InitFreq, Capability); + if (EFI_ERROR (Status)) { + return Status; + } + MicroSecondDelay (100); + return Status; +} + +STATIC +EFI_STATUS +DwMmcHcWaitReset ( + IN UINTN DevBase, + IN UINT32 ResetValue + ) +{ + UINT32 Timeout; + UINT32 Data; + + MmioWrite32 (DevBase + DW_MMC_CTRL, ResetValue); + + Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + while (Timeout--) { + Data = MmioRead32 (DevBase + DW_MMC_CTRL); + if ((Data & DW_MMC_CTRL_RESET_ALL) == 0) { + return EFI_SUCCESS; + } + gBS->Stall (1); + } + + return EFI_TIMEOUT; +} + +/** + Supply SD/MMC card with maximum voltage at initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitPowerVoltage ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + + MmioWrite32 (DevBase + DW_MMC_PWREN, 0x1); + + Status = DwMmcHcWaitReset (DevBase, DW_MMC_CTRL_RESET_ALL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "DwMmcHcInitPowerVoltage: reset failed due to timeout")); + return Status; + } + + MmioWrite32 (DevBase + DW_MMC_CTRL, DW_MMC_CTRL_INT_EN); + + return EFI_SUCCESS; +} + +/** + Initialize the Timeout Control register with most conservative value at + initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + + @retval EFI_SUCCESS The timeout control register is configured + successfully. + @retval Others The timeout control register isn't configured + successfully. + +**/ +EFI_STATUS +DwMmcHcInitTimeoutCtrl ( + IN UINTN DevBase + ) +{ + UINT32 Data; + + Data = ~0; + MmioWrite32 (DevBase + DW_MMC_TMOUT, Data); + + Data = 0x00FFFFFF; + MmioWrite32 (DevBase + DW_MMC_DEBNCE, Data); + + return EFI_SUCCESS; +} + +/** + Initial SD/MMC host controller with lowest clock frequency, max power and + max timeout value at initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command + to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +DwMmcHcInitHost ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ) +{ + EFI_STATUS Status; + + Status = DwMmcHcInitPowerVoltage (DevBase, Capability); + if (EFI_ERROR (Status)) { + return Status; + } + return Status; +} + +EFI_STATUS +DwMmcHcStartDma ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + UINTN DevBase; + UINT32 Ctrl; + UINT32 Bmod; + UINT32 Timeout; + UINT32 Data; + +// DevIo = Trb->Private->DevIo; + DevBase = Trb->Private->DevBase; + + // + // Reset DMA + // + Status = DwMmcHcWaitReset (DevBase, DW_MMC_CTRL_DMA_RESET); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Timed out waiting for CTRL_DMA_RESET")); + return Status; + } + + Bmod = DW_MMC_IDMAC_SWRESET | MmioRead32 (DevBase + DW_MMC_BMOD); + + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); + + // + // Select IDMAC + // + Ctrl = DW_MMC_CTRL_IDMAC_EN; + Ctrl |= MmioRead32 (DevBase + DW_MMC_CTRL); + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl); + + // + // Enable IDMAC + // + Bmod = DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB; + Bmod |= MmioRead32 (DevBase + DW_MMC_BMOD); + + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); + + return EFI_SUCCESS; +} + +EFI_STATUS +DwMmcHcStopDma ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + UINTN DevBase; + UINT32 Ctrl; + UINT32 Bmod; + + DevBase = Trb->Private->DevBase; + + // + // Disable and reset IDMAC + // + Ctrl = MmioRead32 (DevBase + DW_MMC_CTRL); + Ctrl &= ~DW_MMC_CTRL_IDMAC_EN; + Ctrl |= DW_MMC_CTRL_DMA_RESET; + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl); + + // + // Stop IDMAC + // + Bmod = MmioRead32 (DevBase + DW_MMC_BMOD); + Bmod &= ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE); + Bmod |= DW_MMC_BMOD_SWR; + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod); + + return EFI_SUCCESS; +} + +/** + Build DMA descriptor table for transfer. + + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The DMA descriptor table is created successfully. + @retval Others The DMA descriptor table isn't created successfully. + +**/ +EFI_STATUS +BuildDmaDescTable ( + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_PHYSICAL_ADDRESS Data; + UINT64 DataLen; + UINT64 Entries; + UINT32 Index; + UINT64 Remaining; + UINTN TableSize; + UINTN DevBase; + EFI_STATUS Status; + UINTN Bytes; + UINTN Blocks; + DW_MMC_HC_DMA_DESC_LINE *DmaDesc; + UINT32 DmaDescPhy; + UINT32 Idsts; + UINT32 BytCnt; + UINT32 BlkSize; + + Data = Trb->DataPhy; + DataLen = Trb->DataLen; + DevBase = Trb->Private->DevBase; + // + // Only support 32bit DMA Descriptor Table + // + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) { + return EFI_INVALID_PARAMETER; + } + // + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set + // to 0) for 32-bit address descriptor table. + // + if ((Data & (BIT0 | BIT1)) != 0) { + DEBUG (( + DEBUG_INFO, + "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes!\n", + Data + )); + } + + Entries = (DataLen + DWMMC_DMA_BUF_SIZE - 1) / DWMMC_DMA_BUF_SIZE; + TableSize = Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE); + Blocks = (DataLen + DW_MMC_BLOCK_SIZE - 1) / DW_MMC_BLOCK_SIZE; + + Trb->DmaDescPages = (UINT32)EFI_SIZE_TO_PAGES (Entries * DWMMC_DMA_BUF_SIZE); +/* Status = DevIo->AllocateBuffer ( + DevIo, + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (TableSize), + (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc + );*/ + Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (TableSize), + (VOID *)&Trb->DmaDesc); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (Trb->DmaDesc, TableSize); + Bytes = TableSize; + + Status = DmaMap (MapOperationBusMasterCommonBuffer, + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc, + &Bytes, &Trb->DmaDescPhy, &Trb->DmaMap); +/* Status = DevIo->Map ( + DevIo, + EfiBusMasterCommonBuffer, + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc, + &Bytes, + &Trb->DmaDescPhy, + &Trb->DmaMap + );*/ + + if (EFI_ERROR (Status) || (Bytes != TableSize)) { + // + // Map error or unable to map the whole RFis buffer into a contiguous + // region. + // +/* DevIo->FreeBuffer ( + DevIo, + EFI_SIZE_TO_PAGES (TableSize), + (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc + );*/ + return EFI_OUT_OF_RESOURCES; + } + + if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) { + // + // The DMA doesn't support 64bit addressing. + // + DmaUnmap (Trb->DmaMap); +/* DevIo->Unmap ( + DevIo, + Trb->DmaMap + );*/ + return EFI_DEVICE_ERROR; + } + + if (DataLen < DW_MMC_BLOCK_SIZE) { + BlkSize = DataLen; + BytCnt = DataLen; + Remaining = DataLen; + } else { + BlkSize = DW_MMC_BLOCK_SIZE; + BytCnt = DW_MMC_BLOCK_SIZE * Blocks; + Remaining = DW_MMC_BLOCK_SIZE * Blocks; + } + + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt); + DmaDesc = Trb->DmaDesc; + for (Index = 0; Index < Entries; Index++, DmaDesc++) { + DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH | + DW_MMC_IDMAC_DES0_DIC; + DmaDesc->Des1 = DW_MMC_IDMAC_DES1_BS1 (DWMMC_DMA_BUF_SIZE); + // + // Buffer Address + // + DmaDesc->Des2 = (UINT32)((UINTN)Trb->DataPhy + + (DWMMC_DMA_BUF_SIZE * Index)); + // + // Next Descriptor Address + // + DmaDesc->Des3 = (UINT32)((UINTN)Trb->DmaDescPhy + + sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1)); + Remaining = Remaining - DWMMC_DMA_BUF_SIZE; + } + // + // First Descriptor + // + Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS; + // + // Last Descriptor + // + Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH | + DW_MMC_IDMAC_DES0_DIC); + Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN | + DW_MMC_IDMAC_DES0_LD; + Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining + + DWMMC_DMA_BUF_SIZE); + // + // Set the next field of the Last Descriptor + // + Trb->DmaDesc[Entries - 1].Des3 = 0; + DmaDescPhy = (UINT32)Trb->DmaDescPhy; + + MmioWrite32 (DevBase + DW_MMC_DBADDR, DmaDescPhy); + + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + // + // Clear interrupts + // + Idsts = ~0; + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts); + + return Status; +} + +EFI_STATUS +TransferFifo ( + IN DW_MMC_HC_TRB *Trb + ) +{ + UINTN DevBase; + UINT32 Data; + UINT32 Received; + UINT32 Count; + UINT32 Intsts; + UINT32 Sts; + UINT32 FifoCount; + UINT32 Index; /* count with bytes */ + UINT32 Ascending; + UINT32 Descending; + UINT32 Timeout; + + DevBase = Trb->Private->DevBase; + Received = 0; + Count = 0; + Index = 0; + Ascending = 0; + Descending = ((Trb->DataLen + 3) & ~3) - 4; + Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + do { + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS); + + if (!Trb->Read && (Intsts & DW_MMC_INT_TXDR)) { + Sts = MmioRead32 (DevBase + DW_MMC_STATUS); + + while (!(DW_MMC_STS_FIFO_FULL(Sts)) + && (Received < Trb->DataLen) + && (Intsts & DW_MMC_INT_TXDR)) { + if (Trb->UseBE) { + Data = SwapBytes32 (*(UINT32 *)((UINTN)Trb->Data + Descending)); + Descending = Descending - 4; + } else { + Data = *(UINT32 *)((UINTN)Trb->Data + Ascending); + Ascending += 4; + } + Index += 4; + Received += 4; + + MmioWrite32 (DevBase + DW_MMC_FIFO_START, Data); + + Intsts = DW_MMC_INT_TXDR; + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts); + + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS); + Sts = MmioRead32 (DevBase + DW_MMC_STATUS); + } + Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + goto Verify; + } + + if (Trb->Read && ((Intsts & DW_MMC_INT_RXDR) || + (Intsts & DW_MMC_INT_DTO))) { + Sts = MmioRead32 (DevBase + DW_MMC_STATUS); + // + // Convert to bytes + // + FifoCount = GET_STS_FIFO_COUNT (Sts) << 2; + if ((FifoCount == 0) && (Received < Trb->DataLen)) { + goto Verify; + } + Index = 0; + Count = (MIN (FifoCount, Trb->DataLen) + 3) & ~3; + while (Index < Count) { + Data = MmioRead32 (DevBase + DW_MMC_FIFO_START); + + if (Trb->UseBE) { + *(UINT32 *)((UINTN)Trb->Data + Descending) = SwapBytes32 (Data); + Descending = Descending - 4; + } else { + *(UINT32 *)((UINTN)Trb->Data + Ascending) = Data; + Ascending += 4; + } + Index += 4; + Received += 4; + } /* while */ + Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + } /* if */ + +Verify: + if (Intsts & DW_MMC_INT_DATA_ERR) { + DEBUG ((DEBUG_ERROR, "%a: Data error. CmdIndex=%d, IntStatus=%p\n", + __func__, Trb->Packet->SdMmcCmdBlk->CommandIndex, Intsts)); + return EFI_DEVICE_ERROR; + } + + if (Timeout < DW_MMC_HC_GENERIC_TIMEOUT) { + MicroSecondDelay(1); + } + + if (--Timeout == 0) { + DEBUG ((DEBUG_ERROR, "%a: Timed out. CmdIndex=%d, IntStatus=%p\n", + __func__, Trb->Packet->SdMmcCmdBlk->CommandIndex, Intsts)); + return EFI_TIMEOUT; + } + } while ((Received < Trb->DataLen)); + + return EFI_SUCCESS; +} + +/** + Create a new TRB for the SD/MMC cmd request. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Slot The slot number of the SD card to send the command + to. + @param[in] Packet A pointer to the SD command data structure. + @param[in] Event If Event is NULL, blocking I/O is performed. If + Event is not NULL, then nonblocking I/O is + performed, and Event will be signaled when the + Packet completes. + + @return Created Trb or NULL. + +**/ +DW_MMC_HC_TRB * +DwMmcCreateTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN UINT8 Slot, + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event + ) +{ + DW_MMC_HC_TRB *Trb; + EFI_STATUS Status; + EFI_TPL OldTpl; + EFI_IO_OPERATION_TYPE Flag; + UINTN MapLength; + + Trb = AllocateZeroPool (sizeof (DW_MMC_HC_TRB)); + if (Trb == NULL) { + return NULL; + } + + Trb->Signature = DW_MMC_HC_TRB_SIG; + Trb->Slot = Slot; + Trb->BlockSize = 0x200; + Trb->Packet = Packet; + Trb->Event = Event; + Trb->Started = FALSE; + Trb->Timeout = Packet->Timeout; + Trb->Private = Private; + + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) { + Trb->Data = Packet->InDataBuffer; + Trb->DataLen = Packet->InTransferLength; + Trb->Read = TRUE; + ZeroMem (Trb->Data, Trb->DataLen); + } else if (Packet->OutTransferLength && (Packet->OutDataBuffer != NULL)) { + Trb->Data = Packet->OutDataBuffer; + Trb->DataLen = Packet->OutTransferLength; + Trb->Read = FALSE; + } else if (!Packet->InTransferLength && !Packet->OutTransferLength) { + Trb->Data = NULL; + Trb->DataLen = 0; + } else { + goto Error; + } + + if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) || + ((Private->Slot[Trb->Slot].CardType == SdCardType) && + (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) { + Trb->Mode = SdMmcPioMode; + } else { + if (Trb->Read) { + Flag = EfiBusMasterWrite; + } else { + Flag = EfiBusMasterRead; + } + + if (Private->Slot[Trb->Slot].CardType == SdCardType) { + Trb->UseFifo = TRUE; + } else { + Trb->UseFifo = FALSE; + if (Trb->DataLen) { + MapLength = Trb->DataLen; + Status = DmaMap (Flag, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap); +/* Status = DevIo->Map ( + DevIo, + Flag, + Trb->Data, + &MapLength, + &Trb->DataPhy, + &Trb->DataMap + );*/ + if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) { + Status = EFI_BAD_BUFFER_SIZE; + goto Error; + } + + Status = BuildDmaDescTable (Trb); + if (EFI_ERROR (Status)) { + DmaUnmap(Trb->DataMap); + goto Error; + } + Status = DwMmcHcStartDma (Private, Trb); + if (EFI_ERROR (Status)) { + DmaUnmap(Trb->DataMap); + goto Error; + } + } + } + } /* TuningBlock */ + + if (Event != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Private->Queue, &Trb->TrbList); + gBS->RestoreTPL (OldTpl); + } + + return Trb; + +Error: + return NULL; +} + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + +**/ +VOID +DwMmcFreeTrb ( + IN DW_MMC_HC_TRB *Trb + ) +{ + if (Trb->DmaMap != NULL) { + DmaUnmap (Trb->DmaMap); + } + if (Trb->DataMap != NULL) { + DmaUnmap (Trb->DataMap); + } + FreePool (Trb); +} + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +DwMmcCheckTrbEnv ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + return EFI_SUCCESS; +} + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +DwMmcWaitTrbEnv ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status + // Register + // + Packet = Trb->Packet; + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = DwMmcCheckTrbEnv (Private, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + // + // Stall for 1 microsecond. + // + gBS->Stall (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +EFI_STATUS +DwEmmcExecTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINTN DevBase; + UINT32 Cmd; + UINT32 MmcStatus; + UINT32 IntStatus; + UINT32 Argument; + UINT32 ErrMask; + UINT32 Timeout; + + Packet = Trb->Packet; + DevBase = Trb->Private->DevBase; + + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + // + // Wait until MMC is idle + // + do { + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS); + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); + + IntStatus = ~0; + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex); + if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) || + (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) { + switch (Packet->SdMmcCmdBlk->CommandIndex) { + case EMMC_SET_RELATIVE_ADDR: + Cmd |= BIT_CMD_SEND_INIT; + break; + case EMMC_SEND_STATUS: + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case EMMC_STOP_TRANSMISSION: + Cmd |= BIT_CMD_STOP_ABORT_CMD; + break; + } + if (Packet->InTransferLength) { + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED | + BIT_CMD_READ; + } else if (Packet->OutTransferLength) { + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED | + BIT_CMD_WRITE; + } + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; + } else { + switch (Packet->SdMmcCmdBlk->CommandIndex) { + case EMMC_GO_IDLE_STATE: + Cmd |= BIT_CMD_SEND_INIT; + break; + case EMMC_SEND_OP_COND: + Cmd |= BIT_CMD_RESPONSE_EXPECT; + break; + case EMMC_ALL_SEND_CID: + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE | + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; + break; + } + } + switch (Packet->SdMmcCmdBlk->ResponseType) { + case SdMmcResponseTypeR2: + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_LONG_RESPONSE; + break; + case SdMmcResponseTypeR3: + Cmd |= BIT_CMD_RESPONSE_EXPECT; + break; + } + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START; + + Argument = Packet->SdMmcCmdBlk->CommandArgument; + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument); + + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO | + DW_MMC_INT_RCRC | DW_MMC_INT_RE; + ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE; + do { + Timeout = 10000; + if (--Timeout == 0) { + break; + } + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS); + if (IntStatus & ErrMask) { + return EFI_DEVICE_ERROR; + } + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) { + // + // Transfer Not Done + // + MicroSecondDelay (10); + continue; + } + MicroSecondDelay (10); + } while (!(IntStatus & DW_MMC_INT_CMD_DONE)); + switch (Packet->SdMmcCmdBlk->ResponseType) { + case SdMmcResponseTypeR1: + case SdMmcResponseTypeR1b: + case SdMmcResponseTypeR3: + case SdMmcResponseTypeR4: + case SdMmcResponseTypeR5: + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0); + break; + case SdMmcResponseTypeR2: + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0); + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1); + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2); + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3); + break; + } + + // + // The workaround on EMMC_SEND_CSD is used to be compatible with SDHC. + // + if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_CSD) { + { + UINT32 Buf[4]; + ZeroMem (Buf, sizeof (Buf)); + CopyMem ( + (UINT8 *)Buf, + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1, + sizeof (Buf) - 1 + ); + CopyMem ( + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0, + (UINT8 *)Buf, + sizeof (Buf) - 1 + ); + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DwSdExecTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINTN DevBase; + UINT32 Cmd; + UINT32 MmcStatus; + UINT32 IntStatus; + UINT32 Argument; + UINT32 ErrMask; + UINT32 Timeout; + UINT32 Idsts; + UINT32 BytCnt; + UINT32 BlkSize; + EFI_STATUS Status; + + Packet = Trb->Packet; + DevBase = Trb->Private->DevBase; + + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + // + // Wait until MMC is idle + // + do { + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS); + } while (MmcStatus & DW_MMC_STS_DATA_BUSY); + + IntStatus = ~0; + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus); + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex); + if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) || + (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) { + switch (Packet->SdMmcCmdBlk->CommandIndex) { + case SD_SET_RELATIVE_ADDR: + Cmd |= BIT_CMD_SEND_INIT; + break; + case SD_STOP_TRANSMISSION: + Cmd |= BIT_CMD_STOP_ABORT_CMD; + break; + case SD_SEND_SCR: + Trb->UseBE = TRUE; + break; + } + if (Packet->InTransferLength) { + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED | + BIT_CMD_READ; + } else if (Packet->OutTransferLength) { + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED | + BIT_CMD_WRITE; + } + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_SEND_AUTO_STOP; + } else { + switch (Packet->SdMmcCmdBlk->CommandIndex) { + case SD_GO_IDLE_STATE: + Cmd |= BIT_CMD_SEND_INIT; + break; + } + } + switch (Packet->SdMmcCmdBlk->ResponseType) { + case SdMmcResponseTypeR2: + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_LONG_RESPONSE; + break; + case SdMmcResponseTypeR3: + Cmd |= BIT_CMD_RESPONSE_EXPECT; + break; + case SdMmcResponseTypeR1b: + case SdMmcResponseTypeR4: + case SdMmcResponseTypeR6: + case SdMmcResponseTypeR7: + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; + break; + } + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START; + + if (Trb->UseFifo == TRUE) { + BytCnt = Trb->Read ? Packet->InTransferLength : Packet->OutTransferLength; + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt); + if (Trb->Read) { + if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) { + BlkSize = DW_MMC_BLOCK_SIZE; + } else { + BlkSize = Packet->InTransferLength; + } + } + else { + if (Packet->OutTransferLength > DW_MMC_BLOCK_SIZE) { + BlkSize = DW_MMC_BLOCK_SIZE; + } else { + BlkSize = Packet->OutTransferLength; + } + } + + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize); + + if (Trb->DataLen) { + Status = DwMmcHcWaitReset (DevBase, DW_MMC_CTRL_FIFO_RESET); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: FIFO reset timed out. CmdIndex=%d\n", + __func__, Packet->SdMmcCmdBlk->CommandIndex)); + } + } + } + + Argument = Packet->SdMmcCmdBlk->CommandArgument; + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument); + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd); + ArmDataSynchronizationBarrier (); + ArmInstructionSynchronizationBarrier (); + + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO | + DW_MMC_INT_RCRC | DW_MMC_INT_RE; + ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE; + if (Packet->InTransferLength || Packet->OutTransferLength) { + ErrMask |= DW_MMC_INT_DCRC; + } + + Timeout = 10000; + do { + if (--Timeout == 0) { + break; + } + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS); + MicroSecondDelay (1); + } while (!(IntStatus & DW_MMC_INT_CMD_DONE)); + + if (IntStatus & ErrMask) { + DEBUG ((DEBUG_ERROR, "%a: Command error. CmdIndex=%d, IntStatus=%p\n", + __func__, Packet->SdMmcCmdBlk->CommandIndex, IntStatus)); + return EFI_DEVICE_ERROR; + } + + if (Trb->DataLen) { + if (Trb->UseFifo == TRUE) { + Status = TransferFifo (Trb); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + if (Packet->InTransferLength) { + do { + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS); + } while ((Idsts & DW_MMC_IDSTS_RI) == 0); + Status = DwMmcHcStopDma (Private, Trb); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (Packet->OutTransferLength) { + do { + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS); + } while ((Idsts & DW_MMC_IDSTS_TI) == 0); + Status = DwMmcHcStopDma (Private, Trb); + if (EFI_ERROR (Status)) { + return Status; + } + } /* Packet->InTransferLength */ + } /* UseFifo */ + } /* Trb->DataLen */ + + switch (Packet->SdMmcCmdBlk->ResponseType) { + case SdMmcResponseTypeR1: + case SdMmcResponseTypeR1b: + case SdMmcResponseTypeR3: + case SdMmcResponseTypeR4: + case SdMmcResponseTypeR5: + case SdMmcResponseTypeR6: + case SdMmcResponseTypeR7: + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0); + break; + case SdMmcResponseTypeR2: + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0); + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1); + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2); + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3); + break; + } + + // + // The workaround on SD_SEND_CSD/CID is used to be compatible with SDHC. + // + if (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CSD + || Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CID) { + { + UINT32 Buf[4]; + ZeroMem (Buf, sizeof (Buf)); + CopyMem ( + (UINT8 *)Buf, + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1, + sizeof (Buf) - 1 + ); + CopyMem ( + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0, + (UINT8 *)Buf, + sizeof (Buf) - 1 + ); + } + } + + return EFI_SUCCESS; +} + +/** + Execute the specified TRB. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the + host controller. + +**/ +EFI_STATUS +DwMmcExecTrb ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 Slot; + + Slot = Trb->Slot; + if (Private->Slot[Slot].CardType == EmmcCardType) { + Status = DwEmmcExecTrb (Private, Trb); + } else if (Private->Slot[Slot].CardType == SdCardType) { + Status = DwSdExecTrb (Private, Trb); + } else { + ASSERT (0); + } + return Status; +} + +/** + Check the TRB execution result. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +DwMmcCheckTrbResult ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT32 Idsts; + UINTN DevBase; + UINT32 IntStatus; + + DevBase = Private->DevBase; + Packet = Trb->Packet; + if (Trb->UseFifo == TRUE) { + if (Trb->DataLen) { + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS); + // + // Check Auto CMD12 completion + // + if (!(IntStatus & DW_MMC_INT_ACD)) { + return EFI_NOT_READY; + } + + // + // Check data trans over + // + if (!(IntStatus & DW_MMC_INT_DTO)) { + return EFI_NOT_READY; + } + + // + // There will be some errors reported (SBE, HTO, DRT, DCRC, RCRC) + // depending on the command sent (read/write, single/multi block). + // + // Not sure why this happens (do we need to manually stop the command?), + // but it does not seem to affect operation in any way. + // All data is correctly transferred and the FIFO is empty by the time + // we reach this code path. + // + // Each transfer is validated in TransferFifo(), which would fail on any + // of the error states above and more. + // Interrupt status is cleared before a new command is issued, no need + // to do it here. + // + } + return EFI_SUCCESS; + } + if (Packet->InTransferLength) { + do { + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS); + } while ((Idsts & BIT1) == 0); + } else if (Packet->OutTransferLength) { + do { + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS); + } while ((Idsts & BIT0) == 0); + } else { + return EFI_SUCCESS; + } + Idsts = ~0; + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts); + + return EFI_SUCCESS; +} + +/** + Wait for the TRB execution result. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +DwMmcWaitTrbResult ( + IN DW_MMC_HC_PRIVATE_DATA *Private, + IN DW_MMC_HC_TRB *Trb + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + Packet = Trb->Packet; + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status + // Register + // + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = DwMmcCheckTrbResult (Private, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + // + // Stall for 1 microsecond. + // + gBS->Stall (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.h new file mode 100644 index 0000000..9a7b4da --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/DwMmcHci.h @@ -0,0 +1,988 @@ +/** @file + + Provides some data structure definitions used by the SD/MMC host controller + driver. + + Copyright (c) 2015-2021, Intel Corporation. All rights reserved. + Copyright (c) 2018, Linaro Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _DW_MMC_HCI_H_ +#define _DW_MMC_HCI_H_ + +#include +#include + +#include + +// +// SD Host Controller SlotInfo Register Offset +// +#define DW_MMC_HC_SLOT_OFFSET 0x40 + +#define DW_MMC_HC_MAX_SLOT 1 + +// +// SD Host Controller MMIO Register Offset +// +#define DW_MMC_CTRL 0x000 +#define DW_MMC_PWREN 0x004 +#define DW_MMC_CLKDIV 0x008 +#define DW_MMC_CLKSRC 0x00c +#define DW_MMC_CLKENA 0x010 +#define DW_MMC_TMOUT 0x014 +#define DW_MMC_CTYPE 0x018 +#define DW_MMC_BLKSIZ 0x01c +#define DW_MMC_BYTCNT 0x020 +#define DW_MMC_INTMASK 0x024 +#define DW_MMC_CMDARG 0x028 +#define DW_MMC_CMD 0x02c +#define DW_MMC_RESP0 0x030 +#define DW_MMC_RESP1 0x034 +#define DW_MMC_RESP2 0x038 +#define DW_MMC_RESP3 0x03c +#define DW_MMC_RINTSTS 0x044 +#define DW_MMC_STATUS 0x048 +#define DW_MMC_FIFOTH 0x04c +#define DW_MMC_GPIO 0x058 +#define DW_MMC_DEBNCE 0x064 +#define DW_MMC_USRID 0x068 +#define DW_MMC_VERID 0x06c +#define DW_MMC_HCON 0x070 +#define DW_MMC_UHSREG 0x074 +#define DW_MMC_BMOD 0x080 +#define DW_MMC_DBADDR 0x088 +#define DW_MMC_IDSTS 0x08c +#define DW_MMC_IDINTEN 0x090 +#define DW_MMC_DSCADDR 0x094 +#define DW_MMC_BUFADDR 0x098 +#define DW_MMC_CARDTHRCTL 0x100 +#define DW_MMC_UHSREG_EXT 0x108 +#define DW_MMC_ENABLE_SHIFT 0x110 +#define DW_MMC_FIFO_START 0x200 + +#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf) +#define IDSTS_FSM_DMA_IDLE 0 +#define IDSTS_FSM_DMA_SUSPEND 1 +#define IDSTS_FSM_DESC_RD 2 +#define IDSTS_FSM_DESC_CHK 3 +#define IDSTS_FSM_DMA_RD_REQ_WAIT 4 +#define IDSTS_FSM_DMA_WR_REQ_WAIT 5 +#define IDSTS_FSM_DMA_RD 6 +#define IDSTS_FSM_DMA_WR 7 +#define IDSTS_FSM_DESC_CLOSE 8 +#define IDSTS_FSM_MASK 0xf + +#define CMD_UPDATE_CLK 0x80202000 +#define CMD_START_BIT (1 << 31) + +#define MMC_8BIT_MODE (1 << 16) +#define MMC_4BIT_MODE (1 << 0) +#define MMC_1BIT_MODE 0 + +#define DW_MMC_BLOCK_SIZE 512 + +#define CMD_INDEX_MASK 0x3F +#define BIT_CMD_RESPONSE_EXPECT (1 << 6) +#define BIT_CMD_LONG_RESPONSE (1 << 7) +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8) +#define BIT_CMD_DATA_EXPECTED (1 << 9) +#define BIT_CMD_READ (0 << 10) +#define BIT_CMD_WRITE (1 << 10) +#define BIT_CMD_BLOCK_TRANSFER (0 << 11) +#define BIT_CMD_STREAM_TRANSFER (1 << 11) +#define BIT_CMD_SEND_AUTO_STOP (1 << 12) +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) +#define BIT_CMD_STOP_ABORT_CMD (1 << 14) +#define BIT_CMD_SEND_INIT (1 << 15) +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21) +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22) +#define BIT_CMD_CCS_EXPECTED (1 << 23) +#define BIT_CMD_ENABLE_BOOT (1 << 24) +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25) +#define BIT_CMD_DISABLE_BOOT (1 << 26) +#define BIT_CMD_MANDATORY_BOOT (0 << 27) +#define BIT_CMD_ALTERNATE_BOOT (1 << 27) +#define BIT_CMD_VOLT_SWITCH (1 << 28) +#define BIT_CMD_USE_HOLD_REG (1 << 29) +#define BIT_CMD_START (1 << 31) + +#define CMD_INDEX(x) ((x) & CMD_INDEX_MASK) + +#define DW_MMC_INT_EBE (1 << 15) /* End-bit Err */ +#define DW_MMC_INT_ACD (1 << 14) /* Auto command done */ +#define DW_MMC_INT_SBE (1 << 13) /* Start-bit Err */ +#define DW_MMC_INT_HLE (1 << 12) /* Hardware-lock Err */ +#define DW_MMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */ +#define DW_MMC_INT_HTO (1 << 10) /* Data starvation by host timeout */ +#define DW_MMC_INT_DRT (1 << 9) /* Data timeout */ +#define DW_MMC_INT_RTO (1 << 8) /* Response timeout */ +#define DW_MMC_INT_DCRC (1 << 7) /* Data CRC err */ +#define DW_MMC_INT_RCRC (1 << 6) /* Response CRC err */ +#define DW_MMC_INT_RXDR (1 << 5) /* Receive FIFO data request */ +#define DW_MMC_INT_TXDR (1 << 4) /* Transmit FIFO data request */ +#define DW_MMC_INT_DTO (1 << 3) /* Data trans over */ +#define DW_MMC_INT_CMD_DONE (1 << 2) /* Command done */ +#define DW_MMC_INT_RE (1 << 1) /* Response error */ + +#define DW_MMC_INT_DATA_ERR (DW_MMC_INT_EBE |\ + DW_MMC_INT_SBE |\ + DW_MMC_INT_HLE |\ + DW_MMC_INT_FRUN |\ + DW_MMC_INT_DCRC |\ + DW_MMC_INT_HTO |\ + DW_MMC_INT_DRT) + +#define DW_MMC_IDMAC_DES0_DIC (1 << 1) +#define DW_MMC_IDMAC_DES0_LD (1 << 2) +#define DW_MMC_IDMAC_DES0_FS (1 << 3) +#define DW_MMC_IDMAC_DES0_CH (1 << 4) +#define DW_MMC_IDMAC_DES0_ER (1 << 5) +#define DW_MMC_IDMAC_DES0_CES (1 << 30) +#define DW_MMC_IDMAC_DES0_OWN (1 << 31) +#define DW_MMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) +#define DW_MMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) +#define DW_MMC_IDMAC_SWRESET (1 << 0) +#define DW_MMC_IDMAC_FB (1 << 1) +#define DW_MMC_IDMAC_ENABLE (1 << 7) + +#define DW_MMC_CTRL_RESET (1 << 0) +#define DW_MMC_CTRL_FIFO_RESET (1 << 1) +#define DW_MMC_CTRL_DMA_RESET (1 << 2) +#define DW_MMC_CTRL_INT_EN (1 << 4) +#define DW_MMC_CTRL_DMA_EN (1 << 5) +#define DW_MMC_CTRL_IDMAC_EN (1 << 25) +#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET) + +#define DW_MMC_STS_DATA_BUSY (1 << 9) +#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) /* Number of filled locations in FIFO */ +#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff) +#define DW_MMC_STS_FIFO_FULL(x) (((x) >> 3) & 1) + +#define DW_MMC_BMOD_SWR (1 << 0) /* Software Reset */ +#define DW_MMC_BMOD_FB (1 << 1) /* Fix Burst */ +#define DW_MMC_BMOD_DE (1 << 7) /* IDMAC Enable */ + +#define DW_MMC_IDSTS_TI (1 << 0) /* Transmit Interrupt */ +#define DW_MMC_IDSTS_RI (1 << 1) /* Receive Interrupt */ + +#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff) +#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16) +#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28) + +#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16) +#define DW_MMC_CARD_RD_THR_EN (1 << 0) + +#define UHS_DDR_MODE (1 << 16) + +#define GENCLK_DIV 7 + +#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8) +#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13) +#define DW_MMC_GPIO_CLK_ENABLE BIT16 + +#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16) +#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21) +#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26) + +#define DWMMC_DMA_BUF_SIZE (512 * 8) +#define DWMMC_FIFO_THRESHOLD 16 + +#define DWMMC_INIT_CLOCK_FREQ 400 /* KHz */ + +// +// The transfer modes supported by SD Host Controller +// Simplified Spec 3.0 Table 1-2 +// +typedef enum { + SdMmcNoData, + SdMmcPioMode, + SdMmcSdmaMode, + SdMmcAdmaMode +} DW_MMC_HC_TRANSFER_MODE; + +// +// The maximum data length of each descriptor line +// +#define ADMA_MAX_DATA_PER_LINE 0x10000 + +typedef struct { + UINT32 Des0; + UINT32 Des1; + UINT32 Des2; + UINT32 Des3; +} DW_MMC_HC_DMA_DESC_LINE; + +#define SD_MMC_SDMA_BOUNDARY 512 * 1024 +#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1)) + +typedef struct { + UINT8 FirstBar:3; // bit 0:2 + UINT8 Reserved:1; // bit 3 + UINT8 SlotNum:3; // bit 4:6 + UINT8 Reserved1:1; // bit 7 +} DW_MMC_HC_SLOT_INFO; + +/** + Dump the content of SD/MMC host controller's Capability Register. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The buffer to store the capability data. + +**/ +VOID +DumpCapabilityReg ( + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP *Capability + ); + +#if 0 +/** + Read SlotInfo register from SD/MMC host controller pci config space. + + @param[in] PciIo The PCI IO protocol instance. + @param[out] FirstBar The buffer to store the first BAR value. + @param[out] SlotNum The buffer to store the supported slot number. + + @retval EFI_SUCCESS The operation succeeds. + @retval Others The operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcGetSlotInfo ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT UINT8 *FirstBar, + OUT UINT8 *SlotNum + ); +#endif + +#ifdef DWMMC_PCI +/** + Read/Write specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcRwMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ); +#else +/** + Read/Write specified SD/MMC host controller mmio register. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcRwMmio ( + IN UINTN DevBase, + IN UINT32 Offset, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ); +#endif + +#ifdef DWMMC_PCI +/** + Do OR operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcOrMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *OrData + ); +#else +/** + Do OR operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcOrMmio ( + IN UINTN DevBase, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *OrData + ); +#endif + +#ifdef DWMMC_PCI +/** + Do AND operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcAndMmio ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *AndData + ); +#else +/** + Do AND operation with the value of the specified SD/MMC host controller mmio register. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcAndMmio ( + IN UINTN DevBase, + IN UINT32 Offset, + IN UINT8 Count, + IN VOID *AndData + ); +#endif + +#ifdef DWMMC_PCI +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] BarIndex The BAR index of the standard PCI Configuration + header to use as the base address for the memory + operation to perform. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcWaitMmioSet ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 BarIndex, + IN UINT32 Offset, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ); +#else +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Offset The offset within the selected BAR to start the + memory operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +DwMmcHcWaitMmioSet ( + IN UINTN DevBase, + IN UINT32 Offset, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ); +#endif + +#ifdef DWMMC_PCI +/** + Software reset the specified SD/MMC host controller. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +DwMmcHcReset ( +fark + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#else +/** + Software reset the specified SD/MMC host controller. + + @param[in] DevIo The DEVICE IO protocol instance. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +DwMmcHcReset ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#endif + +#ifdef DWMMC_PCI +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcEnableInterrupt ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); +#else +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcEnableInterrupt ( + IN UINTN DevBase + ); +#endif + +#ifdef DWMMC_PCI +/** + Get the capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcGetCapability ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT DW_MMC_HC_SLOT_CAP *Capability + ); +#else +/** + Get the capability data from the specified slot. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcGetCapability ( + IN UINTN DevBase, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT DW_MMC_HC_SLOT_CAP *Capability + ); +#endif + +#if 0 +/** + Get the maximum current capability data from the specified slot. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MaxCurrent The buffer to store the maximum current capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +DwMmcHcGetMaxCurrent ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + OUT UINT64 *MaxCurrent + ); +#endif + +#ifdef DWMMC_PCI +/** + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MediaPresent The pointer to the media present boolean value. + + @retval EFI_SUCCESS There is no media change happened. + @retval EFI_MEDIA_CHANGED There is media change happened. + @retval Others The detection fails. + +**/ +EFI_STATUS +DwMmcHcCardDetect ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT BOOLEAN *MediaPresent + ); +#else +/** + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] MediaPresent The pointer to the media present boolean value. + + @retval EFI_SUCCESS There is no media change happened. + @retval EFI_MEDIA_CHANGED There is media change happened. + @retval Others The detection fails. + +**/ +EFI_STATUS +DwMmcHcCardDetect ( + IN UINTN DevBase, + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT BOOLEAN *MediaPresent + ); +#endif + +#ifdef DWMMC_PCI +/** + Stop SD/MMC card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. + @retval Others Fail to stop SD/MMC clock. + +**/ +EFI_STATUS +DwMmcHcStopClock ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); + +/** + SD/MMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcClockSupply ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT64 ClockFreq, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#else +/** + Stop SD/MMC card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + + @retval EFI_SUCCESS Succeed to stop SD/MMC clock. + @retval Others Fail to stop SD/MMC clock. + +**/ +EFI_STATUS +DwMmcHcStopClock ( + IN UINTN DevBase + ); + +/** + SD/MMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcClockSupply ( + IN UINTN DevBase, + IN UINT64 ClockFreq, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#endif + +#if 0 +/** + SD/MMC bus power control. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] PowerCtrl The value setting to the power control register. + + @retval TRUE There is a SD/MMC card attached. + @retval FALSE There is no a SD/MMC card attached. + +**/ +EFI_STATUS +DwMmcHcPowerControl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN UINT8 PowerCtrl + ); +#endif + +#ifdef DWMMC_PCI +/** + Set the SD/MMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +DwMmcHcSetBusWidth ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN BOOLEAN IsDdr, + IN UINT16 BusWidth + ); +#else +/** + Set the SD/MMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +DwMmcHcSetBusWidth ( + IN UINTN DevBase, + IN BOOLEAN IsDdr, + IN UINT16 BusWidth + ); +#endif + +#ifdef DWMMC_PCI +/** + Supply SD/MMC card with lowest clock frequency at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitClockFreq ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#else +/** + Supply SD/MMC card with lowest clock frequency at initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitClockFreq ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#endif + +#ifdef DWMMC_PCI +/** + Supply SD/MMC card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitPowerVoltage ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#else +/** + Supply SD/MMC card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +DwMmcHcInitPowerVoltage ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#endif + +#ifdef DWMMC_PCI +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +DwMmcHcInitTimeoutCtrl ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot + ); +#else +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +DwMmcHcInitTimeoutCtrl ( + IN UINTN DevBase + ); +#endif + +#ifdef DWMMC_PCI +/** + Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +DwMmcHcInitHost ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 Slot, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#else +/** + Initial SD/MMC host controller with lowest clock frequency, max power and + max timeout value at initialization. + + @param[in] DevIo The DEVICE IO protocol instance. + @param[in] Capability The capability of the slot. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +DwMmcHcInitHost ( + IN UINTN DevBase, + IN DW_MMC_HC_SLOT_CAP Capability + ); +#endif + +#endif /* _DW_MMC_HCI_H_ */ diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/EmmcDevice.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/EmmcDevice.c new file mode 100644 index 0000000..2f3c550 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/EmmcDevice.c @@ -0,0 +1,1035 @@ +/** @file + This file provides some helper functions which are specific for EMMC device. + + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved. + Copyright (c) 2018, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include + +#include "DwMmcHcDxe.h" + +#define EMMC_GET_STATE(x) (((x) >> 9) & 0xf) +#define EMMC_STATE_IDLE 0 +#define EMMC_STATE_READY 1 +#define EMMC_STATE_IDENT 2 +#define EMMC_STATE_STBY 3 +#define EMMC_STATE_TRAN 4 +#define EMMC_STATE_DATA 5 +#define EMMC_STATE_RCV 6 +#define EMMC_STATE_PRG 7 +#define EMMC_STATE_DIS 8 +#define EMMC_STATE_BTST 9 +#define EMMC_STATE_SLP 10 + +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used + +/** + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to + make it go to Idle State. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Slot The slot number of the SD card to send the command + to. + + @retval EFI_SUCCESS The EMMC device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +EmmcReset ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc; + SdMmcCmdBlk.ResponseType = 0; + SdMmcCmdBlk.CommandArgument = 0; + + gBS->Stall (1000); + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_OP_COND to the EMMC device to get the data of the OCR + register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in, out] Argument On input, the argument of SEND_OP_COND is to send + to the device. + On output, the argument is the value of OCR + register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetOcr ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN OUT UINT32 *Argument + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3; + SdMmcCmdBlk.CommandArgument = *Argument; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + *Argument = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send + the data of their CID registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetAllCid ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = 0; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device + Address (RCA). + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSetRca ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_CSD to the EMMC device to get the data of the CSD register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of + this buffer as the content of this byte is + meaningless even if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + OUT EMMC_CSD *Csd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + // + // Copy 128bit data for CSD structure. + // + CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1); + } + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSelect ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD + register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[out] ExtCsd The buffer to store the content of the EXT_CSD + register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcGetExtCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + OUT EMMC_EXT_CSD *ExtCsd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0x00000000; + + Packet.InDataBuffer = ExtCsd; + Packet.InTransferLength = sizeof (EMMC_EXT_CSD); + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + return Status; +} + +/** + Send command SWITCH to the EMMC device to switch the mode of operation of the + selected Device or modifies the EXT_CSD registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Access The access mode of SWTICH command. + @param[in] Index The offset of the field to be access. + @param[in] Value The value to be set to the specified field of + EXT_CSD register. + @param[in] CmdSet The value of CmdSet field of EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 Access, + IN UINT8 Index, + IN UINT8 Value, + IN UINT8 CmdSet + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SWITCH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | \ + (Value << 8) | CmdSet; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed EMMC device to get its status + register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSendStatus ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *DevStatus = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling + point detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSendTuningBlk ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 BusWidth + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[128]; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + if (BusWidth == 8) { + Packet.InTransferLength = sizeof (TuningBlock); + } else { + Packet.InTransferLength = 64; + } + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Tunning the clock to get HS200 optimal sampling point. + + Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes + the tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcTuningClkForHs200 ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 BusWidth + ) +{ + return EFI_SUCCESS; +} + +/** + Switch the bus width to specified width. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. + Otherwise use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchBusWidth ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth); + if (BusWidth == 1) { + Value = 0; + } else { + if (BusWidth == 4) { + Value = 1; + } else if (BusWidth == 8) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + if (IsDdr) { + Value += 4; + } + } + + CmdSet = 0; + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", + BusWidth, + Status + )); + return Status; + } + + do { + Status = EmmcSendStatus (PassThru, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "EmmcSwitchBusWidth: Send status fails with %r\n", + Status + )); + return Status; + } + // + // Check the switch operation is really successful or not. + // + } while ((DevStatus & 0xf) == EMMC_STATE_PRG); + + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +/** + Switch the clock frequency to the specified value. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] HsTiming The value to be written to HS_TIMING field of + EXT_CSD register. + @param[in] ClockFreq The max clock frequency to be set, the unit is MHz. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchClockFreq ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN UINT8 HsTiming, + IN UINT32 ClockFreq + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + DW_MMC_HC_PRIVATE_DATA *Private; + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming); + Value = HsTiming; + CmdSet = 0; + + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", + HsTiming, + Status + )); + return Status; + } + + Status = EmmcSendStatus (PassThru, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "EmmcSwitchClockFreq: Send status fails with %r\n", + Status + )); + return Status; + } + // + // Check the switch operation is really successful or not. + // + if ((DevStatus & BIT7) != 0) { + DEBUG (( + DEBUG_ERROR, + "EmmcSwitchClockFreq: The switch operation fails as DevStatus 0x%08x\n", + DevStatus + )); + return EFI_DEVICE_ERROR; + } + // + // Convert the clock freq unit from MHz to KHz. + // + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, Private->Capability[0]); + + return Status; +} + +/** + Switch to the High Speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. + Otherwise use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchToHighSpeed ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN UINT32 ClockFreq, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + + HsTiming = 1; + Status = EmmcSwitchClockFreq (DevBase, PassThru, Rca, HsTiming, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + return EFI_SUCCESS; +} + +/** + Switch to the HS200 timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSwitchToHS200 ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN UINT32 ClockFreq, + IN UINT8 BusWidth + ) +{ + return EFI_SUCCESS; +} + +/** + Switch the high speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8. + + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcSetBusMode ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca + ) +{ + EFI_STATUS Status; + EMMC_CSD Csd; + EMMC_EXT_CSD ExtCsd; + UINT8 HsTiming; + BOOLEAN IsDdr; + UINT32 DevStatus; + UINT32 ClockFreq; + UINT8 BusWidth; + DW_MMC_HC_PRIVATE_DATA *Private; + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); + ASSERT (Private->Capability[0].BaseClkFreq != 0); + + Status = EmmcGetCsd (PassThru, Rca, &Csd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status)); + return Status; + } + + Status = EmmcSelect (PassThru, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status)); + return Status; + } + + do { + Status = EmmcSendStatus (PassThru, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "EmmcSetBusMode: Get Status fails with %r\n", + Status + )); + return Status; + } + } while (EMMC_GET_STATE (DevStatus) != EMMC_STATE_TRAN); + + BusWidth = 1; + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, FALSE, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + BusWidth = Private->Capability[0].BusWidth; + // + // Get Deivce_Type from EXT_CSD register. + // + Status = EmmcGetExtCsd (PassThru, &ExtCsd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status)); + return Status; + } + + // + // Calculate supported bus speed/bus width/clock frequency. + // + HsTiming = 0; + IsDdr = FALSE; + ClockFreq = 0; + if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && + (Private->Capability[0].Sdr104 != 0)) { + HsTiming = 2; + IsDdr = FALSE; + ClockFreq = 200; + } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && + (Private->Capability[0].Ddr50 != 0)) { + HsTiming = 1; + IsDdr = TRUE; + ClockFreq = 52; + } else if (((ExtCsd.DeviceType & BIT1) != 0) && + (Private->Capability[0].HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + } else if (((ExtCsd.DeviceType & BIT0) != 0) && + (Private->Capability[0].HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 26; + } + + if ((ClockFreq == 0) || (HsTiming == 0)) { + // + // Continue using default setting. + // + return EFI_SUCCESS; + } + + DEBUG (( + DEBUG_INFO, + "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", + HsTiming, + ClockFreq, + BusWidth, + IsDdr ? "TRUE" : "FALSE" + )); + + if (HsTiming == 2) { + // + // Execute HS200 timing switch procedure + // + Status = EmmcSwitchToHS200 (DevBase, PassThru, Rca, ClockFreq, BusWidth); + } else { + // + // Execute High Speed timing switch procedure + // + Status = EmmcSwitchToHighSpeed ( + DevBase, + PassThru, + Rca, + ClockFreq, + IsDdr, + BusWidth + ); + } + + DEBUG (( + DEBUG_INFO, + "EmmcSetBusMode: Switch to %a %r\n", + (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), + Status + )); + + return Status; +} + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcIdentification ( + IN DW_MMC_HC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN DevBase; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + UINT32 Ocr; + UINT16 Rca; + UINT32 DevStatus; + UINT32 Timeout; + + DevBase = Private->DevBase; + PassThru = &Private->PassThru; + + Status = EmmcReset (PassThru); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "EmmcIdentification: Executing Cmd0 fails with %r\n", + Status + )); + return Status; + } + + Timeout = 100; + do { + Ocr = EMMC_CMD1_CAPACITY_GREATER_THAN_2GB; + Status = EmmcGetOcr (PassThru, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "EmmcIdentification: Executing Cmd1 fails with %r\n", + Status + )); + return Status; + } + if (--Timeout <= 0) { + return EFI_DEVICE_ERROR; + } + MicroSecondDelay (100); + } while ((Ocr & BIT31) == 0); + + Status = EmmcGetAllCid (PassThru); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "EmmcIdentification: Executing Cmd2 fails with %r\n", + Status + )); + return Status; + } + // + // valid RCA starts from 1. + // Here we takes a simple formula to calculate the RCA. + // Don't support multiple devices on the slot, that is + // shared bus slot feature. + // + Rca = 1; + Status = EmmcSetRca (PassThru, Rca); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "EmmcIdentification: Executing Cmd3 fails with %r\n", + Status + )); + return Status; + } + // + // Enter Data Tranfer Mode. + // + DEBUG (( + DEBUG_INFO, + "EmmcIdentification: Found a EMMC device at RCA [%d]\n", + Rca + )); + Private->Slot[0].CardType = EmmcCardType; + + Status = EmmcSetBusMode (DevBase, PassThru, Rca); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Exit DATA Mode. + // + do { + Status = EmmcSendStatus (PassThru, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "EmmcSwitchBusWidth: Send status fails with %r\n", + Status + )); + return Status; + } + } while ((DevStatus & 0xf) == EMMC_STATE_DATA); + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/SdDevice.c b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/SdDevice.c new file mode 100644 index 0000000..3523b90 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Drivers/DwMmcHcDxe/SdDevice.c @@ -0,0 +1,1110 @@ +/** @file + This file provides some helper functions which are specific for SD card + device. + + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved. + Copyright (c) 2018, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include + +#include "DwMmcHcDxe.h" + +/** + Send command GO_IDLE_STATE to the device to make it go to Idle State. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + + @retval EFI_SUCCESS The SD device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +SdCardReset ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + //Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_IF_COND to the device to inquiry the SD Memory Card + interface condition. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] SupplyVoltage The supplied voltage by the host. + @param[in] CheckPattern The check pattern to be sent to the device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardVoltageCheck ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 SupplyVoltage, + IN UINT8 CheckPattern + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7; + SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + if (!EFI_ERROR (Status)) { + if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) { + return EFI_DEVICE_ERROR; + } + } + + return Status; +} + +/** + Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SDIO Simplified Spec 3 Section 3.2 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18R The boolean to show if it should switch to 1.8v. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdioSendOpCond ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT32 VoltageWindow, + IN BOOLEAN S18R + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4; + + Switch = S18R ? BIT24 : 0; + + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SD_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of addressed device. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18R The boolean to show if it should switch to 1.8v. + @param[in] Xpc The boolean to show if it should provide 0.36w + power control. + @param[in] Hcs The boolean to show if it support host capacity + info. + @param[out] Ocr The buffer to store returned OCR register value. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendOpCond ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN UINT32 VoltageWindow, + IN BOOLEAN S18R, + IN BOOLEAN Xpc, + IN BOOLEAN Hcs, + OUT UINT32 *Ocr + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + UINT32 MaxPower; + UINT32 HostCapacity; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3; + + Switch = S18R ? BIT24 : 0; + MaxPower = Xpc ? BIT28 : 0; + HostCapacity = Hcs ? BIT30 : 0; + + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | \ + MaxPower | HostCapacity; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *Ocr = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send + the data of their CID registers. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardAllSendCid ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device + Address (RCA). + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[out] Rca The relative device address to assign. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetRca ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + OUT UINT16 *Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16); + } + + return Status; +} + +/** + Send command SEND_CSD to the SD device to get the data of the CSD register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of + this buffer as the content of this byte is meaning- + less even if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardGetCsd ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + OUT SD_CSD *Csd + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1); + } + + return Status; +} + +/** + Send command SEND_CSD to the SD device to get the data of the CSD register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of selected device. + @param[out] Scr The buffer to store the content of the SCR register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardGetScr ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + OUT SD_SCR *Scr + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SEND_SCR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + Packet.InDataBuffer = Scr; + Packet.InTransferLength = sizeof (SD_SCR); + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the SD device to select/deselect it. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSelect ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + if (Rca != 0) { + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + } + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the + device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardVoltageSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SET_BUS_WIDTH to the SD device to set the bus width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of addressed device. + @param[in] BusWidth The bus width to be set, it could be 1 or 4. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetBusWidth ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN UINT8 BusWidth + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 Value; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_APP_CMD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + if (BusWidth == 1) { + Value = 0; + } else if (BusWidth == 4) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + SdMmcCmdBlk.CommandArgument = Value & 0x3; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + return Status; +} + +/** + Send command SWITCH_FUNC to the SD device to check switchable function or + switch card function. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] AccessMode The value for access mode group. + @param[in] CommandSystem The value for command set group. + @param[in] DriveStrength The value for drive length group. + @param[in] PowerLimit The value for power limit group. + @param[in] Mode Switch or check function. + @param[out] SwitchResp The return switch function status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSwitch ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT8 AccessMode, + IN UINT8 CommandSystem, + IN UINT8 DriveStrength, + IN UINT8 PowerLimit, + IN BOOLEAN Mode, + OUT UINT8 *SwitchResp + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 ModeValue; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + ModeValue = Mode ? BIT31 : 0; + SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | \ + ((PowerLimit & 0xF) << 4) | \ + ((DriveStrength & 0xF) << 8) | \ + ((DriveStrength & 0xF) << 12) | \ + ModeValue; + + Packet.InDataBuffer = SwitchResp; + Packet.InTransferLength = 64; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed SD device to get its status + register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendStatus ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + if (!EFI_ERROR (Status)) { + *DevStatus = SdMmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling + point detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSendTuningBlk ( + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru + ) +{ + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[64]; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + Packet.InTransferLength = sizeof (TuningBlock); + + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL); + + return Status; +} + +/** + Switch the bus width to specified width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSwitchBusWidth ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 DevStatus; + + Status = SdCardSetBusWidth (PassThru, Rca, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", + BusWidth, + Status + )); + return Status; + } + + Status = SdCardSendStatus (PassThru, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardSwitchBusWidth: Send status fails with %r\n", + Status + )); + return Status; + } + // + // Check the switch operation is really successful or not. + // + if ((DevStatus >> 16) != 0) { + DEBUG (( + DEBUG_ERROR, + "SdCardSwitchBusWidth: The switch operation fails as DevStatus 0x%08x\n", + DevStatus + )); + return EFI_DEVICE_ERROR; + } + + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth); + + return Status; +} + +/** + Switch the high speed timing according to request. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL + instance. + @param[in] Rca The relative device address to be assigned. + @param[in] S18A The boolean to show if it's a UHS-I SD card. + @param[in] BusWidths The bus width of the SD card. + @param[in] SdVersion1 The boolean to show if it's a Version 1 SD card. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdCardSetBusMode ( + IN UINTN DevBase, + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, + IN UINT16 Rca, + IN BOOLEAN S18A, + IN UINT32 BusWidths, + IN BOOLEAN SdVersion1 + ) +{ + EFI_STATUS Status; + DW_MMC_HC_SLOT_CAP *Capability; + UINT32 ClockFreq; + UINT8 AccessMode; + UINT8 SwitchResp[64]; + DW_MMC_HC_PRIVATE_DATA *Private; + BOOLEAN IsDdr; + + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru); + + Capability = &Private->Capability[0]; + + if ((Capability->BusWidth == 1) || (Capability->BusWidth == 4)) { + BusWidths &= Capability[0].BusWidth; + } else { + DEBUG (( + DEBUG_ERROR, + "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n", + Capability->BusWidth + )); + return EFI_INVALID_PARAMETER; + } + + if (BusWidths == 0) { + DEBUG (( + DEBUG_ERROR, + "SdCardSetBusMode: Get wrong BusWidths:%d\n", + BusWidths + )); + return EFI_INVALID_PARAMETER; + } + + if (Private->Capability[0].Ddr50) { + IsDdr = TRUE; + } else { + IsDdr = FALSE; + } + + Status = SdCardSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidths); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with %r\n", + Status + )); + return Status; + } + + // + // Get the supported bus speed from SWITCH cmd return data group #1. + // SdVersion1 doesn't support the SWITCH cmd. + // + if (!SdVersion1) { + Status = SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Calculate supported bus speed/bus width/clock frequency by host and device + // capability. + // + ClockFreq = 0; + if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) { + ClockFreq = 208; + AccessMode = 3; + } else if (S18A && (Capability->Sdr50 != 0) && + ((SwitchResp[13] & BIT2) != 0)) { + ClockFreq = 100; + AccessMode = 2; + } else if (S18A && (Capability->Ddr50 != 0) && + ((SwitchResp[13] & BIT4) != 0)) { + ClockFreq = 50; + AccessMode = 4; + } else if ((SwitchResp[13] & BIT1) != 0) { + ClockFreq = 50; + AccessMode = 1; + } else { + ClockFreq = 25; + AccessMode = 0; + } + + // + // SdVersion1 doesn't support the SWITCH cmd. + // + if (!SdVersion1) { + Status = SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if ((SwitchResp[16] & 0xF) != AccessMode) { + DEBUG (( + DEBUG_ERROR, + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails! The Switch response is 0x%1x\n", + AccessMode, + ClockFreq, + SwitchResp[16] & 0xF + )); + return EFI_DEVICE_ERROR; + } + + DEBUG (( + DEBUG_INFO, + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n", + AccessMode, + ClockFreq + )); + + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, *Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +EFI_STATUS +SdCardIdentification ( + IN DW_MMC_HC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN DevBase; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + UINT32 Ocr; + UINT16 Rca; + BOOLEAN Xpc; + BOOLEAN S18r; + UINT64 MaxCurrent; + SD_SCR Scr; + SD_CSD Csd; + BOOLEAN SdVersion1; + + DevBase = Private->DevBase; + PassThru = &Private->PassThru; + SdVersion1 = FALSE; + // + // 1. Send Cmd0 to the device + // + Status = SdCardReset (PassThru); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "SdCardIdentification: Executing Cmd0 fails with %r\n", + Status + )); + return Status; + } + MicroSecondDelay (10000); + // + // 2. Send Cmd8 to the device + // + Status = SdCardVoltageCheck (PassThru, 0x1, 0xFF); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "SdCardIdentification: Executing Cmd8 fails with %r\n", + Status + )); + SdVersion1 = TRUE; + } + // + // 3. Send Acmd41 with voltage window 0 to the device + // + Status = SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_INFO, + "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", + Status + )); + return EFI_DEVICE_ERROR; + } + + if (Private->Capability[0].Voltage33 != 0) { + // + // Support 3.3V + // + MaxCurrent = ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4; + S18r = FALSE; + } else if (Private->Capability[0].Voltage30 != 0) { + // + // Support 3.0V + // + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4; + S18r = FALSE; + } else if (Private->Capability[0].Voltage18 != 0) { + // + // Support 1.8V + // + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4; + S18r = TRUE; + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + if (MaxCurrent >= 150) { + Xpc = TRUE; + } else { + Xpc = FALSE; + } + + // + // 4. Repeatly send Acmd41 with supply voltage window to the device. + // Note here we only support the cards complied with SD physical + // layer simplified spec version 2.0 and version 3.0 and above. + // + do { + Status = SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", + Status, + Ocr, + S18r, + Xpc + )); + return EFI_DEVICE_ERROR; + } + } while ((Ocr & BIT31) == 0); + + Status = SdCardAllSendCid (PassThru); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", + Status + )); + return Status; + } + + Status = SdCardSetRca (PassThru, &Rca); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: Executing SdCardSetRca fails with %r\n", + Status + )); + return Status; + } + + Status = SdCardGetCsd (PassThru, Rca, &Csd); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: Executing SdCardGetCsd fails with %r\n", + Status + )); + return Status; + } + + Status = SdCardSelect (PassThru, Rca); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: Selecting card fails with %r\n", + Status + )); + return Status; + } + + Status = SdCardGetScr (PassThru, Rca, &Scr); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "SdCardIdentification: Executing SdCardGetScr fails with %r\n", + Status + )); + return Status; + } + + // + // Enter Data Tranfer Mode. + // + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n")); + Private->Slot[0].CardType = SdCardType; + + Status = SdCardSetBusMode (DevBase, PassThru, Rca, S18r, Scr.SdBusWidths, SdVersion1); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->Slot[0].Initialized = TRUE; + + return Status; +} diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/PlatformDwMmc.h b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/PlatformDwMmc.h new file mode 100644 index 0000000..eac05ff --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/edk2-rockchip/Silicon/Synopsys/DesignWare/Include/Protocol/PlatformDwMmc.h @@ -0,0 +1,73 @@ +/** @file + + Copyright (c) 2018, Linaro. All rights reserved. + Copyright (c) 2021, Intel Corporation. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef __PLATFORM_DW_MMC_H__ +#define __PLATFORM_DW_MMC_H__ + +typedef enum { + RemovableSlot, + EmbeddedSlot, + SharedBusSlot, + UnknownSlot +} EFI_SD_MMC_SLOT_TYPE; + +typedef enum { + UnknownCardType, + SdCardType, + SdioCardType, + MmcCardType, + EmmcCardType +} SD_MMC_CARD_TYPE; + +typedef struct { + UINT32 DefaultSpeed:1; // bit 0 + UINT32 HighSpeed:1; // bit 1 + UINT32 Sdr12:1; // bit 2 + UINT32 Sdr25:1; // bit 3 + UINT32 Sdr50:1; // bit 4 + UINT32 Sdr104:1; // bit 5 + UINT32 Ddr50:1; // bit 6 + UINT32 SysBus64:1; // bit 7 + UINT32 BusWidth:4; // bit 11:8 + UINT32 SlotType:2; // bit 13:12 + UINT32 CardType:3; // bit 16:14 + UINT32 Voltage18:1; // bit 17 + UINT32 Voltage30:1; // bit 18 + UINT32 Voltage33:1; // bit 19 + UINT32 BaseClkFreq; + EFI_HANDLE Controller; +} DW_MMC_HC_SLOT_CAP; + +// +// Protocol interface structure +// +typedef struct _PLATFORM_DW_MMC_PROTOCOL PLATFORM_DW_MMC_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) ( + IN EFI_HANDLE Controller, + IN UINT8 Slot, + OUT DW_MMC_HC_SLOT_CAP *Capability + ); + +typedef +BOOLEAN +(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) ( + IN EFI_HANDLE Controller, + IN UINT8 Slot + ); + +struct _PLATFORM_DW_MMC_PROTOCOL { + PLATFORM_DW_MMC_GET_CAPABILITY GetCapability; + PLATFORM_DW_MMC_CARD_DETECT CardDetect; +}; + +extern EFI_GUID gPlatformDwMmcProtocolGuid; + +#endif /* __PLATFORM_DW_MMC_H__ */ diff --git a/local/UEFI/edk2-rk3588-master/misc/extractbl31.py b/local/UEFI/edk2-rk3588-master/misc/extractbl31.py new file mode 100755 index 0000000..4a96807 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/misc/extractbl31.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Script to extract PT_LOAD segments from bl31.elf. Derived from +# Rockchip's make_fit_atf.py + +import os +import sys + +# pip3 install pyelftools / apt install python3-pyelftools +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection +from elftools.elf.segments import Segment, InterpSegment, NoteSegment + +ELF_SEG_P_TYPE='p_type' +ELF_SEG_P_PADDR='p_paddr' + +def generate_atf_binary(bl31_file_name): + with open(bl31_file_name, "rb") as bl31_file: + bl31 = ELFFile(bl31_file) + + num = bl31.num_segments() + for i in range(num): + seg = bl31.get_segment(i) + if ('PT_LOAD' == seg.__getitem__(ELF_SEG_P_TYPE)): + paddr = seg.__getitem__(ELF_SEG_P_PADDR) + file_name = 'bl31_0x%08x.bin' % paddr + with open(file_name, "wb") as atf: + atf.write(seg.data()); + +generate_atf_binary(sys.argv[1]) diff --git a/local/UEFI/edk2-rk3588-master/misc/repack.sh b/local/UEFI/edk2-rk3588-master/misc/repack.sh new file mode 100755 index 0000000..90a5a41 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/misc/repack.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Used to pack any executable into a complete flash image + +function _fit_repack(){ + mkdir -p ${WORKSPACE}/unpack + + cp ${REPACK_FILE} ${WORKSPACE}/unpack/uboot + cp ${ROOTDIR}/misc/prebuilts/uboot_uefi.img ${WORKSPACE}/ + + pushd ${ROOTDIR}/../git/u-boot + ./scripts/fit-repack.sh -f ${WORKSPACE}/uboot_uefi.img -d ${WORKSPACE}/unpack/ + popd +} + +function _pack(){ + _fit_repack + + echo "****Build 8MB NOR FLASH IMAGE****" + + # FIT Image at 0x100000 + dd if=${WORKSPACE}/uboot_uefi.img of=${WORKSPACE}/RK3588_NOR_FLASH.img bs=1K seek=1024 + + cp ${WORKSPACE}/RK3588_NOR_FLASH.img ${ROOTDIR}/ + echo "Build done: RK3588_NOR_FLASH.img" +} + +ROOTDIR="$(realpath "$(dirname "$0")")/.." +cd "${ROOTDIR}"||exit 1 +REPACK_FILE=${1} +export ROOTDIR REPACK_FILE +WORKSPACE="${ROOTDIR}/workspace" + +_pack diff --git a/local/UEFI/edk2-rk3588-master/misc/rk3588_spi_nor_gpt.img b/local/UEFI/edk2-rk3588-master/misc/rk3588_spi_nor_gpt.img new file mode 100644 index 0000000000000000000000000000000000000000..ccb1ffc2c02617135fe1daadc607be241e609ccd GIT binary patch literal 17408 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/misc/rk3588_spl_v1.12.bin b/local/UEFI/edk2-rk3588-master/misc/rk3588_spl_v1.12.bin new file mode 100644 index 0000000000000000000000000000000000000000..0967d1611c48561807b6ccdb5e2c695ca9392ff0 GIT binary patch literal 228826 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
    &?s{3K^bW+N9 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 z

    +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 ayiU2f(n+BFmrNm|1Z8O^n(cC>E&e|b2va!# literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/misc/tools/aarch64/mkimage b/local/UEFI/edk2-rk3588-master/misc/tools/aarch64/mkimage new file mode 100755 index 0000000000000000000000000000000000000000..469fe93f948014661a4b9a7f0065accc1485efa1 GIT binary patch literal 237712 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

  1. {zn~K26`sbjr%(z{}k> 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 z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O 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

    ? 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ⅅ-LKSd- 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 zX591

    0dKf26*^}v_=_Ioi&F%Y;EZfbYTezr8oK#Q7b`m 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%0DEL`^+(WFFG-#w|Si#o=s zusZa<_McRqIM2+%-{`xqVkVj{dt;tqZPHf;XL?P9b$Y|WNTOriAK&U~jW4g7VdM<&lb=ps!h@M3V>>-k##FUa6Mro}Gb<(e!X37o0s9yioI~$o z&R7V05!$f&M+?+Efw(wZ81MZ=lH@3-3v|s24j%^)jAG?Pn&^HYv1$OH#Sq`#Vz{Yn z41eUl>t^R{2#SfV5Jv`78Wph0FsO?FdUH?v>0)9{12t}%ctd!-iqbjKki#EynrsX< zB{rY!wmlsN(!nv^5$h5({W<6QRx#fvvz^L&OIVV}y+5;eH|Z=m?=l*-oQNi6o%y4V zs@DNhI`)M}~HX1zH!$ImjWrP|1=8sCPCiA0NKJeQ#_MQerA`#+NUo zqI$;|;NUMd>DQIfW_3g&qIul8`(x|CoB`j2{Nm<};Ys}=D+DMi=1^)Kl{jI%P6)5J zn1nUv+gmRpiar`{o6NX9$~JIANI49+hv+X+Qu+#{*BYm=!i=t;6*=tOi?Ih3Ob&|< zHg{snrbE7ji(Rp7YtqAF*9MZzVYSDq9{$%qX}1H2v^y=NKe>@%V&#tlcu$ypA{O-g zq~o|kUJP)H`-CU23+9m~dybOzJfW(H0T<{&egEp`8jP!lWr4l}GTFEYM5&gOk&k_z zeN@+ebl(LC&?-JduNF;}derD@_9T3L4iLpAr4hTq3`q?x6+dprIkXdYUTgE*8+d*= zz`%YK#PPW`q#W?ZMInhfB_C`Gw+-hbAw3D@Y~0kr6w>rI>`c z{vNCF@00VnB%|bJvbun&@xImx{QZWp&IH0R9xpd@AH@hB@sR9vJ!R!;DfT;*h$3}! z>l$+n?#97kIL8x#s2s0Zq7$d$zz%x?*Hdeiu~;F}MiLkEoh_dRUApk?nDgP4Mbp?z zFVq+|S8(8SUwv*AB`QlMdmm*|bv?=1=SCLlQC7 zfrWv#WpVu6f*)sS4F=aefpIJ}er>JW$$~d?flQ~11CO9)#U6g5FSmh|!W!u?lnS-E z*`op>l6H;+{HZXSSR#09KruMGPB;J1HqanRd1esDz5j5}!Hd+{+aHRYC(r@jW*9i2 zlzFnl|D2Li3CBGWFr{5>JsUpH%QMzVV%a2a%!W9mtB6Vd`4L{;af0@)uQI4loivxh zL?)qHo1t=Ji-%S2HZ6&jxvQbijz@E*I} zL5&^J6`4nEww+8vAf&~KR#{~eKoG{HQYlw=- z^A%I1TO^VS7U=NSmrj{Z7>Y{EeSl<-rvCn6UU=JQFVWN&4pmvndH@VK6tR6g?6)nh zW(ra9UJ=(F@HMUQ)!kyf*vZ_R>!4y=WhB_VYYzg;%=%uNdRTF#$tgN%r$$D$i6xR} z-#$^!@J9yfw`qO|r5f(2)T(MhLKGv2!A4LDlI=ck^z~uzS}{eGW0AsJ zhaOU9_X5IV7&;d{rPT&Ov|9;OK)35nnb|`fBx+K1!EPLVz;%Cum9?tc~jIYMtMqe(>XJzq6FC6 z*A^y~#W=WD(AVE<73P;Uyy${vm?YsT0=J!|a|pR__(ZKQE1jqOzWuP!%I7y?bxAE} zR+n^Ca65?I*#rCT@IFwokks9&X5t};Z#eY}Eez<)N|r4xIeS!>(`U21<8H^In$z$! z{o)8S6$dLEPts}j4MhYVHHs!{uWWAZ+0d0Y>R-*62l8kHlenp=Zje`A z+@8(xQ(D`2>^1b4y2WlYVHFkH?&y(&xl&5CcP$Os`)(d9AcSnr5&^es%i%=hN?`&t z^KkVF=@WlsbvUJiUle(ICA26wn&MuxXHrOg&p938u-0at)XhNglL5~i${_SCl^(K* z^#@tA*Vzcga$!O3?5n;kWX{}+K%6C$`FEzLZvJrOdC|&v_5khkpH*jRbw{89+kyeg zt`XMy7J(k})h6H&bbD=NEN_HXt{IS*!{%#7Ux#CQkvMK=d+r_N+hQ{CDJpY<7wTM{ zG-w40tuWQVl-UEUm^7TA_C-ePzJE=lKixeI%~`1V0g+j_VQ2ld zg!Nn>pMM=VG23j8!adcsf`~3CtD(}R1#^psWd!H(*h*r%wO(aIt05)eI7CEq`>M@c zzqa1q|4GV4+?p|G|NLBdj(bg8MOdIq%`7vNtPSsXPJ%2R==oj_U%ohc!5Z3U8b@8KL6il7fZ1jV@^KXOCz_a%{!ddl&& z8}s6tKm6=Yh^F`radJ_q>cszs>l{HILT=y7;B~P9#6$f4VnqeF3L!s!m+mhAp=YWz!hAOA-%2VGCp|NWA22 z2)ot#P_K!THkTg_jPq|I1ym9x+CgtXACI^IvjAU%f&*StnEzaJCGD1~#57ozxnGnK z9@q%i7lf-Vy;FeN0Y_t3roSOQd@vMK#G=}z2`aPfZyM~Ue?<9`ZQZ?bjS+b;0jP~a z!ZAEC2Ua)Kw+UV3A9j2LV?{Tz;r2$b*Y_cZT#zHKn)<3SE5o(~OUOwZIdY?1e!d4S zmATT3{e}l5q^}xuPKrQfj=hG|Bq>~*{B@`aoC8Fi@e72gUNjz)ON#$OdNeuP=rFin z=ODG!w0rv{>4$&Dr6?%@QF3s9DAP$K6oG2q0<$CKRM7lRY0U`S!t*q}e=wa!_22bJpzVEbD!g%HpKFGl&7-qCsu*Fc7de+f~_lI&&yVm@dk7dk4Z?1gwu~>W+9Kx zX%$PbYr1w-$f@QM1QjOY{I_MF;$}%#7>KMq+fyZkiT3C39&r2w*TDfVHVmn)LBAPXbKM7!v$*n%dHm4fyI{S; zugQkBFYR!ffP#+Q@Yl7ffX<;IwpMAKXej83jkXEE|GO5SM0)b!O`EH(9 zz|$Gf2^-u}zxTSUzt#ty*nzt=b4Q_oKUH*FV`$T8aXC|uH#zs+l;AgwzX!*-NXl^l zcIs>=7NytD^^nvp+AzYTb0oK>Q5{2?feCL~P?=6BiouhHq5KS{E1*OhlWw&?arE(v z*QK_%Sl^uCz@}q5-an=hP=I1|7HS83^ogu;AFdRPnNPO9pJ>tt1HYdVSIGMHrS}1& zzq-tkwDuy9g~X{vDn)(3$ds(!F#3b?379l`;aX98-$Vv3i1HSIl0s zuPo-$B#*$26oVKqhDx{}7E*;a_?g8?F zQH^$ZEJ#E*A?(a}(fqIqsw|$kOEnHbLfI_|M~^{$}++LPQkfl zKVchK(;VeSiG{vNp``%+p_?oX51Kiu%z^|%D=ZnL#W5czDy29w+~g_^Id&V7Cx8Tq zcFwzX^*Vx6<2E1R!#k_V-e@RuBa)MPSk~|E(l|;$$PiaE4H8aWpf${RpHwK8-k6Pp zw_L^;j{Z!QgDlPJuGGisrb4dCZ);sqW(awC5B_cl=nlsSURInA`Ks%7#MqCF& zcjq5hH443h6)lPfbZs0I*u96=#z=6)_;^JMKzLHe{{0kuBr9ZW)a_yorb*+lYI>!B`muDilR^wNj^a zUqN}RO?trI2Wtw*<3)~m4u`f+>s&%#4uYHZA)H`$b zP)$`TqT3XH+i2DXbpRiW;pjS#jYqa*m4_vkf%fk+f_&dLQaj*zWU>y(cvD|7{IN+g z@i{du0k@RRBX5hnGm1xmB*AJo$f*@stC=-rXQH^ zWA)4|h2ZB7sDiyo9Cpr+AJ)tMEj0tBB1K@ViqaFlOMzHnL?WW&+8i{r(P(`EK>fzl zKS^)AknrAZptJ_Cm0Qa8v^A%{CC|K}NdUotWmzeJKrM0_!zaA_>gniqjHsDNkCvY_ z`gnPs#eQ-sI(x{O?AaJFY*0acQ4Yb{<7EpUn!wEi8%LQOawT+E<66^6u;ax2YOLnR8@Nq`aT}%&84#Q3gtE{^ zlQ~Mk(lTB_7YvWt2-SX{fb<93uZ{L%2%UVv-`_E>d62_cavXRNMJ-LBf?Ldiczuk_ z$|un1H0+~Dy&c_{p3$GL>MMm{Zgy%+;+8TmI1D%Y@jBl8;5}{3y{RXFjH1lFvf=g;#~=E6oPU_5AA157}Ol z3GUj8*;fELK*qm;0IbvX+`~~*XT)?LE4}OS2-cU z0V$t47t#4$exB=r=6HUfytKV-X9c}S^8yGD~e)bq}&OZ{DQ|$^f z6P9)2r23UC6}6oUUtM(lG1qBD%mQNQbk7mT5vn8Oq%Ea3gCGhVEZ)S}WP{pN)8tBX zu1zU}fLP4reEJu#2&puDfxj)UBA9lB%Gmh(Vq1k(0*yrjI>(djUjkl_78b)b+=smZ zoJLmPEqL7c2N_fB5zs2-)A4tyRT-L$&$RV=jPy`8-Q(}BRtePpk;xCWRMAFl!KH1cNrt@IzBi<#cdNuh0Q={C&OX@2q!_!MoYTu^frvm!$e3T(eD z4}V4-d*?G_Cmgh^S?k$XC`Bhl3E_D6s}%j>Mdp+<&)fFgjwfv9`cDF}Mul=eT4&OX zP{Sz)XCN(5*LU~dqdSCdEvp?^$x$fm%(Fwi2Vx9=SjW_GKK=wMukWZI@yQc$ifLO{ z2Swa+JzFx9#YiMnn_h=ys<8hj|0Ofk*ow@8*12XxX2%4N5B0ne`LrbvW2cnVb3K0V zbVfQ|g2nx{*pjc$-u?!Q34KSHdwV*M%VbeUpj7`NywiiG7qOTd&v!=VWXOi^S%)xc z#0(L+%4F~o%RGGnpU8=*$Zoe_miNOQ7q>8E-84Q;bkYsWTg!Dppra1WT$pa=Yttp` zCAspr%zzYm226OfaqK2NYZxX>67s`uaHF~5k9>sSsvA(dvZ!u5bRAu?8#K_MulLtE zm~v$S!kN|g|65brFLG`*`OlT2tQpH@)6O0>tReVkb!lQ*%Dl;W9|y^gG9p}j*<8q{ zVIjDZ+k(-116X^p6i~me&Zr4K?yJ{mci>LBL@ON004V#io86&u zwg|-RbK)|s#h!1pX2+l-aS<_PCD#*^4p9uu7lQO!BE|)2KtdtP$sZXWzd!je4o+|0 zP_?P_exv^XrSZpa$$8j(dgKn``*NC_yj3>XPri$Ei=dkpdRxNNC=sssm|B&gvQ5K%;BhaRX<0u+wg{K;`H}&xX&=n6}&D&8Gbj3J5%p- zff=2x-$K~Wbb^!iu&;2WP)LVpI2}{62Xv;`e^Gr@^w)vrjLHpQ%(ym z11Zummig7p9;$bv8eN}Mr0)()#5tJrX!-5fOHYxeyKebXe0o=BckEM_ zc(EN4#&m{J6JgM{ke%~xBnrMz`bfPMWE}s7?g5xxV}FO)9q#k4B&EZ1kWYjo|78@UR1V>NR*~UTuhSsW3@?l2fxaWmaz1`Qr2X?9buG?la z?H#@uLDck=>uu5L#NRe6(TSp==*gD8Orfwz{rUY!#Ky>n6rA5^a4EcjvL=EVPs{4D zR!2vl6LCZC0`R~3WY+|Y)%#}(75iremr0}o77LiYhJ(5viF5|CR*CC z!wf2x{~=`SJT78Ozq*sJ?d7N@ML@gce?pRes=@76)7`-u!F($ZD7N}32T%^UvIg_s z`CZ}#Ihs0NR{Y!>f8&QHV$gl+zMs2$7d4?TUQ!CeGvIvk|5VG-38XXVna`3G;2fVn z;o)=?a~;b%o$)s#%X=7Ivae1*x>V@=A(oGuq46O#!p28HjCMxF>KfIz#~Mj$(YEzy zwB?;j^plumy(S+AA$t?WVga}JM5=xjb_^2%GWC;lc{zYuXijLujb$7#a{4{PD*@Xn z&k*S4s79Ia2I`c)8hUkx=08oOouorj$@k%Rg#Az7s@na_)PgU4%FF1;P7_-WVa9g5 zCH>XI3FLvsC%I&2x3c@T%P$G~15Q@xDpF3b+81D4akaHR%};&TeSkshAKw}QBt(iX?LkNe$AnS%BD%BHMo>_4iGPPXSd{CwnWXvEK|Kg1{nMh#aGfq{|F# z^iA7nGV9Vl7UXNVl64^ReVFj0o_6tFBa*0P?8My>ZI4BZQK+xt(kqGi=O z@Lc66XC})3V6b-;O|qLC;tkk7Y)K}QT0aK^kF$E5Q7+B>DW~=Igh2N?0GXs26rTGW zz2u4&GnxG(KBlL)BQa(Qv8ExTTr)7`d)xlftwtl6muj9wVfK&igJf=EYArS6dQvwF zgxsE=?+``5CRpy=xT+AU_(0)Hx|buBsaR*eu{j=_#*$$zJd?B;IaX2p?vUy#muv)R zhmI$kYSd@Lz=^|DL(Jz_NI>Gw@cKr8xH3j^$dc=I7SyLvTS3Y`lMx|q841Kq#v zSlEn~Z~dkbyTyH+tTOl1r9H7y5roX^lYR&C~^v{#W70A|@JC7!1%$nK>Iq=@I{@ zMxxZLjCvvef;jBzjD2KdS<2 z=*o8EWUbk}P)y_>pWnW0CzH4$f6njVdszeB zD%*NSRt4>Qh_i=klCJJDc*;6ry#H_JTWYDm!lI!5_Xx}bA+x&k%j2ni-1Qk?rG5cBU3;(ed$y&T^p)V84=nCu1-il=#=oRYw-(YR; zqM3ixLm~^4cQRu$BzS&h-7^`NSY#oV+?p*n^jFT~y<+Xiy%00!;9|r3{|EI5TKbrw z4$?PY?8kEQ6Spsbk0V)Rx1$6s-U9n=gYAKEAMb9^{^e4W`{kmdSbEsUAiEG@H?`=s zDAL6e$>645_Cr$$h8U)A!War*U^ri0G%cN?`EGmiPcIxli_SgdfCm(&p4URAFm0cu z0BN+p0-H9W?Y*eyKBdo^qb?`8kb9Xld-g(r^nCNzW1Um9AzR6S_;spR67`|9WeX)m|NVRv#d+RJTT4PJ_wu za?-F-y$1P`n(Pu-Vk@xMZL?xsOa)(Ml}P+o_s zS)ip6eFh}?cKgkKW_n|w2+w=#kb&6Lpr{TR%4lhRtJLxYV4x;G9G`|E4 zJt?&Yb}RDd>G79<15rqX{QhL!8H)3S~Is7>!FUz1t$}9BjqI zEfIfek%lPAnpSRw6TlL-m0UEh_|EM6H7vm5(DG53G6%V zMuOjQ4HTB;+yw`3W&I?qHE1?6Y_PS|6B*lIq#USvl%HQ)tw0JNrJdTVsApMftFXirhC z{ilt0Rr8k3l-8osKDsip-cSJtr zyZsXJPAe_jf<>id1M#^2kL0dH<%ACiRTMzlHMj*)rR1v00KjwyZ{mLL?sSh9cQth?%AL9T?sb`~ z)SVo8$J>QP-CF6zM0&`<9xPSuj@~BD`!YTENTOi$ggY;Z(RCcpP*({4y}e%T zY2OVCBDNX}6%NvD38_5YKi(UFxuQ-fepBXzMLMo34_7AqT=9NuHI`{7B|3Jg4C~~< ze?agTbI_0>`uX`G#VV0Gq?}KNh+nlIt=VI;N=P;VTN0bo50;8=g^t8E>U4xJblI8k zl$9C(Eu1C~)WV-To2SOmdV0n{)xp9#L4Rg{dWy(lPksF?5C*^{Qq(@q9%`+@C0LYG=iqN^;ojC^N|Ty_<_8^ z@E2E=s61UIb2nD0xiTu2uZ&lvd`ki}d) zV$UDXDMw%+r0h+LKgv4(l{6|_F$ zE!1;WG~o}?*aJ$q-WJt$-z2H=7axlM;%>P|xkfKp1$%DTnk-KNSpApd-SE%F#Bi0v zo(64?PkJxptIUw-15C2@Od69Mt)G;xb2yc@q^uh!O_MpNgKtI`dMmOkg>+Hyb7~3U zFbJ{gY7HRnFz+JEUzdB&H!RX+0rZy>QfM88lM0ycN%v%=n?@g0>Pm^lNm*4hqQR4S9}pn45^3=UYQ5&|cyA6Q41?QGA!nBYGs1}8mHn49zg=Tmh%Vl#V*fe>=23_g!y9WNq zwnZa{xg!q(BEDr1Hj!!tn-KFS^__`sZFijr@NyBwA0NXBzaVwXVag4zX3M{IAQj4N zA%+*B%$CZ(BE3Q_X@U;QL(BF_{d-(Jpo&YAswiyUH(@E5vkqw1(XUJ=8qtTg%y-|S z_7@EMEUkuD?^VL38Q_-Y1G)7>*smgS$JJmAm9Q~>?EhJNU-Wbx^*&!PWD|9GJokJQ zbAp6D0XrIA3g;&3KoF0hm83=2m5cJx@%#DqQB#f}o64low)ToRr^CHx+1~i28a6z) zaM~Z3O+S@Bmw%2u!-7nE%W3VtG0_;P~b*FD;2zfQZ@3<&gGFPGoe*8F9u17;lmt?k( zV3X*Ot7ws%N!1Jtbzo5~C9Qi9A&EwG9pWbz5473~MFVo>l9ASmGM zjQxxe5jvT+qG4QrNX^_*Q{Vs$&fi7 z>Fxl@?eu|8FUzw9HEL>te2{EP9x~17g^7+DOqq*kj2l z%JBCtZf^jyx!&yTdQ!nQ-^)k7%CDWW{hMouO>rGTW&n47zj;;PHH8Cp8$$X@@|W*8 z@Eet7Dqw}A@jZX(8Hb8$?*XC5tq&+;_R)OvM3T;TP8MFO#eYOdFlL-D47za2G7hBC zS+iN~ltIi49!r4gI}^Vhg>*~XYY0q~vF7*ZQSg*~m!w9x2^)VjRGA5ZFCfgGSx{AK zu>vh)uzQM3K1{5RPE>Q0kKC-0ZhN65z)|Bw-K!*9W5MC*4|u+j|Qw} z4?oqv3A|dT>L~;nD&iovWk68h)LVf~jOrOy`-!S{x| zws7ZrD#idd>J}%MR$Li4V(2Wo^1uOrA?dd`q}IpCM!31qCDH(gdd(FQ?I0lPY$Ji<8Ab!d z`-=A9PhdfrAtHbZgzx-B>%V-(atOZ33>RK_+#ucNE z1jN4>%`Zkamb-zCR0b-coJn$26PQ}@ttS*CMNMg+KwTKJRKpZe#nJPghP|wl05yt& zrgHn=%pvkRgr#Hr4IBErKLv4fjG53c23~LO9g2Bg6}D^jPgbd8;03f;&d`deZdJh_ zgQFKQdM)1r)kQK>7qPy14^PznIiHtL%Jk*_!f^)y=)dbrEl`!(K)W*G4^VF)KxCe* z^tv=gf17bWfw1a?Wyr(+^b5T{+%RPio~-J!{^$ttno_gerw)*O z3H|jgUZe%liE8G(x2lHj>Dj8j3L$i~vfjU8g`d{zduSXmxwD^QrGVH71p|@2f2fdM zp(3Wq@6_#tFDd&>_F5I5Y&{y2EPIhvf?4Mbr!xznXkwO^!SA{F^v7eQ>DsPb zxb~f+$*Shn;o?>=JU5EDYB(~5g{kf;O+NA9Pe6v!O&ShB1}d=rxzrB=e4)ePeBxv@ z+6DWCJk?xV?;JpMY)@c3qdr_9Spp+=X57Yx6IoOo)UXA=*aH+sH@9S^Brgh+I_w#) zRm*fnta#70DFONo+c6P3JAag6Z9f3HCqiW<-i!k0lJQS{2i0|WQjGT* zA$-vs#5%6pyQf}lq!FzSy{u&BurvQA{vUWi`5sU zLjWXguDF6(?j}SH&D-FzB<+AVN)`niE{6|h56dh@`zGZlz9M;VbHgKnrIo8K#3~L; z=$mMC&v`+D9Ryl4;YBjE5)~SW{(4~vaw!4pfn~ECk3Ub>)F?Z9;5F-^9md^799>7W zL|tlGkKkbz+ZO0Gqq(=JkabM>hiAUXe{(c@sHX_#LVHO6hghttz>#xougMppVXIsE znflO)Wo#tTapn4t7P`o;iRvyg5f_40PQZ1cV6<4jJU>R)D~a8MZoE&7uAMc*SDy!p zXy;ml3bso&cv~NnVWm#>9=Tx_fcP81NvpMTdRx9vkGI_Lw-LhsOEMu_hfH?ro7FJ# zg$06lu__@bva7j9cRjhn7@w7RhQks7NVu#BUd}fLe>9^Rb94nvW{h`sdDm(_sumf5 zx0-(YJRi_Mx*^aB;&$cE(I zP`^MaZ@syxGu_^<$XgM?G#Hp+8+bEqQoa1|*ieJ%ZD@+d^+xw*DwTWSS1MXkH(LS3 z!$Xx8$A-~_^E(2u(2Z!T|FPYTynSmGM^EqWB*yIABYS+@x7XZ$UvgejzlWjGp0-dz zwS_1S*WB8G z=?pHIM-$DC^kMJbrFChX`6fBzh2`OxSZ1;2<8OhqNA)2?!94L=u*UxowpN6-Im0t< z$tS2I4mu>-3bJqul0|90K}DkBs`~%1*sfClLjwbh>f=py^lH*uQ_yZ(oJmzpw(M>@ zZqwcBvSD%;tOv-p<-`}_JVN|MgOXR$2P5orsIDR;7(t0k_G6kj>`fY(9vv*0iM1XO zsI62)wmRTG$E>q#ck_F}))`nSiN=ihJRB`t!8f^!C697QCC|XAw<+C`2?975g4z1= zcetkw4}=bwqf`PsGI_--kQAX3+#YFsn$(x#SBy#4%ayym<1uO|-r! z?rG5qpU&U}w!4~o$mBCd&1HN1$aa5Eb!w`|wZ&k=mM$k~tAr!10M)9?GvluorU&)a zuC8$AMe<6zOyzN3kU^vfV49NLcuI}EZ$UE61e!IX=~<-F$antPFA{Qs;H{TE)c+c+ zIReMhqATg7@@kpQvCzv?21>rp1~2tCfe1n`JPrCuMwBt?ONN2rt!P75K6J1n=O96U zHED6`(9t_;Z~~sBpMfedV|P=FpNWQopOaQOoGEJrMV8_}0Mn2nddaEgyfS2@Fm-6G zh^>jqq$*kDHBkj+_`aGAN>j5WwFfW$J1{1qv=hq<%x(FB1YXiaCXfx08VPjOkt^#Z zg1`@)T|@~Y5ivyT@%4%4_u_saMqe6E-&P2S%{a|VxxRb-71iGpB8_43t^~~Z0wv5p zb2*&mQexmdZf!1_5Z2{GRp)x%8aSFCbL^n>WPpY{kR*%Om$HAJ*)vOtelChH3+I+@ zk_WfpuF*O<9+y`G$PeHCy5m}eqg|3w3>K0Yjv=|urX)rsV7}gmTIriN%aSlJPh90< zq5p5wsb1cYFSowXNPBp7DSwqCHXJk%V(mp|8|JXM$ZHjO;_=sKp>oSdhWTIcgqP~5 zh8sybUZD^^S`=bbHGuYY{e+T&=7lX17F03QR@=7%2B!Fs`j{2aO28dpPrzj)kYE|3 zj~TZ>&h(L;V20r)T-BpV!p-#Hxc}d67K0W&&{g$GRUZwkG~ZU-nbbPorj9OaF6e(P zLt!U{3dpGG*zei`MDQN!+X23pI6!b;wIzN)4d7y`l@N3?A-nFFHy3fqyzu#T1;(+r zzc%zs91X}1+{`^FFX1@14Uz{%pT~bxK_1kc@1AITFjuD$e_T2Hkm=|9!J}47MJPn_ zNt&qi)pF;!lB6QF;>_1Kzp7Q8S9n^~Z8BiSlQk(xgpmYihO|Ye^7}sZGZ=AHQh+yO zp1G=xYWArmd@QlyUr3znmEG3FJB%&0iiRju5hBbyjLS?05LgLixE6t_7$=RUp*&(k z{EqC2B2kzN44oeYuMI4{SdO&_MB$z}#=vt7n#Gr&-lYT=(rj#X3I@@uQBKrnza~I) zkPWb|f?QR;_%ZxB@Jq7xYblzicVuiQKT4nhaQ9Rx0GW7qp_DdN#w~K3>gUPV#vMT1 z!qXYFs7pQ@%?s6R3wCUWT_(6^C)-EP`ozqs2dx`F5@7^6CZ<$L1RgZJvnPrFx6p@F zJ1Y8Xo*-d`g9po0qK_xCUa)yp0J+_?)o^_&-O~~d3r`wWG<7lz4lt+Mi>ivrB~p7O z12-?f$W5uF;T`b)iTTB7=^*7!0jhI3El?+q1WFZUzR%gLN}W~Mbeo!|hnrpO9Otvf zSGZ|pDUi6oPSn1dtyV_w(Mm7qOceZ(ikTsL^}CW zU?HjOF9(j4#0|UP#JRxiHlG1q#R+EB;6V!dh;?;s3Mr+*qK6`6SP;uO$k5io zX}pYlKY4LPY_UpBw_4lBYxpe|n`JnhAk-XGTsp~z)mCoqeys@yk$>XS z@net#ZJy(ZB9GnUSF%eG$>zfD)p#?+K)`A5XmI?7W*g)MD`%Q2HxBXo$2}E{36jM& zFaT^|J2zXWq=Mjsu834qmp8ZOJc6$9kjP*!?2J%N$OpLB7JkCG1ihloZ7wB0e^Spb zGJ3Il(&uCGnP%oQ_5gc!TNjspAmS2V1~&4^97>^n#^Hb}!V(l3cbtr^mEv%D9n}Nn zh-Qpru3jVLc2YByP`u#6&y9gpLZ68=1#5@i8ceLJf0F@P6wYg<4#y zw1{ZaMm@L=rCMgF8O8&INt>s%{K4vpUHeAYKtwRPcbf_M6D4_2))R@3hTOzn1fw4& zNAtX|_?tN8Hp=)j==f7TuABG_gCRu#J+SyU$E${a;(dcQx40M<7D#>|b{_zGD6O%6 zB*Rk?C0_1XdeCp#apJ?1!JzLVud8+X6BW7+siHMBVzn%4PJ=nv;PKdMK0|Qjzl+XM z{TWhgR&{BY`3e2-q-Ge^THYe>EAz^#^b?(~>o2&H;%oz1^t+ZDa=PvJ7(9sXRPQN& zi)^{S7Ykd%GuQkTqKjyr8d!O>i%7*B;6B>!ecSrt70A!j6uyQCus*m8ux@O;A|`@Q z_|P>o68lMs^Olo-D0R;Off^gby_|SH0nqV zP~6N|>Iz`b#-1ePUU;#k90M5h9!S=TFSd?&OOTdl1Wv>o!!S}Bk`-Jga$;`rEk+0x8f2|{nS3)=#G);#>KU_$Y9cCr;v62Go(1d@%x!edumuXJ zA{MSuJM}_FZgmOKh~&=(0$0=_#1~8^Q5N$g4hN2RdVS(Jx?i^&i)b{xcp#jZmWz8c zG^T7O5@bB?BAD;7j25Q{`(*TGkA{=uDhZVbP1lJln<-cYFxs|vBvA*$KDj>@7O4{a z7m#HK`qq5Degh&uJkY5%Sf^fwPEQO43xT{<2G`7yYw15hc!hA2M|*~hR-1;VYSi%T zRKG`s##4D*9X~x?+7Z!NZyV;%@-x`J4f7>nod$&4bO3Bu`<_19v|bx3aeS`AaR_B-iSGp`3Ckwr=9QpX-c{hzlbQf=Z(8^(p zg)QK8AEbn#R~b@vDASu3@;EN%lAtEpjR{S|P135HyrP$tD}yA|MwKVT?B${AXjRr-%o} zAg}nR3_ObqmP*Owfa3ENB-;b%M*lGB%6}71`_ob|9I%BMTYDW!6YdAqBit8u#H4rz zfyRGu{a2CH@zibY{l(KfBmWwl@o3L>2q1PX7DKp3EYuB&DuQ2~@#=Ji3FgP89nD6v z$-)JF1_lg3gucV9xm>0?C{Ny_K0IkWa(ZL=+Y>|Y!2Ojm73{ED+IcBFBbFHRJPzm4 zTG)1UENuie8J2R>-M?XeitA9_whA}(PU`(Trgyova#`h+{UZphoKX68d4sz0Be%3T zVqkrwoUv12(Za8mQ>S)e1+Mpuho$>Obo(hq5GD<Ryar`(355HfA)%4D_ZQwPUd zlP7iK2MAcs>`-gATMl=t)Ujy1i451xv|-p7kGSZ8Z6yaXl0{9m45&br0De@WQVKyS z%9c%CH9Q>p>xRp&KO(TE01r11txmRE(VM4)E|B=(FP+Ue=jmW>n_`!jOdOv2V&bkI z%##s~RWv*RBkm@snqZEa+|!sFHbdELbVD#^h55ahY7jqJn}dAnAK3skDsTh+^~!Hi zGqk17`r&~*$!?7k@G4X^5_@+DBvceB(M<=*$MzF%wwV#QH2d$Bf36AeNk-UO5)Kp= zoO!aV9q#rKPOF*MbNd)wIy??K)=$wv52|H>s1E{ewaXy1z+?k&w`XS`5~l;}uWAso zWzVA`2(K^Y>wv^Va~D>$)RM^A)s|D&`7dW5!VXPX{ zTuE>;CGR`(0m(QR^VknEjv)^Up!8F;QUC}Aos(I8Az5yd z>`{+Rx2WQrk_rMv`=fFYT+&B0j9NLs(RbwS8(#3}gH`{n*t4E&)dkO&bU_<6mH~R) zQF_FhDUi`i!y(J~9kG$!box9zFctqlv+<6%QFo@962}&U`}5eUOnio!JJYX-$CKwJrPFtTA|FX;ydM50T1%qK2!4J&`RnNtn%rfZ{bQKIWBIdIG#>dXw*O_-ebEr(k|A;)3qD_0w`xyfL}d{G7Vq#ylIt1N~lGc33BPLu$$EsK&Yp{6_$KbdRc??sJ$k=+S!ps$E%qib&L}7&wrEEupMQ8o!J-0V zz^g_i0g#u?GgL`=?Kgq+2FayoQz;5NJp8uM2n}lDUCXYF^g_14wXJvVcLBjiZ+5My zgw2!Mf@M7iXUJP_;NO#3`mSiGdes9y3V3;)B728;Mwi{FpFq|ep{6>c|pJgrZ9$ef}9y$Sum=_tcLUFW~*~ch?(O#?qt$%vDg}OpY|p}_9V?t42Qf{*Ai#3a(zs6iW@uW znV9U8NK2n9Vw)4+v}te8_bBkJYkceRb-Zo(Hxb~D6nFQlDgp(*8zlX}-@LCJ5YFgA}lVpIhx#A6(Z^ruTAEzi7G zdlX10&wT$3bm(~HdC-Y%I+SG#o|Fe=+r z5TSqgDOVIhmvZbbwXagTMB=Ei8YMC5JuJ#KQD4$!rwe0(mfBejHXbZ)y>(6ZX2jUL zEbz8>2>o}nN9?}Y>h7KrHJ{TfT+wWgrihSk_&HK*Pb0Q0JWcZ*;SWl^Iux(?6a;Fww9murw*|dZ2$T4VCX2>w+Km^AsKI#YUgGKBZf}){5=!EUbp^anPl@b|Q_`n>2N1{_)neZWFUlMBicFv0A*AYqiNk8zC^ zVlK2izV?d;$Egm8H>#l;73ip}u+=B@+ieAqe>zk>z=Dg_dLP00#CTHn&Nf)9=t4oH zN?V}K;q*GY@Xi7ra z%ApK*QdKkDMp=gq2D&gM8Z(eJq^ClAcj#tpQhf?*y1AX)2q=@$y27f`&)yus9jiD` zEy?vXp?M-CEu2vWH|3KBEGvd3Pot6NCWEGzTyOy)S)#N&QgY)kz>sSg{L>KL4*FPX znL#797ZcRkMbiF4KwvpqswT;0Y|4Hl<4``Jsf!(G>G+aTS=yCCY(s!(P^)SUYa@9R zd+=3NTte|ID(7!>pm3CLV&3dz|NR;PT}dJ~1K-cLGYv^JVLl#pZK5-`Vfx9BIXxET7TSbWvBN zFcXS&o@`3rI!Y00t*9%?!l+%lo`9j3kB-_WA{E)?t7{fHnwf^H&O$+ts!PCHZ8&4w zS0&F(B+vYA$lsfW-FQXF`v3cu!yi<0aWb~|o1+AugQ5pHoPxF}ZOm&D2Y^7YkJBYP z-gt4jG&5yiXNMbwbj7laK5Yzba=fU_PS9`o{J`rT49(OMZvs%Y)x8?`q1w8DLdE&U z+e8K8{p|^y7t?gKiPfJ%KXTY=e=&haLgpN8`iCi&Gj-;VDUgUlJd=-GL3_DJjX*7q z9+`B$Yg<(uSbNcL%XW$G4#k+9hmoT-aBp7w^0;(ulYg zp?v&Tl`f?@I(d~Pf1E*qW^ORHpsn3+Cvq4?&%%*o3&QSUFz`hQ{}xXm7hTTVR782# zow|f8)tNS7ZhcG+KZbCl`(%HDy&L&ctZZ;g@8xua8ok~C&|_42ON6wfht&6ai5 z2`4V^*uYK)m`Op;5c~Xc2;(=Nri+o5pm1l4rVej5o^$M{PXXqPxEE$+Hr2a7I> zn|+y3yCOKr1~UYAj(H+u=n$Y*arA96=Fy}3*4Ignh<1vV#^H{Qp}wSOvBLW|w9X$i zNc$c4ShIdxVdL8}A*L_p{DHgxjygNUAMbZxzMs<;+cFd01-B}JWVV8HgwR$5afbLh z+S8~4xvDm4HhD^8M9ULcE*Pm;>OGWFY*M-}{ka@2vQ#+gd&Fs;4iPm+z|XIiuFZ6s zu2_{{!%U76%x$nN#s_Qv`L0&a+XUlQp*C)vuS*G6lFQ)|Z|TprPp~9`u^sh3j+QB{ zf!tF5>CsV%P!{SC7hU}3W+j&Kz3}apt+t0%9viiKoIIOaArvXYphZ>Xji4Mh!a`>^ zB}dAWc;K1JXH{S&EF2=0vlrsF=2C!amT-g(;EHZfIoI5voWT55$X12w-|c=;^QdtP zp&JhrJM!%4oD;e_Zw_1)LHN(DSAmuotK*{HCyx^FuhBZ84;pd``ydmzF#pv30U3Ob zgeg|$V!8^ewEQ#A(-7xt&mTj#fgpqaE-p%s$(Jat10kplfyW^HEcX$Te&UU~RgLDN zm8={qPXVWk;$)SLmw-+YQka z4QwOcXs$5Ho0}u4^pWjqe9%YoYbp6>t7Y02X|A*b7plmTIZaLrfK~D@``?e$qZ8kg z*nU%1DuX}uQBBNj$(G$v)G2*c0&zt$6S)Q3b3~3gO4j;W8gc+83i{){E!^D1;+*UUe24N_WYh@ z5R#7=6jTJ~n)fsGBN$8UgJ`1f{kfWl7BQ?7CvBNEmv^mJyk`#%Bo<<_DFD=5LowF?6r-Fay2Sy_4WsDbM73e@0Kq;QlgjfrWo z9>m$JwPIVtVcTv>wFc<`7A84HyUFIdvSP5+;1m81wd%&u^4PGzy0eVDzZjNj0^Z+D zW~yA@oN{fupI6&9T{xd-bC6|P0qorc{3@NB17%6e_yPmRvSfTSptlIT#H&XFYm@bm z8qtFFsj$+9;Th7-n(x4-{cURC(1}+nH3ty|2=AnG-sG=knjaS&rUkK0kCopbV~7Ck zBNP+5r5&DoMs!HtuOr?7K(n#jZ-_q9_&rk)C*1bv;7Gx?&CwqKbJ={+F|BL*yVw$8 zkm}|i?LS=xb`(bR>Sz(`(d{K+fC_&779_*f9L^26Js{4kT*S$$FL6brj5u!;jBn6+ z_=EZgT~N}mGyLXGC6e!?NhRlZFCb>e$F(mM0;jx`(lwQofX!h+Ol0ee0d!Qy_FM6a zI?Z^y$De@Yd|-ddl9}!l?KuoA075{$zmlB_y&o*sRFO=O1{zss^zx#{FPC~^NZFy- zeRiYk;InwYkpzY1Y^X}(3P8UE`^vws7nkm=sL$bf_p*)oUtClY^(#Go2JqeXNx)Qnh3yin7DyW zFLVJ{q`w;vU87VJd!J(t-t>v{_AC2e_ktP4pE5JEJmAb&mAMa^p zC!;4i(Owm!tqMvfFXt6*{V#b58-6F-8`iy*%TDqFj)>d`4?oy2qUj_$M=Yukt|;%- zW~pTu-n{u-wL>9xT>Ddd(1~Tkerj=b~gA7^jky55MOIX~|DD~|VpSioR<%abpd%CYO<}4coly@4# zG=)!*&C!9GJ|Rf*(~20}c22K&M_@1r+?s3Y6; z4O>Y?o|=;Q5m?WPII{*YwfLDMMVsoj`f7OLkx$H?d-db^ivU*8aC8S+M#I}FnlW3t zZm}vJay6F-^U;}!xHsB?mP`af8wzixVtTrbba8YD_KiPt5m)ovx+tzD99FHN0u)QMfGzLX^yu?;! zVn*G@rF%^Gx>msxi+b=^$d&oGV2(%O#(Ov^l4EYhJr?r)4l3y?AA)Y5(@MAzO2(Y5 zHZxeKvP-_T>~SaW&YC^j&zICjiE{VA+8sZbH9uUtP_fgHZFD z%FBiU;&yZ)-{8EiNa`xu_8~h7<4L$6_T{_sqEuSH@982JL-vSO}r4%27+mMalWyo=>&{!MBGfU&h(vIko~vBo|Cl?e8jm#M}YG& zH)%xO(#u1aNzJQ`JB3F9$1 z59fSZGcKLxVTFHVkuam-jZu(Up!i?S?fe+@kgM4)xLn}xTEv(D>7q?fvL%GNH%{PP z)FZ$Qpxvb*SLpw3hpouLzR8W6GGlBy{n?;&+D*th3kD^{C+t57A$bsfBdQ)Hz(t6q ze&MW6RNK=8mHlY0VXIe|o6`y$TP>$(t-CIc>s@{H<%>)seMKvWtA*!tBcv1miJ*^J zUcKf+`!Chr@*#jSH%6Z+$b@DlFTR^G`}}C3dI-zlYKk_t5Sf1pOQYw=4|HS9=|Rd~ za)}Nz66?hCZ)|YoLm3>Ri_&I`=VPtU`Q9h0n>i2PXXw+gdtuhK0K6R}eH6bUA94^k zXK=krTJn${{)b1JW1oXQ;_PCG?&OJc7lxL_&eaYbK^LhbY6Q#8;DIqZqD69blqz4z z>+Bc#X`;JeK}i}hFv$+Rz0%(@s8-KMxi4@3OI?t~>cS5R9EDD>|~jOa`W0F;|eWJy-+1w6YKbgbW_w$puaV*e7kVf1D9RKd&` z-0J?zm|^st$cxnAh)Ju~bKRD%?{r`Y={ys>y*LD>H;MSLYXQBgvrq zq~~0bxzWH{y=;i`vr^VOg-y<0?suoIlM*p&%1irnF%awu-v6WQg4qcJU-$E95qqY; zdZB5W0kYe>pHT_ZjSiqaRhV(*h2Ij$?rc`;=F!<`2vESF$cfdOQ1ZX+4^-P?5|(?Z zeEIXpJOD3Zquk&H95`J@^aHo!c3{}+c;@d6JJ_lQtC?f^hcFRl_#dgy&4`+&1RULj z9jo}C+RuUF08T2UYqF;ot+O+mPC|5EoVD!p?oiaEZ^^3;t%r{RXrJiX#9I!qZ;VAk zR@+gS(h54{M;C5;V*$}cL!u(^rfy&9oEds*;8L@m`Qdko78-KT7x^hq(DW$hpcYr$ zGEETv3>SqjJJ9Ml<9al1owRC(Z|fv1qI23@i7hS)?SfYq#x+}v#XZ4EGVFOLjt%S5 zF*o1d^&4)BL|`bZ>&?d(PZ&6;88RzzPC6I2VVm_*_ifcARduCyyZyeCN3T@P z<|7|)-Hh`cvLaFe6j|5$4XbAj%+Br^*FeWti9tKJ${BjOG!N~~j)!Z)JG}CY{Tuw~ z5a>;1p|ieb{{loz6O@kR5yD2eP~9$D>c3Et9Pt*#`Fm24aqQ`3JRxK4?q|Pebx2cL zEfpPoE&CaMMFu}^7XZTbzgRBRjP@oM2Go%+V9$Y~dzX)85?GLC?73>M4=-z06Uz7j zeh>#Kk8_hXZ2urZfa~A8=xQ+!rO5dQ7JnH$luJ;r9FuAlm=A1x<$M3Lc5Hu6Kny8* z2pT#`Qzm6ZuudpSp0&Vs#H>h1#z^Dw3_zH}q01u!2xYOHZHnnn64Qjuw@Zf?n!!=1 z?#*9~oulI&Uzksll6+t#m=oCnv1s}E^jb|>IU%4I z)0!hLHwJjzYCG_g0)BvA zuuwktf1wbWosVG%)_Dyzgx~}}yT5l?VU%9jHA;bQe$0P7P~HuZL#m8agCj;%c$3OI z5rm||^?A(D`G`Q(A-DfUw7|!5;Ft}0_)Rjp+236Dg&E{cZ%xrs>b4dS*y27x$#-h! zsuSEPsD29Yk@%(MC9V*+r+Q3ZGXe1B0`rZrMBswd=x~scYXfiDT~oe5Ca4V4|6lTR z7IzsP6EGmD)q<(*oaz~XX56TvJ43IeL6F!?|ia`+Oifen4TQ6CP92OXiEO`A%fG!9Aa8xB83es&QTo0U6Rps$PGLOc)KF`v7N zADFwD`7me6G3qG!?d7JmV2#VL6}{5CkXPf5-tUN{8vQP8mwU9#^#S!nld_gPy0=gs z)*;`TJLn*f*c-5|BY4wv)e5PZ?_ zTo|6=O%Fe+X|@)Hg0BCAmzQLJJTxh6_X$0E_+)|@!4$1)ZTz05#s|}efGX2tq9lB+ zit2uAE7;0O=r+Zhb_o*(A_XV*u|kGYJUIV8besATDy9@LxZ6V7cE%CeYKosAw{yP^ z?5>4*H`w9^3=PM#LaX!|m1V35Zat;%Az4M+w977n|MOJmB2_Ry0`pr;>B4vsy zRT`a3FSF~TM34t7T>1M>4;=In=WxNUT6bSoC~6HM7p3t zuCc^J+O+l0gsQn)h{^8*pbAl)jz6FG^=A)huQpqyOoI%BRM6ZElI>Xzf-+$?jO5ib zygk}?$c_*S3YJ`DYzp0hY_-)x(w+=ULk#2~6}9xukNNosJFWe9S5cALncGl|1d%Wg zQ{Ju=$Y9_qU*n=i_R=s)*6HsQ**$ z>E~Jx@`Pd0PoMGt8^8-|?WSc%of1onJmf^0w1Bh8N(5DwwPCCZes9*~Nqi5GcMr%< zL=tbt$PWY*N83Pw$x#%psn09y?HO(p;v>GCh#^`3plYfCQzY>%&=h?o*ci(Jedme? zcLxA)r&Y*7a+Sg{^#Z68b#Qb9JL=d@jEdQ~!hOc63(wd=3y`h}h;z!)2pV^3oQ1?4}G=JLdOJphHY~@-i?4{x0gE&vEuF?#6zcD(~m!UIzxpmKQ zW=D`*Ks}}5Wp%YVy7%|<*2?zi{RQ-pjmizNKc-8q0{v6fEQpfHgkLQd_A}t`>_Oq` zdXOFPVWV5pwsvN;YkwZKRKzS>k!yUqdqqvt)1aC8hB#|;6!qtWzLs#vvD>%CRw-IP zX?~SyfKJQfkk6R{z2!e1j<3+4szqTz4wG?M8%z;iVu)IJ2IG5CE89t5%n~N%Qb~2z z2G$!LP6HiS3-&wPff|S>I(5Xc+w^P5;5~5fSaO64((&-^tXtio8K%O!yrWJHM(JTl z|MHb&Trr*GxhgBLR4H^aYL6@?Dz9S=7}YIwV%71g^3_t~W@Tht)y$EtfF8W%UGjTN z4IyIsF?G`uV4e{$@X*SgI@&Gce0XJK35L^2Ep)31{7`n{7Av3=^eUCdgJ>L5Q|74< z^%^+OG_04!22hK-|CRFTom{Rxf>@<$)%G!;107_NMq)5=$6~n2A;H3#?;$7uS*=&n z;QE0!yrCRRpjt%-opg|L3p-sI)c)e;Dun1A=CSE5m!xz2BtZ|)LRW#5EnAg~;x3<#bQi$vh&AHNek8pGIJ6{l)LuvA=B4T5hI@*fMMH{AKyYyH62 z%ec;z7O4iaZzDo`Q#U0qx4l>RnO4RBGZIlwGcH(gWJ;tCI+8V@6il-8`3b8)-ci2T z`4qR&ZhtigZI+HYCPV~&gcVbPb@0}vdffOJXW_GY4)UrY^lGZ=R?{d{XSXF(G(w*g z2u=VvNP)K1a}2rAX_1kK{Q|8o0}UW_C(quk`69FZp%bT?q-s>jRTSO8t#UnKt$O@A zs=M>?oTKd655TYW@t`E#tV9mM5AI+6R!GqwOI&zk(Dom#xF}+bTJZ%fs|==w_mJO? z|9%;`D(3b+irPD=Knq2nm^X&Eg_F?u(fgjc=eY(@I{J5{EbW+ExUjxkN*-^kDk~2a z5b0>`rL<1cX3mH^(+`m4hiN+Q_0>xuK{bN?!fpvOg3lrHL`wykBd27CY(bF=`7Kt@ z;|V=htuu^JKPg*kJcz_DHUnm(r-lU zG*q}Qn*?sc3wO9z(A4{j8;V>DXLdnXt8_IOY|2dx=5%>kmvUib1qOp{T|>@OQ+!X8 zJ`rUGq_!!qGklsI{iIYGbgfoTYJJ43pee|9f>S=0IVNE?@RQi3T95w( zUPh#%nI^!VLbfIZzq+^mN)v>u(6eHJh!poPm0y=GsDf%kMZOKx-(+1Ut(LoT-KqJUC3JFypy8toq;tBoW!L`81(Y=>Thgjr%_!U39Bpg_fm*1}I1Z!5Ln~WrI=|{E6%7s3 zz-JMh2!pvPoK<`W8{;Mk8T+H?t?QYqRWu~1?|wY8A6FUe!O&89g_f9KxIk=8HwX?t z#A@fbZq&Q!vfcV8PSe~DF}%1LJ_f(F9sr;W9TrQ9{^s=;6+ZEoGQJ7G1|C%d9^FU+ zNzf%ZpyqDDI+uo}oQ@a@He2lykv~!fwtB~Hl_x-Bwkqu@C~^ND?WJR|P?G%l-N(eC zt%-{i7?DSl)htBaR@ctR+w2(j+^^CE{m+FOcjP$~ULGJhFk4a2$KLMfQv%|3DolR% z|9CF2q@k>T`;g~u4hzuV!g+Ab8}VC2A-oBc0Z4#S9%){r1~GTxAbA}ou6VrXj8K}1 z2(7YHb%WU`vd-Hke6viQ2z_HMe@z?Ng4IuI3U6lt}WK55~CWDpVFyV%Sl&^wbkBem6%gO_Bcnq2)c-0IM2{$;iJS674Z|rK3Iz zw#O@KZ=}M>E+S~#TFMbgjV&CFV9_b_1V2Odf_RrZ@!G)6D{rn@q?pr*0ZdF`K;ivY z=ZekKQB-Z1ALff2*XqM`8^^t&JG=}fZuu#c5+VIsVM~^^OLLwgVy*7by*?MD9+Qv@ zD0QHZMc;+StD+iTsVfE*Ar{!0MUp7pJR6z+^?Wcj#T>&1^imWC#xWhv?I1nIRjmI0 zQLI?4en4|hnUb1@=-nehZ&L9ie5Bv$|=PTUcKzeo4#o z1M*E^TpQ2`wv@WGmM)l6Dw;K;m)f3?`X3Kf0PCL@BdLb0+H|mC5)zy~w~<|IyFozUq-`rt8RaAHXfDq8qp>#0 zHx(*P)ExS*`i@>dqOQlSP?LbTD*L7(eMgm)p2{C#XJISdLMHc`72^kpy=JS#@ZfuLUsgU%x3(lI~`AgdZx;|>;Lb$W*H*`6pOr88A0S3IRZ`+ zGymNgZFQ!s>T@(l`px?b0Pq^U9SeGPJ5xH({)k$?#b}Unkj#)tisvea0V3#DH z?@azl0(6Z4NHF1{@QPirMq27iTxp~3Cc_~x!zvEX+97&li=(n{sH6(fz}osDd1da& z;7Op|(R{7rY#1SJ{gt+0}I-)A`9U&vAG3C9nKpGq!zQEWII5kpOJcp-yVLL_1Q^%$Eq&W=JcI>S>&$D==W zDF;Kaq!1G=kt`ZiPj@ciyM>ju4)R@mK!+r`^`|S*!MowT6lY5AEjwr(Wy@sRI!BbemuU1%dA}gI2f(gT zw}wYJl2K{~xgZ9`TBA*B2T5F98M!kua+g)be+7A@_w9CG{j$I0@$>d zf+;gsor>!~r#b0WI9s|fo+@dYMa(7)RH?2r3X|EUDYG`Qnj!`i0bmOPH}vnu%IMu|DG$2W4|4vn&i-bj2U3d^$we-qTm#fE6%)nat zs5le+wwc5-)haDq{^1#S<6PE4)RGsd0J9{jd@?*bQ3}b9ac)V?cKd+()~((gP>^S8 znz)}CCR->GHglX34&tGjv%t4UQhH3oT6YN7c}n->ttru@=Y8o_W-zbV)2xhKnYLU_K{+?CZ$kC<#~>SC?t<NA6=AptYK+}Jp& zh8=pz5CjSg4OpncVrF-z7lt5|9R@STglJN-iOMFp=t}Q=PeFahO}<<)(IVQS`f$s^}X&EcL)!s;7!0(S&NFE`t z2Gwe&N@l|$glV*|wG9jrTIf0D&zDfjl_%|;T!c)FmmB!G9#hH(c8!*NF;`0=W7iNi zZCD#44?xG5{wD_!Crc=~EQeRgRpZi6(>8yY`B{E$o)1smV2&kJD`_<$tPx6(?J@fI)C%IP((Ws)?G*a7^?e3AglrUdo69&HX8C1287GuAL3<%Fo0U|ev@tMK@x9C`U{s-h zL}$wo`|qW@>XoCB@w0OvEVYnHi;BOXKyZjQQ!NBCEP27kK)WFsn7F~nfLHs6GqgHP z_q@2M$p+jr`)Q)X+v6QC2O+v;a+wd@9n{NV`D1sp=6L; zFq;&ZKJxlLu?by)GqwX7>azj5~OY!npjJ}oh;WQ7^BIOv9%;!`cBwqHh{lJ7oKCA%| zO7c%aHgnsKb@MEiW_pwIW<4I-ih{{%QU2uvsF1uJZ&)FtvKmFC>mqDx((|6sN{AR< z`IjTVm6et5=nFCh-4a0CT$#-NZ19R_j}XW;E9!)Tm*qUH1^K55bk2QqV+@vA#3RlN znOo;pK|>9Lv-G-1BMEqmfTb6>3v@bPqrKsRIz0Xe^68C2 zPyX<=FFRqq2i|34bVaI8b}vKnZh=HC67#HXc2%DLoJG{zQA^0Yb-Cwg3E3jJ7~^~K zF;ozf=;<%uIM1*}fHz2;=8R>xWpAjVBu8N`QDU1{LpSYQ-nB*jRSO6&4!G{OR$NoUONpZdI zYo_pB*?d>)!Nt6*T;LF~QwH-!jSv`0qO%;#S_*NRfa4t9c z%AHhc;}ZGCN|U~H!lLLdan;41mIj4h0Y(?^Q6D@x8f@dPYrdHa`BF|$8`P-aTBmXT zUy7pFJZOkG?g}QE{VN8!K+Q}UF8pIU#Y~(06N^;s=Yv8GwA1|_k^AJeMG&t4DKUq8DrrFfd;*cU097~txsuCIne(Y(y64C zG%PJm^1P&P9eXHGBhOL3$eY` z06BF;X7W|dO}taM9U&eag38w^xZnH=!EmaHYSB!_m$gP9w~al(I+$I2SbOuFf5R#k zB)sDnu{#H^`-g6E=Hsm5O>l$|R@r0-t{VHH$K%oW0fN zxV(?&o19k0EmEN-UoI}DU*w*i&Fd^*@Gq(iz2W9YJM8zr-`rt$$ylt7yRjp(7UCIq zgUSQ4UtSLD{{P!2itos9N%yUI9z_|Ypr0xshGsg+ygrscxjS`xZ5S5Ei222@x_LKXdGn%lUV#jQcnFu&VAsxRhvSlDb}K%)iVjgAUHz1ul! zpP=)6k54r?;3U8Sxl1PM7+Ds_h|ax)UN*4zF=Z~xKzt+jw4Rf z32&53Tyi$+_#TL$CEmp@PD-DJt#QemREUQY=P?>P2H)KiW(#hBJr7sP@O@T^y@yVZ zP_71-08^n!s!n=Y^-wu=B~g*nkFrGw_*8C|<5Vl*!Lwg*vW%NQBUp4<)Ph`2Byzsz z-6JP00Y$ey*<(?X6>{lSA_v63c~Rh>*$;3aP2Uz+ncBv#){Zwg+{rR#WNPv_=3`L z((WEu)cMSVIwl$p0Jhzn+!<698~mM^h*br&BKW1#N{9Vd?q)^WaddBAA%>n7nP46W zxf+XRFHtkH@mOoruVg#VZ;_9!f0{?5ee4sf3|2D!eM-7yFcyPH;3#0LaK_X_U~xyK z5JOQa8ey*Fl-Hugl4Tzc8uUADK%a#;xaNgM%1@Y-ZM-@qW0QxSb1nAvRgOP8aP%IV z#Ez>M<2#-Z8o`kB``E%XbCL^{DMEOGC{w%*iVS=s<6xGZc*P z`SRFrCU}h|inR|MoYJ7NbyRcy?8%rUzdZ^KZ-g$<_e14+>KR5W{YDmVaWL(TnuTdv z8gr5LiVc}8CZ!x;D8crVr7aC8`BB`ao@4zK`hA9y5yVuZxK}>x=x$HO`3++*gU6}g zXj0H-`C3?6-jMl8mHZMY(b6vBz-m{IbYu7sG)Dc!+l85ms4rG4=~v*vh-MAxF^L4U zZ>l`RAGmmeJ20!L`)T{^Li8qY)Yn`d$_G3?ssbfqi-YACTp% zcQpln&l80?O0R2LRP(vp%h`}p5N{3|HcfTN!9b6!JqIGG|2qzz@X2fsOzqJkZYis^ zyhgM5&DKEO3%0K~p1u4~dM)yEclRKZyUfpWB*R8{;6~rS9ur<6Eble~1$9V5SY7z! zQtn@SllZs1TX^|%ct1~;i3Mb7G%{qybm_rw?ntO5NA)Z@JKR34t}wr~C^pLco)x<> zYit)S!CilqeTqvxbb@bHy_+fnT#PV4^p{mi^OKWLv-|wo6%-`dH)XBi3cwl7naqD|Wvt z_R3Dx4i$v$b}%YK`%&Y8s?yd*%o;j|P(2352vD_hOc5?V)Wci!t=Im^(FBrjs^h*# zcZY@GwcM2UTe)DtsKI@>_B-HP$rHcO1(Mf)4@uv9_N}@u04KY6q;*YWzmQ*egf99C zpo`m_yMi!+ZePv$6SL(duU4DNeJ+}oM8$&~nJ6Voqm5*A0gV?-SE3(GuY#oS(snDW zVln3WaN}h4iCqo=g{~szZG{pjbSS=#0TV;ew!&!E=lUj8OvCUudWp_!va$Ho#6kjB z7=6i~rmPJUl}nK-J^3!&dncc#0L~H8;HsF5N*hL$hJ#lP`)pvbj#N+zfyyG#W3`$& z6qH*GB}RRKf*2%n=!?i?Xp;-w0^_LzhE^{_*5rw|6B z(zPNM0n*viTaWj|RucBWUUFHr3H+;W7e(toTtiDoSgKtrcyHGjrYrUpNjL0V<9X{j zz-G-zH`R|%MgQXtV=J@h=y10G6UEs`RT?N`wMx{|L@&E%_j6Yc8)b&N!Xl>diD|G; z(y0_n&SIwgahI|Rfyc>(xR<0ko5cml7s{W>gFnRdoWY{b2Gk@2$sjpZPGYjZ3E(8d zKyXk^-IU-W$K}axd6|%YKk)d+aN&|XoI)$f9EN}%3A1g$AkSgI--B22{RGw~hcnhq=^@qpvcJ%1j) z^>Ao|zFW|y8u1k^yBM(!IihcS95x6pvOCh?mvvQ<+PaH!RPt=@3H4i@2I67SHhsR# zs4$(5D&h4mrnta3VG@Hq_wfr{KXy<>aAM1?**gyC)P}75AmHpaMpLrqcL+OS`4F}J zasLWI@`XJ01QKXGl_N>pulTo}f8{^^{Xjr&zJO`5TI_rU{N5 zNQrea(SbVr#n24How|icf96S=M(+&|ApyrNV2kuFqp{}5O}yMw;0TRRQm6IO)uqL8 zX;@K(kVak3E-r^?RIVW?mSwt<}%mKD$b)eE$ z)bR|?-d~PM7$x)SfWjWEQM&au>BpH}7q6>exY;N~PUC4~k(GLDATmER_=i=mZ;&~}1N zWjrCD?kc~IY{6^&(8g!;yW+cX6Hwh{*iU?qk*89~0+NiAD)*H7{xG|_LPgSEm;Hfx z70G@+LuPB=*dkm3wlTT@k<*Q{-jjzR!*EtY>XXa6+WsiG36;Apgln`#Mo8Z@dUL-b z&1xm%Oox5tQPz*KOCQj62|RTDQsqoYRE}*7cJbTY7$htyG+|HvKSMpdB>4N0zLuwe zRyUQtUrEzIygPU%tU=)pzQYySRJ*~)sqn|s;?C-x`LJ*~=pRRPPR zC{QA`Aqk{V*na2KQ)A$JnEGX%i4`doF82fK&|+u}NZZuRjsXlj2z_q7fpbmQFBA*L z5NeetP8xT%TKe^DY~@QvpN2u*bHxs2a}Lf%?6;&0DV@BN*2*n7lTb;`hnbL8IM;8N^IX|v5 z|LtgJY7(6Vn;!fWnp+bWqjVe1Nj0w|=Q0b7i(lg&SzO7VFjZ$HUjQh(PZ^ePC#IJT zb`2vETp}Egp4FBas6nk^J?E%&n%+f9rgQ7PdB-~|E^{7vZ)^p<3v;4Nm9lIST`3F! zL)RZSY}b$=hk__j&=4@$tV0X+B`C&_5%g~~QjP3`GwB&)TOnzmbtL(3dLLHv?RZ>1 zF03~*pa8uhE7Fb4Pf;6*8$6}rI9VakAaPZ&o-d$EA4}h!PV?|RpHliefek%VIa+Iu zkZ~uFWYgc~vU-$lul$+Tb_0Fg1KdA#arWsZW^cqycJ_`5^Q3Fj(8-K;!sxVvX`|LT z#}_@KSbdQf4MlQ3acjc5I$gG&P$Vd6&y40r7TBzINp!kNe37lXn{>AOAsdGeo0=F; zob9>~L6=0K;uA_Z2O$7#_>$QOS#SlTmoudkz?PAz53)Chv4>@H*U_7(5}eV>@(t>t zJ?D%#3W-xOp!o-sRtyDdW|rq~&lZflSPF?tAUm1?zste_JKSBl$AQVs{)BrT@kgk} zLWL|IK`b_X7@#JQ#Sa%*wtWbgy|xZqKs)XS_2*}Y@U_Nvu1V)UlMn;i6=;7wmakZ) zaT)(V@SHpd3RUBIk!FDmN#@mbSVs=*u}#8Bu0>V>OB?a`dA^p}&T8hFPbcWCU+Dg^ zxej2glG5$+cPCmycg;u$Y!J^<)XwX%CW=Q)z~9-(oJ7J|o-u1DwvyhiiGofzoVApa z%_E=@Mo2PORkqY9xk(gh|7d-}5T_lJsVZ(L1Z*hq#rHTg4`9>3MwcQ0j@b7;Ykms1 zc2RN4YTzfv@_JS8IMo|Swc>Gs862KEcAwM#11WY^O(m5^zk6sU}TcUaXpuua~t&@-#&bEYRKID zxL2U3sUwHsX6;vHl$?FMZo31vg*?j3Us-ZCH+BOL@Wv-_lip?e;u9}U0^F}!oxql?IA7#2}F;FQ3^D#TW%idZX zAFYmcH#T_9x)E3W;9fWYd}-*o`7{l=vo6{5g}i>Ss~~kreUX-C*6h_%lGN@-ytQS| zvR5UD`Y=J9LY81fq5+f<=JB%qCc+~_N zNuqbUE}Fv>3FBlD+#Dtp_^cFQypuC;_ueWUaW4*4s1kmw69bsDyBKQd%1`bp7i2vo zpEv>70;GAgdMmQZ9JR3#mAYfi2JFb}kbmhI38hxiA(r457U)78XcNP37GCu1^tWNADoFrMD^{AWb(}1U@1X1~G^xJPN<^&=G9vAsRn!WVIn9B=@c|Ot2Z~z6n`BnfGzP8|l2%O8# zHrVP#-)enHqY&5EG?~v9v4W;*N5xKey9H7xWoXj5K-fo5wiJ=nh1WYCqV~2dknE&LQb(Q&YG$%?ixtAWF2k z^o*2ExB^Qw_<=kZkYQ>EL~)G8tUDgaJ{D|Q(M<`O-_k$M{5R`U|FDD#1h#xO+}1QK zz#iTb!d(3*ex}Z!hE3MMiiSN1J~dWF#N^O6a7-^a``hT&oOuc=*IG-UO_(5pn2M#8 zh}d)%z_NVbUo7CcZQ0}QStpHvoerjjLg(6o!QbQB25N*^ zFSTE!`!7>|sB}!_cza~2y0NX;VL(1t;%s(yUnypzV@^q@`K%DM2WDeyc!=sfV zA%1cEU%&KGw6YL_1hJgdfqt{e`2DE#8dCh`sH=@Q!mA(xoXKD#wRoh(t+JX!6TFL0 z#c0@6d_(GlKsI5I8`lQkRKb~uS1Q+yreq6WMmU28jyhJPCPS=dT$0CKvhRhnMP&NX z6oP-@re%JD64t{nt*ly))3$1d8g)c|A?wQlHfOFnzv@$4a> zK_{^ccX#A^DE6nlT>YBP*Z#A1Z=C$q_6e{PuZ3gZ-EMNg!gZHt*9VGIn==k^HuMpM z9OJ=_==0QUQJo!IFmEf_VjLXQAM*&+vqYWb!D0bnX*#E|7o7sMX$+z zUm#l=n*AXm8~P5rV9Q*FY0Kvib)z1n;1;o`s)9teDY}mSzex(j$BY;_watpqa6ss# za*TO5)*rCnFFA~4`oykdm>!X;e(IUH(hKqiPzHP;a!SqNa~6m?*+z|^9L{f&qos!S zj{`eQq~&r4yJAkN!{9C;xFR=L(MFxC8Ij3V4QY*TekDx`EI+CJX z_|u4p`gFRk2!r3Q+7KvPP;|i*xrvZ>3c0B(6L66B50?YCJNdJNS&)#aZSFGr_X5{0 z<)$3MdNWP=v9Bnd8PNc?8XPEf$z-fK1ND0S9tNrDS*NSwnF!E*g{Gt*pOZvsl@m0G) z3uoN|a<}l$rVa71K~pDm|MHSS56jRa)MKDYZ=K*{SXHu^GJVh;2jjV;f3CViBo2rd z4@PvrppN0A6392UYo#XUSgQK;8Tukd@t>~+%h%&%(0{xs16X0-FgcVV8a5Xh^7L(n zUJ#0`-rA)utwCB_Mb~*FskKLU)*xPNDh<}h^Y*v|`={W`-Lpl}V@tWit07kT*>EUEB02KAzr&}#pd{gRnmv;h3;8NSA(yrx`EFp3n5~ofUg3vfFOwleMDyjE%4G`rn*d z^@GeYyf}UBf9&il`V@PNo)Wf!g5X;S=7gtX>%*6Q!2Z z2Dlh9ByBVJ_mB@r)L~S_?8jqjW30w+0f0GP*`=C|QFul%Nc0^>GsB#!vuMhaJDnz; zisX$-_$9QYVlfQvUjIeN1dwe4m{DJb^7T*EbcnH7^LCnc-CkFwTkc%_w=Z7o;dkUyEI&^3FvP-3w^n-!5rf{VS=gFXxSRIqFVs- z1Z5mnuUN5$V}UB}ArR*`$Z(h!p!v{AM*anQ7zZLm60o0`1Mr;oz6_hBL}< zu(&O}QktJn(dyL5NiEVTcm;n-=i4&p$JZ4Ap8OGO&GE0w2i4TV$ZE$8v+G{A3;gVb zbOD0;mDTeCZU%OM|BN3AxV6O{MJDT2apsG%|J$|lQ8VYcT1ddk+>+MxIQy7VV)RiW zje&wc20c*o1?)h_*Z_vndwkd`cHUkY5G>T{>~0U zakTUVT@kA^*DF!}w+j9%gey{f&9-bu!7e_!>m#%gpW?Xb&tYy&=Cy@!#BX!*vUTVI0KKpt+8UWhr~Ib17NAdLmJZhy!|exHJ`#^ zZIAaVW@%meASTqy)6G8=Fd3?!XU<}V$J=w`*#F1RsT zWsp5L8_KSiodfpruDVE2^50-pp56J6z5LAqy*r^v5|f&l!K%spdWYdy&9ug-ypS7b z5Io~0O-4NfFubbdpw{iNgfZCmEp(-Rjgw6Rj`KoklnA7r?85n21(S#Wm4(tcJnC>L3#gm z(w~6%%Pu$K5l%+(^vyc!f=s$ljlc*=`lT7}#u1IEAtuB0{`}So_n*da*B|Yw@XAJK z$Q{Ig`9>=UtJpM}IZeEwygzuO&+S}lyLS1Ondd6312rW8wO6)BybrsZs}$uze$Umf zjkwciud9n^nC#AcCcEfree^3(s$PnuMn@aSvuuhVEqssjOjjZY+Kseu+w6pqKU()v zEi1n`_bm+js!dMOcOT(2s*hOh7$>*R_{UTLaaPfq z0XflM8mQ8)wD5!tCT=!Ht6W056u!xL?8iHlQN7<1^4CC5NiAXlZ@YFrcwsrVLO{K3 z=!18BkQ!(*JoqpxO~?es^r`AFkT-w@P^43$Y;*JGbq$#sbDG4D{`IkaMZ(Y}gIn8B zZ%s`Usx8D%A$X<%-KA0y1P#3S_*E#KN?&R|Lvs-5LA_-u)1(TOgSl-0*QE5-0Pz$` z=eaN@e6T$4VK2s);O=|n8CO43?`|o^;Vs6_QH24;E{i1aEe`%+mQ}oB;vaasC?vet zqVGjp7^`=1uI0&35X_NMHP zr4C{c4Pr8YZyp>n|90+O)*59o^4f|X%gWfuOYg)Qu;6--x5@6fm1duHt}wmlWCRC{ zpp?Vrjp8U5Tk}`t@JuAwoObI#Ed^-o-6S6W$G~F+sOx!XDmUuY^RI!@OKi zw@r;(leEu1DgP*mQYLH}*=t}<@^#>Nh&CSGFo&3|IMeNl`W1c&Y&k-A32V>8*>46- zGgha+Y_xSp&r`dFlGhrho3n{Ux)h0a?nLMGjK;=Sa*g=gbZL0o|}w}Ng^LF z0t=pn8;p#}AkPUKa>E==LX@_#8w;=BFbl7+z&`-564o-f(QmU$#mh`ELQ6&iScNlD zDchoDHN^!zgWFu^@w!Cr1e4>Av^(Jv%_AKdb*o;mzbEoMijJ8VQ$Gx^&!sJw`;Hf&7bknbSk|VS>@bwgNpB<`2<3Euews?$7ncqes_LwIKWK50*rJ)6d8HyPE;uBqiLbm+Z(f9 zc<%jgs-|Sud!fik7GFHyn5;=-iPnFx6|C10Xe$CtPDhk339c$|6;c_t!mGBI^?hs(9KqDK&k8PlqgoY-t>#e<% zYkVaJd1^z&CXKpy#9+cp9J}9z82b*ryV-;!SPh`eVco#xdh8mz>cX1q=oZ9i?tS0)^V3k3waC?0#^+=H*`%1j zhsRZS6RF_S#+sVGKPc=!$Ti=`KjVlMA)fyIEMqX05jAhkU*N$NqxiTpAyNK}w={I! zAx;MJ$;3vb;2ey)i)ye9kjmq1t%`%}UY8Miz(}hTk!&FrvEM~;?dftulQhGFTuqev zx8sNJ^Z0Z#2LGDHPTV>{ujk&+RlMq0<=d(fF|dJ8&X@igiq6+QYcE^fRXq|3Sx z*nv^S(MLA(>AVrWYi@bL(r^BMI2n1C>n=3}-lT!baV$>#WqzSjsPG!CrK3lUrHff4 zucGkYocJ;%m4XINw}Z2YpM@K-L*(K#oX+*hF7>Hl2Uc7B7D)wjVIrL^zDhLe&xuM7 zHqhL6^Kr^@$^ev<2vT7dN;6etvuig->Xmz2chuvJ2;a>tBap|DjXhb|SDSst>w9ry zk@w@n(_5*9gL}@UXq81Iq@KrKsa1Kf#6~0%z znw(;l%dM_@sl597!{PReP$@{~Ba57sd~^W^JFUOf6lpxrI*4O7Yj!%m6N6el`wjFREsXH2KO9RsJGO|u}6qoYJptTqCz_b6`JbMTZcCg4aR+zTT zOh~O28ik71^2NQck53=A^Oy&*R~bsHaR;Gn&T17Y2^f!B^6Q^o3`VE<9nsyF)|6jd zl*8{_KdF)Hj*01%@;76~fBQQSTphfp2vxP}K0_S|;1ub`l$U~?*LLqZcQJE@#X%nc z#m7-_8+AC7I8;=j7A9ptcp(KSlqWk3_*+=6_WnwKLe}g8IAE33L!;7+psX!vDPvpV zID?*0#$XT?byqZff&|Kn7k-9DBxb0rm@I~x+`b*s#U0$CW!i%+tus8JTn%8@g$X!R zM-&s5!VfO&h3%6WaDwCoQ^2q;;5tU#st0S$apL4OI0uP@{yt@*Zy^U{kI#!|12G(DuNfcmW?Lp!Oo z5eh8|x8xOpa;SibCe-uSCZN0;jZPnmewNG~Qk$hzTLyqR3&)TkP z&fWbnZsARuh+R^X)E74kaJ&@f*D8tps`O-cK0q-=^sfMuGQdyDdeVq)1*;+Y0%I1PlK58<)DHW! zWoYX@knQvuq>r+BlQHaZp8D!x)3WlUasDIGc&_Qv4^-==WhNOCac56zQ#%uen8n&x zU2fl7MB4^o_Ewv^&wWc{B)%aq0kdie4H`F^IMbm><>iqa(U#myX{LVL_oCsT*f&P8 zWxo7z!x$Uj;dWxBxYTgg_F;1Ng?fZ%4+0LMTPv=|Wnd|PF*J0R-RC9u%WBA|p<1t^ zlGKznW89Klus^nc(ani5Ru~KLHq7sw1al$gJMxOGu1#4d5Rw(Rsen^999_9wj+BD< ztmmHTS4-{a@8;pZf7i1XGQ+m!C`#o{KV%F8c5KNYIBK-64lw71t3WU?7z&Yd@lmbY zUfLF4mzU%BRLNN?~Q0jmI$5H4Kd5$Np4`P#OrlvYaC6GOrVS1<0bd zKQBn>jYqUXk!#lMAd}ykC}LIPo7ZeQO!KLtqV~Hs9(?_=>200>Ok-!5g-_eXC2*-> zi%Jt@Ja3AM`eMsTt#;Fuc^)hAy&Hpkr+9f|dNIdXq7szNYf$|=Thrv`F!4IVx#j_7*WL}VE1G;#_ z#1UYyY!I6kvXhkThcMiEF|@H7g?V_nnJ%Hbn)vuVn2e=$^DsWR_Dp@E`j+K9mi9Gw zE*xUZwxQ#?#jDJC!ssPC=NVMKrGd-=YL?__rHr-EFn!`WBh7_CuOz5A>IuY4^H-4M zM&uC%H;6tDuGUQ3L%vk*wxBg3%R)j5Xz^A$YjKyudS=wt1)7yiZ^U532jWYDp^D65 zR(&K#90x$uis9iKS+M435V?tftXY5K(GcM?Av`0-+DB^26?;cEc*uAoj4)aD8#P=> z!1f|bRq~l#%E!~vT_DD7V%=()QZq({C4fCm6EZ)>4GH_^PxR^T#&U*CxnjkkSmB4m zye<8wK1iMJh9=1eHeAR(xlZ=jeABLrfo(YNnvgYis0<~MD;3E?E&z+Jc0sm?Jl;($O<yq^!o}RINrQ zxwGWhf#T`)Y#dDeZwqbUs79jvHI2s&hXY0NinI~|n4Fg)bm`JaZ;DoQ3=wN6nk^L% zD6FL3+Qy+-*0akn6MH-|IS9qllK-3ib5V^rR|N=cKD|LK5x34T*xwUXjV>v}p(l~n zO0E6Pt$~j^ezTA~TDu4?wXw0M%_XBV%z}00hk8#@zq*)~b(rD4^?i>=PWKjb)8Zyr zB=2mh9lR&0U<9>WjGq!p5hUhkX0$i_PPBg{+p0GHI338|g92@Zz2*{mnZFK9JG*3F zp+hjMXgX7ll19+7|Agh(KBa98IeeY-6eMVj^TSo!Y0+-ek(@gPI`T}?J#F|&Byhaj zq0n4(C`i}07q;un9*{m8zmHituom>_!F|wB5%xzcSWmx{#iafl(9;`l%qqZq+`OTK3QX|x)MUz7C-!*@T z(Py48w6iaT>D7_n%Baa`my<*|Shi9eTRc+MYS!)58@%y?dQE28lZ!wUWgS)0h#ynC z72;|dI6GH1cP5$q{bszU63T1IenK)Vqgi0pR+CftZf3dl5%2g_;yM|O4zHA+#d2v& z5`n*xaQu-MuZzr?gq}!V%~|BV%u(<>FqVu}#pSB1DZ|X&0*Bk9l%UAqpdH6xwWRwH zmyFs}R&i)F!^KPC9I1=G-!=-Lg#nrql@XTasWl}GP1tV}gw$edaXEDSN@ORn} zDdm%d*#*1h+(5Z#o?!9(Xea#Z15?d&rZ`?yMs1u$I?lg0o z&3wfX3C!kcCXrw%a*7%zP#Fv03W_4O19 zEr24M&z>FeVQOj61vMa*)e_ctCY*pc+88uP+kA3@S4h2EIlG2{L6RL$-Js@{>X0Og z%ud?kf_9)!5E3BrwwK*6G&3#cD@gK*laAN{?TrJqB|wbc?|9-5-DWStdHbdFzM{Q^ zDgOBz+-3gLgCAT1Q?>$*MfK+;``3QUr3xC#fBIXn9g0lt?G>k_4)+U`9Uk+3lfbW^ zS=0?H;DyIET-1N(mco()`}zMK&+&F@zwyPU!2>}vt>M22agl#uWx(!ai@DUtRN?CQ zp23ke2MzOIFoPc5&fPXs&juY+Q*Ve*vkVW!k7EuUb9Dlp&3!QG6_2!mV@IJ6MK1i~ z6fO>WJ7tk|g#T?bXOVsFrHXQ3ugZ2mGU-R_s@j^m+ zo^EC%T47iW;hNk#}Ecm8o?*pa44;6&KpTR1=lI@`=3>esWoZ8Dr<%cTzDF#}Vw-azA}xgx;zt%hMAd2AA3dovW5X^=G?{Ea`?o zPbI!6=yeguoOmW_DlSy(93KvulrF}`=IyB36ZT}iGwK&`vB33}ZTjge{8I^ADB!%? z$uv`kvhEPBex?}cQ(YYLKX$09ruCJ2E&(4UPkKN#aEAt_l>F2$$2~XMmTY#n9(Q~dN#6k2YduhTlE(yv$|&gQun2OdPkL!u*l*LFGMPTF=`JaMv-VpzFM7V-Jc0`8MbxZ&juc_v+ZF9qIWo-}ltM#GfRS@ALi^LN#1l~R z;YZxk8dlWCtm?twiFG-tGv`_!GRZ|8i7K@f9jwSyYyFNUy#h+D&5`!eM&y}w*fY5(fEDb zt;V8Zcsw$S^Fy59e1MmH85ncUn~n^s3?r~Y z(P&#`EC6x_>-|KGx$4Jbn&tmKF#$ENj|x*;hxG{WWH={YmxtXyll!IGs!E<8%3?Kc zQ?{u?FIR8heEJJbQ4_>mPTu-{WPl-M2oQUVXrwxK5q^duFKj3Ylao>QZx=Z`UjMv{9`^Y{ z40oPq?6<48F65W%)a4W>fkuM-ra>n*AraBkTLy;V(SIT~pBX7%@!N6XjNy# zI(K*OVfIm$X#=pM`xr2DG+bZruP=W829EbSMuWgvf(*y1ufoW3g^ILE2_~-SMni1K z#b)p{)|@URR8egL@4JN=PN_X~+YMG^Xf7x}E=HScG3l}b9w*FiootgD-vy9XX@%mu3Nu0syN9~0(GG^ep`BCgNpg}%G6Nc$u-Q%1d zMJS*__P%Tk@tKN*sp2h3sLQ8usijz~!C0+={0AMxmEoKtrN?qrDoRB^aatuRN+Fz& zDA*NR2ykjZq*`Pq&N8vJuaTC@v*8q_!;F-)o-dngAs|v+5CxN;UqsmGz)^EXzB9Z9-fJ$rsrTFz=|Vx>Cu=nCm_B-t52 zJJ82_+DJwehxF{GC1_r*ernv1l_YAEAmsm|uGZ}2r2^d87rtB&s=fo9f6T2HJ0BXH zx*|a2IvpBQ3Ey4q5Zx5s#-Fx-!p<2Gk{5;7B#|c5>W)BF z?qJTs-*>LwAfwv+S44xm9BGRNun`Hg!22a68f}qJNH2h-19<}#{wD=d$qfOjdS0mr z0ks6+nw#k_PEMOYYj%Ds_M;;fSwtXMgmAS>lqZuCdp1{Pbhqa3V>gxkLu-wmiTst) zPLWOyQjpNKS%0wGJ^JSd%_57V>iZJ=DAdv#`5SHTK^Wd?dHb*r_;Yd!QQSqf?T`{v zE%qf(!$4?kxfkT$r;Ev6N;yv4|f;FL?ScHy4#HU@bz%jH8$lpyF*o^MKm@Yf;$!^38} z?bon)-@JJpA@49EQ6wBPe&>Uh*b2)ip1NN*4qI+gjTrync12VHY-_)S)((W+P!e9* z)xw!4I$ou7AGLuKYqJron#`6R=~!-i21Jo^+1$GVK=}M%S4A(M zis0zhUDA!jO*X+qp}Y z9`TEFRKN?<7TemT15LtnTmHEf?KNX{n!-n@B8L|DX}~eUfOJ_>UI+B{Yw81}=b>UA zScJS9HWv>tJC8Sdl26Gjzn;b@wcTRA4V73g+p`~K-xbx;`kXZbV8VJx&pR_@3#yPh z-_}|Z(FweU9n6lHNj0WCy2{qw#S-~XhY5bbx4ZC%DY{A?rKB1X4+8%Bkq?4fN-s=5Q}c zW9qIPya$&+666De8kpMMh`8a`PUIH}-($q9lmgOE5Okj5N|+-@+Z1J2v@!`M`*iEL zJD=rAkGOk5-v}b7R&us%fv%>vuYQ>c-WaQQurbBe>NcEHCfLtnr13|_ziqd(`;BH$ zS9(%boT(>xf&Wk@q$Klzhmf&O%I*a)^XdpCj#P&+eT{sfs=`Hg9BSa=jiPS_jL2R7 zKbZFbED8O?R%-R^N0vRefPunbq=`C%n=|B_UCHWRTfuVIv!Wwv9Tm?gIRysr$m^Ky z(&jE!o2H!zG)~mo^R*b)hja19sAzji1A!pag~Guw z%iE(SgP~Fy5mfxIV-mKubrpe9pJVEcl}+~cR9~>D@3pWi*Y?m~Lcg=%oQSH%bnm6) zuB9>(%IrWc87Lf^&>BZyK7zyC3!|!!U>^5ol|zgu*}Iid(d!XPsB-H+NAhB4Vl0Z( zP^k47TccTs%Ax!K-o?Qr8}X=vyax#UTVO+9`6FR4!Cf-~bxo)f`6ednUMA}@`qk{z z#B4%bKe29W3@p4JfWS=QGZa!KRN?IQfdw3NfLKp#er*=s(a^;>!l7x(`0X+dWK_dN zDL~k9#s&GB`_u;oIB16-GEunQ{{7;b=Dfc<>|0k)9#yd#ofieS?eI>>8mosV09bYe zwv#{50uFO$%Av_Iz!vj}gB$c=2RjA%NiqDN)LGd<%jApL%4k$Eoys$_B>I=8(RQ?p znz#LqPo2SNCox?%0bk-;T=WFQF2X7sbLo-2yQ0UQw@zpKt&kEQ{-VYy+aAxg140LX zFoTA1VW1-*eTLA?g;P@}!#{d0-ict|`W9$W#1a%RWnSyU13}DAT~fS;U;$gBa_Qbs zj;%4j=A1!ZXM?mbbq-$vkJJ0uWKtOVy)1F_)Z*{ou^B|{XzX+ir_eJXCUBBUULK_Y2It>ttoBO z>&I++@foZ2ls9m*Y%y@M$7%(X3wTC%Gt+Q8);uJ*m8jz&2j!oR%rF-DAb{3Z_eQcj z;2p};7X(mA%K(5zRP8!!H4tQ}rG^Zzxl8z?jgvWcZQ6Ko3bO3ip_#_9zFZl;9)}ak zh76}V(ERj$R&71?Z(NqrUw7KkG~qhRG+;1xHW4dBaEB`*cCUsfptj|zHb(WJ;+Pp& zC>+qxd?d=ho}!%c=}3SAzeHIl#Pda|Uin>vtwA+A?db6A$pqLz+36-C8EOpRQM9*p zBE)?yXIWjEh>Guf@=W^Hm(++qG66dDq)<;zY`RGk5shc8@xT(zu?+RZ51C2Pxuq(8 za2!&6hXYRwV*XlzEaK|7n<+!{dqYDD<8VAdI|;>Q&3Mf0u@Q1sg7sDDl^NkWMQLxw zwaEGM4@@mr&AC;<`CSuPy%Xj+yA)(B$9R0B#}0WY8Q~WY?d#puO)B%wX()i%n6uq* zNgdb`Y1UppFPeT39dJ=7-n6PyOv!j#PX-3|loy}9PuN>-*#d$17&0i~mZ+Fk@W`EMH;cxUzXtchLc_2}10|MIP=5PMyT!%@Ba~OQy7gtwSA z+RHU~g{rs)cc{y(0mRK*xd-(_2pq9cZ?YM6@_e3WH6EK+>nowrnmnHt4m z*2Tge)M8FGri{6Zt&lLHLlnsgo_)sS^iZ(HxpUeP@Y1PmTZo;~N7g6&o^AO)N!paI zNXPqC@iW|<3P@pRYNKL8fKA_lf2tX@f^(T_7>zzNnx#!^P2+|co z-c1$=Kvv@<@nfA=fzj<~-PmovX;UgGa057o*YpRa4ukgss}TA-`T^x2O2j9d^f?VH zy~69dLG$j74gaUtr7a=)e;m?MJ(8HXBkHeu&$$zX>_VNas~Y(BR<`Si*rlF+enu-s zk#9nO%Wmfkq;*)S z9fUcbXpn&F8@cY&&6vta2+V{}=#6ylX@q>L;ZVFUw5!W5z}`fyT)_WH)vepaEZ@1( z-NWrc$w_Ykx!tF=F;}v$0A%A^T0G<|TD`?X%tEv7dH((1Qh(*^90FDUI}@YuM1&xi zJOhH9u3=t1fyG2@OTBA<$=lJIi12{0ujCcUhJ?v(LM`?nvH+3$v5)kNaN-=Ka9jcR z#6rlsU;cX9a%2w$?SJJ|=kV~#z2r**aOF$X*?l=5HF*4Z?v!o(v(`+@Y)TpGRd-s5 zdfLkK*74#x3?qI9H>wCD#M%as^;J&5g;Gk|@$n?w4iU3vL(;=!IQNjC=kV~?X zm6hCvOLn0LZtV7Bn$eQclfAg|VC;8;e_9wX}(01!!7A%a z`r$I0$g;;93M^?p4Dz+w@Igo|yi+4YgGkdOeT>B;+FTHk@pHgBezqOxCK*f?jF_1Q zr?5OPbm0HP9N%unPc5FF!jK3m+BI~h9fXZM%`0X}q+JU*N7KOw=>RuRKvVZv-**OX zt@?NzOTn~sEDnxm_s5@p=iOaR``I9Tk}FuvUP{L3-;7>|8psiX+W-lY4jy_!W>VCB z;tBjD*9>B>Jz;}Z1rAxc-$)LS|2aKAiQ~vGJe>mIZV#NOsAyMvG;X*iPZ11`Nn7ta ziuEQZ&rnoE3RuzpVO-T{gN|>*Ab|uj*>n@l%8x%KbTEK{Tcc*8ZLi5vns3Yi)qAm) zoTQYP;{33gH|G8`5Y%s2-3DhS8GU`vkQ7(0(fx!|4nRW}MD+KJ&PZ2CBgtk6=2rrU z<09ko2mR^UYnxE|P$pqcZqf(EaQ{8Gcp7D^wOb9YB1NpO+PiDCR)qlzdz3XrPqSuB zj`xRe^FUiQZkhes5Sfi|(YT|3hwgHURK-;g8+nx`x^4XB364Pv7kN)eIR-2R4aXz( ziMy)c>vuvpngu&z5c>+h+`k1E+uv%W#!`W~3+@z-GQ92i+{JG3TV32Z*zn;_+_{{hO1uu!G2gPrnDsfOWEXf!zI*wZzVyS%WP* z#AS`Tu1J_u64s3=1E?7|M~)dR0Sp2teZI>%LE!L;wGvyIZFegquD<__ki*`G0nxX* z`BX)@*$U@&ln@vCWz1lHc%Kc9-lx*zVDyX$geUpCN#@YZ^L7SZP*z0(Z$^5h4?_bl zIMa}p^yd1L(wI2UHZgm!z}q>3b$i9+pKzapk}g9D&|+<|82F|l z3s@)HVg|8G*&ls7J(s1zJ+RKn1Irb;l=cxohpNN7RUplZlp}yo$)VSlENg zD~k$lg&dO3?|zO+qvNx5Q?Y8@_BdYm$BAXjQjVVi6jfQy>&@RJBpHt|v=5*u4jiih zRgiT;2vHO~+d9G6J$gjhP|C^-^Ym$DStll>wDw)G7o+Suz zi4&xXr-jY`0C&aE$f>l4Ykf`ym64WXq`w!i*SEvB%E49^osy|+#L=JTN`Nndp^QMT z>;qx9utS+Dk40j{$^*W{w&-jk?Y3mYa|s&aH@V9*M$JDa!*yC2w--)lpS~G7*F6%u zV%;^})?4WljOBuRpq|O7V&V*VMhXeyEp}dT(wxGE-kz;i&wdC2ulemCZcxckE-So%ilg!g3A!l>rfVfoN(yaEJHk<&-Hct;3z zZU{hqI%$&}SZVbj+qt`(GgC4-n|qLpxgS9XV_qyFCi0olYn!ZlKy#Sy)K((+OmNm`yd*a@O0hkm9g%K0_UR&j^kKSLVUH^v>1Gnt=rRaVe?xEf9U*!$nf;0>6C z8N?Ev=**?U!=85j^WW%=>Nqpoa?Ilibwh`Ks37{-2ScSB)ri89Auqku%Gq9R$^w=IeYv0nD$hY z>HLxmeBo9Q#cDa|n}h)OQ%)>ebWl3~DNcLXbP=r?9L&v=;NBpkfGp;`&*76CAVag) z7qMa8M;B7BAY5sH2Si#)7h|`OH#v~dSzQv|xQ)j|L3wtSYwQ^MT=H!+Y%`wwQA9s#lG_*%XLe}P-wSPL_!~P2s@olTuy-UjTq2C9rpswM zM`4I4QCnKo;V52j#;5Y-9mK35b{!Xa5zmxSt(vG(=H=qb4@Ixb0$3f?`%EoDpLoWt zB(jFRbX^$Iyrd|`CrI*25Z?Wh#FDqh6pI&ucxvAB4&^BiGSp>rW=#GWr}Pw@GFC{4 zQVGb?7kpOLo1=Af8!I-yqHYUYF~k0SdD34;G6F!e(VgmR>p|~5EE`7g%ylJ>I2S> z{eLH|+;%9EFv}v;)l5v%h5TF?aQ>0=HDr^JM_fs^Xs(?|gi~R8n^S_h*gcM@nwkb>g@zEv9o)8*Na0FZPYDXt$Eo=vR&=7BdOWdimma;3@ zfXG(&E(Uu?yl2A2g@bh!fqte8+ts#uOmjUkYQB&Hp(lfXH~X*3{v+u96zX~z4%Pqm z&pN^SGz}T`<161#kfGmVrmt}&wEtCw1-`m&&N|dK|63jap_KmZ{8kPBDGb&9kD(PE z9%B1LKO*EQ!L2LB_v#7QS%3q=35Cr0xIuRnr;9wqP1V(rr6Q_XSaY7={^6 zR>RtBeGi$jAo*`E$Iy;=7ZfT;R&5HnroyY*N6E?St-4t8@&6Nqbi&FQvmrDd9dOor z3Or9}7w@dH^ElKOmTp7F+0Fx4Vn{thA4G=AkJU}B-Zs(KDY2w(s~;VOq3d*bXk)E8 z@1&Wv-OZNiP-MiW?)5mDRUO}@oH)*}<2#xhr-2OmXF^vJ~K ze>@hMrUKumSyo1_OzBax3`OdfW2l0Jt~f33;JRETLoX{~Yd&H?TOMdA=_@RdGkheU20%`@+Kd+10$B)DAV1lk__gv~aO$YYw=5R3)} z?>kx!IH~0_aPoO>(eh7nAM4brOzAB=*#!L|yMhOwT?4*RHRQXToP+Gc__cDaTX z18<+HHh)FTm5`hhXQa2Pq>ojXJ2)9M2uIo*O0?9m@Okaldj-iGp=~j0y^tK|Tgb6! ziXIT}rUKrWWhZ??rYlpTPKdXNq=uycV?6+@tQVX{F1y(*0&k(|exGYuQsrg1o0*de zn@kfetym@7n2kep4=I_msy1I(Nk%)h8OO1xTgTUqr1n2Jl_4|bMBrU`=6iSbm^I`^ zZ9=C6oZW(b5|rv`AZ+902SaGTW_o&BrlUlHO_W%qC8RG2uHA=I6FMi3In&4%&B8ObJ3=@25ezJm`K=t9)I zF=I^rqE{(bO2pw@k~_rwiUMAJjH%bzhCIhBe}%;_-vW(23SidX(}hO>2SAt>?x4`% z2z3(1H9XSVsud-DSa+8nypX`7bw~%|K}DKL%fKgs+|@z8a>4k5#M!0M{@=6A$HH%G z^910QFKU+Pe@axIXnC`?qHhdyubG&s#u;c;C%M9&JHkU*R~#09)qz4JU>gEY&X>$oryepZ>-p*@XNB#)Sy85?NUN!r$Hgmx9l=`bOjG( zb}FA9yE}7~iFMO$97n0agj zS)6H(&2tBfA@26IJreLA$Q?lBZ`-+HlJa>M*U7Z&{2Nwt?(f=pG z0zw}ll!obEX3l%>#}i}zCX01nBw4-RfHPlu@891vEzcWu3it%|a1SPri=p_+cNxsT zD?042?8fr&)Q1KE2%?vZ2UQ_92RRuz$G=|mLT%iHz+nSY!f!1&_*%Q3^*QG)%^TX! z*31*c#92sKvsE^dL!zkd+vl6qsIQ>ge!D!fw7Tar>)tfzn!4e*Jn*<+^oEwQmk*8` zf+|e^z>r18lPB-aF5-tCV-Wxw)&hym6Qu*R2!7L7swdJwN=aFc8gc=%m zg85dxE!9`Mo*75nyDhff8<;OdGB9OF!SRT|di8AP+@nraz@#@>C+X&152uQK{;ycT zhAQg9%*?Xo+Ioj4kjd$(HNxf97|)_eCZp6qE|uJhJmj?Wx9eQpz*HC#rMm>jy!#p- zIwc!kR=@eU#O9RUc64*7FT!;0+xs~&C>(twsO@zEQ+yNrE1wd)Zh-7t-ZDXGBLzUo z-BB$uP9|^`o>z8SP@EgFI3)F%hWy91FgiRm=D&)WO|$AUkI=>LER+ErcI@Bd{gv*l z2}oDz1T$QmQ(}-$9ZlQMxLajl-CvubC@fSp{pC_Bg4~X*Vwmfkj%E|%d9Ct`a!98C2LAieD3(>uDSVGu=r}GF`KZrZLENG`e+~UGb=> z2N^E(&rK~pA$ldH!D=N~R)FGrUGF&ZF^lS$SlS(QD50}r=UBMGev&RQz8xwhrJIIo z5YU{Ff-wpeyT>Yktk+r*ISlJj@*0FNh!ilb^FC|TMWAokIXViuwMY*p>%^9Wuu>io zPj;Dhv9%6{q84KCYpu}lV(SAAn5yqlZ|NrH{b4FTUst%mK)4<^k(fyOzHT@y$#0ZU zDV?#Bl~!h02fLVDZqJzX5hd-n`_~9GA<2Mkh593~BcX>Q8~9-%?{I%`SX4E8&fBIJ zq`@L8+cC7@=mQ6`68hwiJB)&}@TfGgMLwLhiik~Amx2B$DkbKB_5kJLbOB0$Ap=5E zN2?c-=q-1neIE4`EX47XYe7jZ~l4Bk*9M#1{x zXn(#sm|ZX$P!{C0PAfJ;Fyqu^sF@nCw+reTlM=%ELf^}cNCy$ZSRIIJ+gRE600>z) zE-IuREnJY%Z#N3snD7>Yd4C~3`>^EI1~pX+#>P`S%Y}XMN0Zdm3(HpXM`ds&e{+<~0Pa2wFhwCo~m6p%Lsd9LIBDWk~}0A11c zaZ-HzwmbkM`FfAt)F>Gh`wTTB1YT_$t$cy<{uI(3A!ObMCG%YxbA9XeAN~BNaP$;5 z{$=1oz;N4CleD6Cpf;+cVawNnl^3!a6kErsbBkn1^Z{= z(Eh<@dSSjo7cBC+l~TTfh(M$I1G4YXNl*SYXH|FF@!afl`faJLHwp0LW>Bll*-Uty zG)EuJte;P(8oQuVIk(Q2k;Kz0Q$1PNqKvB?=8shoo2#j$0=ljrMMhe22?L-zuH~=o z+j?WSp6R?b{t0w!5vDynno=mlv;EH7-*~y^=_JQ~DBdbUr*2jR@bYVepUKZYqp%%F zr59FM=uZPPJO4)Mw+_xtj=d~8n+C1QF1qJL%P?Cp9r_n&m|n$~rcJb6H5^&Y=EUie z=c4OY7&NZ{xmVGMo~>1}wVe@U@}KuZEY&r4A0%AEz^_HU z%0#3;pdSyXs_I9nffvYHx4|C8(5Lqvk?Ly$E9{1vPG0pMMRumO*rwf1*JGpAHN5+& z3Ferig58Tii&9>y?cpbdnzOhTMF+?;OpzPn9(~ zpHj7VtfAl%L#vFf@9RIMzuEQpp_*i4P}qB2p>$Lnw-9g@hyg^Co)AvM^Sk9RUQK>t z=X&!7jDNMe1Yp=s$B2D6&t{ZO_o3{#{wITgG6=O>ShI&WWvORHZrzf580e?fFj9@^ ze;vrUzYe-BKB+_yFD!NuKe#=|(;E54~FzsGg8lh-Ao({`f{8uWE@h+cvIsXfiu@Q#fAe zIb+m+SH`0Cgo&kpU7SiGZzNf$0`fKUh9{{Ey4q$@cC$SsZ=1!1Z*qMqsbD_P@unCZ zo5H$|AT0_#DBIIg_hxPuOMJC-krxEDl7r6esq`g4hAH5~5Rhu#0TYc_-AFu6`5+Ao z7dfU5uNHse*of9sV0P;;(%A)T*jeKId)2qZEnurY7q5b+h07%t4z&kKj2deV^|qi= z7|Dk5fZFci=PI!SnG{-G3YN-A z<@gznlalLv!x}|QKm#(7*XP_)Sr`dReNAA;UqXEuu$2b`s>6cA)jCytgb{z8B6+=qN+= z@WOfZ8(IpA53M;WjUs2BPVv*R3z=mu^uwn#F^MR`-%qA`rx(O%X>;#}yEDozfMP<4 z$5i+GtPBrz13@kETkVk_we9QY|HXqI9qPTE{R&i0tooqOOF*46OYVlFnPZ=o9;<=5 zTcig56hs=r$21PB(p`}KN(2AFn0!tb|EA#sN6a0C#oQLG&ns=!IKZ!ty17Lj2KX~o zRX9rV!*QfbWN`lDNo3L^dBc%Ip>Mk!w#GYHS<76!QAd6F?YpQ&tvzTMWe@j#L+%=( zv5HST*>Ubaa)adc9I$fRAvE@mu4lo>P3+>r5$yrs$6Hf%wxLMe-9j>qJAd0`kYDzg zTvQ;NZ^{LMLecIAuH1(!(sWEg>qKU&dMIiB4jPJlhpsTP)}q|~)C>xd8s6?a>+LnS zto`StGy@fKVA;-MfgG(4qov@Ye$^1*hyC<8O_jv>>}?YO9GTp@ph3G4NmiP952bv< z&!zi317Ct_x>&u);;QCRcqq(E-Vsx;V#>?Bk; z<-nLHAK_x;+cROWa?Vzt^UGL~WeR_x)dpxy1k)_%mM5osjueaG6KWKSWHuSp*2oE8 zq6-dX`G|cpJI${j^KT*FALalkq6fm>jsI>mRr>9f&t7n&LXL{8>=WE$}|0YwH!h&hYT>{CuOnb#}95!P->D zi%rvm6IjV;{0+3GS3pu8!r6Hx4qK1n9^|!4%b^>TxHNFKt;xo5o3UJBuEpbq?(DLB zA6O90F!N@+cs%ndxCg2-Gp)bq{|EUxJ{^lG7kATj>)z+7!}!Vs;t4)!`G1oJN6RoS zvG;*?cXKPg*@KXs;B?_(R~?VX86Q#=UAq$r{3yLUV?Mjz0%dpFoZ=Gd>Z0CVF}H6S zi*}a)8%L}&0lOUM>WmjBZ6$rCK&S)6jZ8HH_xg8rzYrZj$jWO*56CG3IuLPAtML_H z7q#kT2YL3pqSy&VT@`h0WWKNn6Q`t~G%7sq1|my|x2wcL5iLRw+}n`g^DK2iqy|80 zD`J`p82hyuQe`P_C~nxb#=y#Awyt^mcZ#DqPp`g*((Q)I%WJ5LMb{v5xmSID5ia$v}5LX z$cWt);bRUoq*e1YM`k)+dq?y+!>b(V!tQZU;xclhaqs@Z*plYR&IKEj3YIUNL9aZo z@7qMy*SQ;m)nq6O48}+1xsFbFh6|_5rin3R8j-}?no)J+v{@K=v{GiSEYmB-ZLHL+ zkvghHoBY1ZU*SU}7e#(G+~Owc6xt1&hK93cV{)ord0Gxg2QCkoaxmXAUDQA0>85PdtLcrEuGDOpv45p{&_?*>=1 zPCv%?*egeByvt#igKVn*3|p_FF}z#M!asr>zqfxTL}OvP-u@b?9bBl7b+m3tL7y6O z9v{$}9=8IG&b9!JPSRv<@v~0O&u}#rVnKFO66}Z zx@J-lA09tvJYbmekbrd=%v*xsi$f*%fsi|C+8$iLTs51n3*S?}s4h8aj;QeJMSz7yIeWzWQ^fs-dfv^Tc>b6MMX;M1V)>&zeDO{bxA zVOVAg*I?Huf+`sJAHTGS5j)LJ&UPa0uhF3qd_}L!ff<%TRoNTK-bo0Y+|TuP3GsU@ zzBiz#r%?GpfnnF-YNJ4~r1G!M-fl~N+R{Rh-pmJ9U5w{lIguk|&GgfE74WzpUNazbd{;)jR)U`;@rcJ8s%lgKL3nL7?bp+`fzOW~M(4D<3Dr3vQYG=RA%7$V@0-e|LNmX>t!sbjfql-YX&P5mk5Cqd_&9clef=jVvcmXq14b)Y*KoBfxL&JG z4VgGLbmD1jN128U`-dfKH&WN_6>5K+)+^)5uUH$H1h;u8pEb561z(dKyC2a+4z@Ooc1C>G|csjC_+xMIcRD+ zNNG0t)CzaWU$E<}YOhj$k3z>rwNXwgo>bNr>-mLiXw&3|Krr$Q3d9KztEruWb(hwg zkDq9n{$cJXBkI%UG%q`w4efPLk0L^xT|en2l6*25 zSCnFxG22%(-={p`{?8Zt?T5+0NC4ArN*x;|qh4=mWVs7^Zt9m^ycjcj;2l!{RhgJS zYgSWY%5VQVa=+&@^c?^|iJ^sa@)rPX9ND!3V2s9KeZwVB3pmgWG4M2>lvTm9N7wPK zS*3AeANj$|R3QxBO2Wg=;bIq$0Is59A)X{D*=LuY$x?n``bd;m86i0o9Tq9mzeJjF z6&Eol6h&&^>ep%{NSf4doioGS(dt=Kq{WdQXyfcnQWtf!8flI~<((>(dD>R3UxR;E)q&AFKJD)9t&^T6Nax(S?w zLPW!&ux;_2+Ja`3<3HL79|kBg^gjSlhXRwPjGerG@@ zvoR1l$c}U#K*vGIGZ6)p<_xv-RMqYZJV1H4Fq)=a+o0T7;`NxTmZ8b=>qg#aWtcbtm4sTSA!)+#PGx5&0M(#2aS06ssO~KC}Gi(xw+v% zBe-U2CLmcNFMZkgzu~M7ojEw}!I7reGxOFYp-pn^wuz}U-!bM8M7G@9uvi;4Ir>!C zK1T0+mAVggFSF>Ofr_BiBNB-^u`7A+I{A?y7s}E=Dxg$=1(w1BkS6%~flKqKH4MZs zx$%TNSd1kn@#hD_LW1}_6`b#xac;8@suy^HlA_==qUMisdW+zfnYTp0scS_ zi5_j+hzNc?g$0cd8KB1vgo%6NeWSMIy5v(U(CvwY*lmJ;*EmXyA}omd#}wT9pNgo2 zj?7q9K1EdNm=(5i#bMRXS1l*L4l$@mVitEeHprVGw9Oe6(me=hCj0_^yE^>&zdH*8 zO@kE7gw9Kws5<{=f5TkSZqI%oJ(G@I<*xM#n@AkoWl$7Nr0s3;5aMP;xj9%AoSe01 zMXTf@l3s*O9l}!o14fe(fECR&c?S4r_^hrd^pp;1#@jaNGDL(YOFN6*MV|E13NH`* z2hqfaeo#Q!ad+}zNq#8HcZg&NZHU728t>=u9V~!hpBmp)z&jKLO5HI=?TP^su>c}f zo$XJ+*c)>DHg=mk$5+R!H>dqwh&C7+@fjDa6VE+tzotIEI?vaRd^=nV#Z0Ibr&;GW z-IwIvIbt0mmDU*RvRp>gd5FUu&zO`R!=x^$V{x-*$KCZklxcMVgC<6J?5DXcMCTC` zSPTsYbrF>{(WrB#uq61#*jcN-tXzj_9h3LqkluVF@!*Vz4z!m^pMOA;s||(_Ir&Va zRuavcg2}Bn3=?`@e?@)0O-yhdue~_++~CFoX;7%%^86dEhd2}CnP-N&zh=nS&FBwJ z))dM3O6)&zyU3T!xQ-I6kfsRwrHn`lRJCt>JT>UqPz9Rxr1kLF=qqAf85@pqlZqIG zIWR6jXeJVMsRP3#Bc|}r8m@)+0$lZ;eF&#W1cH|Lgsd7@8Q0QwEnqF6QbkM4EwwNl zag@ z%NB>dD0y7L%IRurFjet(ML15May% zV2pq8jE@wIr^g52a214i-7ivaqIn^Qs@#A%f`rqZWmTOt-vim&P77|g^3f9TY+wp1 z1fs13PKn@wSUYBsd{Xg5G>?%zd#J8x$71^JKqk^op3fmEx+YVc zt6WTLn%MCs`L^q07R`oBm(ng}2%|7DCLL*jlB#WA8a?|5lC1~*L1O?^`m=Gub23Bt zl<0#5aL-et{eHqj@Nk&fw3DA&c3oGQb`ZFn_s%Os@f?93@kEi1IVqvwL(@}>#MfeV ztqm-6R9u`_7%P-ywi!g4y*)Or35gDM4Wl2$zfVd0xL9j%)?;;~b?sk%{_SQW#(=a(=I zKpw{bX6DM})4bKQW|IF02)q5HQm@=Z6STg8qGkaossOIER%3mR`nJ}WpYmCm$RS0+ z_O7M)DzKY+BO3Wz^*U?98F0Wa)6yBR&J1;TJI&nG_{Yey=o;(>?-Ts5HH}ph6*5T0 zOT!}Ag&^heSX|_J(@FIztVt2XZ~-l$PeCj`?@Y&AbgDPzwDEr|Yh~7Oj!v8RO*m5cL@s|dD%>BUA`_Y#r z6aIXwj1OB!h3dRVUP0G&C`oWpNe7$@Ej?+|40B0^g^BG`v< zFW~9phiRGieG}bOxQW8;iXUxavMZ}o;S>vTe^Bs{u9#;h5nKZy%co>{)p((Bv9CFW zXLZvK7D}`X)9rZ9%#uiONfH)qvX2EU=p&^q8MOCoY#9Z1JZ*i?F+p~vFJG_(y2<^n zQVaZ8J*lS~fty{JjP&Pa3IYI|%YF`1Zh5q|jq{7wsnjCZ^GvC%*K~qLVTZ7(g4^3X61aGIX?kKzb%MQ|dx!m0jlLXs~wfxZQSx1~i3W2~{2GQdf>5O-_!H=a{(1(uU{HJh;1^IdEleVIW zfN-`p<5@4sAF(uSkoAp0vQPWMo&FLX00dL{bfVqqD^7}FsuHE(2En!tYLYnm`E4mj zJ1 zeTj1B_<)I+iV#vQXxr+X@LxFh#>qzumdra?B z!Tfvz3i?OnND8T=RW0*+#I8`ZA)Tf4DnS)NYW}~{@Bucb;-{0OH%Z!y4Iw^fN2`df zr~t-}VHoN#7dyBpeL4#wp~24hRVx-YABGVM`Y)}&9i`ms!w#g1Vy#0s6hgfUStM96 z%-&yngpipADyr_eN= zAj~NF_Fx)9MR`ZF=E7)Rj0Ct>IWc{fy#J~;Nh%p!>&b~y$8o(WSkItk5vwVj8y+6y z%}^^lYM*1&tjSk;7c%W&9vPrxna5IzTmP3WbHAj@DB2_)JX+L&BZoVzKA)9zjD|X2 zmo|ap8~#PQ)j5ERDrxBh0tsVs1*$eN!`C=RLqn|GJ2dD0|9z5hfOL6f?Au^CCqtL1UDl}!L ztV=AFJ6Meyv7q+l2bbuH5N3QEd@$SkQtY~c<(GD+Qr@m2wCr)iGM}BGW;JMI+g$GF zVM;w2d`w2HM5hWF!D=I7(}L!7pAm|Q`eE)NM5_(Qz#NJ;JUY$67|}A$)8s7h((%q> zeoj$7IW6l#yAVozu?^sg$J>FE5ol7fj-p8)HoO9N-?8#_z__$S39&U=-Vcb)w1rO} zwSJ=TJm|v4GyFtAlGt+ff83sSIKLr7|1jA`Z&2=0b|8K(h5v!^6f||s^na*2dRv=( zB(8>fq_e69KoxTD=~(Dk3$uh_4;k%pfrs3j^d-&y{7SkFFE6SShrNacXX?kBBu zmmnKoF8IM-oLM8zLo`m;N`w0E(j=E?7#>3WsCH#5XcDdC%2Adds zyi=RT5X|LL&c}FDVKd-_%a)@heJVp3$j^B5ND6Lmkz^8qj(42MwDe%csFcueq*x*L zWtHzMgZ=RNpCqeo+)m|2(}GErl>yVBSf)-qc*EBTadl#pR=%Z2b1QC{vqr zD!gIm*#IA1vO2y-RB*HoCB@tpMO^@W&@5eF-@pYqb*+mqV2({e_5OdL+Thbla@XX7 zoh>aW(RQA>W7wriFqZ`opap6YdtmfeiPm_4f+bK#Hn!tGfp(uxMph7?*a~%zHz6gV zJgClT4QrfH$9=-QQ6Cz}EpwxHoMPVG%_!GuCzZ_+`?=}jonA1&yD;WP<>eTMhP)1nF|Ii_?U_;rEM@JIn zIJXUxTj4y;q*-KaXed#Qp7#}Jwj<|H9t)_fG8TN4@q(mm{p|*2_R$3|3y%V>_^Xj_ zl|>Lh)XyqdQ)z*V&ZF?++UTs=)0K9A_%hP@ZP6lZDDtZOZ{PBiX>5q`!Q3rg>L1v3Wx&D^wFz^r+(|;|A*cuZFeAX`0k0!`{DpqS!J@KJG7Q!J3k+ z0Gq!bi(|E$%`?0^7sS7C2b8ph-&)wI{L0CpwaD4O-KzPmGymwjpAvx`B)IDlQasw+ z;*1ep+shq6w|LV-+<6d9kGre{Lg(%KIQ0Z$n|}?#}I{ASXV< zh!h}+l54TnpkL`1J7?KJv_LBB>etMtUUI2Nx*omA#NzqFG84$v-Q2G0m%ADHtYSOh zC_^4lkA_!R~~HCxmoFwt3D(TG-$9vQf{)u8}q6v*D$mNq$k&Y;=C& z-P#AAwPro7-z#Yjb#k4Q_5Xulc}MhBBB6f`(yTtq79Em%SOJ>VK>a3(M9P9_fLR{@ zCG$}rSPpUMz%SW2Il0leb@}bbc?!~!^=3)=5+z2iu?8>QNoI@HIdlj#agmT9)jW za^+s;ruf(DqUF)-04nBteZKq(LAKpJ#C?{>HuanN0PO*I0Y0iIaKnMmlChrVh0FqB zA=Atb;n!7J3J*9aK{j+~A>~TskS^O%;<3VA67Gw6kK2{=(~tk#khzwx&-LQ*-Ynry&CGMXdv7{%x<0hU+Jw|4^pWT{h&(}kj#`H8gZ zQVVea`3yeFSpSCdTWynAE@sfUAqH9Ok{`b)42DdRypcD$<}u6$FjNOZp3nNZN(@OA zTIaV}ZF7q`yd5{|-efZY77set0b;Ops0U`$Wx%VP4cRc#+nE?I?$_5v;jED;=62zl z7U;JKcVmaA&QxJpHCvR^b=ji1nMakL--C;Cm zW)CO)0|F4n>alap@F%zKIY7i^aFYqb`Za4LJ*Nv7B@#OeL=R!r`P-RPo z&k*x7+#HAor^$?wKinQ{%(Gwy1D zC?#qPSVY|E{xxn~JQ1NYOQv=q3*e`&fwlZBQI0Oyb}C~B2vr#^le)bh!}pcP zNo~0y!CQ$m-heZ_nCmJqH@a`*85z4~cnF_Bf-3HZ4~^6LvIhsV-5b&$G&IS+Zf@ik z>f(|_BBLext*^Ki`HY|U1bzCYiUn6q`^^Yr=7nxS=35~0y^ss1XB`Sqo)m#|7<4aj zZP;{~Xt!sB-$7v?yvHFD=Y6HeI<9Wj8bpObs3t~4ktMz)Op$Z=4r>Ftjo?xoHKY^4 zTVFNujKbioJ%fO7tw1KJKQd1Vr_&9q#a@4{*2o`UzGd(ZX8|cq6z0!|7geTw5)Su0 z-QQ4V{5h=!YKKoj$?o+^XBBq)JhqRpI2gsLsROb060F@tg#Lu4rBW}uTwBq1z^jp; zBEocX&iOq2Pkz1{BOECy(uC5u1avfp{sf>pLi`BZDi76kqV-+gmdGBViH54|Ga+x0 zL;7qgGV&A9f#`NU2VcV4E)`cWu1h@*YA(5z474tGhHIK6K*HqY2V1gXdit_)ZZjFk z2tP^pnBtgg<1n3Xk0cT~bzVnp3GpM{4&g5~ztSGB-!9~XJVOV22PpAj;W?Hmo z_(xKzsb4nmA%3=hIc0DX#%Umj`mI;+?{?BeuA*iL2R#L1T#fS6@mop_yfXMvzdW#l z=RV6?? zpU-0=9tyGEDJ`YB5pR>l8m_?b7Lw1PLktKIFsk5>o5<zCgVqN-5C_uO~Fg*%1NYa55q+k$$Owec$Dn zOWG*-OZjEza1J8p#hKgYB{ro6N>t)PpIyiHa)TI7jYSz^>nRwF6?U z7g^A?V~`$l)2* zzMDRd1g=T+eNU&+J@1#(g4p1?`Cb4;xFd^qA9PazT8>?QAWo(2WNx$<95IkU5+#jx zd4;?g^y|F18X8$<&#q^ULxDd99-zQH*&7}p4vNg}NP<2{(c706q|8KNe=Ly}lpVC2 z;0v~_y?q7YUhkl?$@_HdOS(CRSRRGGZpFb>9!jH(1P0^Fz(h4kg5+%W88W zZE~P**{(TcS_HAlWzVC&4tviQQ=L0e!U>G^pgA{@h%o%%1>QGN>#FJYLxH8 zmzZOuSyvkRZ{!;|pwS$zm}{KLu1r_iej?NNlGTDUk~=J2&o9?XDJ~_2$3qMux3=$N zFrX*~#fLl$&}r4WqZ{XZECkp%o*bxZ(R8Q7wuOYZwr8EIXN@4kf<V=jtB@$w$2V|oY#7~v7 z^`Tm$p+v5o+wvbU_6lG(qQN6C5aipUsdn?aX8Ix^MT;5{yRaQY5TkH+EMMegol4Lb z0+)eR3C}*=-atlpDfL2qhiA|qDzEfB-3xDBDCR>&VTMP zdX>3)3-#Q_n z>;O5UHbLgrxX^<)0mIy?PJAcz16)?1jkc>_dc^oQI;IzB)dv`wpI zjZ%E)!JT{^V+N_o{Fv8G$52*>g)B0bnKSs1?8x&<|{Yu-J6a=Q5IQK zi~;G8?wxF$-Y>coT%hEXe(x`mNP($NjN}(fst(pQt(}c5j_Avp?c_0ub>8#r!+$LN z{!QcFz)+{(_sJD(Fg_hR1$h^cmavZ^M3{f=N zRSfQ);i=dl%F^zfQox#c!3Tc!;}+gn5QNtH#<5$fjjf0xyZ2Zv_$FAmka*V+DM+-E=LclQn#HpCl#A z$AaG*%;>IFCQkGBZ}Yk7DNJI)Y1$rCXjG3)P@$BOvsMS5`QF#(2IjWfdABF2_3(jD zuMw7SYQI}Qzz_Qzg3C~93^0o_(Xoc6TutQpuEciG6lV#W0)ne-d}3S>=NyLZrXD+4G|scE9gDL+3M_nUDXa>KnUKXS;n<)0b?#HyNuh(2S|e`fmo_tVS>SrfPm& z2YcD&)e`C;VZ4(^O6IT})JviBTN4WK-f;7a(UKdHOLvObt+E((cvsxjW)7FD56Fl# z>`cleSuRx4oYHe3HwQ+{z^|)ENxcx3h&dGwodqESS|r~MBToZXF&E+0gewlp;G_a< zti$HUdRAa>UdM9=Blr7&O2=ktU)RM^euZl*Fj)<0=lqdY?!_xF`zub!=}r6UcUuYb zv%W*G`E5w6aFugDB))q~eGn5$5#9tHfLEssF0R2ZhY{m9 zoO5$A>5ZP>3M$3C>)9dEWGq}&U7j^4LaO7+^o`pyotxd#47EO;Ua}eanQX!D#}sS! zdpcIzAmMm+i`p-?mlsX>0@ODK znlhc^UITH0F?5rIl$uIdEJz-B(pI^pwXMeqw*A?w;C|~(OJCj@RJ`_dsWW(oJD}==Q z8$4Uu9h|uKd&7y0Q*U40g@MTii@PkZ>2tGMW*Xri0ySUa&4p!p5VA+m4a0O>)S4o} zIzE-M^ez<)0(_5{;kTpEek>GQP!)fPV-x&nRTSpLnA8k_$eN+?b|4mil>}^jLSS5NU z9(CyytI&Qi;kBKU2SGVwdP^mL7SHM6P3FD9r66S+eZ#q;U&p2LYu{Cm`R>7yeJkkp<-7xLF zpPHO_YzC+$o{<@cJi#5l80TMRI4ka#d<^4&NM}T+t(pQvn&${uEh^}fRFuXCbL-1y z4>2O_0Bfp;AT=!IhD2;m*`)TsZ$|8+s}3B}(?$l+%zt<*yRXL7DuSAvtZgAwsAR~R zQ#l6O@Ym9M^+6_1+q!$e`sn*V2j0bqd5z9DURGG^JNr*VFaUrDm6F)yEm`qDi5-&i zdlmRm?~0#fg>mnwtSGCBfhe4B%zI)f^NQG=GhsP>XldCkpcRU$y1otuS5SXINGGc?_wAt$)p<;Om z@}>M0NxwVst`6%=bWa?P59gLmZq3OwLe`k$F-KzwQjn>*%tBW9d*>bzxpuM)>$_ zdBQg|!#<1&O^!;{E5A9DIr}|yp!IzsrD_`5IlI146}A|}e;G~|6CK*oB1U!>zDb+8 zXQxnrRxfwG@h2pn)229(6tB?()^g;YHt3}s955K!IdDLpfL40du%X;c*aw9=>5j0% z;1Gi&R9a*)dhYgD#mFV{267l{)k9Rb z@XNO#2K7SNVFay%Z*DvE_9vWvMpBrR#o^N}cj9&3{=SEv(m@Ok>`E(u6;KHs5#ieB zbonhA*C^{;Ja)uoE_SIBM8zljDiiHq6nhNGM(tdKI@bQM8m~N5tY4XYJCrqq?-qWVkz?+d}G?zC$-H@&zVLSXJmV0XQpcx1wtP2q$+Tm z$R-;2Cxi<(`x)$?{i^O(O{ltdq&tvJSjNM@-7vVD{iVB;R)N5`q+jp@_b7S0N80Y0 zOIKM1zJPqXr}jXpuk@8z>43@dA{CvY*8hf8(U5Xovy|w^rB15gtxMq%bNqgVxYMqa zf84FvqKh|7(|QmRqMbksL7U*E6~f4*0`TydzoC@8!WLL$c7MpiIH3P;T`>g)}m<0%!GVhFtp zDjg!asma^7xhZd8B>2{k&Mcz4p#pXX+t`&oz*;;RQFg`7&@c21g6zmT&HaS7ff)9f ztm^rSjj$YBZGuyXfHbvR*7~Qi zs;6hV;23V*&NHw1l`PN9pnF(`hf(6ouAc!cGab2tJ1`%R)sqpbhboTA9U+|R+9!bH zxAQdJo8wuYIWU@}IwF?api2dfE&yJ$rgH@c4w}8gD>39>>v=K-K`t>#W`K^%H&B7vSPDp<*R*{Mm zR1>G)7uv+8U!9FeW&KG8c3M$}t{s}YQsp|$r%Gn-^i|F~UssG0*yA7NYjJhr17_6i zQn(4lWrClX2<%f0Xa^JVR#t*jImZ5WkKhjj&dv*F_rc6*s#Nw`m!Xrm^DhAAWvZEI zsQK8TEpb^+=v!@456bL&NKpb`D4hPc-9}ADOIp6qU4Q^KxL&$}C^Apn=c{ePiKHm0 zUc@V`uYeS4jDwB3+|<}LKz$F}mU%PC0FKriDZ}E9@A*f16~+qXw^4_0$G{Jsln?wZ z5`D-|vjD^u_^&YkEMNn0=07OE+^B#S6QDB+Cv`!>h<0HXRW}|&26eB;K!bfeefN&~ zUZ#(s2Ck*cS+>1_wKVZkoX>c2;tn(p6ITz!Cnk0Smin3${)R>9+r#h@wr`x%rYoYu zZ3tzK_!RcD(uFn!hyOg`tL_1|8kL==E%U;}=Y2KL@i!PvJKuuttMp?2*V2HL@3Xr# zL}SVH)LIA$y}dwEr2nAe)%haq$3tk}AcrVShJ@;_IDUupsCj|5pe@t?N7}xIX49J?s`e}ML51-=np92qe`Mi$dTcdtHG}uE9qd|jc|1yheq^1-9yZ0-00_~uk1*QU{6 z6@J0&9-$s!@DR3^H1eg3RlxfVTB*|}jM2U%@IvCp6_NbefW%8TtW zxL_iok!=z93jC|`ra2-P?i2)Ezq#6~Pcc2ENm1Afv~YiEq8dP;c=vg!=rsC&quD9p zz}{|UfR|heeWJu_QHPyv%NnM?dbs z=wApICu9;B55Wz=9?8VO@n%7wtm54A%BiqtrhL=E929)dx#jXP9=zv!IN}%`6j(I(#Gsk%JX!4G$ktS-L6a;GI(*27K1o>UAYBk65idFY>@9dB1 zh7LY5L0n^MO)IBP!>Qc|TL7Q4<&v%=RA-plBB3A=iYhCRuy9-Q&?(Pp+1!#p{CD zW)eeR>s{J~fk_MeUT-=jgkL3e>z#t3$&Qq1+-G^byj{`4FJjm#74QmVhM57R13ba_ zcFcuAZEl)f<2$?JAoSSiavZ^32{+O>N0TI_433|BJTP}GHyJD}T)+%GG8dJvWZl4u zgVQZgX0D{3lQ>wmd_^W0{?v7go8Atg5E;w_wKYK7rXGYinb?iVHYyxW@{ZYd`8OQM zwCZdHR5l~SuV|MQHaM5Z^iSZP#u;~~<1lWu{w2_jeh&mSY@x+ripTIi-QrnVoIsFY zPXiBXxfOfBSBA$-zU!v+68E%&2N(~1MCgRBSB)GZl&0=nE1dk6e3J$bo^DJWGv;Na zFy(ZHB!z38b+Dv1?Fvzk(tpCPV{p<#x8BMYh0cTk47@hx(jcU#Qdq&~2|U)jkG4!D zY%E1Ve#=19n%6%s%%jo&<3h>JO@(cJinHPJ$uaI4IiM7Dn(;MGYEGwAa-`#r&Q5Q) z$H2m^y)*m3{u8YY10jbB+Ca4v#25^Zj$Vm>x!n_>DRYRm7J+|U2Sls8Hvb_b4N772 zb>(-TYoc^rWvb>4tXzS4cZmB>$e%SV2MomvYdrUq%kxqY1?xVfR9ap;`d9{(4N&Gg zS(U?3+?#gsC@^Z{J~NxehdE!41Yh;0PjNT&_qX94>RGQ~t5owAg}i~rwnqX3!U6=c z@Fq7o4q9@H1b-8|*Cm8Y`aT*6^xK$fH}@F z!lD0`e+#rVq);nY6H1X-Kzq<+tX59EviqOIjIZfKDl*7nbV3Beg9@DZM!_sqA#K1Z zi7-!jWjfp=x8} zk+~X-qKP;QOW%ZIhZGxkqCG&QwfD<|=b@kauC6}&&tDAorWP}7BL=?7^eQlC;01+B zR&}O;;w(Np**2xs9(J!t%4=et9zSU!%g z-#Mu)7T1Eq$nX{8p+cOO9JPbN7P{u<->JcuSoyZpskZw;J#M#@ioVc6629k$X_N|J zcz0W-7@Dz|41G5p6ZY^ zmp!KVp*T=d1)=4p2eC;~^5znZ`PjPy-_8`{qrAf@#+9{nM^5|K(q zfps7jZBXR*^NZ(NQ%*76Rmk|rr0V*=M?djgs_65bQs%_U>YyaQB5cm2h9?d}R6}U= zNNx=E_aW9W2H%<(_oX4r6NK#sr!Wv+Qm`r6`zPKH?!|M7?qV^zD-JUQ8utODEM3Xp zFnY2cEid|Da(`E*mWzNq%T1=N%P^ZoU3jzQB%=GCd4NW$T{igJ1(l~GM2y~bb5mYm z5@@#EVk2!Aen3@)aUd$&mFadhwwsOt^J{$fQ>xEXFrZPVzqqfdYFKV$m;w86zz{FD znnFyp9rzlRs-aNCGgX@vWvcwicVft7fwWTma8$cmZc=L7*Cu5VeaCQnuMBFe2ZjA6 z6z{KnhA)rgG1jixU(2F&{sMJ+$Z9?x!Gf4?@hhTdhidXJV6z9CMljwMa~0U7a;9|F zK2Jg?N#4RR7S8gbMhk&-8rEum5I(dsIn73JocIxP_tuLeJ`KBFyHwV*@q-%(OVBQ1LQM4mt z+z81Ri`h|n42&8p0r>N$GP7B<#MzIxPet{~d1~}ZV>qaw60^MUqAT$9BbvZKPaUw2 zi^*-T4iU|;cj!HkN6iHCy($W1$2Z&uFau*<=|Of9h4cK*$p7784drDEOEfIC_|xSv zYX8YcXQz%VW>EpDy$r$3QD!pZJO@N*s`Prh3-qq?>`QQhr$a8Tp}ScHW{+SlOG)O1 zsP*6uqu6|)oRUs3p&UzakCd69ld{BpyR(D2QrT{|>aYPLr-xr$Knl%9%{oco?z@YQ z?SwlJd@BGJ8)D5r5*0ye@2M)o+_$hnsOAoDJ9N1t?SO z6AaoJWnOs>h9w515wXhn4H=&7lkBX+O|o71JNS^19a$qv{g$jX-E0Spia%0^g7)V$ zu@6-fe-eE8tqYYaQnK+A{Qy(SE5`paL|Eqo_{XU&bo^;|RsVNaPBrEwCgSb1n;6}+ zKh|JBw1svD=c$;A^6NG}zTjW_l)>~HfgDFAxa4bWth1MMx?2DKZx-C?UJa=qHCxcI zkOxpk9y!vjW^>ZYQB^YWU6QuQR&J|p?1+7+l``NN)?5LIZ-qd=R&#v+o8nR) zNT=JjB|7IFnZvh@fY%rNwA9ky5^LTwA;>{1YE9BO1#N~+viGyBW)gUHoUZ2{ns`&;~y^CR+1EO(xfWE!GYj=jPZJ* z;xDEs`EJ^@7-a$hZ>@2vKH0fWo6#^lhmc7oq+WLy9dg1~ll~o>OMfcYrq!uzfBeTl z!HLMxIMW{R&AdnK7<<#R$qG7AlWIdWnfoo_CY+;W9bK0S{-(B|4KBn5#k$%e%2uG% z`Gch<(-Ji!`sUD5w58Un>-3X!d=fj`=M9=xy&BEs>w3(_n>G)5uEnudi>7&WU2Aik zp11eOF4d6KNldc_sJf+}SOQK>*2QZc_qq_C{}o&BnPYbJFa8K93iQs0V)W5N(keQv z%b;vN;cA~r$zE6=&-)CI_#$$8S#`GE^xDA2KlpJ2+Rzg1SS>IRUY{1nIi8ftZz`%u znvfZ>-XdwURgm$H`X2i{fTBK>7a>P@FvJW?%bzpO5kAR1#BXFngQBIb*)x_XKDLnV zwA*L|-l0@S4Ibv+S#rBO0)Me{28OH|6Cv~|B?X#$t!-XW^(cU4o0i)&kTZJjtP9&{ zB=LW`?`l4Ls9f+_9Y+9g$#b#b4VyuXlVO=t7<%k+_UNh%4*`{nkTWB@ z0PRv6K#`rVWfHGK`*}s%(m}h1m;Wn&n~Ci>sa<7q=zyMC-Xm*HSS>mXG-(PEyMYS9 zGhYRiiD~4oBe#lF7709EmKQ(nhp7ugR(K~jR@cl(u!IsKREE5;hQnj|5ORe;>!V+F zP9iV}=f#5GLk;yjLp|$NF`#5r1z0g|Rc|`yKWFRMRVT0ZkHF#;5E03AOhPIx3jLB# zA@VOy%~G_D#!GK`*Y?4Sah`rsK{MA%;js?_JQPWrHc z&f5T7LRUPbcw_XJGFAcsHMLB@mRc|w+aowNv4+Kp;n@*p>A^P+|0;mnC&!A*gd0R1 zO=YKE(_T}FRJ^a5wW5Zd6OKXPrn{b4UeITcPi zGpVo`6o!9vMQ}w(Sgcu0Nn|2X^zq4`C_j8$;H>Jri_aiag};zW-iwNM)Gq#%cm?|? zb|yFo3jPJ^dtkrv7kq^)UOONAsc%^CR=O$m!miR#qMmknC_!;ey>#n_+1lzh+I^@F z);aEqyD0Iax2byaou@js)nF42Kz<=SM(KTitF+l+JMI8HeU{kCqM$5IRe%ENQV&TE=xevI=^zq7^9|!U<+0 zL6B)ACTh35m7NlLuh5RX3I6+pyKo?=?Dy(L2&zrm1(@%sgm0l?LxIOqvj*BAGwGMJ z5<-eFk(&TNEr||oX&I0@tv}wN9p6mmeu+n&O^S`fm7f0*RfJt*%#e*NGg#C8CAVq` zBN{cj`9dU@kZSNZ-njr7`&3JEyo1E92o>K_NJuB!9W3wd2XZ2HkmrV~mtcJSx=w!r zTTPTc;U!Qi3%`)NSwb*xFSwVCF=#ZI{2pAW^DQ>5`;WIXwdU=27;9{8y;b@=T~gPN z4R%`o7&b8{g`SAz4$0w8U*(oH`$IEnR;v{pYjH**>hBGs8Jx3L&JG2nxdatn4WJTL z6HS&-Lw-WUJts8|-ckVfU^FN$QoXk#@Fa{rcoS!zy=O&m(}yyT^ZFWI_frflgQE=Z zg^cb02ztfgW$hu`IM4Kw)>o)U{c7^K0vsc{>j?;EVw$3COD4+$COzKe3TYN{6v_7~ zctm$hYfZ$Gp2-6en^6qR?>7{sFB0|3(hf`(&J7utX@O7?wUv-^OZ*Gqrwf;?GZp+A>^s z=_tw-gwSHY0RJ<6wh_oKMVpE~pQi0lG%al4!HsTJ*{=QEs^KRXXY8~bS+}Q%)?&_I z%LFw#O8pPaXpIB=24|1;_z8#)1{LH9>?Z})`u6Uai0@|3j4{qbNRZ>#AzB-c$$7wY z5?$&==FBbZ-VKHFH~?~P%cFWI6z>reVJxaM01&ukYRtER;8P|aa$cXNiS?8^LHqc? zC~h@#xW0uw4fr{j8+z_Cc%?%}N>_5&Jj~`pP>lH@mzY(|Vm_U8e_G4V9jW_6vLRLa z4)Kq@T%{VWIvuY1Pn*CZAS(7dU_*cb1z0Ipt;mPO?sxP>B-y|JEgCoV5ayt89JRJy z^N6rPdkjDNh#D70=wPY1K5q<-C6b92xkjL>>ZB6ShsQTHw`Y;Gel@RbPQ=jr%tmQJ zv6jgL7jjK2&AdK{CQ&z&NyDeC59z2|#iZPvu63UI8M#1D)w$oBQ4Ue7O=*3lO?XKw-Pt=Zz&-K*tB zV!-Nau%xLr-H3|*gzV4-2z;LhgG1>4=NX@(47S)X)<4lAiy;JqTWxH)@cFnmWT8;x zvVHDnsZ~`QiFt_b9BD|B?un5$D8GX8-$xZ?*uhZr&VH2&U}Jda0AG>G7%u> zNY9SSq!IMQAXa#K_m7puIZ`L8W^nO@DDY|LO)5Wr(BG{3lt{-b@_cWt@_{>fmK(40 z2XY67d$T_4uGi0Z6$p=QHjrX?Etp#6L@JHYjuH4pt>|6Sx3XkK3u;SA4qgNbPc%Ib ziC`?(67Se%JeLJ_9C`%Z2U>UdQMlY>_VGK5Zzi9i>~_5#SeXb5NgfKf*|d7W1Hn2h znxk1|Y1;6Q?8gKC3fuQ*ZvzgPM9l3T8!0FwfK1?6b`uKK)HUK<`Z4#8*@M4ML)|s$(N>gUip91I1v7oM zGD@?l8s)jWvU@(Xnk?e^zcpK+SD=d*cXB<~YXerXg0?&(+eiNcq02Qff+c{l;M1yj zDu~R_$V2U8Q10rOftr7TL;|Y}7hBA$+o} z4Pm&h;qgz7djD$+w97tJz7Ir+6v@ahJk@EwaLt{hsiJ@=@B*|4vi z*s!pgQ+zJDzHTIwBdb0K;M(4k&uOr4|&2Y=|AAzCuQVU;K!lQpg)Xdf537zb|=FS;Z}_8#onAAKS=z#Y)!=r zod2o2Y3Y)Uy!kJ^)$N*2Zws{N_r{EqM??7S^)VwGlrzf|UqcfVP{O6qG2k3!xZyjJxs8iui9qELYS)(QUJ#vjTZtu5<=m@KV;)TCX#C z1C4jf<$Do8RwS;Q>9S%XW(W->0x$wEq|uU1XX+o%lSqZPF+(LJlV$Li=?tU5cj+6{ zq~mjlek{NovdJXeM`&xk+?UWF2D0+%m3~n6<5Syg1gOb_!b@u1mvR1vfaRZ??MOPjsqM#k6$$0 zoAw0>Fi<^liASa$s!RcsTppDPqp^W({Q9!g1+*|-0X<@K{S`{ukqV%l zu9Zu`-upft`>v1iuk;XYO$W~U`&P8y@$Cp7*tFNiW!6)o!55K@LVn9XaEc#3LC4!qDrd{)1Y=q2f za-1~j)*Ewg#c}L6-lC2{I36KXwHohv@WeEjYXd|x!Bzm*pxG08+I{6Xicf&eX}Sf` z&#*Gw0__fQ>4^MUD+i4wTsrcQsNe=ZL({daNyU~5q3V7e)pwE#{>x5^ud3PhSiMEa zBOnK8_j0DJILFZ88aNaazcapu{eP0)C(t6{rrpDeHHa=PjgUB;oxwt{;F*DAZ+(+fgxe!POSHNP-T&OV7mjCES)0*rKEaFka|`_(Md^LToB`-?UkxwtVL?XCNR|2I}SRW{gI*ZLVyx{6tTehHz<- zlewO4oKwlN#R%9Y9a7Z%7=ZPk0`-rMV`Vl!fvELnN|RI@nZ3}jij*>5s2K8mngADV%)ObZ3%@>GWN8`I)QWuzZe_IVX+} z*)0myp&TeWXR)3I&z6WiScQgNt&805ws%XxOyE3=chz*ES*rNqouwoC0UsPqK$Rxe zriS%4)nT~Oup|t_Hqe}Cmy+G}40!py<2ni8l(8mQbH9%Hp7GN|y3uKAF<`O-b+b!F z?GwcV8SRQEwn!AJs)oQ{R)ItlC-g@Yf>DvAY+3v>J)l(JIV;V*k28?b!8238bl#Ly z<_IzmR7H@@2Siio!#CMuhmiSc#D!XhW0VvysAb4o;cq2D`f@aNraCd-+n#Z^Vfpn% zbM`vjN2w5ainw+-R4N0oPDc+@5IC`1|4#ONrlPOu%l)w*G`n6cJL9}8ofc}w_enY6 zNx8Cs>!ycqz0ibPO6UDY`1w+EEm~iYUZC{lkE-Q2S6l?Afgq!`a_7(PYX*Q!&f;hm%pE3XACA7;_rOTMAIrFMB zp<0{&7VqOC;abMq*w~Dq#pSn2U8CUKak^0OupZSrJqvzNZGL!9FX2LPrBof~MkE8A zSDZ^d09q$Xk?*}<^?{FOXcbpzu&B+T`m8{Ex}HMGg<3wL z8CT9|MeHt|FsLPdxvw7N&+nBfKYA8I#4dqjg@f&{wv==yE9c&hEO0$v7XcaL{ENz< z`~jV@fc-`KJ>^=E=g(E<5Ju8h=dKJgDy_pO5wwGR!W^R$7c-I11-<@x?%-(&=3VjN zdED(bSEv{qm&g!gv0xhLR?+|vD3s{r5kII_q8jh&eQdv`s&%-L2nJbZOCkZ+;P{X zR_wM9On#QoT<|blgCb-ye?Zd@+#?g? z9Hc-hQkML?Tmc4Mp;x~%pSe@e_OylDHA|XOL^-Zjbv>`XEHC2cdWrnf0;b)Oe`k%T zM#!jrS?c{?5?vkjX=&uypU$)*3O}Jm6!Xj8`!m#(J1u_9Z+ymx(9*&DhSGATvjk?L zQ*;lyxW5z5=H4iFj>u^>b}*+3ePpG6y?DIdIs>R#k0nM?HK%O!sF~?P%LUEMfHb_< zF0EOHe^IFa*2$q1vr)sG1N;K###Bouaz_9)B&<>E-arLCJ1RMt3UQzgog}p-z>f|1 z$24JZ+sT|@H{G&vTiHW+)gk#Nyz$1BY);sv_*9TFRQJ3(goMo}>~RZU<4uF$Fwzx@ zI((=1R*vOt9s|dR7s1BHnbzImO`2wxwN0Tk;LBj$hQWc6Wd&u#R#aPB@(W=PE6m40 z3In6EB>MS@5dp@-GES0Cah@hZj8(nAvrJag5SG$3c(P$f z)Uk2wnN{<2OHQjLve!S-diiGPWeZbEItf*?)8#PCHX0L1=GU$epiOCUJe0HR6>e^V ztJsDanEVcBV|^jOr>iBuQ4mhODy}D9-^qe@%n`iBz$fo_>crayuls;~y`^l)5@O_U z$j<+o2*?#tWc@rMdnO33zgijImc~<}jfNz$C9^~LaHGy(QNPtfO}FeM)$6^BIizqh z6FPsrLx9NLr*iXX3y9V|th{~Fhx{z*1L+wCIpHd9;()`Wr$9qLsa)e~qz3|JJ7%Q} zt#XOeg1w(o2ABPOUD!U|(zGX7KtcED`ig(<{$+{Ic5n?OVxG+d;Ka-c2t3+oJtQog zx)SJv0k$vJfbW&CO0CcPq_>v%uQ@L7CiFC*$(rxG>+ad}DMZQx}rX{dGDB=hy(oq)}bN>eYYl#?zIE zWZ3J++`!V?C~b;7xQ=0$%tmn>r2l7j`rkC5pH<7#U>^hRfYJ*Nqz?LzP~#EXFKK5BJk+bUyD1*jUWlGGO{yU5P( zLqInsCB?}|K4!R&$c0Piou}1-30tpPF{D8h; zejwfv>f9&C>g*UuNhZp<|BkOC{BkF?5auDdfXe@x2(?GXOKUM{ifg|ZCX_6N&_OeY zyECf5eM!|_+ryfapcbW^DNG|F|2Xx*8Q~tcV3HRl>F}{ns4QV$-0=uu=IpVbEV

    N|Y$KNXbj5&?-n#CymnU$NziO-7YSLkNY$aC_1ddE9d<+MXZzGuCY;PmKQ zbNRvEOz=%0!5=(6oKuFNV*@_yD|#((a$757FE$~&B8ffCP1dk_YB`FlzUxG?c_$bU z%0491!z^VnCwg(rI>*d+Lqcwhdy@v+DYT1$=+J?{&7~!HlUwpD4&KUVnV)R>E{9o> z32!8=31meU*ihM+B+b7WW2QVIZ|^bJkR-%|$>E5`{lnn?T3GEh;@IJlUE|@b(1DJb z`-f7Flak)HD6R+2fKF#=O5-S$dhWkPZtD%5x9DGhNQ)(zo}EW>O0{anytSSfKDUtt znMPFOu}O9RVo%j`bfA4z5i4!f3}mGs@|!c-q1?crOn}GrPq@4Y=lRJ2 zM_Pd;@#B4M^*8aj5qioqlCgp?>iImPQQf*DY5WEc_|RZ#$KmaukO#8J-7@CWEog{7 z1Kfg6#DI`6RzbiPTRA#yb&CX;HiudCvOj+j$kkn(;qvU*x2%X*SnGu*H$PIFI-XR) zQ|`i0bV;;N`1O2~o$6!N(&ZuXwE2Xxp_d-qIN$r(o^V&weW-9jhh^e&H!`mVG`Q}4 zUtf3W#lbCzL0Q@}gq6yVL_Kt=^;%zIF8nyBL;1q{t_Gm#HUA&^QK0WIUUo2sn{CG6HJ5rI4l&C=G0*F9#>3!qNMGHZl#fbKD$X_Yy( zO8OQW19LxB?_rswruU?U3}fH|S05hSj+4(=@CELd(sxt8p9bG>xD zH!j%2h=52f6e0*q5B171hkkW&;jR?T$eYHK_a9h1Dsv-I8IG=HMOgwCb8`nEaVzb#U9h@_R) z6>niCBEQ*2$_Dm!v#|niGbISuEpR5x(8nGt4nZ0gYYc*Q_!DmKjNPP>#K7HRN+v#}zWr>Zy%uh0pDMx;Yjo3XW0YTg>oHBA=@7?h zrXcJI6X+QN42s?M(71&kF&2@a4Ej#BPX3?_n3+DTfDPhsMn;|89JT+kLT_vDEa1mZ z(fdK0E%iDq$x$2x9C55uFDw~B|KRq;4j&d!`=XOTyhVC;~p+v#z98zE**o9 zS$M$%TAGgPS_0_ULw!J+Pu15))<95jM5s1V^s%7Pxe_#Dct{-K?nifR>LH6ArFfjH3h{SMI&5S9+g9jC72It8{Q65@sz$c8? z@R&CY2nl3nmjiP&ocB%{TgTt4mRn56hTfs!_SpKmoY0*3jDrBD$s|1sHwME6@Mv0; zI4CT>)z3h?$c2dY@A`&Kj3Hh)whzXu7F}xY@2{NLMxvYi5B_P$O~v#-)JGWu3W=>P zl{|nu*iBd86q_t5>cT_aG*FZ*L*=jI4P5Z|2gotVDdGTXG*-->E1lsSIqnr?UTsO% z-!sGbH!v?sZ)`E9CbazZAIt-ZFgQHK#SN_D5#UQRO=g}vvUOo%h-QGz=A&=n$CO8z zN6I#bfKD**Xbfb^-Dgi->li3U|5SmK@ECTG;T|9E99(jioKVzkjg9e66DOYT>D|nW z6EYq>z`_(_SW;(+Wd9gkw6%>$pyF#)E%l1sm%jBG9izkdrueZ%t|xKw`m_GT4olsy zWpdI)ED`Y0&1BpyHP=V#@w`GehjN*2UJaw8z%yy2%wu=J{#cTdbWI1j_Dq~z0;BN7 z(TYK$o=4Kl9(nMD5U)ReUtel9n!t_?sJGwPr$XzSNIz2BFTiS`JO3R9y?KJtIO zEpQ9nN~hXOAay=+^TZh*GSHQ#!Wa|d+I|&A4vUHrujRG86|SebNiXrcD7JxlWPpxl zBf$vf-{^k|dvY{k(<<2<6dfm+`wN=+t!u|rKM&=eFKnq2R_LKm12!ZxWD zc`>S~YmyB}O2k^!P6Mw7tGQ&->O~j4nG#=s*fcF#ZTDsIv^2J{^8o4BN|fe3&Km4n z6$tpIk+JFL6mdAFc6a9{kGaYM{<@roq6FM+SNA3{An}QJYpvX=dj0 z@!gb2I7cxlZulRllY4NfKrP#yytLptQCQJ*)A~1m)}UAf*J7OV;#|ghw*-?esj>Ap zR!Ii7X*X#Vq#pn*NlrbALIn;MIa&u4N`Ni5isG5O(*ucFL+>w7qL}fszb|lAGlfIu z_jbB%vb=ZZkt)r0jUqR!!}T4U;mM@A6?_FG!ZmXU@D0iQ-Jv6$L-Jp8-9>>?0&LUn zS`0fgfoT=+slsSKakybe%cE_J$fpxy$dFeG3O4-6fc)IZzhzgg;PgY)V({y)luW&a zxSLoxaOBt98dvpG^gwD{jT$vqWARAj-Rgx_$)YQ(MiQ_ZUJPut;>S|cAj;U}d(S;@ z$=ZnlI&E_|q`;zV{VVUg{&PQPAI%*ndp+kzcl@4}`VN|_a0xd4EGhTV!mU@fzlbi) z1TW8}y}O5c-1}`zsfX4@$9Fcu*RLSrRP9c6Nc&zcM9A$&bXS4vK3{IYAmc)c3+=fI zq*o`p!Tk(>6iqF0!l^6QA7Xub)y%Y*HaH^RF>&?KhcB*L>(KuHV9jjP2+(QdV={{p zVY671yA@>CXlT$VCru=>7|pWvsSmY(*!Lm{K4@1kRJT3L#~t=ZxFo{JA1qt;F*t&_ z_LKZli%l!G73Zw^j6u(eW^}V`F=qCP21z?aGRISS77x}I ze*=NdrtclU$PUDT+CzANyrcH(rN3SA(l!3T$o_G0$@GI5 zJ+DKahKm}rlpVg;HA`$+-P(8i9okp)oyL%0k542ZhT@E18b4h6@sBBHTv?kfZ5*U& zB~s%1jv%_`i<6FXB)PA=_vr+FZ%OP=o8U>aftWk1Frt1GW7vh`>b z9l>O;4ISVe$v`(}vv4B6&T^_clfuSQSXAyXiKj*V&pFZ<=xXw5E zw_=Ij(u@z%5uC|mHi>~id>u*e8(iW)v1_h8NGVaw-CffP7Nz=8Mf&wS=jmfKyw=ls zB2V&1=Gx8kJ0u(FTySDpTexqSul}7aPDwY;mMTmM?s4)u;E0mGmE!Tx+$9d(+}y!{ zi5`^0(Ms+=Y5$VapVQtW8r6-X;e#Gwk&&ZXP>4*T2K)FYx{@NXQbaJ^#xF&Sx=)?bK{I1((PIK1qF_SPx{8(*bX7pdcHD>O{J{ID*!yct@BaeBG zw5x?oedCH{c7fLc*g}K6fGe@czm~z2yr&u+OSuk!xJ5Dnq>KZoWY=oCpI#pGBM&k2 zNbF(j37nX)A`3&t?n9&-2s9Ku~*K+3^xIYCpnp7Yp*iKE{Gf;*e$H|IRk<^ z#1-n-MfFNn*A*gATY#CQgWip8hiRe^G4~Tc%k)B_7Pu+{YGGP-h%X)Dc8}_)5T+C6 z223+MMz-)N6>Ef(v7#czUL|RG&9#bgNQ$qlCBSk7uCV36W`2U~)&4B{@z@$_#?da9m;?Rb z6cfmmk$j%R&r-FwKm^P#wtj;J&-__`hEmY+Ww*npMUrto0iNIyOxo>EK>PqgK%;8}W zjzcut$jg-LhFIfHQgT;D{*x3-zgAvTJ4K|!=Wr0)@)0%*mon+S<7*=V{))SiFo9UM zL6nD{$7IeLyI)IiXL{nvR@1b0l0Krnn4xF~()d<#7uo>J%FG?%lXst>X{^!Th@Qx_ z2KNs7&Sz0N>;|5d3RtE1k5N;x?K%}(k4#bC{{_)|-6TB!}+63@Ya2;kXD3-W z&naB|$vb#W<(9vU#B#UE$vZR8Bz?|n=^Mg;%;=F!hOOh?A#KI$-~mVLm8r2kodi@l zKRX9Cmy@`g)WT~ekM#V&ei!}~Rq6F!R=$HhU= zkas+pd${r;gJW&;D^036j%wz1?)+#n4?iN*Ze$96IP*hoG(y7xjWZX8IE)KEU~W!N z3+S&Smu#Hbpib41`L@WJ*AZeY-WKBqy=J{ zgmh!lsI>=534}IKx{ukwSe$k0r=!*9bVb)2(xj-5Le zc)T@n;8eU+%&c;aqo`CJ;k{&pgfax_puN%T+J&}h#`jC4TmlCLk-?GFVFon{I*MCc zeY&QB(uU+7RtkJL3k0i|`O_(nB`?@rp^gR!**dG`?eYs@VUg{~yWb{kYl^w) zzx2|~+P~7*!QT?^A5^uh_+DvFsYR=K??~nKDy8dX?>7)u7b7Jh`&TTdXrRkrIB%$? z<++YyJo^+V=g#qq{Tg#g(Fq)cxu*`!>F4zb$pPOvL~F(4PcvKcPV zN|n^bGZ$z~u<>jNLkZMq$*MJw5eXG>tINC(gT*I$%tV3$!0mHOuLEV=TN52G%0{`v z}w zGttfrq|7geR)800m0owyLO=g`KSj@3>U9QHNWiI0$Pj8Je|pi=KuG%%&lr1LNx)eR zEec~Nht~~yW5zBJ9n1DXg-D8v5GF~wjNgX`qP7Ve;)0pPCXY5I8xjQ>8gE!#ibe($ zSF`>N?*6@+j&jFU`Ziokq^=>&;gLq?P}?%HK-=i;skDOeX4}6^JZc7vt|U7LxMO3( zYPBe<9_TCiJUG7{(i4jd#63|1bfN14GlDmMJxk?l40Yr@GVW+ zcsx9F#SUxNJL2%f#M6(I5L8|*tC4zbujy(E*o}H5?&=^aV8aowM@@CWdb-9sr$5x* z;WmTvui&THrN(tiqi0FTcZO^j*gub%>-zl~o~{g0{*oJ~lWq+!IZOXdxWu|qI}pqj z`y+M=^ANnW*8Cfn3)KPlB^n^^TW8M*Bb*)qXWRtg_kfpa?&u*B&HOQGmO-N-yJEcN zQu&nq%Km>no(gcM?b+<)G^j>zk8GeA+Y_V@<>b-QnFIrEl+RJ01TzqVND_tg>z0z3 zawgZ|vfsJ~K&n3ZWT4slm4HGW-X-c<@{+JDXkh3J$)$O01k7d({hTT}aOxsT!|u&) zQ5BEyXDDLqK!=?H@@M+1-Wd#m<|c7=SV;=ldOb_oO8H0~r*1Q4qcCEnPc1cM3UgCK z?|Ibd-pvEVZ|n7gs=jHX9SfP{GyWZk&fb)%A@@qkS!fDC(!46?zzieIgfZX>-zt;= zqoP>`(Pf(8*qh*uD+0kW>rA3OO#pMbm_~Mc{KCa zgSEx`iq8dNep?$`)U2#Q9rcflP<eAOOu+omHbDSOOA5vFx+Q4o=_FPh&iH?M2st(=9) z%$fXJ{4y`Z2rgca3b|1g8OBwK$Sv|6P}RmTNf-9c=|j^XIvV z2i#$wqC(8C_}%LM?R?cDFvqkfol-)$$< zxEAX`zDHqgAVX+3P(JA27Ay3&a+x~P`pZa63~U4IEZmp3m-4-I{eF>}bOl5hWSCCe zp@xosm^C};h@sPuR}3CETj4HM=Y+sXcQWJx&&V0v6y(!^spbmwA7P3Mk``ZO6Cv>X zu>1rdDZ34P+V^h2^~lT&|JuCZE#fY@R zDf|JsT{j4#fXU=T7QP`8;R`=nwHW+O6a z0mjBJGTLfC-qavHqTM`F=GoOkyWzK&i0-4>1ygku(hF4(OFRr&U?5uBo!XD$?lJ~j zJe)F4M+Jle$RmT_;HE@eSl0v)+%X_~|Uo9nKs|O3QArklCw)(2S3URV4s7vx2tYo%U|zbB7^&}atjNtq*v$UBR*X}sdvaTM z0|Jb{R%%4QWN1JraNH(AP)%CY<<6)02(X(6(``W||D#HO0A%`@Wb zU!fD)eZheRac@GP$RX@wkti8XGf_N?Z)C! zQk*!X=Kx}l_aGYL980Fh{8!gP;G)pJAL_l2{hq>cjBu`pDkR30;iSk$7VpUdSeI{Q zypvi6Tsrw}b+s|?A8Kr(f_|(yNm?e0>TSP>^=f3bM-umUSy-6h;XA9Yh%*g_f6=LP zPs8l`A(YwkH*9sh%LCY5g0b0a$K+w9b3A6wj?RLvzn}f~h#OZN&7`6g7~M|3)i7%@ zRcp4#!QBHFmu_-;DhilYtbK`+p5tiO}2@&0FZ z7$&zs_dx-p@JFDlyaZ=ao+c&50nN$ydmM_SI%5UW4c$4P)n`VJD`r;HF!m)`v{Yqo zzPHZ1$}O7=>5BDNf!Y-#%Dw8i^zE_ArWnrCIz}ufmXY5w-VFyqxRHD)+QI_p{XpX| zI7Y~g;84sG$t8vRrn~xgvH5epvgB`j(YvI0=UI|>Rn5b8?Yb&GbG%?vKT7n7Qb=rK zc#jf?x~+6rsdhp|;)xgRT+`sf`njMN>Rr+Ec~Cp(UVvcl33*;1)ZN)bdXbO6qvF0143BCQMAUz- zfHD%ofhfTEi)frRZ=L&C{WHK$t^D+u$$Aebry0#u<>qHy`W9X4VcOZ%o;hIfc$Jh| zPf0`S)NzBHlvxvB!&?7AIyHc4n){W9guPcRaL(*n>wHjf@Z@EPnA{2~AMh{Ahg6Hf zLUx3Qp!q&GWlKi7PE$x-M2TyTNK#0G&pm9#K!iaKJlwE0C$}4)^?ENG`1lV!RvgK* z@M2RPwup@O`0K$;3zfK2^t0U4$|PI99vU9ty zuYk4cM8(iktDq!ljW{E)3kKLz?a*ZTw3>O&F4Ss{U#zap!kX6hB(Mbh5TbyoUQ9XYW`s|biJKag4 zG>P&YdQ$>xgOl2t}oJmK@jYz4gGSciS0|^-Aqb8EZ!ENe#rMA7* z^@$?gvqz4M)2|;-+2=L+<>q6S>IcvenpInS=Ia8tzSwCkT0&J;a~jAi&5_A0s=~Kh zH-<;#5U3qseN#RYc|7|)o~%S`yjf%M?@hr_+SpKy;KhudJkvJKm(M9F&C2J%$?=}i zZCE1&J{m43c4#|9+k;+e^W#F$>OjGTsQ`lXewBDf!aiye*cdUu5c_xaXt%yyY-3I= zg00x#OJj&*yD5e2oytV|H#&IUU`=>Mw#?LpA{>2iLNTv(+o+%VB*oSrH)X4;?gp7>U2F zJ33G}MpayJF9rJfAGVGD&X5y&McT`vNz!k#nw+b0*gATe@2HaljtO{gp@MDE+S&t)*7U(5p-ZF(0lG6TACu`u6ni+Ly z!Ui}wNw5l<#E;qwle?4>96-5QE=vI`kmXOe0<{~QH8=M6pQhuI-=mE_xWwcD7N;g>I;P&o7@K{wZ}E<0|M8{IK0oYNmy+rjF>fs7 z$F0DsP5g{RDeN4LEY?5tyNPrKZ{`Ptl!RCabb9U40$?sd;$MR$Ym?l9F?Yj2#5{IKrYm>*C zBVbX&4Z@HFH-vP@HMgP|&zO-#mnMiogY3}Bve+0sGWn*hvDW!=PDhC&R;`6RF-V&Z=`gw=fajR*iMLm<%iHs?M?6R(*WLaT_?__;B_%iMsw!Q7(r|k1kugAmX*ZeD$HErOGbpz+)wYRZfS=J z$#l;}_n{(0gR6UhHmwewoVDq`m)l5GR=6sb@OJnxUxtkRX&xozPx}y%(G{12P6E}N zOX1Pin8|9Y{gLV9(;>?jynS(5{Zi)4{GNlO&0;nTFIq^;{QRAJ>%|ty1s}IrriaBK zP+h=FcViRjtAu+|eBUr#@Cv!HVz+LGvZ^m-Xl_L=xvm>pOsEhlk9 zNC0f|`t0X5)_|W&Jzyx|9$rT)>qQ8q@@HxmDBeb#m;dO^zuT~Q)Gs1pKV|_E zu~WD7f=m;&tH>j9kAp{MIl*q-th$~UAISZ4l33se7B`z^0Ea(u?rM-rG)T2p*WB%V z+0`B;H(g!MJ9?PM<4V~NqURiR(&4NYCi>e*jX3D8TFR` z_Nun7^?WXbD|($rD}&ziWK>Q{ubB@t&v1hF5lm`1mP@lcCAfURzNs zGl6fQNkMPb8n*UcFkrs@Z96>-_?f&jt|-=dDH1gnd&%c~QVFKQq^Mw$UiBTH=a9aTe z45dDOp0JX0*~{+(=Mn<=Lfq1}c0ZY}U$5xX^A}Pzn+4pOySJPPQ$uJG0A`PrCvlPx z$w$dnBPUn?)mlJ!!E<;8_cyftV1f>>07oC^Wpfg+-$L?KfMkvZ%fjA;@~6$L2&euy z|DKwFOl*iVKXAk$&RMkCV-mg@<{fv~au0S;*KXGrzs)GI$9e;`ECh{OHYRG~4{vg? z0bY+AwM&-S7?y0yP*V)P^hxO*NS3`$2 z-_j$6hl5=6zWJeD7hEzVyiIizOu#W(%aV1V);tu1yuPoqLsyJ4G=<@Qx1RWVX&lQy zy;K!k4NEF_`aNh^l28%wYy%|dKq{4rmPCT^4U{YByzF!ixh>f0 zTDytZ%!SxQ-ferNC)5laf32LiD4>sI@kjJ#x{X$&VBE;+*voTwHNiqOe>=f-?gix` z)kmMTdSO6Zovae6B2JTUm{Z7JMt6w9Rs!0Y{AI(MzrGe0GgPuoc6qM$8NH+=y$x#p z+sN*uX1l5-iPJ$0a84opyZI^r>n}&m6g05q&?l8=p2Xk5@SJOHQg6Mi?I89B$ZDe_(#&Yjb80uZaj?W1;ZKK`o&|B1aOpBOnWVvk`^7o28d zuhm20YZ%#h{2oW?2==&)pFh=oiLvsz6?GTI{_6jHllWu`S7|zdl*8oSF2F=Ef8mYr zA?B$mHHSNb;-}A+N7S zBti6yOVC&-H*$kPAPi1Wi$_L7RURFU)9%5P2ni_Ilm+00cabhuM}@fuxK0;^sFJ6m z8b!xjY2nVF6j~@~NrGVlJyOGc*?V%dZq>5W;7z!|tVWJG!tm+8GCZOCut+CbKqzMJ zJD)&O$9R5x+xOytW3WlEGyxSbKylu>DZ}IPZVYsi?ILK`+J6iQl|V%ViED`I7%s%@ zT{(x(CRqO>$XI3=E~f{ui-k~22OWE**%HmpA`B5b7CCUZ&bGUU0!JqqU!;Iz4AU_v zL@IOR@v%=j>PRi+PMjngdh&rD5PgAQ-`I)JReWJ+V435&j=Db+)I%<6B??u|;viZ7 zYvR`@&Jq?qchV{fl^&QoaOU2rz22mnO4e<~=Ifx#6tRX6Dg10(-(~qrc1hV9`v&Tf z%(q9~wW>KhAz?V^lja~tOVV-ASZCshmn)t#BNyeAG;#qd6|Hb}Vd-HHX6*dEIC7$4 zN6vSQz{{ACP+h&tOc+t3!$;yKSk}0^<9of+(6tm9PI$$7>q4QsNJ%%})~qilAH-r0 z_3zhOs)iMnD`b@ji8@;a!jprLeO|S+e>2n-oElV*01c5TC)Ppcmqu)9L>Ak$I}W}P zaT+-{4zv{lF`aqMo`;}M=n)u$-E>cf`GFa;Iy%O#gzEPjXjx3s2W1KkMRoCDKJo7} z#cvYw5eH${$%}#-OpX@|uR()2k%}raCQi1_X+f1m zaXL2w$g2K{WT4%(z8JzSJS)Iro{+|RbyoTZwtM(%dN85Sh1SyThR+y`d2~f&a}92B@j^n3Ul@7yAkawPxX#1U_2&R+ z3Xlwe_zw)G;Lr>yFy+ht(!_A=X6&vP4D(JG)-NuO-*+skPph-kTKRxd&zBy_Mt2fW zhsn9YV(D7l;;_+qMm<)g#`I*$206-J71oaVmbz?G2!x$EfD!i$9Jd~y8+I@~loucz zM!@2Epw(kq_`}v^ez!@?nSW)cgUfcytjT3rVNjX=OVoU`rx&ThP}4!VA-Ew<3aQ^1 zT)cUH5db#yy?BWrMa_dY70CI03{?5er#J2F^TN-36kSYoTx;Pm%LVVxn^Ya$QKp)A zgBNPbzfdTD_(k@rfM<~Hkd=#HB8fYS;K$|+dQV_8t*g%3w=JGPM6gri1GpcC${;ET z%N4hdVPcEkp8-d0*tZMVN;Enb=K+4Ue?*ly9v5C#mzPy#&=#3S67n(Zi^V8aeXSN; zmQgV@N;}h*5)7wJ7LeK>AyM}GTb57r|ScCx0=D0hT=pl;7 zJIDkZ1X5mzWhFkn9}`H8zP`|M)50iUT+W6n_pqd?*Nz@LB{w%jQ7v+|68 z{A?rzIqJ}Tmyeu)p|GFDq&2L244x_SHS0LMRX!Gq@7{2sbUZ1>ipnv%rxHOQ;2=-) zhK1i9mCs4__9LK_h!rhPVeR=HFHS zRt^m1z{kC}{VCwAA)p2|8)D6CbgYwqDl=@2UOc{X7*3CW9fz*7Y|aJ&J*$?S;Bt3Dd;L zZ8F4?z6%~1OueVGx@Iluug?A>*F#2apltq|G%N3FJ2|!W{&3E_=R-CW{GcE<2+_+l zTo7Od*mb6J}IyNM{j?zfnDm4TmEkVX`sL!S-uu8 zK2s0g4}uUbTsEG_f1q%eARghE2N+3>cUAiV=FzsWb22{)bh=z)Dt<5;sWYGr;xP)PkBxJ0 zo1|PiPr)@O+MW&9(y5K^ZShiwrc`l|@F_PGW51f7KC&EL{E+YbhdvWBO+&*>w2j>O zLB!U^BhUWF9|NT%OI(|mc>zi7bx~?Xw-AvrQLLV8iw@hrxdjJ{a_<{vRUQTk`6>nmVg9~j2G&#;@-;X z_-Zz8(~sW;G1e_^3{i6~8*aK${Wn(UHkHL!tdSipfzn%En$&R4Vi^85EdVJ*l}%*a zCjx#@gAI2vN42i-g04I<=UGH?G8Asm02T*!T)X|Fqwk_G);(n4por8jZnB0&_u7bp zP?1?;dOe2XlqFmnY={a(EJG7TqB^$hv>Rmbr?(!Yj$Z>RL9mFR=!dDP;HvQGdr+0L zWg(R%PN5oT#+Dht6qw_X%*lgRobxQ;@z-t0nJ}n5wo=9qXl#P{|Ciccu`fFakpuc1 zNYYdiV~x-`sRt_SLMyiiz%~Ac5-IY@Ow)8uGRFH}3$(9rhDqYrZzu&1Kx7I}Y;`~> zu1dClWE*q^*=c=}7Fw#_Tj=Zl=MnA?{^kI7?wjq(MCo9zsBo7fiM}-^gQo_J0?&EI_PQF%Xqjc$lwc+~^n>jy>3Ar%S|A+4E5K_4IqZK6UM=Tv z5P)tJiIAb03FS#9dMweSZAL+MRn*Nr^$MIz|Bj@pdPt6K5)Dab3kOV;b35`kMs}z4 zwW<1;%n}qYKRfqZ;O)RZ|Lu`y%0Se`5@{{-J10_%OJg&qq&?FW-3?xA#|IJ)5EyqN zhW8v8O7aq$EM%a=NZzzslSt`*T2LXJ(+v+H<*m;?z_A-yGatiDs$X!Kq;o-DI=(QC9DS9OG(EpuXT_@Jj!Kxn zf=kPLcTXyBY1XaE0*0vTxW5OQR9*sE7;o)L?5F88A4M&JHB;=tk7-KXwi+HhP6JA& z2WL467H4k;Y1{Pv8vBsL7;8unPVg8yq0ZAMUh`pttCi@uMJk4cnlwBaN(V<)NVFP+4|*Yxh54J->h!V-mUOJ&}Z6w~5TpQk-2NYo$Z>iN&_4d>Z$A5`PgM-i7;hCRv5 z_VQ?)r}`{1!ToD3*q30tPSfWaxyYpQKhZ~qp>Sp%@{=z2$~(5}Lm@gQUD%VbQ{fk- z^HU4*Gx)4%&13&94>g|4n$M@H_>2lrUG!`aT42fJgjQbBI-q}*o~j{1S-35rMw=xU z<0zM4aDFs{f_;ps(;1-s7@IP|xXTI;M^l5=n)w!PRKZeP?nGqO1i{AVLBhYy2)+in zB1dXW2lrgz_=oACf};iZk|*4>h&JqvT%qclV|Y(a~V(DVU3p8}ttk>-DSm!*-;s#ksYIO_gLQyUJ5 zr=K`FQc8h>rlBCgI12}-_F4NKE=>4D5b(^S&}OW*C@`$^rU1$*NSYy3Kw{$H_Wk_KY5&l=cJ31c&KLf{orBt4aix6O(uz*Y zf|vUt^6+anMdPgSU4lO*3`G!x)yIh~xzUs_Tt3-T$$)|i>QiNBm-C&LMK zZtKChVDMrT@m9o#Y-7@61pME)PDqC3hBPk&)YdcHyVk&-1uSvswj?&i9b9LjHw7*9 zz1sAEq8vvg)F#e*z%yAKQGG#k%`f&~-JDsEN8qfSgse*fU%NBT9IA_ z=(5hBM3v}a-CqnI54pb7@GoP#8pA)UZFJoamab@*N%?T<18yO<)%&RqU~0>s-`38r zbaVK+f3Km-8WpT`OWsO21B;?>>BbBKt(0&b36MY6)A#&BQx7z14b&Qj(04UaBgAO- zso1>FV`~IOZoz9MK~nt+p&!?Y7czysrK*7Hal1-~{7N!4%k=yjY z{cKe#ykI;IFh~|R%~scBlL2tQrF1_6>Ef)vuv7D_y{e@uuDl(fMCrN&)&a9b<1&r< z(!qQjeP1sWT^p@3?^js9>dhpuA?*9UhUr0(Y}NUEqM$rJGNvjnp5ncHpBReR?=;kHQe%2HIn%|eOiG+UK;b7$G*MJb{T zmB$Sptg)#pcXU!-Siw z%N=m^qWBAi#pLysunr%`iuqBY<`iBpFem&*3Ptcli*{N=DP$v}5OI4w*NTtX&Zm^BCF%iZ>kD6x08EnXKC11U3`% zk8cdl4!CYe21L>`Yr;Mb3+?ey`?d_rbYJ;K{&(RBLI6U~2DwpGMA#mab_;FWEVDuE z1mq3D574$>C=M(OjLbhEYArlpOJ;+eG=}_3YcipE2>GfFQHy$Hdvb(op3=*F6{nZ6 zNQ<8~XX7ico>APj#n`cOMBNR~Ea3+p(w!-0bYj$+z5Y}& z*d!{$d*U!~mF~aUFE!f=36LVO@{|%i@_M1nD(-p$Y-AXPr4Pzh@|u>Rs2kJ#?Zxfz z8Gwd?no5yU&PmW*@vbT?lVJZCj<3?m^&4Zxl6NHvg>8o&`T+!zYsKxSoyCosn;B=% z)k#vRor+rl*B}9}6zPJADZ!OMc*SYYM9ubuuib@a8xOm-+G)_e4W}Hjo$e?Aw4YiK zu)^B@2p%)e54wRq?S? z$K^dA@SXyKLksijIR=#g@u+cr>(sKatIa(L9PJhwYeOfDau5?23zi7aVFe6?!?`&= z_!Lwbth8Gv>#Ngm>L{^UGC~TVoOm>R1!Ni9t(|a%XfH8`dU%0%FHWp}O;INqWsA+1 zFUs?%5r8`HIU;6D_~^Xb0aP28b2idtd)mz~>_!VAELyfpm>E%Apz_baXJ=Hweje46 zFdi;52C*;oxTyh_;KQP3rSKCEh}=e2F8Tt4@Ie*H4B$cS*yU`-Qp9%}z+`PiKzQ?s zMsS{-BpB@&Ip5C^j&(fZkS?RMu$kI#cyAYK(-IDj|AOQ_jufok?zrqUkZ#?8&6kL9 z3w~K6s-#hi#DdT!Fq#oS!a+rK?^qUi`I_G)IVisN>TdE*NLYo!b<6vqIKwBIAD!gfTsS#7TX2T$OYC)&v+zqr6d&;c_xYU zZ>>`VPZjE+VXG+he)5jTCKJ(^t|wuu@3tm5ceN(^YK&ss<@Yt8p?U23*52h&;T?gJ zE4emBaXfHH!?HqVj=Q^pi_}56%o~Ljhn@FkUqGMgpO9$;W<#V>q>>IR^8H>I1en~A zn6SbS-C_mfmpzA}LRYsF34qL0-a5Lluo`KyE%jIxLQDRM0w1VZfGxO+0^}$J=AE09 z3J;hkp2EK`i#bp=KI>N674z_M^5$b%A6H{fhsTf1bhYyb;1Ws56G;cnrb$i>idb}C zE>N=J)a5BnsWo9}Z33@d30OP;R@ zHv^7Q*R55Rd2ejUQIs#U8C*zaoFkm!tI6oSTnwr$r1PCQ7x>HVK3HO!k>{ljE|g%>&rj=F zcyqMf&+h!H&hMJHiz3$y8D}}r^2dHvl@R;|kt(nANe8gk`>w9;Y_Kmr%rv9k#oyA; z8hD@HQWGGgqfQt=$^gXJncx~|5?jotXL__(*`6rPfB;uyHmvWxUG4KbDyySho1>X= zoY3{8=!GL{j|S4`^cQ&otIR3y8Hbkbt3zmOFpo7{{}TWJeSmwjS!djE&TZJX7tnJA zjJw<2=Mjjv`rBHAIiW=l{KidyvnG>Ib6nize#)r@)?i_)RX$s3NDj}7=+C(7TQu@w z#R2y)RnF#oE(|ClZ@!aHs>tIWwg#ycpFQ2^n2vx&iJ9pcDWobV{=)4ww2JLB7RlT3 z5}J(O@RXS!=|a1B_R?R}CTD4eX_OM?;^azF`Km(H{cbO>?B^{U$V&T1wjCBLFf|_1 zLl4sd7T+iR=sQ@;LOj^8ZG-8fTighyn;2JoxZ(5s)-u4oLI!(E*P<&^N9-a_>He}1 zI`#9uo%2#H>S~hRpq{#9jk>W;&4LpSuK|yJK)2zEFc3HU73LL%)*#$Kzbbw`d7O@4 zINyY54|9;|d;1<1cBu3l_i{k@#b7CW@~{b1z7i|`Bb~WIC61hj)8njfT~KMUl#&()9_)Vzi?vA9*rfW9({ce2uP(s z%W&hZ737Yb9x)y*S&FRQiFj0Uzr|4ZO7ZG!O9==3TVIYXgpk;Fh7HS@og<#5W-kp_FsuHiGF2|)(fkOy;N8GbyO%l4ms#j)+YK}I9cVUJDY|fq{C}_)u*D21q zfNY1ap+X-5RSq6a-8eM|>8l)$b%i%pqUiG|VcGerVVnw$S+3w-M0p)0c(yTM({F(J z3yg3!F)~VWb={&##`MOX)_aS_aDLR)O*r%{sAXa%D?1@vbwy?b*tf+YlkFOfMLWN5 z-=W(b%i_0E)ed*87y%qfQdPv_H|bVj?_~%4d5Uo(!uDs&+Hn~i=d%Gv>}Zql&Rrx} zFA+3*mz+k@O}ZyZGEa5_BKzP1Nv+!w>h^+@kk^W@1t(ontT#J}#|3!_-fZ64KX0j| zw%jBH{_G;XthyErQTUr3@WHpZ?-9VQWyM$d1;iOKx=RB^0-%d>_)F*mLU~(gg_2>3 z>Syn#jslkd3{ID}+&`%mb`+TPPj!)o%+f?r`YkBb5p0aqWPb1J!s{E-fDd4@1W<-Y zcAVE9axkLJd`%#flU*Vu^*Fi$0|^F@eybtl+VfeHO&;VPwr-+z<%?mEYP z!qLSC^&Jezu+eJd>L09)Vv6kH7aYKEd zoGWyI5k-`IB`3TCEwz-Dq5hy5(Y6MI`?p~R!nCxpsG2?R)wACL*wqtnm=%+R*ykku zLo&Ux(8{o?Kh~p=ylL04Rfh^MQ0Q26fav^R%3!o-BlfrWV$5v0`C>TX*fgB(B!ZXy zE1(3l=*3q~Wg5{Qpl!r2ipGBjc*QVzfi3r#ip$&SE6|USD(3yC{uV{edP>oS_}TFd z+yc=c9tmWv`cQ0=C@uC{+TC2lbX^PpgMEV%s95lzV_uTyT-CFWp4mm1(JwtdD^lEO z2I0RErB;Q;4Bl&TxUzVy@_8XT@OQ71P`r?=n=Vx;50nD{<-tgorG!pvnQ?0L)aHp7 zTv01kd1jWlO6mUYz;xNzwfJqSL(K)S9h!7OzQ2LlhQC8m0rlMHqJOJTF)c-L-^IC! zDy-}|>SCOhl7W~Ynm$`=P_sHd*bjJUdxnA6dY^O<(-|O>1rlikEaM97ktfQT?cNqPq9b9qu*O6HU7M!W3$VfdyJJ=wdda$HhSa-$=Cswnu2 zCD^^jS$N%xA+eR3k*&X(`W^1e?V=OHg+BNj?eivSRQEg*BI%7EqCfb0gjG&U37ECw zb>K0GWQ9}hEu(|z`^-+5Bk;2=PLGwaSOPiKfuS%kp3_?|MJ>j09SBOB-ip=D^nkVU zga_29(IzKQkuqkWj>;^jZz1fAlyq|Ea;R+~JpdCGg*8$@OFKhA3eYCyiWYhI*iixqYw2}1NfQ13J)*uxl683~tUs;gr;};eM39@? zEeEu|N}7owJ}$6z8!}V&MJ-x|X5o}WS83pNjzB49I%Wp*LP9x+Q<%{NhUx?F>v#At{Nq^y zVO^dQ=C+bDGG15j1)p4*2bLKFtAqbD7JVrsj^7|Qevc-o5IU&RxYQ_22pT%pg;cEw zGE7k(@PK07<=u)k!9j5??+yH#1LQ;~t$)H7HH)8Db+iqD^CmB5h7NG8B(E^6Xkbd@yfix&m zNSp>y`HWLv{+rt9Lmv`R!2C5#I{a+#1Pr3gK}Lf!2Lx}{C0X;k!6xaB4U$KpoK^lj zaN7P{7SXMr7F#Z{3R^{9*DUY}r8RFPNp(p5CPn*V(|Dx3^k`%R4x=_du<+=bp8W)V zwtAuYzHpTia}lW(a$^f1mX`sHSQ_f}p)|8$!6!g1h>f;hMaOWmG~nZXlVg@dX=2Z! z3|PC0w3$`StWf6Y zYJOJ#P=Bs2AO5yjVhxeK1GuE{8xW%?j(TgDA=yW|yDSVvnZw3YGq|AKrRD8Cs1+{Y z%>fFyz_x1On&O+%hNPaijvMEU-}5x#$N zpmMf|J}7D&V7q1>g0O*=8GPx}Jy;V9$in$pYhXZK-oChQTc~s5ux`=^=!y*_@GxTkY8X-L}KJ|H$`n@ThyQnrIa8CMIiL0-{ zquU4Ze+;dW?hfgYl#K~7Kg`UdnkKgJ<@B&eRkr_?RjU1jP?J;%%_v$$>CVv6 zStt(dZEn8=e6SlJn+LYk|41StvA4IF{8lp-J$#nUPrUttgK2sdUC(_$AS8`bc(oUF z%qdHzizw_c%CnzX6S_BZW;G+%C-$@@?_q^bRtkU5!G*rwDvQ?U14&1{Ww}Amg(1R$ z1-x=DJBLj!KptF)M8=Z^t?Q3bT5%rX2SfIL~lbNb9Ej-b`}v@a~mIR;0NBPzb4@x(!a$| zx(?wvWuZHb)vB|nrL@ii&|2y1MR6I>f|jQqyRUfLwyRG8QU|AV|1S|IRq4-%fku=k zIhITLQ0Ns!7QF&EZu=TWQIvaACnx(##}hsC9D2r4p}*^n4}=9tDC$`qt%X^;1kNva z3%gf7Da2Oir`{Z_?(ggwz7h=4x(nd+5F<^SY(1B}*&w%D1;BBMKbU~DgC@w-iSz)n z8NvN@+(a#5KNAG5wf>oB8?)5GTj0u-Mq8EO+reowSYk9+IDx=SQgk7ARTWCyDj?}_ zGYOmcMQ4F53!G*7vlcbTOLtiT8|6+MZpW2J*Px(Bidl;@X%BsG9MA0 zy#5BNjSx!TbG}#QR5$;#NXM72ymezt$ygTnL~YpQ;%*xjGMIr|Xix=y#!J&*FCIP^ zThHU&0J_Qk34gjKCtp^+5@{I;U{^o9E1H3n!&fiYFO_iK=~I<-aD8_LBsh_laZ)x) zDUgoDgI16Z&0Xy(Yc`8uDvNBWJWtO^Mz;nSzC0KTi8mC}2M}S}etnmsm!F;u)wUl4 zKWFkZaJNq7Q%|@I{J~28%MpH`;f=(%k`hkLq;u%46h}Xlnwe;>Op|(=UfQqrJ{LCI)DN;$5JOAH0+Y z=d8>N@fOn?D9^LSiuZZwD!*pnsljoG4AtnPQz(=diQ1FdX#UH>O*9P?t|&MNG5V%p zkv8XC!e{v;$u%tM)&*KHxSp%`RQo7aGek<>BP$pz9hEMIvYyyg zUtM9)_o%!#RhQBYaH~X2C_F~IkcGT-)6|qbm@%wvNrXNaa3ed26IG+~7dA>~W{(Bc zl6^MagX_!dAnNDHnDz?XHD+G>8lRQUZ?W9e6&^n+gA`veVoq}`W1WdqH zc)^<`VLac#Zx@39M7aMMVM}HEFe=Ev+n}MGSKMki)UccTSNo?V)JpBPGma-uUuF|zXLCOBP?~ba8-+81bhouuyb8e9~~V0aJ~@KGEUY` zci=zZH5x62AYPI!+Kt9ij0@Fbz(joi!dcVYQy!N>?fx*g zjwbFp?)Zg_N&$fk8Ykdi(8nY250l-8;Ba-cjBL2)?y@X! zq*-mCT@`uMqo=@6g2-jEGxx-I)nU&~IvjS0Rwu0^ft6yTLx699q0M1TVNoanm-uh>WMN~5+>7c5^ zC_m0iejpm0SgE+e4_Ip>7WCl6;maUumW$K!gQqKovmkvt^@U zm#oU!^~Gy`^UH`&e!as#t1&?T#RpPFXc-%eAO9VNnmq{V*P+Y3Tba=b8%10q77Xe2 z8zgPsU!%lBje#1S(NB?U)7Ev@@S{lRKUwG7`vh(fWI*AMiCe!aV+MOX6!Xx;rHfg6V1T-74nzs?)+1K8D8=)OtL?)Q~pSL z-f*G%>EitbFilUMS#TvdA|m1#VJlMfGeC0HI2s*Yu7&VeQuZq@tY-qT8X|fw&Ggb2 z!sSj-dfQ($<8$09*W9C!HcJI$l_X-Tb_u&UMMUI;_T%@EU>i)nPQ3B+PA0#$f~TY~ zKg2?F`ZeFJ#6O)NIRN1wo~C`-d+;hK8%_J1JD2Avd?W=O*)KPyjdn5(zl4axK*wLz zmUn|2Eao;8NtkXt0li!a=Q@#oY_IL^p`mi!)hG*Jb*W=+&?5iP3_)$M#6H=Cd9De)|D2)BMu64uvv6YusRPgV5^KB`#s`gudeTM6#uLt?aU5ryW2w35n?B&asfGg+gL%v!16Q{8hDjcYQ#~3>Yx44XaVI=Lf?~TZv|OY3fT~#P zOf}ZzQ$@F1nzc7CKXI&^VMbcIt_4u6I6J%Vb38?+E{Im$7M%+sSo@qY7TivMsutoQ z4{!Yq_j@VrY5kQg(n{}u{IhVcV?1F0EL?Qx5Zn3PeuT9N=cH3wbjrr<0Un%q=U2>~ zJJvX7+N|TatmX6;l|v{ZrIp_ptOIJVEOVdu7B1hKg98zwmffC`@&l_mhz)kK`$@E+ zn}!w=q9|XXJrhx?2WPZ+S+6;paxcpeIc@hlUQZdWo(zx9x0Zi(8$H>Q_*Tg|xQ_~F(mQGC~$Qp=V;f7%Q zLZDzH6XE5J%NCjGQwMyiDmTE_BeKGY`n1qCrc)34}BGXr#52+RHZGNJSFwm&_T_6+TllbDZ77| zZ6%|q*ssL4lJD}c)Kj6n0JLVsStQs;;TLCq6tDw3$d>rjfAxzHiorloj>pE*-;8)j zDtvO3;3UWFo`A4ONmIY@L=?s|j}gc|w`aj*h>)vP_kcW-3Gaoj>W^!i>KTo35}riPyKwo|C>zZkLGt{6?+$~aj=ifQjn>JVtUKn z5l1aq#Iduj*o>rTJX#37YB&lKO5af9-XsR1^?lTH;|&doIM?IAN~(5P%V++Qn|7bz zZh3e@htP;gio-e$hCK)(g6SwMCZO+(i`UmMV0cH_9O|T|0qvbsJ6rye>gy|LR4t<&t}+GN=RofR^>u2V6*D z^7HwPT1kLPNMX~V0^o=m&4g`H%U!ayL-6qIQ131O#O>AceN&WqO9mR}@U%d=iRip4pBFwyGDhPTMS&7LEFZI&L6|Zr)q_Tg_^4s4elde#O z45yzAoccsZF~3YS=@?E9E->Hr>?oQ?;Js^l_qDl(&^=zDAb%bU3CX-JEb;GuRMFw4 zv6gU^-UkWKxuv0;b`F2phmUWWPwJx!nS;Fa#_2?1#S?-$t0^OrOA@eNE2qLJc z{spjHRrn{e$|sd!fpcgqh$|GR==gBDbvKo5#8mdb^WxGtYuuSQQVWakL45CaITyA*M>uPYDq{eNj8~gn z;2B5JOTo3pyeGKeC}HP_yUbh$)3i4QU+EqI-!-Sx1@q);;))$cpM2~GRbJ#p4U@p* zLwt!}S38hnpb=f%^*8WRR3Fhj4V4G!@?_%vV6eAn5?4pEgJ%T52=t}PQ7_q;8ks^P z#`dsN1;EN2F9d9lZKr0_t0ay29^fEibLpBu)mI36s$K3fC|CDeDBB)I%3EqVD2x<6 zWmoFGc{4?Wi|SxRrCTR=h39uL%VZF->|ejh5(Aen#(YJQVIvD|H{vAJYQPfPg7>;M z=SWDz?H&mAVOv(-QV0;hPvz{8(VKmNj+#jl`UVb?3e2eM_o9MGRS={h@^CN*ctW-} zs#UZ6A3P0HyMiDALxy^vWMrGIs#gjZ7=4pP#Wm#zdhKu3pt+a`fU-$spW$%dRi{z< zAO-X)u4n-W3PEW0MV;q`r7#WqVq?a8Yc2I&r{I@06} z=f6D3Vg(qcx3gA^`v@Ffk>+st6iLWjbRC~YTglB2=~RD3Cfz86vo7JWO@>!4;8i{?pZ2&EsF z`|&Q%RiISl6Shag)%9EQzhAysft=W*7xjrl#^pORIBq|bDQR{fJ8V5dyw;UT6=)G1 z4x!dd3zKqUj0e)+x>0UPh`i|aq)UqcK{7N79gEi9q!AmJ>FYa%hgkatL0OJE2v2Fk z({RNZ)%IWx9{!UN+bcn<6VAg9giX_kl20HD$5s^jDA7OKPXd1;?aZ!y4>nIN%3dwS zGTLS2S6nV#!Ga)~hzA!Tcvh4(Y^~Al5;yZXwY}$Jz;!*nGK7%5IW~$I`9v$v>?~;A z@w!@895d1i1luFPKici1@rOW=IF)dfxTJ^t4D~Tq_ORFrdS(&m>dlZg4yy_)Z@l(%WfEL^kvE+$X8hSg6UiV?fWO+=Sb;n?z7xiH^ z-5!n$%7E>ug|D&ps)U4<8=6Je3)=C z=Du9t-tztr>O7`S1CX>;ETGdLCUS_GjhZ68MIof;i5g9Vvr?;oXk7;0LDROFjiz?x ztRxPvIk*-y%md#>$_x$Z7YsKbFK66!yTG1Mp-WxQlh(MpIke=ZV=YJRF%t;wsXt9_ zQy|qPhqPaZTtdAi`e!>{<&f<^qok_OCQzpuwGAD#jrl zQ~VqU93QyDGH|glb3Jvu8)Z2w%G)TcPoc3-@O$)I4}wEEk~E7+axfJHas-8-u;|M% zV2Rm`6~g&o?^*rG$+h8RsBqKLe1hB-`1st_0*1JBxA*$B8;Ln+q>^BhR?8iY09B$j z1(wAFVOv?@#|Q%3O_k1JgMflZQ2I-gHun3Ti%nHQ=`;(OOa630itYODzLIjI;mrPHh3GT% zNJ;C?E75|kPP~8x?3=U{Q_l2QQ!Ex3eLnKId~dk_DHW$7chgS zR0r%BwrM^Pg{pk4glo2PEOdV7#h+;l6MYswFCE07nCTk)x>dvSo;B@ApJ3fAq5Y#b zfavFQ{?x{Rr_~}?5INM;?1=myQb)*m^Qi;{eR`imE+2b1rpWDSHk1wt!dpk~C2c(I zf(<1WT;ktSaUw7vfPCgs&pg~1`JJMHxzUd!dbZ+`&*)|0<^>~1I)6#n6xN>RfK*_V zm6d5YMD+gj+Pvm7x9&k{)fy4U38L0P-DrYEm+xSz?EL99PBKcwi7Q9@mhE$v#$+SH z%KNnNQJ9cqW*r({1A%a5e>8YivVpU(n8wIAWzus?pcsXiNqD9tCdVQ5`6Sj18*pMT zMzU<1)~ol zDIyq`wjw7cL1HED%B@)7y9(7Z{Grg$XHC;?tD>GBU zYFOE#>tnmqi@5s!fo?bca@yh1n?ni?&{mDR!MzsvJnPq`a$=T zD_0Q8DGS_2+}tuAt8`PLZ3_w+5VKMa1F1CfR8CwAEAIndobq?~0vO{EskwlisolB-62F}tJo-sFu9v>e zUln(8j$Z9ql3UFJc?{aUI{lyWQ{e}c>ov54IKeURotl}3dMP0ypPk9aFIys^jV|OP zwOfRclm(1p;gz@`L0Z1zib20`oeW5Zo&T`K>XU3i?PBDmlVe?0i_`3lj7EUZ!C_42 zuK5xR-<4GI`A<+$`5hE@Js8P?Se`nZhg195M6qNSV)$f9cK*7{!n=Xt3lF|}BON%p z39ef1=O%gFn6MyiP9IkaC7w;WG-XOYxQDcp($0MTWddQSnAh$EjoVPZgRd`BQ-zWt z=CxKL4aBj<7GF7MQc>jhVcT>~nNX z;%sPMccR`4CV+UU67s#icKoQ?Z?25kO)Pufd1(;xyNcL{MM!r&FSz^+d%#Cg1bse0S)YnkJJTES(fsZU%`Ou?b;9vC0BWm0h zhpSidol~9}2C_5z_uWGd0n)V>zd8APQZona zTjt_-n~O8hQm-C_hniYfFO^yZJim36K)c@DKMYdSfn?va6@@(w@_L_#z&$62#p_zt znA_2AIM7s(mofaeHl6!XyuFFobE9u0wc5a!D%4cgM(A3~L(dgp8CY%mq>DDL@kh`_ zEeC^NH4b^xeR=6uK@0;=he-L#3oJRxG|lCXX1r@;mWNsjUf;S-h&ClC*X@Y^))fOs z*hFB7)gw>vp7`l$PJrvmW19YJy8qtp1@!%Y1O`)!?*3_Wf13Pc`o>jhLO)Qzyy$7x zx=tN!F*tyQk(SlN*s`rRmjHcw$}0DNT%Qs^o5k>=>13HJ49da$rc?Dp?+n6~ z74J~d2oyo3OIA^< zU1uhaa{~=4u{q;$SWL{pUEg8xA)h!%a5&X)$5p|&5+NS|W$$d6o*w2>&evFch_(H= zjr}yW*1cyO`?(AK@VEbeIZp1#?*OdXTckxp!rZyfJ5-*#8(xiNWBMMb)qHmobK1o- zPbm}EYAA}*XU**fns{0$pLZ_eT)Z`3RIPifyxnbK8Uw?_J^6H~8NIMvzbLDSHPK9Y z;~$8Y{IR4|1P!p4W+6{<8sK@b0j9cP;du^3`cXG%cPU0D%53ZfL*r%<{A9)5dw==xWhyM%)gsqTA0gkzQ^N^eX1KOg zHsiXjnE8sLYV7U7Nv70Ca+(}V)#LP(a&zQ4Nh$L^w-$rrzjeP5HY zu&0c!*`nFCm&8g!k$Qk90Vns~_1h@2SF8;6YM=RBgNV};dmda}tjN=Bg>e?`bi+6I z5J*|p6pQ&)WlzQ0HQ^Z9Spma$YK)=?HfiAiPp;{*GDq}s$n>^)%Pc4k`w%QeJmnK$ zbsZ+~4hgEPzAIKrxLEa!{vzfJx{|d_h#5@oc*@`!oadl2PiB&|9k#Mc%r;FsxyBjh znV9kUSNX^Q9!nXYgbEIgJq0};2I{pFaqMDGX8w+x8fe)y(KW zL0Qr9z|fh7B;~TId!M#`#ug}3Csdr^*-jO@T{t0obeENWXO9q?qFz~@5l2Q=7ZCL2 z**e?xr_hhocjQG}9QeG%oaZUG;XWdJXgKeS{RC(`!*ON_F6!4xQL6O8G&K~R7NfBsLu#_L%*m#-!zI(5Z#{WtHsu{&4{X6(<;ZQ0Ut z!!0)shft<_IC5;2Z4DOStH!gWpK^lFPU%6SaS@)QCP&opM2?T%x9D-f0U#jqgw%} z6zWhT>$dMVIx%l#LJht zZW8}P%iimn9~QKv1UFn#2GfA!$^(`Xn8AT4{Jq^4#!q`n1WN;M6ipiwNUC6A2I4-A z=#jCtM&B)!CcC-%Q?*}AuBh)%fE-S6WX8*MNe@EFev?5$mU{mCz@3@gK!R#e=_y>P zxtK18+ks7%5;#L(SJ2uPCMn9b6TnUFxHM;@VqLdin@s;2kG3w|Ts>kJ6=~tjgJeO_2|(#Ecya_DmdUGa^YL zaME<7y)J+Y6({#WW7Y^}@ouxC3@rr}i_vQ7r}LGOr&m!bV; z+&d4~v?OXITTb3$Y1|88Gl_%y0>@g9`Lw_24k!B!U^z~Th4~fZH!|EQ;9N`7^9Jqk zTT479tvd-J%nu||PvPY6GU#iRXnpy~7eX||V^kg>0D+C^fbn{bX`+&mEymZ#?;b)& z>)IeJ_KA4Lp3h828VVy`KnP`pa1Ya!I}*98z|%`x{xHQ;EH4?1U;O(T@?KN~$&H`h zVkj*64>DUcULgm`Z$aq{Kcf>^{af5p1s69*c$JD=4^7{07A6B$`mrC%HoeO;wiGJu zo|4)1o$dk}*M$1$Fu1rWZ}@UT1jI1QT$#^Q9Us2yKfoXc)Mj1yCcQm;^hF6`xO9wus<;Cl1gp`gpL`>_4&2z= zK1ZQq^W5v3RT>qOHKNhEPh z3Hl?2jBXQ#_1Aw|ffWXp#|Xet$8P zN4akzoMI}7YiA|d{%a6ps;^-?<*WLg%jZ1mb#M@%Q%Pmn>*^Ee&=rSDW=#2EWJecS zm8cNjAlx3b3O<2s=jh){!8~*TJgEnopmTFVn1bQJ1p7X6po6kiU}wZs#SRLB*?@X5 z+%TWKK6Z%+!T0e|w?kG-YU)jW=#R)lQBJX*vKZL8oSj(bse*SnyfIBhi$A3<@rP0d z|11)S*=p&+;tqz`jcU5j)%cvJD3HSRfxDFE-*BgY#DDm}w4w^IRCl z?{Ky0I=0JXd{dk7bKHzll3OUOR}q50sp0G8LA0&YOfBPFFIGTEBr#RMrk_B^s@etQ zZpW#@@&J?<?4E%}Wm|76M`Dl`-+J>qQ4f$MK{$;bE2{4RFjy{&;8X06S|@$@il( z;>TZ2hIsDSr;p>snV!kKur{!iN;NDrzGq{b=6{ZXv{*>zqs4rdnm3)V_(~>EFyyz9 zG2Ce|nXjA1-momDrSsZwE008ZN)Xknw(bY41VlX&XYhe2j$T%}LcUq1>{UAe1>mTC z04I6TgJ73C={&JhYT3nRxpF+;%2%6*z9Ze}U}+^sKZi|D4b2O{?BO_3I4Y1Jn z0vfoVCS$6E;n!GF_hi&cbBlEcbeM*@l+TTzYXW(3&?R}$KHzDJs@R=sQdEG3pL6es z`VCuIkSj8HQ2~eu+ZtzhTVAia3qm(_0cmhO1iUx3$e#Rbt&3Nwih!Eh;hztE89WK7 zhXxLa2QpxNJ>@;&lfFr z!ox!uMWU8+hM3Z-qtG(01)r)hwL|?LChelC^sdQGI_`-=S7(!OayvgC_1-)c@rH2s zY_j*&I_o3m3W&AH4zx<3F#R=5Bv<4Jt9k?5v`va{#m?b(1k>S&w&J{fJ=w2i{lt18v@)i22en%ZzR8SLHHn-A`bS*#aX?8$QIBk5M3v4icS~6vK#GK`A*%c3N zis{J98LfSFem)lSa=dn96p+Y&s>(qG2H~@0+Bvm3mrEAMZ1IqJ-pl7d^CnFYsewfv z(Ntling@5~)NH%g)jCh`V%I_sRrSCQDv{FTy{;LGtzf2cC$xOjgIcQl8#^)|h|?bN z^v(g5k4F&?G`gDaSGKLd6r^44JO&y&Y`LE@A-VQe8+2j2gs5-=yNZweNd(IE=)%>Eay? zs7ZZGz8;cPSqSA|R7QI%dd;bElCASK*uOQ*cl3mif0aZ_bV^wS;p~!8vFJ>dNXL$v=sNseJ4)UIiu+i3U9GyDY(P|&h zw980znFPHKoL|=u^a>!x%#h(tg7`pOn+vKvP!C}?!&Fzm{q$qJ)U5Oz+k|zDhkIws zE9I4ydGzKG>jMXU$M>7fOAprYR`ksR$R)(1oczmpXEq#tX?k_i_butRZ1*|;`o~G* zwBI7@xwf!uq*C?jMhi-VSPbRX98ZQwl*xd%TW3V4=-iG{!E=*`$bf`&FX=5s{nesP zS(OsdO7Yt>c-@-j!qgx*nOQtpJky1Cu-OS$vEfuK_aF_>E;@~8g!TR&z^oj8Dd%bT z+CO_oiEC5RTao0i4u zY~oOzjKG)+!|r2c9IY*4mNX5IDxuQZq)v{PbQ{2K(5+Vx*Ts2`3bRmTtVzVBN+1;* z4hK7ct@c>dht~38)da?|Ae37S>*@b#fjOsEm|fl7oJkYAlhR84IYXWaRp1h>jPWIs zt;gBG^I8i-h)BafdxQ|%1yeoDr+tg|!(s5f3;g!q)HsM}ycSOwFlYkI)r$f^-)X}( zHhYu2j=Mm9vXcQvviF;v;LHvr54)*m{8|%`a9t$w5w=&j!>aM|xNYCCW}#b_T9@@%DTl;E)7oEq2AnhFK|60LCx}z>>A($3iaei_F{5D*J-%zOcw<7s0Z!0 zakoB4Z=vs~j|_hTF0n&$L9^*f+(%E|NW2PdI1fec>;e-9{znIZ*({9=yC>$zRp_An zYjGV%PZ9)mM$|d}R}hY6)|<;(0q;I0Ke)M8?g;yh-@21c{j8j{N)2jjxiV z3aA}syer{Z?mRPXZ$fuP2w}_2y}ij{cJhma+I}HodavaNEl-&X&N)=rfej+&mO|Pz zS^z;nzQ15$v)G8ihrp*2h-j(*!M!g#m)0YGKM|Sdjq1<%JVy%UbnYqJDuHN8^i3ih z7T4NlQGZaAaauR{_bD1;noCxS8vsV(h2qRj$zvC!@Uc)4*C+M=#<9V`X}x`>Da8~g z7p_k(W7Q@9J}c9yvt^aEWMijyBNMf*LL^O-E=I=mjR-(d)JaLI!0=A{%7%fcT6QGg zeVLXWK2?o_-wXH$V$R$qW3ciy01Tz+o)vK`;WU39^20n~HuD47S`;1HmL&yqB(F=N0JIGiOa_(YVlZYhPb=0~hR$w7t0F$lb+Do<#CXY?9<7RQ-57$b z>Dn!q8-(6Dy>q?QwaSAG(K1QzEMujQ6NgY7y)8aJm>o|&72^7<-kL11qUc%VwVTtw zW``_d*lV~C{pRR?_Fdd&s(1kS58Tm`_|vDRP}Xu76gr=(CFUzX$n$g$7q>v)R0e_f z$mDPBu7L@gA8P^HmYwavYD*4+d)InSbjR8RCJsqdOT(MmxHdGLMQK6)E&auhekd5%&-Qf2(U0$F zagl3>{v!CTtD<}dp;|8HjIFtm@HO!UrPvg+Bp+9xEw{+l6bMZYecVqKkrbB(yryXt zhG@APf<{-2GdDNcSD4qbamKyE;+y%7Ly@JgkJBMJ`)p@I{pRC}8pyaj~qKy%@s{`gR%wKbdVbHO=SEhfAT{?wN$g-)89-_jMi~}U*uk`(Nkyy zC$zIcx{e6i_ux!oG_BJDvh{V{0-;u9B2OpUYW(nIk9TQSL zk5L{)|B31jRs?}kJK9IzAV*W=+=-O`1Q?zZe=~>a=+n9lYnuqq(O>!)I?5%D&(lWD)Cf5;oToLwhnG4t~i!mwW!$XSV4B7`*q+x1QD`JNb_a`cT4L zX8i>-vs@H(?aLu4wL9b`%?*TDG09am{kf7bkNsOdzb5Wm6?#Tee^JNXba?`&ny z<{%OK;$-w|O}8`nb^)gRBWUacZv~;PnQrIn)|Hmx2i=NP?}tQD@(f!+&OI4QxL=~7*y)I!wUS?;=mSk8Qylkw*RP3TYh-wJGd z*~*F0&^^U*R%%Z5OjV=X61?8=bJ6t+r^cMI8%B z&SPvqO#f4NrlKbkOMji4t;QDHTvT&YX|Vs;|0;+V-1vG?k+Zgw;dg2j8gp*LsAx7h z>xeO6Y*FlUSq^+=2h;deXq(#_LrOFMPnLc1{Ue5vt3n zbmG9+_vD8&5kG1&`H`|tH#e;2CLk4Uhwtbb%&%C1=k_7;Uqd&r5OLpC!Mh#fxnX15 zyc3V{3%8~_z5SKDOB4A^J4f>3X=_Zo}fE51P4XCo4jnPjsmfYLkO_hS~_MKTa4-_$`-=D5qWHSHlT8d z3QWjLWQ1CE#rJy6L?1WMw##xMt3EII{duqSFN!XyZS5k(0`->k`)nEZZ4^li;#P2A zLH|9HaT6;LM6566M%l?=G7-=!t8uVV(7j>G#}jrWQxs4v-i*g#02?+I&T{vpN6EQr z4qxwjiVD))_R`4s^8yrH^~>$$|JA!-qN*c-VhX6h`HwR84bUczWx&ZNw=S(X2^{!$i<5_ z8%V?i44qDDY&J9rT#MORmPmc1Vw+%rCR6kn@U#=pfOy)A8&BAHt&8kvc42mAufe}e z?MpOO3YG`F%Phi2PotJUd6QHzJ>lH&b=U`Tw z91xH^q>uzA5Y>xcTx^hXmY~}$N4;5t2p;$<=Go`D0xOqqUJm}`d^7O2<`qM6@yX&s zK-L?@aJ1IY#Xe?}N`60|js%saHO%U7tu}TQyu!^f+$80H8p}A?pidOKSe|$dq8Onx zT|&#I$nR@0*6B@l42A4&ddvOQhLFn;_nHg68PU-bSZp1|HHOu1U6`aQ4s>A*xIa|8}vxj4RGL$8z*4su6;_dv{=GJh3o^a zhDAII%pdFxD+`w^(1V>&n?qI;L~h%?>#d{BU2ku4y)MqTFC=i08qs}!(R)Hf8`S*o zHT#+rIwMVBnK2*x6A^mt10b`yzeBO} zv>#+@LiWvmdSg<85B;HPTPHVAXl;eql?gu&`}^s>R#r^@ZZ_`F!%z@yx8)?!<`JuO zoAM z=cn=b?f(;|lqKox=q=t)2>n$m4VVH<&`RYf2TJo3d7Fw4-qDY+{vsdz1}j1dbU#)t zv|uX`AjQ5Y%`R&R&J`@RUq~i%rMLst>;bCqGm(LgWZ)oAax+Yaa{rx-V$vfY8 z`Lz$<^;yS~+W-|82*XG=3hzJch3mSt7I*GOBya!oQ&BY2tnos(r3F2}xyoN!6OEK1 zQ7rZo`^`a_g3ffw)HkP(U|!NRv{^k*K7wud9;jBpb{{U5UL=w440jwFCKs_=J4Oen ztOp=8Zq!r;9Sw3;@W1hDh!Sg9aZ&{aM?PG5ZT_uyLJi+deW%%x%i-O7h!@5u_I~y4 zungCcYp!eZd1n`zUw!LL@g5^DEM>N$2*^}K)E@YLoC3~ao^0PQo0xeO6v~d}GP?c; zV)OuJ{4v|j+Ar9$1t%$zHwFdiFd_(--iX1gMLsX6@}o{dmnJz3h!@4DU27`I(-fpi zQ2^u7=Bzld(dt%$N#C|*aqRU93+Hu}1`p6;1<=%+W10>aM9)G>5izu_nW_g9F4t6m zHv|J4TN0|NwmiGGYRt@! zZb;@A?k;Nu?87R7$36tNaFAh}g*iuo%3be{-<$@!Hd?=+kUdQTCE~g&J9=;fjC=4G zsVLvO4imwj=8I*|xkDHVJZGCwV^5q(pwK4oo61COrj5Ye^8v9J&nWgxwIJ^AHiC(f z&0(n1j#IsSo6iw+)B(v!-E0D!U)^R3XIDH*-<7YpUfs_z=@5`T#`r5$I6 z2bx-;jn@F4SAMqz%F=xOE+w|JTlsnK-jVX889_Cdco?4l} z0F2m196O6g&&pLFHolWEK7aKNZ7wDQRn)e)^Ow6rD*+ObD*om_SgoyRo=O?41{p-vUj>jhRkK{Ta)!Yl5jnWeo{B4-DjzN zHb{XGl019syN~~yo@&aFu;X+lYOr|;*H@5njstGmWu}Xvert3n&AT0b^VK~PbFuhI z2}J8lqk96^6~T1(d)->0vD+jb6IBmq!Qx^Z*u^A! zM#&8*S>FonH{lTCjnOovCn* zdtZjAdWoO~BI=<-Fq{r{ex}hhl;?}DubxD6=%w8GpJMBBigT~t%JN$2Y$Iz;jg_2y z?cn!cbzCOV5M*My!IR6C_IXY3L}-J_QmlV>gjJD1rdG=a^* z9x*(C<>h*)ekp{_L6k#~qj5Kv)TOXNEZk%n1kL*Fs|a&SU3}5hCs$8+-RlmKzWf)| zLE`Ar1K803)Y}+zUunvMlHtP61Qzp{v`H|rZ0I%Xuh{air63U)L?}*K zD_~VF2)f7qCMEi%`Xxv1|8^n6)A{YW!re2${`&rw5*y+svT_i$8yHHe5Dt%K~{?A3d zMbpSz^+Tw?9VgYNtEUkA8AMLE*@O=2ogze5!yjSU7S2TD>0DflG`1;7Vc)@{l>(>} zi(@|lIJa`AA~^1W+p8x1CLB`1`UiCg1`ThJ_{C6uc>;9@;%s>Q@wGpz8hytz5<97+ zrD#_ndZWekc;!+g_)`3(9mJ^kLpEU`v;XQDAX*@qsP*R0aAZF$noWK%(k>LgNsH{P zByV@*41)&_nh0(~B;r^|(BWeslUfq0lCX&G%ZBdtQZrzAMc^3U;uyggQ_^I z21*MNu23K8t+{1PolO=(!CbbLX}M*;f{4~lgl-gY*Q&b7z2+SnK^mWfuK;zd zW4W@=LMd$Cg}BIu35c-be-g4F=k}ZVkr&sf80+;@ikrEU>;GuCF(9_GycLa4wH+XP zQUZf`eWwegX;D**lMY51(m|j%Uw|CgOJUEh@NE3{u==oB{zFkk5PZCH(x6*CRLo^z z6GrTn@0pY|d1-o+6r?Y(dAc$Wcccw>isLnKM+v!oopllewnj7p@f0U^WB3fD4<=Xm znEqx%0!)A#0s^Y?J zqo5yH(=iIZ%m6 zE%swGrq)lb6_gH?g>e+OHKGKk z6~Rcvns~{l)vOR|hQXX@_-AhPfq6mq_Pj4@2z;~WWio{c6cF>T<`{*Gu!*=vgZ6>! zO~rncck2O5#jE`cQP}?R@#z_*Q6^sWL(s37ONR2UHby0Uv&x087Db`b_IH`sC)`70% z-R7ONq3wut5#%UW13rINEaAO1#1W2X1> zD*aiPYZGxON$}GZ^9L9l=Mq=T{k`@Q)avd;^q5jBykSKK(9#BWe566R@Wkj*q-AJsB=)^?aXs_v=7l(!FER0nL$*yE@3lFuMS;E*M|)&yhNR8G#BOgim&#_ z+vdyOp^p8M7aMxgb0ufe5wzqer1-e5%3+ofck~IKt`RM> z^2BBJ&@GNveoZrS>%W;F(gtKnaPW+z3vAJy)Scuf$y1@C>kWmewfVc3nTs}-ef<^< zCxzU&ELynhIqW6hs`oITtD23jG!|ucA)5ch?(0^oRsIw!S1OvGU(}_nFc6$RXO^}@ zAUj-U05XU7s6r0uPt3qWS9m7jaldDA0l;JhrA|YjJy-iPe?un3{*?inc+Q7O(H2a@ z#ad$gs z7CeB4GevImHtC>zk8kBgh4c>9@zc0!5=mvk>c0g(Yc=7t+>GW*lMry3Pp8v-xcC;q6z! ziZ3$lzEw+$nX>eH?st`OWcA2^J{#5X6@Ik!iCPRb!yaV0?IYUh=dY!a@N02L1j$5v z^j!`4*HpKo*$GDPVc~I6pfI!0tu5pe4xrgxlnEd$lBVjR*$wd=JukMagCc4lr~3Prw{*njWEI;p#h^zpu1alqh*X~x z_@N8*)LROfA53Q1aQD*~5dSk_(Qec<)QyCsPj&&r;4;DWD2#2sRe}15L?}?^Iq?mU z4yZ`X;2Yj4XaCy4^q#;EU%6^nSj>hmOG@LIKy0WCqXicGdRZo*VghB7z|D|mV9P|(- z*lS7+dOLTf6F|~wAgON)7@$9aGm2%P~5J z9OkYSs>di9#DlOF5^rR5Cr}yrG7+7${HOaj(iRn+PL6HM&w%*0H?@EaKfc#|r61V{ zXDqvlUW~oCe>Z5LWA;wM=OjphVo}|n{yg;in~s~!h8K~Rp%Zh=#G6JQnHE{n(Y$}e zS->B)M%M|8mG>jPdiPYN5l;qwLFV_>^k)0NI&#}&N$=}Nvc@PQfW$#! zk-pCF_Bk0f3!f*|VcddI_97sr4A2jEFOrFyFm5#nPOhV}+nX1TL zz1|I@+H!}!-*64f z7%|VL` zeWDk#|6y`U3G>HJxT~O82WQ78@V8_320)S|R59(FD+T@jrT77q%B7=sG4pBLp{a^0 z4ps{B%DfT8=X0K@75Vx3T=PuW%leWgR1t)Z|r{Xf~$W}mOUt$$@FU*tOS0az0M=ubV2 zRAEgEmt%S4hjX+O)Z*gtMSP1{n`mMn9_tv+L(1@xl##V9eeb zE!ca4TeOUBhXkpi*zc;%2o7g^tpi)jE%J5PAvf)$kXC{TmD3@w)=R3CL}5k-U?at6 z)`&_);n*SyL^)kw0zHtUO7|j1s-W388H@ZtWtStFI4tHg#~O4Bfk$%fwLh;zPKrRp{teO91l5*Wps+ahK{Ok|A68u!k-cloGqG9PzXuq0s zOyScq$*CXSc7@k%6kh%>a4}v_F;?R1J!VCWB^7PEkel zI+^%xX$))4ert7GwuuD9>qjd;n2HIlJt2#~GQblcVA_8RTonO@EK8`Tp={_fjOdBK z&MTC-uxK!<4kT&dc8)FM@=)+-pS)1KLk|#}G^qS1JpC)^(GRarLMW;@CfL3{6U3%V zaO>FXp;sflNW?1mT2dmb^F+qiB4G3U0n^Q99;DjEXquCz`HaD$!@TqU%+#VwXL-bx z&M*uAB>k6qo6nyaryh|K8G)~I&6Y{VIh1H!5ldt%jbAKy!^?AK*#*5cgM)CT-&+S- z?{Tt@#|__}(3)%AlFWbdqZgzkou8nMjSmGk9iFxM4=^O4p#i82uf*OfnR$e;46uq~ zCJxm^x!tXFqH8K{PW!O5XE%#LeCyeL^!PFoGM|mTy##d9=oMl0r=SPn?mtr9g4i#SXc#Wp9#=M4jiuHYof4n2+Mm`mBg) zrkG>!;9Ch(-ez+)u4mCIs7G>`&I}Xguo~UeiX+of#$01IZbeYbWQx!jg5L4G_(gjA zkuHpe6Eo2aZ3J>XOy1~1V#86C2umpkFbV6}h-V|^P6#Kgt7q+msELhDFc==`vY-Kg zEmG>~SNxSwQI?c7NuN~Sv&8#zWURGoads}Cd=xkuaPoU_HNc9eI3p`v@WQ9cWn%w&&RUZ(iLVaH=qoXWq4Ps|Bbr!u6en09x; zAv6RS(P<7hT5a89Ol(ZOt1#dbYGvU(n)oJLhuwezxJ<_AX3bThRDeS3$ph2x^6|RK zN`23zh(bG&OY-T1#uSXu{jv5oos@0Sb2De#ZRo8fO4K})7>w$D@h-)#X2JB$8ak&86zh$lgAV!}(;e8sGavSyJ zA)s;1cWXL)xJF7Mn3N*wYBH%9_AW|W{slGZ$otST4fXwnJ)S{7l(rX~;dE~vKLjTQz9o!s!nFvxNdy*P%rrMN69sR!G%GlJ)baT! zc^U^O$x64N7!`m}?4oA<%lWal{^#V1FEQhK*_r-T!`{2y*RO0;Gu(6s5J8z7Y`>bE z0!CX?6km+qdKTyHr(djzfP!$i&^6r6AQCAyyu`3>gTto30rJ&6z;4IFVy<{ANNhxX zyr&gAG^$itM7COlDehkd9>jPeltz>-RC~He<8qAr({w`pC6HMMvgRBw_>$qLR9CMX&cLIwEZk{%Q0k5g4KBd;SnjcT9*<_M*pfBFDFIHv z6ayL$&F@v${H+VJEi_BD>gt>Do)H?usJ z@pOdGUi(YnhABY3=~3LH85-;IgZ($Aw5_x9y{3P?+017Ir>s<-M5Tk&mP)if@2HP{ z7AzI6ihI24W#|*?M{1t7p8{JDsmtOA_Rt=4@~km8WlM<9T>SX^F?@e6mVlBj>_-w0 z1fd>#3Zk_u*#9(r9M`#)tkv1aXm%mm`I$-Zc1bxr6$OO)2?fmWWanMZ(Pyo(Jrdde zsEn`>r#3QyX`JHy_qt`Ps#OeigipypzZnNHzabdQK~Qgll|8Fec0IE54Y(EDuANeL zcttzJbRGR|Wj?m+}!~N)7M=&6tWmBu8-_ zBN8g{%+zme;@eS&q(Q-j!>Qi)`8Scv5M5@RB*Oag(+r_VDcVGZcOt^eK+3C>XE@?1 zl3c4owKvZ)EOwqPmk0>bt0{m2^09KfDu z-A?(xR|ukE`IZnfJT4wMs)B!EZA*g}uA{`oMWDw0vX=&q0-@_Zdlt)Ufw&bzU{ir^ zP$y&mtC2-DiH^y0KLX5i=@>VD6?UHR5vJ=dzc`K3z%e96L5P%ASLLjaXK#Qj?)r&` zQIdM4yAo1*+6aHd_wQ4G>3j_@mS1Z7P|UY`P3h_aP<)G&nxT_fP);@7TBPzCKLnB; zjd^b=LASCgb9g0}E&(Z%BxEq+GAW3CIW@_uj#~jj`A{hNu_eD7TQo<3Dj(J1&_3;9 zkz2#UX8rL;%GC<68@U|yPlT06f0`Kjx;&}bIx>dOTd8i!&xfMoJ*JQ>mtOl&V=6e*Fw=2TqNmxMJ1S&t+jRyc6OFv;od z`R8M{TY(t_t0=EHxmN!$x~_}77j=_E=m}g*3Z0zzE`jG&hqEl@G?TNCcRP7<5L$&) zn`KpW-$`VrcjJgG$tT(ST;a%W!A6(Tlz&f=-`n>@(?vBbkix8@-uB;F((Tti@nl}+ zvi_Y5mBO&>vMB*}CQG-^)Of+QSy$PWgGldS{;f|RrleNVSRo-6^s@w{8 zKaN9b-^5M7_G`5xbsFSHU)f_WYo{P=4N+A&Ii#W`z)^z-Y6D1Eo1EC}Gr==#L>7CR zUB;XlF*l)9cE8nVIYvcEeG~!>R%>lRRY+-*s#;F!+N0 zX~1T`Iq==$q|#%^pZq*{a~w%5T$&0pPru7{NFWXl>PZtWf$$TZBC2F8QX6}r9cDVU$@s3 zqB$D$+XDs%wetT)+aU*nBlW_JrR$xK}8BAGNM}pqiPo5?Kor* zb9A%_H0P7h!>}fTz=gn+pp-MUsr)82yzkq%U*n2FyL`>ygZrVR;{>|{91FPjDF4$K zq~7$64Ky`N{jR)L+~3FjWUaRcTwD=1VyHZKt9X&S7eKt>j$nq)=L{C8M;!R4G1#gc z#GIR7rY3Mmg|*kN8OD+c_!sY_JH_*0U38}qEs(95@Lvp}aj;g)sq7doG3xn#a9}ZZQ4dX@B20FXuImPwdqOa^Q~BH3CG5itIq2xH}$vZ7>)uIO{VmrsORQB26-aNA52 zVZ&G(%Q6V)?Z=B2&@xV;;GM20uZ3@&`e#U4n$uty!93eP69m| zsF3ijt+q?QCfno>0CAUKcv5Wtwzc*~mJ6D8fdCxrX1%(Vc+J<04xWMX#DGC17PLOR zRgBpwvI9K^!@?a5Xh4IZ{hNkf{D)CPsQ}iHHt}fxQQb?@IeBW^pjvp~B@eoXiE0*L&FWO`!Vo%HLd0O8gsCYxIpyQnD8v9A2{T8!} z^QxQB6>jLi>jC0pXbpGFFjhoyRM*OwaetkJozalP4^1mWs5r%QZ>uXoDR3@#{4fXh z#nh&G!;T!WJ>X-C>i;}Z=fvSMr@ZuU)u=$VpBc-NVW~cl0sT+g(vT+txVYTUxO4)T z#K^KyhSt49_e$0nZ~2&R&@kKrC6hXn{`Um^wzkk~gfM9GHYUY3aSaod{`O^Cm!av& zQ?}YbFYmbt0z)qjWJ*Wh(CbM5MmZl)ct)f?-E7kT*1~vxVX#Ums~8%jKpt&KQV@sr!d0%sl)34CMN-Ml^XU1{=;FdZyq z2!NyM4QR;5VA!J-YTRhyFa1)Y>45rO=-3DnPXXuL{^aH@aD?!$ z2h=2j;-n|hJP>fT^6WJ@ypT|l$mI~XXd{4D9nrBgP2#~7$XKrP1X+r{!-$`W)NIz# zZ`lalA2}$g&-|W_b>gfC->=(J+BabQkUbEU5yp&ZFQ@aUW!|aHWuWM=W;RjoTcbVu z;bEk8p3abzB_HWFVI5ltj74IZM4TNzUTefjIbpi@jNRXHh zFWTF-)QB+}nq!bwx9!Fy&BlNig&srScAyJ}mF$n@S+{8IL|e>PTLR*;TP4wE_pe_Vu?`{4ARbJ7y$bd{eRGJo1#D-(=P{-_XlAnt zVd%=SvslMk?l9D*Pf3oUaryHmdx{PA0#ycSX;?Uk&UumDevL&kLOa;(@QKac_lM>a z#Y2!?6Ej}g)`=PKR!(JUjQ=?gicD3zTd1bXUb!{o5I9tQ>=QRO~s~-yX9I zjZD=GTJ4~SgToh6S=6avIN)#7RX*RpcgqczIYkm2o0$I}Zc<4ID|Nm|5V$+#98_UI zX!C{XDU>)?^iPc+`=7FT!_*`7*XSBzuL|`cm;nOrTx4Hi!I3^GT0W4%crB@*t*Fns zHiKc0gPMNOpZ&f+;=`J#+71{N607}$P?9%;RDtu`ZU@nB=Ywg`6V(;#RCWjRQUDx> z=RV=`S$#T$rn;_YV1TTj3el=#7qj7f7uVSP;UWoz}F zg``x6N50JLD6F3`y1mC*%`xc|X0FaG%ZhgGyE$~AXSB!(b#IeGWoQ~j%sf1+$o*mD z$bih`^%90#OnU0UNBKQ}_~RG3z=NbMzY~2E+S3wRtQh;xt;Wk0y~octAiHfk_n0c^ z{!;5zzYRx60M}^%4K)))JH-&7onc!WF}#K>gs5Gihn!V2eEUb>1V?g4$|dmCmhZIn zX`&8QL=>`FZ2dw)jmGh|{G9uq0`$}g$GSCNZ0r&mr4bQ(|~;rqmbWv z*f}o=<46VskMI|DjV?#rX#Nh3qrDw7k9#jbamC3&xZBniuP`Hpe%JiLLyi6=rNAc8 zam>$VE?xCO)Ya|7H^HcpZ4{}XnX3D8BEA|B*RHs3F~sYq=C~d!Ko=TGbnWPW4SR;c z4~)i};d`2)$QS{RP9cL%hY%YPyiX#*bP1``5`!4@-?F7M49ZZ#chII)fSG_LJn({n z-&K-EydA0RZaHQ-*C7^pSuY-}(sQB3Ppu-iA(-MZOok|5vd`BwEci4Tvz}c~!XH<_ z8=-{H=)&naM#!Jehx=~Z?iR-C74`m70UaL7q;3&c2Mc;ta~TRv$Cy3s%{&;-MK7|U zK*IKprBN+PG4{+2_Xt(G6-lBoWro~K1mLTi-bNu~`%s%aV>x?;FFujxqE-h1@IATo zRw75(mS3J&2qp#Q;*M{j=C^8+OZf=71ERcu*Ys>oOws0D{s^`Ph8g>GQ5nI`(4Vk+ z?7oHr-I{R^6Nis9Y$E`cmNkojw%0ZFxTNI{dddQCjFu@4UjH@p(=`rBOVR0AXy(1t zM(j~>Ti`KnXuF*BahHB(f6a#1Spsh`O$uT3S<}emcm`&Yf84a?by$cP{5i;TlVjUc zjkeuV((#P0TXMBpjpgqidUXDzH8s~A(pi+T8O(3O1x|Oo9NpR>Mn7U zxX2KZ1GZU9VtWsgh*n^0*s&-nvi6tpVW4IO#I?VH^nBOdd~hVL;3A9{Ts9x0P-$ap zy_j)56dH4)3=>Y0P<^oZge9;!O<;inAvazB)R)Lv#*!w!;(vI`oIC_DvKrc1bfhe!iK~G@FLAa|c%0?{ z8|5b;-BGyb$jZ0yZ?iq+^?Rk>bS3ZGW|TK{yleZ;&?1|IP5pehZoe^FQqBR$Ur5CF zU#7$lZsC!C3h`EeKb2I)jpfn-CX>!&i`ZFB7um?YVQozHKSvd~zg4C35Zj$vq}0uFG_hAbyNTF~)}Rq`&G|J+t8ln8^sQZ#dn zz&?(r3{hJX8_gB>#9Wz1jkLlK?6vr{I-cvNd2{#9oj8+F)m}Xw8ECo6e=dDLc^dbyO#P}G6}q?Mp+E2awbHjQ%-y&jmJxJF z!#P_!o>5;8v@7qLy}Ek0wXl*TiMihZ!O1-d>8MV;Eop@LZKLqclG}KPR5VlzE=(a{ zdw?85s)((J=^5!X30~bqFP$Kc5L8FIV=~(y6ooSD1u0_7Jcc6C%bKIJlf8cIs64yG z%e{Q1t7P?b0>uEL3{HL09^*Uq2MzaxTfbx_!$bUxS>R^E6K(x$9%(Ny1_PP&o9D^S z*sovgs*#A?kPWPKq&BOsynnWv_YahqqvzL~R1rJz9xoMg2q5AP{Q<4{teVb!BgR9{ z%qmT%_F}fgU;PPTOog%MNX-F&RCAnZc*7;QgQi`m-XA{UbSM9iLBSlpgX#(rI>#6u z2vma;i6K`4G-rIw*sAuw#d0^9uh_;9>DD$4&! zd^>cLYCYt`T!<4Q1CagEcg=XSkzORgtXIS@G`K!qSD*?11QjL1I+#s=t|I#WdsLxN zKyeAzz=fBJKh0o#p=~V6(8z)1f5DmOn5)TZ*ZtTnjV+JL@B&-8C0a*vIt{d)qpX}A zf|lZ2Ff5EG2?lB!x=J6Iubm05eeEMKR$d_DGk^!5kzP2ol#8XLlRe-Hg~2T4`U#Ym zG_(Y9UU;Q1e|M-zni?=8;hlfrkd!WRi_S6a$yNyt4i}h0MaG_UwxMjkW^VoVqE%o9;p- zJ?MsGAQ2IZmXigNcqGVV?8W(ex1f_=BT!6+ zwrDx&SPCg)##0!8lqC#@uOF{O<_c8#sa^SuI9ZrN;tUQpaE3#*&tj4cxM7D z^Bk_FG~@=aebql}DD@~pjbPS?LQ=j>0v7qn17?3!H7Z>17&V8S0HICv7gu# z!aYMWxS8_+j!08jOuC%$d+DI&DWk#q1qI;+AwG+<&Uzg?@1WJQah zblTDJ!lY$0oHbfo9S@;yJV9$g<3Rn)2d|h^S`lpa+IfY2WJGjeH%kkr5mim`^gB`8@aVaa)r~6sdBr44mm5WKS3gm?+=~P@l@Y=*Z}} zx;+K{uejKdDZy4q_}SUHwuD8caJ#`gg^H(BH(4+^UYFdK=Y#9teEbIOp5!7|z(fnH z+p0T^>P+ArC$%sH9wpb8tz6U9xJ9?*G5QM%L6!zl&3~K>fvuHAD-Z@pyip`?IHty9 zsr*h{=pj2yW>#L2Gs=Wyey`*T@%Q6&ceohOQz@_QnC?ATkRnA=a+bP48F z;vAry4`^;yvYl=G?Ot6tQ}+7if`7$Fq;Y_3ddq^E(Yqh(-M;*T&Oze2w`+QHxpa)VE;<*f=r4`{kvvs%UP`c zl@!m_22YU%^tANFU@FVtu!{;mUWr=uAhJeERzSkeJev8LK-)3ETP-k!*O8&Hr1WJMdPi*ST_G15}seyY5g?y?aPn;KF&+k59?(O zNB~UF$qg5xi`By`a%KTCrp1tyl)p&-nNnnC*U_9rqgNSC^<98`W~Qaz=yR>pZo|%I zV>fV8m_f*b>oF*`&YEKWzgD|bh(^Piw>|x8RDt$z@r~pVGlWcx0lq<&*)dy(qw3O+hza#CxpZ&p)u zT%18D&h3ZGN*KnN?zpTLlCk%lXM=s;23|W6>@&Nq@ejIi@ESWjeEVwAVfN}CI~XIh z;m)wv5WJHiVi5gC|4XKA!SeeVgPnGtFA` zYF?{x0&_j4jvA1g;ifTTq;T4I3xElcL$(g{o>xN3YOYqbm(FZqi?_>o5%8Sx&R_Wq z`vZn}`V8|2q=GGeN&w61h^)a&7VbTe_iF%e-vg+0O%3Qw2e4sw63nWQ$onu93A_Wfmy)NF|)h4 zU(h9=bMYe{_P$uKA?g}jE!E%(wvxsqJOwoL4&4Vq2(R-X``_IH3@{g?L(1iMrjo9> zWhhO1ZOzj5h zuj5CGnkBOPbVnM32EAOD@GyEkv$X{-!yp)V5#zLI6t%_~KJvd}a+F7ry`w}KUL9(x z5K)~(VLPE@a3E60yQMCqNQc0)(@E^ko=s34cARn9ul{4M`&^Hq#mhnJ%<=;?Y$>CH z?*?~lXn>mw(ZynF_+lW<=^QH@P6|#$jxl&`El;-I_|l|cXh;B^Q!Gz<&{}|J1>b{3 z7Tx1K_C*rV{Z~rX?nM(}c1@UYGDJo-OFssRA3}bp*bWZbVU&h1+<9|(XM%-r4#5$& zn`#Qq7t$~IJ3&u@D4$ym;{uXNLwow4$@GQ@-x=tbc&ujE<7U+AZwDGEf5xZb{Py=A zF4Lo?wd_AkcV(Sbez3|nAPm-^T{|O-p$ZKgHdrqG5w8qGJoDt-4bdT00=p~!n?kZ- z9hQHcFpL2K6xr+~0KCy4uU!6@&CWbrZ}-$?s317%Y64M9sOvwx+__F9D=q$st;|?C z(+BVLv_rN~RB^8-#WUl_D0wr@EFBW-FIFRr-=Y z{Q1$X%pypijz@1L0E`A}qv$>Kd2b8DJKE?v|Jw%^Ho8R+FMDbmaP?mncYR=d?9<{C zj+eBMGTk@%p<*0X8Ig$5b)=$3P1a#xH>X}_ppp0t!Ob%&grJ21j6 zZu04STi(Fdo(REh6`Fu?IP{7^To|;Kf)aS+U70)2<51SJNVlduw190SHDq7ChQA$s zIzOR*8>8#joK@0Dfj+!(Ka!D4Y*V1nP_(Xbvk~bTD`v||0%W8N=g+SQD;^c(KXkfvnT2+6!ksHRba_aB0uA}aTYjEHYtq-_G!`vx~gRq3T~M+Y_QLGp=Uo_J{VU+ji|cat^02NYxMr{2OqH9n{V4$_1m zBOy3ah)c$gyC82VwvF`InU$U4!^)<47>kiJwbB)vndUh#;Je*&k%U>5cDp*IrI|*=#~7AHf)qf zdJkY*d{Pm(Q9_m}tRND-Br%gwKP)jgI8|qid2lTVr%K zOR>2f$14$u^TeJ>$??|AYn*1i15NH}-D*;GFwR#`YWTclF>2*=PamqDK6)2I58&@I z6LAG(J&6G+l4kNs%TE}Il0fcG^J?}o&lJ8OJeh|ZF7&`84EpNd5xxaPLlo7YHYs(J zt|R%0W=XpW{G?LX#A5xyaD8|vhA^VZF{dgyGBC1+*7JpciVf(~^&vDY0&P~>m09j8 zI0gsFkD%@%->oX;M{p-W#NKryN=A!-B}_9T#N>^xzvMDf$;wdxsXsn2RP)GR3M~G( zZST)JVe7MhQ#xR8M#6*_9Y5lY5wmLvVF8)dVJ7wL)Rn3Nuc{6-^(H5D&`EGL%A&qd z!lOKIBr1+S{k=&-R&=*)0H<$2tcFC0jBTR4ZxVhxOEIj6AzdNsj>pbotvI>qV5UE% z-$XG+srjY$eF4{3C>k&UkI_nZ=CFz|3aksMRg(2|D&lVY?Orxj#TB3;VnjN9)hl7)TuRzE&t zk7c9-_Q$Rk>)@0Tox)U>x2*Wq`wyj3^1@r{YsGk-n5gk{)Hv*CArX+AW?uC;b5+ROOnpy;+6*LzM7*-L6! zD1u?1hQ)<13dRRua$MxnAektwc~9wobxWmCnN!U?pkL(3y^YbopdG>~3{r)#mHw9a zx|dYz7u~zd!M8uQ-ARo?>o@IZ!Bavy%SQ~V=g6vgzhc|Q0iEuxpG}eqq%?;yr*0h? zMl5eR=5eAeL}jzE!ng?xnlS8j7hHv<%sy4?Gqp?2yt8>P_al7+n$aVnRYvH20hpsJ znEV(*oOdnxx?GR?m*DZ6!FUN>c}^nkCHniWM*5GpHR~2&hC(Ra6rzYYQsQ5d#oc;Z zZ}u$XjuH(q1kWRiOclKWiN%!NJQWdixNcdG8N1&qD2*D{Gs1jdQogJjQqu3c@AFQ8 zN#w(Mul3+JDJ5rt4&yL*e~|9Ut)7?l{|26_N6On4-Y`l|blDZc1`6pR`I^mbw2xVl zUE{5un?>yhf*ATi$HibAnLm1Xk@W3hp5t}4aB%KRmYy!W6=QODsP8GJpGdqtk94nB;{h$*mt18?117p>3y{02Q2x*ajE@$vX+1I z^KnTXi^Mph%5+B*?Hu0Ib_dI8F^8cR6UGFsUE^nsE&B<2#@baKbBzr192qNG0b9I7 zE9D3KrrhA%RuH5(v^0BR@r$~)iPndK*luAdpVvW`4lSk!UWS6L=k%$L(1BxdR=s0? z4$w0%3nkee@N%ejx?e~3%4EQtTbsm|He;_*>j$k=T#uv|ktomo{52X*tdMzzfo8&#)H-o?8_&cMyS(3f84ugRf6tMZc2}<8tbL9}X zln|xSR)k4>=ptd~3%I{b#*z}vQaPD%S#ARXIIl=A;pSF=XO%DW0zl0azW>bGZ}j9~ zQ=F7i1_YtnPLO#jqwcr$e4e(20gb&JaURbLh$11HS?Z`ylpd^0BIP~zTaDADCvT23*Wk+=f&b|M4bbNQ z%8N{FehnA+z26QaM_lcKnE3l1(2i|-O_EsuU9~Yb>*7mntO-E(7EXaTafDnpSK~^r zG~C1fY&w`mmNhuoo|@==DmDO6RK31&2Hf??WT|F}O={vw2O90pk~3JHTq65bi<+As za>SeRo;)o=*tTA^g=S~aX(h@-0KX@U%-JTaA!}km4~cAxl!A&FwT*R!JcbvJ!ck*4 zB+oDEIZ3mR%O2pZant#Yy=G|i&y7cM!mYf~=bP2HMjiD)Y1UuTn*9)GOyv5`v0GQ; z)iX+`)wBH$3l-fJCyuBCkMD|prV)Nd_WkS^zrFa|r6~Gd8*SXs(ZOlk_tpgGM*P&7 zCQFeuQ}kx(_iQV$TLMcp=hqtO%0knIqWz1 zWU_4DegBJ5O}5cx(RjUTvp%Yb@?^p$UhU(?L(`cc((uHvSua(@q>C@;h==s>hLJg* zNa@h^sEw#VqiYBu`6m6rB8BXI@?%%aacdn9%?JQBr%&iy?H*XPRw$$+PWUwV5qNf* zfRrH#HoOC{POB>W=?9QYe8(vQwEeZ zdq`^JbyP8LWzX)+>{8Qw*QA!N;W3k}Gp~ER1~tpCbQ<-*dX2P>25_}`C}l(@EpAuW z^~B@ILV@e5LEI31SsTo<>HlA(F?}4}O7*oB1M@Mnp?cjLrREL3RC_UNC_9MS?S3#s zH6>EXZV;=2!z}Fb32Y~fp>eR$jo1hDhmX=Rp2Jo**OG$itPB}|)?i`UlMg3pF<6_l zIowvG`+n=h;x@kcglqdQp!A_?6!RHJ2nUbPU&B~=NSPQ=yN~XED-3|ILJwcA@eiI) zh(Om)Cjyro12V1UrEJl-R9t!ZY6xH&TTLkD0U(i^hqdEL@H=!M){*q!GsFvm$Ria8D6%Q$f;aQl!!t00z^ejJg zW;lNvP|^%e-+zx85;RoPa~=a1Dt^ye{T3wr!IrSB@S*!Md|lA1A^#l=SViy=dT~Le z0U2om^eombRR@-((+FF35#k-MNcOh9&dd2&1ef;|LH6|v@l;O>U75t@ukBsxg^3ZW zVcQnlWnl3W3jw9pO>=(D4+kmDrM9_&lN=DFuUd+T1Asxof*YN+B2 zB}60N{Gu_UyL@{{cHj0M&ZU3=3q_QEzTPjo#iT6e`Evis()Uq)%AS&~5MaF_;*^ku zU`lBwF$aqgq0}j*=0TJi2P7wn(*^;FWW8E$uEETjhm^q%knop)0oA@0xj%`9qA(uM zci8TJaw@gkeicBpR5XgrWCsKw7)S092S@M)gDY4Vp z4DnUH5!zh^6xF0lJfWji>Uz&21cNkVv6dc~oL;$wjT0QX>6!PdS2CIa2>YA!v!FKDfpSesd3Zt}p$)_;9c4CJv|Y`lWViN)Ub z#WrgTH~>W)QO2}7k#HTzx`At!Zl}^2<|26_%ZIN4F7`21k2{Qj=hUw{|HAn=V05_u z6j@^0)`J?CpPnZet3E)HCO^OV?1W{-v}Kx>G9=K0*@TfH=3q(V>W{R)2^l27< z>h_lEh&!&gYFoa7LblCpcE)Vl8R~d;r%4$V_*kJ`W@;)74iNwZDQa6+&Av&ri}0v8 zd4SbN{jI-%opM4^L+c?5b>urCfCTe`P{L4ZhmgN(m3FhboTY!S zW$@gExoohxZ_2`aN8=)~28J*Et(Y7fwn36_VV6$>8)d@SFjnB&CHST`^C75IBBgiJ zN5>r_5}TsJ4qm~P~K{F^a0&D7WF57pM>SB zyZa*+Nk6itnSSG`gXP$gz*UdyWSTrx;>&7LJ#N#UFAVHiMy7m&74-OB13t5qch6r|aYqFFj%n#iUWwys7YAwWyyXJPAWB}g1 zB;8IrG&Rybohw>+08bPN4AgNPbwMAmR)e2aCJLE z>L_;q`ep1WmLhur?~&Fgm(*?Dw8}&Xl!VU((e3I!xaCsqESe@EqTfYyr}(2h*v`=Mjm(xdxkunxbhoNKZ~F zK=)B%3dp7!kcO|CDZj)GJbwi%``(dy=bI^8iKUgv?m~)hOpnuLrp%x5m;EVC*77E! ze4e)|1b@+H1Q$CWgfn%|{L7m*ez&fNYPuPscnzW=hdGiC)0zw1#A2|OR}vTJHoA%~ z_F6YFPe)A?2s6=_J;X_M`l;Zrw;BBlwNoC?seq?*M;fs3J6S2~mFpMEZo6YKMiI2n z_k}YL`@}g9I4u^cXPyWXGXQ@_+VD}fMWVFnu~qWE)&wcw*n|Xb6s4|M>_s27Ma4?znSiHM5r;8Yjhb1`&Y}3@v*ONqH=V*3AA+ zMDiMv-d;`NH3DjiYw8VE!a_&|X+X3e=0c&?B*83;>+eZ&1XOhVV>cftz=C|)_Xw_w zW`Z`b;%#8Zjlf_S0tXczZ7tgWn*4~HCpMh8IDMTohsjfx6xfFwXy1u1PDUsLL zTSJSIK$8M>lBvd6=!n53VK{?LSWVV39Lzw4PPemfBjC^`l5sa+e%wGbad1l@ zf!tOC1c~%!#w8Xw6hKRdp;LOS-&lC?&N&x1(xh?P(qnNtDsEs~*J8NXY+l*kO-t-c z_GUF**c5)77srTPxiIoX`ZKSoFCH4i%tuDc300BOke72QmZIHNEyjeaG?=JD;VB4Q zpyM9irIqVpk`$9$+N4bWB3TF_bKi6JSY98d8=7Oh&6anVmjRkR%k;zwX!gpADv!<@ zxoM>Yy0Zh1h%fr1xz*jw#D6jv_BK}}_NoBA(pv5?`Yw1PC*mnf+b3+CDs^P`3P)!hs zR>S^q@)ayfo}DRBLN>$B@0!+N8O%qK05pY#avZqdNt*f3$Ci~jJqcUNs*fApS?UnU6wHVb9zSo*4l9c2B>#cG1DD(4EE(Bm%a0=7FZ>*)d%9XOx zZg0fC8q%%&IVtQK-+voNUUD&2ipF;dXk5V)(}0Tf_Y?3qhG{Ao*yyZY_l@8c#0;pg zo4tIp=6tE{fhq1##J^#NM)p9tOPG_R{18upeK0Bn2URTq)A-H#?Kg=Qh9sR@OSQgy zH~`YW>a_j=D=71frlSB#^j$R=cubjPMHAC;R2g?AXJaH?z85HiKw$uWKN#;)AIm6|_TstJYfAwBL>$uWzl8Er1rApEof4VF1s|D6H;NT5IY@mGVFJt`(F2>4 zvUsxeo09^jcRG?DI%|D!>oOi|8Fw7AZ+?f|=BmHSFq7deV4UUli3)au3wtNR8#Uw$U~jOZ?m?m9IShJ&$BW-mm8Kt1 zJc?z*z%@-~=KzsW1qlE2Z^9r6!fK?NNY=Q?IH3cNmXlY#6=*Y7-x!LL*}x>+Eas(S zg%Pw<+bQ6Sn|+T`hKO3EUx~VqK2Cc$iwyzt%92zwZq&q(P&^trh8He$5Pa_5)&D2{ zfys{4IYnOs7r2k{As-Apge*ffppE3!mrLeG&#od%GJ+ICcg-Aq42JH`whQG4g zhq^O-Sn6h#qD(IJC}XbXA2!~9iurB$`M#Z~2M0Nt(s#R;OJ)MPb!5W(zz_*ys4yO^gx?Jk5-`^n10a|>{(zYH|;0K1?| zyidp#QTxv2EQ+wyBEx&cbVK22of;{A=^%1|O~C3CPuwD&^F4s6RhKbJc%s)YsYENb z3^mKPRpMVdWLJRbrHsnVz5uKVwP^k&XJDVyOU=Hr5=QblU;h6WT|E_n<-* zI4KARwc`%Ew9d2Z7>|8&3{79kLNR!mS_c*W;gv&t3%x{D6#Q zkGjf7k%g(KeL=cZ_o0`Ue+iLaQ?MkwEWYH_WvGQdN&LNTZk#Ev<3QmZL5x+gPNcH= zPT39-*x(cr10kObEdxm7r??-NO1bOt@$Tgeog}-UYw+^`BJyp1>4 ztr~6rU@wAGVza?ryo}Nz`65V7JS0Gwr;K5Nd97i4kcfp|>*9UR$?42(VN8g@e&zm} zuau!jb80tncqwp{ggo5#t`fJ=##k1{zV^eSPZ9V~Am<(K$+CM^t4&x$6DJ;7xbcAi z$v8Ban3A{-g_Orb1jtYPx{Bn>u^wdCy~q_^<3sgLIL9WXYHEM4Oir06+AUI`AC&Hl zCPM_%wn7Va2zJdttJIFzmNcdAePSekdl**?&daRc8@R&OXOR}zV_7*>My`@R_JL<% z7P*!xcwnfJKG56TITxvepaMvMZbE86|2ivdUu1gghAK*|dU2T3dnVU;rclje`qE=>=z`dC@4ki`zJrodi{rt~Y)*kahGTD6+M6Q_g zuo_{eJ!J#sEGjCy>2Y((#-DZC)iU2@q;v;t{c}`ch6LzuYW;q`MG>NR?YJHz1Kx5z zQvh=CE-pod^u@?Jq~K|AGv@!eXE?ro>x8M(CksPcp8EH3#}8g zjva?(Ab@ie@aR65f(Y(4Mh+OR%O4^1-?Yt+!REPRc?+O<|Zkr127>==m!<;GYUD$RrCJ0%AweWe9+eV)!c+Fd}WLGWL|4dVO=uZJvb zWnLo#Z$Vrb5-T;4eQf2z#0(wL=-eclWq3v*m_OuyVOV)!^}KSu zVkORe+l12y9)?Ahvtu}|qK+LzYn67gd^Je2X8w@ZVq>6b^r|8O+vkBtgnB2<ZA?Fu-cVZfxhG ztl$i81aPU!I){wH9_xC6K!N;);AzDYLVVjyeAtp0S`v=mjq=)R%hZ*x<_ zc+VK6#36+9zPErKNJ@mgQ%jfBl1YhmuRwI!tXAAkchOniZ|FwY3+4t=)CeeMtJg?J zaYH9&;@ZDsKjke>No+XWJdYg_>aOoUBzssHE+}|_FukV;eCvWmUKJzb^g=fLijJG2@Eg>V{vG+8HB)-0&wq{}3 zqp(V^E{v+agGO;SyMOK|+};Q6(N4ym!5$G}8S{z0-8gAn-)F04oBVjp?W}tZY;x;}H1n92J+#G{?58*xh%CQm>sCs$ zrS^Qz^P|_|PF;t)Qx2)zE1GNQS2K`l3r&!O1H6_5dFYTyc5T}`W`r-k`(fHuM>RQ1 z3L(`gXbkII?d(Z?b}b4{thj`SQcoEo;*br$kI}~Ee(-~d)s~r?Fx$L`tVxkL* z)ayb<{^s}i=^_I~<}jfZGw>0$@$`75L}*6u<9#r*V|v&FJctW|F{Ey|L@%Vv>U@)m zL>z1Iht1{EW_a+EH&hAFxNH_m2Qr`s=UC_%DUk0*d(zLh=3f`_1^ zC|f|81Ev2nb?$xfD}Bun+R>7LX4=TtF4;6Kq$M8#eN{bis#o5EokIGGS`UsE!+WX7 zRfs3b?{GfudsG0vjyosx?9Xxguw=02)l)aQ?GQC(b?)}O?q0nBp#eSn9tNq=kFI33 zgq=p>O1bTpO5u(`U#7i~I-x>41ycO)&K+ z6W$%6slsrvw~<{amT^9Uue&xql76d!HC8HZ?VTxQf&hoUO~3d!L*3q&eEAIR9iygHpzSR#q$9j1NglGPlOX6!`5D(QlAr zd9&`Irmb0=GgVmb0vv5P89zVS>d2D)*UnWciNQ~Wt8ng z%H!~2Zq_=}IA0xh;|hVTlnAO^BG*%Ii#3F1ScQ+4yTB7xqH_vx_8!yVch zrz~U_htkP*GloB`^DqEshb-ZO(B#{3e<^S?(GQJaKA&X2&A&!aDksu@Y1!5iodx5) zvoTxEnABi8#e(Y;57q~PCwV#kMR@sIY$qNdy#KnI4A$ds)>-a+{NQeIpyGboT$4x= ztyya*k~;Mo%hxt#^iDLUC=4dbO%0sc#o5Rg(1uX4%OmzTa#B(gk#D+)KfdDzQZ$jrrkNFPIpNnTsV;!5v`)F~zbAEg8JTC5RFUbm- z19jcgC2tu*iF9b1D0cfRx9(F%?`;ww;3qpE z(st{_{UH~i!YSXgl`{g1$-&tpI^zfvn7-A^!n92Wqj)f7RyUj1xtpF^x$oQwL`Ctz zyK-MNJ%2O;nNKFSmj&Y{_PNF1wa2naGgKhXV(M>GKmyYk)x=N=D~*}Z=)^Q{fQ7P4 zWuqSyEuFo3Uz;3>-ZHb97o^+?%Y(LPJ|C-iSRiuFkZnrAceAQn&H4wK;gIQrd@2+~ z$B?|T#st~Zcbc@Z;4lsp!}K_7fuys${tbhCCPqzIPwDNqi&0Sxh_?@9WMC4H=e zVJbdzeonqcXvKW6{{^ODQ~;VY_jEt6E-d?Wzk@KH^Gu510kT9d%_@2NkZQJRx4eJ}9{T>eW`swXN}yQV%BK~zxL1*9(=J{dER#DYNU#2O(Go)ibI}l{g)A_juv26{Ysw z_8&PGFfa&?39-5H0U9?o4e9LaCIoyPA!~dff$*1k(%8dg%o5wXd#gEmjl4)zJWETD zljtzu2K6L8sla|foH*SSh$Rs9{d`fVud;ER7dJB(b8TCG>Z-s?7-S>t+=5O*Mma$m ze&0^{VYtSAI$GqzqAhXLz9eAZgy@-`iT|W-`Scj^=m~eoJTra zLneOj7N{cXOA}6)h=VkDHIxgcX1n4^k+j2fHxfYoMg?c5?6)lv&6!t7!YSyK&JHNmpfA31ObcMs=~*~9M3T9*#FIYbM8xeyNiaBQEX zqCHs1@^VF3dC4yC?q;=3V6(HXtfTP`l&IueCE4^}XE_gHhPVD26P%%=0~2sj1{vBI z0ihu<>f$g78zL{i1Q6=wxYHt(p61`XUi=M&^coi4Hk0SyY{8OZ%5CACWsF4a7~8>r zq&duHtmQGILY+cO=_KKeVi50bo9nURPCwukTf$gFCZaUDKOP6*@J4N)YOb1 zw%1wv;ci(EkE-AGem*);D-gaxvQLI9LMCN?Nzp+t&DE{O*suXWIG42I9BUpAeqnf0 zr^)-IS4598ae;yDc*+67&M-42-Sozt%wIbWL+#So!WmU-(^QEtcHwbb2#HbBT)|MU znXU^GcKtEq!z)C9RP&BW43W4;EP647QGkj{D&53_34)PRc0}-M2|8Lh2kXm_WY)Qq zemYgyiqgrU53rGExs9|R?)Cwo7HOpoch6eeAq+T+2`n{9&Ei>~)!n~hVlWr5vlhaH z;1`zW_V*$rP~FMge)D=$djigca3&Q%&pr7MDMN0$vGd+t%}mJH^C_%LELDU4>?8^M z*Nffhl%rXYJX4=jqzvb?Mmq*2^ND@p{Jr4qd9$RSON=%sN#Oh{IO##1!b*^1k8<)z z?3<3c0}lqshDaDqR|Ls)In?$$u_DqXA}sSS%8W-cb2u^J5yt@q4jqT7W&?bkRSS8u z+{gpd#}sNi8AI9X(O|T1)dmpyD5C`|jH$zyQ`;Mbl{Sq_NQ$vc(S7063s*kFQ4|Rr5YA)!2)N6qzO=!JC$XJlr|<}1w(hs4 zpFsAf3EXgKbw@Q^X$+~nm~ykJ*!9EvQqm0w*Y{uc*)11j+?89tA<3ZJ>M5M;LgXs= zYVu(dOJ#bZDo7cnpfiH10PJ3qYOA{V8l%K6c)j`rb_$351+#NwZD+qIK;O~u#>wk% zD#o-yw+Dz>G67rwhuPj9277MR8S3Qc07!pgG?FfjK(q(n((=6gRuf-7-`m``zQ=0o zcPobFse$K2Iy&Liu*FG8+zu3*mSX2?2eeQelbpmo2m`Q#U-Tm#SU2Xv|JU`fYU=v2 zZTFCeV--M=Cq;fY#0bK~tu?dV{nXPLntPS4D=K2STvr!_C>}kOw(C&i_=k6dFqF)^ zZ(--o&@Mpazp+LD2EO`&s~4|$HRrUZ+oGlnby7+tpdl5yjAS?ufJyR0UU{z-tUIdl ze&4^hG8XWDkNs~Jg)nlN-+k`@@?<+v=8YoI2n2K*f|v7%{)2oL`j&fG{|jKyzx5m{ z1dgP@bRMSQ$OP(ibL{I5Dy0@g+zhIs1-R|>Z-2k?;Z5%R&A_de_D_A&0Clf8zYC#i zZZy;Rm3aT&0(!vazCkRJ=$X`}Sn~Ku0*qWmIsNc68 z7>9TxVA=dEg#?2WgwqR&;&bdBZ`V}6A(%&^%;m6W7b0vtr#DgkS##W!+}z8UPhN}0VVeMGtxNDB70 z%l*odQfMAsW`~ejgN&~+qX{N6>vQRktOX+=Sn(IMRBtuatfh#Nmk~@Rc@(qn%&@`w zHTX_1vmBSzHrA69hBpMx<3^YN6Mh8a#e8dhfCOQQ>=YH{fj5qqZdWKN!$#s39WswsbvE`xaGN3&~jks+0T@9pxPPv8Bj* z{3bs`ND&|XTx98$Y7l`UTsk@zi!d!wHv)I_Ws;uLIHVzaQHwR>?5p$fDV9UO8R_CX z0HSv!Y-Yx5P%3llQ3wV;pt)`ccJ3UVeUF-=ZXG@g9osKdT*C{sNLKkN?jw46_5Xt_ zYwIMp>CSw+l~-W*dcm;a52}cN$9w1SL=)g8Fp2?hJE7!nbJaA{xC3#TahD*kzYHj= znOTLQHI&?@!j8nu)wh_+<79saJ^b#y7k`#rh|NX8i8U3d7kOc~?AY5V zZ?9fBoPUTYtddp1GcD2ie_pK@5?vTvtE9j<>x>p`kBbpV{&5-hhpH0)w7*!9^#^13 z(F%g=k^2;7Gp`WG9`1QlZ%JiiR@PfKS9MpUSVSKft}?TtecFoD3J^EDnLA5_STBXy zUZu7q?kxnw$h(4UPx`|fWy!z?E}aexl@F>kU|bb#LtG61pGLs3pdjg7OdPlfNm!h#ksVq1`HW^EEAxvbC?O5YE}I za>fjZxJ@slBR)w=tjKIolWvji{({ny*+m7}Dg@JC%2D!{v6W@9hs zhGs%Yo@@&jTjyOQqeedNM}To2_PsbWjK;A6wC>!YnWeE~&*p~qx8jzUM@B<(Qa4JB zYiES`s=>2vpjkQFnj3`;Vkp&-vmI%?L^gfpE8)h3*5H3ED2s8~R&mlY#A3`ZNg0}J z1(*DiqE~36rrFX}2YU2+px>p-S5NfTL=a&vfILK-sRnPA^aH`l+565y<1WAQ<8=rd za{5BO#93>b)B!am>9ZF8mI0C#?FAJFWn03nH?mwUtV`v~^Ip5Hr*_VGmjw&eaO-44 z!izqj5p1U3nBS4d92{X3So7pCR_s4Qdasx5)SG%z4LpOsANf#KW+6j(`s*_A+7=gs zpxI-3AMwpvVKdz#83?MDRscmny1!ofM4MtEgDvxlAP&At$qNmm6Rpui01yQ@CAl4} zV~Q}}XJUPrL6XS{?@)&R0>aaOt!0+E)zP4QaZf?#QA>qLFmgTpHo)&NI@?1qE&(`K zT{Urtf!j15YakmZs5Vn3>gxG^(|+2rhS>_6ff|p2P_AoEk0503<;mw(WVwd@g)*8* zx_#$8s*|pFuh5@r2A66|QQqsj2rQ{?$`)x)q2Y_mwvKYO`gZvFw=s>~EbVwZE!HiQ zpU!2eamvyKRBj6N1&zPILf{fe%K>rK{LT*x5CWa~=EC*ydXu!uGPIBKOmAE$(pXqmw7^t@9*HzT7=ElJ!I@ zm<^cXMk*>liJNVs7}MY)6LSv0s@^btfnTSVMn-^3vdk$#8f?}IyJ5rJWWWZr?Rt}Q zjD7O5r5#)DXB@L{@cKru&1jU0pqj(RyeekQn>!@8+;D-MMmUK3MNL-N36$>nTatHT zZ?_(6FZ)bxncAYGI4%gn$5{Em_nYFXu1Z)%`klrvWIo4?qe~w&O?{(eL~?}}0^DB& z5JZEn=yuLwKC99@toH#r3hXQdcW@hdF;|})`r2AH*E9bQM&j%!cnuqJp!l#Cpd;NMUoXddaJv}e4en+0?Z@F{vCBq~ zq?eQ>OjPd)q*;ucN4>j_HF}RWt#BU`Pk4LS5D3)PHkA?*JabPys&ev57QP>qqt@(N z^B72fj&Ny>1E6lBwuxJnAXF)^e0*Loz5s5|;IGZ;2$1JU?z1gu18AX%?UE9~OP1E> zZyY7&;sw5Ki#cGp9X(Xj-uyf#hc8boC&Gehc=UNiQi_aEFETS?uO~6F0vF?_phhvQ z2{GoaHdpen?^qet&B>;W8RR^Ia%UM{(P-gc6|tbfIt?@bMKV(Jv+w0DdPvX(r!c$ zYYS>fzB&%1i^wTZ#43U+sT|r@Kq?$*Vh>alaohCBL%|YG|E0jjv8nW4`nD;s7=jwi<`l3s0?v6UZ-IMkl?gRC z5XEs60QZXOQ2~I(nCtiB5nnm{c7$p9FgI*LFAQDg6EMqbMVd+&r)X@*Pe<|}fvA)s zbe`B`2;BYLNqJS|x2><-V)WGk2rE@7eg8aD`%L*;!>jA0DjCahVjiePKfUf007vj& zzno<#CW5Y6${t(nC~`y@NF4*RJ=8+ni}hj# z8<&f$jVrC`P~3!$$tU17<_hlucs?WVPEf@~?sYz7jB6fMbrl1Cyt-U43*WQ^vdzTN zq`#6fDK-kE@xfX3EAdWK^>3DqD_1z7W!VH{5?!p!LrcO!*!^tM2ebo*%)KM3MZjsJ zta=f51J|ySLCrvZCJy?#5p#w%nL=OoYRSv2+}^kN;U$8B&F(tHV9(ANVNVe&JM9ht zoI}1DhZB4yAA#WSs%vF>uv}oOnT&dy2LRbsm*kEEtP0cRN3pebdk!O!W_Dh1a({5% zZZxOS+)Wj{%!pSk`xu*(uZ7lx2#eOJa@Cb)q;u@!?}Xs*rU~X&CwB=$BD=_?Mhv7l zS#VWHiiv(Pg>fa&u^P-AX+V)c85$@hr}CVl>$MH6A_KRBmtuM7dX!B*wWNb zg3WNN9l}<$ihGUcUe0ywg~To%YWFIc5CeSEF|0vlrE|#_r^HSXn>xCg;vPt4SMJdX zL!&UAYN8shAab!hu6#RNs7-R*ZtIaBoiQlpw}8RXMly2)9vs~__}=qW(Bxi7^iCXF zmZmv=p-?>)|3cI40~p%c)jF3T3Ah;-Fr+*7yz#@~aR_Mdkp# zU0_kj0Qdtw>(l#~xIVUkCVQ6ee4G-k9MU?Zr>=zz!>dpnqg3lFV*24?PPcb(LBVp~ zaeUR)wxg)c4#x|U%gA_JD*4?JZke=08HL7zV-w4OCU&>%yf_&m+8eoe-r@$AvE2!=62czALmDzf6>Jao zPuf5xy9sx09{#k1NakojM``xF682HF^ih` zaqex;CDt$CnDwLtnlDaC7;K`K>>a4vz2v+q)%Jy$zzI|+xbqXRH-H?BO{j9amgO7b zx$P8!dfOBBxJvQn?3CG)l`7;e0~)~Y{FqyzgWF2M1>QHn|!zFMsr#3PPW2ZN%<289Q=LaM=ukX*z=#fZmctJbd3$D2fhD10S+ z-Bu>WF7wqpz$TZHYj!hs;!K*1r$k${2aLpfz}*K9ZFLy^SB2qkdK;W!UtLfAy?gqJt+DND(5p)@eUKGUr`6I(ib0p;6j#oCzNw6{q{^=>KDo1w zK3^_L>XP%>zSF0%)tkQ&>+kyAaI&vRSpceV-GN?fYbr-9Ln|#Jvq7r`>^-76 zyo+XuOwukfNAH=_sJ9g0l3_V+01@rmV?_4U8HPd15nb;W28Pj5?PUtb!I>sRT;;2d z1CZH|)}0wDOLl{Az~3L3GWEk%M61VJz6QhxbEcXn7H(HX(z&u-ljVQD+;P%1-abzR z0{HGX4;8g9`q9#U#O82X>EvJ*6A7`agG=YFuZ`vWHsOFw8MVc`ue-BaF=HtT=a zwF+Lx89437K!Rk~CY@_Ta<(NQEi2D_NY=c1-Un4T*EO+0b( z?hAVh(cxk-YMd;2Maw4^%dYLi^s_ry428ZjNiU0^f`YqQQlDXz=}Tmf{vwJoAOaZo zu?_;|^!+(=ZDliYdbx;G9r=fTP!i%%uS5!wMr090A7Lm&t~ji zJy66~B1p5de1E)m zmvG}hwMtSJ(*HM+(H%S2UIuZmnkew#1|!DDzvJq*h7=+^>@C!HU2gGD{~H-J$Mlv{ zX>w8Bj+1RPP`4~(%i1zg={X5|+z&#aR6IQ*XR>RfH|s*EFBYh|YXkF58Ne+hYGZzdR`U(0Lh!uH(0{Zb3C|1X7r>UxYmKYvzvUvLrz zzSVr#;_9Yx+A*xs5UVf6ZWSjr68Ovrp&)dEt1Y*vp)JRbw5XfRTT;@GTSBKi0VapP z^WDm5YpG}Z`-wu-sHjohGU$GwDlh;?yk)^N&*Zri2w`ijW91-HT-DQCno{>&!>yEG z)}-1%SXL;HwFr%RgDaq3tN;*RtF&C=UP7E#wu`Ch85mW2WRhe(t*}AWqWZSk3I`f+ zNHbi?q{+iWX^91aF3mddFsPuXJ1U||R{rh^z}y6VZy?nf^J z;$jOq2kRZ~KpGGomQ%9oHXMZ+pB(2RI;AqYRD<1Z`AK}$J+IN3h{Pn)8~CS6@vFCP zS28Q`zQ3->z1+`j-$Zn!0;AzDJ#_B(1ZlYRBxtp=z~Fzf1o~}S<@mym)GIn2WwlxV zkSzX73nZFZ+476|N`-M7x$8&+M}1I=W%a#1M~?aKy{S`(j8ZcPshUX0H*&uA42UlC z@fzVWe$7S$9GY6c$+iW|e?#38<*oky`fc;#T+|s>r;av; z6$Imo0ofMP{i_qa;5Yh@_ZF9q1CS@B?_pw`&w-`2M>B-Vy*Hse#dz{u5e#E8@ACfE zwhy@Lo)^-_DL-q};(e36ujpTWh=j@wIn%2=RDm>V-|GA-uJ?=^I=7#~2sJrJII!kO ze7!7i2~_?F@dl~LB_pk_ z*@o;HZ)7l`q3r^-es&fbnizJL*mJE9xojWYPqsARjM;YS>10Ers|Sq%hKc$T^#=7V zz#3nPxfxBBjuSQ9Xl`NF_jqWx{-~3@bZ7<$160x!%{=EIHezGY0e$Fx_h^MUY_uJ= z=H1t~O$XB$roOuM%~`IdtR^+N=P7}DAr=#0!#LZCA@h$q7aztyPpY1qz~^h=81XAu zq~X zxiWX^F}a~)D@u1W?K}NDN2P|mW>l6=Nl05dqNtdMU|DA}PUavL!=Mtzd$+fUHzR-m zKBQ9H1QKhi;7lT2R&xPLQN2W10vrQ$_FU_J4=%s#WjPxTGQIpMl(Tar#?}rb=~s8| zEx?cE?$o`{GFmuO<&-3S*j$b>s91rdH4hD@$H%%tUbaXQwKM0oT7O!FO*Nr#8NV&m zfH%tVP5^H|@X@7Lm~qG50ABT;Tcb5hEyPZP7YvXf$8_JB*N@BZ>+W`J^!OzCca7OVz5|&3L?WHLcsR1an(bCCEz?IhM-?WOlffBQASo z^u$6@?gh3sI3~uS&yxfoXrL?_#;9uC%bcunU*oLS>!;Z$SfoCgW;b_-sCU(^`6-&^ zg~m>&qw-+oHnxQlA({Z<1~njVac( z&;_jWxQ%Su!jujATNgmc!o2#&CUqoGpQ)HDVb5M7N&6!c4Z?%-SlLZvj*l2qe#{OP zK5MFcLZ=8+=$09$Wc6B?s{4G~d#KnP&so5SEr?#E2-0A|(nXzs0XJzLG0&5VH-Zl- z;!2DsP+NoUI{w+p#1zT|e!?t2<|b1j3?~JOs>#T{1eu>$WqN=@kw}$Y=O8^|lVs|@ zY{XSK4YyZ2d3pwZvDdzhkv?PWA1g~xgzU!BL{6Wr8jvXGa}SD6VyNaBPRNOK(67Hs zi6H!`iW4Cg49SG}vMe^BV}vLH^I_h*YT)|8!JrPhb&$T;-nXIB!EW9n_KaY0C$;cn zey?nVwWwWbhTf(ZQPpeL;rT^mWtA(;I>B)$3rX%b&1M$-TBml zY??djoJ=Zr{^gChmw2D`{?`qmWjS0)&424whRjYX)>F%G`N9#c?k$KdZ>`z=)HArH7f9$1|rSppe5jWnL;g&%GGyr>H-*YkH`iYVetR zLpP>t*1YQ~GG#h=IOii@=!k9gC$BT!VMifEzrLO5Vt-L2+`t$_us^={g5S7Bo~gsJ zWY#$?OHbPd=iwi~t)YZ;6FRO0f$H;}tm$o~;mB?)c6rrf4e?;5q~ zplS4H7x%7aOMD*l062jsTjN1=3(BHVj##iC{BR#4-xCrc7%M&`u)^-TS>iS%ZE0l? z=>_r@yieS{G{VfKut7LN1pR?}bm_``8A+4Z-}s~!3X9{kG}5(rGgjkP1@igj)TIYu zG{>2uwPJt34^%son?QEaczw~3F&2zV03Kl9uo?xkMU%}Yp~}n>SD&w1fdDiX+XDyg zC`q*Cj(~edQZqMc*(Mrc?#rNvl~ReJUW0w?kA8f#E-yOsyo5Q8);BM_m!e^V^2NF* zkvkFp`&N0zAc1G3e_sdM^~qkF1I5P1a`l{=%RuG_ao&}b$;y>Dg6j#9jmq@7nz9$x zDjohK$L4B4S0f*vlbB;aNXD@Lq~#(q{A4$aM&H_OFKF0gh6m7lF=oXdTP3LK-XMD( zMMo>aH>lG9C@5m!c&L1(9n4lm@FSg{Nc8IwDcCJirn486L5^eFMJu|WTtZu3bf|au zv$HLFSE~efP_~jzro>~hs+5Qwf>FfAy4(*zvyI&BW+7I)7Zeh<2GuNhCv>7EI!DUh zZqVG72nOq(T`l(bPBVbB(`x)W18=S5cu7rnyAg?%AV~9@llJoq;Ghi* zq74AU4c9>!ASsIG9#8PC19cE6{Uvm`*Y{%JH3|%`q&$^~v z@)ej+i3OPOm%5qZRDGtk-&NQH7y|%0I571V>M)~&_{%0+{vvOJ`HjVxFkcwH5235Y zL4%I=75qH~Ew<`UwcZCi@}5*Amzy>z^^G(sM5WGLfeMIbnkv91j;+w1b}I-AWL4I3 zU5>nMb}`xDkTHs$Sq7ChmYKzbgWiJQ@5$Z}FmQ=1I#*R0k~*J8b|Eppd`7)rRUpe( z&CDCsimozAb>i*6dTC4shMt9s1<}EQXsqZ;KJMm#aqKjV%52b38fZI?$TtY+sjxKp zNt&ZTX+C}W>T+4+OI=YpXhX&oq80uwM0%dg+V+a@oA9muMTO=7`-V=*mL_$4_w&DK zx$&+zQx@FRYo_wF`dGYqpF(r4y1i{&Y!ADUojc_5^lqXd&csB@6(ETLAU;ULxWm+p z99#HJl1;G`HDzvO%zXb6k2v_gYoU)TTo`Yu9nKhlGv2ol_Z3ZQJC_6U6LITm6s=jX zHmM1a1NWW&qN#dPE*9wyXxcd&K96|S+BmYTP>V}xI(79DERi~6a^dsEby!8U1b%3} z0|`LY9CQMvKz}`}8LD*R?d@VhjVywP92&hB4>4k>e|CVbFYIKmiv+s6Db(YwNxd-vu$4Z#4xglFI*fGGNQPK6g;)Rb*fq~ZqSI%}beC*SB4`Pe z-GLzViBI}5gt_k0Yl4`NM-&ci-2eUr>oEI~A_?&uIDSmTr!do~?~2FV_^0yeZxuQ# z8-MExpZBw{!VWHGGBBqBys{tX8Mj$_=jSV8NklpjesD3y21O0jo|#1HT#u^KEiV}~ z5*`s(#8>vcvBun7Tnji&l#Cz430qZxhfD>|5Tz~R~~QZb}JHHHXy>8iVwzz?xYIbfh< zuor>_NL1A80W9bLkX)rsA?8+lHuGc(T84vG0YxRQs`s6s;uf9rh6&CvOa41#|3h(xbfO^XXC(mh+u1;b*Ew> zn8?>a$R;u|VY{yH%5T`tntNbVJn{!ViX%rW^V97XCI3hdht8)? zUg|=1|7EQdz7L&oe$J+6AHF{nWz>ZT)r^4Hpk)3!zG`z=kDm6Wt>hS&uG&DRY-=_! zk-N-r@uwum;EH&uLS(zOAGc|Y<{*@21XEns{aLAF;UOVb1xyw&0Nwz+Y`~`fQ2STR zb8G2T^KeK7Asfa=@z~O{&VNf?OJ;tmRdmAOLx$YLr84=Q} ztwB|xhTy}^I2f5PZ)&Yml`zOrq5|NYJN8()=I>YEgzk{I^ZoyxAwbQ=gfH}IJP{Zk z*=?V!+@+M7>d!}0oj1P^x*ThhX@=#xfDSV{?hC11#YNy_KK-ias+a8_wT?*Go|NH| ztXMY=F=wa|KVWtJNo?2|Ph|v8>^T7kgH|83cNWb?*XCCANt11$IeU3eF>L*zxj%9g zaMi@(6?<~OVn9|&S}xtTX`778-L5E)x8{3g$eDhdy`ao11!5`vkJmy;4RE|tib#aJ zI1_~t%BcU0HdIMP5D_H~itd@=B8t zTMM5t!=Bht(Nc0A$p_g}Kl&9IJ}z&>^B;tNW+aHys?GbZF81Kld`Ma()4uXaNAyC;U|H1Jv^o#3|r_ z7nt9OT?;+rK$nsDP+juK)%LMS^)GHBc=HS!$PnTCE0$41-8m0hVi%H0^MSfq#*J`_ zISx3@tTeZU;Z#QkvdbD2c8$xn1hs z@JWF8(>vf;qSdOg^1(Om?4FDyBt|Af;ew9J?tMCi6gr7(h_ffAe7AcFJFRg*y{1>W zLK*HY33U=MfO(h4M1*OabPaVj`+%TE&zpQ33qO6*0XdekzG1nU!7gsJF7{@@*QGC4 zbRy}^|DBNSmhJmzZDdOkHAL9+$poMNflYwj{5C55c1sT9L5zo-bwUw-tRuc9ze&Wi zMbfr1H|R=-!gw6MU9KJ}2_3`XrUUB**+sV3nV*3P&Bl6)LrnXDBZf z#3x|X6=01U1T$#fwq2+uXwKk^cPq3DL8@usB4=EjUs}A_%NWX=TJrG?BFyER?n~(W zDIvsL5p6}0vy2g#wF6y+`TJ}jQo=c)0mnlDapW%2oCQ%!@6%qh@Ph-)D6;A;1I2>d z)Fip3I0b75?Ea1+6r1w^tkq7AxInP{=q;#w6kXKtu@yS$ZSc*mPoyRN_VSN2`joFR z+sl${E=_fxiwYfLaIVHG^lW%st4NZcPz+Htn`SCF=bI-e>zg?6BIYJ#+yrjH_Tzv& zL8bA~6^A)n4<-z#*q0q(`c<2z))mxgA{IvLx)+@&n}%&ve|b{ilT?a7IEsnzGASZO zh5Y{{A!Rw0FV~~yPsnXKHHh1Y6&XI@l8(>7paieHzMo15B=2?CjF>m$gPAI#I8Xt< zB1$J`xN~PxQWz}~DDB~cujy_Izu^;t)%9(zoEf5bd)TR9h(x*+%<4@@FWee<^^iF3 zlws#nmH}1Z3&}W}Zl{Dq)ACOVcE5q~Q+%@C=Fv;_bb$c0iLlq4<@Wmq2rHHNwJ@vw zFE>aZ6)^x>qbBkY_S<7ID1j>!OpBUXG$`66#`#?&uFmVECDCt`jph5$4%5O!{f3Z! ze|X#X#yCGpu?LXeFi$0F50i+r-#sYLTN!OY5w0FEEM5!=+Bl*@ZJ)~NBQ2o-5yM7vdaq^$$`Iw!v!AQHUEU zQ>;CVXOnMOepBuO89f-ha^QtQsDsv+q)F>3iPD z4mNnzRHI%)&DVJEMD(_1xhy`sFvce!FqU#wYV*8B1v&EMU^HBsQ5r!b%va`vR$~6l zj+t&qtgvLeg4AsI1G={Uh47U1#cESbc4D15}Tm=Wbe;&CRMZ>{y8mO?cZz z{KGo>_$=|4D5Y~CWUyw#u?*SUo7vZXNrTek&euXpZ2JRo)331i6DMvBXezpq85XIu zIUT5U-lq@8y;7GRCd_B|ub4u0A}Q0`ZdITtGL0;QSbSMKz^VHZ#RNvn z?Yrl|ZM|%vvSqzGf&xxmfJ_J1J&BiJp^K9_jgDzu)`hzBTf$S*Y{?4~8L-w9;XD4Tx?vM>$eUDytKbM+w zFxL%dO@%!@E;07C_PSE7gV?ugq56M7KmTerr$i94LZ)M=@1<_!m6|5KoWknmBz*U@)-_5i>)+}~}zly&#bJo@pF zrNDV=eNddK=!AqwgJ819?q#)foyU|DtrTN8;tbfR&2_xuI!qQ`3=ytkFYyqj#QPG) zf7E-rddwt7))fGj>D5jy#8iyN_DQ_$3_S!|zOsQZGjAL>0niVGn@|>Z2Ghociw7mk zLkqvLJ~Hujx%2+^t>B%81dT;-zV3hm9og6`ed(8i(t5UyJeo=EO&t}UT06%Q>pU7h zoSscOOol_&5Xr;}${x%Vk3+PC!7G27;>V_@%G-U+VXa`ZUx-+BxbNf>I9?h}nM@2g z%T+hG$C}AHlPN&CO|C%U??7+5Zq1TtKGGK$2Ytiw!cdKmP^h8*FJl@+UB8{<{@&l>BptIgGJX%EzVX8)wi{PF z8?w%(EUP|L-z&Z`mi*x?d{24>d9auX5-6oNHL2(m14E4}IHLetS#uek%*iK=VDb^G zy1(YM)art+)B(^;YIJU|HC7gQQ}IhH|DYhUnG^=4TaHJ@qDDA!IUM7toos|A@)QwV z_V!PuyBd(RDe%?KrC5W2m73cNf5m6?Vi3iB%R#YNq8tG^KVLZx_W0Wshg z_|*gFjU~!q-ACont3i@x>B@#0_<<4wY=)bbjmgB>Wydc1Q}vER>j~=nEX#&usu{F1 zt9W*Ih|9OR7jV#Zk-Bd%9FPvM^r4B4d)4=}(Nnm6dZ;I*Xm72iN*qSaWNj(f5D1#^ z03nnQt8IKSXX4v5-4MeQe@_q@O$wMN|GKm2d-u<;;PoHadx-R0<}^9E2gaCelFuORhG+sM^?Mu4OxwCa zWZv|x8*Pn!`@o8^h;&hp(j5o_*#R$HNu+c5q1S*sO!>WurYG~cfVTo67{82+9I zk*%2N)ql)s?V|zkWaDe{VWo|Ikho3T{G|TF;e?Ai!xbHC51|X?MHXBnc3kZOf_Jpl zkiR>O$_jP`r`@|FaCO#ydE_3!7UeSsel4n0#DstO!bLz|>6F-3t0;3toG`*{Vly0Z zSApD)%4>(n#iExUH_kg9CGWOK)WrvP{@fid41@xt^X5~Z)%|0%%Q64IqFca_|JLP~ z;;&zG9kfco>^WWvAATdMJAQdD^G_n~;M?$MJL!S%zb+PHs?!rl_x60vFFC6xuk} z;33m>NteD?^Uoj|eCuNGx^7!7JN_u+Iy_FiIT5wY%+xQO;4B8TIK~kZ4C&A~X+Y)D#!ZOx9s*{A#2 zXE~LBdLVUg@RZwZE2^uJioMSoj9}j3(tkCwtb31GQEq0%esdW>;6+OUM+C>}6@Vx| zbWu*X5$=3A$nevYgH|jYx`irit5GD)Fvq=kwoKyOaNMbP{$WY%iCOGeS2E)1G9EW+ zb$K%#m380+rn{zMmn_QwtNX6QU{5s`wqk~RP7PLe{4bXWoRyKvfu|2Dcxxi$Wv6S5 zzxD=b4`$smkLqP&Hv`7r=UlcYH-$2@QunVWPh_GaN|aKHjG7d%$iciC7|6BZ>eCuM zaf{N$_0f!uy_*w-^qH%EJu8r9TG?Ir2592pa{_Wk;FJr4v$}wysY0>BTDt>CEww#z!->=wqLNoYuMb$@jjP5M5!U)M)C(nSFe#>L_}qChsf}IX9;F z9S&>5drR?*8i6?e;w#TrjQQAo1-3seswquxhaWAgn#p)s7-|*g&*j(E-ab~>W%z4B z{;mJ$--J#WtbzeOn@$9gtXGhKP6Cn%o^Xl&sEFiQa7Cu)ja)=cz43!qsUjrm-f@O| z(}l6EhwYzApq7e#u13cm-w7~%GSE5o>Je#FeQ&Gg*&?bdq=D1=!$lVd3l-l=t^i&0 zz&mJYHq}A8iFw6^d6h!4Lnd-f$&7B6Hvw@CaDLnW8#i|Ru=uxh zl+45Zcy=jbcQ?g!3K3sN1;f8G1i1v!zWzWBJLG>FPU7dk|JaF}v$6|c!YxOj&d)Lm z4mr1>83mvIOF&Xc#i{4Ix-G5b>PEB9NFYk3-2$s9tTuFI8T?I+xa-DN`rW0bK6San zmyag@{F}YiN1aC!6z@u_zGsb94;u|G>*~-K0laBqeVa-+-Uk|pEJ|w)r!N`wNEGpM z>FNVQ2?L+F^pz9`K28fh{k@_*|n+YrUnsHKS0NrZ%4)p7@-U3Q%&hY18}WBU3eT*T#hi-=xvNtG&3aOnuq< zN1SDmeTd`PSN`vli?6w)tt}fJpq$=ACw4Hc+?Zw@XF4@_s2c&wHXvk^t|W{biH+M~ zG%jBa1m_UizuuGbTQS_bqfPwb`QH9j6Y%0ozxUKZ>lb*u;B)V0@KrS&u+-d!={}i^ zk*A;VrJrdt=07_6&Lpt`#53g-%1lGSeJ#kU1NKhb{c@@#HfE=wtK0mNI9g9Tx2@{~ zGHS5L3|2y`WE77{Rf(u%olBXxq9Qx?^C(kWcX_U#kMI zlusjHeR1QKG@iyHs|J9Cw8B*t11`@iOTr$rU*6yhl`Q7T8yE4ggI?pItL#ad@hL}A zq(8R`6K*C}4c#m!`Fu?C>KEC@tO=(abbn|P_^eu-aHrYEhYq#Y4Y*R zlAAi`J8)vXm4kE%-$G3+Keb+pe@2U}d6_LF@}oU%T;vWHx}vr_K-!zU14boPzs%DPEfVGsSw5ep~U+38lL-wxmWu zvJln{?1lblw*0owF!Bi5z+hVeT!QL9bv`^<6nq>qX?w?lst|xlsXBmQTVxxm7o3%* ziuKW^cVbPA?wMkf;f7~)S&i4W%oss14pnXy&X?TD)x0JuQ0NRRRH|Bxc@4!SWj9Q{Uzz(Ys86hg zwi~_iT2=HWU30WlRyK%{9>$Z>!UH6^YjF|25xL(sv77ebee)YjPsJv*l|bkb5w0pkXP;}j21Zu*tJkYiPXK$H3b+W=UBP@YdO)_<| zZs;Z$$^;33h53jdcE|Cb2p-RC1f{qkNY5JM&B!ET#JtJm=ISw296}i887#O-2rvO&TdQI%1zn>l}@Oa08d6f8_U7uHw?3Nz60Ffn%YT5K{r2Tk`@HR z6GaZ`nrQrSx*ILsiGUNuh`Wl-yt*3k^-#u!{iR|pTs^dhikz5x9)xYM+uCw~vQ9t3 zppRs(H_Ub`+pOdvMZ@!VbNN=6Sg*j)7g}6%ESMCx7|c;v2G(%0l6Zi(`Ed8q$(^o? zJX)gSh|hw9#VUX`{)QT+pmbYo4$W(@A#($+tEV+n zq;2FMFox)cm8|c3IW^RjYJ_AC%xjHt`Uj8#e;yge#{X_rP0WKqXa{Lx#vahmvjg-m zzK^hQ6XfAQuNybJNyChUgGpZqz^^BPR=J;{8jfYYXc4t0gm5K&nBW!66)1`g{bdc#B1PGQ*J<+4Q5>nJEZQu?|VEm%!w-)+jar z+n@?FM8>t;FIl?_W`Ch|6;Q{2Z^k)mjCFeXoW;6tm?p;_fTIqF4C*Os!?jHZ!?$%w z8YMRNs#mJidr-a#(CKL{EGH>1;7EEhy?L|=p)4N_eX^c0yzY!do6+tKGrIQ}2_@sb z22@c$!$rqqWM-(52pa*6Oz!X?{`&AqeahJjUkm1GHJO+;p2h7Wcltc@q`J}`{0egCR!!a**JFci(ci&xQu=Y{uO6ufnhgXjSm>$C7O^+#6F-*y zbNA_gU5FvDilH%J-CmKpa=}_R1k$772=a``NjTWbUQ&(c2ZC%67CiVtUq!I2>i9}) z1^jxwI3;zyt2hUTR2`Gcd(Maw-Nj=L% zK+q&N8}Ip+P<7(8sP1c^)-g?C9+<(C+oM7prAP`io;j@x1bl~#5cZ5H5Ig}Mrj@hx zGRWoLHNb^;f^Z!o&ErGXz#;Z61>2GLbtv%BX<_0D3J9Fl{SJU{iynk#EGdlih+y(} z(0!%thF@FeG^NEO^m=>DVE&0sIO0WmDI5u&of7tZr=g4~iCjE>sj*t7G(PvzC8Um4 z10}3^XzhRxpsrd=KV?8i?9-}7iCF(N7D66^gW!1DQ>S{1&}AuSb2b(H7bY_g(r8YE ze#n@?6l0t_vc`_&Wkzz60b+x(m;#=0~WgqkyaGSw$lw5WwsI%BzNEF7d8<8=q{`J&ha5 zS8g#XXb^UoN_HBnZB9y>jQ#l5h&PsnOWVLOfwo`Cn4DsnjNAR5Cbk5)ep(sUZiUA-kef>s`mlAmL?MRIh&+ne zZ72`{YAXVla+b4ZFW4D>5ri!#dKE1*i{@N4JR>@RA-b9<0?q=1>xBz43iVh5Vvw8c zob{_gQ;MuNqRW8baTCtXg(7(m8t$un_JvfUkIJ~GvgHx1VQLTdLB&=l1U;)SjDHCK zx}*HzQIPs+#4RaR27e@B7Deem+K-&MZV&&Gs5yhVcq!yFu9k6KW)c}&CaUh#bOMdZ zN{7#bZjpkM1ZRKryYx~S-OI1^qT>O^Bqy5G)6({3>Di^?CXXZ1zU`lNCr%&C$TNR8M*z zrIj?lG^v_4(Zwlr3RATZ!uO4u?CdLv+v26XAO|kmph9idy*KgdiIE997;MzC7e$D_ zG&2A#Uqdn%jET3t+CQSyuXC^>)v5rQh;0Zzhc>%1B%POCyLLlV&ps5WYyQfo%~M$iK$9ec`xX%4E=XXrYaYbEedLX8m~zLsFBnEv#o-KWU1DEi4uhvWGWfEq zXi90$n}?Ui0cG>h2=NzDAE81P`8o(?L=12pzex{ONI6`tlryknW#=*z5M=OM>Avp? z2~V0=)BR6u0Iz_xbyNCjJQzXW!&G?jr{xtL(DkwodAX4NWNX%BLBNRsNkF#0=U7#@ zh!e7sWM;bZ0AkUY0IgU>qE(97=2x)k4=&SvF|yq6Go--!JEr3LmWlUnt0LS}kdwwg z9gzjpSO=ko4{3ubPt>|M3gp0)e2beK3V|*LqpZpLY>dj9>|q7S&XrtSjMN0{@V>nk z+{cEH#O)O6h(vu4&r`OWGyYWk^YNAE1vmnlR_@`s*S_Pnmggn7UP-dxYw5}~!{!x? z@tTGjzQg`oaB;pGFDBNYA@&;+pwkXr!b@uSGrU(# zFFInXo;@9Kp>1qdk9xTi>rP*Pim_PtQ@1Ls2aj1+lGDfLw)t|wXKG>{`C#6cq;3ne zt`z*K1KHl>i!ZdxK`t)}qbJs)L8rlE#v~;Ms#u?8QH%FD)3VqKsjZg@qWK4u7uYtq z-Dv?th$JrHEHU;F6&Ns*Qt5y-5IDH#islYAWjm=anyEMqo3j|muV#KV1-iTY)yzh2@vC8 zzHTd7{dO-CNpwzg-w&wUrZRhRS5R>L*)gSi;>ipTUvjiQM)w zZQbhAPMV|#Zjv#< zxyNZ%U8XAx#Q+PN0*!#9$9LDuc0viCz&T2q9EboZd@31ZgG&W&Kx@-^KP5q@*wD~1 ztF1xy8WS;F+1wFzH!kYYt`eUEK6pvlgt~` zIRCIPVjaSHoO&EQdBz(U=2zlhSt}KATUwS(w`eNz4)HGn3;k;>0FRPGKSPtt;PZW>&qGC-+UebC__Cy#%0 zPryvoKc9hkCI)oNM2DR-PcPUFkf7h|iM}Hrs%+rDUIL6X6*_L^cQdk&^g1)8X!{79 z$zvMI=z3D5XbUKtJcuF_71^T*5Q^(-ULeOe+BB5axPQ{L@LTS|7>UyOdxXQ`Ckvtv z1)zo(ka@Cz7#*mIkRV9t}K`xiQaKJEktW*X?Jy-ikG2siH z63#8q-!LBGDUhr#=l2wq9=;(rO19gkHXnXZyoVcH5z^gK1@a9$((G7|dIgi=K^m%B z*%f4X8(`S_`^oVji=kBf%y8p3UdpX){;2!++Vb&aH$qH*$%^||irP|QFoP3j$Mnqt zJ)MDC!^<=PvD@}tW9YpUu1gc698U4gU*xN}Sd9_&I92T=`S6XVSq~WkW(_yUVeJt~ zDccGEqPjoi;o}KfWx2zO)6@x9eBh&cbq^G(lT$-4w>Q7%7{we7Ewi56Vw42TZGeue z;Gj7sU@vb)m}2V>%^iW^oYtO6lw53lbWI)|!v{M8%kv?Bm+XY$kO~wv1O_u1=z(J5 z+8Ujxv(=32n1J$VKY98$e6)l8kv#JY%qoGs?#e&420^wnpgFtN7Gv56%1)cCfwZ%e z4pFu)Pd=~i>iY?-1*&UgrMpVU7`KvXNm{9oKqm=)aK~7;uyocqoEH!7rBV+xD&WtV znlEbRXl*_=7*8_h0uZhE&9WgH$Z6S#kRyt9Bh%r~#~fK3E^l>CPc!Eewt__wm&4t) zN9ic;9o`$mVO5E6!lj!NXb?cnd1Xuf@7ObxodET~3jN^9(o&GSb&=1%&O66mRCZ55 z2ZX0i$&^^S8jxYzWTk{9J3_XgtL zX>$=pKk2P*o zgNzGeT%Oa$9Gya9AGC^Hjq}06BcuXm4!;niV)NC2->#S2MniI4zz{IqFq(bulu5~D zH9Y~k12Xkr?ib(c2%&7TB90xK0Us_ZYj`N|A@~@7+kSpn%OM@#w*{nfmK6J% zDSJ&>P1*-2KV%r*-9`*k)Wjafw2zB>->ah2T*UJXzs=n$CB9$tzCwJp-z{It%aAv3 z0t4&|yJ3dDKxa~XpsextWnXV!-wfNt%xa4bBDk(%uDw^O3LU6tx2=QMhDfGBuoVSO zvR-z-VcH)r7`$|GxQ zWCC(3Rc#KrfQ4o>f>l7bg%-&DY}DkOT=|)xeOoi%esfLra$dVf$ebwuip|hRHK^L1 zTpE9!X3^P})bKRN944h(EfR|z7_csn!kWw5NR<&G5%*&LgqK@kW)jHyl(+d^kYKPw z$V*Z*{rK*jEp~W~BP^ej9|J8fCkM68hOXnhZ^42z+kz3;g;UKqmWPBm_vtznWrskF zH5j)yD;>Dl02V7Sv7-HFaXkZ&(aJfU##1y1E%Se&+Cq6uNMFrOh;i zE_{PK!Fp{rZx`$ak*0bbP`b;}nk%|Cx9D(U%Ozetr9A`VQA>c^FL)g9aa z87Qicsxm;)>%jWOib0A*gzC@)`{aXOL2ei}jAkDc7Dbt@>Ug47D4YpVdkO5u|IG{N zrgzXk?28F~X%kx9((}7kT zh&N9(`{!!{%gdbJfZ*GEQuloGd|sV#Eo@Do&f z5?14O>Ue4;?_(cmUkC;yg2Z(#gYk<7KE~|N7zE0WG|QL9z-nQG&Q9f5s_BDpSN$BS zc~)etCXSxkh0%6d3qDjFB*rpt){9bm)Q6dM@_yK4uk2Q3<(zf2)DKc>%HGOrH5RS# zgWH4jnKJJPEuzY6%FaoW6zzBgn?+J%zckU$^1H^=?8`GK!+@H8Nox~cW?r70d*j|| z7yc1B85@PeZ`iLx8CW?f&$=J~H7nQH#WJ5xP6R$L{PH}{rA7IEGqYFVng~tIB~j{f zO0r5XgQo9syWh*9$%*V6g*UEYQN%?Kq31u!GeHqGoaXYMKb?nizHj<(Xg8Gm9#?XY zo;$T{(PUIQe#)IwTF|LCJ0r0@^qI zOXE(iPM(a$j^8(dhYCpAh6v(T7*lk68MshB_!#6!li!IY%ME8-bj)tOLoppVyXxhkP0x5`hE*-a0$B}h;r?EE# z{b}2<(`*AeB(IuZPaDrP%37tG=Y*}7wneLNh|qgD=2vQ`pDqD{0(fl)`aFLrM?iEN z3-VM`-$*s@Zi{xbHW-hioKayC#aLqcPqeHghDIdbEciBagtTU)S|I%*VbVMy2WT0V z>O(>VTyP+^dWXMvCG01cRl)F~Ah(x8b@0~rj8lz4)fZgH2BbT`85TXLIe+6`dj$A- zq{e0>54aMB-lwtWgWAMS7%Kn3-)rs;9xpZl;2mQHu5Wnz?>w_6OV0@yYI)A(Py2>& ze(afrGwVa7jZ64^X1YZ@Iy{Yiw_G8aiBWp@`JB4-wET84te!Hk!x^d|B~&bxo07mp zB?TY~c}`Skks;LgM+i^54TdFsO{yvGPG$e~5#?{u_R2ZYq1 zrlaf76GsiDs1O=5Q5>zLeTX@qoW$VWX&hyeuR<?ZBDp&VSlT0T2Jk{pmvntyve|{ruyd!<9#IR> zKAsb52E`-I$c7azW%#|mY2Rq%8%0G!Dap^QNV-NDT}N$R<&grMDKKx;VCe6u+))+7OYWECO1NV`g#nc|a3f@;&z=sTF~{=5&WZPDmVB>_;og zJ$*Tgy*3zRKl=*e#X8nop`Q?GeJ^m~5@tDe6_wvA*A@YpX6sO3rbcyyK8_?Q>?P6 zKmD%x4XFk7S5Pde{d;TeJ(4kk1FQ#jOtqYx`hD~f zhA+$?8>Y3wBx6_`-OrE>lnP+12%%2Owv<)m~&V zfF*|Q?~}=Y*_~0~W*mW{LnG=bfA?jsagif`Vxms*(&|6J_>F&sBbM*t6+jMT-1^~9 zwcW8yRk)wyidoHsv4QU0Due}>G(zWQE6ju=U2Q4lpn6oy4sxn*KxWV2|3 z;>O~CvPOnQFmfVoIKfB^YDEqLLBF1X`pln49SKX{Y`Dx7&;j)2{}*+hSC@D=)}|Gt z#|*W58Iv%FVH)jzawsf-9dCgS{?*<`nj-nmXgBth{Q#9+?xS=dh%%jJoIn=_fJ09N z!ks);xSADXGK+dV_t{YG{iGq94VXjD}S^Ntc?faUXtUrxIgu?v3(D}b-Q{RqI zxZK#{A_05_{M``~KeyndNZ1Am+gLtL)vs12BStic^g!4xk3M1j;Ab)OY7e+Nw1dBL zA}om9^)r3|xv#~T1=!aPf$z&jS9J)EH|a_4Xrg_}kz!C!uiG752tCoGCoCiMAJ7F2 z!WG6s;#xb)4$elr!yJmU*^i~4^H;;u1$gAVH*LdpoHjv2xkO=7om(QEW$Th9 z_5&0_75>{V035SR7}A;Fh?6V`$QQYNodW^6Fd&#Ir9Dgj(h{o2s<v0V1&z)yYZBO?cfT<1~;O#tVjz}{k1a*Pd!gO^VE8l8CeB!H6xJKf3W$XvW z9wRS_Q_*FQj0!FCkJe7ocTG{;R`TB8BRIp;NP&S34AKmGReW-YW}L0bgA1okMUYKtaip< z!6Hcl9D?W?oZsswIvt-TCBxLKcwk55iFozZgiO&1WMy@YGd*!oQZB#o>=z^d zYFL;RTV$E$a*PZ4l$*Om2iF0DyrroTXP$6j~i zhS|6g*uFc=dIDd(eIt0~zZ7DIzR$lAvSPc9`>FfH@i1$A)L zNl6dAD|1$x*OI5bnPq;ak*M)L2LlSV1X>nBM^|_wdbNT7Gvrscagw{0f{Nz8b7dC* zhEu7q!=mbe$LGFjuD)v?21h!+d9naavugFiF|Mn{r{HU>0;(v$IxDjlBOw4$bYvROPZeHKQ{UskDHYG|lW(f}J@&}`+QBzwXQL&Um43N9Z zMi*``j=m}XSCac=$@7HLcL3)lA$IU=)kmu~ij8(kwVt<$+M9f}A(}*03ZAQ_+-vg7 zPyI(Oza0+tBbwiJu5SKC2O_x##61ELlpaToK^DKv^DZN25k?WrIS>j|?3hyG%p z|G7);KGZv0Oa>*$%Q_T*jV%L@+U>gW>sGNi_RY>}v}Z!Nb*XqXUyy5L`^y~!mOpAYo~98Oie5|vEAcWqEP@QDoTf^yU!+wFT#~SJKgX zOf*CKxF%V^^~t)^^akwsMCBpUzsnZWbe{oGpNYx-DEQoDXV^Z64z!uMCO}7{_t>v} zw}TmuxY?tn{gHL3?A|ftaM%q9GT1(^nu-*) z*4|e)3mMgQZkQ<>838(oc4BD9iPl*2L&VY~aSO^diJ#!v9OBD_j@-d6G>CzUA`JAa zg%cJLgpz3I<9ks*!?Pf4ml%RERJvMU4W*-M$3=g__u)!75VSiXwp#g1!r1dqQSM9` zc_`C0RXq*@s+}k0yR%WbG@7Y(lpdh0=sKNsHCNK#<3avXZao_E{5tbwSX4A^6-JA4 zFJx_O(F{)Z)up%&;Lj)SOM*5gwnAfJ70!ZG^6+*z>Op+e zR@#RjE=5nu?^DWuLdHPGj+i8Kpb;WO^whrWne`{#)L%??ew!wbC7&UM0XBd`9NDRH z84191>lHoV2n5N+wHGeAKX#Bp_ER;38k8nsl@bV+j& zL5ajRoMt~Qc&Ur?f|%3&G;;9H>|#g8nV>zymZpgU&+mO?{Aqk7`;WE{o%$zIKg zC?e=3+F>;w{EN-y4$&kKq)rW{CP@O^Ve9I0Y^eaSemjjOhVSU?;@;s{o4~P#lOU&L z%5(>BJunq?^{Db9BWa#~LmtR)zBdO7>NVdej>(7VM{+Asw$Wz|8cjLWgS8S((KWxU zw->0`C+JFo`-`1LaB6PTM(R5Sh=T%33wT5PwH3L!<(&V$rZ_xCdrgD>;(bI$KS{+_ z0^vzKO>rs=K;~e)kaAGBW5VyDYHoe%OY(~;g+JZ`4k%Hv{5^??aBrKkad3m2I-1;g z6G#?q_-Bs9{l3mlYr)ViP}#>Dmqb++r}BOyX2exWiu9&svFC6nHt`nz-E^xg(fwwR z@Vx$@c#_aOz6vS`j!DbgLNaZ{x7@NcWkQ7%UHchB%^r&hw@EM%cBd)lW0LXo=6h>x zXP(c_>J*&2>B)QEO;V);%{zngNC$@5HV2@cT{l}11 z^FUied&Y8>qS$je9Q3nBv}OS6HYzj48OwE=kxoMNxqt84xc{E8TU$Z18}i!@t?6&^ zioG;-=KHsUc=<3wwF<*FZ+pN5?V?3{(V#1+MG5;GO{D+pjN`E&IDn811nJn)DjAgK zRLopy91O#3GUkgb`sbwuecMAG#@rd*w2Lh#$F?EU7>)4%^WJm&E#ZUMi3ew1h%)9L zdpr1lzI`*Yy@)iaitKBi=kwmpCY0Dj z(Z0;9zeqlRcxX(JJX`uj52^@-daIdHN>nUXN7s=Dd<;4yp-E??mPyt!JcRH)< zR02F4$TK)fGe`YPdt~zlA+J{%!8kM)iel%DO^^AYxmcBUF1gV1Q+knSR#W|_hkff0lLZn&qD5M*+)_2Rr$Spi*&L-A- zDDi00!c@TAhW9PzBcHf1BmY<4xYlbDv%mbdQQLe@@Rl?0$7n*R$49&M7@;+lOrLsB_>wy|M%6C^bo21fq!B(+QX-_4n zOUR0EVY_GED;G7Q9L-K{$j1-8h_{Mhnn?s->@9NAqwUh-!{56?EZ#Q@DqHldHgNUp zC|^F|(w?UVZM-g8!dCiw>oc)C{z8)BK{X~=Y*tFZ{R1>P=O;Ph&RdXhvp6RlFyk^GUz}cxPlHNphE61o+%0lA3@#5^P=pyK&k+aE(Cj!Ix#S$W^Am6 zr)eg|0*d4^fuWfu^ZFLsWWKVEZlrvU6(oP)t!H{th(&C>2pp?3g$vwxuOoQsjeHJj zPHyltDz3#g7AyZt5yv~_5(jQXOQIxy6E)fDTEl`*hlQ`M?Xh70tQpN{y&3l zZfo{!&YRYkNmOhCMdtIbxmveMZ9_wsy%9&_)<)Xn_B@(K7SK3n8XcMn6w ztDXuFWT1XKx{00p?Ir%4%a@a?D&dXbv+p}jeOA{#sF>Q9 zf2ZlSHgvD|6&`1nalDIV@r+Mv68a&lPLyrdP2l+b z-l7sL%c2E$y3t%UQ!VPun%;vx;r^9J=GuJ;%(?$aK9F8ZB<;T!zd&whJG_1*W}gQG zvtjon4H_DUjxD*&KN8idg?;#rP8RUiz--5b1XuC$hCtD{e{#C^uLKsrE?J*-nVah( zcIg~?V?A6@_@WBT3zTMq!im4Tb}XqnX_@=F9s21B-!z%@$WnRRLjC8c=2SFB&;s&ucb z-7hsFB9ff(O`^Kbb1o}}gFaBLJygc4DQ>f@bY%g){@)`c*56cECBL=wFKV2xs06Ca z_4ZdR)v3giN-@0QabmyA#uWdQ=F$AQbOP8O>*JY{=We>W&yWc+T@`X4q`(=(?Z$NP1Z|N^|m=*Mw`K4&<+> zBIJIaS$-D)RTm69o+&3Hzw*xX-Ubu4O?}z`gE-V^fT)AY2ATL(N^?tk;!KiI_f~3c zz?8HRb??0dSf4PQ2M2BU)ngXAT9VDw^_PUYAFjLOJ-^s5LDMq>=}Q`Bu9sw%?nY^p zVjf|AK@W>tHZG<|kH?*x^y%IV?L_6Vb+^XetBfk`G%v{5Lfsj4izP%~fQlVJE1>pp z#Pk|>kWN=~$GpPx1mMZ$f|774Z^POGB~)N=OsX zSU#80G^o)xk4YQn#9!*a^hyQr_4GF0x{gpQkKG6uIAbeC z^TccdrY6y75x_ec^%jm45LKsM@8?nM%kUVueCYjMC6pvc7go|)c$c3@v9GtRZ&N&> z43a_-R&l@fQ+2hil?ulv9V4$PcmA&keHE27U$%g9E#7t6k<|tJE8lLX=pSoQ=IE{x zCFAbE7ReEJ@RtF#q(R6wJOd{aCT-D{nw9C2$}=N7VR z2oVyo`UX;-*Yry6?gdli=nz0l=;@$`muVeDIg$i~QfZRS>5O~`VG}k6GEH9`#EY-m zU%&J{f$j^sOQ=HBL%TyI94BD}(>uansK#cC%6sJ0J zaTl4Gb4L8%Tb0sDdai*OE$TEi$#nsCI{=i`oRnY)6XObf zFgH|=D&mfBE4PQwehna7#g_Oy&Mm~m@`G7m9HHvXY zKF*gC`&2~rSPVxiTKeSiBbhhC2qg2#K9+sP_xnpf<0#mSJ3M^ z&Q9ykcFh5tBeaTM$O3Qd)!xT8{T1O^q0jQ@7(-s_8)Q?q26H%%wJXur^u9uG@}}9J z$fF!b&>x~A+WWokN++Ik=;UvE$eah^=s87psC^-1k3FVoJQ*zo7d9n<;aHqpzp^Nn1C8h*Pli(gG>>WNBM(I zj=EnM#St`QS)_`2)Xj(`9{sxUdx)1@U<_40_v5hv`!FdQW2ICt&%ZwORkL;{QbN~& zb!=hDxDOhrE7ltTUaxzO)vsV9PB~?JPhOPu1)E7VofILRU(HJ*>YRZ{?h`a_oK(E5 z&oaFHK9uiR?&SU1O=yFQ$ur0)&R|d-Zhyfy%=?lswEJJsf4ENkVcVx{4FZyoZ@pTP z_(K4&h&B_9v~s{(;sZjn$QfT-j?`R{da`uz`)PRY+s*h!tV3eZ&Q7~UQ= z$@8FMAUY)NLNwlx)h;P*r8Joo)*I9K^x3ID`GFgnfY^56#j{t<05f!S;pC#&=P00c zs*BAtc>!gf-ze9-gM?a3Iwub0;(Z)CoS{#Num4d%OA3~T6p1wu!u|b-fKF=2aJ6Ub z?uNQ6YvHe}^KR_Mq8Y!_^fVSW zZ}Y_gif`LV-?IhSA;xk3k_q^Vv3qVkqr1lDz9T>U)^N5AvZfKkFM)$lHb8(C3a$PL z_eQ={tKIlGTt9#wfk2o|t?6&Cy4Af8#fF;i=nYUiIcWYT*ty|ixmj|r=2yt5Oby*r z;!lJ`ZT|Pr><@Z@SQbszQFwq%r}NIoI*{I|rbi`n0J4z$D{j74|1E0M!xsYFW#gVZUGDON3MN;tC$h4`&?+GR5#`kyq#-crS7Smmn#EU)QU++ zvHs_L^o}gHx>cio$Cq`O8-&8iY?G#D66M@7*=rli25Wapg)F%Ex2(|%;TG>a=1MWQ z)7nRhqpaIij(jv6e%guFS3eE0SG(+@TewLV{1jIyXsaUrZTcpvvdqJHjSSk#Msgyn zBfjar@kc|F3E-+STQz?0Ff<4VU9k2YR(irl10)rIzv?MuzqA_8O;@|(!tst0Kpk*h%m;`? ztdsYZ*a}PkYk|4=nq{>NJ*&57!k7GoUZC12@8sb?>vP!!E|ei{(B2klEX^VRmsTeL zqh;B$!YsXFKg{9fGRy4Fd8`pv829C#A1j@Dyk>kC>(7Ex9KY$6-d2L8_l37y9StDB z5C2i5HZL>k&_aJ}z7e)^PDtA}^<2;Jx~*&Wa3%IkCmL%P1Vlbol6sODY=h=k*;;h@ zezNmRL?G@^BdUWLSncyfMSUIGbDUw}@+)M>PLWp;T4#J#|hs1Ftca(YP`?YzooWtS^xJ_Z6WlgIhE7P#BbItI`EGj6Q9zla~e zl`@3r%H2A3y*OJ%m zUC+qz3_V*o&{!*Bz5Ux*Z;`7!x?-ru(}Vxq?N{j<_y)sl!;=-DAC|2B9X0sI35sv4 zEcaMyi>EH_Vv#Hh{>LPEa81IvztT`C-|o_)8fLF|^}VX+=70C;I3C?)5-IUusfG4z z>%XaTrp6cKG1p!Qw!;4{F=xvA1qWfW3a+5&T=X+OwuO7w*4L^|iI^nz0yajX)ZUJs zS!XvF1*k{By2Qd^9phr^zS>v9W1&XXW!l0 z1hp}TJQDRR&q>)2^m!j{$d<=}Z5oM6L6bz&uMMEap7*iNy1NT_ zB3%p~;Nk;@^Ch}Np$Dj$!Su%ouib}sTE(P>(cjkM@!@$xUvN~)$Bar{?7mY zB6gw@i;4Fiayn|yq412iv&u<4az?kniY3aKxAnRaQ@>%^DlHsB6EeJ_^hW$s4I&9_ zwBzUpZSHS%=eoNIfjz1^jDq{Ia z?wCR7X3KJM#?ubt;qw9$XjEodaSaD-KDRsDvE5zJ3oxwG(N)0t-}r;-RLZXM;6jfT z5VRzAM5NRlGIgZM?>)NNC%pjh<$rRi<0dCwR4o{PQYbIp1tf2-^U5#0;Q{B|4vv{W z*kxYARd-am9L1+P*K82dyN9&yALng0kL4H9=nt0=Eyxq}(Z%WBCs8mozNdV~*6?bs zuZIY&deL;DNwBP1)p8!?*eB7IxVjYfx(BHTAfdj66c;Yh=U&=;Oon2;D8GYjYpOxT z&uxHFD{1T#AVWXkTM4~n+Xuw(&De?ZfX2+Os-n}Y?NM!|@y@nEqC_In)k1O5tZpCP zH|y`XbrUP2hLG-`54v1Oa&!7`LC#s_$EQ8aYrwAN(iaARN*n>9;-|{iHkOyB{uUIdOMN0-Z`Y zjB6rgUg`gVt{;KTYp`>^nRDrbGe_wOZs78}8gUSlcL)UPIwo$hdZXg(@}^5_$Jkjh zc81{RnO)H(>^7OPUYUQ25U&Q&>ec>Kn#vTQzt{+N<_71I*jb`I*+4N8L6-il&0Mua zyk&)c03q_5_eu=TrG_`yqfYGI*dF9NxVT^qgX}sW7_=(k;UmgVo@G2jRb-5t*;!Jv z;RYA&Hy2Cr*k+=roor<7{E*!HMoz}zoCU0S%u+idjUp^GCBvoFb|fuvry;v*SN^%- zdtT&c)p`CXjL$HF6|nljgGUP{ghmgGS~Q?Ju2sj$P%B~l7TyB_LR>i51OuZZ=Bb6? z@K`A28O+_qq5#%BC&n^BiHuib*=*gAjtdBnbrd0(g&~}q<#=jn$ai3COYzK{t;@$- zXW9JSsVU}0qVH`fml4+IUM`=ys)sljv|EU8Qg4HHOVg0R@0b&WcG(OZ$c5pSflg9B z{p54-p-vu0Mpb4Syw88MfhdjzZR|=Ym96 ziGfnOeqRMgxlvg}2Ncc7R9`_LU<6+YCjVMnt>|~8xSH9s*z=a3lo|gwA5sXnz{$A% zHd)10cZXN!5SA4LBC|D@r;rUpMcK~gGC(h@Ob=VH$V*iw30vg)_t5+-J&0W!wbWjv zMWv9_RPV`^!{`y742Gv6DLuuJ?<&P}tByrm=aLxgnGsPTu~Vb`P%kF&fhZHi;~%kf zw`K{2qdY2d&N8xX@qI;FDP24_m0h{fxsl!8LQtF9VT0o0vsrSfV@s6bT4e-#ES`-2 zy_E9|^oNvk23LgKZhn~gkA~&IB)4k+U%E#NPN(V!(L}D|!idWMMmUe$H*`Xn?4wat zjjdM7Jx#_h-}XwwpJSI{@7SNCL_3Ap!IY`e+_iNGL1Z*f{InZPpG zs}3R%eoN<^(QUXSolt8Q3rNdT3dfA>yt{npl$Ql_kO zBLR;z#c`F`KmcRb06dRofjbM~%09(eMs?4ZAdRt6ZyR(ZW2~)7>`L8WC1YhuN;k81 zs49{_5%MUtkB^Yeip*B{o)k9PbsJH9Di>vOLCaL|JZ> zO>IMowpNd%StMS1xpWOWkOylPPM$ov1krztK2ixOJ-!zI2!x+-Zb=7}-DK87sf}t3 z+7*g=lb&00(EIa@4m4Vy)KE^EcDq`6QtGOYT7eA zZRyK>*dhf?F4;%1xNxs=RwYDP|D_iL%#^w;6vx3p@+U6FoJ(TM7(p(w@zk$oTSnIY zvuEw*A5y)}ob$(kLPiL2Hy-R3;G2vfO5Oh1o;k|RUBaPtZc||(?{Z*pe+?+htJ)qS z24_H38L>fW`-INSRG+@O3j}d|wzE4vo{eP%-j)};T{wCEx8u`A%`UMxd%LxqQ<~@4 zGkrKY^-+v!EO9G~8n!8BebVnL-a}+M`^xf=7?IRjbZPmT$ix`43bkE^V)~oTrZ@R_ z%8nYMxCwwl9$Hj{SaG$*MP}8KhH{i55#KOVUF&pXG&GWkn-Kk)Q!d_w(aEiYNh17w zHS?};K{)Vg6>PLx#AD;JI2?Ib_1agwJ zUQd=s6Ho23;KWUP-c~MX#iH#Gy7Q3fx`UWh_`=?H*%3Y$@A31>F`otDn)AT-oa~5( zGD`J17)NgB9}em_6m+Q7R)ti3F#qH7zZynNATgd^MnSNUiA+{Ycn)U?=EW#TPO^D~ z2yN@>s=mlmZRLbrj;3@7`FnEpX1yLRb~#8P+3zPrI%Q&i>6gZRQX?KzrC*vP?bvwC zf#d0YV9z*wBn$BdhvvK_59lxh4*MH^nVHr*=^f+E{I!HbM;F&D({n)5h(b3pu$D=j zsWJH!_*v=ajNZV$lbHqm5cskzseih?-rtic+RIb&f^-HM=ioFAoS zeXF4?OkR%)hVAmK)Dh+M(CxkN@M0v6FkS;Ei>eN1i286%^aa)w?~Ox`B;jPhjT4n* zV2NSo6JUj8OV{rvt9}<5bQ6Tw#uKMsnh)?7>bxv=3jvAi9*x*Y0JcPWs?jjptML38 z4K~SHQkHeCA`bPczVYo==ecn7p@-^KB3i-uE@Do*F>T_sHsq$*yj(4m^N@Goy%3NB zG}X2tgb%bgwa!vW`3DGW-g@yms(dhyG-knDhYbWO8a52bE;BHG^{cA6GPqN}Ql+@G7Y6Jv*0 zMw1#NBiTqJ3#0HpYbBBW(RIhsAeULR`){0LKK0%Q6ZjI|h`X2Rn6Q%oMd#GZ1=WwL z93)B7sYB)6=x_8gbQT!kxTmKyU|0g)9UUTB1szK~y}-^6NosG{Iq{JgO(rnZxs*#m zix6HNu|AgRu}lE!TiT4y=~gs^Tfyo{j37LXpKT7D%3%x<^U>rg9o4R1vEh8lF2-#x~g7m={_A9y1{>z6({z1SVKDJKoHa_L*@FX&PO2oB9_E5MJp26=`tb)zs;>ak~a=P{oW-PxtH4 zee&VrKE4K?JVnM6V|avga8w5+CbD#f#u8#Jo?&2p)@qMSMaku|?!5QU#3#y1A<6td zd%bRm67?l9`yDT;6-eQq=}#f5NR}5IdWIN>W?{-T2l3wcwcl59h(>R@-x>}2V6;^- zqwnag^vv9#by|AiJ7D9anejvw(d%>qyHhE5!!xvq^U^B~K=S2zw(JitlJ_G4c@ukS z#-V0x@_VC<`Ip7DxEM#h2k#-T?^Gd(S8Tjww4=!XA3b9Af72c!_GiTS%}x=>O994@ zM*7P1sK+`dWyot`bmlMw|GE5w5B%4bnj`n*$5$PYS4zB2D_M#x>-B#@27(9-YlB_W zSQc>QfMqSF>$m3N+0w zHM>7ZuUlQ_#KI&6^V=*04N)XrXPj9gqNdC(M0beGNA)-EL3Rh#IGdk#nmebv)^*WAJ?NXKKm@PeidXxVHxffZ zH@+LPuDq59v518(^OE!7TELQx_O=iAZ}V8#ahJJr#xz3dGQkRI2CP4)3GlPM?F+aR z^%pZ5#&XWHY;J)cfRmyEr_(i)Mf}!9P5;SnN7|l`2#qaBI@w7rs%uoWN zFvg4uuzq5WSPQ%dVC|6NVXC~#R{%*sw!h>1Pydn~@2c6v9uY^@aBXtivACMQZzqzQ zq;0v9xQY$Q6D$r`{#0o9ayS#j#)Ly_=Q&Tz{wvY%%t7UfaD6N~ZGSXJwo`s)QSZ^~ zGQ^DLGmWIJ+P)og!iX*1Ff%ais4i=<0^5BC^THMkzo20F9d#7^n>B6yTQ%_E)2y?&2?$)N~?k3t7xmNkPJ09<}^ zXR_KeYp9$A+gkr$PCtRTG_T@IR;2rdP->UuO{QFElPc-bk>5Is)~%sg^{_l!%osz< z40vP^jbPchJQ`R+Cf_EVQ3b^HT$bqlFX}0og|I0!-hl_fU+~tSM8*(2gu)E5L4B*Q z`Er?dlr$qn7yUXw=pk(6ZZKZGyt~GHQ=0JnL9LgP{5-Vj5yR%l?Ipl4T1Q`F@x4dS zyQM+u$1qq=NdqeI*~puTb95?8=6;{NWpc_VskqN*x0hNEGn_xroXILYuZUiCJH*<4 zFCOfYGkAJ)Kw2_LC*`F}rsI+F#Yc{^S=cbb{M<(`IZ>DHUPaHF;eWh)G;5g4wgjc3 zAqP8(E=g{LuNAr=TW>PFir7uziL~v`zz?)R%B34IYNg*>91ZXG_A@u~n#tuy5S~YoxnT$ zS0a8V--Vc@z{wNiHU1jA+WXD^JNB-*KHIc} zzlYA0x5#??hq$(mcz_dZDvM8RKIo(ezRn5c)&sR;rX&cQ@D}XQW^JqEe*G&EM=!f? zHbb%PO2XkYT|>du=O%Yk3Gqu?zQ85fVcAWl#G$RFW$6R06{dcUT{Ka$ZESfa$w%B1 ztN)@=eHHRfn-|46^6y9Ub zv&RMHYUEx<5{1~rzD!u(Hhkq%`qN)W>`4ct&vp%`XP0}27`jG(dlhIJX$62lSmFy! zpP~D}ECYNMPQ{>Tt4>q0ARaHE0d3U!Dk;ybhOE*xHgFWVto1k0!_19#7e>8j7Yy{+ z0Z?q$zouq2`f_p<|D**TQPIF7YH~LXWPgik@?ilJPQbD_ywa6=BIBcdKmG84@9rWH z`1+h7RBEc@GSRU_WCoE3{HRjB0)%q_LaN;^8!{^)`Tf_u_)c8lwowfX|PbS zUXbj`4R`{>=a#1hj^GbsbQQTdeqFD?$P4P4$vpSNQNPFh7g@=q!U?-I0Sw0iH}UMi z%W)uzd`=Q-7%Dbg>rz-Ozckz;iI3lyB@iSYxBj7+`R>RGw{SdF&pden)7Vdz!wiWn zmA+=)tZ^xf(z~UtE;2|4TC&&E7;N;E%m;+%JHc5KR}P7_FP62u!621>{H_>qQus;_ z1}+#{Kpg8la+2_UlamCsINI4EX9TjsV=v>775Qq%QuJ>spDae3-7{jRxRRkL-Olx= z=AUyz*N2&* znI+A7D^Rg!oXx!>JSob=#Mh$7+c`CxUmh-s+-o$C*cC9~q^Yq=V(|HZoR^PXpg zaO+CRC0BQn`+Mz76eL4q*eTBK(mm3IB%8$X z>xkDV6Gw|B8FS%@(3-0hwZq#(-yNEq(}}}gx6B5 zANTF^e6*nRo_{SblEp={+_yuxAa*l~_yM%tjd$rjVCn!H7^ggWyQhuafCzed?TuVS z;_cPp4O}Qj_tp{J8P_QFovMJG@}PS^c&V!X;8|3K=xqYA0jK}8tVbZvXIoOrIQD(p zh&(s&>AtJ^r@zZDI{#0hdAB{Mo*Jf=$c(G5yUUCh0C4X(y)P*E)bxebJ$Ewh)?WZH zIn(=*-gW@JFSMxJ{yq9x$*Lvpo&EfxPr^HTAsthEp#S>2m=fmEppiw8-^3VNREFs~ z&d++x6rFqEu$W@ho4Xg?2DdqNzYsYAXxJv$H+%@7V#0kv%^fSG>2t+lz2_%3A3np) zA4^x6>-0E;`6wPgnUwW= zF-IL&J2mp`WUj4}4@d*Fdod^QT(V`foVUt~9<@B+yXc~S=`x#mx_zo&*%tEEEk%x} zNJR)c&Jr8A)q@f8U|(M?o@!S&(@Sf^(Ym>PDury0q^R|%Eo+&MOuQn-Pufw_hgK8O z-O#6?ewT&;Jmk^9Do9KnZ{ShGKT`~zMuJm9dWfef-UdiF?z-)F8b+yeVzihBH|tRf zk9q|iQd@@2*U-7l4_r)^4$Wk!XLe@E!FnEMq7PqOsE;;dX~~FABFpf7kIk*OoFGJ2 zLMAr-Fb*uE*d+@?WsU!m(x?Vpm=Rl~c~W2lKh|fKjmoFtpi=!dLblJ~(8I}A5b#XY zW!tZQ+ZvE~FzJFxD|5iS6~|Oq^QD)doFf5<@n5WgM3xKCacRJ#+iQB35B%8LwCXVL z>P`s@6!riZCgp!kV3j~sbc0?S#?wkj~HXq&ow z>@7i-UxH7+!Op5xJaxamY(L*|u0yV^Cq1S+^~ZDR=?`U1M?dF1Q4Xz$f@NA9O@W0( zvF#xY8fSj!y3oW_H(&#K=kutv)ANEZthkSzz8H&Fn7qjMJaO^wZ&j% zTblQ}U4*fI1NoWmd+$?Q`>XwBWF*GXC(wj?&MMsC7wG_Q)f#(Mma`~8ECkh+HbS?) z-4&q(*?*_KiM|h3_8X~_txi;L~FVk5dR+(}>Z*(P6Aa)v4*te|&cCZrew*zOj zZot8|-Fo{q#vDW+L$TMDexRhyu!&Z-Ks{T()*K~@N!A&A&{_sz^eOxSwF?eM5FyMvaN+D@S)t-7`b zfxs2;_x$ewnAT9a%?3Slb7&KnB_Pc-Fc?}NL}AoUs!#uW`U7fPjBfOZ zJou*BJfT9Q$e3MO50;0gnHjvz;Z%Dl_Fo(qI|d&QT1~?eOcr4drbG87JmU9)l>b#D z7j};enOM97X^-+hpw&&8+ecoo;p-f4P$jaK#GSBTIbRcmralMiw(U7U-dc65Buzel zJ5B{~3@eihY8p`Yd0#d-tMI?bSp}f~?~Tb^*Xq+%Q903;|E$vY5TUEvantUa--g;LeR0_7fI~8i z2)5%jT2rj08tX46D&FVRC9fKIn$u%_+<*brH*pT|gxe9?d}Ze(E^V>GWUM)s$6^MQ zpt78IkccWWQ~?jvF`fMG-$hpw+$?^iQaU-dquN+X>W#0hnoS~X$Vn$sKQfoy)3Xs( zf{Q`NmKVP3^6q@2&sTynhGH0Y7>0c5{znDmP}B?H&BLr+eA!gBY_{#MJbB>lN#U$_ zoclGFpprgs^?4D8^j+P~SrEr-%5a1ClOd}(ba$uSk`{I?@?Em8766*4v1 zA%V+)Rx+V-t6L$ywEY~pwANkj++t1DH!Ny5xP>n`jW>#8l6YVmWlV&52}sg&wi%);M`6o4ETvO8gM3|vPRe< zYx|0u*<$~+bcF{uXdud8_b9IzAoZn9sQN~XdC<9``|9!b5+0qeaXzgk^E@LC&g z=qjhMDZP(0skj%W?3~~8Y@sZs7){qtjn2Y~mTZy-Pvoo1B09>)1}+`1*ZrtvDM|_f z2zR4=(~AuKccFUo%~hzYTa_29hp~v>-Co^e$>Z%pQHPBx&5q0le)BAkI31#~O0WfW z8G|NGi$g#-Q+P&^Z(~qFsv>NJFM|C4xkyBBO~2Nl0Dkmi7F1_w+kxr@K;W#>eEZuH zBu+x3)r<|HY8g|y#xQc2%;&olTjnGX3vfAu-Iz5cFUzad?KBL((()&~iRzg0AzXih>>M}noJ%XT|XOD2mfW>+K7Ktiq@g!H2R5<un&{=@;mqX%c} zo(R|y4CTE#lAaO07)ugOr-uNjRe`WQzAu;n8JCCdEg-$6tuNRLmw}n!lJ*U}8o(S9 z5~<}Q70pA#mvv*e&ko9p6qJLUN=H5@)@j3SB@3Mm<#EaA8f@5Bc{MzF^nmOAu)5?Pf6O zly4nDdi_WT#gV%k!0n-R6y!;c7r3X3Y;Q&{j&2;Te}Vqc=Lj8%`hu*I^b{*(;k&M| z=p`Ogu5n(oZrihD(A^c~&{`VU64qC?c2CZK0D?j&FZmZsW21woKq$P?*>*t{Y8Z(vN_OPKOfPo{R)0zh2JHyPnCrA)|Md(%y zFhX_&O$IzJ6HN$a5)yZnU^z#dnEi5k9+XpRBn zs2d3#;nh;|#T8{0hu(q9TV3baC4ENFj%uU_W*k7?Wn1(l7j1y2YDg9w2gj`VU8MOz zb%c<(!I31Why<3GcHB140Y}W^q8nr~_5aNEP6UmE>nyCh94C z4x@OOx3wY&%`Kab%xjEPCUO39P=dcv6z2+qyczD45B(~Q`4iYHUl?bhch@n{jLUR{ zA`y^|$9^_mae58!mO+5*k-3hm>^DU|AnC1E(=u73>pGEo@J)q%vlqB*tS5+Jijc1gW4J4N3>jyL->tYKGeuamvK%lJOz#*m=QXT<*v zdgbCLEPR^OWbCJv;+uZZR=H+`((m^>(toahbmZvdvas*XAc5D;nB9m2&!cPS1$2`0 zG!x6EA9s1(yL@X{zfs~c8#>HNUTZtj`;C_}>ejvbb4gE)46qB)J^PS9m59Ul_Wwp7 zP4cIyme@0#WQd1J=+-CLsoYG)c`@eZP3s@g@QPPEvLZ)mmrZQ^wwg0^I$pu*M`s)1*%g@HuclGNx=V zQ3%a6P*XQAu1gZ^CaswpREK4wA-1|ggpBj`=ocY-$+3fnS1JW^gx$x;>wnG3AlsB`=l3Tj$#+<@RbY`WO4XGtjCdNLa zg))7Ma0Pv6*fY;!XgJ&xC)uRK6C8z%Zww6u-G>}+^;D7Ug$f#1VDgzmr+kRnx%i0! zI2w2`)xd+zxro-b$tfMa3_c+q0iEM}p(PdTVH;3V1hF-gQBqfLM1!6lW zg9QFnpk~uV<1A2$A2|CdBw@jMyLbvnQ)jm9N&CmDUzTnnO=tWS28D+{LHnUsJAV*W zcEmzD{9pyhWZcQtcVfzHIhk4{JE2WXL}#Mv5mE(@Q5HD~PMH$cFlq z-|;L|2Br?G%&w~8t1BX9u1{a*i4)03cDsgorSR2Pk+|r1U?}Qwj=at0Io(;yW}~10 z;e6=W=AI-3Gdr~p35}A?nD&ValM zEc}KPOtPa(uCuwXdI;wHDYyCXiU`>p`ZYZ!!VmeJ!~49>J+=X$fbZHKej_1D>TT%K zKt$QkL>0BjNRtjlyVCL6na3#wu0>Bo2;H|VVSy#*H_@={^95{za_REo@tNiEsLV6R zO8wokG7d+)s=Cic(MZD_9q2|dO6&HSovail5KbG{yH!<(UvAY?8YrAp_bM2OZt0N> zZN#-dWsvfKFad(Ktre8{OKY}ldV`8mp9>W{&9e}>c-wLx-(Hff!HB}3nXG%vDShFN zd=$Zu$9%H%QH^Si#bg2PUQD*RfZ@(Z2B9T_akH3sU(S|`FnNO?31OWa;I^=FO8x zrAHu<@txrwn@^?zGJU2vf6v@p?_-?g9j7?5;{RP*@(@GXcqHsaPgw7P)c49mY^PW` z0JOMX1%Z+%XBwNIgCt>ursX>YQtc@BBGxWyu`Ph@O7JF?;UTX z`u0fJJgdTwZHqP41`}2>YJ{v?eJIhT)5tP=fw?GO1h`kMfVlD|7KP9GPBPXvZ7>7L zs)vzG7~E9=r<&B?^fkW99qqd;9gx(6TwR?w7DC1mo{YO|C zs?bu*gR}oTZ?wZ%dZpbm>B!EMZ<4p3tC6MPY;;~{h{W(5jawb%b5i{>K05YLjTWGk z-NlSbU605TpV1u#hHD%1w#?OO9UQV8wkCYlNh|~W(KXKL3;wK4zZ0xGY=r6@AQviY zNU*=Nj#}|f%O?q;OeIVSg!n4-gWsJ2>+zy^^9i84Ax0F-yrX&(5>iXjyx&*+Uh2=; zZuo+dJR+X0UDQsygT|orqn#ENw^2nX5g~t^bQWJUyyB!u~;N7jQwAXmo!Oa-2 z@LvP<#L0^kPmwtomeY#nfsq)V40Z7%i{xb=l(8m1DQQzcCcOK}DZBY4c&o6~geaFm zc?xoF?WNBKMb6+o{FLLQF!8DwyG2zatvoS!Y=hbf8>NOR-qL2hPK~Ym)|M3A2dddC zel2aH)PRrBdJ98sZhu&!@1QM!m>i0}XrR8k?xWCdx`J0vyef>eGVWi4(exuvF z57w%mQkqe1o7UzSG;>GZEm*hIJP|?AY0Vu@Smn68UIHtF@GkkAYc=Rf1aCn5nBeCu zGqJ3i=#D#CJ;@LRC+(;5t!>T|2x>J!8|-sn-f{hhVv4krxGL^8qA5_xuE@X+PXySL z>2l94Dk@RM)iqpHL47K`_;VlkwI)d}#}E#;-K$)>HB!fLK2bfhPoZ;ka&@VAGbmK@ zO#_PCzpLfdk`|50tgZ*s09u*c-LIO>UKaC*Hr8W*FnvqHe;spx>RQ2L2&Un#fI4A2 zml4*FcHy?i+}-zt4|?+(%_~y6H#~g@>QDxufQT(1D>44Y7!#F9;zJ*b44KaMTqq>W zm!p#m+UYGifUiB*#ZI(XXtOd!vO2AOXC;4aBUS71;&f?UqsB@+%FVvDmWG096q>`1 zqn7Lrom)Li*fR3fafe(_mZLhmM*Y#8-sm#s=FB(zK^18{%$Oo zEm}Cjf|Qc~@m;^LZaDlTS726~)OeDKa#Vn2=Q4Qp8)7f~DdX$42r4x&p~IO$l0uBv zPy2>^*c4)+-4EEUCM$CLCGs`UfG4XW&uBFg?HqKmtrIoHfjQ>sy@CNyYY&gWOXUMK z9T35<3D3#bmaDSIHxS=ATxSNE3(?Y}3KQg1z>!li!#r}HdA%rYM#*s7X(cPu&i)g0 z4yM(^+)hHfN4@uZCUs=t474=nCa@hM`shjOl0(2?s7EDy$zs2eW#OW#g12vt6`78_ z%g*?bqS;N2#AiqRf$tK*d0jE?-g;xSd&hm~o+(68GXs)d^tJW%#%4cE2AajLt8AVU z^V874p)%wqoS(t(>zqwv`3=78Xbd|_>mvD<{^@04Z#Yy{rMyC;@nAy8Q>nR zS*t}!o-9ih&t9h&;KhypTox+F=WH$`I={Nj>iP5PYlgar;G6?R@^Es-)+A6DT~vkA z^dnmnT03-qEPt4g?G*oLj5wkB6CW4{2_**|lLi z1JZA^Kb-t%Ht`axg_%I`T2I4}ypEf=Ri(to1U0qa$Y%?&3p2%sj$!P8)zhW@mp~Od z#Mu+s_=tz61C9E^gUYIP_$mLZjl#L|(qC4=mU&`=vpUY&wx`EfwqYA?`Ju-t^dn+^ zC`H`f$40cz7;;gS%yVj%k$7e7*5YkYpAbVqGdR0ZTp7TUt( z1~u3Mo<>!e>s$E8?_lCGekFj>n zS->1≥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

  2. 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 BK>+{& literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/misc/tools/x86_64/mkimage b/local/UEFI/edk2-rk3588-master/misc/tools/x86_64/mkimage new file mode 100755 index 0000000000000000000000000000000000000000..2d07f7264ef0c0dcfbf11be880a77b774ae335c8 GIT binary patch literal 211864 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/misc/uefi_rk3588.its b/local/UEFI/edk2-rk3588-master/misc/uefi_rk3588.its new file mode 100644 index 0000000..1b4ad65 --- /dev/null +++ b/local/UEFI/edk2-rk3588-master/misc/uefi_rk3588.its @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 Rockchip Electronic Co.,Ltd + * + * Simple U-boot fit source file containing ATF/OP-TEE/UEFI/dtb + */ + +/dts-v1/; + +/ { + description = "FIT Image with ATF/OP-TEE/UEFI"; + #address-cells = <1>; + + images { + uboot { + description = "UEFI"; + data = /incbin/("./BL33_AP_UEFI.Fv"); + type = "standalone"; + arch = "arm64"; + os = "U-Boot"; + compression = "none"; + load = <0x00200000>; + hash { + algo = "sha256"; + }; + }; + atf-1 { + description = "ARM Trusted Firmware"; + data = /incbin/("./bl31_0x00040000.bin"); + type = "firmware"; + arch = "arm64"; + os = "arm-trusted-firmware"; + compression = "none"; + load = <0x00040000>; + hash { + algo = "sha256"; + }; + }; + atf-2 { + description = "ARM Trusted Firmware"; + data = /incbin/("./bl31_0x000f0000.bin"); + type = "firmware"; + arch = "arm64"; + os = "arm-trusted-firmware"; + compression = "none"; + load = <0x000f0000>; + hash { + algo = "sha256"; + }; + }; + atf-3 { + description = "ARM Trusted Firmware"; + data = /incbin/("./bl31_0xff100000.bin"); + type = "firmware"; + arch = "arm64"; + os = "arm-trusted-firmware"; + compression = "none"; + load = <0xff100000>; + hash { + algo = "sha256"; + }; + }; + optee { + description = "OP-TEE"; + data = /incbin/("./bl32.bin"); + type = "firmware"; + arch = "arm64"; + os = "op-tee"; + compression = "none"; + load = <0x8400000>; + hash { + algo = "sha256"; + }; + }; + fdt { + description = "UEFI dtb"; + data = /incbin/("./@DEVICE@.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + hash { + algo = "sha256"; + }; + }; + nvdata { + description = "UEFI Non-Volatile Data"; + data-position = <0x006C0000>; /* 0x007C0000 - 0x100000 FIT offset */ + data-size = <0x00030000>; /* NV_VARIABLE_STORE + NV_FTW_WORKING + NV_FTW_SPARE */ + type = "standalone"; + arch = "arm64"; + compression = "none"; + load = <0x007C0000>; + }; + }; + + configurations { + default = "conf"; + conf { + description = "@DEVICE@"; + rollback-index = <0x0>; + firmware = "atf-1"; + loadables = "uboot", "atf-2", "atf-3", "optee", "nvdata"; + fdt = "fdt"; + signature { + algo = "sha256,rsa2048"; + padding = "pss"; + key-name-hint = "dev"; + sign-images = "fdt", "firmware", "loadables"; + }; + }; + }; +}; diff --git a/local/UEFI/orangepi-5plus_UEFI_Release_v0.11.2.img b/local/UEFI/orangepi-5plus_UEFI_Release_v0.11.2.img new file mode 100644 index 0000000000000000000000000000000000000000..68a79e30cd5db2a4b3778cf95c93918846fe9e88 GIT binary patch literal 6915584 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 z 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-minipc-linux.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-blueberry-minipc-linux.dtb new file mode 100644 index 0000000000000000000000000000000000000000..e57b6ad65d272991679efaeb05a307b441748555 GIT binary patch literal 269283 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-hinlink-h88k.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-hinlink-h88k.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c3c7bfb71ca943599b7a7e384caefbe86bbe724a GIT binary patch literal 268895 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 p&K@%Z-5@)$Q_ode*d&0nY`t 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 c=^Eqj|hp+|XQ{>VG8AZy~k2HtRL*EalSxwM%J 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 literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-nanopc-t6.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-nanopc-t6.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c74d7b802c7a0ce11118b1b425d955beb803f5f0 GIT binary patch literal 273254 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%0AAFz*CqejNj~q!lI88#fmtT!VsiOlOVW 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 IdGqrB2mUhPJ^%m! literal 0 HcmV?d00001 diff --git a/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5-itx.dtb b/local/UEFI/edk2-rk3588-master/edk2-rockchip-non-osi/Platform/Rockchip/DeviceTree/rk3588-rock-5-itx.dtb new file mode 100755 index 0000000000000000000000000000000000000000..170b261b203cda5610edc4dc182095c0a7df5dbf GIT binary patch literal 272046 zcmeEv37lkAb^d!bE3-2UsJIo22w{rpWi|}P7B^H7#4!=Kp6aUV?qYf=s=9jyW3X9N zP!!y7OBBRJ5Jen!jb;=yL`88$6Qf{^JN`*TB#DFn?>qP0`|ew6>+S(fxW9gVw{y=q z_ndRjUEZtrZe4xfox$Q`t`CA>d$8!%pCUdM*TJ~f;X-)s7f^nKNyq+&np=eU2&U`B z@}Ae|%afmNXA*z@ z%+sIr%>0)8(|0@%Wej0)tXgbT8cY+{YFv-sRBBZF3guF5^xPg+AlSN7yt-afC3UNi zeva1JW^BXq7e(dL#Fmdl<$XkD%g>3*`~C92jLJ9r-r55aZyrdoBPG*utlG*YWhg247- z3g+4bOr;btVexz*1rsr2VLpN;t5h8> zj8|*b!q`k%j2-2a@p@dpPu8npYkjybSufV=+J{FZ>&0qK{b3kleW;%)S4xG_WW53% zl=|5@5Jn&k!aObsvpEfOGGQtc4$n|Re#G;PBuphP<3j;+=BBf2m63{NXUG$o@I#oh zk}xzo;n?s@n4L+Oh-HUoBnd-%@bExC;l!p!rCu$L(L6oX3J%uKxcbUaWc`K@)}QCq zN0uMezrw5E8i~Wb;@l@PE{+_lA?y zWBi7n+0>}P&sC(YXIHGd(bn}w9iz>$?q*vTxh9A67F!p&Bv*bwlI^Ka*RJKEelOwq^Yz{rW_E$SC&^ zsi*uRDP#Llv&n{Bi27L zSueA#sfWCCXWG6;>{*-1on`C10b*sgbJO@Z=B7%Y<0!&ev2|%3=FYZto({PN3QJ>H zI~gxe8eA&{jp}%9tWp@7j>_Auo6ssZiGN|EHa12a2*k%VO)y;DQz;jO60zru;Fwwmbb0cv%OMcYeP5BL}IyXBwH9MPE`tH z)d>*@Wx5XNt|$EdmoEP$V+525|CH}u3#?_!QT7?6!9%XBW#sMiNPFw&l-{6|0Qd~= zMd7_%n;smS+&x&6Nt~S+GR~HK<#ElW4>zzKLWg|_{~oZ`wmRrT_*H4*RAjUnZ|sGFhr$o(4OymQ{Ww4Lw=z#s8GF*B~bZ(9JlzqC8v z!zXqrcgj_G7rTF8!4eo`9t83Z0HZ851hlg(Zj#l zKFAn0eej1u(OcW)0Xvtm@NTw4=yWV}tA`%}cTx`zbRW9a!@t`;h#t7_9>ht&WVurJ z2E`x2I^xH%ewcFzUl*kX7}xtigP~J<;`*nXG4T_?$LtAbDGziXZtAiRKec@jd*XiD z_pWADHy_{H?V67JqHc8XvlRcn2F$KtKKysPCn$Bv|IaP|HSP(DGamOR_RfC{97Nk^ z=yVKp>yLf`+%g8leja%KyPXrL-)Ias%GJrpkDk~^ZO&_LanMG=&|3ani(0vNWBYdk zx9~2uGc(yUI8q-z0Q)iU=f))Yw0Z1jQ~P7~C3$ASy)QT1KCitVuM4?%x4e-L@(Lb> z_ilKl4-#I-F(#`Mg=$|zMj~~y3RlNxHH1abcDXkY(V#(U%gHC?6aESX37WkYX1+9g zo6!7!X_|ctMYFF7&AZYxmC|S|c;`aFi3*<_3pfk*Yyh|irzQuhJQ0k>*LNjn@<`@>>DAFr z{*#5cLYk5Gg=b&~s4uzKdG!5pZTn(ut9f5SZBMq7efc#Dai#mhGiOvFQ0`sm=z8dUlC+i(p>?ZNkt&eJ@)&I#N$QUA=hNcs+5rdhv$w`h&FIz!;vC zOjDj#_&76oTA6`US!;@u^N`~+11IjENj+fsK~R`Q$AHv&&D*iQMj#>>`eV|vZB9daotJ-65X>U$ z>d!`cz{|fB=~*v-Ndo=~)D3v`*C0LXu_VS#UZJ!nc?7!oA zt`|I;gN$)67DWzUmonxskhXv9GRB-_Wgs$&#vNpYd(yU_lxdeTqPqT9$Y?`CMv?D< zjBsz>_Hzz0qB;MskkO$D8Cn0!xnTg08rXiemC?4X1a&qEe}*P)W#nLdf9CrO`m@6# zyo=KQOop_jyC}n-xiQZ^Tq1Wa9iNLb{889ywNfyl_t*by`I_y$LOKsb3WkelX zJ<<*j_wo;f9X{Nn--#VQ!h@$BdU=s?w8nuQ;+YwMxc+u2V@^MFvco?#89y?Tfyl_N z^TKKwPrx*$@JvO+>+9kr-a1Xz(~Yr8rA7!N54Y}%+PgX=7JF--#Ye?`)8fYgpsaXc z_luv2^d2w&0+9G=lox*2Ay5CwD;(=9l!~QMJO$!(D}zA_0f1obdr(?L`7zWDc=hKQ zln$PL@ljE|(B`@?L04AJq;VkWaxIjgE6e)>O_%G71YOzD9B8_nv*UElO|aH&x*h0u{&eYY6LdS!@BHb~2N}BkX8a=0&|1GT#NGJJ z7{7E4wqC|7$1mv!t&;Bl3zM~4VX8PZRw1~+)6Rp*TBTl`s!og)YLnH8sYYSO=>WBh zNss(tPFcJg@uP9&aUFq+qI94g{Dvnfut5&E^3{M7)S_KbHR!cxUIWcISWFDND z9v`aI(T0I-5f;A@|7`lbnx;?u9MbeHtlNS7HxMH%d9KEPj`S|1v8Y=D9+#YtH2S;b z0$guK8ts<61=stL2EHX&w=TI6X{;5N+!O?lrT_Nv--SE^+e>^Q(r-hG_}`9eFVe*S zAzWWXn)ttj>xW1a|G(klTul7`lfchnt_{&fU@610m*0%yQ@#ANf59Lbrq~~$*YmSTQAapu9jTgm@F0ei;eLj#1qlx{e&aEJo*qErTIMCeJ@zO@;k_f z!OHiYf;bnfIQ8RFzw9-Tr!4+$KmH@0U%Db#TbvbGfm?b^ydO*dGzbp4*sF(LA4}s^ zd`pMp{aku}5T43WXY1b>JoJ)*C@;27J%+Tq%{}sjty%4uHfXz)a{Dj*oZb{2f<$tpbhN6(3EGL!N@c`{$<}?@NCoW0!tPU=Z7M1aoh&a^QP%35=I^Fp%ZS zb<5=v7%v^c9Nqy8Wa;VLPe*tl%a$;{EGY|wWvAhv8~>1MSL0&vJ9NF?_+NGJ838Z$ z)lWw-KM7X-<4ffd7%v^c+#9UA;u^UG#!EXG$aPian{o+^myTc#4_0l#?14*QymSO} zdz)qgLyliNhW&IKx-I6!OuDH#(Wm97+t6(>FJ{tB&5J%QKi!6I zi@7nAZfb7yY5D1PbeqqQnRHY0qfg6Ex1`(KcVcY$A->G61z?M5yE^R&<@h-DY58eG z7xT@svx1f1c%EFec|Yx7IN!9KlbVi;7IR^y+|qMl%W+}&Z|(m$r-J{seZ+j(aUV11 zC;EXFb5v%3Q*%^XABDcO_EGFFeAsbE%O!ryOFNx%j%qg_Vjb0XK3s-5%9{iIbVLht zls5;Tezx_ZSBehjW7RNe(_Ll@#~0=&o0BX%OM z=MhVF+%0AQcn**Af~7d;S&GFI*NIEF;(C_hXX)ukb2CoZaa^xL8s`N|v43BB4brfm zrPu1&fqgDyC&2Y=g8OHNr6=J6E}?Y>(xXU|7M?30F522sY=)NN%tL5>0O_wHO{$0*NEG>d0&nYl=#dg8-lJq%6Y(KuFgL8^-4cNvdI9CB@lXHq?XDbZlOWL17 ze2kXmkzc@bie(oCM|=>dZ9j2t@$lUPUVi@P7BT#CZgCj!FYLL++LH&|-jM02KXyNu zIY+cuuVtQ_q}FS8FWa8JTkE%2t7Xzmt<~m0v&A|slV)n2HW!-B*JznEQ){%j(46;P zU-#V9r`?N3_GIRAyKfeq>mE7=gSp(Etq9EZ=A0!CgEJAY+)o?Z1ue`y_H0G)=-Emf zPjn_CFnYEUhq)>?Hhj6J$BDDk7Hg+W{iW7UcKt?P{Iu&I)^5%<)uwGkmdD}uKaWa16j6&;rwQOP9)3u?(gl|ki7e8#~0S2 zc5NsydRD@81QVT=2#l^1V=&%XiNNSOF%A=*l?aTUmBeAN4%M>{f$`FgAFP|~K7cTO zI)b?>W;wev15XMhOFjuv)qilKib$1qc z;oG@v^W?qu;ITk1@a3l?80-sfe~Vn?-A_j_IKTS9O>zm0mv%6aH}_z?1jb88Fo$=5 z=lBlroD{R2Ogmb3Rm^tMcGN`PTl|vvd1=r4P&7}Py2H)b)}kg zsrB$&={8>zXVRV1nV+4PMHk+=U0N5J`>+K$tF!A3^5CbVv5EC&yK_g(53T#cbvf3X zp1t{LM+<9rzuZqpFj)Vz#e?-vOPJ<%-h9oOsrS@9CA;RJJpHuepKG9&=U!Y(Va?h0 zToY%X-n~6P?P&4rv+cPi)|@TRHK{wSfxLTrembIsHIR4T&QBYdrZR7_?#z^Vdfln( z5z5@Z9B+`hU+$+P7_5W5`+I)c!Ehba?wpn9qixSwvF>bp&WiI<@BW^jj`+bk$h*Ji zrwvR}=CZfaGt|BXIzxRd=J8{39ij7i0mp9-o}mUy|F@i>9;bTE|1UU0Jsf>`@C+3~ zK(Koq-4~?q!=~1b{u!8`&h|AT=LgSFv!5kQuNNOYLxoKmo0;!3Qg$uMy}F+^c52pF zc6}%?x>jV`!EjCMotygU2pP_Qi-|h?*YyS3Us1Kff#?M=iR$uGR1Rp&6g#YANx0msa$vvFR zkq@4I#@4Ty=LD(stDW&UKg%Y4`9qQ?9~zJIX_WDYCQtm< zIl*TiN{rq8A<6T1DL%zD{K4sce~M2$b&c?cruX|&eBzekA0VIn-M5S*_^#Sm@!UdV zdZ=+O-iSCZ?223;&ZPU+PBtLr4_~+JKM`{z+C2RpEuMM!$mL7Rn3KjPM<$VHU^)D+ zyvLUoM{TkUzZJ;s<)^Rks`Alu2l+82=J4ul%_*GvS9T!?>v)f(%m_AJDA(w`5r`Ad z_b>a!rf=|lL;}ain z`@@ju_5`2Me}c~kT%KI7gl;YGDI#Pcs?Je zJXk)te)jk**NmDUP#?tKM)^L7>wAw!@vSI&KzYRPwqiWO#)L=mDZG})OGpaL1}5B` zq-%Sx9(xJd&k*eCxH$IIzb@ZVn&fx=>{MZCE-wS-@d{_>B>oo5wq@B~&=|yPxlwG} zEux+NS(IPiK>A@`{$)s$U((+RKYlr4&H=+FA1-S}y+}>Yku5$jiHE2co?A2=4c+4ib;j2yW3wi+3e~QQ6x) z5qM6j(TDrI9|CvqfB_A&)vRzM}DJ5 zoy+<3mOlSA7lISIYW{AWNAICp1P*)KrO~@}_)L@iZ3>?|i(v3B7X950VeIcq;xH)p zVf42^F&LaB#b6ZPz=(eNuAttYt$v3nqn7=7!ZjtI*PC4*q(6FJImQRhX>1>)Kl&S~ zI835H*PGwn#9)&BiS;?^k9`y#R)WyBKQH{Bk6JjRAJXI{{n7K@7$4}5eQs1>^!bK3 zO!Ql(rhP_#to{Wi)@RqBzHRbZTl)h2w*9&KXV=YYzfFIL+g|qGK%7_H=hkO336~9n z``mgiDKJ@m=Gi6hg!ikzHe|1tbQl#&h{^|JF$u3YJGfnv94Q2 ze6zPSUgf|?plnt%!Shm<7aC^qp>>=$c|Q0gFaN^}V(*-9`uzdoMthl8d4?L+>XTEG zrOB~@UT%MdHtVlP+O8XzpCPQ)LvPFPM4Iap2FC0YW8&w9Id}Pf-WRl&mMd-7#-q(Yf}|f4C`e9 zgzxkg>ysO$sxb8u6kA?1aZ!JcH~oBlX_~D}yN590){rweU5*2hZj&{W%>R2)FTCOd z-PMAe2p7uJptlo<3lW{!-*Hdvl4c95S zxW*;Dg8H5UJ4`srQ*>P4@>NC}n_2D|^4&okwzQpFYBW-*ZfY3C8FDl99e~1+=2=J+7kO$!Ge=!`G{s|$&6K(QmG;~NC;J=&QaI3^SKm(q zo-95h33M+5;_O5QoFALhF3eQx(HURdc3bP9Q~I34TGKZZ2>Ws%=wnW5L%$yo2TuO9 zv8?{VY^ru|v+8nQ}0+ogp45`n*TfhQ1i$fufK5MeXQ|As#6D zc&Ak+eKY!u4(~62czQEl=3$4#*@+!Ksx|F7+hM2lIqzrLVP7;3=46MR($BZ2KPNlv zl>QM-=o>G5|Jvah&3KuI9TI0Jc6elK+HFZ43=wxj2`MyYBLaS?ibxMoR5hiGLt*=gLZA{bZT3?;gD#U1c z0}SQVLHwB=y+0~LEqkmzN87ak50M&Ka*r3`pQ)BBlZ7NqJGs&M8T^x_U8T_~ z&Ml_#6_|-KaU+nw_?WJZ7mV6meG~o<;wImoZNPUPbRP1EtuH<3t+JJOc{z9HfJ^Wr zPkj}}Cnu^?lXX-}d+zU|zMCh*k}#`)|Ay@EsR%6&IH9HATPeI`a>9H~EY1@LOPG!4 zpf8}#I}1MuXYc+uzz+I3#CI`ZC`a6@Jm`0bpNoruWsryPvKi@cs$Q)%Sfgq4X`g~j zP$*OQ73kN`cSiZ8PuFt_rLpLcTCvfn&Qt(m+sL`_^N=_F1s%mL4laTN?)bM`I>r6x z7B}Tos#m9wXNY(XKf683$9RT~E;@v5@ZljfZ`)2}vjy$QxA0z?oWyba2)~o8qQW<$ zi}rCk+inHzgFKNwk9I-Lr z=tKr(`G=j(*`D~Ep6!dsN9pv=vp>Y8{7HYdH|Y;BIU^4Dq2p2*$^&lemFY9B0Pp6+Fnjb#QZ+DHSqS=b88Itq*0}No}O7xe- zq`j7j=-GkMaebhkb@0tfKSq~&lIIDmEr+nPf#D&3<4fN(X>cEGapT){)xuD9xIWqN z*8#47|3g5Ay!k@PQ* zK70mg=!WZRj=zxi7Z`KB%yK-B4FY;37}h2QFU7_m6>p z!FvkuegkP{d8W!ZkBjRh82lova~7S7H2SpYG+Y$|;BOe$c}PM^-C;GT(ngIBl!S!0CiSx1qP86rU$?yo%j_?`ZWQd+~V}09i zGGNVjE-%Fi+gfrpb(ol6Fs4^L2Qc8>**)=djJ#Oe=8>P@cNvx*KC8HZyW3}0GrkuY zlZE&njum;PwcofM>v(8u=wtI|S`WVCYJiCCU=6-BdZv}n5!z=?nbvV&zDcP>*wVCZ zN#h~6U1Z@preU9ygrV8CEonUR7MgN*{aCPXM6{3*aN6;O=TVS6(Zf+m(*ORvI^QI3# zB#sZ*pnL8QH2ib~gXebb^T~wq(h-dJOg3TcbFN4`7|O*y!;Er29l=E3b7-mq%Ei-- zpZ3PhiCx;lmUsUwE*Fk_xxlNRcD&+wX8TT4^6IA}7|2E6l}i{u?O-4m`@Rc-(f435 z9l=EJ$`u&-8{LOoMd=z{DodiT!zw`|{DDDN)y#|ryTJkb;q+O7d*zYe@1 z7wU}PrSVk?vkt|3>y_ca-kKVkZlFrq!#~Km2>GJzGH>s#GLInVB1|{gC(AzgNvIFe zuYuu`nJ3s1f$ikHrZG`#Y?KbUa`JUObH9@!{2P!2+h9NDe&_i;l$YlI+m_!QrB@#6rR{IwQMA(DhhbXx z&Y8Mk{UwS6{S>`C8Tqg_S@+M8P?vcYhTKKUQNG6i@UKuS_gOSQarCu!+Bts~Hk8EXD%8W&rI^R}qLoNG9 z8d&?evGF&^gRk%%h=*{Ma1rK_DBcSdkMgLkSRbnL?VELNrq4YAIa__DQhOX z@1XVo%I-kON_64NN(@bV*;G~?+1bS{W%bWZWc5yzgP-t9#KX8sxX8y`?2LYkZJ`s9 z-Kgdl%Fdn&e7@|&bEAx*sq8wkvr7#Uu_lAdAEW<*+AKR;AlV%VSp_=31Yvb@d>p6u zC9~?2eo|KGpWYWhbs>8HS~T`97g+zyz9*XF!gEkdnIMFmoNXFsq%O_-6IO1pr{y~; zcw}bk9C*xn9Zz=D>eX|C(s=otLgUX;-r=$V_`^LK z@7DMw8q-Ix{(Quw`6y&lYc-jVYNNHFR;_vK4a(;croGj3)3sYWoj)CTbgnMT0uFfw z^3;C)cB{Y!!GOeUfvPH zxL)g*^_n!de0Q`?>tsE)4`|shgq4h45RY4xCMO1l%UI+?*eDX* zTz9ADb-c~7r!Z2-;$0dAjVj-9QWzgD6I$A>16o<1?SI~^6zaeuzmU7E1D}a>Sg#CC zPEO%5FSBZ8{UK~%P!|%_f*b9Z6aX@dOYyDz=QB^f(fSh9ulzakE4})AkcT`h{Hn!q z_*LtWN42Ye1oFhK_*eZ2^7N-R-;ewzIpYK=cX2Hxej;FTzO+w;Uk+l zi!B*Aj4ZFTQ~B0=!e&n7*8?qFE1IqC^sGE_Af#v>hr%RH?l}ldIUdDCvY+J|>`n6&<8CX?h6`g{IPHbcnspQZO1q<49Fj+0;DO49f3XO8q|ftDerPtqU5W%(if zui#43_kDY&ys<_}3V=8x`+fdCWElqd&!;zze1e{=$}Lxs@ty{ODTg`IJA>^JQuJPh!X!Okf7oAn z_RDoQ7niB-CHuFJ%@AVt1A7Tyjlu-Ik}uD>(R<+li6NxuU5dgaJ%4;;&LgnTaxLA> zxQ)JWmIM(7_|LP^@IvGhG-WSg;Z9&8>C-{8FF~^Pn&(Bt!Z5&pN(sF!vOzj z-#f8~+_L~5*@NZG;ON38W=S{8CSHm1ESq>b$|0Y{^g-lzA#Eb@y9s%>6i77HpViqA zU_$P-JtI(AwzUC^gGUq1^zQrC1=9OIkYgC&zi#w?I^ZL{Th6-H`##dm(mTg`mfoL% za_XIP!9wf3A2=CQ4jt=#7;WaO_fgdp@ROM>285*F|QXQc9Cc(wjw7h5`PwGUYtZF`cAmEodI}_K^<40RQ>) zXiEutd=y?>Kj9wE21%J#CrkFYh}DFPWJ&MLAfk-XdJRg2R%r}BW-Q={YN|dtHdd+Q zq-q;GDO3%<%=3g&oyP?hr#vG&q4|jZO9_IoWFPD~etc_-@08}{%L zV?L7@zEfhJ53&9`8uR`P^WQabxJF~13!yv&Ka6v4)%a~D4tVa&cE2>SJo8I9rIS-U zIocKBc%I8XoC+TIKk@SGf)j4XgYkI2=BZyjCphl5>t^{J6rWMr_~D1lF8R$J0rQOc zjQe5FU%7AjU0<7(=iNUBRpMIm<9F-}dkaA6WW)UiY4HlHeI=+v&J9%^0(UIx(ss~S zik0#40kkJ5d5&~KE0aL6xH`KgQJc@bLhGP|++O0T+0}_@?&1}C`-8NG$58@*?gE$-N8Eo{}I^y_o zu)J(>Fn?dLZpr1^7WvhO!LEMi<&Q_&_8H05r)eG29NFv#+Q}ZBYZ#pQj!cgg@yp)= zeugoHgJbi96~ZB`=24xqE#bd^V6#ppO=Kdqmd^EP|0GI$C`N@*eKhS0m5+k4rVCFQq&$5kW6(v<$p+sa1HyE!HZLpoOOe~Ucj{%)-kA4r}O@@^-OGYuY`lRJ6z z_MnV`H0LW1%7I}a<-r>Q2TC5#0q%r-^ev=3^1#oqkn*t4U;*cX+s6*@nvh5TLdwJ9 zvhu(j;m$DZcmWIHS@<`XvBP!TfwGn7I@wI_#!EoPixb6>$~Yc@pkr|-3xZT4FIFc8wv!vjKl=usZu3p)#BrQR6t<1{UHCYgZ;FGm$VcNN+=M*rI_%Y$ zcE~*SL|Dvyt3QO8>*+nX&czky!?;PpQfBPS3S7*?hV3}aq@!&F|4RUG#+T?&<MgFgFormjXxH9OZ)@Q2$ zr!r`&uY{~Oqls-J@>rvJ%ui0%m!XWj>KqyVz2-01__f*w`V!t}O?gtUTTmRMwN~?a zkJcMemPPALQCp#LzJW{9*oxv94eS5fjW@u#{@!G8ha9hzr?uG&kiHPtMYs}j z?LTP#y&7Mu@%uD>zs4M&Z1(|;Z_xOI8t>JZW1esy*7zeDb8p4+k0K^-d9|U7k-h}i zt8j7kcPXyd;G(V39^>-wOO1tx0EYNHpCRvJ1}%BlI%%@+Dlf4q$c4NlaHrqtZ^uX; z;8uRE#)wa2Hk(G%vElI_W{nLWclMa*OZg+u*Es$^Y4{31f!N3SI^{Plm%fzm0I#-f zQ~yKUUY~Lk27iu=e$dF(6bI%n(aGzPe*>Es@iQP02C_%|B=TH{}7 ze5Z+p2fyzs?+lyhOZl0@frD*5`neMn?bP1#{aJIj}R00I@QUWk$wxVx8mY?T0%Dv zf#XGZ<2r}!^B(OZkf&}?Cb7?pFN3$E{;v&8lFo@JwtW^lkJP+BcYWKm4Zo%FcQyWw z#_YRK?{AQQhp8i937Te!PWZ)O`+CHW!o@sfju1`Ij!AS$h``I%IA^%fP=yTJt9}B&AH7j?W{Xu&z6VZ z2P|X|eox!1;5~%;R3oVK7B>nJC?j5G3=EftS;8TzxB>k77S*=OjIE+=^&dl=fK^j_ZuXjT}!prgL# zI#Xy&7`}(Q00uDu3M6XTs zNrG*OcR*#e2I-}^Acs)bRpF7E2W=@oLF1z|=Db08dJN)1Y~E|dUKioudgOnv{O=1! zrG)=`CEe%yKemV7sfdo}Je@u-%MYWb*J>%)%R?`JWN z-?Mp-=9ln(K;m26==fm`2+HfEslu=ddJrFJKMa|3Ex@u z-s9w_O`kE&@ji~`?_#2i0mJtjHGN-`g;}uoKFRtvzQ$b+KI!-VE9-q6sdvcu?@jX4 zQJ?=P{okxwn){>YX>fEd2Bzxm;SjqbJi|Qt#;TW#Om)$mP=FokE#%Nxf6Z zmxZ5pa-m;n=UD`#Zlo3sCEG@m@La zJ&Jxhg28(iz4s{k=?DhzUG(0g=%*bF-@CX4cVv0-U5{Qmg28(iz4s{k=?Dfss_DBg zDI1ZGz83?hCwv}Igu_0sXUaW`EkO8EjZ}+F2GIO^X7^urxhd6yk^R?Q8PC5jk$-4}9WcdypKMj&Dfe|b&?peW8xKHEHY8`knvKX8x;dKioIVrMf zg~1ws^_@qJe0&yp2I557@;eb*oGb$$%l9js(zRztxtk4a?w=5|4(IDQ8yYRvE9F7? zqS0V6h-F6sgg{t?HH>YVdS)8*UW?BMHo-7qE8e_%sOAMyS0MlkzPR;c?OH?LA{Cq z*UU$+&x1Tguhw5;z+&oha&G4@J)Od&Oc+3v)aeY$sBD(6c4HMfb)K!gUUBwm#;b8q zz+~EF*)nK#?6WwAL{5LfL?eNy zQ}W2Pand(!9IpQhHr_;kUHLQkiI&f}p9Q&!j_V^uYS+6xD6-x_xw~}%fcoVl8Dap| z-x$4qR5e6*mey+>W!BDdM!$SVgerC~gmaJ8t^fQEcnm+Kc#pF7J}5|f%>1Nj+}g0k zmJeT!yhlX7!Hdij0;L9D=RW=ui)YygVE`9-@%3~8 z@>C$p*TnSXhOpF8@6B}8iJ!N23R)eHVairyK)b2nHzM^4jW_nLDcFf;yWFQnz^qc8 zs=wz9E`eQ6$>Jp_v$7Ch#(k=wi{$RhLD!?9-OF`uv(5LZ#7UmPN7H@k7f}znhVC?Gi5C@h)h)M*?)IYm-ajWlnm^0N)|8G3idZ{ z&(S)=w`W~f$?puEE{8uQ;w&(cSIb`P68hjvLbb zpGKMOKNe_n1CX%fVA>FW1bTac|f1C+ltQ z`^j&svzsB*gI~{fhvv9e{uEf1ka@o6>kc;UbY~5heER;!*B|Se*)3!d+v8=)t403< zJsaVBh44{^lH2&X7hr-m>Eq1AvtIyv_b8k(`}j6Hwa6b8XgTj!7G3JR?~JDC_h zdMvze)1OBnbme|;`~~Dm?+6q(J-^_2A9u4vh(LJIT79QJlM#5&7(o8+Jj2qmG$7aI z``N~W_wD{Szzg1TcWZo)(t3E-dc>S{IIhSOg0p|fMC_O6SFFpjcdk`G?$tj7>1AI2 zVx(!1Z139y`e<>=^YA=bBFqxrD@Z^8F3-1@P#+&7W&Y|0rKT;$wr3l%>5M%;kVkX1 zhr0;MFu;HNKYf?PNHQiLkg2+z0b59d&8hhc`}UPVw(C+j6K;H z`(sZEnv6ZGSK1J9aqNAF&)p>MU88DVW6#RD)!3tcVJmocgR>qV9GfZ*ja5)$c-z3l zWUW#!PE{xPhGBeKuHmiOV3Uh?1LRY<{vH?m1GAPTzDV(%>_+u+UrV9tdFE`uGBEw<1~> zIE3UA!Cwcgxfcawly$^&BI2`ftm-_9Yk>Y@#Zz@Apk#-)aRDS2P z41q2IbNG$35_|GQ-`4yJ?<#BrW7UaWrj|JT`DYM$BG7U-pF?{+Y{BwlLDTMME=Qg+ zzD(mcX#6^jUyqn=9tW`YYe88Q7Ke%@x#c%nnJEpHBnu1%561uMJ9S(Hyr0F(`_60L z)4S!Z8Begi<@<>%0}uM>Y~v!(Mjvw*YJ7>tuhjTr#O&kt$aac>y>I5NDK#k_(&|_b zi37p6Gg)s^)~thGGUq(nlh&_Y0jsojNqF*xe%ksq&p;Yu#^%>@4YN=4%i;cx|NULa zv4w#-17(j#8hCcH41M3n_%%VelkugRe|3=C$NbAR{|YfpdAAVVKHsm?&-k^$V%c3< zeoq(C8d{*=%{a<&R*-RI@26k{;W-GBk^XhQ{=Jc^lrX^m`)_=u#7HtGul^X>i9BR0 z<&actj5OOfUJiKhD&vIsILFF(n8O^4=4-hQP#HE|>vrOcbR5fCSA4npA|B)$Ng6uc z`J$T=zUZb|u**Qx6uvw0MMc0`Is0p2@Y!qe91A&GU-TvvQpRu8_$?Y=q4Ap$Q)Ul@ zFS5Kff?t(|t{ zi$16D#uwd=93+E4y`Av@`68|fNx#LMp5u6AU+woi%cae8^hGx%e9=uUebEqT+A%^K zvion2k!HTg+9JmZ`*nZ#q7Gyj(6&T|#hG3{qEqr7Y9pVA;)>Rk0J3XJmLm|R2Pn*X z=pUsF|6oc8`)`&A|0pix|4AbJlRVpk$2Gs2DV2j#u{2r^*N$nzWBqG%!M?~Dh(XHJ5Q~^_(3$mL_I+{k{y5e>6m?D4OiBlxTYV>g*X;ea znRcLS-xN;3FW;Yrw`-lnCj&2Zu=pv8AGn&{=RjX&eR8A1BA@aJTyMa>L?)o^=J$ta zS*tNM0vNFeH@~~bUId@)1>GLQoNtM^6*pyTY~hP2k+78iDO-O&A4lHmZMCmAJAkxJ zD_u1kL%`c~e(pd90c9&PsPC#aYK7?ud{CT2BY7Vqx!>yNdt$vdKqLLmJDGfmMF=t_ zV?2D>WHnD29qrjXof2il!1b?9V_oND2YZFhH)`_mFurCFTMzh!4Er!Kah?JCcE0{T z^5|Rm1C9ShxF1tP;(QBn@J2;5e;2C3m(!1{pI`ljU~nBk8iF;6h>@{ zyAI~t`MBo*Chp_PbNp?}Eh0Cd3vs37cPYxO{KTdpzv$OX2EG#+(hvIQRrWI_su#De z_vA5W`=Sh!_GOQwNUux#nne?aO#6BbDy)3k+1GafOZ)n+#{Z0%{LIz9h==XFv9Fu8 zO*{MA0l0*HZMQ2E(rmXbp}uu|UIuW6O#6B*Dy;mheIHU2k^={Z?WF32~w8S3ZAET1DAWP+b^l0=mWev=dHIh)k2iL^fj z`|}Zla}mcFa4&-HB<31}`OO+{(Ri!I+ce&;G4F?wC-liYUq+b}<>@k}%yVW;m7_A@ zj8CBn1aiHxy1rPhKbG4Z%aJ(*(uZQ~Sx88^u}sFB_gg5yIREAC31atn(MJ6HGZhE) zDfgMVruipaJYgX2$D;hgMy-M_U=ul2oty}2#nLW(SY~i+a<@y5R!2qwZQ8UO%REDY z?7j6zrK@M*@@Q_x@>kGR2{M+0{a*p;C{O-SeF2`l%2;TxZHmWk-aaN$IKEjbUr)6m|@aF{ThYqO@@<;#R+bzU-N^Ddg`cY|pN{q-%b7_YD3qgL z=NmrY>(lc$U|CE)^Js47Z0@QgoGkzMfA#uFNIJw>>>#tp>8jg5t_+u0#mw=*H@_8HuV z&_u6I^w~teyeWRr0XOQULD#@!w2{g5ffxd5ay@q^V)DcOunc`&zMtQf)_jk*A5i@) zQk!3N8eq_N5#%EAvo$_b+iv6nGJloF6Y}zm?w2BX zS(krV^XQjb%X9Cd{YtLo*WQS_TcY~4wD+%gdG58os`(acrd$;;_%0E@1R+7`HT^z{ z*2^=Xy|(QDB#qE%Te0&9e(irE4IXX#bxV! z`cdNON?(Z2=i?huo_vH?A|J=G86~cb;DFu5aL`^XpTzNA~ zgW&LZ5INkIz;SO1M|->YP6Ef>DID$Xf-{HLm+-0-j`nt8&jevFVq4dxaJ07z-Us*j zc#q>?(Qj_iVMiPQJ{bXi)q?s%o)**Wbe98egPi~Z2IC~smvz-RO9Z*C0vZtUlK z@%F*5knh%h{xyMPdkRNPUSfk*9_W|YAn)yIzr;8FCWWKD{rn(-<7X)x?d|9G1dgAl zaJ09dI}$klG=*a;N}~SKZ+LnYdHm3;hhD??As^SvHk8D1EQ|7j5ECl0|Q z{w*fcj_jB^Qa#Z=bF)!i?9<~x?DL?gUhH!m`EKmfU4@*CbdjB2Wt5AmDz}WZb z%RnGbmg74e*Y7mnIEj_xn_J?-e3O%@Wf>-ADTMtuuz_G4o$OxSl@(gb=ba8K^k8iRqM^CmG-XBUl&c0NZ zfGtdw>B?O{jE!+MAt6(4A4iq#AMo1!eE2^oN8eq17xL7{p(qx)4MLcd-(Y=@CqjXt zZQiNv|4Z97k(21@r+{G~{-mDJE+tErjQ|$>EqaZ%gFIJEOzkO%0JIFzy7M)ils|Oa z>iHJ?ZR8;IZ92LoD!k6$rn$nBkg1!SP-S(4K0BMX^LbKMo!InW04HtwIfyB5;I+ES z?TE@++VtTH*R4$TY{=O)e;nKcTnyx;JGI6SN&<>GXoW3oev7fAbJ6 z1C4dVaA6FjM;&mDb{4J-y(~UN;Y2U>w7=opK|I}#jdRcj{kQ(6&N)=>XzKtWPDv*H zzW66}z%TFb(OJ}VjBTL|U31(%i!4K?e*O^^RzGZG=fW4GocehYV&ZG&Yal=8PuPaA zt#rYDL&pLK*lu*OXuq}tFSxhMwMV27((P6Ub+i#3lp9rwKf1$f_@h0<i-JA;x zZ0mE_mi&N!+22l)ZWrgeKhyrU=}*8JNbJSoZolv4UYYW5hxF;{v=avU`prXz$YB(LsrdCSrP! z^eh3iBX9KO)=xi7%h2a_+=Kr@^KEpW+YLC;Nm(@F9$+ATu3b|4C>w3CKGFrXEMb8E zS?BBGD&(y$C{JA@*l%p-zKnY6ME8)nWeU$SYr~HK$X?D-#pyi(_O5~1^&5StiKtB6 zdV+Xa2HMN_2X`Nhq?4PS122wXWPbal2a_dR_MTplc(JBy_8eIF6~c9KPjfzVS2sR^ z_D|m1*oEAy6uWT#ru|&CMRB)~OYm*L#POPikm^asHtRJnevD(Z6P~#~VOznUzV|1% zsXHexq!}#jze7`9OF2A(ivy7Us^xE~^;|^;ZiF`)BR?^P_&bKxqq*+@4>^u+#$1mvK1^fy8Oa}qm^e2gYtHTF?yqh(I2V0E!1JhsA%5n03oJXOYaPnHX%D^_^DFfLk?Et_&Ba$Ji}t3%sk?H_pX( z;o{tD=UvEi^%clduEdEr`TWVcAEDgZ4eG^z|61W8pJjJgrAIhoXR7UNjr*zl%ZF