genode/repos/os/src/drivers/gpu/intel/mmio.h
2019-05-27 14:46:53 +02:00

1310 lines
36 KiB
C++

/*
* \brief Broadwell MMIO definitions
* \author Josef Soentgen
* \data 2017-03-15
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MMIO_H_
#define _MMIO_H_
/* Genode includes */
#include <base/log.h>
#include <util/mmio.h>
/* local includes */
#include <types.h>
namespace Igd {
class Mmio;
}
class Igd::Mmio : public Genode::Mmio
{
public:
enum {
/*
* XXX IDs are taken from Linux, still looking
* for a reference in the documentation
*/
RCS_ID = 0,
VCS_ID = 1,
BCS_ID = 2,
VECS_ID = 3,
VCS2_ID = 4,
NUM_ENGINES = 5,
NUM_FENCES = 32,
SIZE = 2u<<20,
};
static char const *engine_name(int id)
{
switch (id) {
case RCS_ID: return "RCS";
case VCS_ID: return "VCS";
case BCS_ID: return "BCS";
case VECS_ID: return "VECS";
case VCS2_ID: return "VCS2";
}
return "<unknown>";
}
/*************************
** Interrupt registers **
*************************/
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 953 ff.
*/
struct MASTER_INT_CTL : Register<0x44200, 32>
{
struct Master_interrupt_enable : Bitfield<31, 1> { };
struct Pcu_interrupts_pending : Bitfield<30, 1> { };
struct Audio_codec_interrupts_pending : Bitfield<24, 1> { };
struct De_pch_interrupts_pending : Bitfield<23, 1> { };
struct De_misc_interrupts_pending : Bitfield<22, 1> { };
struct De_port_interrupts_pending : Bitfield<20, 1> { };
struct De_pipe_c_interrupts_pending : Bitfield<18, 1> { };
struct De_pipe_b_interrupts_pending : Bitfield<17, 1> { };
struct De_pipe_a_interrupts_pending : Bitfield<16, 1> { };
struct Vebox_interrupts_pending : Bitfield< 6, 1> { };
struct Gtpm_interrupts_pending : Bitfield< 4, 1> { };
struct Vcs2_interrupts_pending : Bitfield< 3, 1> { };
struct Vcs1_interrupts_pending : Bitfield< 2, 1> { };
struct Blitter_interrupts_pending : Bitfield< 1, 1> { };
struct Render_interrupts_pending : Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 658 ff.
*/
template <long int REG>
struct GT_0_INTERRUPT : Register<REG, 32>
{
using B = Register<REG, 32>;
struct Bcs_wait_on_semaphore : B::template Bitfield<27, 1> { };
struct Bcs_ctx_switch_interrupt : B::template Bitfield<24, 1> { };
struct Bcs_mi_flush_dw_notify : B::template Bitfield<20, 1> { };
struct Bcs_error_interrupt : B::template Bitfield<19, 1> { };
struct Bcs_mi_user_interrupt : B::template Bitfield<16, 1> { };
struct Cs_wait_on_semaphore : B::template Bitfield<11, 1> { };
struct Cs_l3_counter_slave : B::template Bitfield<10, 1> { };
struct Cs_ctx_switch_interrupt : B::template Bitfield< 8, 1> { };
struct Page_fault_error : B::template Bitfield< 7, 1> { };
struct Cs_watchdog_counter_expired : B::template Bitfield< 6, 1> { };
struct L3_parity_error : B::template Bitfield< 5, 1> { };
struct Cs_pipe_control_notify : B::template Bitfield< 4, 1> { };
struct Cs_error_interrupt : B::template Bitfield< 3, 1> { };
struct Cs_mi_user_interrupt : B::template Bitfield< 0, 1> { };
};
struct GT_0_INTERRUPT_ISR : GT_0_INTERRUPT<0x44300> { };
struct GT_0_INTERRUPT_IMR : GT_0_INTERRUPT<0x44304> { };
struct GT_0_INTERRUPT_IIR : GT_0_INTERRUPT<0x44308> { };
struct GT_0_INTERRUPT_IER : GT_0_INTERRUPT<0x4430C> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 673 ff.
*/
template <long int REG>
struct GT_1_INTERRUPT : Register<REG, 32>
{
using B = Register<REG, 32>;
struct Vcs2_wait_on_semaphore : B::template Bitfield<27, 1> { };
struct Vcs2_ctx_switch_interrupt : B::template Bitfield<24, 1> { };
struct Vcs2_watchdog_counter_expired : B::template Bitfield<22, 1> { };
struct Vcs2_mi_flush_dw_notify : B::template Bitfield<20, 1> { };
struct Vcs2_error_interrupt : B::template Bitfield<19, 1> { };
struct Vcs2_mi_user_interrupt : B::template Bitfield<16, 1> { };
struct Vcs1_wait_on_semaphore : B::template Bitfield<11, 1> { };
struct Vcs1_ctx_switch_interrupt : B::template Bitfield< 8, 1> { };
struct Vcs1_watchdog_counter_expired : B::template Bitfield< 6, 1> { };
struct Vcs1_pipe_control_notify : B::template Bitfield< 4, 1> { };
struct Vcs1_error_interrupt : B::template Bitfield< 3, 1> { };
struct Vcs1_mi_user_interrupt : B::template Bitfield< 0, 1> { };
};
struct GT_1_INTERRUPT_ISR : GT_1_INTERRUPT<0x44310> { };
struct GT_1_INTERRUPT_IMR : GT_1_INTERRUPT<0x44314> { };
struct GT_1_INTERRUPT_IIR : GT_1_INTERRUPT<0x44318> { };
struct GT_1_INTERRUPT_IER : GT_1_INTERRUPT<0x4431C> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 687 ff.
*/
template <long int REG>
struct GT_2_INTERRUPT : Register<REG, 32>
{
using B = Register<REG, 32>;
struct Unslice_frequency_control_up_interrupt : B::template Bitfield<13, 1> { };
struct Unslice_frequency_control_down_interrupt : B::template Bitfield<12, 1> { };
struct Nfafdl_frequency_up_interrupt : B::template Bitfield<11, 1> { };
struct Nfafdl_frequency_down_interrupt : B::template Bitfield<10, 1> { };
struct Gtpm_engines_idle_interrupt : B::template Bitfield< 8, 1> { };
struct Gtpm_uncore_to_core_trap_interrupt : B::template Bitfield< 7, 1> { };
struct Gtpm_render_frequency_downwards_timeout_during_rc6_interrupt : B::template Bitfield< 6, 1> { };
struct Gtpm_render_p_state_up_threshold_interrupt : B::template Bitfield< 5, 1> { };
struct Gtpm_render_p_state_down_threshold_interrupt : B::template Bitfield< 4, 1> { };
struct Gtpm_render_geyserville_up_evaluation_interval_interrupt : B::template Bitfield< 2, 1> { };
struct Gtpm_render_geyserville_down_evaluation_interval_interrupt : B::template Bitfield< 1, 1> { };
};
struct GT_2_INTERRUPT_ISR : GT_2_INTERRUPT<0x44320> { };
struct GT_2_INTERRUPT_IMR : GT_2_INTERRUPT<0x44324> { };
struct GT_2_INTERRUPT_IIR : GT_2_INTERRUPT<0x44328> { };
struct GT_2_INTERRUPT_IER : GT_2_INTERRUPT<0x4432C> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 689 ff.
*/
template <long int REG>
struct GT_3_INTERRUPT : Register<REG, 32>
{
using B = Register<REG, 32>;
struct Performance_monitoring_buffer_half_full_interrupt : B::template Bitfield<28, 1> { };
struct Vecs_wait_on_semaphore : B::template Bitfield<11, 1> { };
struct Vecs_ctx_switch_interrupt : B::template Bitfield< 8, 1> { };
struct Vecs_mi_flush_dw_notify : B::template Bitfield< 4, 1> { };
struct Vecs_error_interrupt : B::template Bitfield< 3, 1> { };
struct Vecs_mi_user_interrupt : B::template Bitfield< 0, 1> { };
};
struct GT_3_INTERRUPT_ISR : GT_3_INTERRUPT<0x44330> { };
struct GT_3_INTERRUPT_IMR : GT_3_INTERRUPT<0x44334> { };
struct GT_3_INTERRUPT_IIR : GT_3_INTERRUPT<0x44338> { };
struct GT_3_INTERRUPT_IER : GT_3_INTERRUPT<0x4433C> { };
/**************************
** Page-table registers **
**************************/
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1169
*/
struct PAT_INDEX : Genode::Register<32>
{
struct Class_of_service : Bitfield<8, 2> { };
struct Lru_age : Bitfield<4, 2>
{
enum {
UCR = 0b00,
A0 = 0b01,
DNC = 0b10,
A3 = 0b11,
};
};
struct Target_cache : Bitfield<2, 2>
{
enum {
ELLC = 0b00,
LLC = 0b01,
LLCELLC = 0b10,
LLCeLLC = 0b11,
};
};
struct Mem_type : Bitfield<0, 2>
{
enum {
UC = 0b00,
WC = 0b01,
WT = 0b10,
WB = 0b11,
};
};
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1170
*/
struct PAT_INDEX_H : Register<0x040E0, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1071
*/
struct PAT_INDEX_L : Register<0x040E4, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1516 ff.
*/
struct TIMESTAMP_CTR : Register<0x44070, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 75
*
* TODO registers are not continuous
*/
struct FAULT_REG : Register_array<0x04000, 32, NUM_ENGINES, 32>
{
struct Engine_ID : Bitfield<12,3>
{
enum EID {
GFX = 0,
MFX0 = 1,
MFX1 = 2,
VEBX = 3,
BLT = 4
};
};
struct SRCID : Bitfield< 3,8> { };
struct Fault_Type : Bitfield< 1,2>
{
enum GFX_FT {
INVALID_PTE = 0,
INVALID_PDE = 1,
INVALID_PDPE = 2,
INVALID_PML4E = 3
};
};
struct Valid_Bit : Bitfield<0,1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 446
*/
struct FAULT_TLB_RB_DATA0 : Register<0x04B10, 32>
{
struct Fault_cycle_va : Bitfield<0, 32> { }; /* 43:12 */
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 447
*/
struct FAULT_TLB_RB_DATA1 : Register<0x04B14, 32>
{
struct Cycle_gtt_sel : Bitfield<4, 1> { };
struct Fault_cycle_va : Bitfield<0, 4> { }; /* 47:44 */
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1353 ff.
*/
struct RING_BUFFER_TAIL_RCSUNIT : Register<0x02030, 32>
{
struct Tail_Offset : Bitfield< 3, 18> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1350 ff.
*/
struct RING_BUFFER_HEAD_RCSUNIT : Register<0x02034, 32>
{
struct Wrap_Count : Bitfield<21, 11> { };
struct Head_Offset : Bitfield< 2, 19> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1352
*/
struct RING_BUFFER_START_RCSUNIT : Register<0x02038, 32>
{
struct Starting_Address : Bitfield<12, 20> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1345 ff.
*/
struct RING_BUFFER_CTL_RCSUNIT : Register<0x0203C, 32>
{
struct Buffer_length : Bitfield<12, 9> { };
struct RBWait : Bitfield<11, 1> { };
struct Semaphore_wait : Bitfield<10, 1> { };
struct Automatic_report_head_pointer : Bitfield< 1, 2>
{
enum {
MI_AUTOREPORT_OFF = 0,
MI_AUTOREPORT_64KB = 1,
MI_AUTOREPORT_4KB = 2,
MI_AUTO_REPORT_128KB = 3
};
};
struct Ring_buffer_enable : Bitfield< 0, 1> { };
};
/*********************
** Debug registers **
*********************/
/*
* Ancient (2008) Volume 1: Graphics Core p. 228
*/
struct IPEIR : Register<0x2064, 32>
{
struct Batch_buffer_error : Bitfield<3, 1> { };
};
/*
* Ancient (2008) Volume 1: Graphics Core p. 229
*/
struct IPEHR : Register<0x2068, 32> { };
/*
* Ancient (2008) Volume 1: Graphics Core p. 229
*/
template <long int BASE>
struct INSTDONE_BASE : Register<BASE + 0x6C, 32>
{
enum { DEFAULT_VALUE = 0xffe7fffe, };
};
struct RCS_INSTDONE : INSTDONE_BASE<0x2000>
{
struct Row_0_eu_0_done : Bitfield<31, 1> { };
struct Row_0_eu_1_done : Bitfield<30, 1> { };
struct Row_0_eu_2_done : Bitfield<29, 1> { };
struct Row_0_eu_3_done : Bitfield<28, 1> { };
struct Row_1_eu_0_done : Bitfield<27, 1> { };
struct Row_1_eu_1_done : Bitfield<26, 1> { };
struct Row_1_eu_2_done : Bitfield<25, 1> { };
struct Row_1_eu_3_done : Bitfield<24, 1> { };
struct Sf_done : Bitfield<23, 1> { };
struct Se_done : Bitfield<22, 1> { };
struct Windower_done : Bitfield<21, 1> { };
struct Reserved1 : Bitfield<20, 1> { };
struct Reserved2 : Bitfield<19, 1> { };
struct Dip_done : Bitfield<18, 1> { };
struct Pl_done : Bitfield<17, 1> { };
struct Dg_done : Bitfield<16, 1> { };
struct Qc_done : Bitfield<15, 1> { };
struct Ft_done : Bitfield<14, 1> { };
struct Dm_done : Bitfield<13, 1> { };
struct Sc_done : Bitfield<12, 1> { };
struct Fl_done : Bitfield<11, 1> { };
struct By_done : Bitfield<10, 1> { };
struct Ps_done : Bitfield< 9, 1> { };
struct Cc_done : Bitfield< 8, 1> { };
struct Map_fl_done : Bitfield< 7, 1> { };
struct Map_l2_idle : Bitfield< 6, 1> { };
struct Msg_arb_0_done : Bitfield< 5, 1> { };
struct Msg_arb_1_done : Bitfield< 4, 1> { };
struct Ic_row_0_done : Bitfield< 3, 1> { };
struct Ic_row_1_done : Bitfield< 2, 1> { };
struct Cp_done : Bitfield< 1, 1> { };
struct Ring_0_enable : Bitfield< 0, 1> { };
};
/*
* Ancient (2008) Volume 1: Graphics Core p. 229
*/
template <long int BASE>
struct INSTDONE_1_BASE : Register<BASE + 0x7C, 32>
{
enum { DEFAULT_VALUE = 0x0, };
};
struct RCS_INSTDONE_1 : INSTDONE_1_BASE<0x2000> { };
/*
* Ancient (2008) Volume 1: Graphics Core p. 231
*/
template <long int BASE>
struct ACTHD_BASE : Register<BASE + 0x74, 32>
{
using B = Register<BASE + 0x74, 32>;
struct Head_pointer : B::template Bitfield<2, 30> { };
struct Reserved : B::template Bitfield<0, 2> { }; /* MBZ */
};
struct RCS_ACTHD : ACTHD_BASE<0x2000> { };
/*
* Ancient (2008) Volume 1: Graphics Core p. 205
*/
struct PGTBL_ER : Register<0x2024, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 618 ff.
*/
struct GFX_MODE : Register<0x0229C, 32>
{
struct Mask_bits : Bitfield<16, 16> { };
struct Execlist_enable_mask : Bitfield<31, 1> { };
struct Execlist_enable : Bitfield<15, 1> { };
struct Ppgtt_enable_mask : Bitfield<25, 1> { };
struct Ppgtt_enable : Bitfield< 9, 1> { };
struct Virtual_addressing_enable_mask : Bitfield<23, 1> { };
struct Virtual_addressing_enable : Bitfield< 7, 1> { };
struct Privilege_check_disable_mask : Bitfield<16, 1> { };
struct Privilege_check_disable : Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 6-11.15 p. 19 ff.
* IHD-OS-BDW-Vol 7-11.15 p. 42
*/
struct RCS_RING_CONTEXT_STATUS_PTR : Register<0x023A0, 32>
{
struct Read_pointer_mask : Bitfield<24, 8> { };
struct Write_pointer_mask : Bitfield<16, 8> { };
struct Read_pointer : Bitfield< 8, 8> { };
struct Write_pointer : Bitfield< 0, 8> { };
};
/*********************
** Error registers **
*********************/
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 413
*/
template <long int BASE>
struct EIR_BASE : Register<BASE + 0xB0, 32>
{
using B = Register<BASE + 0xB0, 32>;
struct Reserved : B::template Bitfield<16, 16> { }; /* MBZ */
struct Error_identity_bits : B::template Bitfield< 0, 16> { };
};
struct RCS_EIR : EIR_BASE<0x2000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 414
*/
template <long int BASE>
struct EMR_BASE : Register<BASE + 0xB4, 32>
{
using B = Register<BASE + 0xB4, 32>;
struct Reserved : B::template Bitfield<8, 24> { }; /* MBO */
struct Error_mask_bits : B::template Bitfield<0, 8> { };
struct Error_page_table : B::template Bitfield<4, 1> { };
struct Error_mem_refresh : B::template Bitfield<1, 1> { };
};
struct RCS_EMR : EMR_BASE<0x2000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 415 ff.
*/
/* struct ERR */
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 417
*/
template <long int BASE>
struct ESR_BASE : Register<BASE + 0xB8, 32>
{
using B = Register<BASE + 0xB8, 32>;
struct Reserved : B::template Bitfield<16, 16> { }; /* MBZ */
struct Error_status_bits : B::template Bitfield< 0, 16> { };
};
struct RCS_ESR : ESR_BASE<0x2000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 944 ff.
*/
struct ERROR : Register<0x040A0, 32>
{
struct Ctx_fault_ctxt_not_prsnt_err : Bitfield<15, 1> { }; /* typo in PRM (prsmt) */
struct Ctx_fault_root_not_prsnt_err : Bitfield<14, 1> { }; /* " */
struct Ctx_fault_pasid_not_prsnt_err : Bitfield<13, 1> { };
struct Ctx_fault_pasid_ovflw_err : Bitfield<12, 1> { };
struct Ctx_fault_pasid_dis_err : Bitfield<11, 1> { };
struct Rstrm_fault_nowb_atomic_err : Bitfield<10, 1> { };
struct Unloaded_pd_error : Bitfield< 8, 1> { };
struct Hws_page_fault_error : Bitfield< 3, 1> { };
struct Invalid_page_directory_entry_error : Bitfield< 2, 1> { };
struct Ctx_page_fault_error : Bitfield< 1, 1> { };
struct Tlb_fault_error : Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 948
*/
struct ERROR_2 : Register<0x040A4, 32>
{
struct Tlbpend_reg_faultcnt : Bitfield< 0, 6> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1237
*/
struct PP_PFD : Register<0x04580, 32>
{
struct Fault_entry_page_address : Bitfield<12, 20> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1315 ff.
*/
struct RC_CTRL0 : Register<0x0A090, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1317 ff.
*/
struct RC_CTRL1 : Register<0x0A094, 32>
{
struct Rc_state : Bitfield<18, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1095
*/
struct NDE_RSTWRN_OPT : Register<0x46408, 32>
{
struct Rst_pch_handshake_en : Bitfield<4, 1> { };
};
/*
* XXX documentation reference missing
*/
struct PWR_WELL_CTL2 : Register<0x45404, 32>
{
struct Misc_io_power_state : Bitfield< 0, 1> { };
struct Misc_io_power_request : Bitfield< 1, 1> { };
struct Ddi_a_and_ddi_e_io_power_state : Bitfield< 2, 1> { };
struct Ddi_a_and_ddi_e_io_power_request : Bitfield< 3, 1> { };
struct Ddi_b_io_power_state : Bitfield< 4, 1> { };
struct Ddi_b_io_power_request : Bitfield< 5, 1> { };
struct Ddi_c_io_power_state : Bitfield< 6, 1> { };
struct Ddi_c_io_power_request : Bitfield< 7, 1> { };
struct Ddi_d_io_power_state : Bitfield< 8, 1> { };
struct Ddi_d_io_power_request : Bitfield< 9, 1> { };
struct Power_well_1_state : Bitfield<28, 1> { };
struct Power_well_1_request : Bitfield<29, 1> { };
struct Power_well_2_state : Bitfield<30, 1> { };
struct Power_well_2_request : Bitfield<31, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 853
*/
struct L3_LRA_1_GPGPU : Register<0x04DD4, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 711
*/
struct HWSTAM : Register<0x02098, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 712
*/
struct HWS_PGA_RCSUNIT : Register<0x02080, 32> { };
struct HWS_PGA_VCSUNIT0 : Register<0x12080, 32> { };
struct HWS_PGA_VECSUNIT : Register<0x1A080, 32> { };
struct HWS_PGA_VCSUNIT1 : Register<0x1C080, 32> { };
struct HWS_PGA_BCSUNIT : Register<0x22080, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1370
*/
struct RP_FREQ_NORMAL : Register<0x0A008, 32>
{
struct Turbo_disable : Bitfield<31, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 1318
*/
struct RP_CTRL : Register<0xA024, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 493
*/
/*
reg_post is in the same cacheline as FORCEWAKE and is
read after FORCEWAKE was written to prevent reordering
when reading from FORCEWAKE_ACK_HSW [1] (older driver
version used a different register for posting reads but
that did not work on certain older (~2012) machines.
[1] https://lists.freedesktop.org/archives/intel-gfx/2015-January/058101.html
*/
enum { FORCEWAKE_ID_RENDER = 0, };
struct FORCEWAKE_MT : Register<0x0A188, 32>
{
enum {
RESET = 0xffff0000u,
};
struct Multiple_force_wake_mask : Bitfield<16, 16> { };
struct Force_wake_request_for_thread_15 : Bitfield<15, 1> { };
struct Force_wake_request_for_thread_14 : Bitfield<14, 1> { };
struct Force_wake_request_for_thread_13 : Bitfield<13, 1> { };
struct Force_wake_request_for_thread_12 : Bitfield<12, 1> { };
struct Force_wake_request_for_thread_11 : Bitfield<11, 1> { };
struct Force_wake_request_for_thread_10 : Bitfield<10, 1> { };
struct Force_wake_request_for_thread_9 : Bitfield< 9, 1> { };
struct Force_wake_request_for_thread_8 : Bitfield< 8, 1> { };
struct Force_wake_request_for_thread_7 : Bitfield< 7, 1> { };
struct Force_wake_request_for_thread_6 : Bitfield< 6, 1> { };
struct Force_wake_request_for_thread_5 : Bitfield< 5, 1> { };
struct Force_wake_request_for_thread_4 : Bitfield< 4, 1> { };
struct Force_wake_request_for_thread_3 : Bitfield< 3, 1> { };
struct Force_wake_request_for_thread_2 : Bitfield< 2, 1> { };
struct Force_wake_request_for_thread_1 : Bitfield< 1, 1> { };
struct Force_wake_request_for_thread_0 : Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 703
*
* also known as FORCEWAKE_ACK_HSW in the Linux driver
*/
struct GTSP1 : Register<0x130044, 32> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 606
*
* also known as ECOBUS in the Linux driver
*/
struct MISC_CTRL0 : Register<0x0A180, 32> { };
/*
* Reset control registers
*
* adds offset to given BASE address
*/
template <long int BASE>
struct RESET_CTRL_BASE : Register<BASE + 0xD0, 32>
{
using B = Register<BASE + 0xD0, 32>;
struct Mask_bits : B::template Bitfield<16, 15> { };
struct Ready_for_reset : B::template Bitfield< 1, 1> { };
struct Request_reset : B::template Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 288
*/
struct CS_RESET_CTRL : RESET_CTRL_BASE<0x02000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 165
*/
struct BCS_RESET_CTRL : RESET_CTRL_BASE<0x22000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 609 ff.
*/
struct GDRST : Register<0x0941C, 32>
{
struct Graphics_media1_soft_reset_ctl : Bitfield<6, 1> { };
struct Graphics_widi_soft_reset_ctl : Bitfield<6, 1> { };
struct Graphics_vebox_soft_reset_ctl : Bitfield<4, 1> { };
struct Graphics_blitter_soft_reset_ctl : Bitfield<3, 1> { };
struct Graphics_media_soft_reset_ctl : Bitfield<2, 1> { };
struct Graphics_render_soft_reset_ctl : Bitfield<1, 1> { };
struct Graphics_full_soft_reset_ctl : Bitfield<0, 1> { };
};
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 611 ff.
*/
struct FENCE_REG : Register_array<0x100000, 64, NUM_FENCES, 64>
{
struct Fence_upper_bound : Bitfield<44, 20> { };
struct Fence_pitch : Bitfield<32, 11> { };
struct Fence_lower_bound : Bitfield<12, 20> { };
struct Tile_walk : Bitfield< 1, 1> { };
struct Fence_valid : Bitfield< 0, 1> { };
};
/*
* IHD-OS-BDW-Vol 12-11.15 p. 5
*/
struct GFX_FLSH_CNTL : Register<0x101008, 32> { };
/************************
** EXECLIST registers **
************************/
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 435
*/
template <long int BASE>
struct EXECLIST_STATUS_BASE : Register<BASE + 0x234, 64>
{
using B = Register<BASE + 0x234, 64>;
struct Current_context_id : B::template Bitfield<32, 32> { };
struct Arbitration_enable : B::template Bitfield<16, 1> { };
struct Current_active_element_status : B::template Bitfield<14, 2>
{
enum {
NO_ACTIVE_ELEMENT = 0b00,
ELEMENT_0_ACTIVE = 0b01,
ELEMENT_1_ACTIVE = 0b10,
RESERVERD = 0b11,
};
};
struct Last_context_switch_reason : B::template Bitfield< 5, 9> { };
struct Execlist_0_valid : B::template Bitfield< 4, 1> { };
struct Execlist_1_valid : B::template Bitfield< 3, 1> { };
struct Execlist_queue_full : B::template Bitfield< 2, 1> { };
struct Execlist_write_pointer : B::template Bitfield< 1, 1> { };
struct Current_execlist_pointer : B::template Bitfield< 0, 1> { };
};
struct EXECLIST_STATUS_RSCUNIT : EXECLIST_STATUS_BASE<0x02000> { };
struct EXECLIST_STATUS_VCSUNIT0 : EXECLIST_STATUS_BASE<0x12000> { };
struct EXECLIST_STATUS_VECSUNIT : EXECLIST_STATUS_BASE<0x1A000> { };
struct EXECLIST_STATUS_VCSUNIT1 : EXECLIST_STATUS_BASE<0x1C000> { };
struct EXECLIST_STATUS_BSCUNIT : EXECLIST_STATUS_BASE<0x22000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 438
*/
template <long int BASE>
struct EXECLIST_SUBMITPORT_BASE : Register<BASE + 0x230, 32>
{
using B = Register<BASE + 0x230, 32>;
struct Context_descriptor_dw : B::template Bitfield<0, 32> { };
};
struct EXECLIST_SUBMITPORT_RSCUNIT : EXECLIST_SUBMITPORT_BASE<0x02000> { };
struct EXECLIST_SUBMITPORT_VCSUNIT0 : EXECLIST_SUBMITPORT_BASE<0x12000> { };
struct EXECLIST_SUBMITPORT_VECSUNIT : EXECLIST_SUBMITPORT_BASE<0x1A000> { };
struct EXECLIST_SUBMITPORT_VCSUNIT1 : EXECLIST_SUBMITPORT_BASE<0x1C000> { };
struct EXECLIST_SUBMITPORT_BSCUNIT : EXECLIST_SUBMITPORT_BASE<0x22000> { };
/*
* IHD-OS-BDW-Vol 2c-11.15 p. 266 ff.
* IHD-OS-BDW-Vol 6-11.15 p. 19 ff.
*/
enum {
CTXT_ST_BUF_QW_NUM = 8,
CTXT_ST_BUF_NUM = 6,
};
template <long int BASE>
struct CTXT_ST_BUF_BASE : Register_array<BASE + 0x370, 64, CTXT_ST_BUF_NUM, 64>
{
using B = Register_array<BASE + 0x370, 64, CTXT_ST_BUF_NUM, 64>;
/*
* Judging by the documentation it seems that one context status
* buffer in fact contains the same DWORD twice.
*/
struct Context_status_udw : B::template Bitfield<32, 32> { };
struct Context_status_ldw : B::template Bitfield< 0, 32> { };
};
struct CTXT_ST_BUF_RCSUNIT : CTXT_ST_BUF_BASE<0x2000> { };
struct PGTBL_CTL2 : Register<0x20C4, 32> { };
private:
Mmio::Delayer &_delayer;
void _fw_reset()
{
using namespace Genode;
/* "needs to be initialized by newly loaded gfx driver" */
write_post<FORCEWAKE_MT>(FORCEWAKE_MT::RESET);
read<MISC_CTRL0>();
}
/**
* Set forcewake state, i.e., prevent GT from powering down
*/
void _fw_enable(unsigned id)
{
using namespace Genode;
unsigned const i = 1u << id;
FORCEWAKE_MT::access_t v = 0;
FORCEWAKE_MT::Multiple_force_wake_mask::set(v, i);
FORCEWAKE_MT::Force_wake_request_for_thread_0::set(v, i);
write<FORCEWAKE_MT>(v);
read<MISC_CTRL0>();
try {
wait_for(Attempts(50), Microseconds(1000), _delayer,
GTSP1::Equal(1));
} catch (Polling_timeout) {
error("could not enable force-wake engine");
}
}
/**
* Clear forcewake state
*/
void _fw_disable(unsigned id)
{
using namespace Genode;
unsigned const i = 1u << id;
FORCEWAKE_MT::access_t v = 0;
FORCEWAKE_MT::Multiple_force_wake_mask::set(v, i);
write<FORCEWAKE_MT>(v);
read<MISC_CTRL0>();
try {
wait_for(Attempts(50), Microseconds(1000), _delayer,
GTSP1::Equal(0));
} catch (Polling_timeout) {
error("could not disable force-wake engine");
}
}
/**
* Reset interrupts
*/
void _intr_reset()
{
write_post<MASTER_INT_CTL>(0);
write_post<GT_0_INTERRUPT_IMR>(0xffffffff);
write<GT_0_INTERRUPT_IER>(0);
/* do it like they do in Rome^WLinux */
write_post<GT_0_INTERRUPT_IIR>(0xffffffff);
write_post<GT_0_INTERRUPT_IIR>(0xffffffff);
/* mask all in the hardware status mask register */
write_post<HWSTAM>(0xffffffff);
/* TODO DE intr handling (p. 363) */
}
/**
* Enable interrupts
*/
void _intr_enable()
{
using namespace Genode;
/* GT0 RCS/BCS */
{
uint32_t tmp = read<GT_0_INTERRUPT_IIR>();
if (tmp != 0) { error("GT_0_INTERRUPT_IIR not zero"); }
GT_0_INTERRUPT_IER::access_t ier = 0;
GT_0_INTERRUPT_IER::Cs_mi_user_interrupt::set(ier, 1);
GT_0_INTERRUPT_IER::Cs_ctx_switch_interrupt::set(ier, 1);
GT_0_INTERRUPT_IER::Bcs_mi_user_interrupt::set(ier, 1);
GT_0_INTERRUPT_IER::Bcs_ctx_switch_interrupt::set(ier, 1);
write<GT_0_INTERRUPT_IER>(ier);
GT_0_INTERRUPT_IMR::access_t imr = ~0u;
GT_0_INTERRUPT_IMR::Cs_mi_user_interrupt::set(imr, 0);
GT_0_INTERRUPT_IMR::Cs_ctx_switch_interrupt::set(imr, 0);
GT_0_INTERRUPT_IMR::Bcs_mi_user_interrupt::set(imr, 0);
GT_0_INTERRUPT_IMR::Bcs_ctx_switch_interrupt::set(imr, 0);
write_post<GT_0_INTERRUPT_IMR>(imr);
/* demask also in the hardware status mask register */
write_post<HWSTAM>(imr);
}
/* GT1 VCS1/VCS2 */
{
uint32_t tmp = read<GT_1_INTERRUPT_IIR>();
if (tmp != 0) { error("GT_1_INTERRUPT_IIR not zero"); }
GT_1_INTERRUPT_IER::access_t ier = 0;
GT_1_INTERRUPT_IER::Vcs1_mi_user_interrupt::set(ier, 1);
GT_1_INTERRUPT_IER::Vcs1_ctx_switch_interrupt::set(ier, 1);
GT_1_INTERRUPT_IER::Vcs2_mi_user_interrupt::set(ier, 1);
GT_1_INTERRUPT_IER::Vcs2_ctx_switch_interrupt::set(ier, 1);
write<GT_1_INTERRUPT_IER>(ier);
GT_1_INTERRUPT_IMR::access_t imr = ~0u;
GT_1_INTERRUPT_IMR::Vcs1_mi_user_interrupt::set(imr, 0);
GT_1_INTERRUPT_IMR::Vcs1_ctx_switch_interrupt::set(imr, 0);
GT_1_INTERRUPT_IMR::Vcs2_mi_user_interrupt::set(imr, 0);
GT_1_INTERRUPT_IMR::Vcs2_ctx_switch_interrupt::set(imr, 0);
write_post<GT_1_INTERRUPT_IMR>(imr);
}
/* GT2 GTPM */
{
uint32_t tmp = read<GT_2_INTERRUPT_IIR>();
if (tmp != 0) { error("GT_2_INTERRUPT_IIR not zero"); }
GT_2_INTERRUPT_IER::access_t ier = 0;
write<GT_2_INTERRUPT_IER>(ier);
GT_2_INTERRUPT_IMR::access_t imr = ~0u;
write_post<GT_2_INTERRUPT_IMR>(imr);
}
/* GT3 VECS*/
{
uint32_t tmp = read<GT_3_INTERRUPT_IIR>();
if (tmp != 0) { error("GT_3_INTERRUPT_IIR not zero"); }
GT_3_INTERRUPT_IER::access_t ier = 0;
GT_3_INTERRUPT_IER::Vecs_mi_user_interrupt::set(ier, 1);
GT_3_INTERRUPT_IER::Vecs_ctx_switch_interrupt::set(ier, 1);
write<GT_3_INTERRUPT_IER>(ier);
GT_3_INTERRUPT_IMR::access_t imr = ~0u;
GT_3_INTERRUPT_IMR::Vecs_mi_user_interrupt::set(imr, 0);
GT_3_INTERRUPT_IMR::Vecs_ctx_switch_interrupt::set(imr, 0);
write_post<GT_3_INTERRUPT_IMR>(imr);
}
/* finally enable interrupts */
write_post<MASTER_INT_CTL::Master_interrupt_enable>(1);
}
/**
* Disable Render P-states
*/
void _disable_rps()
{
/*
* Set RC0 state -- does not matter at this point b/c
* we disable RC states entirely.
*/
write_post<RC_CTRL1::Rc_state>(0);
write<RC_CTRL0>(0);
write<RP_FREQ_NORMAL::Turbo_disable>(1);
write<RP_CTRL>(0);
}
/**
* Reset fence registers
*/
void _reset_fences()
{
for (int i = 0; i < NUM_FENCES; i++) {
write<FENCE_REG>(i, 0);
read<FENCE_REG>(i);
}
}
/**
* Clear fault registers of all engines
*/
void _clear_fault_regs()
{
/* TODO */
}
/**
* Flush GFX TLB in the system agent
*/
void _gfx_flush_cntl()
{
write_post<GFX_FLSH_CNTL>(1);
}
/**
* Setup page attributes
*/
void _set_page_attributes()
{
enum { NUM_PAT = 8, };
PAT_INDEX::access_t p[NUM_PAT] = {};
unsigned const mt[NUM_PAT] {
PAT_INDEX::Mem_type::WB,
PAT_INDEX::Mem_type::WC,
PAT_INDEX::Mem_type::WT,
PAT_INDEX::Mem_type::UC,
PAT_INDEX::Mem_type::WB,
PAT_INDEX::Mem_type::WB,
PAT_INDEX::Mem_type::WB,
PAT_INDEX::Mem_type::WB,
};
unsigned const tc[NUM_PAT] {
PAT_INDEX::Target_cache::LLC,
PAT_INDEX::Target_cache::LLCELLC,
PAT_INDEX::Target_cache::LLCELLC,
PAT_INDEX::Target_cache::ELLC,
PAT_INDEX::Target_cache::LLCELLC,
PAT_INDEX::Target_cache::LLCELLC,
PAT_INDEX::Target_cache::LLCELLC,
PAT_INDEX::Target_cache::LLCELLC,
};
unsigned const la[NUM_PAT] {
PAT_INDEX::Lru_age::UCR,
PAT_INDEX::Lru_age::UCR,
PAT_INDEX::Lru_age::UCR,
PAT_INDEX::Lru_age::UCR,
PAT_INDEX::Lru_age::UCR,
PAT_INDEX::Lru_age::A0,
PAT_INDEX::Lru_age::DNC,
PAT_INDEX::Lru_age::A3,
};
uint64_t v = 0u;
for (int i = 0; i < NUM_PAT; i++) {
PAT_INDEX::Lru_age::set( p[i], la[i]);
PAT_INDEX::Mem_type::set( p[i], mt[i]);
PAT_INDEX::Target_cache::set(p[i], tc[i]);
v |= (p[i] & 0xff) << (8 * i);
}
write<PAT_INDEX_L>(v);
write<PAT_INDEX_H>(v >> 32);
}
/**
* Reset engine
*/
template <typename REG>
bool _reset_engine()
{
typename REG::access_t v = 0;
REG::Mask_bits::set(v, 1);
REG::Request_reset::set(v, 1);
write_post<REG>(v);
try {
wait_for(Attempts(35), Microseconds(20), _delayer,
typename REG::Ready_for_reset::Equal(1));
} catch (Mmio::Polling_timeout) {
Genode::error("could not reset engine");
return false;
}
return true;
}
/**
* Reset engine by using hardware id
*
* \param id hardware id of the engine to be resetted
*/
bool _reset_engine(unsigned id)
{
switch (id) {
case RCS_ID: return _reset_engine<CS_RESET_CTRL>();
case BCS_ID: return _reset_engine<BCS_RESET_CTRL>();
default: return true;
}
}
bool _reset_engines()
{
for (int i = 0; i < NUM_ENGINES; i++) {
if (!_reset_engine(i)) { return false; }
}
return true;
}
/**
* Reset device
*/
void _reset_device()
{
_fw_enable(FORCEWAKE_ID_RENDER);
bool res = _reset_engines();
if (!res) {
Genode::warning("cannot reset device, engines not ready");
return;
}
write<GDRST::Graphics_full_soft_reset_ctl>(1);
try {
wait_for(Attempts(50), Microseconds(10), _delayer,
GDRST::Graphics_full_soft_reset_ctl::Equal(0));
} catch (Mmio::Polling_timeout) {
Genode::error("resetting device failed");
}
_fw_disable(FORCEWAKE_ID_RENDER);
}
/**
* Disable north DE handshake
*/
void _disable_nde_handshake()
{
NDE_RSTWRN_OPT::access_t v = read<NDE_RSTWRN_OPT>();
NDE_RSTWRN_OPT::Rst_pch_handshake_en::set(v, 0);
write<NDE_RSTWRN_OPT>(v);
}
/**
* Enable execlist
*/
void _enable_execlist()
{
GFX_MODE::access_t v = read<GFX_MODE>();
GFX_MODE::Execlist_enable_mask::set(v, 1);
GFX_MODE::Execlist_enable::set(v, 1);
write<GFX_MODE>(v);
}
public:
Mmio(Mmio::Delayer &delayer, addr_t const base)
: Genode::Mmio(base), _delayer(delayer) { }
template <typename T>
void write_post(typename T::access_t const value)
{
write<T>(value);
(void)read<T>();
}
void forcewake_enable() { _fw_enable(FORCEWAKE_ID_RENDER); }
void forcewake_disable() { _fw_disable(FORCEWAKE_ID_RENDER); }
void reset()
{
_intr_reset();
_reset_device();
_fw_reset();
_reset_fences();
_disable_nde_handshake();
_set_page_attributes();
}
void init()
{
_disable_rps();
_enable_execlist();
}
void enable_intr()
{
write<Igd::Mmio::RCS_EMR>(0xffffff00);
_intr_enable();
}
void disable_master_irq()
{
write_post<Igd::Mmio::MASTER_INT_CTL::Master_interrupt_enable>(0);
}
void enable_master_irq()
{
write_post<Igd::Mmio::MASTER_INT_CTL::Master_interrupt_enable>(1);
}
void flush_gfx_tlb() { _gfx_flush_cntl(); }
void clear_errors()
{
write_post<ERROR>(0);
}
void update_context_status_pointer()
{
RCS_RING_CONTEXT_STATUS_PTR::access_t const wp = read<RCS_RING_CONTEXT_STATUS_PTR::Write_pointer>();
if (wp > 0x05) {
Genode::warning("ring context status write-pointer invalid");
return;
}
RCS_RING_CONTEXT_STATUS_PTR::access_t v = 0;
RCS_RING_CONTEXT_STATUS_PTR::Read_pointer_mask::set(v, 0xff);
RCS_RING_CONTEXT_STATUS_PTR::Read_pointer::set(v, wp);
write<RCS_RING_CONTEXT_STATUS_PTR>(v);
}
bool csb_unread()
{
RCS_RING_CONTEXT_STATUS_PTR::access_t const r = read<RCS_RING_CONTEXT_STATUS_PTR::Read_pointer>();
RCS_RING_CONTEXT_STATUS_PTR::access_t const w = read<RCS_RING_CONTEXT_STATUS_PTR::Write_pointer>();
return (r != w) && (r + 1) % CTXT_ST_BUF_NUM <= w; /* XXX */
}
uint32_t find_free_fence()
{
uint32_t id = 0xff;
for (int i = 0; i < NUM_FENCES; i++) {
if (!read<FENCE_REG::Fence_valid>(i)) {
id = i;
break;
}
}
return id;
}
uint32_t update_fence(uint32_t id, addr_t lower, addr_t upper,
uint32_t pitch, bool x)
{
FENCE_REG::access_t v = 0;
typename FENCE_REG::access_t const l = lower >> 12;
typename FENCE_REG::access_t const u = upper >> 12;
FENCE_REG::Fence_upper_bound::set(v, u);
FENCE_REG::Fence_lower_bound::set(v, l);
FENCE_REG::Fence_pitch::set(v, pitch);
enum { MI_TILE_XMAJOR = 0b00, MI_TILE_YMAJOR = 0b01, };
FENCE_REG::Tile_walk::set(v, x ? MI_TILE_XMAJOR : MI_TILE_YMAJOR);
FENCE_REG::Fence_valid::set(v, 1);
write<FENCE_REG>(v, id);
(void)read<FENCE_REG>(id);
return id;
}
void clear_fence(uint32_t const id)
{
write<FENCE_REG>(0, id);
(void)read<FENCE_REG>(id);
}
/**
* Check if fault
*/
bool fault_regs_valid()
{
bool result = false;
/* TODO */
return result;
}
/*********************
** DEBUG interface **
*********************/
void dump();
void power_dump();
void error_dump();
void intr_dump();
void fault_dump();
void execlist_status_dump();
void context_status_pointer_dump();
};
#endif /* _MMIO_H_ */