Adds watermark, DMIF, and surface programming.

Signed-off-by: Harry Wentland <harry.wentland at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
---
 .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c   | 965 +++++++++++++++++++++
 .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h   | 117 +++
 2 files changed, 1082 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
 create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h

diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
new file mode 100644
index 000000000000..3a928e63e647
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
@@ -0,0 +1,965 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dm_services.h"
+
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+/* TODO: this needs to be looked at, used by Stella's workaround*/
+#include "gmc/gmc_8_2_d.h"
+#include "gmc/gmc_8_2_sh_mask.h"
+
+#include "include/logger_interface.h"
+#include "adapter_service_interface.h"
+#include "inc/bandwidth_calcs.h"
+
+#include "dce110_mem_input.h"
+
+#define MAX_WATERMARK 0xFFFF
+#define SAFE_NBP_MARK 0x7FFF
+
+#define DCP_REG(reg) (reg + mem_input110->offsets.dcp)
+#define DMIF_REG(reg) (reg + mem_input110->offsets.dmif)
+#define PIPE_REG(reg) (reg + mem_input110->offsets.pipe)
+
+static void set_flip_control(
+       struct dce110_mem_input *mem_input110,
+       bool immediate)
+{
+       uint32_t value = 0;
+
+       value = dm_read_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_FLIP_CONTROL));
+       set_reg_field_value(value, 0,
+                               GRPH_FLIP_CONTROL,
+                               GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
+       set_reg_field_value(value, 0,
+                               GRPH_FLIP_CONTROL,
+                               GRPH_SURFACE_UPDATE_H_RETRACE_EN);
+       if (immediate == true)
+               set_reg_field_value(value, 1,
+                       GRPH_FLIP_CONTROL,
+                       GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
+
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_FLIP_CONTROL),
+               value);
+}
+
+static void program_sec_addr(
+       struct dce110_mem_input *mem_input110,
+       PHYSICAL_ADDRESS_LOC address)
+{
+       uint32_t value = 0;
+       uint32_t temp = 0;
+       /*high register MUST be programmed first*/
+       temp = address.high_part &
+GRPH_SECONDARY_SURFACE_ADDRESS_HIGH__GRPH_SECONDARY_SURFACE_ADDRESS_HIGH_MASK;
+
+       set_reg_field_value(value, temp,
+               GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
+               GRPH_SECONDARY_SURFACE_ADDRESS_HIGH);
+
+       dm_write_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH),
+                       value);
+
+       temp = 0;
+       value = 0;
+       temp = address.low_part >>
+       GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS__SHIFT;
+
+       set_reg_field_value(value, temp,
+               GRPH_SECONDARY_SURFACE_ADDRESS,
+               GRPH_SECONDARY_SURFACE_ADDRESS);
+
+       dm_write_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS),
+                       value);
+}
+
+static void program_pri_addr(
+       struct dce110_mem_input *mem_input110,
+       PHYSICAL_ADDRESS_LOC address)
+{
+       uint32_t value = 0;
+       uint32_t temp = 0;
+
+       /*high register MUST be programmed first*/
+       temp = address.high_part &
+GRPH_PRIMARY_SURFACE_ADDRESS_HIGH__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_MASK;
+
+       set_reg_field_value(value, temp,
+               GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
+               GRPH_PRIMARY_SURFACE_ADDRESS_HIGH);
+
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH),
+               value);
+
+       temp = 0;
+       value = 0;
+       temp = address.low_part >>
+       GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS__SHIFT;
+
+       set_reg_field_value(value, temp,
+               GRPH_PRIMARY_SURFACE_ADDRESS,
+               GRPH_PRIMARY_SURFACE_ADDRESS);
+
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS),
+               value);
+}
+
+static void program_addr(
+       struct dce110_mem_input *mem_input110,
+       const struct dc_plane_address *addr)
+{
+       switch (addr->type) {
+       case PLN_ADDR_TYPE_GRAPHICS:
+               program_pri_addr(
+                       mem_input110,
+                       addr->grph.addr);
+               break;
+       case PLN_ADDR_TYPE_GRPH_STEREO:
+               program_pri_addr(
+                       mem_input110,
+                       addr->grph_stereo.left_addr);
+               program_sec_addr(
+                       mem_input110,
+                       addr->grph_stereo.right_addr);
+               break;
+       case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
+       default:
+               /* not supported */
+               BREAK_TO_DEBUGGER();
+       }
+}
+
+static void enable(struct dce110_mem_input *mem_input110)
+{
+       uint32_t value = 0;
+
+       value = dm_read_reg(mem_input110->base.ctx, DCP_REG(mmGRPH_ENABLE));
+       set_reg_field_value(value, 1, GRPH_ENABLE, GRPH_ENABLE);
+       dm_write_reg(mem_input110->base.ctx,
+               DCP_REG(mmGRPH_ENABLE),
+               value);
+}
+
+static void program_tiling(
+       struct dce110_mem_input *mem_input110,
+       const struct dc_tiling_info *info,
+       const enum surface_pixel_format pixel_format)
+{
+       uint32_t value = 0;
+
+       value = dm_read_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_CONTROL));
+
+       set_reg_field_value(value, info->num_banks,
+               GRPH_CONTROL, GRPH_NUM_BANKS);
+
+       set_reg_field_value(value, info->bank_width,
+               GRPH_CONTROL, GRPH_BANK_WIDTH);
+
+       set_reg_field_value(value, info->bank_height,
+               GRPH_CONTROL, GRPH_BANK_HEIGHT);
+
+       set_reg_field_value(value, info->tile_aspect,
+               GRPH_CONTROL, GRPH_MACRO_TILE_ASPECT);
+
+       set_reg_field_value(value, info->tile_split,
+               GRPH_CONTROL, GRPH_TILE_SPLIT);
+
+       set_reg_field_value(value, info->tile_mode,
+               GRPH_CONTROL, GRPH_MICRO_TILE_MODE);
+
+       set_reg_field_value(value, info->pipe_config,
+               GRPH_CONTROL, GRPH_PIPE_CONFIG);
+
+       set_reg_field_value(value, info->array_mode,
+               GRPH_CONTROL, GRPH_ARRAY_MODE);
+
+       set_reg_field_value(value, 1,
+               GRPH_CONTROL, GRPH_COLOR_EXPANSION_MODE);
+
+       set_reg_field_value(value, 0,
+               GRPH_CONTROL, GRPH_Z);
+
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_CONTROL),
+               value);
+}
+
+static void program_size_and_rotation(
+       struct dce110_mem_input *mem_input110,
+       enum dc_rotation_angle rotation,
+       const union plane_size *plane_size)
+{
+       uint32_t value = 0;
+       union plane_size local_size = *plane_size;
+
+       if (rotation == ROTATION_ANGLE_90 ||
+               rotation == ROTATION_ANGLE_270) {
+
+               uint32_t swap;
+
+               swap = local_size.grph.surface_size.x;
+               local_size.grph.surface_size.x =
+                       local_size.grph.surface_size.y;
+               local_size.grph.surface_size.y  = swap;
+
+               swap = local_size.grph.surface_size.width;
+               local_size.grph.surface_size.width =
+                       local_size.grph.surface_size.height;
+               local_size.grph.surface_size.height = swap;
+       }
+
+       set_reg_field_value(value, local_size.grph.surface_size.x,
+                       GRPH_X_START, GRPH_X_START);
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_X_START),
+               value);
+
+       value = 0;
+       set_reg_field_value(value, local_size.grph.surface_size.y,
+                       GRPH_Y_START, GRPH_Y_START);
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_Y_START),
+               value);
+
+       value = 0;
+       set_reg_field_value(value, local_size.grph.surface_size.width,
+                       GRPH_X_END, GRPH_X_END);
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_X_END),
+               value);
+
+       value = 0;
+       set_reg_field_value(value, local_size.grph.surface_size.height,
+                       GRPH_Y_END, GRPH_Y_END);
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_Y_END),
+               value);
+
+       value = 0;
+       set_reg_field_value(value, local_size.grph.surface_pitch,
+                       GRPH_PITCH, GRPH_PITCH);
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmGRPH_PITCH),
+               value);
+
+
+       value = 0;
+       switch (rotation) {
+       case ROTATION_ANGLE_90:
+               set_reg_field_value(value, 3,
+                       HW_ROTATION, GRPH_ROTATION_ANGLE);
+               break;
+       case ROTATION_ANGLE_180:
+               set_reg_field_value(value, 2,
+                       HW_ROTATION, GRPH_ROTATION_ANGLE);
+               break;
+       case ROTATION_ANGLE_270:
+               set_reg_field_value(value, 1,
+                       HW_ROTATION, GRPH_ROTATION_ANGLE);
+               break;
+       default:
+               set_reg_field_value(value, 0,
+                       HW_ROTATION, GRPH_ROTATION_ANGLE);
+               break;
+       }
+       dm_write_reg(
+               mem_input110->base.ctx,
+               DCP_REG(mmHW_ROTATION),
+               value);
+}
+
+static void program_pixel_format(
+       struct dce110_mem_input *mem_input110,
+       enum surface_pixel_format format)
+{
+       if (format >= SURFACE_PIXEL_FORMAT_GRPH_BEGIN &&
+               format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+               uint32_t value = 0;
+
+               /* handle colour twizzle formats, swapping R and B */
+               if (format == SURFACE_PIXEL_FORMAT_GRPH_BGRA8888 ||
+                       format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 ||
+                       format ==
+                       SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS ||
+                       format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
+                       set_reg_field_value(
+                               value, 2, GRPH_SWAP_CNTL, GRPH_RED_CROSSBAR);
+                       set_reg_field_value(
+                               value, 2, GRPH_SWAP_CNTL, GRPH_BLUE_CROSSBAR);
+               }
+
+               dm_write_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_SWAP_CNTL),
+                       value);
+
+
+               value = dm_read_reg(
+                               mem_input110->base.ctx,
+                               DCP_REG(mmGRPH_CONTROL));
+
+               switch (format) {
+               case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
+                       set_reg_field_value(
+                               value, 0, GRPH_CONTROL, GRPH_DEPTH);
+                       set_reg_field_value(
+                               value, 0, GRPH_CONTROL, GRPH_FORMAT);
+                       break;
+               case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+                       set_reg_field_value(
+                               value, 1, GRPH_CONTROL, GRPH_DEPTH);
+                       set_reg_field_value(
+                               value, 1, GRPH_CONTROL, GRPH_FORMAT);
+                       break;
+               case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
+               case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
+                       set_reg_field_value(
+                               value, 2, GRPH_CONTROL, GRPH_DEPTH);
+                       set_reg_field_value(
+                               value, 0, GRPH_CONTROL, GRPH_FORMAT);
+                       break;
+               case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
+               case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
+               case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
+                       set_reg_field_value(
+                               value, 2, GRPH_CONTROL, GRPH_DEPTH);
+                       set_reg_field_value(
+                               value, 1, GRPH_CONTROL, GRPH_FORMAT);
+                       break;
+               case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+               case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+                       set_reg_field_value(
+                               value, 3, GRPH_CONTROL, GRPH_DEPTH);
+                       set_reg_field_value(
+                               value, 0, GRPH_CONTROL, GRPH_FORMAT);
+                       break;
+               default:
+                       break;
+               }
+               dm_write_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmGRPH_CONTROL),
+                       value);
+
+               /*TODO [hwentlan] MOVE THIS TO CONTROLLER GAMMA!!!!!*/
+               value = dm_read_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmPRESCALE_GRPH_CONTROL));
+
+               if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
+                       set_reg_field_value(
+                               value, 1, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_SELECT);
+                       set_reg_field_value(
+                               value, 1, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_R_SIGN);
+                       set_reg_field_value(
+                               value, 1, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_G_SIGN);
+                       set_reg_field_value(
+                               value, 1, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_B_SIGN);
+               } else {
+                       set_reg_field_value(
+                               value, 0, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_SELECT);
+                       set_reg_field_value(
+                               value, 0, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_R_SIGN);
+                       set_reg_field_value(
+                               value, 0, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_G_SIGN);
+                       set_reg_field_value(
+                               value, 0, PRESCALE_GRPH_CONTROL,
+                               GRPH_PRESCALE_B_SIGN);
+               }
+               dm_write_reg(
+                       mem_input110->base.ctx,
+                       DCP_REG(mmPRESCALE_GRPH_CONTROL),
+                       value);
+       }
+}
+
+static void wait_for_no_surface_update_pending(
+                               struct dce110_mem_input *mem_input110)
+{
+       uint32_t value;
+
+       do  {
+               value = dm_read_reg(mem_input110->base.ctx,
+                               DCP_REG(mmGRPH_UPDATE));
+
+       } while (get_reg_field_value(value, GRPH_UPDATE,
+                       GRPH_SURFACE_UPDATE_PENDING));
+}
+
+bool dce110_mem_input_program_surface_flip_and_addr(
+       struct mem_input *mem_input,
+       const struct dc_plane_address *address,
+       bool flip_immediate)
+{
+       struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+
+       set_flip_control(mem_input110, flip_immediate);
+       program_addr(mem_input110,
+               address);
+
+       if (flip_immediate)
+               wait_for_no_surface_update_pending(mem_input110);
+
+       return true;
+}
+
+bool dce110_mem_input_program_surface_config(
+       struct mem_input *mem_input,
+       enum surface_pixel_format format,
+       struct dc_tiling_info *tiling_info,
+       union plane_size *plane_size,
+       enum dc_rotation_angle rotation)
+{
+       struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
+
+       enable(mem_input110);
+       program_tiling(mem_input110, tiling_info, format);
+       program_size_and_rotation(mem_input110, rotation, plane_size);
+       program_pixel_format(mem_input110, format);
+
+       return true;
+}
+
+static void program_urgency_watermark(
+       const struct dc_context *ctx,
+       const uint32_t offset,
+       struct bw_watermarks marks_low,
+       uint32_t total_dest_line_time_ns)
+{
+       /* register value */
+       uint32_t urgency_cntl = 0;
+       uint32_t wm_mask_cntl = 0;
+
+       uint32_t urgency_addr = offset + mmDPG_PIPE_URGENCY_CONTROL;
+       uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+       /*Write mask to enable reading/writing of watermark set A*/
+       wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+       set_reg_field_value(wm_mask_cntl,
+                       1,
+                       DPG_WATERMARK_MASK_CONTROL,
+                       URGENCY_WATERMARK_MASK);
+       dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+       urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+       set_reg_field_value(
+               urgency_cntl,
+               marks_low.a_mark,
+               DPG_PIPE_URGENCY_CONTROL,
+               URGENCY_LOW_WATERMARK);
+
+       set_reg_field_value(
+               urgency_cntl,
+               total_dest_line_time_ns,
+               DPG_PIPE_URGENCY_CONTROL,
+               URGENCY_HIGH_WATERMARK);
+       dm_write_reg(ctx, urgency_addr, urgency_cntl);
+
+
+       /*Write mask to enable reading/writing of watermark set B*/
+       wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+       set_reg_field_value(wm_mask_cntl,
+                       2,
+                       DPG_WATERMARK_MASK_CONTROL,
+                       URGENCY_WATERMARK_MASK);
+       dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+       urgency_cntl = dm_read_reg(ctx, urgency_addr);
+
+       set_reg_field_value(urgency_cntl,
+               marks_low.b_mark,
+               DPG_PIPE_URGENCY_CONTROL,
+               URGENCY_LOW_WATERMARK);
+
+       set_reg_field_value(urgency_cntl,
+               total_dest_line_time_ns,
+               DPG_PIPE_URGENCY_CONTROL,
+               URGENCY_HIGH_WATERMARK);
+       dm_write_reg(ctx, urgency_addr, urgency_cntl);
+}
+
+static void program_stutter_watermark(
+       const struct dc_context *ctx,
+       const uint32_t offset,
+       struct bw_watermarks marks)
+{
+       /* register value */
+       uint32_t stutter_cntl = 0;
+       uint32_t wm_mask_cntl = 0;
+
+       uint32_t stutter_addr = offset + mmDPG_PIPE_STUTTER_CONTROL;
+       uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+
+       /*Write mask to enable reading/writing of watermark set A*/
+
+       wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+       set_reg_field_value(wm_mask_cntl,
+               1,
+               DPG_WATERMARK_MASK_CONTROL,
+               STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+       dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+       stutter_cntl = dm_read_reg(ctx, stutter_addr);
+
+       set_reg_field_value(stutter_cntl,
+               1,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_ENABLE);
+       set_reg_field_value(stutter_cntl,
+               1,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_IGNORE_FBC);
+
+       /*Write watermark set A*/
+       set_reg_field_value(stutter_cntl,
+               marks.a_mark,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+       dm_write_reg(ctx, stutter_addr, stutter_cntl);
+
+       /*Write mask to enable reading/writing of watermark set B*/
+       wm_mask_cntl = dm_read_reg(ctx, wm_addr);
+       set_reg_field_value(wm_mask_cntl,
+               2,
+               DPG_WATERMARK_MASK_CONTROL,
+               STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
+       dm_write_reg(ctx, wm_addr, wm_mask_cntl);
+
+       stutter_cntl = dm_read_reg(ctx, stutter_addr);
+       set_reg_field_value(stutter_cntl,
+               1,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_ENABLE);
+       set_reg_field_value(stutter_cntl,
+               1,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_IGNORE_FBC);
+
+       /*Write watermark set B*/
+       set_reg_field_value(stutter_cntl,
+               marks.b_mark,
+               DPG_PIPE_STUTTER_CONTROL,
+               STUTTER_EXIT_SELF_REFRESH_WATERMARK);
+       dm_write_reg(ctx, stutter_addr, stutter_cntl);
+}
+
+static void program_nbp_watermark(
+       const struct dc_context *ctx,
+       const uint32_t offset,
+       struct bw_watermarks marks)
+{
+       uint32_t value;
+       uint32_t addr;
+       /* Write mask to enable reading/writing of watermark set A */
+       addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_WATERMARK_MASK_CONTROL,
+               NB_PSTATE_CHANGE_WATERMARK_MASK);
+       dm_write_reg(ctx, addr, value);
+
+       addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_ENABLE);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+       dm_write_reg(ctx, addr, value);
+
+       /* Write watermark set A */
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               marks.a_mark,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_WATERMARK);
+       dm_write_reg(ctx, addr, value);
+
+       /* Write mask to enable reading/writing of watermark set B */
+       addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               2,
+               DPG_WATERMARK_MASK_CONTROL,
+               NB_PSTATE_CHANGE_WATERMARK_MASK);
+       dm_write_reg(ctx, addr, value);
+
+       addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_ENABLE);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
+       set_reg_field_value(
+               value,
+               1,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
+       dm_write_reg(ctx, addr, value);
+
+       /* Write watermark set B */
+       value = dm_read_reg(ctx, addr);
+       set_reg_field_value(
+               value,
+               marks.b_mark,
+               DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
+               NB_PSTATE_CHANGE_WATERMARK);
+       dm_write_reg(ctx, addr, value);
+}
+
+void dce110_mem_input_program_safe_display_marks(struct mem_input *mi)
+{
+       struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
+       struct bw_watermarks max_marks = { MAX_WATERMARK, MAX_WATERMARK };
+       struct bw_watermarks nbp_marks = { SAFE_NBP_MARK, SAFE_NBP_MARK };
+
+       program_urgency_watermark(
+               mi->ctx, bm_dce110->offsets.dmif, max_marks, MAX_WATERMARK);
+       program_stutter_watermark(mi->ctx, bm_dce110->offsets.dmif, max_marks);
+       program_nbp_watermark(mi->ctx, bm_dce110->offsets.dmif, nbp_marks);
+}
+
+void dce110_mem_input_program_display_marks(
+       struct mem_input *mem_input,
+       struct bw_watermarks nbp,
+       struct bw_watermarks stutter,
+       struct bw_watermarks urgent,
+       uint32_t h_total,
+       uint32_t pixel_clk_in_khz,
+       uint32_t pstate_blackout_duration_ns)
+{
+       struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mem_input);
+       uint32_t total_dest_line_time_ns = 1000000UL * h_total
+               / pixel_clk_in_khz + pstate_blackout_duration_ns;
+
+       program_urgency_watermark(
+               mem_input->ctx,
+               bm_dce110->offsets.dmif,
+               urgent,
+               total_dest_line_time_ns);
+       program_nbp_watermark(
+               mem_input->ctx,
+               bm_dce110->offsets.dmif,
+               nbp);
+       program_stutter_watermark(
+               mem_input->ctx,
+               bm_dce110->offsets.dmif,
+               stutter);
+}
+
+static uint32_t get_dmif_switch_time_us(struct dc_crtc_timing *timing)
+{
+       uint32_t frame_time;
+       uint32_t pixels_per_second;
+       uint32_t pixels_per_frame;
+       uint32_t refresh_rate;
+       const uint32_t us_in_sec = 1000000;
+       const uint32_t min_single_frame_time_us = 30000;
+       /*return double of frame time*/
+       const uint32_t single_frame_time_multiplier = 2;
+
+       if (timing == NULL)
+               return single_frame_time_multiplier * min_single_frame_time_us;
+
+       /*TODO: should we use pixel format normalized pixel clock here?*/
+       pixels_per_second = timing->pix_clk_khz * 1000;
+       pixels_per_frame = timing->h_total * timing->v_total;
+
+       if (!pixels_per_second || !pixels_per_frame) {
+               /* avoid division by zero */
+               ASSERT(pixels_per_frame);
+               ASSERT(pixels_per_second);
+               return single_frame_time_multiplier * min_single_frame_time_us;
+       }
+
+       refresh_rate = pixels_per_second / pixels_per_frame;
+
+       if (!refresh_rate) {
+               /* avoid division by zero*/
+               ASSERT(refresh_rate);
+               return single_frame_time_multiplier * min_single_frame_time_us;
+       }
+
+       frame_time = us_in_sec / refresh_rate;
+
+       if (frame_time < min_single_frame_time_us)
+               frame_time = min_single_frame_time_us;
+
+       frame_time *= single_frame_time_multiplier;
+
+       return frame_time;
+}
+
+void dce110_mem_input_allocate_dmif_buffer(
+               struct mem_input *mi,
+               struct dc_crtc_timing *timing,
+               uint32_t paths_num)
+{
+       const uint32_t retry_delay = 10;
+       uint32_t retry_count = get_dmif_switch_time_us(timing) / retry_delay;
+
+       struct dce110_mem_input *bm110 = TO_DCE110_MEM_INPUT(mi);
+       uint32_t addr = bm110->offsets.pipe + mmPIPE0_DMIF_BUFFER_CONTROL;
+       uint32_t value;
+       uint32_t field;
+       uint32_t pix_dur;
+
+       if (bm110->supported_stutter_mode
+                       & STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)
+               goto register_underflow_int;
+
+       /*Allocate DMIF buffer*/
+       value = dm_read_reg(mi->ctx, addr);
+       field = get_reg_field_value(
+               value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
+       if (field == 2)
+               goto register_underflow_int;
+
+       set_reg_field_value(
+                       value,
+                       2,
+                       PIPE0_DMIF_BUFFER_CONTROL,
+                       DMIF_BUFFERS_ALLOCATED);
+
+       dm_write_reg(mi->ctx, addr, value);
+
+       do {
+               value = dm_read_reg(mi->ctx, addr);
+               field = get_reg_field_value(
+                       value,
+                       PIPE0_DMIF_BUFFER_CONTROL,
+                       DMIF_BUFFERS_ALLOCATION_COMPLETED);
+
+               if (field)
+                       break;
+
+               dm_delay_in_microseconds(mi->ctx, retry_delay);
+               retry_count--;
+
+       } while (retry_count > 0);
+
+       if (field == 0)
+               dal_logger_write(mi->ctx->logger,
+                               LOG_MAJOR_ERROR,
+                               LOG_MINOR_COMPONENT_GPU,
+                               "%s: DMIF allocation failed",
+                               __func__);
+
+
+       if (timing->pix_clk_khz != 0) {
+               addr = mmDPG_PIPE_ARBITRATION_CONTROL1 + bm110->offsets.dmif;
+               value = dm_read_reg(mi->ctx, addr);
+               pix_dur = 1000000000ULL / timing->pix_clk_khz;
+
+               set_reg_field_value(
+                       value,
+                       pix_dur,
+                       DPG_PIPE_ARBITRATION_CONTROL1,
+                       PIXEL_DURATION);
+
+               dm_write_reg(mi->ctx, addr, value);
+       }
+
+       /*
+        * Stella Wong proposed the following change
+        *
+        * Value of mcHubRdReqDmifLimit.ENABLE:
+        * 00 - disable DMIF rdreq limit
+        * 01 - enable DMIF rdreq limit, disabled by DMIF stall = 1 || urg != 0
+        * 02 - enable DMIF rdreq limit, disable by DMIF stall = 1
+        * 03 - force enable DMIF rdreq limit, ignore DMIF stall / urgent
+        */
+       if (!IS_FPGA_MAXIMUS_DC(mi->ctx->dce_environment)) {
+               addr = mmMC_HUB_RDREQ_DMIF_LIMIT;
+               value = dm_read_reg(mi->ctx, addr);
+
+               if (paths_num > 1)
+                       set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, 
ENABLE);
+               else
+                       set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, 
ENABLE);
+               dm_write_reg(mi->ctx, addr, value);
+       }
+
+register_underflow_int:
+       /*todo*/;
+       /*register_interrupt(bm110, irq_source, ctrl_id);*/
+}
+
+static void deallocate_dmif_buffer_helper(
+                               struct dc_context *ctx, uint32_t offset)
+{
+       uint32_t value;
+       uint32_t count = 0xBB8; /* max retry count */
+
+       value = dm_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
+
+       if (!get_reg_field_value(
+               value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED))
+               return;
+
+       set_reg_field_value(
+               value, 0, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
+
+       dm_write_reg(
+               ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset, value);
+
+       do {
+               value = dm_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
+               dm_delay_in_microseconds(ctx, 10);
+               count--;
+       } while (count > 0 &&
+               !get_reg_field_value(
+                       value,
+                       PIPE0_DMIF_BUFFER_CONTROL,
+                       DMIF_BUFFERS_ALLOCATION_COMPLETED));
+}
+
+void dce110_mem_input_deallocate_dmif_buffer(
+       struct mem_input *mi, uint32_t paths_num)
+{
+       struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
+       uint32_t value;
+
+       if (!(bm_dce110->supported_stutter_mode &
+               STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)) {
+
+               /* De-allocate DMIF buffer first */
+               if (mmPIPE0_DMIF_BUFFER_CONTROL + bm_dce110->offsets.pipe != 0)
+                       deallocate_dmif_buffer_helper(
+                                       mi->ctx, bm_dce110->offsets.pipe);
+       }
+
+       /* TODO: unregister underflow interrupt
+       unregisterInterrupt();
+       */
+
+       /* Value of mcHubRdReqDmifLimit.ENABLE.
+        * 00 - disable dmif rdreq limit
+        * 01 - enable dmif rdreq limit, disable by dmif stall=1||urg!=0
+        * 02 - enable dmif rdreq limit, disable by dmif stall=1
+        * 03 - force enable dmif rdreq limit, ignore dmif stall/urgent
+        * Stella Wong proposed this change. */
+       if (!IS_FPGA_MAXIMUS_DC(mi->ctx->dce_environment)) {
+               value = dm_read_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT);
+               if (paths_num > 1)
+                       set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, 
ENABLE);
+               else
+                       set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, 
ENABLE);
+
+               dm_write_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT, value);
+       }
+}
+
+static struct mem_input_funcs dce110_mem_input_funcs = {
+       .mem_input_program_safe_display_marks =
+                       dce110_mem_input_program_safe_display_marks,
+       .mem_input_program_display_marks =
+                       dce110_mem_input_program_display_marks,
+       .mem_input_allocate_dmif_buffer = dce110_mem_input_allocate_dmif_buffer,
+       .mem_input_deallocate_dmif_buffer =
+                       dce110_mem_input_deallocate_dmif_buffer,
+       .mem_input_program_surface_flip_and_addr =
+                       dce110_mem_input_program_surface_flip_and_addr,
+       .mem_input_program_surface_config =
+                       dce110_mem_input_program_surface_config,
+};
+/*****************************************/
+/* Constructor, Destructor               */
+/*****************************************/
+
+bool dce110_mem_input_construct(
+       struct dce110_mem_input *mem_input110,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dce110_mem_input_reg_offsets *offsets)
+{
+       mem_input110->base.funcs = &dce110_mem_input_funcs;
+       mem_input110->base.ctx = ctx;
+
+       mem_input110->base.inst = inst;
+
+       mem_input110->offsets = *offsets;
+
+       mem_input110->supported_stutter_mode = 0;
+       dal_adapter_service_get_feature_value(FEATURE_STUTTER_MODE,
+                       &(mem_input110->supported_stutter_mode),
+                       sizeof(mem_input110->supported_stutter_mode));
+
+       return true;
+}
+
+void dce110_mem_input_destroy(struct mem_input **mem_input)
+{
+       dm_free((*mem_input)->ctx, TO_DCE110_MEM_INPUT(*mem_input));
+       *mem_input = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h 
b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
new file mode 100644
index 000000000000..5a4e5fe33a79
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
@@ -0,0 +1,117 @@
+/* Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_MEM_INPUT_DCE110_H__
+#define __DC_MEM_INPUT_DCE110_H__
+
+#include "inc/mem_input.h"
+
+#define TO_DCE110_MEM_INPUT(mi)\
+       container_of(mi, struct dce110_mem_input, base)
+
+struct dce110_mem_input_reg_offsets {
+       uint32_t dcp;
+       uint32_t dmif;
+       uint32_t pipe;
+};
+
+struct dce110_mem_input {
+       struct mem_input base;
+       struct dce110_mem_input_reg_offsets offsets;
+       uint32_t supported_stutter_mode;
+};
+
+bool dce110_mem_input_construct(
+       struct dce110_mem_input *mem_input110,
+       struct dc_context *ctx,
+       uint32_t inst,
+       const struct dce110_mem_input_reg_offsets *offsets);
+
+/*
+ * dce110_mem_input_program_display_marks
+ *
+ * This function will program nbp stutter and urgency watermarks to maximum
+ * safe values
+ */
+void dce110_mem_input_program_safe_display_marks(struct mem_input *mi);
+
+/*
+ * dce110_mem_input_program_display_marks
+ *
+ * This function will program nbp stutter and urgency watermarks to minimum
+ * allowable values
+ */
+void dce110_mem_input_program_display_marks(
+       struct mem_input *mem_input,
+       struct bw_watermarks nbp,
+       struct bw_watermarks stutter,
+       struct bw_watermarks urgent,
+       uint32_t h_total,
+       uint32_t pixel_clk_in_khz,
+       uint32_t pstate_blackout_duration_ns);
+
+/*
+ * dce110_mem_input_allocate_dmif_buffer
+ *
+ * This function will allocate a dmif buffer and program required
+ * pixel duration for pipe
+ */
+void dce110_mem_input_allocate_dmif_buffer(
+               struct mem_input *mem_input,
+               struct dc_crtc_timing *timing,
+               uint32_t paths_num);
+
+/*
+ * dce110_mem_input_deallocate_dmif_buffer
+ *
+ * This function will deallocate a dmif buffer from pipe
+ */
+void dce110_mem_input_deallocate_dmif_buffer(
+       struct mem_input *mem_input, uint32_t paths_num);
+
+/*
+ * dce110_mem_input_program_surface_flip_and_addr
+ *
+ * This function programs hsync/vsync mode and surface address
+ */
+bool dce110_mem_input_program_surface_flip_and_addr(
+       struct mem_input *mem_input,
+       const struct dc_plane_address *address,
+       bool flip_immediate);
+
+/*
+ * dce110_mem_input_program_surface_config
+ *
+ * This function will program surface tiling, size, rotation and pixel format
+ * to corresponding dcp registers.
+ */
+bool  dce110_mem_input_program_surface_config(
+       struct mem_input *mem_input,
+       enum surface_pixel_format format,
+       struct dc_tiling_info *tiling_info,
+       union plane_size *plane_size,
+       enum dc_rotation_angle rotation);
+
+
+#endif
-- 
2.1.4

Reply via email to