summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c')
-rw-r--r--drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c507
1 files changed, 507 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c b/drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c
new file mode 100644
index 000000000000..94c0d83f00cc
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/controller/dce110/timing_generator_v_dce110.c
@@ -0,0 +1,507 @@
+/*
+ * 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 "dal_services.h"
+
+/* include DCE11 register header files */
+#include "dce/dce_11_0_d.h"
+#include "dce/dce_11_0_sh_mask.h"
+
+
+#include "include/grph_object_id.h"
+#include "include/adapter_service_interface.h"
+
+#include "timing_generator_v_dce110.h"
+#include "../timing_generator.h"
+
+enum tg_regs_idx {
+ IDX_CRTC_UPDATE_LOCK,
+ IDX_CRTC_MASTER_UPDATE_LOCK,
+ IDX_CRTC_MASTER_UPDATE_MODE,
+ IDX_CRTC_H_TOTAL,
+ IDX_CRTC_V_TOTAL,
+ IDX_CRTC_H_BLANK_START_END,
+ IDX_CRTC_V_BLANK_START_END,
+ IDX_CRTC_H_SYNC_A,
+ IDX_CRTC_V_SYNC_A,
+ IDX_CRTC_H_SYNC_A_CNTL,
+ IDX_CRTC_V_SYNC_A_CNTL,
+ IDX_CRTC_INTERLACE_CONTROL,
+ IDX_CRTC_BLANK_CONTROL,
+ IDX_PIPE_PG_STATUS,
+
+ IDX_CRTC_TEST_PATTERN_COLOR,
+ IDX_CRTC_TEST_PATTERN_CONTROL,
+ IDX_CRTC_TEST_PATTERN_PARAMETERS,
+ IDX_CRTC_FLOW_CONTROL,
+ IDX_CRTC_STATUS,
+ IDX_CRTC_STATUS_POSITION,
+ IDX_CRTC_STATUS_FRAME_COUNT,
+ IDX_CRTC_STEREO_CONTROL,
+ IDX_CRTC_STEREO_STATUS,
+ IDX_CRTC_STEREO_FORCE_NEXT_EYE,
+ IDX_CRTC_3D_STRUCTURE_CONTROL,
+ IDX_CRTC_DOUBLE_BUFFER_CONTROL,
+ IDX_CRTC_V_TOTAL_MIN,
+ IDX_CRTC_V_TOTAL_MAX,
+ IDX_CRTC_V_TOTAL_CONTROL,
+ IDX_CRTC_NOM_VERT_POSITION,
+ IDX_CRTC_STATIC_SCREEN_CONTROL,
+ IDX_CRTC_TRIGB_CNTL,
+ IDX_CRTC_FORCE_COUNT_CNTL,
+ IDX_CRTC_GSL_CONTROL,
+
+ IDX_CRTC_CONTROL,
+ IDX_CRTC_START_LINE_CONTROL,
+ IDX_CRTC_COUNT_CONTROL,
+
+ IDX_MODE_EXT_OVERSCAN_LEFT_RIGHT,
+ IDX_MODE_EXT_OVERSCAN_TOP_BOTTOM,
+ IDX_DCP_GSL_CONTROL,
+ IDX_GRPH_UPDATE,
+
+ IDX_CRTC_VBI_END,
+
+ IDX_BLND_UNDERFLOW_INTERRUPT,
+ IDX_CRTC_BLACK_COLOR,
+ TG_REGS_IDX_SIZE
+};
+
+#define regs_for_underlay_controller()\
+{[IDX_CRTC_UPDATE_LOCK] = 0,\
+[IDX_CRTC_MASTER_UPDATE_LOCK] = 0,\
+[IDX_CRTC_MASTER_UPDATE_MODE] = 0,\
+[IDX_CRTC_H_TOTAL] = mmCRTCV_H_TOTAL,\
+[IDX_CRTC_V_TOTAL] = mmCRTCV_V_TOTAL,\
+[IDX_CRTC_H_BLANK_START_END] = mmCRTCV_H_BLANK_START_END,\
+[IDX_CRTC_V_BLANK_START_END] = mmCRTCV_V_BLANK_START_END,\
+[IDX_CRTC_H_SYNC_A] = 0,\
+[IDX_CRTC_V_SYNC_A] = 0,\
+[IDX_CRTC_H_SYNC_A_CNTL] = 0,\
+[IDX_CRTC_V_SYNC_A_CNTL] = 0,\
+[IDX_CRTC_INTERLACE_CONTROL] = 0,\
+[IDX_CRTC_BLANK_CONTROL] = mmCRTCV_BLANK_CONTROL,\
+[IDX_PIPE_PG_STATUS] = 0,\
+[IDX_CRTC_TEST_PATTERN_COLOR] = mmCRTCV_TEST_PATTERN_COLOR,\
+[IDX_CRTC_TEST_PATTERN_CONTROL] = mmCRTCV_TEST_PATTERN_CONTROL,\
+[IDX_CRTC_TEST_PATTERN_PARAMETERS] = mmCRTCV_TEST_PATTERN_PARAMETERS,\
+[IDX_CRTC_FLOW_CONTROL] = 0,\
+[IDX_CRTC_STATUS] = 0,\
+[IDX_CRTC_STATUS_POSITION] = 0,\
+[IDX_CRTC_STATUS_FRAME_COUNT] = 0,\
+[IDX_CRTC_STEREO_CONTROL] = 0,\
+[IDX_CRTC_STEREO_STATUS] = 0,\
+[IDX_CRTC_STEREO_FORCE_NEXT_EYE] = 0,\
+[IDX_CRTC_3D_STRUCTURE_CONTROL] = 0,\
+[IDX_CRTC_DOUBLE_BUFFER_CONTROL] = 0,\
+[IDX_CRTC_V_TOTAL_MIN] = 0,\
+[IDX_CRTC_V_TOTAL_MAX] = 0,\
+[IDX_CRTC_V_TOTAL_CONTROL] = 0,\
+[IDX_CRTC_NOM_VERT_POSITION] = 0,\
+[IDX_CRTC_STATIC_SCREEN_CONTROL] = 0,\
+[IDX_CRTC_TRIGB_CNTL] = 0,\
+[IDX_CRTC_FORCE_COUNT_CNTL] = 0,\
+[IDX_CRTC_GSL_CONTROL] = 0,\
+[IDX_CRTC_CONTROL] = mmCRTCV_CONTROL,\
+[IDX_CRTC_START_LINE_CONTROL] = mmCRTCV_START_LINE_CONTROL,\
+[IDX_CRTC_COUNT_CONTROL] = 0,\
+[IDX_MODE_EXT_OVERSCAN_LEFT_RIGHT] = 0,\
+[IDX_MODE_EXT_OVERSCAN_TOP_BOTTOM] = 0,\
+[IDX_DCP_GSL_CONTROL] = 0,\
+[IDX_GRPH_UPDATE] = 0,\
+[IDX_CRTC_VBI_END] = 0,\
+[IDX_BLND_UNDERFLOW_INTERRUPT] = 0,\
+[IDX_CRTC_BLACK_COLOR] = mmCRTCV_BLACK_COLOR,\
+}
+
+static uint32_t tg_underlay_regs[][TG_REGS_IDX_SIZE] = {
+ regs_for_underlay_controller(),
+};
+
+static void set_lock_master(struct timing_generator *tg, bool lock)
+{
+ struct dal_context *dal_ctx = tg->ctx;
+ uint32_t addr = tg->regs[IDX_CRTC_MASTER_UPDATE_LOCK];
+ uint32_t value = dal_read_reg(dal_ctx, addr);
+
+ set_reg_field_value(
+ value,
+ lock ? 1 : 0,
+ CRTCV_MASTER_UPDATE_LOCK,
+ MASTER_UPDATE_LOCK);
+
+ dal_write_reg(dal_ctx, addr, value);
+}
+
+static void program_blanking(
+ struct timing_generator *tg,
+ const struct hw_crtc_timing *timing)
+{
+ struct dal_context *dal_ctx = tg->ctx;
+ uint32_t value = 0;
+ uint32_t addr = 0;
+ uint32_t tmp = 0;
+
+ addr = tg->regs[IDX_CRTC_H_TOTAL];
+ value = dal_read_reg(dal_ctx, addr);
+ set_reg_field_value(
+ value,
+ timing->h_total - 1,
+ CRTCV_H_TOTAL,
+ CRTC_H_TOTAL);
+ dal_write_reg(dal_ctx, addr, value);
+
+ addr = tg->regs[IDX_CRTC_V_TOTAL];
+ value = dal_read_reg(dal_ctx, addr);
+ set_reg_field_value(
+ value,
+ timing->v_total - 1,
+ CRTCV_V_TOTAL,
+ CRTC_V_TOTAL);
+ dal_write_reg(dal_ctx, addr, value);
+
+ addr = tg->regs[IDX_CRTC_H_BLANK_START_END];
+ value = dal_read_reg(dal_ctx, addr);
+
+ tmp = timing->h_total -
+ (timing->h_sync_start + timing->h_overscan_left);
+
+ set_reg_field_value(
+ value,
+ tmp,
+ CRTC_H_BLANK_START_END,
+ CRTC_H_BLANK_END);
+
+ tmp = tmp + timing->h_addressable +
+ timing->h_overscan_left + timing->h_overscan_right;
+
+ set_reg_field_value(
+ value,
+ tmp,
+ CRTC_H_BLANK_START_END,
+ CRTC_H_BLANK_START);
+
+ dal_write_reg(dal_ctx, addr, value);
+
+ addr = tg->regs[IDX_CRTC_V_BLANK_START_END];
+ value = dal_read_reg(dal_ctx, addr);
+
+ tmp = timing->v_total - (timing->v_sync_start + timing->v_overscan_top);
+
+ set_reg_field_value(
+ value,
+ tmp,
+ CRTCV_V_BLANK_START_END,
+ CRTC_V_BLANK_END);
+
+ tmp = tmp + timing->v_addressable + timing->v_overscan_top +
+ timing->v_overscan_bottom;
+
+ set_reg_field_value(
+ value,
+ tmp,
+ CRTCV_V_BLANK_START_END,
+ CRTC_V_BLANK_START);
+
+ dal_write_reg(dal_ctx, addr, value);
+}
+
+static void set_test_pattern(
+ struct timing_generator *tg,
+ /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
+ * because this is not DP-specific (which is probably somewhere in DP
+ * encoder) */
+ enum controller_dp_test_pattern test_pattern,
+ enum crtc_color_depth color_depth)
+{
+ struct dal_context *dal_ctx = tg->ctx;
+ uint32_t value;
+ uint32_t addr;
+
+ /* TODO: add support for other test patterns */
+ switch (test_pattern) {
+ default:
+ value = 0;
+ addr = tg->regs[IDX_CRTC_TEST_PATTERN_PARAMETERS];
+
+ set_reg_field_value(
+ value,
+ 6,
+ CRTCV_TEST_PATTERN_PARAMETERS,
+ CRTC_TEST_PATTERN_VRES);
+ set_reg_field_value(
+ value,
+ 6,
+ CRTCV_TEST_PATTERN_PARAMETERS,
+ CRTC_TEST_PATTERN_HRES);
+
+ dal_write_reg(dal_ctx, addr, value);
+
+ addr = tg->regs[IDX_CRTC_TEST_PATTERN_CONTROL];
+ value = 0;
+
+ set_reg_field_value(
+ value,
+ 1,
+ CRTCV_TEST_PATTERN_CONTROL,
+ CRTC_TEST_PATTERN_EN);
+
+ set_reg_field_value(
+ value,
+ 0,
+ CRTCV_TEST_PATTERN_CONTROL,
+ CRTC_TEST_PATTERN_MODE);
+
+ set_reg_field_value(
+ value,
+ 1,
+ CRTCV_TEST_PATTERN_CONTROL,
+ CRTC_TEST_PATTERN_DYNAMIC_RANGE);
+ /* add color depth translation here */
+ set_reg_field_value(
+ value,
+ 1,
+ CRTCV_TEST_PATTERN_CONTROL,
+ CRTC_TEST_PATTERN_COLOR_FORMAT);
+ dal_write_reg(dal_ctx, addr, value);
+ break;
+ } /* switch() */
+}
+
+static int get_vsync_and_front_porch_size(
+ const struct hw_crtc_timing *timing)
+{
+ int32_t front_porch = (int32_t) (
+ timing->v_sync_start
+ - timing->v_addressable
+ - timing->v_overscan_bottom
+ + timing->flags.INTERLACED);
+
+ return timing->v_sync_width + front_porch;
+}
+
+static void enable_advanced_request(
+ struct timing_generator *tg,
+ bool enable,
+ const struct hw_crtc_timing *timing)
+{
+ uint32_t addr = tg->regs[IDX_CRTC_START_LINE_CONTROL];
+ uint32_t value = dal_read_reg(tg->ctx, addr);
+ uint32_t start_line_position;
+
+ if (enable) {
+ if (get_vsync_and_front_porch_size(timing) <= 3)
+ start_line_position = 3;
+ else
+ start_line_position = 4;
+ } else
+ start_line_position = 2;
+
+ set_reg_field_value(
+ value,
+ start_line_position,
+ CRTCV_START_LINE_CONTROL,
+ CRTC_ADVANCED_START_LINE_POSITION);
+
+ set_reg_field_value(
+ value,
+ enable ? 1 : 0,
+ CRTCV_START_LINE_CONTROL,
+ CRTC_LEGACY_REQUESTOR_EN);
+
+ dal_write_reg(tg->ctx, addr, value);
+}
+
+/*****************************************/
+/* Constructor, Destructor, Fcn Pointers */
+/*****************************************/
+
+static void destroy(struct timing_generator **tg)
+{
+ dal_free(*tg);
+ *tg = NULL;
+}
+
+static bool disable_crtc(struct timing_generator *tg)
+{
+ uint32_t addr = tg->regs[IDX_CRTC_CONTROL];
+ uint32_t value = dal_read_reg(tg->ctx, addr);
+
+ set_reg_field_value(
+ value,
+ 0,
+ CRTCV_CONTROL,
+ CRTC_DISABLE_POINT_CNTL);
+
+ set_reg_field_value(
+ value,
+ 0,
+ CRTCV_CONTROL,
+ CRTC_MASTER_EN);
+
+ dal_write_reg(tg->ctx, addr, value);
+
+ return true;
+}
+
+static bool blank_crtc(
+ struct timing_generator *tg,
+ enum color_space color_space)
+{
+ struct crtc_black_color black_color;
+ uint32_t addr = tg->regs[IDX_CRTC_BLACK_COLOR];
+ uint32_t value = dal_read_reg(tg->ctx, addr);
+
+ dal_timing_generator_color_space_to_black_color(
+ color_space,
+ &black_color);
+
+ set_reg_field_value(
+ value,
+ black_color.black_color_b_cb,
+ CRTCV_BLACK_COLOR,
+ CRTC_BLACK_COLOR_B_CB);
+ set_reg_field_value(
+ value,
+ black_color.black_color_g_y,
+ CRTCV_BLACK_COLOR,
+ CRTC_BLACK_COLOR_G_Y);
+ set_reg_field_value(
+ value,
+ black_color.black_color_r_cr,
+ CRTCV_BLACK_COLOR,
+ CRTC_BLACK_COLOR_R_CR);
+
+ dal_write_reg(tg->ctx, addr, value);
+
+ addr = tg->regs[IDX_CRTC_BLANK_CONTROL];
+ value = dal_read_reg(tg->ctx, addr);
+ set_reg_field_value(
+ value,
+ 1,
+ CRTCV_BLANK_CONTROL,
+ CRTC_BLANK_DATA_EN);
+
+ set_reg_field_value(
+ value,
+ 1,
+ CRTCV_BLANK_CONTROL,
+ CRTC_BLANK_DE_MODE);
+
+ dal_write_reg(tg->ctx, addr, value);
+
+ return true;
+}
+
+static const struct timing_generator_funcs timing_generator_dce110_funcs = {
+ .blank_crtc = blank_crtc,
+ .did_triggered_reset_occur = NULL,
+ .disable_crtc = disable_crtc,
+ .disable_reset_trigger = NULL,
+ .disable_stereo = NULL,
+ .enable_advanced_request = enable_advanced_request,
+ .enable_crtc = NULL,
+ .enable_reset_trigger = NULL,
+ .enable_stereo = NULL,
+ .force_stereo_next_eye = NULL,
+ .get_crtc_position = NULL,
+ .get_crtc_timing = NULL,
+ .get_current_frame_number = NULL,
+ .get_global_swap_lock_setup = NULL,
+ .get_io_sequence = NULL,
+ .get_stereo_status = NULL,
+ .is_counter_moving = NULL,
+ .is_in_vertical_blank = NULL,
+ .is_test_pattern_enabled = NULL,
+ .set_lock_graph_surface_registers = NULL,
+ .set_lock_master = set_lock_master,
+ .set_lock_timing_registers = NULL,
+ .program_blanking = program_blanking,
+ .program_drr = NULL,
+ .program_flow_control = NULL,
+ .program_timing_generator = NULL,
+ .program_vbi_end_signal = NULL,
+ .reprogram_timing = NULL,
+ .reset_stereo_3d_phase = NULL,
+ .set_early_control = NULL,
+ .set_horizontal_sync_composite = NULL,
+ .set_horizontal_sync_polarity = NULL,
+ .set_test_pattern = set_test_pattern,
+ .set_vertical_sync_polarity = NULL,
+ .setup_global_swap_lock = NULL,
+ .unblank_crtc = NULL,
+ .validate_timing = NULL,
+ .destroy = destroy,
+ .wait_for_vactive = NULL,
+ .force_triggered_reset_now = NULL,
+ .wait_for_vblank = NULL,
+ .get_crtc_scanoutpos = NULL,
+ .get_vblank_counter = NULL,
+};
+
+static bool construct(struct timing_generator *tg,
+ struct dal_context *ctx,
+ struct adapter_service *as,
+ enum controller_id id)
+{
+ if (!as)
+ return false;
+
+ switch (id) {
+ case CONTROLLER_ID_UNDERLAY0:
+ break;
+ default:
+ return false;
+ }
+
+ if (!dal_timing_generator_construct(tg, id))
+ return false;
+
+ tg->ctx = ctx;
+ tg->bp = dal_adapter_service_get_bios_parser(as);
+
+ tg->regs = tg_underlay_regs[id - CONTROLLER_ID_UNDERLAY0];
+
+ tg->funcs = &timing_generator_dce110_funcs;
+ return true;
+}
+
+struct timing_generator *dal_timing_generator_v_dce110_create(
+ struct adapter_service *as,
+ struct dal_context *ctx,
+ enum controller_id id)
+{
+ struct timing_generator *tg = dal_alloc(sizeof(*tg));
+
+ if (!tg)
+ return NULL;
+
+ if (construct(tg, ctx, as, id))
+ return tg;
+
+ BREAK_TO_DEBUGGER();
+ dal_free(tg);
+ return NULL;
+}