linux/drivers/gpu/drm/amd/display/dc/dc_helper.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 */
  23/*
  24 * dc_helper.c
  25 *
  26 *  Created on: Aug 30, 2016
  27 *      Author: agrodzov
  28 */
  29
  30#include <linux/delay.h>
  31
  32#include "dm_services.h"
  33#include <stdarg.h>
  34
  35struct dc_reg_value_masks {
  36        uint32_t value;
  37        uint32_t mask;
  38};
  39
  40struct dc_reg_sequence {
  41        uint32_t addr;
  42        struct dc_reg_value_masks value_masks;
  43};
  44
  45static inline void set_reg_field_value_masks(
  46        struct dc_reg_value_masks *field_value_mask,
  47        uint32_t value,
  48        uint32_t mask,
  49        uint8_t shift)
  50{
  51        ASSERT(mask != 0);
  52
  53        field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift));
  54        field_value_mask->mask = field_value_mask->mask | mask;
  55}
  56
  57static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask,
  58                uint32_t addr, int n,
  59                uint8_t shift1, uint32_t mask1, uint32_t field_value1,
  60                va_list ap)
  61{
  62        uint32_t shift, mask, field_value;
  63        int i = 1;
  64
  65        /* gather all bits value/mask getting updated in this register */
  66        set_reg_field_value_masks(field_value_mask,
  67                        field_value1, mask1, shift1);
  68
  69        while (i < n) {
  70                shift = va_arg(ap, uint32_t);
  71                mask = va_arg(ap, uint32_t);
  72                field_value = va_arg(ap, uint32_t);
  73
  74                set_reg_field_value_masks(field_value_mask,
  75                                field_value, mask, shift);
  76                i++;
  77        }
  78}
  79
  80uint32_t generic_reg_update_ex(const struct dc_context *ctx,
  81                uint32_t addr, int n,
  82                uint8_t shift1, uint32_t mask1, uint32_t field_value1,
  83                ...)
  84{
  85        struct dc_reg_value_masks field_value_mask = {0};
  86        uint32_t reg_val;
  87        va_list ap;
  88
  89        va_start(ap, field_value1);
  90
  91        set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
  92                        field_value1, ap);
  93
  94        va_end(ap);
  95
  96        /* mmio write directly */
  97        reg_val = dm_read_reg(ctx, addr);
  98        reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
  99        dm_write_reg(ctx, addr, reg_val);
 100        return reg_val;
 101}
 102
 103uint32_t generic_reg_set_ex(const struct dc_context *ctx,
 104                uint32_t addr, uint32_t reg_val, int n,
 105                uint8_t shift1, uint32_t mask1, uint32_t field_value1,
 106                ...)
 107{
 108        struct dc_reg_value_masks field_value_mask = {0};
 109        va_list ap;
 110
 111        va_start(ap, field_value1);
 112
 113        set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
 114                        field_value1, ap);
 115
 116        va_end(ap);
 117
 118
 119        /* mmio write directly */
 120        reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
 121        dm_write_reg(ctx, addr, reg_val);
 122        return reg_val;
 123}
 124
 125uint32_t dm_read_reg_func(
 126        const struct dc_context *ctx,
 127        uint32_t address,
 128        const char *func_name)
 129{
 130        uint32_t value;
 131#ifdef DM_CHECK_ADDR_0
 132        if (address == 0) {
 133                DC_ERR("invalid register read; address = 0\n");
 134                return 0;
 135        }
 136#endif
 137        value = cgs_read_register(ctx->cgs_device, address);
 138        trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value);
 139
 140        return value;
 141}
 142
 143uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr,
 144                uint8_t shift, uint32_t mask, uint32_t *field_value)
 145{
 146        uint32_t reg_val = dm_read_reg(ctx, addr);
 147        *field_value = get_reg_field_value_ex(reg_val, mask, shift);
 148        return reg_val;
 149}
 150
 151uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr,
 152                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 153                uint8_t shift2, uint32_t mask2, uint32_t *field_value2)
 154{
 155        uint32_t reg_val = dm_read_reg(ctx, addr);
 156        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 157        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 158        return reg_val;
 159}
 160
 161uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr,
 162                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 163                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 164                uint8_t shift3, uint32_t mask3, uint32_t *field_value3)
 165{
 166        uint32_t reg_val = dm_read_reg(ctx, addr);
 167        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 168        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 169        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 170        return reg_val;
 171}
 172
 173uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr,
 174                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 175                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 176                uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
 177                uint8_t shift4, uint32_t mask4, uint32_t *field_value4)
 178{
 179        uint32_t reg_val = dm_read_reg(ctx, addr);
 180        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 181        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 182        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 183        *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
 184        return reg_val;
 185}
 186
 187uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr,
 188                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 189                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 190                uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
 191                uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
 192                uint8_t shift5, uint32_t mask5, uint32_t *field_value5)
 193{
 194        uint32_t reg_val = dm_read_reg(ctx, addr);
 195        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 196        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 197        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 198        *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
 199        *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
 200        return reg_val;
 201}
 202
 203uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr,
 204                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 205                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 206                uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
 207                uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
 208                uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
 209                uint8_t shift6, uint32_t mask6, uint32_t *field_value6)
 210{
 211        uint32_t reg_val = dm_read_reg(ctx, addr);
 212        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 213        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 214        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 215        *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
 216        *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
 217        *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
 218        return reg_val;
 219}
 220
 221uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr,
 222                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 223                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 224                uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
 225                uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
 226                uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
 227                uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
 228                uint8_t shift7, uint32_t mask7, uint32_t *field_value7)
 229{
 230        uint32_t reg_val = dm_read_reg(ctx, addr);
 231        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 232        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 233        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 234        *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
 235        *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
 236        *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
 237        *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
 238        return reg_val;
 239}
 240
 241uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr,
 242                uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
 243                uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
 244                uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
 245                uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
 246                uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
 247                uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
 248                uint8_t shift7, uint32_t mask7, uint32_t *field_value7,
 249                uint8_t shift8, uint32_t mask8, uint32_t *field_value8)
 250{
 251        uint32_t reg_val = dm_read_reg(ctx, addr);
 252        *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
 253        *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
 254        *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
 255        *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
 256        *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
 257        *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
 258        *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
 259        *field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8);
 260        return reg_val;
 261}
 262/* note:  va version of this is pretty bad idea, since there is a output parameter pass by pointer
 263 * compiler won't be able to check for size match and is prone to stack corruption type of bugs
 264
 265uint32_t generic_reg_get(const struct dc_context *ctx,
 266                uint32_t addr, int n, ...)
 267{
 268        uint32_t shift, mask;
 269        uint32_t *field_value;
 270        uint32_t reg_val;
 271        int i = 0;
 272
 273        reg_val = dm_read_reg(ctx, addr);
 274
 275        va_list ap;
 276        va_start(ap, n);
 277
 278        while (i < n) {
 279                shift = va_arg(ap, uint32_t);
 280                mask = va_arg(ap, uint32_t);
 281                field_value = va_arg(ap, uint32_t *);
 282
 283                *field_value = get_reg_field_value_ex(reg_val, mask, shift);
 284                i++;
 285        }
 286
 287        va_end(ap);
 288
 289        return reg_val;
 290}
 291*/
 292
 293void generic_reg_wait(const struct dc_context *ctx,
 294        uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,
 295        unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
 296        const char *func_name, int line)
 297{
 298        uint32_t field_value;
 299        uint32_t reg_val;
 300        int i;
 301
 302        /* something is terribly wrong if time out is > 200ms. (5Hz) */
 303        ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000);
 304
 305        for (i = 0; i <= time_out_num_tries; i++) {
 306                if (i) {
 307                        if (delay_between_poll_us >= 1000)
 308                                msleep(delay_between_poll_us/1000);
 309                        else if (delay_between_poll_us > 0)
 310                                udelay(delay_between_poll_us);
 311                }
 312
 313                reg_val = dm_read_reg(ctx, addr);
 314
 315                field_value = get_reg_field_value_ex(reg_val, mask, shift);
 316
 317                if (field_value == condition_value) {
 318                        if (i * delay_between_poll_us > 1000 &&
 319                                        !IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
 320                                DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",
 321                                                delay_between_poll_us * i / 1000,
 322                                                func_name, line);
 323                        return;
 324                }
 325        }
 326
 327        DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
 328                        delay_between_poll_us, time_out_num_tries,
 329                        func_name, line);
 330
 331        if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
 332                BREAK_TO_DEBUGGER();
 333}
 334
 335void generic_write_indirect_reg(const struct dc_context *ctx,
 336                uint32_t addr_index, uint32_t addr_data,
 337                uint32_t index, uint32_t data)
 338{
 339        dm_write_reg(ctx, addr_index, index);
 340        dm_write_reg(ctx, addr_data, data);
 341}
 342
 343uint32_t generic_read_indirect_reg(const struct dc_context *ctx,
 344                uint32_t addr_index, uint32_t addr_data,
 345                uint32_t index)
 346{
 347        uint32_t value = 0;
 348
 349        dm_write_reg(ctx, addr_index, index);
 350        value = dm_read_reg(ctx, addr_data);
 351
 352        return value;
 353}
 354
 355
 356uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
 357                uint32_t addr_index, uint32_t addr_data,
 358                uint32_t index, uint32_t reg_val, int n,
 359                uint8_t shift1, uint32_t mask1, uint32_t field_value1,
 360                ...)
 361{
 362        uint32_t shift, mask, field_value;
 363        int i = 1;
 364
 365        va_list ap;
 366
 367        va_start(ap, field_value1);
 368
 369        reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
 370
 371        while (i < n) {
 372                shift = va_arg(ap, uint32_t);
 373                mask = va_arg(ap, uint32_t);
 374                field_value = va_arg(ap, uint32_t);
 375
 376                reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
 377                i++;
 378        }
 379
 380        generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val);
 381        va_end(ap);
 382
 383        return reg_val;
 384}
 385