LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/dc - dc_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 295 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 27 0.0 %

          Line data    Source code
       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             : #include <linux/stdarg.h>
      32             : 
      33             : #include "dm_services.h"
      34             : 
      35             : #include "dc.h"
      36             : #include "dc_dmub_srv.h"
      37             : #include "reg_helper.h"
      38             : 
      39           0 : static inline void submit_dmub_read_modify_write(
      40             :         struct dc_reg_helper_state *offload,
      41             :         const struct dc_context *ctx)
      42             : {
      43           0 :         struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write;
      44           0 :         bool gather = false;
      45             : 
      46           0 :         offload->should_burst_write =
      47           0 :                         (offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1));
      48           0 :         cmd_buf->header.payload_bytes =
      49           0 :                         sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count;
      50             : 
      51           0 :         gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress;
      52           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = false;
      53             : 
      54           0 :         dc_dmub_srv_cmd_queue(ctx->dmub_srv, &offload->cmd_data);
      55             : 
      56           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather;
      57             : 
      58           0 :         memset(cmd_buf, 0, sizeof(*cmd_buf));
      59             : 
      60           0 :         offload->reg_seq_count = 0;
      61           0 :         offload->same_addr_count = 0;
      62           0 : }
      63             : 
      64           0 : static inline void submit_dmub_burst_write(
      65             :         struct dc_reg_helper_state *offload,
      66             :         const struct dc_context *ctx)
      67             : {
      68           0 :         struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write;
      69           0 :         bool gather = false;
      70             : 
      71           0 :         cmd_buf->header.payload_bytes =
      72           0 :                         sizeof(uint32_t) * offload->reg_seq_count;
      73             : 
      74           0 :         gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress;
      75           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = false;
      76             : 
      77           0 :         dc_dmub_srv_cmd_queue(ctx->dmub_srv, &offload->cmd_data);
      78             : 
      79           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather;
      80             : 
      81           0 :         memset(cmd_buf, 0, sizeof(*cmd_buf));
      82             : 
      83           0 :         offload->reg_seq_count = 0;
      84           0 : }
      85             : 
      86           0 : static inline void submit_dmub_reg_wait(
      87             :                 struct dc_reg_helper_state *offload,
      88             :                 const struct dc_context *ctx)
      89             : {
      90           0 :         struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait;
      91           0 :         bool gather = false;
      92             : 
      93           0 :         gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress;
      94           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = false;
      95             : 
      96           0 :         dc_dmub_srv_cmd_queue(ctx->dmub_srv, &offload->cmd_data);
      97             : 
      98           0 :         memset(cmd_buf, 0, sizeof(*cmd_buf));
      99           0 :         offload->reg_seq_count = 0;
     100             : 
     101           0 :         ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather;
     102           0 : }
     103             : 
     104             : struct dc_reg_value_masks {
     105             :         uint32_t value;
     106             :         uint32_t mask;
     107             : };
     108             : 
     109             : struct dc_reg_sequence {
     110             :         uint32_t addr;
     111             :         struct dc_reg_value_masks value_masks;
     112             : };
     113             : 
     114           0 : static inline void set_reg_field_value_masks(
     115             :         struct dc_reg_value_masks *field_value_mask,
     116             :         uint32_t value,
     117             :         uint32_t mask,
     118             :         uint8_t shift)
     119             : {
     120           0 :         ASSERT(mask != 0);
     121             : 
     122           0 :         field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift));
     123           0 :         field_value_mask->mask = field_value_mask->mask | mask;
     124           0 : }
     125             : 
     126           0 : static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask,
     127             :                 uint32_t addr, int n,
     128             :                 uint8_t shift1, uint32_t mask1, uint32_t field_value1,
     129             :                 va_list ap)
     130             : {
     131             :         uint32_t shift, mask, field_value;
     132           0 :         int i = 1;
     133             : 
     134             :         /* gather all bits value/mask getting updated in this register */
     135           0 :         set_reg_field_value_masks(field_value_mask,
     136             :                         field_value1, mask1, shift1);
     137             : 
     138           0 :         while (i < n) {
     139           0 :                 shift = va_arg(ap, uint32_t);
     140           0 :                 mask = va_arg(ap, uint32_t);
     141           0 :                 field_value = va_arg(ap, uint32_t);
     142             : 
     143           0 :                 set_reg_field_value_masks(field_value_mask,
     144             :                                 field_value, mask, shift);
     145           0 :                 i++;
     146             :         }
     147           0 : }
     148             : 
     149             : static void dmub_flush_buffer_execute(
     150             :                 struct dc_reg_helper_state *offload,
     151             :                 const struct dc_context *ctx)
     152             : {
     153           0 :         submit_dmub_read_modify_write(offload, ctx);
     154           0 :         dc_dmub_srv_cmd_execute(ctx->dmub_srv);
     155             : }
     156             : 
     157             : static void dmub_flush_burst_write_buffer_execute(
     158             :                 struct dc_reg_helper_state *offload,
     159             :                 const struct dc_context *ctx)
     160             : {
     161           0 :         submit_dmub_burst_write(offload, ctx);
     162           0 :         dc_dmub_srv_cmd_execute(ctx->dmub_srv);
     163             : }
     164             : 
     165           0 : static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr,
     166             :                 uint32_t reg_val)
     167             : {
     168           0 :         struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;
     169           0 :         struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write;
     170             : 
     171             :         /* flush command if buffer is full */
     172           0 :         if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX)
     173             :                 dmub_flush_burst_write_buffer_execute(offload, ctx);
     174             : 
     175           0 :         if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE &&
     176           0 :                         addr != cmd_buf->addr) {
     177           0 :                 dmub_flush_burst_write_buffer_execute(offload, ctx);
     178           0 :                 return false;
     179             :         }
     180             : 
     181           0 :         cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE;
     182           0 :         cmd_buf->header.sub_type = 0;
     183           0 :         cmd_buf->addr = addr;
     184           0 :         cmd_buf->write_values[offload->reg_seq_count] = reg_val;
     185           0 :         offload->reg_seq_count++;
     186             : 
     187           0 :         return true;
     188             : }
     189             : 
     190           0 : static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr,
     191             :                 struct dc_reg_value_masks *field_value_mask)
     192             : {
     193           0 :         struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;
     194           0 :         struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write;
     195             :         struct dmub_cmd_read_modify_write_sequence *seq;
     196             : 
     197             :         /* flush command if buffer is full */
     198           0 :         if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE &&
     199           0 :                         offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX)
     200             :                 dmub_flush_buffer_execute(offload, ctx);
     201             : 
     202           0 :         if (offload->should_burst_write) {
     203           0 :                 if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value))
     204           0 :                         return field_value_mask->value;
     205             :                 else
     206           0 :                         offload->should_burst_write = false;
     207             :         }
     208             : 
     209             :         /* pack commands */
     210           0 :         cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE;
     211           0 :         cmd_buf->header.sub_type = 0;
     212           0 :         seq = &cmd_buf->seq[offload->reg_seq_count];
     213             : 
     214           0 :         if (offload->reg_seq_count) {
     215           0 :                 if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr)
     216           0 :                         offload->same_addr_count++;
     217             :                 else
     218           0 :                         offload->same_addr_count = 0;
     219             :         }
     220             : 
     221           0 :         seq->addr = addr;
     222           0 :         seq->modify_mask = field_value_mask->mask;
     223           0 :         seq->modify_value = field_value_mask->value;
     224           0 :         offload->reg_seq_count++;
     225             : 
     226           0 :         return field_value_mask->value;
     227             : }
     228             : 
     229             : static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr,
     230             :                 uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us)
     231             : {
     232           0 :         struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload;
     233           0 :         struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait;
     234             : 
     235           0 :         cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT;
     236           0 :         cmd_buf->header.sub_type = 0;
     237           0 :         cmd_buf->reg_wait.addr = addr;
     238           0 :         cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift);
     239           0 :         cmd_buf->reg_wait.mask = mask;
     240           0 :         cmd_buf->reg_wait.time_out_us = time_out_us;
     241             : }
     242             : 
     243           0 : uint32_t generic_reg_update_ex(const struct dc_context *ctx,
     244             :                 uint32_t addr, int n,
     245             :                 uint8_t shift1, uint32_t mask1, uint32_t field_value1,
     246             :                 ...)
     247             : {
     248           0 :         struct dc_reg_value_masks field_value_mask = {0};
     249             :         uint32_t reg_val;
     250             :         va_list ap;
     251             : 
     252           0 :         va_start(ap, field_value1);
     253             : 
     254           0 :         set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
     255             :                         field_value1, ap);
     256             : 
     257           0 :         va_end(ap);
     258             : 
     259           0 :         if (ctx->dmub_srv &&
     260           0 :             ctx->dmub_srv->reg_helper_offload.gather_in_progress)
     261           0 :                 return dmub_reg_value_pack(ctx, addr, &field_value_mask);
     262             :                 /* todo: return void so we can decouple code running in driver from register states */
     263             : 
     264             :         /* mmio write directly */
     265           0 :         reg_val = dm_read_reg(ctx, addr);
     266           0 :         reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
     267           0 :         dm_write_reg(ctx, addr, reg_val);
     268           0 :         return reg_val;
     269             : }
     270             : 
     271           0 : uint32_t generic_reg_set_ex(const struct dc_context *ctx,
     272             :                 uint32_t addr, uint32_t reg_val, int n,
     273             :                 uint8_t shift1, uint32_t mask1, uint32_t field_value1,
     274             :                 ...)
     275             : {
     276           0 :         struct dc_reg_value_masks field_value_mask = {0};
     277             :         va_list ap;
     278             : 
     279           0 :         va_start(ap, field_value1);
     280             : 
     281           0 :         set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
     282             :                         field_value1, ap);
     283             : 
     284           0 :         va_end(ap);
     285             : 
     286             : 
     287             :         /* mmio write directly */
     288           0 :         reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
     289             : 
     290           0 :         if (ctx->dmub_srv &&
     291           0 :             ctx->dmub_srv->reg_helper_offload.gather_in_progress) {
     292           0 :                 return dmub_reg_value_burst_set_pack(ctx, addr, reg_val);
     293             :                 /* todo: return void so we can decouple code running in driver from register states */
     294             :         }
     295             : 
     296           0 :         dm_write_reg(ctx, addr, reg_val);
     297           0 :         return reg_val;
     298             : }
     299             : 
     300           0 : uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr,
     301             :                 uint8_t shift, uint32_t mask, uint32_t *field_value)
     302             : {
     303           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     304           0 :         *field_value = get_reg_field_value_ex(reg_val, mask, shift);
     305           0 :         return reg_val;
     306             : }
     307             : 
     308           0 : uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr,
     309             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     310             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2)
     311             : {
     312           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     313           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     314           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     315           0 :         return reg_val;
     316             : }
     317             : 
     318           0 : uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr,
     319             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     320             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     321             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3)
     322             : {
     323           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     324           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     325           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     326           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     327           0 :         return reg_val;
     328             : }
     329             : 
     330           0 : uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr,
     331             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     332             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     333             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
     334             :                 uint8_t shift4, uint32_t mask4, uint32_t *field_value4)
     335             : {
     336           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     337           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     338           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     339           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     340           0 :         *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
     341           0 :         return reg_val;
     342             : }
     343             : 
     344           0 : uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr,
     345             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     346             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     347             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
     348             :                 uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
     349             :                 uint8_t shift5, uint32_t mask5, uint32_t *field_value5)
     350             : {
     351           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     352           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     353           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     354           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     355           0 :         *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
     356           0 :         *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
     357           0 :         return reg_val;
     358             : }
     359             : 
     360           0 : uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr,
     361             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     362             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     363             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
     364             :                 uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
     365             :                 uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
     366             :                 uint8_t shift6, uint32_t mask6, uint32_t *field_value6)
     367             : {
     368           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     369           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     370           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     371           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     372           0 :         *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
     373           0 :         *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
     374           0 :         *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
     375           0 :         return reg_val;
     376             : }
     377             : 
     378           0 : uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr,
     379             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     380             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     381             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
     382             :                 uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
     383             :                 uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
     384             :                 uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
     385             :                 uint8_t shift7, uint32_t mask7, uint32_t *field_value7)
     386             : {
     387           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     388           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     389           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     390           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     391           0 :         *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
     392           0 :         *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
     393           0 :         *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
     394           0 :         *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
     395           0 :         return reg_val;
     396             : }
     397             : 
     398           0 : uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr,
     399             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     400             :                 uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
     401             :                 uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
     402             :                 uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
     403             :                 uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
     404             :                 uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
     405             :                 uint8_t shift7, uint32_t mask7, uint32_t *field_value7,
     406             :                 uint8_t shift8, uint32_t mask8, uint32_t *field_value8)
     407             : {
     408           0 :         uint32_t reg_val = dm_read_reg(ctx, addr);
     409           0 :         *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
     410           0 :         *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
     411           0 :         *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
     412           0 :         *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
     413           0 :         *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
     414           0 :         *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
     415           0 :         *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
     416           0 :         *field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8);
     417           0 :         return reg_val;
     418             : }
     419             : /* note:  va version of this is pretty bad idea, since there is a output parameter pass by pointer
     420             :  * compiler won't be able to check for size match and is prone to stack corruption type of bugs
     421             : 
     422             : uint32_t generic_reg_get(const struct dc_context *ctx,
     423             :                 uint32_t addr, int n, ...)
     424             : {
     425             :         uint32_t shift, mask;
     426             :         uint32_t *field_value;
     427             :         uint32_t reg_val;
     428             :         int i = 0;
     429             : 
     430             :         reg_val = dm_read_reg(ctx, addr);
     431             : 
     432             :         va_list ap;
     433             :         va_start(ap, n);
     434             : 
     435             :         while (i < n) {
     436             :                 shift = va_arg(ap, uint32_t);
     437             :                 mask = va_arg(ap, uint32_t);
     438             :                 field_value = va_arg(ap, uint32_t *);
     439             : 
     440             :                 *field_value = get_reg_field_value_ex(reg_val, mask, shift);
     441             :                 i++;
     442             :         }
     443             : 
     444             :         va_end(ap);
     445             : 
     446             :         return reg_val;
     447             : }
     448             : */
     449             : 
     450           0 : void generic_reg_wait(const struct dc_context *ctx,
     451             :         uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,
     452             :         unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
     453             :         const char *func_name, int line)
     454             : {
     455             :         uint32_t field_value;
     456             :         uint32_t reg_val;
     457             :         int i;
     458             : 
     459           0 :         if (ctx->dmub_srv &&
     460           0 :             ctx->dmub_srv->reg_helper_offload.gather_in_progress) {
     461           0 :                 dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value,
     462             :                                 delay_between_poll_us * time_out_num_tries);
     463             :                 return;
     464             :         }
     465             : 
     466             :         /*
     467             :          * Something is terribly wrong if time out is > 3000ms.
     468             :          * 3000ms is the maximum time needed for SMU to pass values back.
     469             :          * This value comes from experiments.
     470             :          *
     471             :          */
     472           0 :         ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000);
     473             : 
     474           0 :         for (i = 0; i <= time_out_num_tries; i++) {
     475           0 :                 if (i) {
     476           0 :                         if (delay_between_poll_us >= 1000)
     477           0 :                                 msleep(delay_between_poll_us/1000);
     478           0 :                         else if (delay_between_poll_us > 0)
     479           0 :                                 udelay(delay_between_poll_us);
     480             :                 }
     481             : 
     482           0 :                 reg_val = dm_read_reg(ctx, addr);
     483             : 
     484           0 :                 field_value = get_reg_field_value_ex(reg_val, mask, shift);
     485             : 
     486           0 :                 if (field_value == condition_value) {
     487           0 :                         if (i * delay_between_poll_us > 1000 &&
     488           0 :                                         !IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
     489           0 :                                 DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",
     490             :                                                 delay_between_poll_us * i / 1000,
     491             :                                                 func_name, line);
     492             :                         return;
     493             :                 }
     494             :         }
     495             : 
     496           0 :         DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
     497             :                         delay_between_poll_us, time_out_num_tries,
     498             :                         func_name, line);
     499             : 
     500           0 :         if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
     501           0 :                 BREAK_TO_DEBUGGER();
     502             : }
     503             : 
     504           0 : void generic_write_indirect_reg(const struct dc_context *ctx,
     505             :                 uint32_t addr_index, uint32_t addr_data,
     506             :                 uint32_t index, uint32_t data)
     507             : {
     508           0 :         dm_write_reg(ctx, addr_index, index);
     509           0 :         dm_write_reg(ctx, addr_data, data);
     510           0 : }
     511             : 
     512           0 : uint32_t generic_read_indirect_reg(const struct dc_context *ctx,
     513             :                 uint32_t addr_index, uint32_t addr_data,
     514             :                 uint32_t index)
     515             : {
     516           0 :         uint32_t value = 0;
     517             : 
     518             :         // when reg read, there should not be any offload.
     519           0 :         if (ctx->dmub_srv &&
     520           0 :             ctx->dmub_srv->reg_helper_offload.gather_in_progress) {
     521           0 :                 ASSERT(false);
     522             :         }
     523             : 
     524           0 :         dm_write_reg(ctx, addr_index, index);
     525           0 :         value = dm_read_reg(ctx, addr_data);
     526             : 
     527           0 :         return value;
     528             : }
     529             : 
     530           0 : uint32_t generic_indirect_reg_get(const struct dc_context *ctx,
     531             :                 uint32_t addr_index, uint32_t addr_data,
     532             :                 uint32_t index, int n,
     533             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     534             :                 ...)
     535             : {
     536             :         uint32_t shift, mask, *field_value;
     537           0 :         uint32_t value = 0;
     538           0 :         int i = 1;
     539             : 
     540             :         va_list ap;
     541             : 
     542           0 :         va_start(ap, field_value1);
     543             : 
     544           0 :         value = generic_read_indirect_reg(ctx, addr_index, addr_data, index);
     545           0 :         *field_value1 = get_reg_field_value_ex(value, mask1, shift1);
     546             : 
     547           0 :         while (i < n) {
     548           0 :                 shift = va_arg(ap, uint32_t);
     549           0 :                 mask = va_arg(ap, uint32_t);
     550           0 :                 field_value = va_arg(ap, uint32_t *);
     551             : 
     552           0 :                 *field_value = get_reg_field_value_ex(value, mask, shift);
     553           0 :                 i++;
     554             :         }
     555             : 
     556           0 :         va_end(ap);
     557             : 
     558           0 :         return value;
     559             : }
     560             : 
     561           0 : uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
     562             :                 uint32_t addr_index, uint32_t addr_data,
     563             :                 uint32_t index, uint32_t reg_val, int n,
     564             :                 uint8_t shift1, uint32_t mask1, uint32_t field_value1,
     565             :                 ...)
     566             : {
     567             :         uint32_t shift, mask, field_value;
     568           0 :         int i = 1;
     569             : 
     570             :         va_list ap;
     571             : 
     572           0 :         va_start(ap, field_value1);
     573             : 
     574           0 :         reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
     575             : 
     576           0 :         while (i < n) {
     577           0 :                 shift = va_arg(ap, uint32_t);
     578           0 :                 mask = va_arg(ap, uint32_t);
     579           0 :                 field_value = va_arg(ap, uint32_t);
     580             : 
     581           0 :                 reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
     582           0 :                 i++;
     583             :         }
     584             : 
     585           0 :         generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val);
     586           0 :         va_end(ap);
     587             : 
     588           0 :         return reg_val;
     589             : }
     590             : 
     591             : 
     592           0 : uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx,
     593             :                 uint32_t index, uint32_t reg_val, int n,
     594             :                 uint8_t shift1, uint32_t mask1, uint32_t field_value1,
     595             :                 ...)
     596             : {
     597             :         uint32_t shift, mask, field_value;
     598           0 :         int i = 1;
     599             : 
     600             :         va_list ap;
     601             : 
     602           0 :         va_start(ap, field_value1);
     603             : 
     604           0 :         reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
     605             : 
     606           0 :         while (i < n) {
     607           0 :                 shift = va_arg(ap, uint32_t);
     608           0 :                 mask = va_arg(ap, uint32_t);
     609           0 :                 field_value = va_arg(ap, uint32_t);
     610             : 
     611           0 :                 reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
     612           0 :                 i++;
     613             :         }
     614             : 
     615           0 :         dm_write_index_reg(ctx, CGS_IND_REG__PCIE, index, reg_val);
     616           0 :         va_end(ap);
     617             : 
     618           0 :         return reg_val;
     619             : }
     620             : 
     621           0 : uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx,
     622             :                 uint32_t index, int n,
     623             :                 uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
     624             :                 ...)
     625             : {
     626             :         uint32_t shift, mask, *field_value;
     627           0 :         uint32_t value = 0;
     628           0 :         int i = 1;
     629             : 
     630             :         va_list ap;
     631             : 
     632           0 :         va_start(ap, field_value1);
     633             : 
     634           0 :         value = dm_read_index_reg(ctx, CGS_IND_REG__PCIE, index);
     635           0 :         *field_value1 = get_reg_field_value_ex(value, mask1, shift1);
     636             : 
     637           0 :         while (i < n) {
     638           0 :                 shift = va_arg(ap, uint32_t);
     639           0 :                 mask = va_arg(ap, uint32_t);
     640           0 :                 field_value = va_arg(ap, uint32_t *);
     641             : 
     642           0 :                 *field_value = get_reg_field_value_ex(value, mask, shift);
     643           0 :                 i++;
     644             :         }
     645             : 
     646           0 :         va_end(ap);
     647             : 
     648           0 :         return value;
     649             : }
     650             : 
     651           0 : void reg_sequence_start_gather(const struct dc_context *ctx)
     652             : {
     653             :         /* if reg sequence is supported and enabled, set flag to
     654             :          * indicate we want to have REG_SET, REG_UPDATE macro build
     655             :          * reg sequence command buffer rather than MMIO directly.
     656             :          */
     657             : 
     658           0 :         if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) {
     659           0 :                 struct dc_reg_helper_state *offload =
     660             :                         &ctx->dmub_srv->reg_helper_offload;
     661             : 
     662             :                 /* caller sequence mismatch.  need to debug caller.  offload will not work!!! */
     663           0 :                 ASSERT(!offload->gather_in_progress);
     664             : 
     665           0 :                 offload->gather_in_progress = true;
     666             :         }
     667           0 : }
     668             : 
     669           0 : void reg_sequence_start_execute(const struct dc_context *ctx)
     670             : {
     671             :         struct dc_reg_helper_state *offload;
     672             : 
     673           0 :         if (!ctx->dmub_srv)
     674             :                 return;
     675             : 
     676           0 :         offload = &ctx->dmub_srv->reg_helper_offload;
     677             : 
     678           0 :         if (offload && offload->gather_in_progress) {
     679           0 :                 offload->gather_in_progress = false;
     680           0 :                 offload->should_burst_write = false;
     681           0 :                 switch (offload->cmd_data.cmd_common.header.type) {
     682             :                 case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE:
     683           0 :                         submit_dmub_read_modify_write(offload, ctx);
     684           0 :                         break;
     685             :                 case DMUB_CMD__REG_REG_WAIT:
     686           0 :                         submit_dmub_reg_wait(offload, ctx);
     687           0 :                         break;
     688             :                 case DMUB_CMD__REG_SEQ_BURST_WRITE:
     689           0 :                         submit_dmub_burst_write(offload, ctx);
     690           0 :                         break;
     691             :                 default:
     692             :                         return;
     693             :                 }
     694             : 
     695           0 :                 dc_dmub_srv_cmd_execute(ctx->dmub_srv);
     696             :         }
     697             : }
     698             : 
     699           0 : void reg_sequence_wait_done(const struct dc_context *ctx)
     700             : {
     701             :         /* callback to DM to poll for last submission done*/
     702             :         struct dc_reg_helper_state *offload;
     703             : 
     704           0 :         if (!ctx->dmub_srv)
     705             :                 return;
     706             : 
     707           0 :         offload = &ctx->dmub_srv->reg_helper_offload;
     708             : 
     709           0 :         if (offload &&
     710           0 :             ctx->dc->debug.dmub_offload_enabled &&
     711           0 :             !ctx->dc->debug.dmcub_emulation) {
     712           0 :                 dc_dmub_srv_wait_idle(ctx->dmub_srv);
     713             :         }
     714             : }

Generated by: LCOV version 1.14