1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <ddk/protocol/pci.h> 8 9 #include <hwreg/bitfields.h> 10 #include <inttypes.h> 11 #include <stddef.h> 12 #include <string.h> 13 #include <zircon/assert.h> 14 #include <zircon/types.h> 15 #include <lib/zx/vmo.h> 16 17 #include "registers-ddi.h" 18 19 namespace i915 { 20 // Various definitions from IGD OpRegion/Software SCI documentation. 21 22 // Offsets into the PCI configuration space of IGD registers 23 constexpr uint16_t kIgdSwSciReg = 0xe8; 24 constexpr uint16_t kIgdOpRegionAddrReg = 0xfc; 25 26 // Length of the igd opregion 27 constexpr uint32_t kIgdOpRegionLen = 0x2000; 28 29 constexpr uint32_t kMaxVbtSize = 6144; 30 31 typedef struct igd_opregion { 32 uint8_t signature[16]; 33 uint32_t kb_size; 34 uint32_t version; 35 uint8_t system_bios_build_version[32]; 36 uint8_t video_bios_build_version[16]; 37 uint8_t graphics_bios_build_version[16]; 38 uint32_t supported_mailboxes; 39 uint32_t driver_model; 40 uint32_t pcon; 41 uint8_t gop_version[32]; 42 uint8_t rsvd[124]; 43 44 uint8_t mailbox1[256]; 45 uint8_t mailbox2[256]; 46 uint8_t mailbox3[256]; 47 uint8_t mailbox4[kMaxVbtSize]; 48 uint8_t mailbox5[1024]; 49 validateigd_opregion50 bool validate() { 51 const char* sig = "IntelGraphicsMem"; 52 return !memcmp(signature, reinterpret_cast<const void*>(sig), 16) 53 && kb_size >= (sizeof(struct igd_opregion) >> 10); 54 } 55 } igd_opregion_t; 56 57 static_assert(sizeof(igd_opregion_t) == 0x2000, "Bad igd opregion len"); 58 static_assert(offsetof(igd_opregion_t, mailbox4) == 1024, "Bad mailbox4 offset"); 59 60 typedef struct sci_interface { 61 uint32_t entry_and_exit_params; 62 uint32_t additional_params; 63 uint32_t driver_sleep_timeout; 64 uint8_t rsvd[240]; 65 } sci_interface_t; 66 67 static_assert(sizeof(sci_interface_t) == 252, "Bad sci_interface_t size"); 68 69 // Header for each bios data block. 70 typedef struct block_header { 71 uint8_t type; 72 // Size of the block, not including the header 73 uint8_t size_low; 74 uint8_t size_high; 75 } block_header_t; 76 static_assert(sizeof(block_header_t) == 3, "Bad block_header size"); 77 78 typedef struct bios_data_blocks_header { 79 uint8_t signature[16]; 80 uint16_t version; 81 // Size of the header by itself 82 uint16_t header_size; 83 // Size of the header + all the blocks 84 uint16_t bios_data_blocks_size; 85 validatebios_data_blocks_header86 bool validate() { 87 const char* sig = "BIOS_DATA_BLOCK"; 88 return !memcmp(signature, sig, 15) && bios_data_blocks_size >= sizeof(block_header_t); 89 } 90 } bios_data_blocks_header_t; 91 static_assert(sizeof(bios_data_blocks_header_t) == 22, "Bad bios_data_blocks_header size"); 92 93 typedef struct vbt_header { 94 uint8_t signature[20]; 95 uint16_t version; 96 uint16_t header_size; 97 uint16_t vbt_size; 98 uint8_t checksum; 99 uint8_t rsvd; 100 uint32_t bios_data_blocks_offset; 101 uint32_t aim_offset[4]; 102 validatevbt_header103 bool validate() { 104 const char* sig_prefix = "$VBT"; 105 return !memcmp(signature, sig_prefix, 4) 106 && sizeof(bios_data_blocks_header_t) < vbt_size && vbt_size <= kMaxVbtSize 107 && bios_data_blocks_offset < vbt_size - sizeof(bios_data_blocks_header_t); 108 } 109 } vbt_header_t; 110 static_assert(sizeof(vbt_header_t) == 48, "Bad vbt_header size"); 111 112 typedef struct general_definitions { 113 static constexpr uint32_t kBlockType = 2; 114 115 uint8_t unused[4]; 116 // Contains the length of each entry in ddis. 117 uint8_t ddi_config_size; 118 // Array of ddi_config structures. 119 uint8_t ddis[0]; 120 } general_definitions_t; 121 122 // Bitfield for ddi_config's ddi_flags register 123 class DdiFlags : public hwreg::RegisterBase<DdiFlags, uint16_t> { 124 public: 125 DEF_BIT(12, internal); 126 DEF_BIT(11, not_hdmi); 127 DEF_BIT(4, tmds); 128 DEF_BIT(2, dp); 129 Get()130 static auto Get() { return hwreg::RegisterAddr<DdiFlags>(0); } 131 }; 132 133 typedef struct ddi_config { 134 uint8_t unused1[2]; 135 // See DdiFlags class 136 uint16_t ddi_flags; 137 uint8_t unused2[3]; 138 139 uint8_t hdmi_cfg; 140 // Index into the recommended buffer translation table to use when 141 // configuring DDI_BUF_TRANS[9] for HDMI/DVI. 142 DEF_SUBFIELD(hdmi_cfg, 3, 0, ddi_buf_trans_idx); 143 144 uint8_t unused3[8]; 145 // Specifies the DDI this config this corresponds to as well as type of DDI. 146 uint8_t port_type; 147 uint8_t unused4[6]; 148 149 uint8_t flags; 150 // Flag that indicates that there is an iboost override. An override enables 151 // iboost for all DDI_BUF_TRANS values and overrides the recommended iboost. 152 DEF_SUBBIT(flags, 3, has_iboost_override); 153 154 uint8_t unused5[13]; 155 156 uint8_t iboost_levels; 157 // The iboost override level, if has_iboost_override is set. 158 DEF_SUBFIELD(iboost_levels, 7, 4, hdmi_iboost_override); 159 DEF_SUBFIELD(iboost_levels, 3, 0, dp_iboost_override); 160 } ddi_config_t; 161 static_assert(offsetof(ddi_config_t, ddi_flags) == 2, "Bad ddi_flags offset"); 162 static_assert(offsetof(ddi_config_t, hdmi_cfg) == 7, "Bad hdmi_cfg offset"); 163 static_assert(offsetof(ddi_config_t, port_type) == 16, "Bad port_type offset"); 164 static_assert(offsetof(ddi_config_t, flags) == 23, "Bad flags offset"); 165 static_assert(offsetof(ddi_config_t, iboost_levels) == 37, "Bad iboost_levels offset"); 166 static_assert(sizeof(ddi_config_t) == 38, "Bad ddi_config_t size"); 167 168 typedef struct edp_config { 169 static constexpr uint32_t kBlockType = 27; 170 171 uint8_t unused[204]; 172 // Contains 16 nibbles, one for each panel type 0x0-0xf. If the value 173 // is 0, then the panel is a low voltage panel. 174 uint8_t vswing_preemphasis[8]; 175 // A bunch of other unused stuff 176 } edp_config_t; 177 static_assert(offsetof(edp_config_t, vswing_preemphasis) == 204, "Bad vswing_preemphasis offset"); 178 179 typedef struct lvds_config { 180 static constexpr uint32_t kBlockType = 40; 181 182 // The default panel type for the hardware. Can be overridden by the IGD 183 // SCI panel details function. 184 uint8_t panel_type; 185 // A bunch of other unused stuff 186 } lvds_config_t; 187 188 typedef struct lfp_backlight_entry { 189 uint8_t flags; 190 uint8_t pwm_freq_hz_low; 191 uint8_t pwm_freq_hz_high; 192 uint8_t min_brightness; 193 uint8_t unused[2]; 194 } lfp_backlight_entry_t; 195 static_assert(sizeof(lfp_backlight_entry_t) == 6, "Bad struct size"); 196 197 typedef struct lfp_backlight { 198 static constexpr uint32_t kBlockType = 43; 199 200 uint8_t entry_size; 201 lfp_backlight_entry_t entries[16]; 202 uint8_t level[16]; 203 } lfp_backlight_t; 204 static_assert(sizeof(lfp_backlight_t) == 113, "Bad struct size"); 205 206 class IgdOpRegion { 207 public: 208 IgdOpRegion(); 209 ~IgdOpRegion(); 210 zx_status_t Init(pci_protocol_t* pci); 211 SupportsHdmi(registers::Ddi ddi)212 bool SupportsHdmi(registers::Ddi ddi) const { 213 return ddi_supports_hdmi_[ddi]; 214 } SupportsDvi(registers::Ddi ddi)215 bool SupportsDvi(registers::Ddi ddi) const { 216 return ddi_supports_dvi_[ddi]; 217 } SupportsDp(registers::Ddi ddi)218 bool SupportsDp(registers::Ddi ddi) const { 219 return ddi_supports_dp_[ddi]; 220 } IsEdp(registers::Ddi ddi)221 bool IsEdp(registers::Ddi ddi) const { 222 return ddi_is_edp_[ddi]; 223 } 224 IsLowVoltageEdp(registers::Ddi ddi)225 bool IsLowVoltageEdp(registers::Ddi ddi) const { 226 ZX_DEBUG_ASSERT(SupportsDp(ddi)); 227 // TODO(stevensd): Support the case where more than one type of edp panel is present. 228 return ddi_is_edp_[ddi] && edp_is_low_voltage_; 229 } 230 GetIBoost(registers::Ddi ddi,bool is_dp)231 uint8_t GetIBoost(registers::Ddi ddi, bool is_dp) const { 232 return is_dp ? iboosts_[ddi].dp_iboost : iboosts_[ddi].hdmi_iboost; 233 } 234 235 static constexpr uint8_t kUseDefaultIdx = 0xff; GetHdmiBufferTranslationIndex(registers::Ddi ddi)236 uint8_t GetHdmiBufferTranslationIndex(registers::Ddi ddi) const { 237 ZX_DEBUG_ASSERT(SupportsHdmi(ddi) || SupportsDvi(ddi)); 238 return hdmi_buffer_translation_idx_[ddi]; 239 } 240 GetMinBacklightBrightness()241 double GetMinBacklightBrightness() const { 242 return min_backlight_brightness_; 243 } 244 245 private: 246 template<typename T> T* GetSection(uint16_t* size); 247 uint8_t* GetSection(uint8_t tag, uint16_t* size); 248 bool ProcessDdiConfigs(); 249 bool CheckForLowVoltageEdp(pci_protocol_t* pci); 250 bool GetPanelType(pci_protocol_t* pci, uint8_t* type); 251 bool Swsci(pci_protocol_t* pci, uint16_t function, uint16_t subfunction, 252 uint32_t additional_param, uint16_t* exit_param, uint32_t* additional_res); 253 void ProcessBacklightData(); 254 255 zx::vmo igd_opregion_pages_; 256 uintptr_t igd_opregion_pages_base_; 257 uintptr_t igd_opregion_pages_len_; 258 igd_opregion_t* igd_opregion_; 259 bios_data_blocks_header_t* bdb_; 260 261 bool ddi_supports_hdmi_[registers::kDdiCount] = {}; 262 bool ddi_supports_dvi_[registers::kDdiCount] = {}; 263 bool ddi_supports_dp_[registers::kDdiCount] = {}; 264 bool ddi_is_edp_[registers::kDdiCount] = {}; 265 266 bool edp_is_low_voltage_; 267 uint8_t panel_type_; 268 double min_backlight_brightness_; 269 270 struct { 271 uint8_t hdmi_iboost; 272 uint8_t dp_iboost; 273 } iboosts_[registers::kDdiCount]; 274 uint8_t hdmi_buffer_translation_idx_[registers::kDdiCount]; 275 }; 276 277 } // namespace i915 278