2009-06-05 20:42:42 +08:00
|
|
|
/*
|
|
|
|
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
|
|
|
|
* VA Linux Systems Inc., Fremont, California.
|
|
|
|
* Copyright 2008 Red Hat 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.
|
|
|
|
*
|
|
|
|
* Original Authors:
|
|
|
|
* Kevin E. Martin, Rickard E. Faith, Alan Hourihane
|
|
|
|
*
|
|
|
|
* Kernel port Author: Dave Airlie
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef RADEON_MODE_H
|
|
|
|
#define RADEON_MODE_H
|
|
|
|
|
2012-10-03 01:01:07 +08:00
|
|
|
#include <drm/drm_crtc.h>
|
|
|
|
#include <drm/drm_edid.h>
|
2016-11-29 02:51:09 +08:00
|
|
|
#include <drm/drm_encoder.h>
|
2012-10-03 01:01:07 +08:00
|
|
|
#include <drm/drm_dp_helper.h>
|
2015-02-24 07:24:04 +08:00
|
|
|
#include <drm/drm_dp_mst_helper.h>
|
2012-10-03 01:01:07 +08:00
|
|
|
#include <drm/drm_fixed.h>
|
|
|
|
#include <drm/drm_crtc_helper.h>
|
2009-06-05 20:42:42 +08:00
|
|
|
#include <linux/i2c.h>
|
|
|
|
#include <linux/i2c-algo-bit.h>
|
2009-07-14 03:04:08 +08:00
|
|
|
|
2010-03-30 13:34:13 +08:00
|
|
|
struct radeon_bo;
|
2009-07-14 03:04:08 +08:00
|
|
|
struct radeon_device;
|
2009-06-05 20:42:42 +08:00
|
|
|
|
|
|
|
#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)
|
|
|
|
#define to_radeon_connector(x) container_of(x, struct radeon_connector, base)
|
|
|
|
#define to_radeon_encoder(x) container_of(x, struct radeon_encoder, base)
|
|
|
|
#define to_radeon_framebuffer(x) container_of(x, struct radeon_framebuffer, base)
|
|
|
|
|
2014-06-30 03:02:20 +08:00
|
|
|
#define RADEON_MAX_HPD_PINS 7
|
|
|
|
#define RADEON_MAX_CRTCS 6
|
|
|
|
#define RADEON_MAX_AFMT_BLOCKS 7
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
enum radeon_rmx_type {
|
|
|
|
RMX_OFF,
|
|
|
|
RMX_FULL,
|
|
|
|
RMX_CENTER,
|
|
|
|
RMX_ASPECT
|
|
|
|
};
|
|
|
|
|
|
|
|
enum radeon_tv_std {
|
|
|
|
TV_STD_NTSC,
|
|
|
|
TV_STD_PAL,
|
|
|
|
TV_STD_PAL_M,
|
|
|
|
TV_STD_PAL_60,
|
|
|
|
TV_STD_NTSC_J,
|
|
|
|
TV_STD_SCART_PAL,
|
|
|
|
TV_STD_SECAM,
|
|
|
|
TV_STD_PAL_CN,
|
2009-12-18 08:00:29 +08:00
|
|
|
TV_STD_PAL_N,
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
2010-08-04 07:59:20 +08:00
|
|
|
enum radeon_underscan_type {
|
|
|
|
UNDERSCAN_OFF,
|
|
|
|
UNDERSCAN_ON,
|
|
|
|
UNDERSCAN_AUTO,
|
|
|
|
};
|
|
|
|
|
2010-05-19 07:26:47 +08:00
|
|
|
enum radeon_hpd_id {
|
|
|
|
RADEON_HPD_1 = 0,
|
|
|
|
RADEON_HPD_2,
|
|
|
|
RADEON_HPD_3,
|
|
|
|
RADEON_HPD_4,
|
|
|
|
RADEON_HPD_5,
|
|
|
|
RADEON_HPD_6,
|
|
|
|
RADEON_HPD_NONE = 0xff,
|
|
|
|
};
|
|
|
|
|
2015-02-23 23:11:49 +08:00
|
|
|
enum radeon_output_csc {
|
|
|
|
RADEON_OUTPUT_CSC_BYPASS = 0,
|
|
|
|
RADEON_OUTPUT_CSC_TVRGB = 1,
|
|
|
|
RADEON_OUTPUT_CSC_YCBCR601 = 2,
|
|
|
|
RADEON_OUTPUT_CSC_YCBCR709 = 3,
|
|
|
|
};
|
|
|
|
|
2010-08-06 09:21:16 +08:00
|
|
|
#define RADEON_MAX_I2C_BUS 16
|
|
|
|
|
2009-11-11 04:59:44 +08:00
|
|
|
/* radeon gpio-based i2c
|
|
|
|
* 1. "mask" reg and bits
|
|
|
|
* grabs the gpio pins for software use
|
|
|
|
* 0=not held 1=held
|
|
|
|
* 2. "a" reg and bits
|
|
|
|
* output pin value
|
|
|
|
* 0=low 1=high
|
|
|
|
* 3. "en" reg and bits
|
|
|
|
* sets the pin direction
|
|
|
|
* 0=input 1=output
|
|
|
|
* 4. "y" reg and bits
|
|
|
|
* input pin value
|
|
|
|
* 0=low 1=high
|
|
|
|
*/
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_i2c_bus_rec {
|
|
|
|
bool valid;
|
2009-11-24 06:39:28 +08:00
|
|
|
/* id used by atom */
|
|
|
|
uint8_t i2c_id;
|
2010-01-13 06:54:34 +08:00
|
|
|
/* id used by atom */
|
2010-05-19 07:26:47 +08:00
|
|
|
enum radeon_hpd_id hpd;
|
2009-11-24 06:39:28 +08:00
|
|
|
/* can be used with hw i2c engine */
|
|
|
|
bool hw_capable;
|
|
|
|
/* uses multi-media i2c engine */
|
|
|
|
bool mm_i2c;
|
|
|
|
/* regs and bits */
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t mask_clk_reg;
|
|
|
|
uint32_t mask_data_reg;
|
|
|
|
uint32_t a_clk_reg;
|
|
|
|
uint32_t a_data_reg;
|
2009-11-11 04:59:44 +08:00
|
|
|
uint32_t en_clk_reg;
|
|
|
|
uint32_t en_data_reg;
|
|
|
|
uint32_t y_clk_reg;
|
|
|
|
uint32_t y_data_reg;
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t mask_clk_mask;
|
|
|
|
uint32_t mask_data_mask;
|
|
|
|
uint32_t a_clk_mask;
|
|
|
|
uint32_t a_data_mask;
|
2009-11-11 04:59:44 +08:00
|
|
|
uint32_t en_clk_mask;
|
|
|
|
uint32_t en_data_mask;
|
|
|
|
uint32_t y_clk_mask;
|
|
|
|
uint32_t y_data_mask;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_tmds_pll {
|
|
|
|
uint32_t freq;
|
|
|
|
uint32_t value;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define RADEON_MAX_BIOS_CONNECTOR 16
|
|
|
|
|
2010-02-03 01:05:01 +08:00
|
|
|
/* pll flags */
|
2009-06-05 20:42:42 +08:00
|
|
|
#define RADEON_PLL_USE_BIOS_DIVS (1 << 0)
|
|
|
|
#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1)
|
|
|
|
#define RADEON_PLL_USE_REF_DIV (1 << 2)
|
|
|
|
#define RADEON_PLL_LEGACY (1 << 3)
|
|
|
|
#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4)
|
|
|
|
#define RADEON_PLL_PREFER_HIGH_REF_DIV (1 << 5)
|
|
|
|
#define RADEON_PLL_PREFER_LOW_FB_DIV (1 << 6)
|
|
|
|
#define RADEON_PLL_PREFER_HIGH_FB_DIV (1 << 7)
|
|
|
|
#define RADEON_PLL_PREFER_LOW_POST_DIV (1 << 8)
|
|
|
|
#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9)
|
|
|
|
#define RADEON_PLL_USE_FRAC_FB_DIV (1 << 10)
|
2009-07-13 23:08:18 +08:00
|
|
|
#define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
|
2010-01-20 06:16:10 +08:00
|
|
|
#define RADEON_PLL_USE_POST_DIV (1 << 12)
|
2010-03-09 01:55:16 +08:00
|
|
|
#define RADEON_PLL_IS_LCD (1 << 13)
|
2011-02-01 05:48:52 +08:00
|
|
|
#define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14)
|
2009-06-05 20:42:42 +08:00
|
|
|
|
|
|
|
struct radeon_pll {
|
2010-01-20 06:16:10 +08:00
|
|
|
/* reference frequency */
|
|
|
|
uint32_t reference_freq;
|
|
|
|
|
|
|
|
/* fixed dividers */
|
|
|
|
uint32_t reference_div;
|
|
|
|
uint32_t post_div;
|
|
|
|
|
|
|
|
/* pll in/out limits */
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t pll_in_min;
|
|
|
|
uint32_t pll_in_max;
|
|
|
|
uint32_t pll_out_min;
|
|
|
|
uint32_t pll_out_max;
|
2010-03-09 01:55:16 +08:00
|
|
|
uint32_t lcd_pll_out_min;
|
|
|
|
uint32_t lcd_pll_out_max;
|
2010-01-20 06:16:10 +08:00
|
|
|
uint32_t best_vco;
|
2009-06-05 20:42:42 +08:00
|
|
|
|
2010-01-20 06:16:10 +08:00
|
|
|
/* divider limits */
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t min_ref_div;
|
|
|
|
uint32_t max_ref_div;
|
|
|
|
uint32_t min_post_div;
|
|
|
|
uint32_t max_post_div;
|
|
|
|
uint32_t min_feedback_div;
|
|
|
|
uint32_t max_feedback_div;
|
|
|
|
uint32_t min_frac_feedback_div;
|
|
|
|
uint32_t max_frac_feedback_div;
|
2010-01-20 06:16:10 +08:00
|
|
|
|
|
|
|
/* flags for the current clock */
|
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
/* pll id */
|
|
|
|
uint32_t id;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_i2c_chan {
|
|
|
|
struct i2c_adapter adapter;
|
2009-12-08 05:07:28 +08:00
|
|
|
struct drm_device *dev;
|
2014-04-07 22:33:46 +08:00
|
|
|
struct i2c_algo_bit_data bit;
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_i2c_bus_rec rec;
|
2014-03-21 22:34:07 +08:00
|
|
|
struct drm_dp_aux aux;
|
2014-04-07 22:33:46 +08:00
|
|
|
bool has_aux;
|
2014-05-08 22:58:04 +08:00
|
|
|
struct mutex mutex;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* mostly for macs, but really any system without connector tables */
|
|
|
|
enum radeon_connector_table {
|
2010-09-08 02:41:30 +08:00
|
|
|
CT_NONE = 0,
|
2009-06-05 20:42:42 +08:00
|
|
|
CT_GENERIC,
|
|
|
|
CT_IBOOK,
|
|
|
|
CT_POWERBOOK_EXTERNAL,
|
|
|
|
CT_POWERBOOK_INTERNAL,
|
|
|
|
CT_POWERBOOK_VGA,
|
|
|
|
CT_MINI_EXTERNAL,
|
|
|
|
CT_MINI_INTERNAL,
|
|
|
|
CT_IMAC_G5_ISIGHT,
|
|
|
|
CT_EMAC,
|
2010-06-11 13:09:05 +08:00
|
|
|
CT_RN50_POWER,
|
2010-09-08 02:41:30 +08:00
|
|
|
CT_MAC_X800,
|
2011-02-08 02:15:28 +08:00
|
|
|
CT_MAC_G5_9600,
|
2012-12-21 05:35:47 +08:00
|
|
|
CT_SAM440EP,
|
|
|
|
CT_MAC_G4_SILVER
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
2009-11-11 10:25:07 +08:00
|
|
|
enum radeon_dvo_chip {
|
|
|
|
DVO_SIL164,
|
|
|
|
DVO_SIL1178,
|
|
|
|
};
|
|
|
|
|
2010-03-30 13:34:14 +08:00
|
|
|
struct radeon_fbdev;
|
2010-03-30 13:34:13 +08:00
|
|
|
|
2012-05-14 22:52:29 +08:00
|
|
|
struct radeon_afmt {
|
|
|
|
bool enabled;
|
|
|
|
int offset;
|
|
|
|
bool last_buffer_filled_status;
|
|
|
|
int id;
|
|
|
|
};
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_mode_info {
|
|
|
|
struct atom_context *atom_context;
|
2009-10-28 03:08:01 +08:00
|
|
|
struct card_info *atom_card_info;
|
2009-06-05 20:42:42 +08:00
|
|
|
enum radeon_connector_table connector_table;
|
|
|
|
bool mode_config_initialized;
|
2014-06-30 03:02:20 +08:00
|
|
|
struct radeon_crtc *crtcs[RADEON_MAX_CRTCS];
|
|
|
|
struct radeon_afmt *afmt[RADEON_MAX_AFMT_BLOCKS];
|
2009-09-09 15:40:54 +08:00
|
|
|
/* DVI-I properties */
|
|
|
|
struct drm_property *coherent_mode_property;
|
|
|
|
/* DAC enable load detect */
|
|
|
|
struct drm_property *load_detect_property;
|
2010-08-04 07:59:20 +08:00
|
|
|
/* TV standard */
|
2009-09-09 15:40:54 +08:00
|
|
|
struct drm_property *tv_std_property;
|
|
|
|
/* legacy TMDS PLL detect */
|
|
|
|
struct drm_property *tmds_pll_property;
|
2010-08-04 07:59:20 +08:00
|
|
|
/* underscan */
|
|
|
|
struct drm_property *underscan_property;
|
2010-09-22 03:30:59 +08:00
|
|
|
struct drm_property *underscan_hborder_property;
|
|
|
|
struct drm_property *underscan_vborder_property;
|
2013-09-04 02:58:44 +08:00
|
|
|
/* audio */
|
|
|
|
struct drm_property *audio_property;
|
2013-09-25 05:26:26 +08:00
|
|
|
/* FMT dithering */
|
|
|
|
struct drm_property *dither_property;
|
2015-02-23 23:11:49 +08:00
|
|
|
/* Output CSC */
|
|
|
|
struct drm_property *output_csc_property;
|
2010-02-05 17:21:19 +08:00
|
|
|
/* hardcoded DFP edid from BIOS */
|
|
|
|
struct edid *bios_hardcoded_edid;
|
2011-03-23 16:10:10 +08:00
|
|
|
int bios_hardcoded_edid_size;
|
2010-03-30 13:34:13 +08:00
|
|
|
|
|
|
|
/* pointer to fbdev info structure */
|
2010-03-30 13:34:14 +08:00
|
|
|
struct radeon_fbdev *rfbdev;
|
2012-07-26 21:50:57 +08:00
|
|
|
/* firmware flags */
|
|
|
|
u16 firmware_flags;
|
2012-09-14 21:45:50 +08:00
|
|
|
/* pointer to backlight encoder */
|
|
|
|
struct radeon_encoder *bl_encoder;
|
2015-02-24 07:24:03 +08:00
|
|
|
|
|
|
|
/* bitmask for active encoder frontends */
|
|
|
|
uint32_t active_encoders;
|
2009-07-14 03:04:08 +08:00
|
|
|
};
|
|
|
|
|
2012-07-26 23:05:22 +08:00
|
|
|
#define RADEON_MAX_BL_LEVEL 0xFF
|
|
|
|
|
2012-09-14 21:45:50 +08:00
|
|
|
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
|
|
|
|
|
2012-07-26 23:05:22 +08:00
|
|
|
struct radeon_backlight_privdata {
|
|
|
|
struct radeon_encoder *encoder;
|
|
|
|
uint8_t negative;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-08-13 14:32:14 +08:00
|
|
|
#define MAX_H_CODE_TIMING_LEN 32
|
|
|
|
#define MAX_V_CODE_TIMING_LEN 32
|
|
|
|
|
|
|
|
/* need to store these as reading
|
|
|
|
back code tables is excessive */
|
|
|
|
struct radeon_tv_regs {
|
|
|
|
uint32_t tv_uv_adr;
|
|
|
|
uint32_t timing_cntl;
|
|
|
|
uint32_t hrestart;
|
|
|
|
uint32_t vrestart;
|
|
|
|
uint32_t frestart;
|
|
|
|
uint16_t h_code_timing[MAX_H_CODE_TIMING_LEN];
|
|
|
|
uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN];
|
|
|
|
};
|
|
|
|
|
2012-09-13 22:56:16 +08:00
|
|
|
struct radeon_atom_ss {
|
|
|
|
uint16_t percentage;
|
2014-01-16 02:41:31 +08:00
|
|
|
uint16_t percentage_divider;
|
2012-09-13 22:56:16 +08:00
|
|
|
uint8_t type;
|
|
|
|
uint16_t step;
|
|
|
|
uint8_t delay;
|
|
|
|
uint8_t range;
|
|
|
|
uint8_t refdiv;
|
|
|
|
/* asic_ss */
|
|
|
|
uint16_t rate;
|
|
|
|
uint16_t amount;
|
|
|
|
};
|
|
|
|
|
2014-06-30 17:12:34 +08:00
|
|
|
enum radeon_flip_status {
|
|
|
|
RADEON_FLIP_NONE,
|
|
|
|
RADEON_FLIP_PENDING,
|
|
|
|
RADEON_FLIP_SUBMITTED
|
|
|
|
};
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_crtc {
|
|
|
|
struct drm_crtc base;
|
|
|
|
int crtc_id;
|
|
|
|
u16 lut_r[256], lut_g[256], lut_b[256];
|
|
|
|
bool enabled;
|
|
|
|
bool can_tile;
|
2016-10-27 13:54:31 +08:00
|
|
|
bool cursor_out_of_bounds;
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t crtc_offset;
|
|
|
|
struct drm_gem_object *cursor_bo;
|
|
|
|
uint64_t cursor_addr;
|
2014-11-18 17:00:08 +08:00
|
|
|
int cursor_x;
|
|
|
|
int cursor_y;
|
|
|
|
int cursor_hot_x;
|
|
|
|
int cursor_hot_y;
|
2009-06-05 20:42:42 +08:00
|
|
|
int cursor_width;
|
|
|
|
int cursor_height;
|
2013-01-24 23:06:33 +08:00
|
|
|
int max_cursor_width;
|
|
|
|
int max_cursor_height;
|
2009-07-09 13:04:19 +08:00
|
|
|
uint32_t legacy_display_base_addr;
|
2009-07-14 03:04:08 +08:00
|
|
|
enum radeon_rmx_type rmx_type;
|
2010-08-04 07:59:20 +08:00
|
|
|
u8 h_border;
|
|
|
|
u8 v_border;
|
2009-07-14 03:04:08 +08:00
|
|
|
fixed20_12 vsc;
|
|
|
|
fixed20_12 hsc;
|
2009-10-10 03:14:30 +08:00
|
|
|
struct drm_display_mode native_mode;
|
2010-01-13 06:54:34 +08:00
|
|
|
int pll_id;
|
2010-11-21 23:59:01 +08:00
|
|
|
/* page flipping */
|
2014-06-04 06:13:21 +08:00
|
|
|
struct workqueue_struct *flip_queue;
|
|
|
|
struct radeon_flip_work *flip_work;
|
2014-06-30 17:12:34 +08:00
|
|
|
enum radeon_flip_status flip_status;
|
2012-09-13 22:56:16 +08:00
|
|
|
/* pll sharing */
|
|
|
|
struct radeon_atom_ss ss;
|
|
|
|
bool ss_enabled;
|
|
|
|
u32 adjusted_clock;
|
|
|
|
int bpc;
|
|
|
|
u32 pll_reference_div;
|
|
|
|
u32 pll_post_div;
|
|
|
|
u32 pll_flags;
|
2012-09-13 23:52:08 +08:00
|
|
|
struct drm_encoder *encoder;
|
drm/radeon: work around KMS modeset limitations in PLL allocation (v2)
Since the current KMS API sets the mode independantly on
each crtc, we may end up with resource conflicts. The PLL
allocation is one of those cases. In the following example
we have 3 crtcs in use driving 2 DVI connectors and 1 DP
connector. On the initial kernel modeset for fbdev, the
display topology ends up as follows:
crtc0 -> DP-0
crtc1 -> DVI-0
crtc2 -> DVI-1
Because this is the first modeset, all of the PLLs are
available as none have been assigned. So we end up with
the following:
crtc0 uses DCPLL
crtc1 uses PPLL2
crtc2 uses PPLL1
When X starts, it assigns a different topology:
crtc0 -> DVI-0
crtc1 -> DP-0
crtc2 -> DVI-1
However, since the KMS API is per crtc, we set the mode on each
crtc independantly. When it comes time to set the mode on crtc0,
the topology for crtc1 and crtc2 are still intact. crtc1 and
crtc2 are already assigned PPLL2 and PPLL1 so when it comes time
to set the mode on crtc0, crtc1 and crtc2 have not been torn down
yet, so there appears to be no PLLs available. In reality, we
are reconfiguring the entire display topology, however, since
each crtc is handled independantly, we don't know that in the
driver at each crtc mode set time.
This patch checks to see if the same connector is being driven by
another crtc, and if so, uses the PLL already associated with it.
v2: store connector in the radeon crtc struct, simplify checking.
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2012-09-18 05:34:45 +08:00
|
|
|
struct drm_connector *connector;
|
2013-03-21 22:38:49 +08:00
|
|
|
/* for dpm */
|
|
|
|
u32 line_time;
|
|
|
|
u32 wm_low;
|
|
|
|
u32 wm_high;
|
drm/radeon: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v2)
commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many
vblanks were missed" introduced in Linux 4.4-rc1 makes the drm core
more fragile to drivers which don't update hw vblank counters and
vblank timestamps in sync with firing of the vblank irq and
essentially at leading edge of vblank.
This exposed a problem with radeon-kms/amdgpu-kms which do not
satisfy above requirements:
The vblank irq fires a few scanlines before start of vblank, but
programmed pageflips complete at start of vblank and
vblank timestamps update at start of vblank, whereas the
hw vblank counter increments only later, at start of vsync.
This leads to problems like off by one errors for vblank counter
updates, vblank counters apparently going backwards or vblank
timestamps apparently having time going backwards. The net result
is stuttering of graphics in games, or little hangs, as well as
total failure of timing sensitive applications.
See bug #93147 for an example of the regression on Linux 4.4-rc:
https://bugs.freedesktop.org/show_bug.cgi?id=93147
This patch tries to align all above events better from the
viewpoint of the drm core / of external callers to fix the problem:
1. The apparent start of vblank is shifted a few scanlines earlier,
so the vblank irq now always happens after start of this extended
vblank interval and thereby drm_update_vblank_count() always samples
the updated vblank count and timestamp of the new vblank interval.
To achieve this, the reporting of scanout positions by
radeon_get_crtc_scanoutpos() now operates as if the vblank starts
radeon_crtc->lb_vblank_lead_lines before the real start of the hw
vblank interval. This means that the vblank timestamps which are based
on these scanout positions will now update at this earlier start of
vblank.
2. The driver->get_vblank_counter() function will bump the returned
vblank count as read from the hw by +1 if the query happens after
the shifted earlier start of the vblank, but before the real hw increment
at start of vsync, so the counter appears to increment at start of vblank
in sync with the timestamp update.
3. Calls from vblank irq-context and regular non-irq calls are now
treated identical, always simulating the shifted vblank start, to
avoid inconsistent results for queries happening from vblank irq vs.
happening from drm_vblank_enable() or vblank_disable_fn().
4. The radeon_flip_work_func will delay mmio programming a pageflip until
the start of the real vblank iff it happens to execute inside the shifted
earlier start of the vblank, so pageflips now also appear to execute at
start of the shifted vblank, in sync with vblank counter and timestamp
updates. This to avoid some races between updates of vblank count and
timestamps that are used for swap scheduling and pageflip execution which
could cause pageflips to execute before the scheduled target vblank.
The lb_vblank_lead_lines "fudge" value is calculated as the size of
the display controllers line buffer in scanlines for the given video
mode: Vblank irq's are triggered by the line buffer logic when the line
buffer refill for a video frame ends, ie. when the line buffer source read
position enters the hw vblank. This means that a vblank irq could fire at
most as many scanlines before the current reported scanout position of the
crtc timing generator as the number of scanlines the line buffer can
maximally hold for a given video mode.
This patch has been successfully tested on a RV730 card with DCE-3 display
engine and on a evergreen card with DCE-4 display engine, in single-display
and dual-display configuration, with different video modes.
A similar patch is needed for amdgpu-kms to fix the same problem.
Limitations:
- Line buffer sizes in pixels are hard-coded on < DCE-4 to a value
i just guessed to be high enough to work ok, lacking info on the true
sizes atm.
Fixes: fdo#93147
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Michel Dänzer <michel.daenzer@amd.com>
Cc: Harry Wentland <Harry.Wentland@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
(v1) Tested-by: Dave Witbrodt <dawitbro@sbcglobal.net>
(v2) Refine radeon_flip_work_func() for better efficiency:
In radeon_flip_work_func, replace the busy waiting udelay(5)
with event lock held by a more performance and energy efficient
usleep_range() until at least predicted true start of hw vblank,
with some slack for scheduler happiness. Release the event lock
during waits to not delay other outputs in doing their stuff, as
the waiting can last up to 200 usecs in some cases.
Retested on DCE-3 and DCE-4 to verify it still works nicely.
(v2) Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2015-11-26 03:14:31 +08:00
|
|
|
u32 lb_vblank_lead_lines;
|
2013-07-08 23:26:42 +08:00
|
|
|
struct drm_display_mode hw_mode;
|
2015-02-23 23:59:36 +08:00
|
|
|
enum radeon_output_csc output_csc;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_encoder_primary_dac {
|
|
|
|
/* legacy primary dac */
|
|
|
|
uint32_t ps2_pdac_adj;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_encoder_lvds {
|
|
|
|
/* legacy lvds */
|
|
|
|
uint16_t panel_vcc_delay;
|
|
|
|
uint8_t panel_pwr_delay;
|
|
|
|
uint8_t panel_digon_delay;
|
|
|
|
uint8_t panel_blon_delay;
|
|
|
|
uint16_t panel_ref_divider;
|
|
|
|
uint8_t panel_post_divider;
|
|
|
|
uint16_t panel_fb_divider;
|
|
|
|
bool use_bios_dividers;
|
|
|
|
uint32_t lvds_gen_cntl;
|
|
|
|
/* panel mode */
|
2009-10-10 03:14:30 +08:00
|
|
|
struct drm_display_mode native_mode;
|
2011-03-23 07:30:23 +08:00
|
|
|
struct backlight_device *bl_dev;
|
|
|
|
int dpms_mode;
|
|
|
|
uint8_t backlight_level;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_encoder_tv_dac {
|
|
|
|
/* legacy tv dac */
|
|
|
|
uint32_t ps2_tvdac_adj;
|
|
|
|
uint32_t ntsc_tvdac_adj;
|
|
|
|
uint32_t pal_tvdac_adj;
|
|
|
|
|
2009-08-13 14:32:14 +08:00
|
|
|
int h_pos;
|
|
|
|
int v_pos;
|
|
|
|
int h_size;
|
|
|
|
int supported_tv_stds;
|
|
|
|
bool tv_on;
|
2009-06-05 20:42:42 +08:00
|
|
|
enum radeon_tv_std tv_std;
|
2009-08-13 14:32:14 +08:00
|
|
|
struct radeon_tv_regs tv;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_encoder_int_tmds {
|
|
|
|
/* legacy int tmds */
|
|
|
|
struct radeon_tmds_pll tmds_pll[4];
|
|
|
|
};
|
|
|
|
|
2009-11-11 10:25:07 +08:00
|
|
|
struct radeon_encoder_ext_tmds {
|
|
|
|
/* tmds over dvo */
|
|
|
|
struct radeon_i2c_chan *i2c_bus;
|
|
|
|
uint8_t slave_addr;
|
|
|
|
enum radeon_dvo_chip dvo_chip;
|
|
|
|
};
|
|
|
|
|
2009-10-16 23:15:25 +08:00
|
|
|
/* spread spectrum */
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_encoder_atom_dig {
|
2010-08-13 06:58:47 +08:00
|
|
|
bool linkb;
|
2009-06-05 20:42:42 +08:00
|
|
|
/* atom dig */
|
|
|
|
bool coherent_mode;
|
2010-10-05 05:13:01 +08:00
|
|
|
int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */
|
|
|
|
/* atom lvds/edp */
|
|
|
|
uint32_t lcd_misc;
|
2009-06-05 20:42:42 +08:00
|
|
|
uint16_t panel_pwr_delay;
|
2010-10-05 05:13:01 +08:00
|
|
|
uint32_t lcd_ss_id;
|
2009-06-05 20:42:42 +08:00
|
|
|
/* panel mode */
|
2009-10-10 03:14:30 +08:00
|
|
|
struct drm_display_mode native_mode;
|
2011-03-23 07:30:23 +08:00
|
|
|
struct backlight_device *bl_dev;
|
|
|
|
int dpms_mode;
|
|
|
|
uint8_t backlight_level;
|
2012-01-21 04:01:29 +08:00
|
|
|
int panel_mode;
|
2012-05-14 22:52:29 +08:00
|
|
|
struct radeon_afmt *afmt;
|
2015-07-23 22:01:09 +08:00
|
|
|
struct r600_audio_pin *pin;
|
2015-02-24 07:24:04 +08:00
|
|
|
int active_mst_links;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
2009-08-13 14:32:14 +08:00
|
|
|
struct radeon_encoder_atom_dac {
|
|
|
|
enum radeon_tv_std tv_std;
|
|
|
|
};
|
|
|
|
|
2015-02-24 07:24:04 +08:00
|
|
|
struct radeon_encoder_mst {
|
|
|
|
int crtc;
|
|
|
|
struct radeon_encoder *primary;
|
|
|
|
struct radeon_connector *connector;
|
|
|
|
struct drm_dp_mst_port *port;
|
|
|
|
int pbn;
|
|
|
|
int fe;
|
|
|
|
bool fe_from_be;
|
|
|
|
bool enc_active;
|
|
|
|
};
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_encoder {
|
|
|
|
struct drm_encoder base;
|
2010-08-13 06:58:47 +08:00
|
|
|
uint32_t encoder_enum;
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t encoder_id;
|
|
|
|
uint32_t devices;
|
2009-08-13 14:32:14 +08:00
|
|
|
uint32_t active_device;
|
2009-06-05 20:42:42 +08:00
|
|
|
uint32_t flags;
|
|
|
|
uint32_t pixel_clock;
|
|
|
|
enum radeon_rmx_type rmx_type;
|
2010-08-04 07:59:20 +08:00
|
|
|
enum radeon_underscan_type underscan_type;
|
2010-09-22 03:30:59 +08:00
|
|
|
uint32_t underscan_hborder;
|
|
|
|
uint32_t underscan_vborder;
|
2009-10-10 03:14:30 +08:00
|
|
|
struct drm_display_mode native_mode;
|
2009-06-05 20:42:42 +08:00
|
|
|
void *enc_priv;
|
2010-04-06 04:14:55 +08:00
|
|
|
int audio_polling_active;
|
2010-11-17 01:09:42 +08:00
|
|
|
bool is_ext_encoder;
|
2011-01-07 10:19:21 +08:00
|
|
|
u16 caps;
|
2014-12-02 02:49:39 +08:00
|
|
|
struct radeon_audio_funcs *audio;
|
2015-02-23 23:59:36 +08:00
|
|
|
enum radeon_output_csc output_csc;
|
2015-02-24 07:24:04 +08:00
|
|
|
bool can_mst;
|
|
|
|
uint32_t offset;
|
|
|
|
bool is_mst_encoder;
|
|
|
|
/* front end for this mst encoder */
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_connector_atom_dig {
|
|
|
|
uint32_t igp_lane_info;
|
2009-11-24 07:02:35 +08:00
|
|
|
/* displayport */
|
2012-10-18 21:32:40 +08:00
|
|
|
u8 dpcd[DP_RECEIVER_CAP_SIZE];
|
2009-11-24 07:02:35 +08:00
|
|
|
u8 dp_sink_type;
|
2009-11-25 02:32:59 +08:00
|
|
|
int dp_clock;
|
|
|
|
int dp_lane_count;
|
2010-11-17 15:54:42 +08:00
|
|
|
bool edp_on;
|
2015-02-24 07:24:04 +08:00
|
|
|
bool is_mst;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
2009-12-05 03:45:27 +08:00
|
|
|
struct radeon_gpio_rec {
|
|
|
|
bool valid;
|
|
|
|
u8 id;
|
|
|
|
u32 reg;
|
|
|
|
u32 mask;
|
2014-11-08 00:34:57 +08:00
|
|
|
u32 shift;
|
2009-12-05 03:45:27 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_hpd {
|
|
|
|
enum radeon_hpd_id hpd;
|
|
|
|
u8 plugged_state;
|
|
|
|
struct radeon_gpio_rec gpio;
|
|
|
|
};
|
|
|
|
|
2010-08-06 09:21:18 +08:00
|
|
|
struct radeon_router {
|
|
|
|
u32 router_id;
|
|
|
|
struct radeon_i2c_bus_rec i2c_info;
|
|
|
|
u8 i2c_addr;
|
2010-11-09 00:08:29 +08:00
|
|
|
/* i2c mux */
|
|
|
|
bool ddc_valid;
|
|
|
|
u8 ddc_mux_type;
|
|
|
|
u8 ddc_mux_control_pin;
|
|
|
|
u8 ddc_mux_state;
|
|
|
|
/* clock/data mux */
|
|
|
|
bool cd_valid;
|
|
|
|
u8 cd_mux_type;
|
|
|
|
u8 cd_mux_control_pin;
|
|
|
|
u8 cd_mux_state;
|
2010-08-06 09:21:18 +08:00
|
|
|
};
|
|
|
|
|
2013-09-04 02:58:44 +08:00
|
|
|
enum radeon_connector_audio {
|
|
|
|
RADEON_AUDIO_DISABLE = 0,
|
|
|
|
RADEON_AUDIO_ENABLE = 1,
|
|
|
|
RADEON_AUDIO_AUTO = 2
|
|
|
|
};
|
|
|
|
|
2013-09-25 05:26:26 +08:00
|
|
|
enum radeon_connector_dither {
|
|
|
|
RADEON_FMT_DITHER_DISABLE = 0,
|
|
|
|
RADEON_FMT_DITHER_ENABLE = 1,
|
|
|
|
};
|
|
|
|
|
2015-02-24 07:24:04 +08:00
|
|
|
struct stream_attribs {
|
|
|
|
uint16_t fe;
|
|
|
|
uint16_t slots;
|
|
|
|
};
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
struct radeon_connector {
|
|
|
|
struct drm_connector base;
|
|
|
|
uint32_t connector_id;
|
|
|
|
uint32_t devices;
|
|
|
|
struct radeon_i2c_chan *ddc_bus;
|
2010-08-04 07:59:20 +08:00
|
|
|
/* some systems have an hdmi and vga port with a shared ddc line */
|
2009-10-16 04:16:35 +08:00
|
|
|
bool shared_ddc;
|
2009-08-13 14:32:14 +08:00
|
|
|
bool use_digital;
|
|
|
|
/* we need to mind the EDID between detect
|
|
|
|
and get modes due to analog/digital/tvencoder */
|
|
|
|
struct edid *edid;
|
2009-06-05 20:42:42 +08:00
|
|
|
void *con_priv;
|
2009-09-09 15:40:54 +08:00
|
|
|
bool dac_load_detect;
|
2011-10-08 02:23:48 +08:00
|
|
|
bool detected_by_load; /* if the connection status was determined by load */
|
2015-12-04 07:26:07 +08:00
|
|
|
bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */
|
2009-11-06 02:16:01 +08:00
|
|
|
uint16_t connector_object_id;
|
2009-12-05 03:45:27 +08:00
|
|
|
struct radeon_hpd hpd;
|
2010-08-06 09:21:18 +08:00
|
|
|
struct radeon_router router;
|
|
|
|
struct radeon_i2c_chan *router_bus;
|
2013-09-04 02:58:44 +08:00
|
|
|
enum radeon_connector_audio audio;
|
2013-09-25 05:26:26 +08:00
|
|
|
enum radeon_connector_dither dither;
|
2014-06-05 21:58:24 +08:00
|
|
|
int pixelclock_for_modeset;
|
2015-02-24 07:24:04 +08:00
|
|
|
bool is_mst_connector;
|
|
|
|
struct radeon_connector *mst_port;
|
|
|
|
struct drm_dp_mst_port *port;
|
|
|
|
struct drm_dp_mst_topology_mgr mst_mgr;
|
|
|
|
|
|
|
|
struct radeon_encoder *mst_encoder;
|
|
|
|
struct stream_attribs cur_stream_attribs[6];
|
|
|
|
int enabled_attribs;
|
2009-06-05 20:42:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct radeon_framebuffer {
|
|
|
|
struct drm_framebuffer base;
|
|
|
|
struct drm_gem_object *obj;
|
|
|
|
};
|
|
|
|
|
2011-10-27 03:59:50 +08:00
|
|
|
#define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
|
|
|
|
((em) == ATOM_ENCODER_MODE_DP_MST))
|
2010-10-06 07:57:36 +08:00
|
|
|
|
2013-04-08 18:41:31 +08:00
|
|
|
struct atom_clock_dividers {
|
|
|
|
u32 post_div;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
#ifdef __BIG_ENDIAN
|
|
|
|
u32 reserved : 6;
|
|
|
|
u32 whole_fb_div : 12;
|
|
|
|
u32 frac_fb_div : 14;
|
|
|
|
#else
|
|
|
|
u32 frac_fb_div : 14;
|
|
|
|
u32 whole_fb_div : 12;
|
|
|
|
u32 reserved : 6;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
u32 fb_div;
|
|
|
|
};
|
|
|
|
u32 ref_div;
|
|
|
|
bool enable_post_div;
|
|
|
|
bool enable_dithen;
|
|
|
|
u32 vco_mode;
|
|
|
|
u32 real_clock;
|
2013-02-20 03:35:34 +08:00
|
|
|
/* added for CI */
|
|
|
|
u32 post_divider;
|
|
|
|
u32 flags;
|
2013-04-08 18:41:31 +08:00
|
|
|
};
|
|
|
|
|
2013-02-14 05:38:25 +08:00
|
|
|
struct atom_mpll_param {
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
#ifdef __BIG_ENDIAN
|
|
|
|
u32 reserved : 8;
|
|
|
|
u32 clkfrac : 12;
|
|
|
|
u32 clkf : 12;
|
|
|
|
#else
|
|
|
|
u32 clkf : 12;
|
|
|
|
u32 clkfrac : 12;
|
|
|
|
u32 reserved : 8;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
u32 fb_div;
|
|
|
|
};
|
|
|
|
u32 post_div;
|
|
|
|
u32 bwcntl;
|
|
|
|
u32 dll_speed;
|
|
|
|
u32 vco_mode;
|
|
|
|
u32 yclk_sel;
|
|
|
|
u32 qdr;
|
|
|
|
u32 half_rate;
|
|
|
|
};
|
|
|
|
|
2013-06-24 22:50:34 +08:00
|
|
|
#define MEM_TYPE_GDDR5 0x50
|
|
|
|
#define MEM_TYPE_GDDR4 0x40
|
|
|
|
#define MEM_TYPE_GDDR3 0x30
|
|
|
|
#define MEM_TYPE_DDR2 0x20
|
|
|
|
#define MEM_TYPE_GDDR1 0x10
|
|
|
|
#define MEM_TYPE_DDR3 0xb0
|
|
|
|
#define MEM_TYPE_MASK 0xf0
|
|
|
|
|
|
|
|
struct atom_memory_info {
|
|
|
|
u8 mem_vendor;
|
|
|
|
u8 mem_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_AC_TIMING_ENTRIES 16
|
|
|
|
|
|
|
|
struct atom_memory_clock_range_table
|
|
|
|
{
|
|
|
|
u8 num_entries;
|
|
|
|
u8 rsv[3];
|
|
|
|
u32 mclk[MAX_AC_TIMING_ENTRIES];
|
|
|
|
};
|
|
|
|
|
|
|
|
#define VBIOS_MC_REGISTER_ARRAY_SIZE 32
|
|
|
|
#define VBIOS_MAX_AC_TIMING_ENTRIES 20
|
|
|
|
|
|
|
|
struct atom_mc_reg_entry {
|
|
|
|
u32 mclk_max;
|
|
|
|
u32 mc_data[VBIOS_MC_REGISTER_ARRAY_SIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct atom_mc_register_address {
|
|
|
|
u16 s1;
|
|
|
|
u8 pre_reg_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct atom_mc_reg_table {
|
|
|
|
u8 last;
|
|
|
|
u8 num_entries;
|
|
|
|
struct atom_mc_reg_entry mc_reg_table_entry[VBIOS_MAX_AC_TIMING_ENTRIES];
|
|
|
|
struct atom_mc_register_address mc_reg_address[VBIOS_MC_REGISTER_ARRAY_SIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_VOLTAGE_ENTRIES 32
|
|
|
|
|
|
|
|
struct atom_voltage_table_entry
|
|
|
|
{
|
|
|
|
u16 value;
|
|
|
|
u32 smio_low;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct atom_voltage_table
|
|
|
|
{
|
|
|
|
u32 count;
|
|
|
|
u32 mask_low;
|
2013-02-14 06:29:54 +08:00
|
|
|
u32 phase_delay;
|
2013-06-24 22:50:34 +08:00
|
|
|
struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
|
|
|
|
};
|
|
|
|
|
drm/radeon: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v2)
commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many
vblanks were missed" introduced in Linux 4.4-rc1 makes the drm core
more fragile to drivers which don't update hw vblank counters and
vblank timestamps in sync with firing of the vblank irq and
essentially at leading edge of vblank.
This exposed a problem with radeon-kms/amdgpu-kms which do not
satisfy above requirements:
The vblank irq fires a few scanlines before start of vblank, but
programmed pageflips complete at start of vblank and
vblank timestamps update at start of vblank, whereas the
hw vblank counter increments only later, at start of vsync.
This leads to problems like off by one errors for vblank counter
updates, vblank counters apparently going backwards or vblank
timestamps apparently having time going backwards. The net result
is stuttering of graphics in games, or little hangs, as well as
total failure of timing sensitive applications.
See bug #93147 for an example of the regression on Linux 4.4-rc:
https://bugs.freedesktop.org/show_bug.cgi?id=93147
This patch tries to align all above events better from the
viewpoint of the drm core / of external callers to fix the problem:
1. The apparent start of vblank is shifted a few scanlines earlier,
so the vblank irq now always happens after start of this extended
vblank interval and thereby drm_update_vblank_count() always samples
the updated vblank count and timestamp of the new vblank interval.
To achieve this, the reporting of scanout positions by
radeon_get_crtc_scanoutpos() now operates as if the vblank starts
radeon_crtc->lb_vblank_lead_lines before the real start of the hw
vblank interval. This means that the vblank timestamps which are based
on these scanout positions will now update at this earlier start of
vblank.
2. The driver->get_vblank_counter() function will bump the returned
vblank count as read from the hw by +1 if the query happens after
the shifted earlier start of the vblank, but before the real hw increment
at start of vsync, so the counter appears to increment at start of vblank
in sync with the timestamp update.
3. Calls from vblank irq-context and regular non-irq calls are now
treated identical, always simulating the shifted vblank start, to
avoid inconsistent results for queries happening from vblank irq vs.
happening from drm_vblank_enable() or vblank_disable_fn().
4. The radeon_flip_work_func will delay mmio programming a pageflip until
the start of the real vblank iff it happens to execute inside the shifted
earlier start of the vblank, so pageflips now also appear to execute at
start of the shifted vblank, in sync with vblank counter and timestamp
updates. This to avoid some races between updates of vblank count and
timestamps that are used for swap scheduling and pageflip execution which
could cause pageflips to execute before the scheduled target vblank.
The lb_vblank_lead_lines "fudge" value is calculated as the size of
the display controllers line buffer in scanlines for the given video
mode: Vblank irq's are triggered by the line buffer logic when the line
buffer refill for a video frame ends, ie. when the line buffer source read
position enters the hw vblank. This means that a vblank irq could fire at
most as many scanlines before the current reported scanout position of the
crtc timing generator as the number of scanlines the line buffer can
maximally hold for a given video mode.
This patch has been successfully tested on a RV730 card with DCE-3 display
engine and on a evergreen card with DCE-4 display engine, in single-display
and dual-display configuration, with different video modes.
A similar patch is needed for amdgpu-kms to fix the same problem.
Limitations:
- Line buffer sizes in pixels are hard-coded on < DCE-4 to a value
i just guessed to be high enough to work ok, lacking info on the true
sizes atm.
Fixes: fdo#93147
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Michel Dänzer <michel.daenzer@amd.com>
Cc: Harry Wentland <Harry.Wentland@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
(v1) Tested-by: Dave Witbrodt <dawitbro@sbcglobal.net>
(v2) Refine radeon_flip_work_func() for better efficiency:
In radeon_flip_work_func, replace the busy waiting udelay(5)
with event lock held by a more performance and energy efficient
usleep_range() until at least predicted true start of hw vblank,
with some slack for scheduler happiness. Release the event lock
during waits to not delay other outputs in doing their stuff, as
the waiting can last up to 200 usecs in some cases.
Retested on DCE-3 and DCE-4 to verify it still works nicely.
(v2) Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2015-11-26 03:14:31 +08:00
|
|
|
/* Driver internal use only flags of radeon_get_crtc_scanoutpos() */
|
drm/vblank: drop the mode argument from drm_calc_vbltimestamp_from_scanoutpos
If we restrict this helper to only kms drivers (which is the case) we
can look up the correct mode easily ourselves. But it's a bit tricky:
- All legacy drivers look at crtc->hwmode. But that is updated already
at the beginning of the modeset helper, which means when we disable
a pipe. Hence the final timestamps might be a bit off. But since
this is an existing bug I'm not going to change it, but just try to
be bug-for-bug compatible with the current code. This only applies
to radeon&amdgpu.
- i915 tries to get it perfect by updating crtc->hwmode when the pipe
is off (i.e. vblank->enabled = false).
- All other atomic drivers look at crtc->state->adjusted_mode. Those
that look at state->requested_mode simply don't adjust their mode,
so it's the same. That has two problems: Accessing crtc->state from
interrupt handling code is unsafe, and it's updated before we shut
down the pipe. For nonblocking modesets it's even worse.
For atomic drivers try to implement what i915 does. To do that we add
a new hwmode field to the vblank structure, and update it from
drm_calc_timestamping_constants(). For atomic drivers that's called
from the right spot by the helper library already, so all fine. But
for safety let's enforce that.
For legacy driver this function is only called at the end (oh the
fun), which is broken, so again let's not bother and just stay
bug-for-bug compatible.
The benefit is that we can use drm_calc_vbltimestamp_from_scanoutpos
directly to implement ->get_vblank_timestamp in every driver, deleting
a lot of code.
v2: Completely new approach, trying to mimick the i915 solution.
v3: Fixup kerneldoc.
v4: Drop the WARN_ON to check that the vblank is off, atomic helpers
currently unconditionally call this. Recomputing the same stuff should
be harmless.
v5: Fix typos and move misplaced hunks to the right patches (Neil).
v6: Undo hunk movement (kbuild).
Cc: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Cc: Eric Anholt <eric@anholt.net>
Cc: Rob Clark <robdclark@gmail.com>
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170509140329.24114-4-daniel.vetter@ffwll.ch
2017-05-09 22:03:28 +08:00
|
|
|
#define DRM_SCANOUTPOS_VALID (1 << 0)
|
|
|
|
#define DRM_SCANOUTPOS_IN_VBLANK (1 << 1)
|
|
|
|
#define DRM_SCANOUTPOS_ACCURATE (1 << 2)
|
drm/radeon: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v2)
commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many
vblanks were missed" introduced in Linux 4.4-rc1 makes the drm core
more fragile to drivers which don't update hw vblank counters and
vblank timestamps in sync with firing of the vblank irq and
essentially at leading edge of vblank.
This exposed a problem with radeon-kms/amdgpu-kms which do not
satisfy above requirements:
The vblank irq fires a few scanlines before start of vblank, but
programmed pageflips complete at start of vblank and
vblank timestamps update at start of vblank, whereas the
hw vblank counter increments only later, at start of vsync.
This leads to problems like off by one errors for vblank counter
updates, vblank counters apparently going backwards or vblank
timestamps apparently having time going backwards. The net result
is stuttering of graphics in games, or little hangs, as well as
total failure of timing sensitive applications.
See bug #93147 for an example of the regression on Linux 4.4-rc:
https://bugs.freedesktop.org/show_bug.cgi?id=93147
This patch tries to align all above events better from the
viewpoint of the drm core / of external callers to fix the problem:
1. The apparent start of vblank is shifted a few scanlines earlier,
so the vblank irq now always happens after start of this extended
vblank interval and thereby drm_update_vblank_count() always samples
the updated vblank count and timestamp of the new vblank interval.
To achieve this, the reporting of scanout positions by
radeon_get_crtc_scanoutpos() now operates as if the vblank starts
radeon_crtc->lb_vblank_lead_lines before the real start of the hw
vblank interval. This means that the vblank timestamps which are based
on these scanout positions will now update at this earlier start of
vblank.
2. The driver->get_vblank_counter() function will bump the returned
vblank count as read from the hw by +1 if the query happens after
the shifted earlier start of the vblank, but before the real hw increment
at start of vsync, so the counter appears to increment at start of vblank
in sync with the timestamp update.
3. Calls from vblank irq-context and regular non-irq calls are now
treated identical, always simulating the shifted vblank start, to
avoid inconsistent results for queries happening from vblank irq vs.
happening from drm_vblank_enable() or vblank_disable_fn().
4. The radeon_flip_work_func will delay mmio programming a pageflip until
the start of the real vblank iff it happens to execute inside the shifted
earlier start of the vblank, so pageflips now also appear to execute at
start of the shifted vblank, in sync with vblank counter and timestamp
updates. This to avoid some races between updates of vblank count and
timestamps that are used for swap scheduling and pageflip execution which
could cause pageflips to execute before the scheduled target vblank.
The lb_vblank_lead_lines "fudge" value is calculated as the size of
the display controllers line buffer in scanlines for the given video
mode: Vblank irq's are triggered by the line buffer logic when the line
buffer refill for a video frame ends, ie. when the line buffer source read
position enters the hw vblank. This means that a vblank irq could fire at
most as many scanlines before the current reported scanout position of the
crtc timing generator as the number of scanlines the line buffer can
maximally hold for a given video mode.
This patch has been successfully tested on a RV730 card with DCE-3 display
engine and on a evergreen card with DCE-4 display engine, in single-display
and dual-display configuration, with different video modes.
A similar patch is needed for amdgpu-kms to fix the same problem.
Limitations:
- Line buffer sizes in pixels are hard-coded on < DCE-4 to a value
i just guessed to be high enough to work ok, lacking info on the true
sizes atm.
Fixes: fdo#93147
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Michel Dänzer <michel.daenzer@amd.com>
Cc: Harry Wentland <Harry.Wentland@amd.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
(v1) Tested-by: Dave Witbrodt <dawitbro@sbcglobal.net>
(v2) Refine radeon_flip_work_func() for better efficiency:
In radeon_flip_work_func, replace the busy waiting udelay(5)
with event lock held by a more performance and energy efficient
usleep_range() until at least predicted true start of hw vblank,
with some slack for scheduler happiness. Release the event lock
during waits to not delay other outputs in doing their stuff, as
the waiting can last up to 200 usecs in some cases.
Retested on DCE-3 and DCE-4 to verify it still works nicely.
(v2) Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
2015-11-26 03:14:31 +08:00
|
|
|
#define USE_REAL_VBLANKSTART (1 << 30)
|
|
|
|
#define GET_DISTANCE_TO_VBLANKSTART (1 << 31)
|
2014-01-08 02:01:32 +08:00
|
|
|
|
|
|
|
extern void
|
|
|
|
radeon_add_atom_connector(struct drm_device *dev,
|
|
|
|
uint32_t connector_id,
|
|
|
|
uint32_t supported_device,
|
|
|
|
int connector_type,
|
|
|
|
struct radeon_i2c_bus_rec *i2c_bus,
|
|
|
|
uint32_t igp_lane_info,
|
|
|
|
uint16_t connector_object_id,
|
|
|
|
struct radeon_hpd *hpd,
|
|
|
|
struct radeon_router *router);
|
|
|
|
extern void
|
|
|
|
radeon_add_legacy_connector(struct drm_device *dev,
|
|
|
|
uint32_t connector_id,
|
|
|
|
uint32_t supported_device,
|
|
|
|
int connector_type,
|
|
|
|
struct radeon_i2c_bus_rec *i2c_bus,
|
|
|
|
uint16_t connector_object_id,
|
|
|
|
struct radeon_hpd *hpd);
|
2014-01-08 02:06:31 +08:00
|
|
|
extern uint32_t
|
|
|
|
radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
|
|
|
|
uint8_t dac);
|
|
|
|
extern void radeon_link_encoder_connector(struct drm_device *dev);
|
2014-01-08 02:01:32 +08:00
|
|
|
|
2009-12-18 08:00:29 +08:00
|
|
|
extern enum radeon_tv_std
|
|
|
|
radeon_combios_get_tv_info(struct radeon_device *rdev);
|
|
|
|
extern enum radeon_tv_std
|
|
|
|
radeon_atombios_get_tv_info(struct radeon_device *rdev);
|
2013-04-13 02:04:10 +08:00
|
|
|
extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
|
2013-03-26 00:47:23 +08:00
|
|
|
u16 *vddc, u16 *vddci, u16 *mvdd);
|
2009-12-18 08:00:29 +08:00
|
|
|
|
2014-01-08 01:53:29 +08:00
|
|
|
extern void
|
|
|
|
radeon_combios_connected_scratch_regs(struct drm_connector *connector,
|
|
|
|
struct drm_encoder *encoder,
|
|
|
|
bool connected);
|
|
|
|
extern void
|
|
|
|
radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
|
|
|
|
struct drm_encoder *encoder,
|
|
|
|
bool connected);
|
|
|
|
|
2010-08-04 07:59:20 +08:00
|
|
|
extern struct drm_connector *
|
|
|
|
radeon_get_connector_for_encoder(struct drm_encoder *encoder);
|
2012-01-21 04:03:30 +08:00
|
|
|
extern struct drm_connector *
|
|
|
|
radeon_get_connector_for_encoder_init(struct drm_encoder *encoder);
|
|
|
|
extern bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
|
|
|
|
u32 pixel_clock);
|
2010-08-04 07:59:20 +08:00
|
|
|
|
2011-10-31 20:58:47 +08:00
|
|
|
extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder);
|
|
|
|
extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector);
|
2011-05-20 16:34:21 +08:00
|
|
|
extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
|
2012-03-27 03:12:54 +08:00
|
|
|
extern int radeon_get_monitor_bpc(struct drm_connector *connector);
|
2011-05-20 16:34:21 +08:00
|
|
|
|
2014-07-15 23:00:47 +08:00
|
|
|
extern struct edid *radeon_connector_edid(struct drm_connector *connector);
|
|
|
|
|
2009-12-05 05:56:37 +08:00
|
|
|
extern void radeon_connector_hotplug(struct drm_connector *connector);
|
2011-05-20 16:34:28 +08:00
|
|
|
extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
|
2009-11-25 02:32:59 +08:00
|
|
|
struct drm_display_mode *mode);
|
|
|
|
extern void radeon_dp_set_link_config(struct drm_connector *connector,
|
2012-07-17 23:56:50 +08:00
|
|
|
const struct drm_display_mode *mode);
|
2011-05-20 16:34:28 +08:00
|
|
|
extern void radeon_dp_link_train(struct drm_encoder *encoder,
|
|
|
|
struct drm_connector *connector);
|
2011-08-14 01:36:13 +08:00
|
|
|
extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
|
2009-11-24 07:02:35 +08:00
|
|
|
extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
|
2009-11-28 02:01:46 +08:00
|
|
|
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
|
2012-01-21 04:01:29 +08:00
|
|
|
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
|
|
|
|
struct drm_connector *connector);
|
2014-03-18 11:48:15 +08:00
|
|
|
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
|
|
|
|
u8 power_state);
|
2014-03-21 22:34:07 +08:00
|
|
|
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
|
2015-02-20 07:21:36 +08:00
|
|
|
extern ssize_t
|
|
|
|
radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg);
|
|
|
|
|
2011-05-20 16:34:27 +08:00
|
|
|
extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
|
2015-02-24 07:24:01 +08:00
|
|
|
extern void atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override);
|
2011-05-23 01:20:36 +08:00
|
|
|
extern void radeon_atom_encoder_init(struct radeon_device *rdev);
|
2012-03-21 05:18:04 +08:00
|
|
|
extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
|
2009-11-25 02:32:59 +08:00
|
|
|
extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
|
|
|
|
int action, uint8_t lane_num,
|
|
|
|
uint8_t lane_set);
|
2015-02-24 07:24:01 +08:00
|
|
|
extern void atombios_dig_transmitter_setup2(struct drm_encoder *encoder,
|
|
|
|
int action, uint8_t lane_num,
|
|
|
|
uint8_t lane_set, int fe);
|
2015-02-24 07:24:04 +08:00
|
|
|
extern void atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder,
|
|
|
|
int fe);
|
2011-06-14 05:13:34 +08:00
|
|
|
extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
|
2011-10-31 05:20:22 +08:00
|
|
|
extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
|
2014-01-06 23:46:34 +08:00
|
|
|
void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
|
2009-12-08 05:07:28 +08:00
|
|
|
|
2010-08-06 09:21:16 +08:00
|
|
|
extern void radeon_i2c_init(struct radeon_device *rdev);
|
|
|
|
extern void radeon_i2c_fini(struct radeon_device *rdev);
|
|
|
|
extern void radeon_combios_i2c_init(struct radeon_device *rdev);
|
|
|
|
extern void radeon_atombios_i2c_init(struct radeon_device *rdev);
|
|
|
|
extern void radeon_i2c_add(struct radeon_device *rdev,
|
|
|
|
struct radeon_i2c_bus_rec *rec,
|
|
|
|
const char *name);
|
|
|
|
extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
|
|
|
|
struct radeon_i2c_bus_rec *i2c_bus);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
|
|
|
|
struct radeon_i2c_bus_rec *rec,
|
|
|
|
const char *name);
|
|
|
|
extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c);
|
2009-12-23 04:04:48 +08:00
|
|
|
extern void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
|
|
|
|
u8 slave_addr,
|
|
|
|
u8 addr,
|
|
|
|
u8 *val);
|
|
|
|
extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
|
|
|
|
u8 slave_addr,
|
|
|
|
u8 addr,
|
|
|
|
u8 val);
|
2010-11-09 00:08:29 +08:00
|
|
|
extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
|
|
|
|
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
|
2013-01-04 02:09:28 +08:00
|
|
|
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
|
2009-06-05 20:42:42 +08:00
|
|
|
|
2010-10-05 05:13:01 +08:00
|
|
|
extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
|
|
|
|
struct radeon_atom_ss *ss,
|
|
|
|
int id);
|
|
|
|
extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
|
|
|
|
struct radeon_atom_ss *ss,
|
|
|
|
int id, u32 clock);
|
2014-11-08 00:16:25 +08:00
|
|
|
extern struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
|
|
|
|
u8 id);
|
2010-10-05 05:13:01 +08:00
|
|
|
|
2011-02-01 05:48:52 +08:00
|
|
|
extern void radeon_compute_pll_legacy(struct radeon_pll *pll,
|
|
|
|
uint64_t freq,
|
|
|
|
uint32_t *dot_clock_p,
|
|
|
|
uint32_t *fb_div_p,
|
|
|
|
uint32_t *frac_fb_div_p,
|
|
|
|
uint32_t *ref_div_p,
|
|
|
|
uint32_t *post_div_p);
|
|
|
|
|
|
|
|
extern void radeon_compute_pll_avivo(struct radeon_pll *pll,
|
|
|
|
u32 freq,
|
|
|
|
u32 *dot_clock_p,
|
|
|
|
u32 *fb_div_p,
|
|
|
|
u32 *frac_fb_div_p,
|
|
|
|
u32 *ref_div_p,
|
|
|
|
u32 *post_div_p);
|
2009-06-05 20:42:42 +08:00
|
|
|
|
2009-10-13 12:10:37 +08:00
|
|
|
extern void radeon_setup_encoder_clones(struct drm_device *dev);
|
|
|
|
|
2009-06-05 20:42:42 +08:00
|
|
|
struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index);
|
|
|
|
struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int with_tv);
|
|
|
|
struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
|
|
|
|
struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
|
|
|
|
struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
|
2010-11-17 01:09:41 +08:00
|
|
|
extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
|
2009-11-30 14:54:16 +08:00
|
|
|
extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
|
2011-05-20 16:34:19 +08:00
|
|
|
extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
|
2009-08-13 14:32:14 +08:00
|
|
|
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
|
2014-09-19 04:27:46 +08:00
|
|
|
extern bool radeon_encoder_is_digital(struct drm_encoder *encoder);
|
2009-06-05 20:42:42 +08:00
|
|
|
|
|
|
|
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
|
|
|
|
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
|
|
|
|
struct drm_framebuffer *old_fb);
|
2010-09-26 19:47:23 +08:00
|
|
|
extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
2010-10-14 03:09:44 +08:00
|
|
|
int x, int y,
|
|
|
|
enum mode_set_atomic state);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
|
struct drm_display_mode *mode,
|
|
|
|
struct drm_display_mode *adjusted_mode,
|
|
|
|
int x, int y,
|
|
|
|
struct drm_framebuffer *old_fb);
|
|
|
|
extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
|
|
|
|
|
|
|
|
extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
|
|
|
|
struct drm_framebuffer *old_fb);
|
2010-09-26 19:47:23 +08:00
|
|
|
extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
2010-10-14 03:09:44 +08:00
|
|
|
int x, int y,
|
|
|
|
enum mode_set_atomic state);
|
2010-09-26 19:47:23 +08:00
|
|
|
extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
|
|
|
|
struct drm_framebuffer *fb,
|
|
|
|
int x, int y, int atomic);
|
2014-11-18 17:00:08 +08:00
|
|
|
extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
|
|
|
|
struct drm_file *file_priv,
|
|
|
|
uint32_t handle,
|
|
|
|
uint32_t width,
|
|
|
|
uint32_t height,
|
|
|
|
int32_t hot_x,
|
|
|
|
int32_t hot_y);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
|
|
|
|
int x, int y);
|
2014-11-21 10:48:57 +08:00
|
|
|
extern void radeon_cursor_reset(struct drm_crtc *crtc);
|
2009-06-05 20:42:42 +08:00
|
|
|
|
2015-09-25 00:35:31 +08:00
|
|
|
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
|
|
|
|
unsigned int flags, int *vpos, int *hpos,
|
2015-09-15 03:43:44 +08:00
|
|
|
ktime_t *stime, ktime_t *etime,
|
|
|
|
const struct drm_display_mode *mode);
|
2010-10-06 07:57:36 +08:00
|
|
|
|
2010-02-05 17:21:19 +08:00
|
|
|
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
|
|
|
extern struct edid *
|
2010-12-09 11:13:06 +08:00
|
|
|
radeon_bios_get_hardcoded_edid(struct radeon_device *rdev);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern bool radeon_atom_get_clock_info(struct drm_device *dev);
|
|
|
|
extern bool radeon_combios_get_clock_info(struct drm_device *dev);
|
|
|
|
extern struct radeon_encoder_atom_dig *
|
|
|
|
radeon_atombios_get_lvds_info(struct radeon_encoder *encoder);
|
2009-11-11 10:25:07 +08:00
|
|
|
extern bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,
|
|
|
|
struct radeon_encoder_int_tmds *tmds);
|
|
|
|
extern bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder,
|
|
|
|
struct radeon_encoder_int_tmds *tmds);
|
|
|
|
extern bool radeon_legacy_get_tmds_info_from_table(struct radeon_encoder *encoder,
|
|
|
|
struct radeon_encoder_int_tmds *tmds);
|
|
|
|
extern bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder,
|
|
|
|
struct radeon_encoder_ext_tmds *tmds);
|
|
|
|
extern bool radeon_legacy_get_ext_tmds_info_from_table(struct radeon_encoder *encoder,
|
|
|
|
struct radeon_encoder_ext_tmds *tmds);
|
2009-06-13 01:26:08 +08:00
|
|
|
extern struct radeon_encoder_primary_dac *
|
|
|
|
radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder);
|
|
|
|
extern struct radeon_encoder_tv_dac *
|
|
|
|
radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern struct radeon_encoder_lvds *
|
|
|
|
radeon_combios_get_lvds_info(struct radeon_encoder *encoder);
|
|
|
|
extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder);
|
|
|
|
extern struct radeon_encoder_tv_dac *
|
|
|
|
radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder);
|
|
|
|
extern struct radeon_encoder_primary_dac *
|
|
|
|
radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder);
|
2009-11-11 10:25:07 +08:00
|
|
|
extern bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder);
|
|
|
|
extern void radeon_external_tmds_setup(struct drm_encoder *encoder);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock);
|
|
|
|
extern void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev);
|
|
|
|
extern void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock);
|
|
|
|
extern void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev);
|
2009-09-15 10:21:01 +08:00
|
|
|
extern void radeon_save_bios_scratch_regs(struct radeon_device *rdev);
|
|
|
|
extern void radeon_restore_bios_scratch_regs(struct radeon_device *rdev);
|
2009-06-05 20:42:42 +08:00
|
|
|
extern void
|
|
|
|
radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc);
|
|
|
|
extern void
|
|
|
|
radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on);
|
|
|
|
extern void
|
|
|
|
radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc);
|
|
|
|
extern void
|
|
|
|
radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on);
|
2012-03-06 18:44:40 +08:00
|
|
|
int radeon_framebuffer_init(struct drm_device *dev,
|
2010-03-30 13:34:13 +08:00
|
|
|
struct radeon_framebuffer *rfb,
|
2015-11-12 01:11:29 +08:00
|
|
|
const struct drm_mode_fb_cmd2 *mode_cmd,
|
2010-03-30 13:34:13 +08:00
|
|
|
struct drm_gem_object *obj);
|
2009-06-05 20:42:42 +08:00
|
|
|
|
|
|
|
int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
|
|
|
|
bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev);
|
|
|
|
bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev);
|
|
|
|
void radeon_atombios_init_crtc(struct drm_device *dev,
|
|
|
|
struct radeon_crtc *radeon_crtc);
|
|
|
|
void radeon_legacy_init_crtc(struct drm_device *dev,
|
|
|
|
struct radeon_crtc *radeon_crtc);
|
|
|
|
|
|
|
|
void radeon_get_clock_info(struct drm_device *dev);
|
|
|
|
|
|
|
|
extern bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev);
|
|
|
|
extern bool radeon_get_atom_connector_info_from_supported_devices_table(struct drm_device *dev);
|
|
|
|
|
|
|
|
void radeon_enc_destroy(struct drm_encoder *encoder);
|
|
|
|
void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj);
|
|
|
|
void radeon_combios_asic_init(struct drm_device *dev);
|
2009-07-14 03:04:08 +08:00
|
|
|
bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
2012-07-17 23:56:50 +08:00
|
|
|
const struct drm_display_mode *mode,
|
2009-07-14 03:04:08 +08:00
|
|
|
struct drm_display_mode *adjusted_mode);
|
2010-05-01 00:00:44 +08:00
|
|
|
void radeon_panel_mode_fixup(struct drm_encoder *encoder,
|
|
|
|
struct drm_display_mode *adjusted_mode);
|
2009-08-13 14:32:14 +08:00
|
|
|
void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc);
|
|
|
|
|
|
|
|
/* legacy tv */
|
|
|
|
void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder,
|
|
|
|
uint32_t *h_total_disp, uint32_t *h_sync_strt_wid,
|
|
|
|
uint32_t *v_total_disp, uint32_t *v_sync_strt_wid);
|
|
|
|
void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder,
|
|
|
|
uint32_t *htotal_cntl, uint32_t *ppll_ref_div,
|
|
|
|
uint32_t *ppll_div_3, uint32_t *pixclks_cntl);
|
|
|
|
void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
|
|
|
|
uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div,
|
|
|
|
uint32_t *p2pll_div_0, uint32_t *pixclks_cntl);
|
|
|
|
void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
|
|
|
|
struct drm_display_mode *mode,
|
|
|
|
struct drm_display_mode *adjusted_mode);
|
2010-03-30 13:34:13 +08:00
|
|
|
|
2013-09-24 00:22:11 +08:00
|
|
|
/* fmt blocks */
|
|
|
|
void avivo_program_fmt(struct drm_encoder *encoder);
|
|
|
|
void dce3_program_fmt(struct drm_encoder *encoder);
|
|
|
|
void dce4_program_fmt(struct drm_encoder *encoder);
|
|
|
|
void dce8_program_fmt(struct drm_encoder *encoder);
|
|
|
|
|
2010-03-30 13:34:13 +08:00
|
|
|
/* fbdev layer */
|
|
|
|
int radeon_fbdev_init(struct radeon_device *rdev);
|
|
|
|
void radeon_fbdev_fini(struct radeon_device *rdev);
|
|
|
|
void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
|
|
|
|
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
|
2010-11-21 23:59:01 +08:00
|
|
|
|
2014-05-27 22:49:21 +08:00
|
|
|
void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
|
2015-02-24 07:23:59 +08:00
|
|
|
|
|
|
|
void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector);
|
|
|
|
void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector);
|
|
|
|
|
2010-11-21 23:59:01 +08:00
|
|
|
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
|
|
|
|
|
2011-02-07 10:16:14 +08:00
|
|
|
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
|
2015-02-24 07:24:03 +08:00
|
|
|
|
2015-02-24 07:24:04 +08:00
|
|
|
/* mst */
|
|
|
|
int radeon_dp_mst_init(struct radeon_connector *radeon_connector);
|
|
|
|
int radeon_dp_mst_probe(struct radeon_connector *radeon_connector);
|
|
|
|
int radeon_dp_mst_check_status(struct radeon_connector *radeon_connector);
|
|
|
|
int radeon_mst_debugfs_init(struct radeon_device *rdev);
|
|
|
|
void radeon_dp_mst_prepare_pll(struct drm_crtc *crtc, struct drm_display_mode *mode);
|
|
|
|
|
|
|
|
void radeon_setup_mst_connector(struct drm_device *dev);
|
|
|
|
|
2015-02-24 07:24:03 +08:00
|
|
|
int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
|
|
|
|
void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
|
2009-06-05 20:42:42 +08:00
|
|
|
#endif
|