Merge branch 'drm-next-3.16' of git://people.freedesktop.org/~agd5f/linux into drm-next
Highlights: - GPUVM opimtizations - HDMI audio cleanups - Deep color HDMI support - more bug fixes, cleanups * 'drm-next-3.16' of git://people.freedesktop.org/~agd5f/linux: (29 commits) drm/edid: Add quirk for Sony PVM-2541A to get 12 bpc hdmi deep color. drm/edid: Parse and handle HDMI deep color modes. drm/radeon: Limit hdmi deep color bit depth to 12 bpc. drm/radeon: Setup HDMI_CONTROL for hdmi deep color gcp's (v2) drm/radeon: fix pll setup for hdmi deep color (v7) drm/radeon: use hw cts/n values for deep color drm/radeon: only apply hdmi bpc pll flags when encoder mode is hdmi drm/radeon/atom: fix dithering on certain panels drm/radeon: optimize CIK VM handling v2 drm/radeon: optimize SI VM handling drm/radeon: add define for flags used in R600+ GTT drm/radeon: rework page flip handling v3 drm/radeon: separate vblank and pflip crtc handling drm/radeon: split page flip and pending callback drm/radeon: remove drm_vblank_get|put from pflip handling drm/radeon: remove (pre|post)_page_flip callbacks drm/radeon/dp: fix lane/clock setup for dp 1.2 capable devices drm/radeon: fix typo in radeon_connector_is_dp12_capable() radeon: Remove useless quirk for zx1/FireGL X1 combo introduced with fdo #7770 vgaswitcheroo: switch the mux to the igp on power down when runpm is enabled ...
This commit is contained in:
commit
5536141ddd
|
@ -70,6 +70,8 @@
|
|||
#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7)
|
||||
/* Force 8bpc */
|
||||
#define EDID_QUIRK_FORCE_8BPC (1 << 8)
|
||||
/* Force 12bpc */
|
||||
#define EDID_QUIRK_FORCE_12BPC (1 << 9)
|
||||
|
||||
struct detailed_mode_closure {
|
||||
struct drm_connector *connector;
|
||||
|
@ -125,6 +127,9 @@ static struct edid_quirk {
|
|||
{ "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
{ "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
|
||||
|
||||
/* Sony PVM-2541A does up to 12 bpc, but only reports max 8 bpc */
|
||||
{ "SNY", 0x2541, EDID_QUIRK_FORCE_12BPC },
|
||||
|
||||
/* ViewSonic VA2026w */
|
||||
{ "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING },
|
||||
|
||||
|
@ -3422,17 +3427,117 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
||||
|
||||
/**
|
||||
* drm_assign_hdmi_deep_color_info - detect whether monitor supports
|
||||
* hdmi deep color modes and update drm_display_info if so.
|
||||
*
|
||||
* @edid: monitor EDID information
|
||||
* @info: Updated with maximum supported deep color bpc and color format
|
||||
* if deep color supported.
|
||||
*
|
||||
* Parse the CEA extension according to CEA-861-B.
|
||||
* Return true if HDMI deep color supported, false if not or unknown.
|
||||
*/
|
||||
static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
|
||||
struct drm_display_info *info,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
u8 *edid_ext, *hdmi;
|
||||
int i;
|
||||
int start_offset, end_offset;
|
||||
unsigned int dc_bpc = 0;
|
||||
|
||||
edid_ext = drm_find_cea_extension(edid);
|
||||
if (!edid_ext)
|
||||
return false;
|
||||
|
||||
if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Because HDMI identifier is in Vendor Specific Block,
|
||||
* search it from all data blocks of CEA extension.
|
||||
*/
|
||||
for_each_cea_db(edid_ext, i, start_offset, end_offset) {
|
||||
if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
|
||||
/* HDMI supports at least 8 bpc */
|
||||
info->bpc = 8;
|
||||
|
||||
hdmi = &edid_ext[i];
|
||||
if (cea_db_payload_len(hdmi) < 6)
|
||||
return false;
|
||||
|
||||
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
|
||||
dc_bpc = 10;
|
||||
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
|
||||
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
|
||||
dc_bpc = 12;
|
||||
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
|
||||
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
|
||||
dc_bpc = 16;
|
||||
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
|
||||
if (dc_bpc > 0) {
|
||||
DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
|
||||
drm_get_connector_name(connector), dc_bpc);
|
||||
info->bpc = dc_bpc;
|
||||
|
||||
/*
|
||||
* Deep color support mandates RGB444 support for all video
|
||||
* modes and forbids YCRCB422 support for all video modes per
|
||||
* HDMI 1.3 spec.
|
||||
*/
|
||||
info->color_formats = DRM_COLOR_FORMAT_RGB444;
|
||||
|
||||
/* YCRCB444 is optional according to spec. */
|
||||
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
|
||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
||||
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
|
||||
/*
|
||||
* Spec says that if any deep color mode is supported at all,
|
||||
* then deep color 36 bit must be supported.
|
||||
*/
|
||||
if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
|
||||
DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
|
||||
drm_get_connector_name(connector));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_add_display_info - pull display info out if present
|
||||
* @edid: EDID data
|
||||
* @info: display info (attached to connector)
|
||||
* @connector: connector whose edid is used to build display info
|
||||
*
|
||||
* Grab any available display info and stuff it into the drm_display_info
|
||||
* structure that's part of the connector. Useful for tracking bpp and
|
||||
* color spaces.
|
||||
*/
|
||||
static void drm_add_display_info(struct edid *edid,
|
||||
struct drm_display_info *info)
|
||||
struct drm_display_info *info,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
u8 *edid_ext;
|
||||
|
||||
|
@ -3462,6 +3567,9 @@ static void drm_add_display_info(struct edid *edid,
|
|||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
||||
}
|
||||
|
||||
/* HDMI deep color modes supported? Assign to info, if so */
|
||||
drm_assign_hdmi_deep_color_info(edid, info, connector);
|
||||
|
||||
/* Only defined for 1.4 with digital displays */
|
||||
if (edid->revision < 4)
|
||||
return;
|
||||
|
@ -3491,6 +3599,9 @@ static void drm_add_display_info(struct edid *edid,
|
|||
break;
|
||||
}
|
||||
|
||||
DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
|
||||
drm_get_connector_name(connector), info->bpc);
|
||||
|
||||
info->color_formats |= DRM_COLOR_FORMAT_RGB444;
|
||||
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
|
||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
||||
|
@ -3549,11 +3660,14 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
|||
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
||||
edid_fixup_preferred(connector, quirks);
|
||||
|
||||
drm_add_display_info(edid, &connector->display_info);
|
||||
drm_add_display_info(edid, &connector->display_info, connector);
|
||||
|
||||
if (quirks & EDID_QUIRK_FORCE_8BPC)
|
||||
connector->display_info.bpc = 8;
|
||||
|
||||
if (quirks & EDID_QUIRK_FORCE_12BPC)
|
||||
connector->display_info.bpc = 12;
|
||||
|
||||
return num_modes;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_add_edid_modes);
|
||||
|
|
|
@ -72,7 +72,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
|
|||
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
|
||||
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
|
||||
r200.o radeon_legacy_tv.o r600_cs.o r600_blit_shaders.o \
|
||||
radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
|
||||
radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o dce3_1_afmt.o \
|
||||
evergreen.o evergreen_cs.o evergreen_blit_shaders.o \
|
||||
evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
|
||||
atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
|
||||
|
|
|
@ -559,6 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
u32 adjusted_clock = mode->clock;
|
||||
int encoder_mode = atombios_get_encoder_mode(encoder);
|
||||
u32 dp_clock = mode->clock;
|
||||
u32 clock = mode->clock;
|
||||
int bpc = radeon_crtc->bpc;
|
||||
bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
|
||||
|
||||
|
@ -634,6 +635,24 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
|
||||
}
|
||||
|
||||
/* adjust pll for deep color modes */
|
||||
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
|
||||
switch (bpc) {
|
||||
case 8:
|
||||
default:
|
||||
break;
|
||||
case 10:
|
||||
clock = (clock * 5) / 4;
|
||||
break;
|
||||
case 12:
|
||||
clock = (clock * 3) / 2;
|
||||
break;
|
||||
case 16:
|
||||
clock = clock * 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
|
||||
* accordingly based on the encoder/transmitter to work around
|
||||
* special hw requirements.
|
||||
|
@ -655,7 +674,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
switch (crev) {
|
||||
case 1:
|
||||
case 2:
|
||||
args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
|
||||
args.v1.usPixelClock = cpu_to_le16(clock / 10);
|
||||
args.v1.ucTransmitterID = radeon_encoder->encoder_id;
|
||||
args.v1.ucEncodeMode = encoder_mode;
|
||||
if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
|
||||
|
@ -667,7 +686,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
|
||||
break;
|
||||
case 3:
|
||||
args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
|
||||
args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
|
||||
args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
|
||||
args.v3.sInput.ucEncodeMode = encoder_mode;
|
||||
args.v3.sInput.ucDispPllConfig = 0;
|
||||
|
@ -681,10 +700,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
|
|||
args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
|
||||
} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
if (encoder_mode == ATOM_ENCODER_MODE_HDMI)
|
||||
/* deep color support */
|
||||
args.v3.sInput.usPixelClock =
|
||||
cpu_to_le16((mode->clock * bpc / 8) / 10);
|
||||
if (dig->coherent_mode)
|
||||
args.v3.sInput.ucDispPllConfig |=
|
||||
DISPPLL_CONFIG_COHERENT_MODE;
|
||||
|
@ -864,14 +879,21 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
|
|||
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
|
||||
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
|
||||
switch (bpc) {
|
||||
case 8:
|
||||
default:
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
|
||||
break;
|
||||
case 10:
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
|
||||
break;
|
||||
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
|
||||
switch (bpc) {
|
||||
case 8:
|
||||
default:
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
|
||||
break;
|
||||
case 10:
|
||||
/* yes this is correct, the atom define is wrong */
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
|
||||
break;
|
||||
case 12:
|
||||
/* yes this is correct, the atom define is wrong */
|
||||
args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
args.v5.ucTransmitterID = encoder_id;
|
||||
args.v5.ucEncoderMode = encoder_mode;
|
||||
|
@ -886,20 +908,22 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
|
|||
args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
|
||||
if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
|
||||
switch (bpc) {
|
||||
case 8:
|
||||
default:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
|
||||
break;
|
||||
case 10:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
|
||||
break;
|
||||
case 12:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
|
||||
break;
|
||||
case 16:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
|
||||
break;
|
||||
if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
|
||||
switch (bpc) {
|
||||
case 8:
|
||||
default:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
|
||||
break;
|
||||
case 10:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
|
||||
break;
|
||||
case 12:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
|
||||
break;
|
||||
case 16:
|
||||
args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
args.v6.ucTransmitterID = encoder_id;
|
||||
args.v6.ucEncoderMode = encoder_mode;
|
||||
|
@ -1021,10 +1045,17 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
|
|||
struct radeon_encoder *radeon_encoder =
|
||||
to_radeon_encoder(radeon_crtc->encoder);
|
||||
u32 pll_clock = mode->clock;
|
||||
u32 clock = mode->clock;
|
||||
u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
|
||||
struct radeon_pll *pll;
|
||||
int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
|
||||
|
||||
/* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */
|
||||
if (ASIC_IS_DCE5(rdev) && !ASIC_IS_DCE8(rdev) &&
|
||||
(encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
|
||||
(radeon_crtc->bpc > 8))
|
||||
clock = radeon_crtc->adjusted_clock;
|
||||
|
||||
switch (radeon_crtc->pll_id) {
|
||||
case ATOM_PPLL1:
|
||||
pll = &rdev->clock.p1pll;
|
||||
|
@ -1059,7 +1090,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
|
|||
radeon_crtc->crtc_id, &radeon_crtc->ss);
|
||||
|
||||
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
|
||||
encoder_mode, radeon_encoder->encoder_id, mode->clock,
|
||||
encoder_mode, radeon_encoder->encoder_id, clock,
|
||||
ref_div, fb_div, frac_fb_div, post_div,
|
||||
radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss);
|
||||
|
||||
|
|
|
@ -95,9 +95,12 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
|
|||
int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
|
||||
unsigned char *base;
|
||||
int recv_bytes;
|
||||
int r = 0;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
mutex_lock(&chan->mutex);
|
||||
|
||||
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
|
||||
|
||||
radeon_atom_copy_swap(base, send, send_bytes, true);
|
||||
|
@ -117,19 +120,22 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
|
|||
/* timeout */
|
||||
if (args.v1.ucReplyStatus == 1) {
|
||||
DRM_DEBUG_KMS("dp_aux_ch timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
r = -ETIMEDOUT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* flags not zero */
|
||||
if (args.v1.ucReplyStatus == 2) {
|
||||
DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
|
||||
return -EBUSY;
|
||||
r = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* error */
|
||||
if (args.v1.ucReplyStatus == 3) {
|
||||
DRM_DEBUG_KMS("dp_aux_ch error\n");
|
||||
return -EIO;
|
||||
r = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
recv_bytes = args.v1.ucDataOutLen;
|
||||
|
@ -139,7 +145,11 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
|
|||
if (recv && recv_size)
|
||||
radeon_atom_copy_swap(recv, base + 16, recv_bytes, false);
|
||||
|
||||
return recv_bytes;
|
||||
r = recv_bytes;
|
||||
done:
|
||||
mutex_unlock(&chan->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#define BARE_ADDRESS_SIZE 3
|
||||
|
@ -281,6 +291,19 @@ static int dp_get_max_dp_pix_clock(int link_rate,
|
|||
|
||||
/***** radeon specific DP functions *****/
|
||||
|
||||
static int radeon_dp_get_max_link_rate(struct drm_connector *connector,
|
||||
u8 dpcd[DP_DPCD_SIZE])
|
||||
{
|
||||
int max_link_rate;
|
||||
|
||||
if (radeon_connector_is_dp12_capable(connector))
|
||||
max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
|
||||
else
|
||||
max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
|
||||
|
||||
return max_link_rate;
|
||||
}
|
||||
|
||||
/* First get the min lane# when low rate is used according to pixel clock
|
||||
* (prefer low rate), second check max lane# supported by DP panel,
|
||||
* if the max lane# < low rate lane# then use max lane# instead.
|
||||
|
@ -290,7 +313,7 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
|
|||
int pix_clock)
|
||||
{
|
||||
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
|
||||
int max_link_rate = drm_dp_max_link_rate(dpcd);
|
||||
int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
|
||||
int max_lane_num = drm_dp_max_lane_count(dpcd);
|
||||
int lane_num;
|
||||
int max_dp_pix_clock;
|
||||
|
@ -328,7 +351,7 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
|
|||
return 540000;
|
||||
}
|
||||
|
||||
return drm_dp_max_link_rate(dpcd);
|
||||
return radeon_dp_get_max_link_rate(connector, dpcd);
|
||||
}
|
||||
|
||||
static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
|
||||
|
|
|
@ -1884,8 +1884,11 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
|
|||
args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
|
||||
else
|
||||
args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
|
||||
} else
|
||||
} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
|
||||
args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
|
||||
} else {
|
||||
args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
|
||||
}
|
||||
switch (radeon_encoder->encoder_id) {
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
|
||||
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
|
||||
|
|
|
@ -43,15 +43,19 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
|
|||
int index = GetIndexIntoMasterTable(COMMAND, ProcessI2cChannelTransaction);
|
||||
unsigned char *base;
|
||||
u16 out = cpu_to_le16(0);
|
||||
int r = 0;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
mutex_lock(&chan->mutex);
|
||||
|
||||
base = (unsigned char *)rdev->mode_info.atom_context->scratch;
|
||||
|
||||
if (flags & HW_I2C_WRITE) {
|
||||
if (num > ATOM_MAX_HW_I2C_WRITE) {
|
||||
DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 3)\n", num);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (buf == NULL)
|
||||
args.ucRegIndex = 0;
|
||||
|
@ -65,7 +69,8 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
|
|||
} else {
|
||||
if (num > ATOM_MAX_HW_I2C_READ) {
|
||||
DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
args.ucRegIndex = 0;
|
||||
args.lpI2CDataOut = 0;
|
||||
|
@ -82,13 +87,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
|
|||
/* error */
|
||||
if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
|
||||
DRM_DEBUG_KMS("hw_i2c error\n");
|
||||
return -EIO;
|
||||
r = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!(flags & HW_I2C_WRITE))
|
||||
radeon_atom_copy_swap(buf, base, num, false);
|
||||
|
||||
return 0;
|
||||
done:
|
||||
mutex_unlock(&chan->mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int radeon_atom_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||
|
|
|
@ -5328,6 +5328,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
|
|||
WREG32(MC_VM_MX_L1_TLB_CNTL,
|
||||
(0xA << 7) |
|
||||
ENABLE_L1_TLB |
|
||||
ENABLE_L1_FRAGMENT_PROCESSING |
|
||||
SYSTEM_ACCESS_MODE_NOT_IN_SYS |
|
||||
ENABLE_ADVANCED_DRIVER_MODEL |
|
||||
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
|
||||
|
@ -5340,7 +5341,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
|
|||
CONTEXT1_IDENTITY_ACCESS_MODE(1));
|
||||
WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
|
||||
WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
|
||||
L2_CACHE_BIGK_FRAGMENT_SIZE(6));
|
||||
BANK_SELECT(4) |
|
||||
L2_CACHE_BIGK_FRAGMENT_SIZE(4));
|
||||
/* setup context0 */
|
||||
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
|
||||
WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
|
||||
|
@ -5376,6 +5378,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
|
|||
(u32)(rdev->dummy_page.addr >> 12));
|
||||
WREG32(VM_CONTEXT1_CNTL2, 4);
|
||||
WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
|
||||
PAGE_TABLE_BLOCK_SIZE(RADEON_VM_BLOCK_SIZE - 9) |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
|
||||
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
|
@ -7311,7 +7314,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D1 vblank\n");
|
||||
}
|
||||
|
@ -7337,7 +7340,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D2 vblank\n");
|
||||
}
|
||||
|
@ -7363,7 +7366,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[2]))
|
||||
radeon_crtc_handle_flip(rdev, 2);
|
||||
radeon_crtc_handle_vblank(rdev, 2);
|
||||
rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D3 vblank\n");
|
||||
}
|
||||
|
@ -7389,7 +7392,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[3]))
|
||||
radeon_crtc_handle_flip(rdev, 3);
|
||||
radeon_crtc_handle_vblank(rdev, 3);
|
||||
rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D4 vblank\n");
|
||||
}
|
||||
|
@ -7415,7 +7418,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[4]))
|
||||
radeon_crtc_handle_flip(rdev, 4);
|
||||
radeon_crtc_handle_vblank(rdev, 4);
|
||||
rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D5 vblank\n");
|
||||
}
|
||||
|
@ -7441,7 +7444,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[5]))
|
||||
radeon_crtc_handle_flip(rdev, 5);
|
||||
radeon_crtc_handle_vblank(rdev, 5);
|
||||
rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D6 vblank\n");
|
||||
}
|
||||
|
|
|
@ -741,7 +741,26 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,
|
|||
|
||||
trace_radeon_vm_set_page(pe, addr, count, incr, flags);
|
||||
|
||||
if (flags & R600_PTE_SYSTEM) {
|
||||
if (flags == R600_PTE_GART) {
|
||||
uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8;
|
||||
while (count) {
|
||||
unsigned bytes = count * 8;
|
||||
if (bytes > 0x1FFFF8)
|
||||
bytes = 0x1FFFF8;
|
||||
|
||||
ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
|
||||
ib->ptr[ib->length_dw++] = bytes;
|
||||
ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */
|
||||
ib->ptr[ib->length_dw++] = src & 0xffffffff;
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(src);
|
||||
ib->ptr[ib->length_dw++] = pe & 0xffffffff;
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(pe);
|
||||
|
||||
pe += bytes;
|
||||
src += bytes;
|
||||
count -= bytes / 8;
|
||||
}
|
||||
} else if (flags & R600_PTE_SYSTEM) {
|
||||
while (count) {
|
||||
ndw = count * 2;
|
||||
if (ndw > 0xFFFFE)
|
||||
|
|
|
@ -482,6 +482,7 @@
|
|||
#define READ_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 16)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 18)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 19)
|
||||
#define PAGE_TABLE_BLOCK_SIZE(x) (((x) & 0xF) << 24)
|
||||
#define VM_CONTEXT1_CNTL 0x1414
|
||||
#define VM_CONTEXT0_CNTL2 0x1430
|
||||
#define VM_CONTEXT1_CNTL2 0x1434
|
||||
|
|
|
@ -1050,7 +1050,7 @@ static const struct cs_extent_def SECT_CONTEXT_defs[] =
|
|||
{SECT_CONTEXT_def_5, 0x0000a29e, 5 },
|
||||
{SECT_CONTEXT_def_6, 0x0000a2a5, 56 },
|
||||
{SECT_CONTEXT_def_7, 0x0000a2de, 290 },
|
||||
{ 0, 0, 0 }
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
static const u32 SECT_CLEAR_def_1[] =
|
||||
{
|
||||
|
@ -1061,7 +1061,7 @@ static const u32 SECT_CLEAR_def_1[] =
|
|||
static const struct cs_extent_def SECT_CLEAR_defs[] =
|
||||
{
|
||||
{SECT_CLEAR_def_1, 0x0000ffc0, 3 },
|
||||
{ 0, 0, 0 }
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
static const u32 SECT_CTRLCONST_def_1[] =
|
||||
{
|
||||
|
@ -1071,11 +1071,11 @@ static const u32 SECT_CTRLCONST_def_1[] =
|
|||
static const struct cs_extent_def SECT_CTRLCONST_defs[] =
|
||||
{
|
||||
{SECT_CTRLCONST_def_1, 0x0000f3fc, 2 },
|
||||
{ 0, 0, 0 }
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
static const struct cs_section_def cayman_cs_data[] = {
|
||||
{ SECT_CONTEXT_defs, SECT_CONTEXT },
|
||||
{ SECT_CLEAR_defs, SECT_CLEAR },
|
||||
{ SECT_CTRLCONST_defs, SECT_CTRLCONST },
|
||||
{ 0, SECT_NONE }
|
||||
{ NULL, SECT_NONE }
|
||||
};
|
||||
|
|
|
@ -936,9 +936,9 @@ static const struct cs_extent_def ci_SECT_CONTEXT_defs[] =
|
|||
{ci_SECT_CONTEXT_def_5, 0x0000a2a0, 2 },
|
||||
{ci_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
|
||||
{ci_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
|
||||
{ 0, 0, 0 }
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
static const struct cs_section_def ci_cs_data[] = {
|
||||
{ ci_SECT_CONTEXT_defs, SECT_CONTEXT },
|
||||
{ 0, SECT_NONE }
|
||||
{ NULL, SECT_NONE }
|
||||
};
|
||||
|
|
|
@ -933,9 +933,9 @@ static const struct cs_extent_def si_SECT_CONTEXT_defs[] =
|
|||
{si_SECT_CONTEXT_def_5, 0x0000a2a1, 1 },
|
||||
{si_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
|
||||
{si_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
|
||||
{ 0, 0, 0 }
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
static const struct cs_section_def si_cs_data[] = {
|
||||
{ si_SECT_CONTEXT_defs, SECT_CONTEXT },
|
||||
{ 0, SECT_NONE }
|
||||
{ NULL, SECT_NONE }
|
||||
};
|
||||
|
|
244
drivers/gpu/drm/radeon/dce3_1_afmt.c
Normal file
244
drivers/gpu/drm/radeon/dce3_1_afmt.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright 2013 Advanced Micro Devices, Inc.
|
||||
* Copyright 2014 Rafał Miłecki
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/hdmi.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "radeon.h"
|
||||
#include "radeon_asic.h"
|
||||
#include "r600d.h"
|
||||
|
||||
static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
|
||||
{
|
||||
struct radeon_device *rdev = encoder->dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct radeon_connector *radeon_connector = NULL;
|
||||
u32 tmp;
|
||||
u8 *sadb;
|
||||
int sad_count;
|
||||
|
||||
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
radeon_connector = to_radeon_connector(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radeon_connector) {
|
||||
DRM_ERROR("Couldn't find encoder's connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
|
||||
if (sad_count < 0) {
|
||||
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
|
||||
return;
|
||||
}
|
||||
|
||||
/* program the speaker allocation */
|
||||
tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
|
||||
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
|
||||
/* set HDMI mode */
|
||||
tmp |= HDMI_CONNECTION;
|
||||
if (sad_count)
|
||||
tmp |= SPEAKER_ALLOCATION(sadb[0]);
|
||||
else
|
||||
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
|
||||
WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
|
||||
|
||||
kfree(sadb);
|
||||
}
|
||||
|
||||
static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
|
||||
{
|
||||
struct radeon_device *rdev = encoder->dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct radeon_connector *radeon_connector = NULL;
|
||||
struct cea_sad *sads;
|
||||
int i, sad_count;
|
||||
|
||||
static const u16 eld_reg_to_type[][2] = {
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
|
||||
};
|
||||
|
||||
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
radeon_connector = to_radeon_connector(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radeon_connector) {
|
||||
DRM_ERROR("Couldn't find encoder's connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
|
||||
if (sad_count < 0) {
|
||||
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
|
||||
return;
|
||||
}
|
||||
BUG_ON(!sads);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
|
||||
u32 value = 0;
|
||||
u8 stereo_freqs = 0;
|
||||
int max_channels = -1;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < sad_count; j++) {
|
||||
struct cea_sad *sad = &sads[j];
|
||||
|
||||
if (sad->format == eld_reg_to_type[i][1]) {
|
||||
if (sad->channels > max_channels) {
|
||||
value = MAX_CHANNELS(sad->channels) |
|
||||
DESCRIPTOR_BYTE_2(sad->byte2) |
|
||||
SUPPORTED_FREQUENCIES(sad->freq);
|
||||
max_channels = sad->channels;
|
||||
}
|
||||
|
||||
if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
|
||||
stereo_freqs |= sad->freq;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
|
||||
|
||||
WREG32(eld_reg_to_type[i][0], value);
|
||||
}
|
||||
|
||||
kfree(sads);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the info frames with the data from the current display mode
|
||||
*/
|
||||
void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||||
struct hdmi_avi_infoframe frame;
|
||||
uint32_t offset;
|
||||
ssize_t err;
|
||||
|
||||
if (!dig || !dig->afmt)
|
||||
return;
|
||||
|
||||
/* Silent, r600_hdmi_enable will raise WARN for us */
|
||||
if (!dig->afmt->enabled)
|
||||
return;
|
||||
offset = dig->afmt->offset;
|
||||
|
||||
/* disable audio prior to setting up hw */
|
||||
dig->afmt->pin = r600_audio_get_pin(rdev);
|
||||
r600_audio_enable(rdev, dig->afmt->pin, false);
|
||||
|
||||
r600_audio_set_dto(encoder, mode->clock);
|
||||
|
||||
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
|
||||
HDMI0_NULL_SEND); /* send null packets when required */
|
||||
|
||||
WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
|
||||
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
|
||||
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
|
||||
AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
|
||||
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
|
||||
} else {
|
||||
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
|
||||
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
|
||||
HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
|
||||
}
|
||||
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
dce3_2_afmt_write_speaker_allocation(encoder);
|
||||
dce3_2_afmt_write_sad_regs(encoder);
|
||||
}
|
||||
|
||||
WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
|
||||
HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
|
||||
HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
|
||||
|
||||
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
|
||||
HDMI0_NULL_SEND | /* send null packets when required */
|
||||
HDMI0_GC_SEND | /* send general control packets */
|
||||
HDMI0_GC_CONT); /* send general control packets every frame */
|
||||
|
||||
/* TODO: HDMI0_AUDIO_INFO_UPDATE */
|
||||
WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
|
||||
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
|
||||
HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
|
||||
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
|
||||
HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
|
||||
|
||||
WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
|
||||
HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
|
||||
HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
|
||||
|
||||
WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
|
||||
r600_hdmi_update_ACR(encoder, mode->clock);
|
||||
|
||||
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
|
||||
WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
|
||||
WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
|
||||
WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
|
||||
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
|
||||
|
||||
r600_hdmi_audio_workaround(encoder);
|
||||
|
||||
/* enable audio after to setting up hw */
|
||||
r600_audio_enable(rdev, dig->afmt->pin, true);
|
||||
}
|
|
@ -1300,36 +1300,6 @@ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_irq_kms_pflip_irq_get - pre-pageflip callback.
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc: crtc to prepare for pageflip on
|
||||
*
|
||||
* Pre-pageflip callback (evergreen+).
|
||||
* Enables the pageflip irq (vblank irq).
|
||||
*/
|
||||
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* enable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_get(rdev, crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* evergreen_post_page_flip - pos-pageflip callback.
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc: crtc to cleanup pageflip on
|
||||
*
|
||||
* Post-pageflip callback (evergreen+).
|
||||
* Disables the pageflip irq (vblank irq).
|
||||
*/
|
||||
void evergreen_post_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* disable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_put(rdev, crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* evergreen_page_flip - pageflip callback.
|
||||
*
|
||||
|
@ -1343,7 +1313,7 @@ void evergreen_post_page_flip(struct radeon_device *rdev, int crtc)
|
|||
* double buffered update to take place.
|
||||
* Returns the current update pending status.
|
||||
*/
|
||||
u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
void evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset);
|
||||
|
@ -1375,9 +1345,23 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
|||
/* Unlock the lock, so double-buffering can take place inside vblank */
|
||||
tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK;
|
||||
WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* evergreen_page_flip_pending - check if page flip is still pending
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc_id: crtc to check
|
||||
*
|
||||
* Returns the current update pending status.
|
||||
*/
|
||||
bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
|
||||
/* Return current update_pending status: */
|
||||
return RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING;
|
||||
return !!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) &
|
||||
EVERGREEN_GRPH_SURFACE_UPDATE_PENDING);
|
||||
}
|
||||
|
||||
/* get temperature in millidegrees */
|
||||
|
@ -4805,7 +4789,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D1 vblank\n");
|
||||
}
|
||||
|
@ -4831,7 +4815,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D2 vblank\n");
|
||||
}
|
||||
|
@ -4857,7 +4841,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[2]))
|
||||
radeon_crtc_handle_flip(rdev, 2);
|
||||
radeon_crtc_handle_vblank(rdev, 2);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D3 vblank\n");
|
||||
}
|
||||
|
@ -4883,7 +4867,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[3]))
|
||||
radeon_crtc_handle_flip(rdev, 3);
|
||||
radeon_crtc_handle_vblank(rdev, 3);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D4 vblank\n");
|
||||
}
|
||||
|
@ -4909,7 +4893,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[4]))
|
||||
radeon_crtc_handle_flip(rdev, 4);
|
||||
radeon_crtc_handle_vblank(rdev, 4);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D5 vblank\n");
|
||||
}
|
||||
|
@ -4935,7 +4919,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[5]))
|
||||
radeon_crtc_handle_flip(rdev, 5);
|
||||
radeon_crtc_handle_vblank(rdev, 5);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D6 vblank\n");
|
||||
}
|
||||
|
|
|
@ -293,10 +293,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
|
|||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
|
||||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
|
||||
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||||
struct hdmi_avi_infoframe frame;
|
||||
uint32_t offset;
|
||||
ssize_t err;
|
||||
uint32_t val;
|
||||
int bpc = 8;
|
||||
|
||||
if (!dig || !dig->afmt)
|
||||
return;
|
||||
|
@ -306,6 +309,12 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
|
|||
return;
|
||||
offset = dig->afmt->offset;
|
||||
|
||||
/* hdmi deep color mode general control packets setup, if bpc > 8 */
|
||||
if (encoder->crtc) {
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
|
||||
bpc = radeon_crtc->bpc;
|
||||
}
|
||||
|
||||
/* disable audio prior to setting up hw */
|
||||
if (ASIC_IS_DCE6(rdev)) {
|
||||
dig->afmt->pin = dce6_audio_get_pin(rdev);
|
||||
|
@ -322,6 +331,35 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
|
|||
|
||||
WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
|
||||
|
||||
val = RREG32(HDMI_CONTROL + offset);
|
||||
val &= ~HDMI_DEEP_COLOR_ENABLE;
|
||||
val &= ~HDMI_DEEP_COLOR_DEPTH_MASK;
|
||||
|
||||
switch (bpc) {
|
||||
case 0:
|
||||
case 6:
|
||||
case 8:
|
||||
case 16:
|
||||
default:
|
||||
DRM_DEBUG("%s: Disabling hdmi deep color for %d bpc.\n",
|
||||
drm_get_connector_name(connector), bpc);
|
||||
break;
|
||||
case 10:
|
||||
val |= HDMI_DEEP_COLOR_ENABLE;
|
||||
val |= HDMI_DEEP_COLOR_DEPTH(HDMI_30BIT_DEEP_COLOR);
|
||||
DRM_DEBUG("%s: Enabling hdmi deep color 30 for 10 bpc.\n",
|
||||
drm_get_connector_name(connector));
|
||||
break;
|
||||
case 12:
|
||||
val |= HDMI_DEEP_COLOR_ENABLE;
|
||||
val |= HDMI_DEEP_COLOR_DEPTH(HDMI_36BIT_DEEP_COLOR);
|
||||
DRM_DEBUG("%s: Enabling hdmi deep color 36 for 12 bpc.\n",
|
||||
drm_get_connector_name(connector));
|
||||
break;
|
||||
}
|
||||
|
||||
WREG32(HDMI_CONTROL + offset, val);
|
||||
|
||||
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
|
||||
HDMI_NULL_SEND | /* send null packets when required */
|
||||
HDMI_GC_SEND | /* send general control packets */
|
||||
|
@ -348,9 +386,13 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
|
|||
|
||||
/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
|
||||
|
||||
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
|
||||
HDMI_ACR_SOURCE | /* select SW CTS value */
|
||||
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
|
||||
if (bpc > 8)
|
||||
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
|
||||
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
|
||||
else
|
||||
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
|
||||
HDMI_ACR_SOURCE | /* select SW CTS value */
|
||||
HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
|
||||
|
||||
evergreen_hdmi_update_ACR(encoder, mode->clock);
|
||||
|
||||
|
|
|
@ -517,10 +517,11 @@
|
|||
# define HDMI_ERROR_ACK (1 << 8)
|
||||
# define HDMI_ERROR_MASK (1 << 9)
|
||||
# define HDMI_DEEP_COLOR_ENABLE (1 << 24)
|
||||
# define HDMI_DEEP_COLOR_DEPTH (((x) & 3) << 28)
|
||||
# define HDMI_DEEP_COLOR_DEPTH(x) (((x) & 3) << 28)
|
||||
# define HDMI_24BIT_DEEP_COLOR 0
|
||||
# define HDMI_30BIT_DEEP_COLOR 1
|
||||
# define HDMI_36BIT_DEEP_COLOR 2
|
||||
# define HDMI_DEEP_COLOR_DEPTH_MASK (3 << 28)
|
||||
#define HDMI_STATUS 0x7034
|
||||
# define HDMI_ACTIVE_AVMUTE (1 << 0)
|
||||
# define HDMI_AUDIO_PACKET_ERROR (1 << 16)
|
||||
|
|
|
@ -1228,12 +1228,14 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
|
|||
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
|
||||
/* Setup L2 cache */
|
||||
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
|
||||
ENABLE_L2_FRAGMENT_PROCESSING |
|
||||
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
|
||||
ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
|
||||
EFFECTIVE_L2_QUEUE_SIZE(7) |
|
||||
CONTEXT1_IDENTITY_ACCESS_MODE(1));
|
||||
WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
|
||||
WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
|
||||
BANK_SELECT(6) |
|
||||
L2_CACHE_BIGK_FRAGMENT_SIZE(6));
|
||||
/* setup context0 */
|
||||
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
|
||||
|
@ -1266,6 +1268,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
|
|||
(u32)(rdev->dummy_page.addr >> 12));
|
||||
WREG32(VM_CONTEXT1_CNTL2, 4);
|
||||
WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
|
||||
PAGE_TABLE_BLOCK_SIZE(RADEON_VM_BLOCK_SIZE - 9) |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
|
||||
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
#define READ_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 16)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 18)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 19)
|
||||
#define PAGE_TABLE_BLOCK_SIZE(x) (((x) & 0xF) << 24)
|
||||
#define VM_CONTEXT1_CNTL 0x1414
|
||||
#define VM_CONTEXT0_CNTL2 0x1430
|
||||
#define VM_CONTEXT1_CNTL2 0x1434
|
||||
|
|
|
@ -141,36 +141,6 @@ void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* r100_pre_page_flip - pre-pageflip callback.
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc: crtc to prepare for pageflip on
|
||||
*
|
||||
* Pre-pageflip callback (r1xx-r4xx).
|
||||
* Enables the pageflip irq (vblank irq).
|
||||
*/
|
||||
void r100_pre_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* enable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_get(rdev, crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* r100_post_page_flip - pos-pageflip callback.
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc: crtc to cleanup pageflip on
|
||||
*
|
||||
* Post-pageflip callback (r1xx-r4xx).
|
||||
* Disables the pageflip irq (vblank irq).
|
||||
*/
|
||||
void r100_post_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* disable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_put(rdev, crtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* r100_page_flip - pageflip callback.
|
||||
*
|
||||
|
@ -182,9 +152,8 @@ void r100_post_page_flip(struct radeon_device *rdev, int crtc)
|
|||
* During vblank we take the crtc lock and wait for the update_pending
|
||||
* bit to go high, when it does, we release the lock, and allow the
|
||||
* double buffered update to take place.
|
||||
* Returns the current update pending status.
|
||||
*/
|
||||
u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
void r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK;
|
||||
|
@ -206,8 +175,24 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
|||
tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK;
|
||||
WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* r100_page_flip_pending - check if page flip is still pending
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @crtc_id: crtc to check
|
||||
*
|
||||
* Check if the last pagefilp is still pending (r1xx-r4xx).
|
||||
* Returns the current update pending status.
|
||||
*/
|
||||
bool r100_page_flip_pending(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
|
||||
/* Return current update_pending status: */
|
||||
return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET;
|
||||
return !!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) &
|
||||
RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -794,7 +779,7 @@ int r100_irq_process(struct radeon_device *rdev)
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
}
|
||||
if (status & RADEON_CRTC2_VBLANK_STAT) {
|
||||
if (rdev->irq.crtc_vblank_int[1]) {
|
||||
|
@ -803,7 +788,7 @@ int r100_irq_process(struct radeon_device *rdev)
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
}
|
||||
if (status & RADEON_FP_DETECT_STAT) {
|
||||
queue_hotplug = true;
|
||||
|
|
|
@ -3876,7 +3876,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D1 vblank\n");
|
||||
}
|
||||
|
@ -3902,7 +3902,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D2 vblank\n");
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
|
|||
/*
|
||||
* update the N and CTS parameters for a given pixel clock rate
|
||||
*/
|
||||
static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
|
||||
void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
@ -142,21 +142,33 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
|
|||
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
|
||||
uint32_t offset = dig->afmt->offset;
|
||||
|
||||
WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz));
|
||||
WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz);
|
||||
WREG32_P(HDMI0_ACR_32_0 + offset,
|
||||
HDMI0_ACR_CTS_32(acr.cts_32khz),
|
||||
~HDMI0_ACR_CTS_32_MASK);
|
||||
WREG32_P(HDMI0_ACR_32_1 + offset,
|
||||
HDMI0_ACR_N_32(acr.n_32khz),
|
||||
~HDMI0_ACR_N_32_MASK);
|
||||
|
||||
WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz));
|
||||
WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz);
|
||||
WREG32_P(HDMI0_ACR_44_0 + offset,
|
||||
HDMI0_ACR_CTS_44(acr.cts_44_1khz),
|
||||
~HDMI0_ACR_CTS_44_MASK);
|
||||
WREG32_P(HDMI0_ACR_44_1 + offset,
|
||||
HDMI0_ACR_N_44(acr.n_44_1khz),
|
||||
~HDMI0_ACR_N_44_MASK);
|
||||
|
||||
WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz));
|
||||
WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz);
|
||||
WREG32_P(HDMI0_ACR_48_0 + offset,
|
||||
HDMI0_ACR_CTS_48(acr.cts_48khz),
|
||||
~HDMI0_ACR_CTS_48_MASK);
|
||||
WREG32_P(HDMI0_ACR_48_1 + offset,
|
||||
HDMI0_ACR_N_48(acr.n_48khz),
|
||||
~HDMI0_ACR_N_48_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* build a HDMI Video Info Frame
|
||||
*/
|
||||
static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
|
||||
void *buffer, size_t size)
|
||||
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
@ -231,7 +243,7 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
|
|||
/*
|
||||
* write the audio workaround status to the hardware
|
||||
*/
|
||||
static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
|
||||
void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
@ -250,7 +262,7 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
|
|||
value, ~HDMI0_AUDIO_TEST_EN);
|
||||
}
|
||||
|
||||
static void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
|
||||
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
@ -320,121 +332,6 @@ static void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
|
|||
}
|
||||
}
|
||||
|
||||
static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
|
||||
{
|
||||
struct radeon_device *rdev = encoder->dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct radeon_connector *radeon_connector = NULL;
|
||||
u32 tmp;
|
||||
u8 *sadb;
|
||||
int sad_count;
|
||||
|
||||
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
radeon_connector = to_radeon_connector(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radeon_connector) {
|
||||
DRM_ERROR("Couldn't find encoder's connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
|
||||
if (sad_count < 0) {
|
||||
DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
|
||||
return;
|
||||
}
|
||||
|
||||
/* program the speaker allocation */
|
||||
tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
|
||||
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
|
||||
/* set HDMI mode */
|
||||
tmp |= HDMI_CONNECTION;
|
||||
if (sad_count)
|
||||
tmp |= SPEAKER_ALLOCATION(sadb[0]);
|
||||
else
|
||||
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
|
||||
WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
|
||||
|
||||
kfree(sadb);
|
||||
}
|
||||
|
||||
static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
|
||||
{
|
||||
struct radeon_device *rdev = encoder->dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct radeon_connector *radeon_connector = NULL;
|
||||
struct cea_sad *sads;
|
||||
int i, sad_count;
|
||||
|
||||
static const u16 eld_reg_to_type[][2] = {
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
|
||||
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
|
||||
};
|
||||
|
||||
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
radeon_connector = to_radeon_connector(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radeon_connector) {
|
||||
DRM_ERROR("Couldn't find encoder's connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
|
||||
if (sad_count < 0) {
|
||||
DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
|
||||
return;
|
||||
}
|
||||
BUG_ON(!sads);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
|
||||
u32 value = 0;
|
||||
u8 stereo_freqs = 0;
|
||||
int max_channels = -1;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < sad_count; j++) {
|
||||
struct cea_sad *sad = &sads[j];
|
||||
|
||||
if (sad->format == eld_reg_to_type[i][1]) {
|
||||
if (sad->channels > max_channels) {
|
||||
value = MAX_CHANNELS(sad->channels) |
|
||||
DESCRIPTOR_BYTE_2(sad->byte2) |
|
||||
SUPPORTED_FREQUENCIES(sad->freq);
|
||||
max_channels = sad->channels;
|
||||
}
|
||||
|
||||
if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
|
||||
stereo_freqs |= sad->freq;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
|
||||
|
||||
WREG32(eld_reg_to_type[i][0], value);
|
||||
}
|
||||
|
||||
kfree(sads);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the info frames with the data from the current display mode
|
||||
*/
|
||||
|
@ -447,6 +344,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
|
|||
u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
|
||||
struct hdmi_avi_infoframe frame;
|
||||
uint32_t offset;
|
||||
uint32_t acr_ctl;
|
||||
ssize_t err;
|
||||
|
||||
if (!dig || !dig->afmt)
|
||||
|
@ -463,52 +361,44 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
|
|||
|
||||
r600_audio_set_dto(encoder, mode->clock);
|
||||
|
||||
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
|
||||
HDMI0_NULL_SEND); /* send null packets when required */
|
||||
WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
|
||||
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
|
||||
HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
|
||||
~(HDMI0_AUDIO_SAMPLE_SEND |
|
||||
HDMI0_AUDIO_DELAY_EN_MASK |
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
|
||||
HDMI0_60958_CS_UPDATE));
|
||||
|
||||
WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
|
||||
/* DCE 3.0 uses register that's normally for CRC_CONTROL */
|
||||
acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
|
||||
HDMI0_ACR_PACKET_CONTROL;
|
||||
WREG32_P(acr_ctl + offset,
|
||||
HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
|
||||
HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
|
||||
~(HDMI0_ACR_SOURCE |
|
||||
HDMI0_ACR_AUTO_SEND));
|
||||
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
|
||||
WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
|
||||
AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
|
||||
AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
|
||||
} else {
|
||||
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
|
||||
HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
|
||||
HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
|
||||
HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
|
||||
}
|
||||
WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
|
||||
HDMI0_NULL_SEND | /* send null packets when required */
|
||||
HDMI0_GC_SEND | /* send general control packets */
|
||||
HDMI0_GC_CONT); /* send general control packets every frame */
|
||||
|
||||
if (ASIC_IS_DCE32(rdev)) {
|
||||
dce3_2_afmt_write_speaker_allocation(encoder);
|
||||
dce3_2_afmt_write_sad_regs(encoder);
|
||||
}
|
||||
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
|
||||
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
|
||||
HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
|
||||
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
|
||||
HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
|
||||
|
||||
WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
|
||||
HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
|
||||
HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
|
||||
WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
|
||||
HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
|
||||
HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
|
||||
~(HDMI0_AVI_INFO_LINE_MASK |
|
||||
HDMI0_AUDIO_INFO_LINE_MASK));
|
||||
|
||||
WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
|
||||
HDMI0_NULL_SEND | /* send null packets when required */
|
||||
HDMI0_GC_SEND | /* send general control packets */
|
||||
HDMI0_GC_CONT); /* send general control packets every frame */
|
||||
|
||||
/* TODO: HDMI0_AUDIO_INFO_UPDATE */
|
||||
WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
|
||||
HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
|
||||
HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
|
||||
HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
|
||||
HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
|
||||
|
||||
WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
|
||||
HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
|
||||
HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
|
||||
|
||||
WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
|
||||
WREG32_AND(HDMI0_GC + offset,
|
||||
~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */
|
||||
|
||||
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
|
||||
if (err < 0) {
|
||||
|
@ -523,22 +413,45 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
|
|||
}
|
||||
|
||||
r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
|
||||
|
||||
/* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */
|
||||
|
||||
WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset,
|
||||
~(HDMI0_GENERIC0_SEND |
|
||||
HDMI0_GENERIC0_CONT |
|
||||
HDMI0_GENERIC0_UPDATE |
|
||||
HDMI0_GENERIC1_SEND |
|
||||
HDMI0_GENERIC1_CONT |
|
||||
HDMI0_GENERIC0_LINE_MASK |
|
||||
HDMI0_GENERIC1_LINE_MASK));
|
||||
|
||||
r600_hdmi_update_ACR(encoder, mode->clock);
|
||||
|
||||
WREG32_P(HDMI0_60958_0 + offset,
|
||||
HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
|
||||
~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
|
||||
HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
|
||||
|
||||
WREG32_P(HDMI0_60958_1 + offset,
|
||||
HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
|
||||
~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
|
||||
|
||||
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
|
||||
WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
|
||||
WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
|
||||
WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
|
||||
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
|
||||
|
||||
r600_hdmi_audio_workaround(encoder);
|
||||
|
||||
/* enable audio after to setting up hw */
|
||||
r600_audio_enable(rdev, dig->afmt->pin, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* update settings with current parameters from audio engine
|
||||
/**
|
||||
* r600_hdmi_update_audio_settings - Update audio infoframe
|
||||
*
|
||||
* @encoder: drm encoder
|
||||
*
|
||||
* Gets info about current audio stream and updates audio infoframe.
|
||||
*/
|
||||
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
|
||||
{
|
||||
|
@ -550,7 +463,7 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
|
|||
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
|
||||
struct hdmi_audio_infoframe frame;
|
||||
uint32_t offset;
|
||||
uint32_t iec;
|
||||
uint32_t value;
|
||||
ssize_t err;
|
||||
|
||||
if (!dig->afmt || !dig->afmt->enabled)
|
||||
|
@ -563,60 +476,6 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
|
|||
DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n",
|
||||
(int)audio.status_bits, (int)audio.category_code);
|
||||
|
||||
iec = 0;
|
||||
if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL)
|
||||
iec |= 1 << 0;
|
||||
if (audio.status_bits & AUDIO_STATUS_NONAUDIO)
|
||||
iec |= 1 << 1;
|
||||
if (audio.status_bits & AUDIO_STATUS_COPYRIGHT)
|
||||
iec |= 1 << 2;
|
||||
if (audio.status_bits & AUDIO_STATUS_EMPHASIS)
|
||||
iec |= 1 << 3;
|
||||
|
||||
iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code);
|
||||
|
||||
switch (audio.rate) {
|
||||
case 32000:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3);
|
||||
break;
|
||||
case 44100:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0);
|
||||
break;
|
||||
case 48000:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2);
|
||||
break;
|
||||
case 88200:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8);
|
||||
break;
|
||||
case 96000:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa);
|
||||
break;
|
||||
case 176400:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc);
|
||||
break;
|
||||
case 192000:
|
||||
iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe);
|
||||
break;
|
||||
}
|
||||
|
||||
WREG32(HDMI0_60958_0 + offset, iec);
|
||||
|
||||
iec = 0;
|
||||
switch (audio.bits_per_sample) {
|
||||
case 16:
|
||||
iec |= HDMI0_60958_CS_WORD_LENGTH(0x2);
|
||||
break;
|
||||
case 20:
|
||||
iec |= HDMI0_60958_CS_WORD_LENGTH(0x3);
|
||||
break;
|
||||
case 24:
|
||||
iec |= HDMI0_60958_CS_WORD_LENGTH(0xb);
|
||||
break;
|
||||
}
|
||||
if (audio.status_bits & AUDIO_STATUS_V)
|
||||
iec |= 0x5 << 16;
|
||||
WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f);
|
||||
|
||||
err = hdmi_audio_infoframe_init(&frame);
|
||||
if (err < 0) {
|
||||
DRM_ERROR("failed to setup audio infoframe\n");
|
||||
|
@ -631,8 +490,22 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
|
|||
return;
|
||||
}
|
||||
|
||||
value = RREG32(HDMI0_AUDIO_PACKET_CONTROL + offset);
|
||||
if (value & HDMI0_AUDIO_TEST_EN)
|
||||
WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
|
||||
value & ~HDMI0_AUDIO_TEST_EN);
|
||||
|
||||
WREG32_OR(HDMI0_CONTROL + offset,
|
||||
HDMI0_ERROR_ACK);
|
||||
|
||||
WREG32_AND(HDMI0_INFOFRAME_CONTROL0 + offset,
|
||||
~HDMI0_AUDIO_INFO_SOURCE);
|
||||
|
||||
r600_hdmi_update_audio_infoframe(encoder, buffer, sizeof(buffer));
|
||||
r600_hdmi_audio_workaround(encoder);
|
||||
|
||||
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
|
||||
HDMI0_AUDIO_INFO_CONT |
|
||||
HDMI0_AUDIO_INFO_UPDATE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1029,15 +1029,18 @@
|
|||
#define HDMI0_AUDIO_PACKET_CONTROL 0x7408
|
||||
# define HDMI0_AUDIO_SAMPLE_SEND (1 << 0)
|
||||
# define HDMI0_AUDIO_DELAY_EN(x) (((x) & 3) << 4)
|
||||
# define HDMI0_AUDIO_DELAY_EN_MASK (3 << 4)
|
||||
# define HDMI0_AUDIO_SEND_MAX_PACKETS (1 << 8)
|
||||
# define HDMI0_AUDIO_TEST_EN (1 << 12)
|
||||
# define HDMI0_AUDIO_PACKETS_PER_LINE(x) (((x) & 0x1f) << 16)
|
||||
# define HDMI0_AUDIO_PACKETS_PER_LINE_MASK (0x1f << 16)
|
||||
# define HDMI0_AUDIO_CHANNEL_SWAP (1 << 24)
|
||||
# define HDMI0_60958_CS_UPDATE (1 << 26)
|
||||
# define HDMI0_AZ_FORMAT_WTRIG_MASK (1 << 28)
|
||||
# define HDMI0_AZ_FORMAT_WTRIG_ACK (1 << 29)
|
||||
#define HDMI0_AUDIO_CRC_CONTROL 0x740c
|
||||
# define HDMI0_AUDIO_CRC_EN (1 << 0)
|
||||
#define DCE3_HDMI0_ACR_PACKET_CONTROL 0x740c
|
||||
#define HDMI0_VBI_PACKET_CONTROL 0x7410
|
||||
# define HDMI0_NULL_SEND (1 << 0)
|
||||
# define HDMI0_GC_SEND (1 << 4)
|
||||
|
@ -1054,7 +1057,9 @@
|
|||
# define HDMI0_MPEG_INFO_UPDATE (1 << 10)
|
||||
#define HDMI0_INFOFRAME_CONTROL1 0x7418
|
||||
# define HDMI0_AVI_INFO_LINE(x) (((x) & 0x3f) << 0)
|
||||
# define HDMI0_AVI_INFO_LINE_MASK (0x3f << 0)
|
||||
# define HDMI0_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8)
|
||||
# define HDMI0_AUDIO_INFO_LINE_MASK (0x3f << 8)
|
||||
# define HDMI0_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16)
|
||||
#define HDMI0_GENERIC_PACKET_CONTROL 0x741c
|
||||
# define HDMI0_GENERIC0_SEND (1 << 0)
|
||||
|
@ -1063,7 +1068,9 @@
|
|||
# define HDMI0_GENERIC1_SEND (1 << 4)
|
||||
# define HDMI0_GENERIC1_CONT (1 << 5)
|
||||
# define HDMI0_GENERIC0_LINE(x) (((x) & 0x3f) << 16)
|
||||
# define HDMI0_GENERIC0_LINE_MASK (0x3f << 16)
|
||||
# define HDMI0_GENERIC1_LINE(x) (((x) & 0x3f) << 24)
|
||||
# define HDMI0_GENERIC1_LINE_MASK (0x3f << 24)
|
||||
#define HDMI0_GC 0x7428
|
||||
# define HDMI0_GC_AVMUTE (1 << 0)
|
||||
#define HDMI0_AVI_INFO0 0x7454
|
||||
|
@ -1119,16 +1126,22 @@
|
|||
#define HDMI0_GENERIC1_6 0x74a8
|
||||
#define HDMI0_ACR_32_0 0x74ac
|
||||
# define HDMI0_ACR_CTS_32(x) (((x) & 0xfffff) << 12)
|
||||
# define HDMI0_ACR_CTS_32_MASK (0xfffff << 12)
|
||||
#define HDMI0_ACR_32_1 0x74b0
|
||||
# define HDMI0_ACR_N_32(x) (((x) & 0xfffff) << 0)
|
||||
# define HDMI0_ACR_N_32_MASK (0xfffff << 0)
|
||||
#define HDMI0_ACR_44_0 0x74b4
|
||||
# define HDMI0_ACR_CTS_44(x) (((x) & 0xfffff) << 12)
|
||||
# define HDMI0_ACR_CTS_44_MASK (0xfffff << 12)
|
||||
#define HDMI0_ACR_44_1 0x74b8
|
||||
# define HDMI0_ACR_N_44(x) (((x) & 0xfffff) << 0)
|
||||
# define HDMI0_ACR_N_44_MASK (0xfffff << 0)
|
||||
#define HDMI0_ACR_48_0 0x74bc
|
||||
# define HDMI0_ACR_CTS_48(x) (((x) & 0xfffff) << 12)
|
||||
# define HDMI0_ACR_CTS_48_MASK (0xfffff << 12)
|
||||
#define HDMI0_ACR_48_1 0x74c0
|
||||
# define HDMI0_ACR_N_48(x) (((x) & 0xfffff) << 0)
|
||||
# define HDMI0_ACR_N_48_MASK (0xfffff << 0)
|
||||
#define HDMI0_ACR_STATUS_0 0x74c4
|
||||
#define HDMI0_ACR_STATUS_1 0x74c8
|
||||
#define HDMI0_AUDIO_INFO0 0x74cc
|
||||
|
@ -1148,14 +1161,17 @@
|
|||
# define HDMI0_60958_CS_CATEGORY_CODE(x) (((x) & 0xff) << 8)
|
||||
# define HDMI0_60958_CS_SOURCE_NUMBER(x) (((x) & 0xf) << 16)
|
||||
# define HDMI0_60958_CS_CHANNEL_NUMBER_L(x) (((x) & 0xf) << 20)
|
||||
# define HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK (0xf << 20)
|
||||
# define HDMI0_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
|
||||
# define HDMI0_60958_CS_CLOCK_ACCURACY(x) (((x) & 3) << 28)
|
||||
# define HDMI0_60958_CS_CLOCK_ACCURACY_MASK (3 << 28)
|
||||
#define HDMI0_60958_1 0x74d8
|
||||
# define HDMI0_60958_CS_WORD_LENGTH(x) (((x) & 0xf) << 0)
|
||||
# define HDMI0_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 4)
|
||||
# define HDMI0_60958_CS_VALID_L(x) (((x) & 1) << 16)
|
||||
# define HDMI0_60958_CS_VALID_R(x) (((x) & 1) << 18)
|
||||
# define HDMI0_60958_CS_CHANNEL_NUMBER_R(x) (((x) & 0xf) << 20)
|
||||
# define HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK (0xf << 20)
|
||||
#define HDMI0_ACR_PACKET_CONTROL 0x74dc
|
||||
# define HDMI0_ACR_SEND (1 << 0)
|
||||
# define HDMI0_ACR_CONT (1 << 1)
|
||||
|
@ -1166,6 +1182,7 @@
|
|||
# define HDMI0_ACR_48 3
|
||||
# define HDMI0_ACR_SOURCE (1 << 8) /* 0 - hw; 1 - cts value */
|
||||
# define HDMI0_ACR_AUTO_SEND (1 << 12)
|
||||
#define DCE3_HDMI0_AUDIO_CRC_CONTROL 0x74dc
|
||||
#define HDMI0_RAMP_CONTROL0 0x74e0
|
||||
# define HDMI0_RAMP_MAX_COUNT(x) (((x) & 0xffffff) << 0)
|
||||
#define HDMI0_RAMP_CONTROL1 0x74e4
|
||||
|
|
|
@ -676,14 +676,16 @@ void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
|
|||
* IRQS.
|
||||
*/
|
||||
|
||||
struct radeon_unpin_work {
|
||||
struct work_struct work;
|
||||
struct radeon_device *rdev;
|
||||
int crtc_id;
|
||||
struct radeon_fence *fence;
|
||||
struct radeon_flip_work {
|
||||
struct work_struct flip_work;
|
||||
struct work_struct unpin_work;
|
||||
struct radeon_device *rdev;
|
||||
int crtc_id;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct radeon_bo *old_rbo;
|
||||
u64 new_crtc_base;
|
||||
struct radeon_bo *old_rbo;
|
||||
struct radeon_bo *new_rbo;
|
||||
struct radeon_fence *fence;
|
||||
};
|
||||
|
||||
struct r500_irq_stat_regs {
|
||||
|
@ -848,6 +850,15 @@ struct radeon_mec {
|
|||
#define R600_PTE_READABLE (1 << 5)
|
||||
#define R600_PTE_WRITEABLE (1 << 6)
|
||||
|
||||
/* PTE (Page Table Entry) fragment field for different page sizes */
|
||||
#define R600_PTE_FRAG_4KB (0 << 7)
|
||||
#define R600_PTE_FRAG_64KB (4 << 7)
|
||||
#define R600_PTE_FRAG_256KB (6 << 7)
|
||||
|
||||
/* flags used for GART page table entries on R600+ */
|
||||
#define R600_PTE_GART ( R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED \
|
||||
| R600_PTE_READABLE | R600_PTE_WRITEABLE)
|
||||
|
||||
struct radeon_vm_pt {
|
||||
struct radeon_bo *bo;
|
||||
uint64_t addr;
|
||||
|
@ -1876,9 +1887,8 @@ struct radeon_asic {
|
|||
} dpm;
|
||||
/* pageflipping */
|
||||
struct {
|
||||
void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
|
||||
u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
void (*post_page_flip)(struct radeon_device *rdev, int crtc);
|
||||
void (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
bool (*page_flip_pending)(struct radeon_device *rdev, int crtc);
|
||||
} pflip;
|
||||
};
|
||||
|
||||
|
@ -2737,9 +2747,8 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
|
|||
#define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))
|
||||
#define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))
|
||||
#define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev))
|
||||
#define radeon_pre_page_flip(rdev, crtc) (rdev)->asic->pflip.pre_page_flip((rdev), (crtc))
|
||||
#define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base))
|
||||
#define radeon_post_page_flip(rdev, crtc) (rdev)->asic->pflip.post_page_flip((rdev), (crtc))
|
||||
#define radeon_page_flip_pending(rdev, crtc) (rdev)->asic->pflip.page_flip_pending((rdev), (crtc))
|
||||
#define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc))
|
||||
#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
|
||||
#define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
|
||||
|
|
|
@ -117,9 +117,6 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
|
|||
/* ATI Host Bridge / RV280 [M9+] Needs AGPMode 1 (phoronix forum) */
|
||||
{ PCI_VENDOR_ID_ATI, 0xcbb2, PCI_VENDOR_ID_ATI, 0x5c61,
|
||||
PCI_VENDOR_ID_SONY, 0x8175, 1},
|
||||
/* HP Host Bridge / R300 [FireGL X1] Needs AGPMode 2 (fdo #7770) */
|
||||
{ PCI_VENDOR_ID_HP, 0x122e, PCI_VENDOR_ID_ATI, 0x4e47,
|
||||
PCI_VENDOR_ID_ATI, 0x0152, 2},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -248,9 +248,8 @@ static struct radeon_asic r100_asic = {
|
|||
.set_clock_gating = &radeon_legacy_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -315,9 +314,8 @@ static struct radeon_asic r200_asic = {
|
|||
.set_clock_gating = &radeon_legacy_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -396,9 +394,8 @@ static struct radeon_asic r300_asic = {
|
|||
.set_clock_gating = &radeon_legacy_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -463,9 +460,8 @@ static struct radeon_asic r300_asic_pcie = {
|
|||
.set_clock_gating = &radeon_legacy_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -530,9 +526,8 @@ static struct radeon_asic r420_asic = {
|
|||
.set_clock_gating = &radeon_atom_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -597,9 +592,8 @@ static struct radeon_asic rs400_asic = {
|
|||
.set_clock_gating = &radeon_legacy_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &r100_pre_page_flip,
|
||||
.page_flip = &r100_page_flip,
|
||||
.post_page_flip = &r100_post_page_flip,
|
||||
.page_flip_pending = &r100_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -666,9 +660,8 @@ static struct radeon_asic rs600_asic = {
|
|||
.set_clock_gating = &radeon_atom_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -735,9 +728,8 @@ static struct radeon_asic rs690_asic = {
|
|||
.set_clock_gating = &radeon_atom_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -802,9 +794,8 @@ static struct radeon_asic rv515_asic = {
|
|||
.set_clock_gating = &radeon_atom_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -869,9 +860,8 @@ static struct radeon_asic r520_asic = {
|
|||
.set_clock_gating = &radeon_atom_set_clock_gating,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -968,9 +958,8 @@ static struct radeon_asic r600_asic = {
|
|||
.get_temperature = &rv6xx_get_temp,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1059,9 +1048,8 @@ static struct radeon_asic rv6xx_asic = {
|
|||
.force_performance_level = &rv6xx_dpm_force_performance_level,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1150,9 +1138,8 @@ static struct radeon_asic rs780_asic = {
|
|||
.force_performance_level = &rs780_dpm_force_performance_level,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rs600_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rs600_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1201,7 +1188,7 @@ static struct radeon_asic rv770_asic = {
|
|||
.set_backlight_level = &atombios_set_backlight_level,
|
||||
.get_backlight_level = &atombios_get_backlight_level,
|
||||
.hdmi_enable = &r600_hdmi_enable,
|
||||
.hdmi_setmode = &r600_hdmi_setmode,
|
||||
.hdmi_setmode = &dce3_1_hdmi_setmode,
|
||||
},
|
||||
.copy = {
|
||||
.blit = &r600_copy_cpdma,
|
||||
|
@ -1256,9 +1243,8 @@ static struct radeon_asic rv770_asic = {
|
|||
.vblank_too_short = &rv770_dpm_vblank_too_short,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &rs600_pre_page_flip,
|
||||
.page_flip = &rv770_page_flip,
|
||||
.post_page_flip = &rs600_post_page_flip,
|
||||
.page_flip_pending = &rv770_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1375,9 +1361,8 @@ static struct radeon_asic evergreen_asic = {
|
|||
.vblank_too_short = &cypress_dpm_vblank_too_short,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1467,9 +1452,8 @@ static struct radeon_asic sumo_asic = {
|
|||
.force_performance_level = &sumo_dpm_force_performance_level,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1560,9 +1544,8 @@ static struct radeon_asic btc_asic = {
|
|||
.vblank_too_short = &btc_dpm_vblank_too_short,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1704,9 +1687,8 @@ static struct radeon_asic cayman_asic = {
|
|||
.vblank_too_short = &ni_dpm_vblank_too_short,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1805,9 +1787,8 @@ static struct radeon_asic trinity_asic = {
|
|||
.enable_bapm = &trinity_dpm_enable_bapm,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1936,9 +1917,8 @@ static struct radeon_asic si_asic = {
|
|||
.vblank_too_short = &ni_dpm_vblank_too_short,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2099,9 +2079,8 @@ static struct radeon_asic ci_asic = {
|
|||
.powergate_uvd = &ci_dpm_powergate_uvd,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2204,9 +2183,8 @@ static struct radeon_asic kv_asic = {
|
|||
.enable_bapm = &kv_dpm_enable_bapm,
|
||||
},
|
||||
.pflip = {
|
||||
.pre_page_flip = &evergreen_pre_page_flip,
|
||||
.page_flip = &evergreen_page_flip,
|
||||
.post_page_flip = &evergreen_post_page_flip,
|
||||
.page_flip_pending = &evergreen_page_flip_pending,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -135,9 +135,9 @@ extern void r100_pm_prepare(struct radeon_device *rdev);
|
|||
extern void r100_pm_finish(struct radeon_device *rdev);
|
||||
extern void r100_pm_init_profile(struct radeon_device *rdev);
|
||||
extern void r100_pm_get_dynpm_state(struct radeon_device *rdev);
|
||||
extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern void r100_page_flip(struct radeon_device *rdev, int crtc,
|
||||
u64 crtc_base);
|
||||
extern bool r100_page_flip_pending(struct radeon_device *rdev, int crtc);
|
||||
extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc);
|
||||
extern int r100_mc_wait_for_idle(struct radeon_device *rdev);
|
||||
|
||||
|
@ -241,9 +241,9 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev,
|
|||
extern void rs600_pm_misc(struct radeon_device *rdev);
|
||||
extern void rs600_pm_prepare(struct radeon_device *rdev);
|
||||
extern void rs600_pm_finish(struct radeon_device *rdev);
|
||||
extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern void rs600_page_flip(struct radeon_device *rdev, int crtc,
|
||||
u64 crtc_base);
|
||||
extern bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc);
|
||||
void rs600_set_safe_registers(struct radeon_device *rdev);
|
||||
extern void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc);
|
||||
extern int rs600_mc_wait_for_idle(struct radeon_device *rdev);
|
||||
|
@ -387,6 +387,11 @@ void r600_rlc_stop(struct radeon_device *rdev);
|
|||
int r600_audio_init(struct radeon_device *rdev);
|
||||
struct r600_audio_pin r600_audio_status(struct radeon_device *rdev);
|
||||
void r600_audio_fini(struct radeon_device *rdev);
|
||||
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
|
||||
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
|
||||
size_t size);
|
||||
void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock);
|
||||
void r600_hdmi_audio_workaround(struct drm_encoder *encoder);
|
||||
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
|
||||
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
|
||||
void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
|
||||
|
@ -447,7 +452,8 @@ void rv770_fini(struct radeon_device *rdev);
|
|||
int rv770_suspend(struct radeon_device *rdev);
|
||||
int rv770_resume(struct radeon_device *rdev);
|
||||
void rv770_pm_misc(struct radeon_device *rdev);
|
||||
u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
void rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc);
|
||||
void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
|
||||
void r700_cp_stop(struct radeon_device *rdev);
|
||||
void r700_cp_fini(struct radeon_device *rdev);
|
||||
|
@ -458,6 +464,8 @@ int rv770_copy_dma(struct radeon_device *rdev,
|
|||
u32 rv770_get_xclk(struct radeon_device *rdev);
|
||||
int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
|
||||
int rv770_get_temp(struct radeon_device *rdev);
|
||||
/* hdmi */
|
||||
void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
|
||||
/* rv7xx pm */
|
||||
int rv770_dpm_init(struct radeon_device *rdev);
|
||||
int rv770_dpm_enable(struct radeon_device *rdev);
|
||||
|
@ -513,9 +521,9 @@ extern void sumo_pm_init_profile(struct radeon_device *rdev);
|
|||
extern void btc_pm_init_profile(struct radeon_device *rdev);
|
||||
int sumo_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
|
||||
int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
|
||||
extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
|
||||
extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc);
|
||||
extern void evergreen_page_flip(struct radeon_device *rdev, int crtc,
|
||||
u64 crtc_base);
|
||||
extern bool evergreen_page_flip_pending(struct radeon_device *rdev, int crtc);
|
||||
extern void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc);
|
||||
void evergreen_disable_interrupt_state(struct radeon_device *rdev);
|
||||
int evergreen_mc_wait_for_idle(struct radeon_device *rdev);
|
||||
|
|
|
@ -145,6 +145,31 @@ int radeon_get_monitor_bpc(struct drm_connector *connector)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
|
||||
/* hdmi deep color only implemented on DCE4+ */
|
||||
if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) {
|
||||
DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n",
|
||||
drm_get_connector_name(connector), bpc);
|
||||
bpc = 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
|
||||
* much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
|
||||
* 12 bpc is always supported on hdmi deep color sinks, as this is
|
||||
* required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
|
||||
*/
|
||||
if (bpc > 12) {
|
||||
DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
|
||||
drm_get_connector_name(connector), bpc);
|
||||
bpc = 12;
|
||||
}
|
||||
}
|
||||
|
||||
DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
|
||||
drm_get_connector_name(connector), connector->display_info.bpc, bpc);
|
||||
|
||||
return bpc;
|
||||
}
|
||||
|
||||
|
@ -1387,7 +1412,7 @@ bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
|
|||
struct radeon_device *rdev = dev->dev_private;
|
||||
|
||||
if (ASIC_IS_DCE5(rdev) &&
|
||||
(rdev->clock.dp_extclk >= 53900) &&
|
||||
(rdev->clock.default_dispclk >= 53900) &&
|
||||
radeon_connector_encoder_is_hbr2(connector)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -249,16 +249,21 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc)
|
|||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
destroy_workqueue(radeon_crtc->flip_queue);
|
||||
kfree(radeon_crtc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle unpin events outside the interrupt handler proper.
|
||||
/**
|
||||
* radeon_unpin_work_func - unpin old buffer object
|
||||
*
|
||||
* @__work - kernel work item
|
||||
*
|
||||
* Unpin the old frame buffer object outside of the interrupt handler
|
||||
*/
|
||||
static void radeon_unpin_work_func(struct work_struct *__work)
|
||||
{
|
||||
struct radeon_unpin_work *work =
|
||||
container_of(__work, struct radeon_unpin_work, work);
|
||||
struct radeon_flip_work *work =
|
||||
container_of(__work, struct radeon_flip_work, unpin_work);
|
||||
int r;
|
||||
|
||||
/* unpin of the old buffer */
|
||||
|
@ -276,33 +281,22 @@ static void radeon_unpin_work_func(struct work_struct *__work)
|
|||
kfree(work);
|
||||
}
|
||||
|
||||
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
|
||||
void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
struct radeon_unpin_work *work;
|
||||
struct radeon_flip_work *work;
|
||||
unsigned long flags;
|
||||
u32 update_pending;
|
||||
int vpos, hpos;
|
||||
|
||||
spin_lock_irqsave(&rdev->ddev->event_lock, flags);
|
||||
work = radeon_crtc->unpin_work;
|
||||
if (work == NULL ||
|
||||
(work->fence && !radeon_fence_signaled(work->fence))) {
|
||||
work = radeon_crtc->flip_work;
|
||||
if (work == NULL) {
|
||||
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
|
||||
return;
|
||||
}
|
||||
/* New pageflip, or just completion of a previous one? */
|
||||
if (!radeon_crtc->deferred_flip_completion) {
|
||||
/* do the flip (mmio) */
|
||||
update_pending = radeon_page_flip(rdev, crtc_id, work->new_crtc_base);
|
||||
} else {
|
||||
/* This is just a completion of a flip queued in crtc
|
||||
* at last invocation. Make sure we go directly to
|
||||
* completion routine.
|
||||
*/
|
||||
update_pending = 0;
|
||||
radeon_crtc->deferred_flip_completion = 0;
|
||||
}
|
||||
|
||||
update_pending = radeon_page_flip_pending(rdev, crtc_id);
|
||||
|
||||
/* Has the pageflip already completed in crtc, or is it certain
|
||||
* to complete in this vblank?
|
||||
|
@ -320,19 +314,38 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
|
|||
*/
|
||||
update_pending = 0;
|
||||
}
|
||||
if (update_pending) {
|
||||
/* crtc didn't flip in this target vblank interval,
|
||||
* but flip is pending in crtc. It will complete it
|
||||
* in next vblank interval, so complete the flip at
|
||||
* next vblank irq.
|
||||
*/
|
||||
radeon_crtc->deferred_flip_completion = 1;
|
||||
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
|
||||
if (!update_pending)
|
||||
radeon_crtc_handle_flip(rdev, crtc_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_crtc_handle_flip - page flip completed
|
||||
*
|
||||
* @rdev: radeon device pointer
|
||||
* @crtc_id: crtc number this event is for
|
||||
*
|
||||
* Called when we are sure that a page flip for this crtc is completed.
|
||||
*/
|
||||
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
struct radeon_flip_work *work;
|
||||
unsigned long flags;
|
||||
|
||||
/* this can happen at init */
|
||||
if (radeon_crtc == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&rdev->ddev->event_lock, flags);
|
||||
work = radeon_crtc->flip_work;
|
||||
if (work == NULL) {
|
||||
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pageflip (will be) certainly completed in this vblank. Clean up. */
|
||||
radeon_crtc->unpin_work = NULL;
|
||||
/* Pageflip completed. Clean up. */
|
||||
radeon_crtc->flip_work = NULL;
|
||||
|
||||
/* wakeup userspace */
|
||||
if (work->event)
|
||||
|
@ -340,86 +353,71 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
|
|||
|
||||
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
|
||||
|
||||
drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id);
|
||||
radeon_fence_unref(&work->fence);
|
||||
radeon_post_page_flip(work->rdev, work->crtc_id);
|
||||
schedule_work(&work->work);
|
||||
radeon_irq_kms_pflip_irq_get(rdev, work->crtc_id);
|
||||
queue_work(radeon_crtc->flip_queue, &work->unpin_work);
|
||||
}
|
||||
|
||||
static int radeon_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags)
|
||||
/**
|
||||
* radeon_flip_work_func - page flip framebuffer
|
||||
*
|
||||
* @work - kernel work item
|
||||
*
|
||||
* Wait for the buffer object to become idle and do the actual page flip
|
||||
*/
|
||||
static void radeon_flip_work_func(struct work_struct *__work)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
struct radeon_framebuffer *old_radeon_fb;
|
||||
struct radeon_framebuffer *new_radeon_fb;
|
||||
struct drm_gem_object *obj;
|
||||
struct radeon_bo *rbo;
|
||||
struct radeon_unpin_work *work;
|
||||
struct radeon_flip_work *work =
|
||||
container_of(__work, struct radeon_flip_work, flip_work);
|
||||
struct radeon_device *rdev = work->rdev;
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id];
|
||||
|
||||
struct drm_crtc *crtc = &radeon_crtc->base;
|
||||
struct drm_framebuffer *fb = work->fb;
|
||||
|
||||
uint32_t tiling_flags, pitch_pixels;
|
||||
uint64_t base;
|
||||
|
||||
unsigned long flags;
|
||||
u32 tiling_flags, pitch_pixels;
|
||||
u64 base;
|
||||
int r;
|
||||
|
||||
work = kzalloc(sizeof *work, GFP_KERNEL);
|
||||
if (work == NULL)
|
||||
return -ENOMEM;
|
||||
down_read(&rdev->exclusive_lock);
|
||||
while (work->fence) {
|
||||
r = radeon_fence_wait(work->fence, false);
|
||||
if (r == -EDEADLK) {
|
||||
up_read(&rdev->exclusive_lock);
|
||||
r = radeon_gpu_reset(rdev);
|
||||
down_read(&rdev->exclusive_lock);
|
||||
}
|
||||
|
||||
work->event = event;
|
||||
work->rdev = rdev;
|
||||
work->crtc_id = radeon_crtc->crtc_id;
|
||||
old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
|
||||
new_radeon_fb = to_radeon_framebuffer(fb);
|
||||
/* schedule unpin of the old buffer */
|
||||
obj = old_radeon_fb->obj;
|
||||
/* take a reference to the old object */
|
||||
drm_gem_object_reference(obj);
|
||||
rbo = gem_to_radeon_bo(obj);
|
||||
work->old_rbo = rbo;
|
||||
obj = new_radeon_fb->obj;
|
||||
rbo = gem_to_radeon_bo(obj);
|
||||
|
||||
spin_lock(&rbo->tbo.bdev->fence_lock);
|
||||
if (rbo->tbo.sync_obj)
|
||||
work->fence = radeon_fence_ref(rbo->tbo.sync_obj);
|
||||
spin_unlock(&rbo->tbo.bdev->fence_lock);
|
||||
|
||||
INIT_WORK(&work->work, radeon_unpin_work_func);
|
||||
|
||||
/* We borrow the event spin lock for protecting unpin_work */
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (radeon_crtc->unpin_work) {
|
||||
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
|
||||
r = -EBUSY;
|
||||
goto unlock_free;
|
||||
if (r) {
|
||||
DRM_ERROR("failed to wait on page flip fence (%d)!\n",
|
||||
r);
|
||||
goto cleanup;
|
||||
} else
|
||||
radeon_fence_unref(&work->fence);
|
||||
}
|
||||
radeon_crtc->unpin_work = work;
|
||||
radeon_crtc->deferred_flip_completion = 0;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
/* pin the new buffer */
|
||||
DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n",
|
||||
work->old_rbo, rbo);
|
||||
work->old_rbo, work->new_rbo);
|
||||
|
||||
r = radeon_bo_reserve(rbo, false);
|
||||
r = radeon_bo_reserve(work->new_rbo, false);
|
||||
if (unlikely(r != 0)) {
|
||||
DRM_ERROR("failed to reserve new rbo buffer before flip\n");
|
||||
goto pflip_cleanup;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Only 27 bit offset for legacy CRTC */
|
||||
r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM,
|
||||
r = radeon_bo_pin_restricted(work->new_rbo, RADEON_GEM_DOMAIN_VRAM,
|
||||
ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, &base);
|
||||
if (unlikely(r != 0)) {
|
||||
radeon_bo_unreserve(rbo);
|
||||
radeon_bo_unreserve(work->new_rbo);
|
||||
r = -EINVAL;
|
||||
DRM_ERROR("failed to pin new rbo buffer before flip\n");
|
||||
goto pflip_cleanup;
|
||||
goto cleanup;
|
||||
}
|
||||
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
|
||||
radeon_bo_unreserve(rbo);
|
||||
radeon_bo_get_tiling_flags(work->new_rbo, &tiling_flags, NULL);
|
||||
radeon_bo_unreserve(work->new_rbo);
|
||||
|
||||
if (!ASIC_IS_AVIVO(rdev)) {
|
||||
/* crtc offset is from display base addr not FB location */
|
||||
|
@ -457,44 +455,91 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
|
|||
base &= ~7;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
work->new_crtc_base = base;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
/* We borrow the event spin lock for protecting flip_work */
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
|
||||
/* set the proper interrupt */
|
||||
radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id);
|
||||
|
||||
/* do the flip (mmio) */
|
||||
radeon_page_flip(rdev, radeon_crtc->crtc_id, base);
|
||||
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
up_read(&rdev->exclusive_lock);
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
|
||||
radeon_fence_unref(&work->fence);
|
||||
kfree(work);
|
||||
up_read(&rdev->exclusive_lock);
|
||||
}
|
||||
|
||||
static int radeon_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
|
||||
struct radeon_framebuffer *old_radeon_fb;
|
||||
struct radeon_framebuffer *new_radeon_fb;
|
||||
struct drm_gem_object *obj;
|
||||
struct radeon_flip_work *work;
|
||||
unsigned long flags;
|
||||
|
||||
work = kzalloc(sizeof *work, GFP_KERNEL);
|
||||
if (work == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&work->flip_work, radeon_flip_work_func);
|
||||
INIT_WORK(&work->unpin_work, radeon_unpin_work_func);
|
||||
|
||||
work->rdev = rdev;
|
||||
work->crtc_id = radeon_crtc->crtc_id;
|
||||
work->fb = fb;
|
||||
work->event = event;
|
||||
|
||||
/* schedule unpin of the old buffer */
|
||||
old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
|
||||
obj = old_radeon_fb->obj;
|
||||
|
||||
/* take a reference to the old object */
|
||||
drm_gem_object_reference(obj);
|
||||
work->old_rbo = gem_to_radeon_bo(obj);
|
||||
|
||||
new_radeon_fb = to_radeon_framebuffer(fb);
|
||||
obj = new_radeon_fb->obj;
|
||||
work->new_rbo = gem_to_radeon_bo(obj);
|
||||
|
||||
spin_lock(&work->new_rbo->tbo.bdev->fence_lock);
|
||||
if (work->new_rbo->tbo.sync_obj)
|
||||
work->fence = radeon_fence_ref(work->new_rbo->tbo.sync_obj);
|
||||
spin_unlock(&work->new_rbo->tbo.bdev->fence_lock);
|
||||
|
||||
/* update crtc fb */
|
||||
crtc->primary->fb = fb;
|
||||
|
||||
r = drm_vblank_get(dev, radeon_crtc->crtc_id);
|
||||
if (r) {
|
||||
DRM_ERROR("failed to get vblank before flip\n");
|
||||
goto pflip_cleanup1;
|
||||
}
|
||||
/* We borrow the event spin lock for protecting flip_work */
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
|
||||
/* set the proper interrupt */
|
||||
radeon_pre_page_flip(rdev, radeon_crtc->crtc_id);
|
||||
if (radeon_crtc->flip_work) {
|
||||
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
|
||||
radeon_fence_unref(&work->fence);
|
||||
kfree(work);
|
||||
return -EBUSY;
|
||||
}
|
||||
radeon_crtc->flip_work = work;
|
||||
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
|
||||
queue_work(radeon_crtc->flip_queue, &work->flip_work);
|
||||
|
||||
return 0;
|
||||
|
||||
pflip_cleanup1:
|
||||
if (unlikely(radeon_bo_reserve(rbo, false) != 0)) {
|
||||
DRM_ERROR("failed to reserve new rbo in error path\n");
|
||||
goto pflip_cleanup;
|
||||
}
|
||||
if (unlikely(radeon_bo_unpin(rbo) != 0)) {
|
||||
DRM_ERROR("failed to unpin new rbo in error path\n");
|
||||
}
|
||||
radeon_bo_unreserve(rbo);
|
||||
|
||||
pflip_cleanup:
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
radeon_crtc->unpin_work = NULL;
|
||||
unlock_free:
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
drm_gem_object_unreference_unlocked(old_radeon_fb->obj);
|
||||
radeon_fence_unref(&work->fence);
|
||||
kfree(work);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -564,6 +609,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
|
|||
|
||||
drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
|
||||
radeon_crtc->crtc_id = index;
|
||||
radeon_crtc->flip_queue = create_singlethread_workqueue("radeon-crtc");
|
||||
rdev->mode_info.crtcs[index] = radeon_crtc;
|
||||
|
||||
if (rdev->family >= CHIP_BONAIRE) {
|
||||
|
|
|
@ -94,6 +94,8 @@ static int pre_xfer(struct i2c_adapter *i2c_adap)
|
|||
struct radeon_i2c_bus_rec *rec = &i2c->rec;
|
||||
uint32_t temp;
|
||||
|
||||
mutex_lock(&i2c->mutex);
|
||||
|
||||
/* RV410 appears to have a bug where the hw i2c in reset
|
||||
* holds the i2c port in a bad state - switch hw i2c away before
|
||||
* doing DDC - do this for all r200s/r300s/r400s for safety sake
|
||||
|
@ -170,6 +172,8 @@ static void post_xfer(struct i2c_adapter *i2c_adap)
|
|||
temp = RREG32(rec->mask_data_reg) & ~rec->mask_data_mask;
|
||||
WREG32(rec->mask_data_reg, temp);
|
||||
temp = RREG32(rec->mask_data_reg);
|
||||
|
||||
mutex_unlock(&i2c->mutex);
|
||||
}
|
||||
|
||||
static int get_clock(void *i2c_priv)
|
||||
|
@ -813,6 +817,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
struct radeon_i2c_bus_rec *rec = &i2c->rec;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&i2c->mutex);
|
||||
|
||||
switch (rdev->family) {
|
||||
case CHIP_R100:
|
||||
case CHIP_RV100:
|
||||
|
@ -879,6 +885,8 @@ static int radeon_hw_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&i2c->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -919,6 +927,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
|
|||
i2c->adapter.dev.parent = &dev->pdev->dev;
|
||||
i2c->dev = dev;
|
||||
i2c_set_adapdata(&i2c->adapter, i2c);
|
||||
mutex_init(&i2c->mutex);
|
||||
if (rec->mm_i2c ||
|
||||
(rec->hw_capable &&
|
||||
radeon_hw_i2c &&
|
||||
|
|
|
@ -191,6 +191,7 @@ struct radeon_i2c_chan {
|
|||
struct radeon_i2c_bus_rec rec;
|
||||
struct drm_dp_aux aux;
|
||||
bool has_aux;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
/* mostly for macs, but really any system without connector tables */
|
||||
|
@ -324,8 +325,8 @@ struct radeon_crtc {
|
|||
struct drm_display_mode native_mode;
|
||||
int pll_id;
|
||||
/* page flipping */
|
||||
struct radeon_unpin_work *unpin_work;
|
||||
int deferred_flip_completion;
|
||||
struct workqueue_struct *flip_queue;
|
||||
struct radeon_flip_work *flip_work;
|
||||
/* pll sharing */
|
||||
struct radeon_atom_ss ss;
|
||||
bool ss_enabled;
|
||||
|
@ -906,6 +907,7 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
|
|||
|
||||
void radeon_fb_output_poll_changed(struct radeon_device *rdev);
|
||||
|
||||
void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id);
|
||||
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
|
||||
|
||||
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
|
||||
|
|
|
@ -722,7 +722,7 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
|
|||
{
|
||||
int r;
|
||||
|
||||
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0);
|
||||
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
spin_lock(&bo->tbo.bdev->fence_lock);
|
||||
|
|
|
@ -65,7 +65,7 @@ static inline int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr)
|
|||
{
|
||||
int r;
|
||||
|
||||
r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, 0);
|
||||
r = ttm_bo_reserve(&bo->tbo, !no_intr, false, false, NULL);
|
||||
if (unlikely(r != 0)) {
|
||||
if (r != -ERESTARTSYS)
|
||||
dev_err(bo->rdev->dev, "%p reserve failed\n", bo);
|
||||
|
|
|
@ -657,6 +657,84 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_vm_frag_ptes - add fragment information to PTEs
|
||||
*
|
||||
* @rdev: radeon_device pointer
|
||||
* @ib: IB for the update
|
||||
* @pe_start: first PTE to handle
|
||||
* @pe_end: last PTE to handle
|
||||
* @addr: addr those PTEs should point to
|
||||
* @flags: hw mapping flags
|
||||
*
|
||||
* Global and local mutex must be locked!
|
||||
*/
|
||||
static void radeon_vm_frag_ptes(struct radeon_device *rdev,
|
||||
struct radeon_ib *ib,
|
||||
uint64_t pe_start, uint64_t pe_end,
|
||||
uint64_t addr, uint32_t flags)
|
||||
{
|
||||
/**
|
||||
* The MC L1 TLB supports variable sized pages, based on a fragment
|
||||
* field in the PTE. When this field is set to a non-zero value, page
|
||||
* granularity is increased from 4KB to (1 << (12 + frag)). The PTE
|
||||
* flags are considered valid for all PTEs within the fragment range
|
||||
* and corresponding mappings are assumed to be physically contiguous.
|
||||
*
|
||||
* The L1 TLB can store a single PTE for the whole fragment,
|
||||
* significantly increasing the space available for translation
|
||||
* caching. This leads to large improvements in throughput when the
|
||||
* TLB is under pressure.
|
||||
*
|
||||
* The L2 TLB distributes small and large fragments into two
|
||||
* asymmetric partitions. The large fragment cache is significantly
|
||||
* larger. Thus, we try to use large fragments wherever possible.
|
||||
* Userspace can support this by aligning virtual base address and
|
||||
* allocation size to the fragment size.
|
||||
*/
|
||||
|
||||
/* NI is optimized for 256KB fragments, SI and newer for 64KB */
|
||||
uint64_t frag_flags = rdev->family == CHIP_CAYMAN ?
|
||||
R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB;
|
||||
uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80;
|
||||
|
||||
uint64_t frag_start = ALIGN(pe_start, frag_align);
|
||||
uint64_t frag_end = pe_end & ~(frag_align - 1);
|
||||
|
||||
unsigned count;
|
||||
|
||||
/* system pages are non continuously */
|
||||
if ((flags & R600_PTE_SYSTEM) || !(flags & R600_PTE_VALID) ||
|
||||
(frag_start >= frag_end)) {
|
||||
|
||||
count = (pe_end - pe_start) / 8;
|
||||
radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count,
|
||||
RADEON_GPU_PAGE_SIZE, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle the 4K area at the beginning */
|
||||
if (pe_start != frag_start) {
|
||||
count = (frag_start - pe_start) / 8;
|
||||
radeon_asic_vm_set_page(rdev, ib, pe_start, addr, count,
|
||||
RADEON_GPU_PAGE_SIZE, flags);
|
||||
addr += RADEON_GPU_PAGE_SIZE * count;
|
||||
}
|
||||
|
||||
/* handle the area in the middle */
|
||||
count = (frag_end - frag_start) / 8;
|
||||
radeon_asic_vm_set_page(rdev, ib, frag_start, addr, count,
|
||||
RADEON_GPU_PAGE_SIZE, flags | frag_flags);
|
||||
|
||||
/* handle the 4K area at the end */
|
||||
if (frag_end != pe_end) {
|
||||
addr += RADEON_GPU_PAGE_SIZE * count;
|
||||
count = (pe_end - frag_end) / 8;
|
||||
radeon_asic_vm_set_page(rdev, ib, frag_end, addr, count,
|
||||
RADEON_GPU_PAGE_SIZE, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* radeon_vm_update_ptes - make sure that page tables are valid
|
||||
*
|
||||
|
@ -703,10 +781,9 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
|
|||
if ((last_pte + 8 * count) != pte) {
|
||||
|
||||
if (count) {
|
||||
radeon_asic_vm_set_page(rdev, ib, last_pte,
|
||||
last_dst, count,
|
||||
RADEON_GPU_PAGE_SIZE,
|
||||
flags);
|
||||
radeon_vm_frag_ptes(rdev, ib, last_pte,
|
||||
last_pte + 8 * count,
|
||||
last_dst, flags);
|
||||
}
|
||||
|
||||
count = nptes;
|
||||
|
@ -721,9 +798,9 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
|
|||
}
|
||||
|
||||
if (count) {
|
||||
radeon_asic_vm_set_page(rdev, ib, last_pte,
|
||||
last_dst, count,
|
||||
RADEON_GPU_PAGE_SIZE, flags);
|
||||
radeon_vm_frag_ptes(rdev, ib, last_pte,
|
||||
last_pte + 8 * count,
|
||||
last_dst, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,6 +964,8 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
|
|||
*/
|
||||
int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
|
||||
{
|
||||
const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE,
|
||||
RADEON_VM_PTE_COUNT * 8);
|
||||
unsigned pd_size, pd_entries, pts_size;
|
||||
int r;
|
||||
|
||||
|
@ -908,7 +987,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = radeon_bo_create(rdev, pd_size, RADEON_VM_PTB_ALIGN_SIZE, false,
|
||||
r = radeon_bo_create(rdev, pd_size, align, false,
|
||||
RADEON_GEM_DOMAIN_VRAM, NULL,
|
||||
&vm->page_directory);
|
||||
if (r)
|
||||
|
|
|
@ -109,19 +109,7 @@ void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
|
|||
}
|
||||
}
|
||||
|
||||
void rs600_pre_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* enable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_get(rdev, crtc);
|
||||
}
|
||||
|
||||
void rs600_post_page_flip(struct radeon_device *rdev, int crtc)
|
||||
{
|
||||
/* disable the pflip int */
|
||||
radeon_irq_kms_pflip_irq_put(rdev, crtc);
|
||||
}
|
||||
|
||||
u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
|
||||
|
@ -148,9 +136,15 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
|||
/* Unlock the lock, so double-buffering can take place inside vblank */
|
||||
tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
|
||||
WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
|
||||
}
|
||||
|
||||
bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
|
||||
/* Return current update_pending status: */
|
||||
return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING;
|
||||
return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) &
|
||||
AVIVO_D1GRPH_SURFACE_UPDATE_PENDING);
|
||||
}
|
||||
|
||||
void avivo_program_fmt(struct drm_encoder *encoder)
|
||||
|
@ -632,12 +626,6 @@ static void rs600_gart_fini(struct radeon_device *rdev)
|
|||
radeon_gart_table_vram_free(rdev);
|
||||
}
|
||||
|
||||
#define R600_PTE_VALID (1 << 0)
|
||||
#define R600_PTE_SYSTEM (1 << 1)
|
||||
#define R600_PTE_SNOOPED (1 << 2)
|
||||
#define R600_PTE_READABLE (1 << 5)
|
||||
#define R600_PTE_WRITEABLE (1 << 6)
|
||||
|
||||
int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
|
||||
{
|
||||
void __iomem *ptr = (void *)rdev->gart.ptr;
|
||||
|
@ -646,8 +634,7 @@ int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
|
|||
return -EINVAL;
|
||||
}
|
||||
addr = addr & 0xFFFFFFFFFFFFF000ULL;
|
||||
addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED;
|
||||
addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE;
|
||||
addr |= R600_PTE_GART;
|
||||
writeq(addr, ptr + (i * 8));
|
||||
return 0;
|
||||
}
|
||||
|
@ -787,7 +774,7 @@ int rs600_irq_process(struct radeon_device *rdev)
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
}
|
||||
if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
|
||||
if (rdev->irq.crtc_vblank_int[1]) {
|
||||
|
@ -796,7 +783,7 @@ int rs600_irq_process(struct radeon_device *rdev)
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
}
|
||||
if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
|
||||
queue_hotplug = true;
|
||||
|
|
|
@ -801,7 +801,7 @@ u32 rv770_get_xclk(struct radeon_device *rdev)
|
|||
return reference_clock;
|
||||
}
|
||||
|
||||
u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
void rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
|
||||
|
@ -835,9 +835,15 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
|
|||
/* Unlock the lock, so double-buffering can take place inside vblank */
|
||||
tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
|
||||
WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
|
||||
}
|
||||
|
||||
bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc_id)
|
||||
{
|
||||
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
|
||||
|
||||
/* Return current update_pending status: */
|
||||
return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING;
|
||||
return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) &
|
||||
AVIVO_D1GRPH_SURFACE_UPDATE_PENDING);
|
||||
}
|
||||
|
||||
/* get temperature in millidegrees */
|
||||
|
|
|
@ -4044,18 +4044,21 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
|
|||
WREG32(MC_VM_MX_L1_TLB_CNTL,
|
||||
(0xA << 7) |
|
||||
ENABLE_L1_TLB |
|
||||
ENABLE_L1_FRAGMENT_PROCESSING |
|
||||
SYSTEM_ACCESS_MODE_NOT_IN_SYS |
|
||||
ENABLE_ADVANCED_DRIVER_MODEL |
|
||||
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
|
||||
/* Setup L2 cache */
|
||||
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
|
||||
ENABLE_L2_FRAGMENT_PROCESSING |
|
||||
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
|
||||
ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
|
||||
EFFECTIVE_L2_QUEUE_SIZE(7) |
|
||||
CONTEXT1_IDENTITY_ACCESS_MODE(1));
|
||||
WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
|
||||
WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
|
||||
L2_CACHE_BIGK_FRAGMENT_SIZE(0));
|
||||
BANK_SELECT(4) |
|
||||
L2_CACHE_BIGK_FRAGMENT_SIZE(4));
|
||||
/* setup context0 */
|
||||
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
|
||||
WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
|
||||
|
@ -4092,6 +4095,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
|
|||
(u32)(rdev->dummy_page.addr >> 12));
|
||||
WREG32(VM_CONTEXT1_CNTL2, 4);
|
||||
WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
|
||||
PAGE_TABLE_BLOCK_SIZE(RADEON_VM_BLOCK_SIZE - 9) |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
|
||||
DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
|
||||
|
@ -6146,7 +6150,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[0]))
|
||||
radeon_crtc_handle_flip(rdev, 0);
|
||||
radeon_crtc_handle_vblank(rdev, 0);
|
||||
rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D1 vblank\n");
|
||||
}
|
||||
|
@ -6172,7 +6176,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[1]))
|
||||
radeon_crtc_handle_flip(rdev, 1);
|
||||
radeon_crtc_handle_vblank(rdev, 1);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D2 vblank\n");
|
||||
}
|
||||
|
@ -6198,7 +6202,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[2]))
|
||||
radeon_crtc_handle_flip(rdev, 2);
|
||||
radeon_crtc_handle_vblank(rdev, 2);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D3 vblank\n");
|
||||
}
|
||||
|
@ -6224,7 +6228,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[3]))
|
||||
radeon_crtc_handle_flip(rdev, 3);
|
||||
radeon_crtc_handle_vblank(rdev, 3);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D4 vblank\n");
|
||||
}
|
||||
|
@ -6250,7 +6254,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[4]))
|
||||
radeon_crtc_handle_flip(rdev, 4);
|
||||
radeon_crtc_handle_vblank(rdev, 4);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D5 vblank\n");
|
||||
}
|
||||
|
@ -6276,7 +6280,7 @@ restart_ih:
|
|||
wake_up(&rdev->irq.vblank_queue);
|
||||
}
|
||||
if (atomic_read(&rdev->irq.pflip[5]))
|
||||
radeon_crtc_handle_flip(rdev, 5);
|
||||
radeon_crtc_handle_vblank(rdev, 5);
|
||||
rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
|
||||
DRM_DEBUG("IH: D6 vblank\n");
|
||||
}
|
||||
|
|
|
@ -79,7 +79,25 @@ void si_dma_vm_set_page(struct radeon_device *rdev,
|
|||
|
||||
trace_radeon_vm_set_page(pe, addr, count, incr, flags);
|
||||
|
||||
if (flags & R600_PTE_SYSTEM) {
|
||||
if (flags == R600_PTE_GART) {
|
||||
uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8;
|
||||
while (count) {
|
||||
unsigned bytes = count * 8;
|
||||
if (bytes > 0xFFFF8)
|
||||
bytes = 0xFFFF8;
|
||||
|
||||
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY,
|
||||
1, 0, 0, bytes);
|
||||
ib->ptr[ib->length_dw++] = pe & 0xffffffff;
|
||||
ib->ptr[ib->length_dw++] = src & 0xffffffff;
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff;
|
||||
ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff;
|
||||
|
||||
pe += bytes;
|
||||
src += bytes;
|
||||
count -= bytes / 8;
|
||||
}
|
||||
} else if (flags & R600_PTE_SYSTEM) {
|
||||
while (count) {
|
||||
ndw = count * 2;
|
||||
if (ndw > 0xFFFFE)
|
||||
|
|
|
@ -362,6 +362,7 @@
|
|||
#define READ_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 16)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 18)
|
||||
#define WRITE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 19)
|
||||
#define PAGE_TABLE_BLOCK_SIZE(x) (((x) & 0xF) << 24)
|
||||
#define VM_CONTEXT1_CNTL 0x1414
|
||||
#define VM_CONTEXT0_CNTL2 0x1430
|
||||
#define VM_CONTEXT1_CNTL2 0x1434
|
||||
|
|
|
@ -623,7 +623,8 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
|
|||
ret = dev->bus->pm->runtime_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (vgasr_priv.handler->switchto)
|
||||
vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
|
||||
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -202,6 +202,11 @@ struct detailed_timing {
|
|||
#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6)
|
||||
#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7)
|
||||
|
||||
#define DRM_EDID_HDMI_DC_48 (1 << 6)
|
||||
#define DRM_EDID_HDMI_DC_36 (1 << 5)
|
||||
#define DRM_EDID_HDMI_DC_30 (1 << 4)
|
||||
#define DRM_EDID_HDMI_DC_Y444 (1 << 3)
|
||||
|
||||
struct edid {
|
||||
u8 header[8];
|
||||
/* Vendor & product info */
|
||||
|
|
Loading…
Reference in a new issue