linux/drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c
<<
>>
Prefs
   1/*
   2 * Copyright 2017 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#include <linux/slab.h>
  27
  28#include "dce_ipp.h"
  29#include "reg_helper.h"
  30#include "dm_services.h"
  31
  32#define REG(reg) \
  33        (ipp_dce->regs->reg)
  34
  35#undef FN
  36#define FN(reg_name, field_name) \
  37        ipp_dce->ipp_shift->field_name, ipp_dce->ipp_mask->field_name
  38
  39#define CTX \
  40        ipp_dce->base.ctx
  41
  42
  43static void dce_ipp_cursor_set_position(
  44        struct input_pixel_processor *ipp,
  45        const struct dc_cursor_position *position,
  46        const struct dc_cursor_mi_param *param)
  47{
  48        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
  49
  50        /* lock cursor registers */
  51        REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
  52
  53        /* Flag passed in structure differentiates cursor enable/disable. */
  54        /* Update if it differs from cached state. */
  55        REG_UPDATE(CUR_CONTROL, CURSOR_EN, position->enable);
  56
  57        REG_SET_2(CUR_POSITION, 0,
  58                CURSOR_X_POSITION, position->x,
  59                CURSOR_Y_POSITION, position->y);
  60
  61        REG_SET_2(CUR_HOT_SPOT, 0,
  62                CURSOR_HOT_SPOT_X, position->x_hotspot,
  63                CURSOR_HOT_SPOT_Y, position->y_hotspot);
  64
  65        /* unlock cursor registers */
  66        REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
  67}
  68
  69static void dce_ipp_cursor_set_attributes(
  70        struct input_pixel_processor *ipp,
  71        const struct dc_cursor_attributes *attributes)
  72{
  73        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
  74        int mode;
  75
  76        /* Lock cursor registers */
  77        REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, true);
  78
  79        /* Program cursor control */
  80        switch (attributes->color_format) {
  81        case CURSOR_MODE_MONO:
  82                mode = 0;
  83                break;
  84        case CURSOR_MODE_COLOR_1BIT_AND:
  85                mode = 1;
  86                break;
  87        case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
  88                mode = 2;
  89                break;
  90        case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
  91                mode = 3;
  92                break;
  93        default:
  94                BREAK_TO_DEBUGGER(); /* unsupported */
  95                mode = 0;
  96        }
  97
  98        REG_UPDATE_3(CUR_CONTROL,
  99                CURSOR_MODE, mode,
 100                CURSOR_2X_MAGNIFY, attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
 101                CUR_INV_TRANS_CLAMP, attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
 102
 103        if (attributes->color_format == CURSOR_MODE_MONO) {
 104                REG_SET_3(CUR_COLOR1, 0,
 105                        CUR_COLOR1_BLUE, 0,
 106                        CUR_COLOR1_GREEN, 0,
 107                        CUR_COLOR1_RED, 0);
 108
 109                REG_SET_3(CUR_COLOR2, 0,
 110                        CUR_COLOR2_BLUE, 0xff,
 111                        CUR_COLOR2_GREEN, 0xff,
 112                        CUR_COLOR2_RED, 0xff);
 113        }
 114
 115        /*
 116         * Program cursor size -- NOTE: HW spec specifies that HW register
 117         * stores size as (height - 1, width - 1)
 118         */
 119        REG_SET_2(CUR_SIZE, 0,
 120                CURSOR_WIDTH, attributes->width-1,
 121                CURSOR_HEIGHT, attributes->height-1);
 122
 123        /* Program cursor surface address */
 124        /* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
 125         * surface base address in byte. It is 4K byte aligned.
 126         * The correct way to program cursor surface address is to first write
 127         * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS
 128         */
 129        REG_SET(CUR_SURFACE_ADDRESS_HIGH, 0,
 130                CURSOR_SURFACE_ADDRESS_HIGH, attributes->address.high_part);
 131
 132        REG_SET(CUR_SURFACE_ADDRESS, 0,
 133                CURSOR_SURFACE_ADDRESS, attributes->address.low_part);
 134
 135        /* Unlock Cursor registers. */
 136        REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
 137}
 138
 139
 140static void dce_ipp_program_prescale(struct input_pixel_processor *ipp,
 141                                     struct ipp_prescale_params *params)
 142{
 143        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
 144
 145        /* set to bypass mode first before change */
 146        REG_UPDATE(PRESCALE_GRPH_CONTROL,
 147                   GRPH_PRESCALE_BYPASS, 1);
 148
 149        REG_SET_2(PRESCALE_VALUES_GRPH_R, 0,
 150                  GRPH_PRESCALE_SCALE_R, params->scale,
 151                  GRPH_PRESCALE_BIAS_R, params->bias);
 152
 153        REG_SET_2(PRESCALE_VALUES_GRPH_G, 0,
 154                  GRPH_PRESCALE_SCALE_G, params->scale,
 155                  GRPH_PRESCALE_BIAS_G, params->bias);
 156
 157        REG_SET_2(PRESCALE_VALUES_GRPH_B, 0,
 158                  GRPH_PRESCALE_SCALE_B, params->scale,
 159                  GRPH_PRESCALE_BIAS_B, params->bias);
 160
 161        if (params->mode != IPP_PRESCALE_MODE_BYPASS) {
 162                REG_UPDATE(PRESCALE_GRPH_CONTROL,
 163                           GRPH_PRESCALE_BYPASS, 0);
 164
 165                /* If prescale is in use, then legacy lut should be bypassed */
 166                REG_UPDATE(INPUT_GAMMA_CONTROL,
 167                           GRPH_INPUT_GAMMA_MODE, 1);
 168        }
 169}
 170
 171static void dce_ipp_program_input_lut(
 172        struct input_pixel_processor *ipp,
 173        const struct dc_gamma *gamma)
 174{
 175        int i;
 176        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
 177
 178        /* power on LUT memory */
 179        if (REG(DCFE_MEM_PWR_CTRL))
 180                REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 1);
 181
 182        /* enable all */
 183        REG_SET(DC_LUT_WRITE_EN_MASK, 0, DC_LUT_WRITE_EN_MASK, 0x7);
 184
 185        /* 256 entry mode */
 186        REG_UPDATE(DC_LUT_RW_MODE, DC_LUT_RW_MODE, 0);
 187
 188        /* LUT-256, unsigned, integer, new u0.12 format */
 189        REG_SET_3(DC_LUT_CONTROL, 0,
 190                DC_LUT_DATA_R_FORMAT, 3,
 191                DC_LUT_DATA_G_FORMAT, 3,
 192                DC_LUT_DATA_B_FORMAT, 3);
 193
 194        /* start from index 0 */
 195        REG_SET(DC_LUT_RW_INDEX, 0,
 196                DC_LUT_RW_INDEX, 0);
 197
 198        for (i = 0; i < gamma->num_entries; i++) {
 199                REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
 200                                dc_fixpt_round(
 201                                        gamma->entries.red[i]));
 202                REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
 203                                dc_fixpt_round(
 204                                        gamma->entries.green[i]));
 205                REG_SET(DC_LUT_SEQ_COLOR, 0, DC_LUT_SEQ_COLOR,
 206                                dc_fixpt_round(
 207                                        gamma->entries.blue[i]));
 208        }
 209
 210        /* power off LUT memory */
 211        if (REG(DCFE_MEM_PWR_CTRL))
 212                REG_SET(DCFE_MEM_PWR_CTRL, 0, DCP_LUT_MEM_PWR_DIS, 0);
 213
 214        /* bypass prescale, enable legacy LUT */
 215        REG_UPDATE(PRESCALE_GRPH_CONTROL, GRPH_PRESCALE_BYPASS, 1);
 216        REG_UPDATE(INPUT_GAMMA_CONTROL, GRPH_INPUT_GAMMA_MODE, 0);
 217}
 218
 219static void dce_ipp_set_degamma(
 220        struct input_pixel_processor *ipp,
 221        enum ipp_degamma_mode mode)
 222{
 223        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
 224        uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
 225
 226        ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS || mode == IPP_DEGAMMA_MODE_HW_sRGB);
 227
 228        REG_SET_3(DEGAMMA_CONTROL, 0,
 229                  GRPH_DEGAMMA_MODE, degamma_type,
 230                  CURSOR_DEGAMMA_MODE, degamma_type,
 231                  CURSOR2_DEGAMMA_MODE, degamma_type);
 232}
 233
 234#if defined(CONFIG_DRM_AMD_DC_SI)
 235static void dce60_ipp_set_degamma(
 236        struct input_pixel_processor *ipp,
 237        enum ipp_degamma_mode mode)
 238{
 239        struct dce_ipp *ipp_dce = TO_DCE_IPP(ipp);
 240        uint32_t degamma_type = (mode == IPP_DEGAMMA_MODE_HW_sRGB) ? 1 : 0;
 241
 242        ASSERT(mode == IPP_DEGAMMA_MODE_BYPASS || mode == IPP_DEGAMMA_MODE_HW_sRGB);
 243        /* DCE6 does not have CURSOR2_DEGAMMA_MODE bit in DEGAMMA_CONTROL reg */
 244        REG_SET_2(DEGAMMA_CONTROL, 0,
 245                  GRPH_DEGAMMA_MODE, degamma_type,
 246                  CURSOR_DEGAMMA_MODE, degamma_type);
 247}
 248#endif
 249
 250static const struct ipp_funcs dce_ipp_funcs = {
 251        .ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes,
 252        .ipp_cursor_set_position = dce_ipp_cursor_set_position,
 253        .ipp_program_prescale = dce_ipp_program_prescale,
 254        .ipp_program_input_lut = dce_ipp_program_input_lut,
 255        .ipp_set_degamma = dce_ipp_set_degamma
 256};
 257
 258#if defined(CONFIG_DRM_AMD_DC_SI)
 259static const struct ipp_funcs dce60_ipp_funcs = {
 260        .ipp_cursor_set_attributes = dce_ipp_cursor_set_attributes,
 261        .ipp_cursor_set_position = dce_ipp_cursor_set_position,
 262        .ipp_program_prescale = dce_ipp_program_prescale,
 263        .ipp_program_input_lut = dce_ipp_program_input_lut,
 264        .ipp_set_degamma = dce60_ipp_set_degamma
 265};
 266#endif
 267
 268
 269/*****************************************/
 270/* Constructor, Destructor               */
 271/*****************************************/
 272
 273void dce_ipp_construct(
 274        struct dce_ipp *ipp_dce,
 275        struct dc_context *ctx,
 276        int inst,
 277        const struct dce_ipp_registers *regs,
 278        const struct dce_ipp_shift *ipp_shift,
 279        const struct dce_ipp_mask *ipp_mask)
 280{
 281        ipp_dce->base.ctx = ctx;
 282        ipp_dce->base.inst = inst;
 283        ipp_dce->base.funcs = &dce_ipp_funcs;
 284
 285        ipp_dce->regs = regs;
 286        ipp_dce->ipp_shift = ipp_shift;
 287        ipp_dce->ipp_mask = ipp_mask;
 288}
 289
 290#if defined(CONFIG_DRM_AMD_DC_SI)
 291void dce60_ipp_construct(
 292        struct dce_ipp *ipp_dce,
 293        struct dc_context *ctx,
 294        int inst,
 295        const struct dce_ipp_registers *regs,
 296        const struct dce_ipp_shift *ipp_shift,
 297        const struct dce_ipp_mask *ipp_mask)
 298{
 299        ipp_dce->base.ctx = ctx;
 300        ipp_dce->base.inst = inst;
 301        ipp_dce->base.funcs = &dce60_ipp_funcs;
 302
 303        ipp_dce->regs = regs;
 304        ipp_dce->ipp_shift = ipp_shift;
 305        ipp_dce->ipp_mask = ipp_mask;
 306}
 307#endif
 308
 309void dce_ipp_destroy(struct input_pixel_processor **ipp)
 310{
 311        kfree(TO_DCE_IPP(*ipp));
 312        *ipp = NULL;
 313}
 314