diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_watermark.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_watermark.rs index 3242840cf9..1729070d78 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_watermark.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_watermark.rs @@ -5,16 +5,25 @@ use redox_driver_sys::memory::MmioRegion; use super::info::IntelDeviceInfo; use crate::driver::Result; +use crate::kms::ModeInfo; const DBUF_CTL_S1: usize = 0x45008; const DBUF_CTL_S2: usize = 0x4500C; const PLANE_BUF_CFG_BASE: usize = 0x7017C; const PLANE_WM_BASE: usize = 0x70240; +const PLANE_WM_LINES_BASE: usize = 0x70244; +const PLANE_WM_BLOCKS_BASE: usize = 0x70248; const PIPE_STRIDE: usize = 0x1000; const DBUF_SLICE_ENABLE: u32 = 1 << 31; const DBUF_TRACKER_STATE_SERVICE: u32 = 0x0F00; +const WM_LINES_ENABLE: u32 = 1 << 31; +const WM_BLOCKS_ENABLE: u32 = 1 << 31; +const WM_DISABLE: u32 = 0; + +const XE2_MEMORY_BW_KBPS: u32 = 50_000_000; + pub struct DisplayWatermark { mmio: Arc, is_xe2: bool, @@ -52,21 +61,53 @@ impl DisplayWatermark { Ok(()) } - pub fn program_pipe_watermarks(&self, pipe: u8, enabled: bool) -> Result<()> { + pub fn program_for_mode(&self, pipe: u8, mode: &ModeInfo, enabled: bool) -> Result<()> { if !self.is_xe2 { return Ok(()); } + if !enabled { + self.disable_pipe(pipe)?; + return Ok(()); + } let buf_cfg = PLANE_BUF_CFG_BASE + (pipe as usize) * PIPE_STRIDE; let wm_reg = PLANE_WM_BASE + (pipe as usize) * PIPE_STRIDE; + let lines_reg = PLANE_WM_LINES_BASE + (pipe as usize) * PIPE_STRIDE; + let blocks_reg = PLANE_WM_BLOCKS_BASE + (pipe as usize) * PIPE_STRIDE; - if enabled { - self.mmio.write_u32(buf_cfg, 0x00000000); - self.mmio.write_u32(wm_reg, 0x00000000); - } else { - self.mmio.write_u32(buf_cfg, 0); - self.mmio.write_u32(wm_reg, 0); - } - debug!("redox-drm-intel: pipe {} watermarks programmed", pipe); + let lines = Self::compute_watermark_lines(mode); + let blocks = Self::compute_watermark_blocks(mode); + + self.mmio.write_u32(buf_cfg, 0x00000000); + self.mmio.write_u32(wm_reg, WM_DISABLE); + self.mmio.write_u32(lines_reg, WM_LINES_ENABLE | (lines & 0x1F)); + self.mmio.write_u32(blocks_reg, WM_BLOCKS_ENABLE | (blocks & 0x3FF)); + debug!("redox-drm-intel: pipe {} watermarks: {} lines, {} blocks for {}x{}", + pipe, lines, blocks, mode.hdisplay, mode.vdisplay); + Ok(()) + } + + fn compute_watermark_lines(mode: &ModeInfo) -> u32 { + let pixel_rate = mode.pixel_clock as u64; + if pixel_rate == 0 { return 8; } + let lines = (pixel_rate * mode.hdisplay as u64) / (XE2_MEMORY_BW_KBPS as u64 / 1000); + lines.min(31).max(4) as u32 + } + + fn compute_watermark_blocks(mode: &ModeInfo) -> u32 { + let pixel_rate = mode.pixel_clock as u64; + if pixel_rate == 0 { return 64; } + let bytes_per_line = (mode.hdisplay as u64 * 4) / 64; + let blocks = (pixel_rate * bytes_per_line) / (XE2_MEMORY_BW_KBPS as u64 / 1000); + blocks.min(512).max(32) as u32 + } + + fn disable_pipe(&self, pipe: u8) -> Result<()> { + let buf_cfg = PLANE_BUF_CFG_BASE + (pipe as usize) * PIPE_STRIDE; + let wm_reg = PLANE_WM_BASE + (pipe as usize) * PIPE_STRIDE; + let lines_reg = PLANE_WM_LINES_BASE + (pipe as usize) * PIPE_STRIDE; + self.mmio.write_u32(buf_cfg, 0); + self.mmio.write_u32(wm_reg, 0); + self.mmio.write_u32(lines_reg, 0); Ok(()) } diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs index e0d73208ea..d4ffb7ecb5 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs @@ -630,6 +630,8 @@ impl GpuDriver for IntelDriver { self.transcoder.configure(pipe.index, port, TransDdiMode::Dp, 4)?; } + self.watermark.program_for_mode(pipe.index, mode, true)?; + self.display.page_flip(&pipe, fb_addr)?; let mut crtcs = self