170ccab60SHarry Wentland /*
270ccab60SHarry Wentland  * Copyright 2017 Advanced Micro Devices, Inc.
370ccab60SHarry Wentland  *
470ccab60SHarry Wentland  * Permission is hereby granted, free of charge, to any person obtaining a
570ccab60SHarry Wentland  * copy of this software and associated documentation files (the "Software"),
670ccab60SHarry Wentland  * to deal in the Software without restriction, including without limitation
770ccab60SHarry Wentland  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
870ccab60SHarry Wentland  * and/or sell copies of the Software, and to permit persons to whom the
970ccab60SHarry Wentland  * Software is furnished to do so, subject to the following conditions:
1070ccab60SHarry Wentland  *
1170ccab60SHarry Wentland  * The above copyright notice and this permission notice shall be included in
1270ccab60SHarry Wentland  * all copies or substantial portions of the Software.
1370ccab60SHarry Wentland  *
1470ccab60SHarry Wentland  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1570ccab60SHarry Wentland  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1670ccab60SHarry Wentland  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1770ccab60SHarry Wentland  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1870ccab60SHarry Wentland  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1970ccab60SHarry Wentland  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2070ccab60SHarry Wentland  * OTHER DEALINGS IN THE SOFTWARE.
2170ccab60SHarry Wentland  *
2270ccab60SHarry Wentland  * Authors: AMD
2370ccab60SHarry Wentland  *
2470ccab60SHarry Wentland  */
2570ccab60SHarry Wentland 
2670ccab60SHarry Wentland #include "dm_services.h"
2770ccab60SHarry Wentland #include "dcn10_ipp.h"
2870ccab60SHarry Wentland #include "reg_helper.h"
2970ccab60SHarry Wentland 
3070ccab60SHarry Wentland #define REG(reg) \
3170ccab60SHarry Wentland 	(ippn10->regs->reg)
3270ccab60SHarry Wentland 
3370ccab60SHarry Wentland #undef FN
3470ccab60SHarry Wentland #define FN(reg_name, field_name) \
3570ccab60SHarry Wentland 	ippn10->ipp_shift->field_name, ippn10->ipp_mask->field_name
3670ccab60SHarry Wentland 
3770ccab60SHarry Wentland #define CTX \
3870ccab60SHarry Wentland 	ippn10->base.ctx
3970ccab60SHarry Wentland 
40a3ac9dadSDmytro Laktyushkin static bool ippn10_cursor_program_control(
4170ccab60SHarry Wentland 		struct dcn10_ipp *ippn10,
4270ccab60SHarry Wentland 		bool pixel_data_invert,
4370ccab60SHarry Wentland 		enum dc_cursor_color_format color_format)
4470ccab60SHarry Wentland {
4551666631SDmytro Laktyushkin 	if (REG(CURSOR_SETTINS))
4670ccab60SHarry Wentland 		REG_SET_2(CURSOR_SETTINS, 0,
4770ccab60SHarry Wentland 				/* no shift of the cursor HDL schedule */
4870ccab60SHarry Wentland 				CURSOR0_DST_Y_OFFSET, 0,
4970ccab60SHarry Wentland 				 /* used to shift the cursor chunk request deadline */
5070ccab60SHarry Wentland 				CURSOR0_CHUNK_HDL_ADJUST, 3);
5151666631SDmytro Laktyushkin 	else
5251666631SDmytro Laktyushkin 		REG_SET_2(CURSOR_SETTINGS, 0,
5351666631SDmytro Laktyushkin 				/* no shift of the cursor HDL schedule */
5451666631SDmytro Laktyushkin 				CURSOR0_DST_Y_OFFSET, 0,
5551666631SDmytro Laktyushkin 				 /* used to shift the cursor chunk request deadline */
5651666631SDmytro Laktyushkin 				CURSOR0_CHUNK_HDL_ADJUST, 3);
5770ccab60SHarry Wentland 
5870ccab60SHarry Wentland 	REG_UPDATE_2(CURSOR0_CONTROL,
5970ccab60SHarry Wentland 			CUR0_MODE, color_format,
6035ce37d6SDmytro Laktyushkin 			CUR0_EXPANSION_MODE, 0);
6170ccab60SHarry Wentland 
6270ccab60SHarry Wentland 	if (color_format == CURSOR_MODE_MONO) {
6370ccab60SHarry Wentland 		/* todo: clarify what to program these to */
6470ccab60SHarry Wentland 		REG_UPDATE(CURSOR0_COLOR0,
6570ccab60SHarry Wentland 				CUR0_COLOR0, 0x00000000);
6670ccab60SHarry Wentland 		REG_UPDATE(CURSOR0_COLOR1,
6770ccab60SHarry Wentland 				CUR0_COLOR1, 0xFFFFFFFF);
6870ccab60SHarry Wentland 	}
6970ccab60SHarry Wentland 
7070ccab60SHarry Wentland 	/* TODO: Fixed vs float */
7170ccab60SHarry Wentland 
7270ccab60SHarry Wentland 	REG_UPDATE_3(FORMAT_CONTROL,
7370ccab60SHarry Wentland 				CNVC_BYPASS, 0,
7470ccab60SHarry Wentland 				ALPHA_EN, 1,
7570ccab60SHarry Wentland 				FORMAT_EXPANSION_MODE, 0);
7670ccab60SHarry Wentland 
7770ccab60SHarry Wentland 	return true;
7870ccab60SHarry Wentland }
7970ccab60SHarry Wentland 
8070ccab60SHarry Wentland enum cursor_pitch {
8170ccab60SHarry Wentland 	CURSOR_PITCH_64_PIXELS = 0,
8270ccab60SHarry Wentland 	CURSOR_PITCH_128_PIXELS,
8370ccab60SHarry Wentland 	CURSOR_PITCH_256_PIXELS
8470ccab60SHarry Wentland };
8570ccab60SHarry Wentland 
8670ccab60SHarry Wentland enum cursor_lines_per_chunk {
8770ccab60SHarry Wentland 	CURSOR_LINE_PER_CHUNK_2 = 1,
8870ccab60SHarry Wentland 	CURSOR_LINE_PER_CHUNK_4,
8970ccab60SHarry Wentland 	CURSOR_LINE_PER_CHUNK_8,
9070ccab60SHarry Wentland 	CURSOR_LINE_PER_CHUNK_16
9170ccab60SHarry Wentland };
9270ccab60SHarry Wentland 
93a3ac9dadSDmytro Laktyushkin static enum cursor_pitch ippn10_get_cursor_pitch(
9470ccab60SHarry Wentland 		unsigned int pitch)
9570ccab60SHarry Wentland {
9670ccab60SHarry Wentland 	enum cursor_pitch hw_pitch;
9770ccab60SHarry Wentland 
9870ccab60SHarry Wentland 	switch (pitch) {
9970ccab60SHarry Wentland 	case 64:
10070ccab60SHarry Wentland 		hw_pitch = CURSOR_PITCH_64_PIXELS;
10170ccab60SHarry Wentland 		break;
10270ccab60SHarry Wentland 	case 128:
10370ccab60SHarry Wentland 		hw_pitch = CURSOR_PITCH_128_PIXELS;
10470ccab60SHarry Wentland 		break;
10570ccab60SHarry Wentland 	case 256:
10670ccab60SHarry Wentland 		hw_pitch = CURSOR_PITCH_256_PIXELS;
10770ccab60SHarry Wentland 		break;
10870ccab60SHarry Wentland 	default:
10970ccab60SHarry Wentland 		DC_ERR("Invalid cursor pitch of %d. "
11070ccab60SHarry Wentland 				"Only 64/128/256 is supported on DCN.\n", pitch);
11170ccab60SHarry Wentland 		hw_pitch = CURSOR_PITCH_64_PIXELS;
11270ccab60SHarry Wentland 		break;
11370ccab60SHarry Wentland 	}
11470ccab60SHarry Wentland 	return hw_pitch;
11570ccab60SHarry Wentland }
11670ccab60SHarry Wentland 
117a3ac9dadSDmytro Laktyushkin static enum cursor_lines_per_chunk ippn10_get_lines_per_chunk(
11870ccab60SHarry Wentland 		unsigned int cur_width,
11970ccab60SHarry Wentland 		enum dc_cursor_color_format format)
12070ccab60SHarry Wentland {
12170ccab60SHarry Wentland 	enum cursor_lines_per_chunk line_per_chunk;
12270ccab60SHarry Wentland 
12370ccab60SHarry Wentland 	if (format == CURSOR_MODE_MONO)
12470ccab60SHarry Wentland 		/* impl B. expansion in CUR Buffer reader */
12570ccab60SHarry Wentland 		line_per_chunk = CURSOR_LINE_PER_CHUNK_16;
12670ccab60SHarry Wentland 	else if (cur_width <= 32)
12770ccab60SHarry Wentland 		line_per_chunk = CURSOR_LINE_PER_CHUNK_16;
12870ccab60SHarry Wentland 	else if (cur_width <= 64)
12970ccab60SHarry Wentland 		line_per_chunk = CURSOR_LINE_PER_CHUNK_8;
13070ccab60SHarry Wentland 	else if (cur_width <= 128)
13170ccab60SHarry Wentland 		line_per_chunk = CURSOR_LINE_PER_CHUNK_4;
13270ccab60SHarry Wentland 	else
13370ccab60SHarry Wentland 		line_per_chunk = CURSOR_LINE_PER_CHUNK_2;
13470ccab60SHarry Wentland 
13570ccab60SHarry Wentland 	return line_per_chunk;
13670ccab60SHarry Wentland }
13770ccab60SHarry Wentland 
138a3ac9dadSDmytro Laktyushkin static void ippn10_cursor_set_attributes(
13970ccab60SHarry Wentland 		struct input_pixel_processor *ipp,
14070ccab60SHarry Wentland 		const struct dc_cursor_attributes *attr)
14170ccab60SHarry Wentland {
14270ccab60SHarry Wentland 	struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
143a3ac9dadSDmytro Laktyushkin 	enum cursor_pitch hw_pitch = ippn10_get_cursor_pitch(attr->pitch);
144a3ac9dadSDmytro Laktyushkin 	enum cursor_lines_per_chunk lpc = ippn10_get_lines_per_chunk(
14570ccab60SHarry Wentland 			attr->width, attr->color_format);
14670ccab60SHarry Wentland 
14770ccab60SHarry Wentland 	ippn10->curs_attr = *attr;
14870ccab60SHarry Wentland 
14970ccab60SHarry Wentland 	REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
15070ccab60SHarry Wentland 			CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
15170ccab60SHarry Wentland 	REG_UPDATE(CURSOR_SURFACE_ADDRESS,
15270ccab60SHarry Wentland 			CURSOR_SURFACE_ADDRESS, attr->address.low_part);
15370ccab60SHarry Wentland 
15470ccab60SHarry Wentland 	REG_UPDATE_2(CURSOR_SIZE,
15570ccab60SHarry Wentland 			CURSOR_WIDTH, attr->width,
15670ccab60SHarry Wentland 			CURSOR_HEIGHT, attr->height);
15770ccab60SHarry Wentland 	REG_UPDATE_3(CURSOR_CONTROL,
15870ccab60SHarry Wentland 			CURSOR_MODE, attr->color_format,
15970ccab60SHarry Wentland 			CURSOR_PITCH, hw_pitch,
16070ccab60SHarry Wentland 			CURSOR_LINES_PER_CHUNK, lpc);
161a3ac9dadSDmytro Laktyushkin 	ippn10_cursor_program_control(ippn10,
16270ccab60SHarry Wentland 			attr->attribute_flags.bits.INVERT_PIXEL_DATA,
16370ccab60SHarry Wentland 			attr->color_format);
16470ccab60SHarry Wentland }
16570ccab60SHarry Wentland 
166a3ac9dadSDmytro Laktyushkin static void ippn10_cursor_set_position(
16770ccab60SHarry Wentland 		struct input_pixel_processor *ipp,
16870ccab60SHarry Wentland 		const struct dc_cursor_position *pos,
16970ccab60SHarry Wentland 		const struct dc_cursor_mi_param *param)
17070ccab60SHarry Wentland {
17170ccab60SHarry Wentland 	struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
17270ccab60SHarry Wentland 	int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start;
17370ccab60SHarry Wentland 	uint32_t cur_en = pos->enable ? 1 : 0;
17470ccab60SHarry Wentland 	uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0;
17570ccab60SHarry Wentland 
176d3ec0562SLeo (Sunpeng) Li 	/*
177d3ec0562SLeo (Sunpeng) Li 	 * Guard aganst cursor_set_position() from being called with invalid
178d3ec0562SLeo (Sunpeng) Li 	 * attributes
179d3ec0562SLeo (Sunpeng) Li 	 *
180d3ec0562SLeo (Sunpeng) Li 	 * TODO: Look at combining cursor_set_position() and
181d3ec0562SLeo (Sunpeng) Li 	 * cursor_set_attributes() into cursor_update()
182d3ec0562SLeo (Sunpeng) Li 	 */
183d3ec0562SLeo (Sunpeng) Li 	if (ippn10->curs_attr.address.quad_part == 0)
184d3ec0562SLeo (Sunpeng) Li 		return;
185d3ec0562SLeo (Sunpeng) Li 
18670ccab60SHarry Wentland 	dst_x_offset *= param->ref_clk_khz;
18770ccab60SHarry Wentland 	dst_x_offset /= param->pixel_clk_khz;
18870ccab60SHarry Wentland 
18970ccab60SHarry Wentland 	ASSERT(param->h_scale_ratio.value);
19070ccab60SHarry Wentland 
19170ccab60SHarry Wentland 	if (param->h_scale_ratio.value)
19270ccab60SHarry Wentland 		dst_x_offset = dal_fixed31_32_floor(dal_fixed31_32_div(
19370ccab60SHarry Wentland 				dal_fixed31_32_from_int(dst_x_offset),
19470ccab60SHarry Wentland 				param->h_scale_ratio));
19570ccab60SHarry Wentland 
19670ccab60SHarry Wentland 	if (src_x_offset >= (int)param->viewport_width)
19770ccab60SHarry Wentland 		cur_en = 0;  /* not visible beyond right edge*/
19870ccab60SHarry Wentland 
19970ccab60SHarry Wentland 	if (src_x_offset + (int)ippn10->curs_attr.width < 0)
20070ccab60SHarry Wentland 		cur_en = 0;  /* not visible beyond left edge*/
20170ccab60SHarry Wentland 
20270ccab60SHarry Wentland 	if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0)
203a3ac9dadSDmytro Laktyushkin 		ippn10_cursor_set_attributes(ipp, &ippn10->curs_attr);
20470ccab60SHarry Wentland 	REG_UPDATE(CURSOR_CONTROL,
20570ccab60SHarry Wentland 			CURSOR_ENABLE, cur_en);
20670ccab60SHarry Wentland 	REG_UPDATE(CURSOR0_CONTROL,
20770ccab60SHarry Wentland 			CUR0_ENABLE, cur_en);
20870ccab60SHarry Wentland 
20970ccab60SHarry Wentland 	REG_SET_2(CURSOR_POSITION, 0,
21070ccab60SHarry Wentland 			CURSOR_X_POSITION, pos->x,
21170ccab60SHarry Wentland 			CURSOR_Y_POSITION, pos->y);
21270ccab60SHarry Wentland 
21370ccab60SHarry Wentland 	REG_SET_2(CURSOR_HOT_SPOT, 0,
21470ccab60SHarry Wentland 			CURSOR_HOT_SPOT_X, pos->x_hotspot,
21570ccab60SHarry Wentland 			CURSOR_HOT_SPOT_Y, pos->y_hotspot);
21670ccab60SHarry Wentland 
21770ccab60SHarry Wentland 	REG_SET(CURSOR_DST_OFFSET, 0,
21870ccab60SHarry Wentland 			CURSOR_DST_X_OFFSET, dst_x_offset);
21970ccab60SHarry Wentland 	/* TODO Handle surface pixel formats other than 4:4:4 */
22070ccab60SHarry Wentland }
22170ccab60SHarry Wentland 
22270ccab60SHarry Wentland /*****************************************/
22370ccab60SHarry Wentland /* Constructor, Destructor               */
22470ccab60SHarry Wentland /*****************************************/
22570ccab60SHarry Wentland 
22670ccab60SHarry Wentland static void dcn10_ipp_destroy(struct input_pixel_processor **ipp)
22770ccab60SHarry Wentland {
2282004f45eSHarry Wentland 	kfree(TO_DCN10_IPP(*ipp));
22970ccab60SHarry Wentland 	*ipp = NULL;
23070ccab60SHarry Wentland }
23170ccab60SHarry Wentland 
23270ccab60SHarry Wentland static const struct ipp_funcs dcn10_ipp_funcs = {
233a3ac9dadSDmytro Laktyushkin 	.ipp_cursor_set_attributes	= ippn10_cursor_set_attributes,
234a3ac9dadSDmytro Laktyushkin 	.ipp_cursor_set_position	= ippn10_cursor_set_position,
235b3c340faSYue Hin Lau 	.ipp_set_degamma		= NULL,
236b3c340faSYue Hin Lau 	.ipp_program_input_lut		= NULL,
237b3c340faSYue Hin Lau 	.ipp_full_bypass		= NULL,
238b3c340faSYue Hin Lau 	.ipp_setup			= NULL,
239b3c340faSYue Hin Lau 	.ipp_program_degamma_pwl	= NULL,
24070ccab60SHarry Wentland 	.ipp_destroy			= dcn10_ipp_destroy
24170ccab60SHarry Wentland };
24270ccab60SHarry Wentland 
24370ccab60SHarry Wentland void dcn10_ipp_construct(
24470ccab60SHarry Wentland 	struct dcn10_ipp *ippn10,
24570ccab60SHarry Wentland 	struct dc_context *ctx,
24670ccab60SHarry Wentland 	int inst,
24770ccab60SHarry Wentland 	const struct dcn10_ipp_registers *regs,
24870ccab60SHarry Wentland 	const struct dcn10_ipp_shift *ipp_shift,
24970ccab60SHarry Wentland 	const struct dcn10_ipp_mask *ipp_mask)
25070ccab60SHarry Wentland {
25170ccab60SHarry Wentland 	ippn10->base.ctx = ctx;
25270ccab60SHarry Wentland 	ippn10->base.inst = inst;
25370ccab60SHarry Wentland 	ippn10->base.funcs = &dcn10_ipp_funcs;
25470ccab60SHarry Wentland 
25570ccab60SHarry Wentland 	ippn10->regs = regs;
25670ccab60SHarry Wentland 	ippn10->ipp_shift = ipp_shift;
25770ccab60SHarry Wentland 	ippn10->ipp_mask = ipp_mask;
25870ccab60SHarry Wentland }
259a3ac9dadSDmytro Laktyushkin 
260