cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dcn20_hubbub.c (20976B)


      1/*
      2 * Copyright 2016 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: AMD
     23 *
     24 */
     25
     26
     27#include "dcn20_hubbub.h"
     28#include "reg_helper.h"
     29#include "clk_mgr.h"
     30
     31#define REG(reg)\
     32	hubbub1->regs->reg
     33
     34#define CTX \
     35	hubbub1->base.ctx
     36
     37#undef FN
     38#define FN(reg_name, field_name) \
     39	hubbub1->shifts->field_name, hubbub1->masks->field_name
     40
     41#define REG(reg)\
     42	hubbub1->regs->reg
     43
     44#define CTX \
     45	hubbub1->base.ctx
     46
     47#undef FN
     48#define FN(reg_name, field_name) \
     49	hubbub1->shifts->field_name, hubbub1->masks->field_name
     50
     51#ifdef NUM_VMID
     52#undef NUM_VMID
     53#endif
     54#define NUM_VMID 16
     55
     56bool hubbub2_dcc_support_swizzle(
     57		enum swizzle_mode_values swizzle,
     58		unsigned int bytes_per_element,
     59		enum segment_order *segment_order_horz,
     60		enum segment_order *segment_order_vert)
     61{
     62	bool standard_swizzle = false;
     63	bool display_swizzle = false;
     64	bool render_swizzle = false;
     65
     66	switch (swizzle) {
     67	case DC_SW_4KB_S:
     68	case DC_SW_64KB_S:
     69	case DC_SW_VAR_S:
     70	case DC_SW_4KB_S_X:
     71	case DC_SW_64KB_S_X:
     72	case DC_SW_VAR_S_X:
     73		standard_swizzle = true;
     74		break;
     75	case DC_SW_64KB_R_X:
     76		render_swizzle = true;
     77		break;
     78	case DC_SW_4KB_D:
     79	case DC_SW_64KB_D:
     80	case DC_SW_VAR_D:
     81	case DC_SW_4KB_D_X:
     82	case DC_SW_64KB_D_X:
     83	case DC_SW_VAR_D_X:
     84		display_swizzle = true;
     85		break;
     86	default:
     87		break;
     88	}
     89
     90	if (standard_swizzle) {
     91		if (bytes_per_element == 1) {
     92			*segment_order_horz = segment_order__contiguous;
     93			*segment_order_vert = segment_order__na;
     94			return true;
     95		}
     96		if (bytes_per_element == 2) {
     97			*segment_order_horz = segment_order__non_contiguous;
     98			*segment_order_vert = segment_order__contiguous;
     99			return true;
    100		}
    101		if (bytes_per_element == 4) {
    102			*segment_order_horz = segment_order__non_contiguous;
    103			*segment_order_vert = segment_order__contiguous;
    104			return true;
    105		}
    106		if (bytes_per_element == 8) {
    107			*segment_order_horz = segment_order__na;
    108			*segment_order_vert = segment_order__contiguous;
    109			return true;
    110		}
    111	}
    112	if (render_swizzle) {
    113		if (bytes_per_element == 2) {
    114			*segment_order_horz = segment_order__contiguous;
    115			*segment_order_vert = segment_order__contiguous;
    116			return true;
    117		}
    118		if (bytes_per_element == 4) {
    119			*segment_order_horz = segment_order__non_contiguous;
    120			*segment_order_vert = segment_order__contiguous;
    121			return true;
    122		}
    123		if (bytes_per_element == 8) {
    124			*segment_order_horz = segment_order__contiguous;
    125			*segment_order_vert = segment_order__non_contiguous;
    126			return true;
    127		}
    128	}
    129	if (display_swizzle && bytes_per_element == 8) {
    130		*segment_order_horz = segment_order__contiguous;
    131		*segment_order_vert = segment_order__non_contiguous;
    132		return true;
    133	}
    134
    135	return false;
    136}
    137
    138bool hubbub2_dcc_support_pixel_format(
    139		enum surface_pixel_format format,
    140		unsigned int *bytes_per_element)
    141{
    142	/* DML: get_bytes_per_element */
    143	switch (format) {
    144	case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
    145	case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
    146		*bytes_per_element = 2;
    147		return true;
    148	case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
    149	case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
    150	case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
    151	case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
    152	case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX:
    153	case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX:
    154	case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT:
    155	case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT:
    156	case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
    157	case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
    158		*bytes_per_element = 4;
    159		return true;
    160	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
    161	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
    162	case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
    163	case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
    164		*bytes_per_element = 8;
    165		return true;
    166	default:
    167		return false;
    168	}
    169}
    170
    171static void hubbub2_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
    172		unsigned int bytes_per_element)
    173{
    174	/* copied from DML.  might want to refactor DML to leverage from DML */
    175	/* DML : get_blk256_size */
    176	if (bytes_per_element == 1) {
    177		*blk256_width = 16;
    178		*blk256_height = 16;
    179	} else if (bytes_per_element == 2) {
    180		*blk256_width = 16;
    181		*blk256_height = 8;
    182	} else if (bytes_per_element == 4) {
    183		*blk256_width = 8;
    184		*blk256_height = 8;
    185	} else if (bytes_per_element == 8) {
    186		*blk256_width = 8;
    187		*blk256_height = 4;
    188	}
    189}
    190
    191static void hubbub2_det_request_size(
    192		unsigned int detile_buf_size,
    193		unsigned int height,
    194		unsigned int width,
    195		unsigned int bpe,
    196		bool *req128_horz_wc,
    197		bool *req128_vert_wc)
    198{
    199	unsigned int blk256_height = 0;
    200	unsigned int blk256_width = 0;
    201	unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
    202
    203	hubbub2_get_blk256_size(&blk256_width, &blk256_height, bpe);
    204
    205	swath_bytes_horz_wc = width * blk256_height * bpe;
    206	swath_bytes_vert_wc = height * blk256_width * bpe;
    207
    208	*req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
    209			false : /* full 256B request */
    210			true; /* half 128b request */
    211
    212	*req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
    213			false : /* full 256B request */
    214			true; /* half 128b request */
    215}
    216
    217bool hubbub2_get_dcc_compression_cap(struct hubbub *hubbub,
    218		const struct dc_dcc_surface_param *input,
    219		struct dc_surface_dcc_cap *output)
    220{
    221	struct dc *dc = hubbub->ctx->dc;
    222	/* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
    223	enum dcc_control dcc_control;
    224	unsigned int bpe;
    225	enum segment_order segment_order_horz, segment_order_vert;
    226	bool req128_horz_wc, req128_vert_wc;
    227
    228	memset(output, 0, sizeof(*output));
    229
    230	if (dc->debug.disable_dcc == DCC_DISABLE)
    231		return false;
    232
    233	if (!hubbub->funcs->dcc_support_pixel_format(input->format,
    234			&bpe))
    235		return false;
    236
    237	if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
    238			&segment_order_horz, &segment_order_vert))
    239		return false;
    240
    241	hubbub2_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size,
    242			input->surface_size.height,  input->surface_size.width,
    243			bpe, &req128_horz_wc, &req128_vert_wc);
    244
    245	if (!req128_horz_wc && !req128_vert_wc) {
    246		dcc_control = dcc_control__256_256_xxx;
    247	} else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
    248		if (!req128_horz_wc)
    249			dcc_control = dcc_control__256_256_xxx;
    250		else if (segment_order_horz == segment_order__contiguous)
    251			dcc_control = dcc_control__128_128_xxx;
    252		else
    253			dcc_control = dcc_control__256_64_64;
    254	} else if (input->scan == SCAN_DIRECTION_VERTICAL) {
    255		if (!req128_vert_wc)
    256			dcc_control = dcc_control__256_256_xxx;
    257		else if (segment_order_vert == segment_order__contiguous)
    258			dcc_control = dcc_control__128_128_xxx;
    259		else
    260			dcc_control = dcc_control__256_64_64;
    261	} else {
    262		if ((req128_horz_wc &&
    263			segment_order_horz == segment_order__non_contiguous) ||
    264			(req128_vert_wc &&
    265			segment_order_vert == segment_order__non_contiguous))
    266			/* access_dir not known, must use most constraining */
    267			dcc_control = dcc_control__256_64_64;
    268		else
    269			/* reg128 is true for either horz and vert
    270			 * but segment_order is contiguous
    271			 */
    272			dcc_control = dcc_control__128_128_xxx;
    273	}
    274
    275	/* Exception for 64KB_R_X */
    276	if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X))
    277		dcc_control = dcc_control__128_128_xxx;
    278
    279	if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
    280		dcc_control != dcc_control__256_256_xxx)
    281		return false;
    282
    283	switch (dcc_control) {
    284	case dcc_control__256_256_xxx:
    285		output->grph.rgb.max_uncompressed_blk_size = 256;
    286		output->grph.rgb.max_compressed_blk_size = 256;
    287		output->grph.rgb.independent_64b_blks = false;
    288		break;
    289	case dcc_control__128_128_xxx:
    290		output->grph.rgb.max_uncompressed_blk_size = 128;
    291		output->grph.rgb.max_compressed_blk_size = 128;
    292		output->grph.rgb.independent_64b_blks = false;
    293		break;
    294	case dcc_control__256_64_64:
    295		output->grph.rgb.max_uncompressed_blk_size = 256;
    296		output->grph.rgb.max_compressed_blk_size = 64;
    297		output->grph.rgb.independent_64b_blks = true;
    298		break;
    299	default:
    300		ASSERT(false);
    301		break;
    302	}
    303	output->capable = true;
    304	output->const_color_support = true;
    305
    306	return true;
    307}
    308
    309static enum dcn_hubbub_page_table_depth page_table_depth_to_hw(unsigned int page_table_depth)
    310{
    311	enum dcn_hubbub_page_table_depth depth = 0;
    312
    313	switch (page_table_depth) {
    314	case 1:
    315		depth = DCN_PAGE_TABLE_DEPTH_1_LEVEL;
    316		break;
    317	case 2:
    318		depth = DCN_PAGE_TABLE_DEPTH_2_LEVEL;
    319		break;
    320	case 3:
    321		depth = DCN_PAGE_TABLE_DEPTH_3_LEVEL;
    322		break;
    323	case 4:
    324		depth = DCN_PAGE_TABLE_DEPTH_4_LEVEL;
    325		break;
    326	default:
    327		ASSERT(false);
    328		break;
    329	}
    330
    331	return depth;
    332}
    333
    334static enum dcn_hubbub_page_table_block_size page_table_block_size_to_hw(unsigned int page_table_block_size)
    335{
    336	enum dcn_hubbub_page_table_block_size block_size = 0;
    337
    338	switch (page_table_block_size) {
    339	case 4096:
    340		block_size = DCN_PAGE_TABLE_BLOCK_SIZE_4KB;
    341		break;
    342	case 65536:
    343		block_size = DCN_PAGE_TABLE_BLOCK_SIZE_64KB;
    344		break;
    345	case 32768:
    346		block_size = DCN_PAGE_TABLE_BLOCK_SIZE_32KB;
    347		break;
    348	default:
    349		ASSERT(false);
    350		block_size = page_table_block_size;
    351		break;
    352	}
    353
    354	return block_size;
    355}
    356
    357void hubbub2_init_vm_ctx(struct hubbub *hubbub,
    358		struct dcn_hubbub_virt_addr_config *va_config,
    359		int vmid)
    360{
    361	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    362	struct dcn_vmid_page_table_config virt_config;
    363
    364	virt_config.page_table_start_addr = va_config->page_table_start_addr >> 12;
    365	virt_config.page_table_end_addr = va_config->page_table_end_addr >> 12;
    366	virt_config.depth = page_table_depth_to_hw(va_config->page_table_depth);
    367	virt_config.block_size = page_table_block_size_to_hw(va_config->page_table_block_size);
    368	virt_config.page_table_base_addr = va_config->page_table_base_addr;
    369
    370	dcn20_vmid_setup(&hubbub1->vmid[vmid], &virt_config);
    371}
    372
    373int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub,
    374		struct dcn_hubbub_phys_addr_config *pa_config)
    375{
    376	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    377	struct dcn_vmid_page_table_config phys_config;
    378
    379	REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
    380			FB_BASE, pa_config->system_aperture.fb_base >> 24);
    381	REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
    382			FB_TOP, pa_config->system_aperture.fb_top >> 24);
    383	REG_SET(DCN_VM_FB_OFFSET, 0,
    384			FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
    385	REG_SET(DCN_VM_AGP_BOT, 0,
    386			AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
    387	REG_SET(DCN_VM_AGP_TOP, 0,
    388			AGP_TOP, pa_config->system_aperture.agp_top >> 24);
    389	REG_SET(DCN_VM_AGP_BASE, 0,
    390			AGP_BASE, pa_config->system_aperture.agp_base >> 24);
    391
    392	REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0,
    393			DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, (pa_config->page_table_default_page_addr >> 44) & 0xF);
    394	REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0,
    395			DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, (pa_config->page_table_default_page_addr >> 12) & 0xFFFFFFFF);
    396
    397	if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
    398		phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
    399		phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
    400		phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
    401		phys_config.depth = 0;
    402		phys_config.block_size = 0;
    403		// Init VMID 0 based on PA config
    404		dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
    405	}
    406
    407	return NUM_VMID;
    408}
    409
    410void hubbub2_update_dchub(struct hubbub *hubbub,
    411		struct dchub_init_data *dh_data)
    412{
    413	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    414
    415	if (REG(DCN_VM_FB_LOCATION_TOP) == 0)
    416		return;
    417
    418	switch (dh_data->fb_mode) {
    419	case FRAME_BUFFER_MODE_ZFB_ONLY:
    420		/*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
    421		REG_UPDATE(DCN_VM_FB_LOCATION_TOP,
    422				FB_TOP, 0);
    423
    424		REG_UPDATE(DCN_VM_FB_LOCATION_BASE,
    425				FB_BASE, 0xFFFFFF);
    426
    427		/*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/
    428		REG_UPDATE(DCN_VM_AGP_BASE,
    429				AGP_BASE, dh_data->zfb_phys_addr_base >> 24);
    430
    431		/*This field defines the bottom range of the AGP aperture and represents the 24*/
    432		/*MSBs, bits [47:24] of the 48 address bits*/
    433		REG_UPDATE(DCN_VM_AGP_BOT,
    434				AGP_BOT, dh_data->zfb_mc_base_addr >> 24);
    435
    436		/*This field defines the top range of the AGP aperture and represents the 24*/
    437		/*MSBs, bits [47:24] of the 48 address bits*/
    438		REG_UPDATE(DCN_VM_AGP_TOP,
    439				AGP_TOP, (dh_data->zfb_mc_base_addr +
    440						dh_data->zfb_size_in_byte - 1) >> 24);
    441		break;
    442	case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
    443		/*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
    444
    445		/*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/
    446		REG_UPDATE(DCN_VM_AGP_BASE,
    447				AGP_BASE, dh_data->zfb_phys_addr_base >> 24);
    448
    449		/*This field defines the bottom range of the AGP aperture and represents the 24*/
    450		/*MSBs, bits [47:24] of the 48 address bits*/
    451		REG_UPDATE(DCN_VM_AGP_BOT,
    452				AGP_BOT, dh_data->zfb_mc_base_addr >> 24);
    453
    454		/*This field defines the top range of the AGP aperture and represents the 24*/
    455		/*MSBs, bits [47:24] of the 48 address bits*/
    456		REG_UPDATE(DCN_VM_AGP_TOP,
    457				AGP_TOP, (dh_data->zfb_mc_base_addr +
    458						dh_data->zfb_size_in_byte - 1) >> 24);
    459		break;
    460	case FRAME_BUFFER_MODE_LOCAL_ONLY:
    461		/*Should not touch FB LOCATION (should be done by VBIOS)*/
    462
    463		/*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/
    464		REG_UPDATE(DCN_VM_AGP_BASE,
    465				AGP_BASE, 0);
    466
    467		/*This field defines the bottom range of the AGP aperture and represents the 24*/
    468		/*MSBs, bits [47:24] of the 48 address bits*/
    469		REG_UPDATE(DCN_VM_AGP_BOT,
    470				AGP_BOT, 0xFFFFFF);
    471
    472		/*This field defines the top range of the AGP aperture and represents the 24*/
    473		/*MSBs, bits [47:24] of the 48 address bits*/
    474		REG_UPDATE(DCN_VM_AGP_TOP,
    475				AGP_TOP, 0);
    476		break;
    477	default:
    478		break;
    479	}
    480
    481	dh_data->dchub_initialzied = true;
    482	dh_data->dchub_info_valid = false;
    483}
    484
    485void hubbub2_wm_read_state(struct hubbub *hubbub,
    486		struct dcn_hubbub_wm *wm)
    487{
    488	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    489
    490	struct dcn_hubbub_wm_set *s;
    491
    492	memset(wm, 0, sizeof(struct dcn_hubbub_wm));
    493
    494	s = &wm->sets[0];
    495	s->wm_set = 0;
    496	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
    497	if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A))
    498		s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
    499	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
    500		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
    501		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
    502	}
    503	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
    504
    505	s = &wm->sets[1];
    506	s->wm_set = 1;
    507	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
    508	if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B))
    509		s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
    510	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
    511		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
    512		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
    513	}
    514	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
    515
    516	s = &wm->sets[2];
    517	s->wm_set = 2;
    518	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
    519	if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C))
    520		s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
    521	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
    522		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
    523		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
    524	}
    525	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
    526
    527	s = &wm->sets[3];
    528	s->wm_set = 3;
    529	s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
    530	if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D))
    531		s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
    532	if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
    533		s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
    534		s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
    535	}
    536	s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
    537}
    538
    539void hubbub2_get_dchub_ref_freq(struct hubbub *hubbub,
    540		unsigned int dccg_ref_freq_inKhz,
    541		unsigned int *dchub_ref_freq_inKhz)
    542{
    543	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    544	uint32_t ref_div = 0;
    545	uint32_t ref_en = 0;
    546
    547	REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div,
    548			DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en);
    549
    550	if (ref_en) {
    551		if (ref_div == 2)
    552			*dchub_ref_freq_inKhz = dccg_ref_freq_inKhz / 2;
    553		else
    554			*dchub_ref_freq_inKhz = dccg_ref_freq_inKhz;
    555
    556		// DC hub reference frequency must be around 50Mhz, otherwise there may be
    557		// overflow/underflow issues when doing HUBBUB programming
    558		if (*dchub_ref_freq_inKhz < 40000 || *dchub_ref_freq_inKhz > 60000)
    559			ASSERT_CRITICAL(false);
    560
    561		return;
    562	} else {
    563		*dchub_ref_freq_inKhz = dccg_ref_freq_inKhz;
    564
    565		// HUBBUB global timer must be enabled.
    566		ASSERT_CRITICAL(false);
    567		return;
    568	}
    569}
    570
    571static bool hubbub2_program_watermarks(
    572		struct hubbub *hubbub,
    573		struct dcn_watermark_set *watermarks,
    574		unsigned int refclk_mhz,
    575		bool safe_to_lower)
    576{
    577	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    578	bool wm_pending = false;
    579	/*
    580	 * Need to clamp to max of the register values (i.e. no wrap)
    581	 * for dcn1, all wm registers are 21-bit wide
    582	 */
    583	if (hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
    584		wm_pending = true;
    585
    586	if (hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
    587		wm_pending = true;
    588
    589	/*
    590	 * There's a special case when going from p-state support to p-state unsupported
    591	 * here we are going to LOWER watermarks to go to dummy p-state only, but this has
    592	 * to be done prepare_bandwidth, not optimize
    593	 */
    594	if (hubbub1->base.ctx->dc->clk_mgr->clks.prev_p_state_change_support == true &&
    595		hubbub1->base.ctx->dc->clk_mgr->clks.p_state_change_support == false)
    596		safe_to_lower = true;
    597
    598	hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
    599
    600	REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
    601			DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
    602	REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 180);
    603
    604	hubbub->funcs->allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
    605	return wm_pending;
    606}
    607
    608void hubbub2_read_state(struct hubbub *hubbub, struct dcn_hubbub_state *hubbub_state)
    609{
    610	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
    611
    612	if (REG(DCN_VM_FAULT_ADDR_MSB))
    613		hubbub_state->vm_fault_addr_msb = REG_READ(DCN_VM_FAULT_ADDR_MSB);
    614
    615	if (REG(DCN_VM_FAULT_ADDR_LSB))
    616		hubbub_state->vm_fault_addr_msb = REG_READ(DCN_VM_FAULT_ADDR_LSB);
    617
    618	if (REG(DCN_VM_FAULT_CNTL))
    619		REG_GET(DCN_VM_FAULT_CNTL, DCN_VM_ERROR_STATUS_MODE, &hubbub_state->vm_error_mode);
    620
    621	if (REG(DCN_VM_FAULT_STATUS)) {
    622		 REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_STATUS, &hubbub_state->vm_error_status);
    623		 REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, &hubbub_state->vm_error_vmid);
    624		 REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, &hubbub_state->vm_error_pipe);
    625	}
    626}
    627
    628static const struct hubbub_funcs hubbub2_funcs = {
    629	.update_dchub = hubbub2_update_dchub,
    630	.init_dchub_sys_ctx = hubbub2_init_dchub_sys_ctx,
    631	.init_vm_ctx = hubbub2_init_vm_ctx,
    632	.dcc_support_swizzle = hubbub2_dcc_support_swizzle,
    633	.dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
    634	.get_dcc_compression_cap = hubbub2_get_dcc_compression_cap,
    635	.wm_read_state = hubbub2_wm_read_state,
    636	.get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
    637	.program_watermarks = hubbub2_program_watermarks,
    638	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
    639	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
    640	.hubbub_read_state = hubbub2_read_state,
    641};
    642
    643void hubbub2_construct(struct dcn20_hubbub *hubbub,
    644	struct dc_context *ctx,
    645	const struct dcn_hubbub_registers *hubbub_regs,
    646	const struct dcn_hubbub_shift *hubbub_shift,
    647	const struct dcn_hubbub_mask *hubbub_mask)
    648{
    649	hubbub->base.ctx = ctx;
    650
    651	hubbub->base.funcs = &hubbub2_funcs;
    652
    653	hubbub->regs = hubbub_regs;
    654	hubbub->shifts = hubbub_shift;
    655	hubbub->masks = hubbub_mask;
    656
    657	hubbub->debug_test_index_pstate = 0xB;
    658	hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */
    659}