Home | History | Annotate | Line # | Download | only in dce
      1 /*	$NetBSD: amdgpu_dce_ipp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2017 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: AMD
     25  *
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_ipp.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
     30 
     31 #include <linux/slab.h>
     32 
     33 #include "dce_ipp.h"
     34 #include "reg_helper.h"
     35 #include "dm_services.h"
     36 
     37 #define REG(reg) \
     38 	(ipp_dce->regs->reg)
     39 
     40 #undef FN
     41 #define FN(reg_name, field_name) \
     42 	ipp_dce->ipp_shift->field_name, ipp_dce->ipp_mask->field_name
     43 
     44 #define CTX \
     45 	ipp_dce->base.ctx
     46 
     47 
     48 static void dce_ipp_cursor_set_position(
     49 	struct input_pixel_processor *ipp,
     50 	const struct dc_cursor_position *position,
     51 	const struct dc_cursor_mi_param *param)
     52 {
     53 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
     54 
     55 	/* lock cursor registers */
     56 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
     57 
     58 	/* Flag passed in structure differentiates cursor enable/disable. */
     59 	/* Update if it differs from cached state. */
     60 	REG_UPDATE(CUR_CONTROL, CURSOR_EN, position->enable);
     61 
     62 	REG_SET_2(CUR_POSITION, 0,
     63 		CURSOR_X_POSITION, position->x,
     64 		CURSOR_Y_POSITION, position->y);
     65 
     66 	REG_SET_2(CUR_HOT_SPOT, 0,
     67 		CURSOR_HOT_SPOT_X, position->x_hotspot,
     68 		CURSOR_HOT_SPOT_Y, position->y_hotspot);
     69 
     70 	/* unlock cursor registers */
     71 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
     72 }
     73 
     74 static void dce_ipp_cursor_set_attributes(
     75 	struct input_pixel_processor *ipp,
     76 	const struct dc_cursor_attributes *attributes)
     77 {
     78 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
     79 	int mode;
     80 
     81 	/* Lock cursor registers */
     82 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
     83 
     84 	/* Program cursor control */
     85 	switch (attributes->color_format) {
     86 	case CURSOR_MODE_MONO:
     87 		mode = 0;
     88 		break;
     89 	case CURSOR_MODE_COLOR_1BIT_AND:
     90 		mode = 1;
     91 		break;
     92 	case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
     93 		mode = 2;
     94 		break;
     95 	case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
     96 		mode = 3;
     97 		break;
     98 	default:
     99 		BREAK_TO_DEBUGGER(); /* unsupported */
    100 		mode = 0;
    101 	}
    102 
    103 	REG_UPDATE_3(CUR_CONTROL,
    104 		CURSOR_MODE, mode,
    105 		CURSOR_2X_MAGNIFY, attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
    106 		CUR_INV_TRANS_CLAMP, attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
    107 
    108 	if (attributes->color_format == CURSOR_MODE_MONO) {
    109 		REG_SET_3(CUR_COLOR1, 0,
    110 			CUR_COLOR1_BLUE, 0,
    111 			CUR_COLOR1_GREEN, 0,
    112 			CUR_COLOR1_RED, 0);
    113 
    114 		REG_SET_3(CUR_COLOR2, 0,
    115 			CUR_COLOR2_BLUE, 0xff,
    116 			CUR_COLOR2_GREEN, 0xff,
    117 			CUR_COLOR2_RED, 0xff);
    118 	}
    119 
    120 	/*
    121 	 * Program cursor size -- NOTE: HW spec specifies that HW register
    122 	 * stores size as (height - 1, width - 1)
    123 	 */
    124 	REG_SET_2(CUR_SIZE, 0,
    125 		CURSOR_WIDTH, attributes->width-1,
    126 		CURSOR_HEIGHT, attributes->height-1);
    127 
    128 	/* Program cursor surface address */
    129 	/* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
    130 	 * surface base address in byte. It is 4K byte aligned.
    131 	 * The correct way to program cursor surface address is to first write
    132 	 * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
    133 	 */
    134 	REG_SET(CUR_SURFACE_ADDRESS_HIGH, 0,
    135 		CURSOR_SURFACE_ADDRESS_HIGH, attributes->address.high_part);
    136 
    137 	REG_SET(CUR_SURFACE_ADDRESS, 0,
    138 		CURSOR_SURFACE_ADDRESS, attributes->address.low_part);
    139 
    140 	/* Unlock Cursor registers. */
    141 	REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
    142 }
    143 
    144 
    145 static void dce_ipp_program_prescale(struct input_pixel_processor *ipp,
    146 				     struct ipp_prescale_params *params)
    147 {
    148 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
    149 
    150 	/* set to bypass mode first before change */
    151 	REG_UPDATE(PRESCALE_GRPH_CONTROL,
    152 		   GRPH_PRESCALE_BYPASS, 1);
    153 
    154 	REG_SET_2(PRESCALE_VALUES_GRPH_R, 0,
    155 		  GRPH_PRESCALE_SCALE_R, params->scale,
    156 		  GRPH_PRESCALE_BIAS_R, params->bias);
    157 
    158 	REG_SET_2(PRESCALE_VALUES_GRPH_G, 0,
    159 		  GRPH_PRESCALE_SCALE_G, params->scale,
    160 		  GRPH_PRESCALE_BIAS_G, params->bias);
    161 
    162 	REG_SET_2(PRESCALE_VALUES_GRPH_B, 0,
    163 		  GRPH_PRESCALE_SCALE_B, params->scale,
    164 		  GRPH_PRESCALE_BIAS_B, params->bias);
    165 
    166 	if (params->mode != IPP_PRESCALE_MODE_BYPASS) {
    167 		REG_UPDATE(PRESCALE_GRPH_CONTROL,
    168 			   GRPH_PRESCALE_BYPASS, 0);
    169 
    170 		/* If prescale is in use, then legacy lut should be bypassed */
    171 		REG_UPDATE(INPUT_GAMMA_CONTROL,
    172 			   GRPH_INPUT_GAMMA_MODE, 1);
    173 	}
    174 }
    175 
    176 static void dce_ipp_program_input_lut(
    177 	struct input_pixel_processor *ipp,
    178 	const struct dc_gamma *gamma)
    179 {
    180 	int i;
    181 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
    182 
    183 	/* power on LUT memory */
    184 	if (REG(DCFE_MEM_PWR_CTRL))
    185 		REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 1);
    186 
    187 	/* enable all */
    188 	REG_SET(DC_LUT_WRITE_EN_MASK, 0, DC_LUT_WRITE_EN_MASK, 0x7);
    189 
    190 	/* 256 entry mode */
    191 	REG_UPDATE(DC_LUT_RW_MODE, DC_LUT_RW_MODE, 0);
    192 
    193 	/* LUT-256, unsigned, integer, new u0.12 format */
    194 	REG_SET_3(DC_LUT_CONTROL, 0,
    195 		DC_LUT_DATA_R_FORMAT, 3,
    196 		DC_LUT_DATA_G_FORMAT, 3,
    197 		DC_LUT_DATA_B_FORMAT, 3);
    198 
    199 	/* start from index 0 */
    200 	REG_SET(DC_LUT_RW_INDEX, 0,
    201 		DC_LUT_RW_INDEX, 0);
    202 
    203 	for (i = 0; i < gamma->num_entries; i++) {
    204 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
    205 				dc_fixpt_round(
    206 					gamma->entries.red[i]));
    207 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
    208 				dc_fixpt_round(
    209 					gamma->entries.green[i]));
    210 		REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
    211 				dc_fixpt_round(
    212 					gamma->entries.blue[i]));
    213 	}
    214 
    215 	/* power off LUT memory */
    216 	if (REG(DCFE_MEM_PWR_CTRL))
    217 		REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 0);
    218 
    219 	/* bypass prescale, enable legacy LUT */
    220 	REG_UPDATE(PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
    221 	REG_UPDATE(INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
    222 }
    223 
    224 static void dce_ipp_set_degamma(
    225 	struct input_pixel_processor *ipp,
    226 	enum ipp_degamma_mode mode)
    227 {
    228 	struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
    229 	uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
    230 
    231 	ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS || mode == IPP_DEGAMMA_MODE_HW_sRGB);
    232 
    233 	REG_SET_3(DEGAMMA_CONTROL, 0,
    234 		  GRPH_DEGAMMA_MODE, degamma_type,
    235 		  CURSOR_DEGAMMA_MODE, degamma_type,
    236 		  CURSOR2_DEGAMMA_MODE, degamma_type);
    237 }
    238 
    239 static const struct ipp_funcs dce_ipp_funcs = {
    240 	.ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes,
    241 	.ipp_cursor_set_position = dce_ipp_cursor_set_position,
    242 	.ipp_program_prescale = dce_ipp_program_prescale,
    243 	.ipp_program_input_lut = dce_ipp_program_input_lut,
    244 	.ipp_set_degamma = dce_ipp_set_degamma
    245 };
    246 
    247 /*****************************************/
    248 /* Constructor, Destructor               */
    249 /*****************************************/
    250 
    251 void dce_ipp_construct(
    252 	struct dce_ipp *ipp_dce,
    253 	struct dc_context *ctx,
    254 	int inst,
    255 	const struct dce_ipp_registers *regs,
    256 	const struct dce_ipp_shift *ipp_shift,
    257 	const struct dce_ipp_mask *ipp_mask)
    258 {
    259 	ipp_dce->base.ctx = ctx;
    260 	ipp_dce->base.inst = inst;
    261 	ipp_dce->base.funcs = &dce_ipp_funcs;
    262 
    263 	ipp_dce->regs = regs;
    264 	ipp_dce->ipp_shift = ipp_shift;
    265 	ipp_dce->ipp_mask = ipp_mask;
    266 }
    267 
    268 void dce_ipp_destroy(struct input_pixel_processor **ipp)
    269 {
    270 	kfree(TO_DCE_IPP(*ipp));
    271 	*ipp = NULL;
    272 }
    273