/*
 * dml1_harness.c — DF-4198 model harness.
 *
 * Compiles the REAL, unmodified dml1_display_rq_dlg_calc.c (byte-identical
 * copy of sys/dev/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c) plus the
 * real dcn_calc_math.c / dml_common_defs.c into a userspace binary, then
 * drives it with a realistic DCN1 pipe-source configuration.
 *
 *   ./dml1_harness normal     source_format = dm_444_32 (what dcn_calcs.c
 *                            maps every non-420/64bpp UABI format to)
 *   ./dml1_harness mono8      source_format = dm_444_8 (= dm_mono_8, enum
 *                            value 7 — a valid display_mode_enums.h value that
 *                            get_bytes_per_element() does not handle)
 *
 * Expected: "normal" completes and prints computed RQ/DLG regs;
 *           "mono8" dies with SIGFPE (integer #DE — same exception class as
 *           the in-kernel divide-by-zero panic) inside get_surf_rq_param().
 */
#include "display_mode_lib.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned long g_assert_count;
unsigned long g_dtrace_count;

/* linkage stubs for the printer helpers declared in display_rq_dlg_helpers.h */
void print__rq_params_st(struct display_mode_lib *m, display_rq_params_st p) { (void)m;(void)p; }
void print__data_rq_sizing_params_st(struct display_mode_lib *m, display_data_rq_sizing_params_st p) { (void)m;(void)p; }
void print__data_rq_dlg_params_st(struct display_mode_lib *m, display_data_rq_dlg_params_st p) { (void)m;(void)p; }
void print__data_rq_misc_params_st(struct display_mode_lib *m, display_data_rq_misc_params_st p) { (void)m;(void)p; }
void print__rq_dlg_params_st(struct display_mode_lib *m, display_rq_dlg_params_st p) { (void)m;(void)p; }
void print__dlg_sys_params_st(struct display_mode_lib *m, display_dlg_sys_params_st p) { (void)m;(void)p; }
void print__data_rq_regs_st(struct display_mode_lib *m, display_data_rq_regs_st p) { (void)m;(void)p; }
void print__rq_regs_st(struct display_mode_lib *m, display_rq_regs_st p) { (void)m;(void)p; }
void print__dlg_regs_st(struct display_mode_lib *m, display_dlg_regs_st p) { (void)m;(void)p; }
void print__ttu_regs_st(struct display_mode_lib *m, display_ttu_regs_st p) { (void)m;(void)p; }

static struct display_mode_lib dml;

int main(int argc, char **argv)
{
	struct _vcs_dpi_display_pipe_source_params_st src;
	struct _vcs_dpi_display_rq_params_st rq_param;
	const char *mode = argc > 1 ? argv[1] : "normal";

	/* DCN1 (Raven) defaults, from dcn10_resource.c / dcn10 soc/ip bounding
	 * boxes — only the fields this file touches are needed. */
	memset(&dml, 0, sizeof(dml));
	dml.ip.det_buffer_size_kbytes = 164;
	dml.ip.dpte_buffer_size_in_pte_reqs = 64;
	dml.ip.min_vblank_lines = 32;
	dml.ip.dppclk_delay_subtotal = 39;
	dml.ip.dispclk_delay_subtotal = 27;
	dml.soc.vmm_page_size_bytes = 4096;
	dml.project = DML_PROJECT_RAVEN1;

	memset(&src, 0, sizeof(src));
	src.source_scan = dm_horz;
	src.sw_mode = dm_sw_64kb_s;
	src.macro_tile_size = dm_64k_tile;
	src.viewport_width = 1920;
	src.viewport_height = 1080;
	src.viewport_width_c = 1920;
	src.viewport_height_c = 1080;
	src.data_pitch = 1920 * 4;
	src.data_pitch_c = 1920 * 4;
	src.meta_pitch = 1920 * 4 / 256;
	src.meta_pitch_c = 1920 * 4 / 256;

	if (strcmp(mode, "mono8") == 0 || strcmp(mode, "mono8_linear") == 0) {
		/* dm_444_8 == dm_mono_8 == 7: legal enum, unhandled by
		 * get_bytes_per_element() => returns 0 */
		src.source_format = dm_444_8;
	} else {
		/* what dcn_calcs.c maps all other UABI formats to */
		src.source_format = dm_444_32;
	}
	if (strcmp(mode, "mono8_linear") == 0) {
		/* linear swizzle => live 256 / bytes_per_element at
		 * dml1_display_rq_dlg_calc.c:641 */
		src.sw_mode = dm_sw_linear;
	}

	printf("harness: mode=%s source_format=%d\n", mode, src.source_format);
	fflush(stdout);

	memset(&rq_param, 0, sizeof(rq_param));
	dml1_rq_dlg_get_rq_params(&dml, &rq_param, src);

	printf("OK: rq_l sw=%u h=%u dpte_row_h=%u meta_row_h=%u "
	       "dpte_bytes_row=%u meta_bytes_row=%u stored_swath=%u "
	       "(assert-warns=%lu dtrace=%lu)\n",
	       rq_param.dlg.rq_l.swath_width_ub,
	       rq_param.dlg.rq_l.swath_height,
	       rq_param.dlg.rq_l.dpte_row_height,
	       rq_param.dlg.rq_l.meta_row_height,
	       rq_param.dlg.rq_l.dpte_bytes_per_row_ub,
	       rq_param.dlg.rq_l.meta_bytes_per_row_ub,
	       rq_param.misc.rq_l.stored_swath_bytes,
	       g_assert_count, g_dtrace_count);
	return 0;
}
