14562236bSHarry Wentland /* 2bf93b448SAlex Deucher * Copyright 2017 Advanced Micro Devices, Inc. 3bf93b448SAlex Deucher * 4bf93b448SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 5bf93b448SAlex Deucher * copy of this software and associated documentation files (the "Software"), 6bf93b448SAlex Deucher * to deal in the Software without restriction, including without limitation 7bf93b448SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf93b448SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 9bf93b448SAlex Deucher * Software is furnished to do so, subject to the following conditions: 10bf93b448SAlex Deucher * 11bf93b448SAlex Deucher * The above copyright notice and this permission notice shall be included in 12bf93b448SAlex Deucher * all copies or substantial portions of the Software. 13bf93b448SAlex Deucher * 14bf93b448SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15bf93b448SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf93b448SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf93b448SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18bf93b448SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19bf93b448SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20bf93b448SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 21bf93b448SAlex Deucher * 22bf93b448SAlex Deucher */ 23bf93b448SAlex Deucher /* 244562236bSHarry Wentland * dc_helper.c 254562236bSHarry Wentland * 264562236bSHarry Wentland * Created on: Aug 30, 2016 274562236bSHarry Wentland * Author: agrodzov 284562236bSHarry Wentland */ 29c366be54SSam Ravnborg 30c366be54SSam Ravnborg #include <linux/delay.h> 31c366be54SSam Ravnborg 324562236bSHarry Wentland #include "dm_services.h" 334562236bSHarry Wentland #include <stdarg.h> 344562236bSHarry Wentland 353a1627b0SNicholas Kazlauskas #include "dc.h" 363a1627b0SNicholas Kazlauskas #include "dc_dmub_srv.h" 373a1627b0SNicholas Kazlauskas 383a1627b0SNicholas Kazlauskas static inline void submit_dmub_read_modify_write( 393a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload, 403a1627b0SNicholas Kazlauskas const struct dc_context *ctx) 413a1627b0SNicholas Kazlauskas { 423a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; 433a1627b0SNicholas Kazlauskas bool gather = false; 443a1627b0SNicholas Kazlauskas 453a1627b0SNicholas Kazlauskas offload->should_burst_write = 463a1627b0SNicholas Kazlauskas (offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1)); 473a1627b0SNicholas Kazlauskas cmd_buf->header.payload_bytes = 483a1627b0SNicholas Kazlauskas sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count; 493a1627b0SNicholas Kazlauskas 503a1627b0SNicholas Kazlauskas gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; 513a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; 523a1627b0SNicholas Kazlauskas 533a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); 543a1627b0SNicholas Kazlauskas 553a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; 563a1627b0SNicholas Kazlauskas 573a1627b0SNicholas Kazlauskas memset(cmd_buf, 0, sizeof(*cmd_buf)); 583a1627b0SNicholas Kazlauskas 593a1627b0SNicholas Kazlauskas offload->reg_seq_count = 0; 603a1627b0SNicholas Kazlauskas offload->same_addr_count = 0; 613a1627b0SNicholas Kazlauskas } 623a1627b0SNicholas Kazlauskas 633a1627b0SNicholas Kazlauskas static inline void submit_dmub_burst_write( 643a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload, 653a1627b0SNicholas Kazlauskas const struct dc_context *ctx) 663a1627b0SNicholas Kazlauskas { 673a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; 683a1627b0SNicholas Kazlauskas bool gather = false; 693a1627b0SNicholas Kazlauskas 703a1627b0SNicholas Kazlauskas cmd_buf->header.payload_bytes = 713a1627b0SNicholas Kazlauskas sizeof(uint32_t) * offload->reg_seq_count; 723a1627b0SNicholas Kazlauskas 733a1627b0SNicholas Kazlauskas gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; 743a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; 753a1627b0SNicholas Kazlauskas 763a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); 773a1627b0SNicholas Kazlauskas 783a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; 793a1627b0SNicholas Kazlauskas 803a1627b0SNicholas Kazlauskas memset(cmd_buf, 0, sizeof(*cmd_buf)); 813a1627b0SNicholas Kazlauskas 823a1627b0SNicholas Kazlauskas offload->reg_seq_count = 0; 833a1627b0SNicholas Kazlauskas } 843a1627b0SNicholas Kazlauskas 853a1627b0SNicholas Kazlauskas static inline void submit_dmub_reg_wait( 863a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload, 873a1627b0SNicholas Kazlauskas const struct dc_context *ctx) 883a1627b0SNicholas Kazlauskas { 893a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; 903a1627b0SNicholas Kazlauskas bool gather = false; 913a1627b0SNicholas Kazlauskas 923a1627b0SNicholas Kazlauskas gather = ctx->dmub_srv->reg_helper_offload.gather_in_progress; 933a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = false; 943a1627b0SNicholas Kazlauskas 953a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd_buf->header); 963a1627b0SNicholas Kazlauskas 973a1627b0SNicholas Kazlauskas memset(cmd_buf, 0, sizeof(*cmd_buf)); 983a1627b0SNicholas Kazlauskas offload->reg_seq_count = 0; 993a1627b0SNicholas Kazlauskas 1003a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress = gather; 1013a1627b0SNicholas Kazlauskas } 1023a1627b0SNicholas Kazlauskas 10344788bbcSTony Cheng struct dc_reg_value_masks { 10444788bbcSTony Cheng uint32_t value; 10544788bbcSTony Cheng uint32_t mask; 10644788bbcSTony Cheng }; 10744788bbcSTony Cheng 10844788bbcSTony Cheng struct dc_reg_sequence { 10944788bbcSTony Cheng uint32_t addr; 11044788bbcSTony Cheng struct dc_reg_value_masks value_masks; 11144788bbcSTony Cheng }; 11244788bbcSTony Cheng 11344788bbcSTony Cheng static inline void set_reg_field_value_masks( 11444788bbcSTony Cheng struct dc_reg_value_masks *field_value_mask, 11544788bbcSTony Cheng uint32_t value, 11644788bbcSTony Cheng uint32_t mask, 11744788bbcSTony Cheng uint8_t shift) 11844788bbcSTony Cheng { 11944788bbcSTony Cheng ASSERT(mask != 0); 12044788bbcSTony Cheng 12144788bbcSTony Cheng field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift)); 12244788bbcSTony Cheng field_value_mask->mask = field_value_mask->mask | mask; 12344788bbcSTony Cheng } 12444788bbcSTony Cheng 125148cccf2SYongqiang Sun static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask, 126148cccf2SYongqiang Sun uint32_t addr, int n, 1274562236bSHarry Wentland uint8_t shift1, uint32_t mask1, uint32_t field_value1, 128148cccf2SYongqiang Sun va_list ap) 1294562236bSHarry Wentland { 1304562236bSHarry Wentland uint32_t shift, mask, field_value; 1314562236bSHarry Wentland int i = 1; 1324562236bSHarry Wentland 13344788bbcSTony Cheng /* gather all bits value/mask getting updated in this register */ 134148cccf2SYongqiang Sun set_reg_field_value_masks(field_value_mask, 13544788bbcSTony Cheng field_value1, mask1, shift1); 1364562236bSHarry Wentland 1374562236bSHarry Wentland while (i < n) { 1384562236bSHarry Wentland shift = va_arg(ap, uint32_t); 1394562236bSHarry Wentland mask = va_arg(ap, uint32_t); 1404562236bSHarry Wentland field_value = va_arg(ap, uint32_t); 1414562236bSHarry Wentland 142148cccf2SYongqiang Sun set_reg_field_value_masks(field_value_mask, 14344788bbcSTony Cheng field_value, mask, shift); 1444562236bSHarry Wentland i++; 1454562236bSHarry Wentland } 146148cccf2SYongqiang Sun } 147148cccf2SYongqiang Sun 1483a1627b0SNicholas Kazlauskas static void dmub_flush_buffer_execute( 1493a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload, 1503a1627b0SNicholas Kazlauskas const struct dc_context *ctx) 1513a1627b0SNicholas Kazlauskas { 1523a1627b0SNicholas Kazlauskas submit_dmub_read_modify_write(offload, ctx); 1533a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_execute(ctx->dmub_srv); 1543a1627b0SNicholas Kazlauskas } 1553a1627b0SNicholas Kazlauskas 1563a1627b0SNicholas Kazlauskas static void dmub_flush_burst_write_buffer_execute( 1573a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload, 1583a1627b0SNicholas Kazlauskas const struct dc_context *ctx) 1593a1627b0SNicholas Kazlauskas { 1603a1627b0SNicholas Kazlauskas submit_dmub_burst_write(offload, ctx); 1613a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_execute(ctx->dmub_srv); 1623a1627b0SNicholas Kazlauskas } 1633a1627b0SNicholas Kazlauskas 1643a1627b0SNicholas Kazlauskas static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr, 1653a1627b0SNicholas Kazlauskas uint32_t reg_val) 1663a1627b0SNicholas Kazlauskas { 1673a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; 1683a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; 1693a1627b0SNicholas Kazlauskas 1703a1627b0SNicholas Kazlauskas /* flush command if buffer is full */ 1713a1627b0SNicholas Kazlauskas if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX) 1723a1627b0SNicholas Kazlauskas dmub_flush_burst_write_buffer_execute(offload, ctx); 1733a1627b0SNicholas Kazlauskas 1743a1627b0SNicholas Kazlauskas if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE && 1753a1627b0SNicholas Kazlauskas addr != cmd_buf->addr) { 1763a1627b0SNicholas Kazlauskas dmub_flush_burst_write_buffer_execute(offload, ctx); 1773a1627b0SNicholas Kazlauskas return false; 1783a1627b0SNicholas Kazlauskas } 1793a1627b0SNicholas Kazlauskas 1803a1627b0SNicholas Kazlauskas cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE; 1813a1627b0SNicholas Kazlauskas cmd_buf->addr = addr; 1823a1627b0SNicholas Kazlauskas cmd_buf->write_values[offload->reg_seq_count] = reg_val; 1833a1627b0SNicholas Kazlauskas offload->reg_seq_count++; 1843a1627b0SNicholas Kazlauskas 1853a1627b0SNicholas Kazlauskas return true; 1863a1627b0SNicholas Kazlauskas } 1873a1627b0SNicholas Kazlauskas 1883a1627b0SNicholas Kazlauskas static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr, 1893a1627b0SNicholas Kazlauskas struct dc_reg_value_masks *field_value_mask) 1903a1627b0SNicholas Kazlauskas { 1913a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; 1923a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; 1933a1627b0SNicholas Kazlauskas struct dmub_cmd_read_modify_write_sequence *seq; 1943a1627b0SNicholas Kazlauskas 1953a1627b0SNicholas Kazlauskas /* flush command if buffer is full */ 1963a1627b0SNicholas Kazlauskas if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE && 1973a1627b0SNicholas Kazlauskas offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX) 1983a1627b0SNicholas Kazlauskas dmub_flush_buffer_execute(offload, ctx); 1993a1627b0SNicholas Kazlauskas 2003a1627b0SNicholas Kazlauskas if (offload->should_burst_write) { 2013a1627b0SNicholas Kazlauskas if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value)) 2023a1627b0SNicholas Kazlauskas return field_value_mask->value; 2033a1627b0SNicholas Kazlauskas else 2043a1627b0SNicholas Kazlauskas offload->should_burst_write = false; 2053a1627b0SNicholas Kazlauskas } 2063a1627b0SNicholas Kazlauskas 2073a1627b0SNicholas Kazlauskas /* pack commands */ 2083a1627b0SNicholas Kazlauskas cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE; 2093a1627b0SNicholas Kazlauskas seq = &cmd_buf->seq[offload->reg_seq_count]; 2103a1627b0SNicholas Kazlauskas 2113a1627b0SNicholas Kazlauskas if (offload->reg_seq_count) { 2123a1627b0SNicholas Kazlauskas if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr) 2133a1627b0SNicholas Kazlauskas offload->same_addr_count++; 2143a1627b0SNicholas Kazlauskas else 2153a1627b0SNicholas Kazlauskas offload->same_addr_count = 0; 2163a1627b0SNicholas Kazlauskas } 2173a1627b0SNicholas Kazlauskas 2183a1627b0SNicholas Kazlauskas seq->addr = addr; 2193a1627b0SNicholas Kazlauskas seq->modify_mask = field_value_mask->mask; 2203a1627b0SNicholas Kazlauskas seq->modify_value = field_value_mask->value; 2213a1627b0SNicholas Kazlauskas offload->reg_seq_count++; 2223a1627b0SNicholas Kazlauskas 2233a1627b0SNicholas Kazlauskas return field_value_mask->value; 2243a1627b0SNicholas Kazlauskas } 2253a1627b0SNicholas Kazlauskas 2263a1627b0SNicholas Kazlauskas static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr, 2273a1627b0SNicholas Kazlauskas uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us) 2283a1627b0SNicholas Kazlauskas { 2293a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; 2303a1627b0SNicholas Kazlauskas struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; 2313a1627b0SNicholas Kazlauskas 2323a1627b0SNicholas Kazlauskas cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT; 2333a1627b0SNicholas Kazlauskas cmd_buf->reg_wait.addr = addr; 2343a1627b0SNicholas Kazlauskas cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift); 2353a1627b0SNicholas Kazlauskas cmd_buf->reg_wait.mask = mask; 2363a1627b0SNicholas Kazlauskas cmd_buf->reg_wait.time_out_us = time_out_us; 2373a1627b0SNicholas Kazlauskas } 2383a1627b0SNicholas Kazlauskas 239148cccf2SYongqiang Sun uint32_t generic_reg_update_ex(const struct dc_context *ctx, 240148cccf2SYongqiang Sun uint32_t addr, int n, 241148cccf2SYongqiang Sun uint8_t shift1, uint32_t mask1, uint32_t field_value1, 242148cccf2SYongqiang Sun ...) 243148cccf2SYongqiang Sun { 244148cccf2SYongqiang Sun struct dc_reg_value_masks field_value_mask = {0}; 245148cccf2SYongqiang Sun uint32_t reg_val; 246148cccf2SYongqiang Sun va_list ap; 247148cccf2SYongqiang Sun 248148cccf2SYongqiang Sun va_start(ap, field_value1); 249148cccf2SYongqiang Sun 250148cccf2SYongqiang Sun set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, 251148cccf2SYongqiang Sun field_value1, ap); 252148cccf2SYongqiang Sun 253148cccf2SYongqiang Sun va_end(ap); 254148cccf2SYongqiang Sun 2553a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && 2563a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress) 2573a1627b0SNicholas Kazlauskas return dmub_reg_value_pack(ctx, addr, &field_value_mask); 2583a1627b0SNicholas Kazlauskas /* todo: return void so we can decouple code running in driver from register states */ 2593a1627b0SNicholas Kazlauskas 260148cccf2SYongqiang Sun /* mmio write directly */ 261148cccf2SYongqiang Sun reg_val = dm_read_reg(ctx, addr); 262148cccf2SYongqiang Sun reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; 263148cccf2SYongqiang Sun dm_write_reg(ctx, addr, reg_val); 264148cccf2SYongqiang Sun return reg_val; 265148cccf2SYongqiang Sun } 266148cccf2SYongqiang Sun 267148cccf2SYongqiang Sun uint32_t generic_reg_set_ex(const struct dc_context *ctx, 268148cccf2SYongqiang Sun uint32_t addr, uint32_t reg_val, int n, 269148cccf2SYongqiang Sun uint8_t shift1, uint32_t mask1, uint32_t field_value1, 270148cccf2SYongqiang Sun ...) 271148cccf2SYongqiang Sun { 272148cccf2SYongqiang Sun struct dc_reg_value_masks field_value_mask = {0}; 273148cccf2SYongqiang Sun va_list ap; 274148cccf2SYongqiang Sun 275148cccf2SYongqiang Sun va_start(ap, field_value1); 276148cccf2SYongqiang Sun 277148cccf2SYongqiang Sun set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, 278148cccf2SYongqiang Sun field_value1, ap); 279148cccf2SYongqiang Sun 2804562236bSHarry Wentland va_end(ap); 2814562236bSHarry Wentland 28244788bbcSTony Cheng 28344788bbcSTony Cheng /* mmio write directly */ 28444788bbcSTony Cheng reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; 2852200eb9eSNicholas Kazlauskas 2863a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && 2873a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress) { 2883a1627b0SNicholas Kazlauskas return dmub_reg_value_burst_set_pack(ctx, addr, reg_val); 2893a1627b0SNicholas Kazlauskas /* todo: return void so we can decouple code running in driver from register states */ 2903a1627b0SNicholas Kazlauskas } 2912200eb9eSNicholas Kazlauskas 29244788bbcSTony Cheng dm_write_reg(ctx, addr, reg_val); 2934562236bSHarry Wentland return reg_val; 2944562236bSHarry Wentland } 2954562236bSHarry Wentland 296901f4f97SYongqiang Sun uint32_t dm_read_reg_func( 297901f4f97SYongqiang Sun const struct dc_context *ctx, 298901f4f97SYongqiang Sun uint32_t address, 299901f4f97SYongqiang Sun const char *func_name) 300901f4f97SYongqiang Sun { 301901f4f97SYongqiang Sun uint32_t value; 302901f4f97SYongqiang Sun #ifdef DM_CHECK_ADDR_0 303901f4f97SYongqiang Sun if (address == 0) { 304901f4f97SYongqiang Sun DC_ERR("invalid register read; address = 0\n"); 305901f4f97SYongqiang Sun return 0; 306901f4f97SYongqiang Sun } 307901f4f97SYongqiang Sun #endif 3083a1627b0SNicholas Kazlauskas 3093a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && 3103a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress && 3113a1627b0SNicholas Kazlauskas !ctx->dmub_srv->reg_helper_offload.should_burst_write) { 3123a1627b0SNicholas Kazlauskas ASSERT(false); 3133a1627b0SNicholas Kazlauskas return 0; 3143a1627b0SNicholas Kazlauskas } 3153a1627b0SNicholas Kazlauskas 316901f4f97SYongqiang Sun value = cgs_read_register(ctx->cgs_device, address); 317901f4f97SYongqiang Sun trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value); 318901f4f97SYongqiang Sun 319901f4f97SYongqiang Sun return value; 320901f4f97SYongqiang Sun } 321901f4f97SYongqiang Sun 3224562236bSHarry Wentland uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr, 3234562236bSHarry Wentland uint8_t shift, uint32_t mask, uint32_t *field_value) 3244562236bSHarry Wentland { 3254562236bSHarry Wentland uint32_t reg_val = dm_read_reg(ctx, addr); 3264562236bSHarry Wentland *field_value = get_reg_field_value_ex(reg_val, mask, shift); 3274562236bSHarry Wentland return reg_val; 3284562236bSHarry Wentland } 3294562236bSHarry Wentland 3304562236bSHarry Wentland uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr, 3314562236bSHarry Wentland uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 3324562236bSHarry Wentland uint8_t shift2, uint32_t mask2, uint32_t *field_value2) 3334562236bSHarry Wentland { 3344562236bSHarry Wentland uint32_t reg_val = dm_read_reg(ctx, addr); 3354562236bSHarry Wentland *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 3364562236bSHarry Wentland *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 3374562236bSHarry Wentland return reg_val; 3384562236bSHarry Wentland } 3394562236bSHarry Wentland 3404562236bSHarry Wentland uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr, 3414562236bSHarry Wentland uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 3424562236bSHarry Wentland uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 3434562236bSHarry Wentland uint8_t shift3, uint32_t mask3, uint32_t *field_value3) 3444562236bSHarry Wentland { 3454562236bSHarry Wentland uint32_t reg_val = dm_read_reg(ctx, addr); 3464562236bSHarry Wentland *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 3474562236bSHarry Wentland *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 3484562236bSHarry Wentland *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 3494562236bSHarry Wentland return reg_val; 3504562236bSHarry Wentland } 3514562236bSHarry Wentland 35298d2cc2bSAndrew Wong uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr, 35398d2cc2bSAndrew Wong uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 35498d2cc2bSAndrew Wong uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 35598d2cc2bSAndrew Wong uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 35698d2cc2bSAndrew Wong uint8_t shift4, uint32_t mask4, uint32_t *field_value4) 35798d2cc2bSAndrew Wong { 35898d2cc2bSAndrew Wong uint32_t reg_val = dm_read_reg(ctx, addr); 35998d2cc2bSAndrew Wong *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 36098d2cc2bSAndrew Wong *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 36198d2cc2bSAndrew Wong *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 36298d2cc2bSAndrew Wong *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 36398d2cc2bSAndrew Wong return reg_val; 36498d2cc2bSAndrew Wong } 36598d2cc2bSAndrew Wong 3664562236bSHarry Wentland uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr, 3674562236bSHarry Wentland uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 3684562236bSHarry Wentland uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 3694562236bSHarry Wentland uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 3704562236bSHarry Wentland uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 3714562236bSHarry Wentland uint8_t shift5, uint32_t mask5, uint32_t *field_value5) 3724562236bSHarry Wentland { 3734562236bSHarry Wentland uint32_t reg_val = dm_read_reg(ctx, addr); 3744562236bSHarry Wentland *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 3754562236bSHarry Wentland *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 3764562236bSHarry Wentland *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 3774562236bSHarry Wentland *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 3784562236bSHarry Wentland *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 3794562236bSHarry Wentland return reg_val; 3804562236bSHarry Wentland } 3814562236bSHarry Wentland 3820a93dc7fSDmytro Laktyushkin uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr, 3830a93dc7fSDmytro Laktyushkin uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 3840a93dc7fSDmytro Laktyushkin uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 3850a93dc7fSDmytro Laktyushkin uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 3860a93dc7fSDmytro Laktyushkin uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 3870a93dc7fSDmytro Laktyushkin uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 3880a93dc7fSDmytro Laktyushkin uint8_t shift6, uint32_t mask6, uint32_t *field_value6) 3890a93dc7fSDmytro Laktyushkin { 3900a93dc7fSDmytro Laktyushkin uint32_t reg_val = dm_read_reg(ctx, addr); 3910a93dc7fSDmytro Laktyushkin *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 3920a93dc7fSDmytro Laktyushkin *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 3930a93dc7fSDmytro Laktyushkin *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 3940a93dc7fSDmytro Laktyushkin *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 3950a93dc7fSDmytro Laktyushkin *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 3960a93dc7fSDmytro Laktyushkin *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 3970a93dc7fSDmytro Laktyushkin return reg_val; 3980a93dc7fSDmytro Laktyushkin } 3990a93dc7fSDmytro Laktyushkin 4000a93dc7fSDmytro Laktyushkin uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr, 4010a93dc7fSDmytro Laktyushkin uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 4020a93dc7fSDmytro Laktyushkin uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 4030a93dc7fSDmytro Laktyushkin uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 4040a93dc7fSDmytro Laktyushkin uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 4050a93dc7fSDmytro Laktyushkin uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 4060a93dc7fSDmytro Laktyushkin uint8_t shift6, uint32_t mask6, uint32_t *field_value6, 4070a93dc7fSDmytro Laktyushkin uint8_t shift7, uint32_t mask7, uint32_t *field_value7) 4080a93dc7fSDmytro Laktyushkin { 4090a93dc7fSDmytro Laktyushkin uint32_t reg_val = dm_read_reg(ctx, addr); 4100a93dc7fSDmytro Laktyushkin *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 4110a93dc7fSDmytro Laktyushkin *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 4120a93dc7fSDmytro Laktyushkin *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 4130a93dc7fSDmytro Laktyushkin *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 4140a93dc7fSDmytro Laktyushkin *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 4150a93dc7fSDmytro Laktyushkin *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 4160a93dc7fSDmytro Laktyushkin *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7); 4170a93dc7fSDmytro Laktyushkin return reg_val; 4180a93dc7fSDmytro Laktyushkin } 4190a93dc7fSDmytro Laktyushkin 4200a93dc7fSDmytro Laktyushkin uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr, 4210a93dc7fSDmytro Laktyushkin uint8_t shift1, uint32_t mask1, uint32_t *field_value1, 4220a93dc7fSDmytro Laktyushkin uint8_t shift2, uint32_t mask2, uint32_t *field_value2, 4230a93dc7fSDmytro Laktyushkin uint8_t shift3, uint32_t mask3, uint32_t *field_value3, 4240a93dc7fSDmytro Laktyushkin uint8_t shift4, uint32_t mask4, uint32_t *field_value4, 4250a93dc7fSDmytro Laktyushkin uint8_t shift5, uint32_t mask5, uint32_t *field_value5, 4260a93dc7fSDmytro Laktyushkin uint8_t shift6, uint32_t mask6, uint32_t *field_value6, 4270a93dc7fSDmytro Laktyushkin uint8_t shift7, uint32_t mask7, uint32_t *field_value7, 4280a93dc7fSDmytro Laktyushkin uint8_t shift8, uint32_t mask8, uint32_t *field_value8) 4290a93dc7fSDmytro Laktyushkin { 4300a93dc7fSDmytro Laktyushkin uint32_t reg_val = dm_read_reg(ctx, addr); 4310a93dc7fSDmytro Laktyushkin *field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1); 4320a93dc7fSDmytro Laktyushkin *field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2); 4330a93dc7fSDmytro Laktyushkin *field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3); 4340a93dc7fSDmytro Laktyushkin *field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4); 4350a93dc7fSDmytro Laktyushkin *field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5); 4360a93dc7fSDmytro Laktyushkin *field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6); 4370a93dc7fSDmytro Laktyushkin *field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7); 4380a93dc7fSDmytro Laktyushkin *field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8); 4390a93dc7fSDmytro Laktyushkin return reg_val; 4400a93dc7fSDmytro Laktyushkin } 4414562236bSHarry Wentland /* note: va version of this is pretty bad idea, since there is a output parameter pass by pointer 4424562236bSHarry Wentland * compiler won't be able to check for size match and is prone to stack corruption type of bugs 4434562236bSHarry Wentland 4444562236bSHarry Wentland uint32_t generic_reg_get(const struct dc_context *ctx, 4454562236bSHarry Wentland uint32_t addr, int n, ...) 4464562236bSHarry Wentland { 4474562236bSHarry Wentland uint32_t shift, mask; 4484562236bSHarry Wentland uint32_t *field_value; 4494562236bSHarry Wentland uint32_t reg_val; 4504562236bSHarry Wentland int i = 0; 4514562236bSHarry Wentland 4524562236bSHarry Wentland reg_val = dm_read_reg(ctx, addr); 4534562236bSHarry Wentland 4544562236bSHarry Wentland va_list ap; 4554562236bSHarry Wentland va_start(ap, n); 4564562236bSHarry Wentland 4574562236bSHarry Wentland while (i < n) { 4584562236bSHarry Wentland shift = va_arg(ap, uint32_t); 4594562236bSHarry Wentland mask = va_arg(ap, uint32_t); 4604562236bSHarry Wentland field_value = va_arg(ap, uint32_t *); 4614562236bSHarry Wentland 4624562236bSHarry Wentland *field_value = get_reg_field_value_ex(reg_val, mask, shift); 4634562236bSHarry Wentland i++; 4644562236bSHarry Wentland } 4654562236bSHarry Wentland 4664562236bSHarry Wentland va_end(ap); 4674562236bSHarry Wentland 4684562236bSHarry Wentland return reg_val; 4694562236bSHarry Wentland } 4704562236bSHarry Wentland */ 4714562236bSHarry Wentland 472335d5d7bSYongqiang Sun void generic_reg_wait(const struct dc_context *ctx, 4734562236bSHarry Wentland uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value, 4744562236bSHarry Wentland unsigned int delay_between_poll_us, unsigned int time_out_num_tries, 475daf6b57dSDmytro Laktyushkin const char *func_name, int line) 4764562236bSHarry Wentland { 4774562236bSHarry Wentland uint32_t field_value; 4784562236bSHarry Wentland uint32_t reg_val; 4794562236bSHarry Wentland int i; 4804562236bSHarry Wentland 4813a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && 4823a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress) { 4833a1627b0SNicholas Kazlauskas dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value, 4843a1627b0SNicholas Kazlauskas delay_between_poll_us * time_out_num_tries); 4853a1627b0SNicholas Kazlauskas return; 4863a1627b0SNicholas Kazlauskas } 4873a1627b0SNicholas Kazlauskas 4888a5d8245STony Cheng /* something is terribly wrong if time out is > 200ms. (5Hz) */ 48921e471f0SEric Yang ASSERT(delay_between_poll_us * time_out_num_tries <= 3000000); 4908a5d8245STony Cheng 4914562236bSHarry Wentland for (i = 0; i <= time_out_num_tries; i++) { 4924562236bSHarry Wentland if (i) { 493755d3bcfSEric Yang if (delay_between_poll_us >= 1000) 4944562236bSHarry Wentland msleep(delay_between_poll_us/1000); 495755d3bcfSEric Yang else if (delay_between_poll_us > 0) 496755d3bcfSEric Yang udelay(delay_between_poll_us); 4974562236bSHarry Wentland } 4984562236bSHarry Wentland 4994562236bSHarry Wentland reg_val = dm_read_reg(ctx, addr); 5004562236bSHarry Wentland 5014562236bSHarry Wentland field_value = get_reg_field_value_ex(reg_val, mask, shift); 5024562236bSHarry Wentland 50342cf181bSDmytro Laktyushkin if (field_value == condition_value) { 50418e4aa33SKen Chalmers if (i * delay_between_poll_us > 1000 && 50518e4aa33SKen Chalmers !IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) 506d71589f2SDavid Francis DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n", 50742cf181bSDmytro Laktyushkin delay_between_poll_us * i / 1000, 50842cf181bSDmytro Laktyushkin func_name, line); 509335d5d7bSYongqiang Sun return; 5104562236bSHarry Wentland } 51142cf181bSDmytro Laktyushkin } 5124562236bSHarry Wentland 513d71589f2SDavid Francis DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n", 5148a5d8245STony Cheng delay_between_poll_us, time_out_num_tries, 5158a5d8245STony Cheng func_name, line); 516f0558542SDmytro Laktyushkin 517f0558542SDmytro Laktyushkin if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) 51811589813SDmytro Laktyushkin BREAK_TO_DEBUGGER(); 5194562236bSHarry Wentland } 52016aecfd4STony Cheng 52116aecfd4STony Cheng void generic_write_indirect_reg(const struct dc_context *ctx, 52216aecfd4STony Cheng uint32_t addr_index, uint32_t addr_data, 52316aecfd4STony Cheng uint32_t index, uint32_t data) 52416aecfd4STony Cheng { 52516aecfd4STony Cheng dm_write_reg(ctx, addr_index, index); 52616aecfd4STony Cheng dm_write_reg(ctx, addr_data, data); 52716aecfd4STony Cheng } 52816aecfd4STony Cheng 52916aecfd4STony Cheng uint32_t generic_read_indirect_reg(const struct dc_context *ctx, 53016aecfd4STony Cheng uint32_t addr_index, uint32_t addr_data, 53116aecfd4STony Cheng uint32_t index) 53216aecfd4STony Cheng { 53316aecfd4STony Cheng uint32_t value = 0; 5342200eb9eSNicholas Kazlauskas 5353a1627b0SNicholas Kazlauskas // when reg read, there should not be any offload. 5363a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && 5373a1627b0SNicholas Kazlauskas ctx->dmub_srv->reg_helper_offload.gather_in_progress) { 5383a1627b0SNicholas Kazlauskas ASSERT(false); 5393a1627b0SNicholas Kazlauskas } 54016aecfd4STony Cheng 54116aecfd4STony Cheng dm_write_reg(ctx, addr_index, index); 54216aecfd4STony Cheng value = dm_read_reg(ctx, addr_data); 54316aecfd4STony Cheng 54416aecfd4STony Cheng return value; 54516aecfd4STony Cheng } 54616aecfd4STony Cheng 54716aecfd4STony Cheng 54816aecfd4STony Cheng uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx, 54916aecfd4STony Cheng uint32_t addr_index, uint32_t addr_data, 55016aecfd4STony Cheng uint32_t index, uint32_t reg_val, int n, 55116aecfd4STony Cheng uint8_t shift1, uint32_t mask1, uint32_t field_value1, 55216aecfd4STony Cheng ...) 55316aecfd4STony Cheng { 55416aecfd4STony Cheng uint32_t shift, mask, field_value; 55516aecfd4STony Cheng int i = 1; 55616aecfd4STony Cheng 55716aecfd4STony Cheng va_list ap; 55816aecfd4STony Cheng 55916aecfd4STony Cheng va_start(ap, field_value1); 56016aecfd4STony Cheng 56116aecfd4STony Cheng reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1); 56216aecfd4STony Cheng 56316aecfd4STony Cheng while (i < n) { 56416aecfd4STony Cheng shift = va_arg(ap, uint32_t); 56516aecfd4STony Cheng mask = va_arg(ap, uint32_t); 56616aecfd4STony Cheng field_value = va_arg(ap, uint32_t); 56716aecfd4STony Cheng 56816aecfd4STony Cheng reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift); 56916aecfd4STony Cheng i++; 57016aecfd4STony Cheng } 57116aecfd4STony Cheng 57216aecfd4STony Cheng generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val); 57316aecfd4STony Cheng va_end(ap); 57416aecfd4STony Cheng 57516aecfd4STony Cheng return reg_val; 57616aecfd4STony Cheng } 5773a1627b0SNicholas Kazlauskas 5783a1627b0SNicholas Kazlauskas void reg_sequence_start_gather(const struct dc_context *ctx) 5793a1627b0SNicholas Kazlauskas { 5803a1627b0SNicholas Kazlauskas /* if reg sequence is supported and enabled, set flag to 5813a1627b0SNicholas Kazlauskas * indicate we want to have REG_SET, REG_UPDATE macro build 5823a1627b0SNicholas Kazlauskas * reg sequence command buffer rather than MMIO directly. 5833a1627b0SNicholas Kazlauskas */ 5843a1627b0SNicholas Kazlauskas 5853a1627b0SNicholas Kazlauskas if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) { 5863a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload = 5873a1627b0SNicholas Kazlauskas &ctx->dmub_srv->reg_helper_offload; 5883a1627b0SNicholas Kazlauskas 5893a1627b0SNicholas Kazlauskas /* caller sequence mismatch. need to debug caller. offload will not work!!! */ 5903a1627b0SNicholas Kazlauskas ASSERT(!offload->gather_in_progress); 5913a1627b0SNicholas Kazlauskas 5923a1627b0SNicholas Kazlauskas offload->gather_in_progress = true; 5933a1627b0SNicholas Kazlauskas } 5943a1627b0SNicholas Kazlauskas } 5953a1627b0SNicholas Kazlauskas 5963a1627b0SNicholas Kazlauskas void reg_sequence_start_execute(const struct dc_context *ctx) 5973a1627b0SNicholas Kazlauskas { 5983a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload; 5993a1627b0SNicholas Kazlauskas 6003a1627b0SNicholas Kazlauskas if (!ctx->dmub_srv) 6013a1627b0SNicholas Kazlauskas return; 6023a1627b0SNicholas Kazlauskas 6033a1627b0SNicholas Kazlauskas offload = &ctx->dmub_srv->reg_helper_offload; 6043a1627b0SNicholas Kazlauskas 6053a1627b0SNicholas Kazlauskas if (offload && offload->gather_in_progress) { 6063a1627b0SNicholas Kazlauskas offload->gather_in_progress = false; 6073a1627b0SNicholas Kazlauskas offload->should_burst_write = false; 6083a1627b0SNicholas Kazlauskas switch (offload->cmd_data.cmd_common.header.type) { 6093a1627b0SNicholas Kazlauskas case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE: 6103a1627b0SNicholas Kazlauskas submit_dmub_read_modify_write(offload, ctx); 6113a1627b0SNicholas Kazlauskas break; 6123a1627b0SNicholas Kazlauskas case DMUB_CMD__REG_REG_WAIT: 6133a1627b0SNicholas Kazlauskas submit_dmub_reg_wait(offload, ctx); 6143a1627b0SNicholas Kazlauskas break; 6153a1627b0SNicholas Kazlauskas case DMUB_CMD__REG_SEQ_BURST_WRITE: 6163a1627b0SNicholas Kazlauskas submit_dmub_burst_write(offload, ctx); 6173a1627b0SNicholas Kazlauskas break; 6183a1627b0SNicholas Kazlauskas default: 6193a1627b0SNicholas Kazlauskas return; 6203a1627b0SNicholas Kazlauskas } 6213a1627b0SNicholas Kazlauskas 6223a1627b0SNicholas Kazlauskas dc_dmub_srv_cmd_execute(ctx->dmub_srv); 6233a1627b0SNicholas Kazlauskas } 6243a1627b0SNicholas Kazlauskas } 6253a1627b0SNicholas Kazlauskas 6263a1627b0SNicholas Kazlauskas void reg_sequence_wait_done(const struct dc_context *ctx) 6273a1627b0SNicholas Kazlauskas { 6283a1627b0SNicholas Kazlauskas /* callback to DM to poll for last submission done*/ 6293a1627b0SNicholas Kazlauskas struct dc_reg_helper_state *offload; 6303a1627b0SNicholas Kazlauskas 6313a1627b0SNicholas Kazlauskas if (!ctx->dmub_srv) 6323a1627b0SNicholas Kazlauskas return; 6333a1627b0SNicholas Kazlauskas 6343a1627b0SNicholas Kazlauskas offload = &ctx->dmub_srv->reg_helper_offload; 6353a1627b0SNicholas Kazlauskas 6363a1627b0SNicholas Kazlauskas if (offload && 6373a1627b0SNicholas Kazlauskas ctx->dc->debug.dmub_offload_enabled && 6383a1627b0SNicholas Kazlauskas !ctx->dc->debug.dmcub_emulation) { 6393a1627b0SNicholas Kazlauskas dc_dmub_srv_wait_idle(ctx->dmub_srv); 6403a1627b0SNicholas Kazlauskas } 6413a1627b0SNicholas Kazlauskas } 642