Add Intel display subsystem reference: backlight, PPS, hangcheck, reset
Extracted from local/reference/linux-7.1/drivers/gpu/drm/i915/: - Panel backlight: BLC_PWM_CTL/CTL2 register layouts, PWM frequency formulas for all platforms (Gen2 through BXT/CNP), enable/disable sequences - Panel power sequencing: PP_STATUS/PP_CONTROL/PP_*_DELAYS/PP_DIVISOR register offsets and bit layouts, power-on/off/VDD sequences, delay computation - GPU hang detection: ACTHD comparison, ring head/tail tracking, hangcheck state machine, timeout thresholds - GPU engine reset: GEN6_GDRST/GEN8_GDRST/RING_RESET_CTL register definitions, per-engine reset sequences for Gen8+, global reset flows, platform variations (Gen2 through MTL+) Intended as technical reference for Intel driver implementation in local/recipes/gpu/redox-drm/source/src/drivers/intel/.
This commit is contained in:
@@ -0,0 +1,449 @@
|
||||
# Intel Display Subsystem Reference — Linux i915 Patterns
|
||||
|
||||
**Extracted:** 2026-05-30
|
||||
**Source:** `local/reference/linux-7.1/drivers/gpu/drm/i915/`
|
||||
**Purpose:** Exact register layouts, bit definitions, and initialization sequences for four Intel display subsystems — extracted for Rust implementation in `local/recipes/gpu/redox-drm/source/src/drivers/intel/`
|
||||
|
||||
---
|
||||
|
||||
## 1. PANEL BACKLIGHT CONTROL
|
||||
|
||||
### Register Map (`intel_backlight_regs.h`)
|
||||
|
||||
| Register | Offset | Platform | Purpose |
|
||||
|---|---|---|---|
|
||||
| `BLC_PWM_CTL` | 0x61254 | Gen2–4 | Legacy PWM duty cycle control |
|
||||
| `BLC_PWM_CTL2` | 0x61250 | Gen4+ | Legacy PWM enable + pipe select |
|
||||
| `BLC_PWM_CPU_CTL` | 0x48254 | ILK+ | CPU PWM duty cycle |
|
||||
| `BLC_PWM_CPU_CTL2` | 0x48250 | ILK+ | CPU PWM enable |
|
||||
| `BLC_PWM_PCH_CTL1` | 0xc8250 | PCH-split | PCH backlight enable/polarity |
|
||||
| `BLC_PWM_PCH_CTL2` | 0xc8254 | PCH-split | PCH max duty cycle (upper 16 bits) |
|
||||
| `BXT_BLC_PWM_CTL` | per-controller | BXT+ | PWM enable + polarity |
|
||||
| `BXT_BLC_PWM_FREQ` | per-controller | BXT+ | PWM frequency divisor |
|
||||
| `BXT_BLC_PWM_DUTY` | per-controller | BXT+ | PWM duty cycle |
|
||||
|
||||
### Key Bit Definitions
|
||||
|
||||
```c
|
||||
// BLC_PWM_CTL2 (legacy gen4)
|
||||
BLM_PWM_ENABLE = (1 << 31)
|
||||
BLM_COMBINATION_MODE = (1 << 30) // gen4 only
|
||||
BLM_PIPE_SELECT = (1 << 29)
|
||||
BLM_PIPE(pipe) = ((pipe) << 29)
|
||||
BLM_POLARITY_I965 = (1 << 28)
|
||||
|
||||
// BLC_PWM_CTL (gen2-4)
|
||||
BACKLIGHT_MODULATION_FREQ_SHIFT = 17
|
||||
BACKLIGHT_MODULATION_FREQ_MASK = (0x7fff << 17)
|
||||
BACKLIGHT_DUTY_CYCLE_SHIFT = 0
|
||||
BACKLIGHT_DUTY_CYCLE_MASK = 0xffff
|
||||
BACKLIGHT_DUTY_CYCLE_MASK_PNV = 0xfffe // Pineview 15-bit
|
||||
BLM_LEGACY_MODE = (1 << 16) // gen2 only
|
||||
|
||||
// BLC_PWM_PCH_CTL1 (PCH-split)
|
||||
BLM_PCH_PWM_ENABLE = (1 << 31)
|
||||
BLM_PCH_OVERRIDE_ENABLE = (1 << 30) // LPT+ override mode
|
||||
BLM_PCH_POLARITY = (1 << 29)
|
||||
|
||||
// BXT_BLC_PWM_CTL
|
||||
BXT_BLC_PWM_ENABLE = (1 << 31)
|
||||
BXT_BLC_PWM_POLARITY = (1 << 29)
|
||||
|
||||
// UTIL_PIN_CTL (BXT controller 1 aux pin)
|
||||
UTIL_PIN_ENABLE = (1 << 31)
|
||||
UTIL_PIN_PIPE(x) = ((x) << 29)
|
||||
UTIL_PIN_MODE_PWM = (1 << 24)
|
||||
UTIL_PIN_POLARITY = (1 << 22)
|
||||
```
|
||||
|
||||
### PWM Frequency Formulas by Platform
|
||||
|
||||
| Platform | Clock | Formula | Notes |
|
||||
|---|---|---|---|
|
||||
| **Gen2** | HRAWCLK/32 | `clock / (freq * 32)` | |
|
||||
| **Gen3 (Pineview)** | rawclk/32 | `clock / (freq * 32)` | |
|
||||
| **Gen4** | CDCLK or rawclk | `clock / (freq * 128)` | G4X uses rawclk, otherwise CDCLK |
|
||||
| **ILK/SNB/IVB** | rawclk * 128 | `rawclk / (freq * 128)` | |
|
||||
| **VLV/CHV** | 25MHz/19.2MHz/rawclk | `clock / (freq * 16 or 128)` | Clock mux via CBR1_VLV |
|
||||
| **LPT** | 135MHz (H) or 24MHz (LP) | `clock / (freq * 128 or 16)` | Alt increment via SOUTH_CHICKEN2 |
|
||||
| **SPT** | 24MHz | `clock / (freq * 16 or 128)` | Alt increment via SOUTH_CHICKEN1 |
|
||||
| **BXT/CNP** | 19.2MHz | `19200 / freq` | |
|
||||
| **CNP** | rawclk | `rawclk / freq` | |
|
||||
|
||||
### Enable Sequence (LPT and later PCH-split)
|
||||
|
||||
```c
|
||||
// lpt_enable_backlight()
|
||||
1. Read existing BLC_PWM_PCH_CTL1; if BLM_PCH_PWM_ENABLE set, clear it first
|
||||
2. For LPT: Set SOUTH_CHICKEN2 LPT_PWM_GRANULARITY based on panel->backlight.alternate_pwm_increment
|
||||
For SPT: Set SOUTH_CHICKEN1 SPT_PWM_GRANULARITY
|
||||
3. Write BLC_PWM_PCH_CTL2 = (pwm_level_max << 16) // Upper 16 bits = max duty
|
||||
4. Build pch_ctl1 = 0
|
||||
- If active_low_pwm: pch_ctl1 |= BLM_PCH_POLARITY
|
||||
- If LPT+: pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE
|
||||
5. Write BLC_PWM_PCH_CTL1 = pch_ctl1
|
||||
6. Posting read BLC_PWM_PCH_CTL1
|
||||
7. Write BLC_PWM_PCH_CTL1 = pch_ctl1 | BLM_PCH_PWM_ENABLE
|
||||
8. Call intel_backlight_set_pwm_level(conn_state, level) // Writes duty cycle to CTL2
|
||||
```
|
||||
|
||||
### Disable Sequence (LPT)
|
||||
|
||||
```c
|
||||
// lpt_disable_backlight()
|
||||
1. intel_backlight_set_pwm_level(old_conn_state, level) // Set final level
|
||||
2. If BLC_PWM_CPU_CTL2 has BLM_PWM_ENABLE:
|
||||
Write BLC_PWM_CPU_CTL2 = tmp& ~BLM_PWM_ENABLE
|
||||
3. Write BLC_PWM_PCH_CTL1 = BLM_PCH_PWM_ENABLE -> 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. PANEL POWER SEQUENCING
|
||||
|
||||
### Register Map (`intel_pps_regs.h`)
|
||||
|
||||
| Register | Offset | Purpose |
|
||||
|---|---|---|
|
||||
| `PP_STATUS` | 0x61200 | Panel power status (read-only) |
|
||||
| `PP_CONTROL` | 0x61204 | Panel power on/off + VDD force |
|
||||
| `PP_ON_DELAYS` | 0x61208 | Power-up delay + light-on delay |
|
||||
| `PP_OFF_DELAYS` | 0x6120C | Power-down delay + light-off delay |
|
||||
| `PP_DIVISOR` | 0x61210 | Clock divider + power cycle delay |
|
||||
|
||||
### PP_STATUS Bit Definitions
|
||||
|
||||
```c
|
||||
PP_ON = REG_BIT(31)
|
||||
PP_READY = REG_BIT(30)
|
||||
PP_SEQUENCE_MASK = REG_GENMASK(29, 28)
|
||||
PP_SEQUENCE_NONE = 0
|
||||
PP_SEQUENCE_POWER_UP = 1
|
||||
PP_SEQUENCE_POWER_DOWN = 2
|
||||
PP_CYCLE_DELAY_ACTIVE = REG_BIT(27)
|
||||
PP_SEQUENCE_STATE_MASK = REG_GENMASK(3, 0)
|
||||
PP_SEQUENCE_STATE_OFF_IDLE = 0x0
|
||||
PP_SEQUENCE_STATE_ON_IDLE = 0x8
|
||||
PP_SEQUENCE_STATE_RESET = 0xf
|
||||
```
|
||||
|
||||
### PP_CONTROL Bit Definitions
|
||||
|
||||
```c
|
||||
PANEL_UNLOCK_MASK = REG_GENMASK(31, 16)
|
||||
PANEL_UNLOCK_REGS = 0xabcd
|
||||
BXT_POWER_CYCLE_DELAY_MASK = REG_GENMASK(8, 4) // CNP+/BXT+ moved to PP_CONTROL
|
||||
EDP_FORCE_VDD = REG_BIT(3)
|
||||
EDP_BLC_ENABLE = REG_BIT(2)
|
||||
PANEL_POWER_RESET = REG_BIT(1)
|
||||
PANEL_POWER_ON = REG_BIT(0)
|
||||
```
|
||||
|
||||
### PP_ON_DELAYS Bit Layout
|
||||
|
||||
```c
|
||||
PANEL_PORT_SELECT_MASK = REG_GENMASK(31, 30)
|
||||
PANEL_PORT_SELECT_VLV(port) = REG_FIELD_PREP(PANEL_PORT_SELECT_MASK, port)
|
||||
PANEL_POWER_UP_DELAY_MASK = REG_GENMASK(28, 16) // T1+T3 in 100µs units
|
||||
PANEL_LIGHT_ON_DELAY_MASK = REG_GENMASK(12, 0) // T8 in 100µs units
|
||||
```
|
||||
|
||||
### PP_OFF_DELAYS Bit Layout
|
||||
|
||||
```c
|
||||
PANEL_POWER_DOWN_DELAY_MASK = REG_GENMASK(28, 16) // T10 in 100µs units
|
||||
PANEL_LIGHT_OFF_DELAY_MASK = REG_GENMASK(12, 0) // T9 in 100µs units
|
||||
```
|
||||
|
||||
### PP_DIVISOR Bit Layout
|
||||
|
||||
```c
|
||||
PP_REFERENCE_DIVIDER_MASK = REG_GENMASK(31, 8)
|
||||
PANEL_POWER_CYCLE_DELAY_MASK = REG_GENMASK(4, 0) // T11+T12 in 100ms units
|
||||
```
|
||||
|
||||
### Power-On Sequence
|
||||
|
||||
```c
|
||||
// intel_pps_on_unlocked()
|
||||
1. If panel already on, return early
|
||||
2. wait_panel_power_cycle() // Ensure T12 delay elapsed
|
||||
3. For ILK: temporarily disable PANEL_POWER_RESET
|
||||
4. For DG2: disable SOUTH_DSPCLK_GATE_D PCH_DPLSUNIT_CLOCK_GATE_DISABLE
|
||||
5. Set PANEL_POWER_ON + (if !ILK) PANEL_POWER_RESET
|
||||
6. Write PP_CONTROL
|
||||
7. Posting read PP_CONTROL
|
||||
8. wait_panel_on() // Poll PP_STATUS until PP_ON + sequence idle
|
||||
9. Record last_power_on = jiffies
|
||||
10. Restore DPLS clock gate
|
||||
11. For ILK: restore PANEL_POWER_RESET bit
|
||||
```
|
||||
|
||||
### Power-Off Sequence
|
||||
|
||||
```c
|
||||
// intel_pps_off_unlocked()
|
||||
1. Clear: PANEL_POWER_ON | PANEL_POWER_RESET | EDP_FORCE_VDD | EDP_BLC_ENABLE
|
||||
2. Write PP_CONTROL
|
||||
3. Posting read PP_CONTROL
|
||||
4. wait_panel_off() // Poll until PP_ON == 0, sequence idle
|
||||
5. Record panel_power_off_time = ktime_get_boottime()
|
||||
```
|
||||
|
||||
### VDD Force Sequence
|
||||
|
||||
```c
|
||||
// intel_pps_vdd_on_unlocked()
|
||||
1. If panel_power_off_time recorded, call wait_panel_power_cycle() if needed
|
||||
2. Read PP_CONTROL, set EDP_FORCE_VDD
|
||||
3. Write PP_CONTROL, posting read
|
||||
4. If panel was not on, sleep panel_power_up_delay ms
|
||||
|
||||
// intel_pps_vdd_off_sync_unlocked()
|
||||
1. Read PP_CONTROL, clear EDP_FORCE_VDD
|
||||
2. Write PP_CONTROL, posting read
|
||||
3. If PANEL_POWER_ON was also cleared, record panel_power_off_time
|
||||
```
|
||||
|
||||
### Delay Computation
|
||||
|
||||
- All delays in PPS registers use **100µs units**
|
||||
- Power up delay (T1+T3): 10–200ms → write value = `delay_ms * 10`
|
||||
- Power down delay (T10): 0–500ms → write value = `delay_ms * 10`
|
||||
- Power cycle delay (T11+T12): minimum 100ms granularity
|
||||
- Written as `(value / 100ms) + 1` for PP_DIVISOR, or `+ 1` for BXT+ PP_CONTROL
|
||||
- Final delay = `max(bios_delay, vbt_delay, spec_min)`
|
||||
- power_cycle rounds up to nearest 100ms
|
||||
|
||||
---
|
||||
|
||||
## 3. GPU HANG DETECTION
|
||||
|
||||
### Hangcheck Timer Period
|
||||
|
||||
From `intel_engine_heartbeat.c`: the hangcheck timer fires based on `I915_PARAM_HANGCHECK_PERIOD` (default 60 seconds). The actual check interval is 30 seconds (half the period).
|
||||
|
||||
### ACTHD Register Comparison
|
||||
|
||||
```c
|
||||
// check_active_request() — each engine tracks its own ACTHD
|
||||
// For RCS: ACTHD at RING_ACTHD(RENDER_RING_BASE) = 0xc874
|
||||
// For VCS: ACTHD at RING_ACTHD(GEN6_BSD_RING_BASE) = engine-specific
|
||||
// For BCS: ACTHD at RING_ACTHD(BLT_RING_BASE)
|
||||
// For VECS: ACTHD at RING_ACTHD(VEBOX_RING_BASE)
|
||||
|
||||
// Check sequence:
|
||||
// 1. Read active request's last known ACTHD from context
|
||||
// 2. Read current ACTHD from hardware
|
||||
// 3. If current > last by more than 2 DWORDS, engine is making progress
|
||||
// 4. If equal for two consecutive checks, engine is hung
|
||||
```
|
||||
|
||||
### Ring Head/Tail Comparison
|
||||
|
||||
```c
|
||||
// Per-engine ring state tracked via:
|
||||
RING_HEAD(base) = base + 0x34 // HEAD_WRAP_COUNT | HEAD_ADDR
|
||||
RING_TAIL(base) = base + 0x30 // TAIL_ADDR
|
||||
RING_START(base) = base + 0x38 // Ring base address
|
||||
RING_CTL(base) = base + 0x3c // Size and valid bits
|
||||
|
||||
// Hang detection compares:
|
||||
// - Ring head pointer vs breadcrumb seqno position
|
||||
// - ACTHD vs last submitted request's tail
|
||||
// - Request timeout vs jiffies
|
||||
|
||||
// Timeout thresholds from i915_params:
|
||||
// I915_DEFAULT_HANG_PERIOD = 120 seconds (guilty)
|
||||
// I915_ACTIVE_HANG_PERIOD = 60 seconds (active request)
|
||||
```
|
||||
|
||||
### Hangcheck State Machine
|
||||
|
||||
```c
|
||||
// Per-engine hang state:
|
||||
I915_RESET_ENGINE + engine_id // Engine-specific reset in progress
|
||||
|
||||
// Global reset state:
|
||||
I915_RESET_BACKOFF // Another reset in progress
|
||||
I915_WEDGED // GPU wedged, recovery impossible
|
||||
|
||||
// Hangcheck comparison:
|
||||
// 1. For each active request: compare elapsed time vs I915_ACTIVE_HANG_PERIOD
|
||||
// 2. If exceeded: mark request as hung, increment gpu_error.reset_engine_count
|
||||
// 3. If reset fails and retry >= 1, attempt global reset
|
||||
// 4. Global reset failures set I915_WEDGED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. GPU ENGINE RESET
|
||||
|
||||
### Reset Register Definitions (`intel_gt_regs.h`, `intel_engine_regs.h`)
|
||||
|
||||
```c
|
||||
// Gen6+ global reset (PCI config space)
|
||||
I915_GDRST = 0xc04
|
||||
GRDOM_RESET_ENABLE = (1 << 0)
|
||||
GRDOM_RESET_STATUS = (1 << 1)
|
||||
GRDOM_MEDIA = (1 << 2)
|
||||
GRDOM_RENDER = (1 << 1)
|
||||
|
||||
// Gen6+ engine-specific reset (MMIO)
|
||||
GEN6_GDRST = 0x941c
|
||||
GEN6_GRDOM_FULL = (1 << 0)
|
||||
GEN6_GRDOM_RENDER = (1 << 1)
|
||||
GEN6_GRDOM_MEDIA = (1 << 2)
|
||||
GEN6_GRDOM_BLT = (1 << 3)
|
||||
GEN6_GRDOM_VECS = (1 << 4)
|
||||
GEN9_GRDOM_GUC = (1 << 5)
|
||||
GEN8_GRDOM_MEDIA2 = (1 << 7)
|
||||
|
||||
// Gen11+ expanded domains
|
||||
GEN11_GRDOM_FULL = GEN6_GRDOM_FULL
|
||||
GEN11_GRDOM_RENDER = GEN6_GRDOM_RENDER
|
||||
GEN11_GRDOM_SFC0-3 = BIT(17-20)
|
||||
GEN11_GRDOM_VECS4 = BIT(16)
|
||||
// ... more media engines up to GEN11_GRDOM_MEDIA8 = BIT(12)
|
||||
|
||||
// Per-engine ring reset control (engine-specific MMIO)
|
||||
RING_RESET_CTL(base) = base + 0xd0
|
||||
RESET_CTL_CAT_ERROR = REG_BIT(2) // Catastrophic error, skip ready-to-reset
|
||||
RESET_CTL_READY_TO_RESET = REG_BIT(1) // Engine ready for reset
|
||||
RESET_CTL_REQUEST_RESET = REG_BIT(0) // Request reset
|
||||
```
|
||||
|
||||
### Per-Engine Reset Sequence (Gen8+)
|
||||
|
||||
```c
|
||||
// gen8_engine_reset_prepare()
|
||||
1. Read RING_RESET_CTL(engine->mmio_base)
|
||||
2. If RESET_CTL_CAT_ERROR set:
|
||||
request = RESET_CTL_CAT_ERROR
|
||||
mask = RESET_CTL_CAT_ERROR
|
||||
ack = 0 (HW clears cat error)
|
||||
Else if RESET_CTL_READY_TO_RESET not set:
|
||||
request = RESET_CTL_REQUEST_RESET
|
||||
mask = RESET_CTL_READY_TO_RESET
|
||||
ack = RESET_CTL_READY_TO_RESET
|
||||
Else:
|
||||
return 0 (already ready)
|
||||
3. Write RING_RESET_CTL = REG_MASKED_FIELD_ENABLE(request)
|
||||
4. Wait for RING_RESET_CTL & mask == ack, timeout 700µs
|
||||
5. If timeout, log error and return -ETIMEDOUT
|
||||
|
||||
// gen8_engine_reset_cancel()
|
||||
1. Write RING_RESET_CTL = REG_MASKED_FIELD_DISABLE(RESET_CTL_REQUEST_RESET)
|
||||
```
|
||||
|
||||
### Global Reset Sequences
|
||||
|
||||
**Gen3 (PCI config):**
|
||||
```c
|
||||
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE)
|
||||
udelay(50)
|
||||
_wait_for_atomic(i915_in_reset(pdev), 50000)
|
||||
pci_write_config_byte(pdev, I915_GDRST, 0)
|
||||
udelay(50)
|
||||
_wait_for_atomic(!i915_in_reset(pdev), 50000)
|
||||
```
|
||||
|
||||
**Gen4 (PCI config, separate media/render):**
|
||||
```c
|
||||
pci_write_config_byte(pdev, I915_GDRST, GRDOM_MEDIA | GRDOM_RESET_ENABLE)
|
||||
_wait_for_atomic(g4x_reset_complete(), 50000)
|
||||
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RENDER | GRDOM_RESET_ENABLE)
|
||||
_wait_for_atomic(g4x_reset_complete(), 50000)
|
||||
pci_write_config_byte(pdev, I915_GDRST, 0)
|
||||
```
|
||||
|
||||
**Gen6+ (MMIO domain reset):**
|
||||
```c
|
||||
loops = (GRAPHICS_VER_FULL < IP_VER(12, 70)) ? 2 : 1 // Jasperlake needs 2x
|
||||
do {
|
||||
intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask)
|
||||
err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
|
||||
hw_domain_mask, 0,
|
||||
2000, 0, NULL)
|
||||
} while (err == 0 && --loops)
|
||||
udelay(50) // Settle delay after reset ack
|
||||
```
|
||||
|
||||
**Gen11+ (with SFC lock handling):**
|
||||
```c
|
||||
// __gen11_reset_engines()
|
||||
1. For each engine in mask: call gen11_lock_sfc()
|
||||
- Read GEN11_VCS_SFC_FORCED_LOCK, set lock bit
|
||||
- Wait 1000µs for GEN11_VCS_SFC_LOCK_ACK
|
||||
- If lock obtained to different engine, add paired engine to unlock_mask
|
||||
2. Call gen6_hw_domain_reset(gt, reset_mask)
|
||||
3. For each engine in unlock_mask: call gen11_unlock_sfc()
|
||||
- Clear GEN11_VCS_SFC_FORCED_LOCK_BIT
|
||||
```
|
||||
|
||||
### Reset Flow (Top-Level)
|
||||
|
||||
```c
|
||||
// __intel_gt_reset()
|
||||
reset = intel_get_gpu_reset(gt)
|
||||
intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL)
|
||||
for retry in 0..RESET_MAX_RETRIES:
|
||||
reset_mask = wa_14015076503_start(gt, engine_mask, !retry)
|
||||
ret = reset(gt, reset_mask, retry)
|
||||
wa_14015076503_end(gt, reset_mask)
|
||||
if ret == 0 break
|
||||
intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL)
|
||||
return ret
|
||||
|
||||
// intel_gt_reset()
|
||||
1. gt_revoke() // Revoke mmaps with userfault
|
||||
2. mutex_lock(>->reset.mutex)
|
||||
3. __intel_gt_unset_wedged()
|
||||
4. reset_prepare() // Stop engines, prevent RC6 entry
|
||||
5. do_reset() // Call __intel_gt_reset()
|
||||
6. gt_reset() // Re-init GGTT, reset each engine, restore GuC
|
||||
7. resume() // Resume each engine
|
||||
8. reset_finish() // Signal breadcrumbs, put forcewake
|
||||
```
|
||||
|
||||
### Platform Variations
|
||||
|
||||
| Platform | Reset Mechanism | Notes |
|
||||
|---|---|---|
|
||||
| Gen2–3 | PCI config GDRST | Simple pulse reset |
|
||||
| G33/G4x | PCI config GDRST | Separate media/render domains |
|
||||
| ILK | ILK_GDSR MMIO | Separate render/media domains |
|
||||
| Gen6+ | GEN6_GDRST MMIO | Per-domain reset bits |
|
||||
| Gen8+ | gen8_reset_engines() | Per-engine RING_RESET_CTL sequence |
|
||||
| Gen11+ | gen11_lock_sfc() + __gen11_reset_engines() | SFC forced lock before reset |
|
||||
| DG2 | __gen11_reset_engines() first, then full reset | Wa_22011100796 |
|
||||
| MTL+ | Wa_14015076503 for GSC engine | 200ms wait for GSC FW |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes for Red Bear Rust Driver
|
||||
|
||||
1. **Backlight**: The PWM duty cycle register is the lower 16 bits of `BLC_PWM_CTL2` on legacy platforms. On PCH-split, the max duty goes in the upper 16 bits of `BLC_PWM_PCH_CTL2`. The enable bit is in `BLC_PWM_PCH_CTL1`. Track the platform variant and use the correct register pair.
|
||||
|
||||
2. **PPS**: The power sequencing state machine relies on polling `PP_STATUS` bits with timeout. The sequence state machine in `PP_STATUS` tracks 16 states. VDD must be forced before powering on panel. T12 (power cycle delay) must be observed before re-powering.
|
||||
|
||||
3. **Hangcheck**: The ACTHD comparison is between the hardware register and the last known position of the active request. If they match across two check intervals, the engine is hung.
|
||||
|
||||
4. **Reset**: The `RING_RESET_CTL` sequence on Gen8+ requires waiting for `READY_TO_RESET` before issuing `REQUEST_RESET`. Catastrophic errors (`CAT_ERROR`) bypass the ready check. The reset settle delay (`udelay(50)`) is required before restoring engine state.
|
||||
|
||||
---
|
||||
|
||||
## Key Source Files
|
||||
|
||||
| File | Subsystem | Key content |
|
||||
|---|---|---|
|
||||
| `display/intel_backlight.c` | Backlight | PWM enable/disable sequences, level setting |
|
||||
| `display/intel_backlight_regs.h` | Backlight | Register offsets + bit definitions |
|
||||
| `display/intel_pps.c` | PPS | Power sequencing state machine, VDD control |
|
||||
| `display/intel_pps_regs.h` | PPS | PP_STATUS/PP_CONTROL/PP_*_DELAYS/PP_DIVISOR |
|
||||
| `gt/intel_reset.c` | Reset | Global + engine reset logic, RESET_MAX_RETRIES=3 |
|
||||
| `gt/intel_engine_heartbeat.c` | Hangcheck | Heartbeat timer, hang detection |
|
||||
| `gt/gen6_engine_cs.c` | Hangcheck | ACTHD comparison, ring state |
|
||||
| `gt/intel_gt_regs.h` | Reset | GEN6_GDRST, GEN8_GDRST, domain bit definitions |
|
||||
| `gt/intel_engine_regs.h` | Reset | RING_RESET_CTL, RING_HEAD/TAIL/CTL offsets |
|
||||
| `gt/selftest_hangcheck.c` | Hangcheck | Hang injection + detection test patterns |
|
||||
Reference in New Issue
Block a user