Commit 0a397154 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-next-3.10-2' of git://people.freedesktop.org/~agd5f/linux into drm-next

Alex writes:
A few more updates for 3.10.  Nothing too major here.  Mostly bug fixes.
The big changes are adding golden register init for 7xx and newer asics
and some audio cleanups.

* 'drm-next-3.10-2' of git://people.freedesktop.org/~agd5f/linux: (32 commits)
  drm/radeon: disable UVD advanced semaphore mode
  drm/radeon: fix endian bugs in radeon_atom_get_clock_dividers() (v3)
  drm/radeon: fix up audio dto programming for DCE2
  drm/radeon/evergreen: set SAD registers
  drm: add drm_edid_to_eld helper extracting SADs from EDID (v2)
  drm/radeon/si: add support for golden register init
  drm/radeon/cayman,TN: add support for golden register init (v2)
  drm/radeon/evergreen: add support for golden register init
  drm/radeon/7xx: add support for golden register init
  drm/radeon: add helper function to support golden registers
  drm/radeon: fix typo in si_select_se_sh()
  drm/radeon: switch audio handling to use callbacks
  drm/radeon: clean up audio dto programming
  drm/radeon: clean up audio supported check
  drm/radeon: raise UVD clocks on init v3
  drm/radeon: raise UVD clocks only on demand
  drm/radeon: put UVD PLLs in bypass mode
  drm/radeon: disable audio format interrupts on Evergreen
  drm/radeon: fix hdmi mode enable on RS600/RS690/RS740
  drm/radeon/evergreen: write default channel numbers
  ...
parents f9df7ea3 03708b05
...@@ -2510,6 +2510,65 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) ...@@ -2510,6 +2510,65 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
} }
EXPORT_SYMBOL(drm_edid_to_eld); EXPORT_SYMBOL(drm_edid_to_eld);
/**
* drm_edid_to_sad - extracts SADs from EDID
* @edid: EDID to parse
* @sads: pointer that will be set to the extracted SADs
*
* Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it.
* Note: returned pointer needs to be kfreed
*
* Return number of found SADs or negative number on error.
*/
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads)
{
int count = 0;
int i, start, end, dbl;
u8 *cea;
cea = drm_find_cea_extension(edid);
if (!cea) {
DRM_DEBUG_KMS("SAD: no CEA Extension found\n");
return -ENOENT;
}
if (cea_revision(cea) < 3) {
DRM_DEBUG_KMS("SAD: wrong CEA revision\n");
return -ENOTSUPP;
}
if (cea_db_offsets(cea, &start, &end)) {
DRM_DEBUG_KMS("SAD: invalid data block offsets\n");
return -EPROTO;
}
for_each_cea_db(cea, i, start, end) {
u8 *db = &cea[i];
if (cea_db_tag(db) == AUDIO_BLOCK) {
int j;
dbl = cea_db_payload_len(db);
count = dbl / 3; /* SAD is 3B */
*sads = kcalloc(count, sizeof(**sads), GFP_KERNEL);
if (!*sads)
return -ENOMEM;
for (j = 0; j < count; j++) {
u8 *sad = &db[1 + j * 3];
(*sads)[j].format = (sad[0] & 0x78) >> 3;
(*sads)[j].channels = sad[0] & 0x7;
(*sads)[j].freq = sad[1] & 0x7F;
(*sads)[j].byte2 = sad[2];
}
break;
}
}
return count;
}
EXPORT_SYMBOL(drm_edid_to_sad);
/** /**
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
* @connector: connector associated with the HDMI/DP sink * @connector: connector associated with the HDMI/DP sink
......
...@@ -458,6 +458,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 ...@@ -458,6 +458,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
union union
{ {
ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
ULONG ulClockParams; //ULONG access for BE
ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
}; };
UCHAR ucRefDiv; //Output Parameter UCHAR ucRefDiv; //Output Parameter
...@@ -490,6 +491,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 ...@@ -490,6 +491,7 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
union union
{ {
ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter
ULONG ulClockParams; //ULONG access for BE
ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter
}; };
UCHAR ucRefDiv; //Output Parameter UCHAR ucRefDiv; //Output Parameter
......
...@@ -2150,13 +2150,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -2150,13 +2150,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
atombios_apply_encoder_quirks(encoder, adjusted_mode); atombios_apply_encoder_quirks(encoder, adjusted_mode);
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
r600_hdmi_enable(encoder); if (rdev->asic->display.hdmi_enable)
if (ASIC_IS_DCE6(rdev)) radeon_hdmi_enable(rdev, encoder, true);
; /* TODO (use pointers instead of if-s?) */ if (rdev->asic->display.hdmi_setmode)
else if (ASIC_IS_DCE4(rdev)) radeon_hdmi_setmode(rdev, encoder, adjusted_mode);
evergreen_hdmi_setmode(encoder, adjusted_mode);
else
r600_hdmi_setmode(encoder, adjusted_mode);
} }
} }
...@@ -2413,8 +2410,10 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) ...@@ -2413,8 +2410,10 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
disable_done: disable_done:
if (radeon_encoder_is_digital(encoder)) { if (radeon_encoder_is_digital(encoder)) {
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
r600_hdmi_disable(encoder); if (rdev->asic->display.hdmi_enable)
radeon_hdmi_enable(rdev, encoder, false);
}
dig = radeon_encoder->enc_priv; dig = radeon_encoder->enc_priv;
dig->dig_encoder = -1; dig->dig_encoder = -1;
} }
......
This diff is collapsed.
...@@ -54,6 +54,68 @@ static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t cloc ...@@ -54,6 +54,68 @@ static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t cloc
WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz); WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
} }
static void evergreen_hdmi_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);
}
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;
int j;
for (j = 0; j < sad_count; j++) {
struct cea_sad *sad = &sads[j];
if (sad->format == eld_reg_to_type[i][1]) {
value = MAX_CHANNELS(sad->channels) |
DESCRIPTOR_BYTE_2(sad->byte2) |
SUPPORTED_FREQUENCIES(sad->freq);
if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
value |= SUPPORTED_FREQUENCIES_STEREO(sad->freq);
break;
}
}
WREG32(eld_reg_to_type[i][0], value);
}
kfree(sads);
}
/* /*
* build a HDMI Video Info Frame * build a HDMI Video Info Frame
*/ */
...@@ -85,6 +147,30 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, ...@@ -85,6 +147,30 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
frame[0xC] | (frame[0xD] << 8)); frame[0xC] | (frame[0xD] << 8));
} }
static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
{
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;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
u32 base_rate = 48000;
if (!dig || !dig->afmt)
return;
/* XXX: properly calculate this */
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff);
WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff);
WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
}
/* /*
* update the info frames with the data from the current display mode * update the info frames with the data from the current display mode
*/ */
...@@ -104,33 +190,19 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode ...@@ -104,33 +190,19 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
return; return;
offset = dig->afmt->offset; offset = dig->afmt->offset;
r600_audio_set_clock(encoder, mode->clock); evergreen_audio_set_dto(encoder, mode->clock);
WREG32(HDMI_VBI_PACKET_CONTROL + offset, WREG32(HDMI_VBI_PACKET_CONTROL + offset,
HDMI_NULL_SEND); /* send null packets when required */ HDMI_NULL_SEND); /* send null packets when required */
WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000); WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
HDMI_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 */
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
HDMI_ACR_SOURCE); /* select SW CTS value */
WREG32(HDMI_VBI_PACKET_CONTROL + offset, WREG32(HDMI_VBI_PACKET_CONTROL + offset,
HDMI_NULL_SEND | /* send null packets when required */ HDMI_NULL_SEND | /* send null packets when required */
HDMI_GC_SEND | /* send general control packets */ HDMI_GC_SEND | /* send general control packets */
HDMI_GC_CONT); /* send general control packets every frame */ HDMI_GC_CONT); /* send general control packets every frame */
WREG32(HDMI_INFOFRAME_CONTROL0 + offset, WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
HDMI_AVI_INFO_SEND | /* enable AVI info frames */
HDMI_AVI_INFO_CONT | /* send AVI info frames every frame/field */
HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */ HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */ HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
...@@ -138,11 +210,47 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode ...@@ -138,11 +210,47 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */ AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32(HDMI_INFOFRAME_CONTROL1 + offset, WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
HDMI_AVI_INFO_LINE(2) | /* anything other than 0 */
HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */ HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */ WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
HDMI_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_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
/* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
WREG32(HDMI_ACR_PACKET_CONTROL + offset,
HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
HDMI_ACR_SOURCE); /* select SW CTS value */
evergreen_hdmi_update_ACR(encoder, mode->clock);
WREG32(AFMT_60958_0 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_L(1));
WREG32(AFMT_60958_1 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_R(2));
WREG32(AFMT_60958_2 + offset,
AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
AFMT_60958_CS_CHANNEL_NUMBER_7(8));
/* fglrx sets 0x0001005f | (x & 0x00fc0000) in 0x5f78 here */
WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
AFMT_AUDIO_CHANNEL_ENABLE(0xff));
/* fglrx sets 0x40 in 0x5f80 here */
evergreen_hdmi_write_sad_regs(encoder);
err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
if (err < 0) { if (err < 0) {
DRM_ERROR("failed to setup AVI infoframe: %zd\n", err); DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
...@@ -156,7 +264,17 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode ...@@ -156,7 +264,17 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
} }
evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer)); evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
evergreen_hdmi_update_ACR(encoder, mode->clock);
WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
HDMI_AVI_INFO_SEND | /* enable AVI info frames */
HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
~HDMI_AVI_INFO_LINE_MASK);
WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF); WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
...@@ -164,3 +282,20 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode ...@@ -164,3 +282,20 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
} }
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
/* Silent, r600_hdmi_enable will raise WARN for us */
if (enable && dig->afmt->enabled)
return;
if (!enable && !dig->afmt->enabled)
return;
dig->afmt->enabled = enable;
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
}
...@@ -226,6 +226,8 @@ ...@@ -226,6 +226,8 @@
#define EVERGREEN_CRTC_STATUS_HV_COUNT 0x6ea0 #define EVERGREEN_CRTC_STATUS_HV_COUNT 0x6ea0
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 #define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
#define EVERGREEN_MASTER_UPDATE_LOCK 0x6ef4
#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8
#define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0
#define EVERGREEN_DC_GPIO_HPD_A 0x64b4 #define EVERGREEN_DC_GPIO_HPD_A 0x64b4
......
...@@ -234,6 +234,7 @@ ...@@ -234,6 +234,7 @@
# define HDMI_MPEG_INFO_CONT (1 << 9) # define HDMI_MPEG_INFO_CONT (1 << 9)
#define HDMI_INFOFRAME_CONTROL1 0x7048 #define HDMI_INFOFRAME_CONTROL1 0x7048
# define HDMI_AVI_INFO_LINE(x) (((x) & 0x3f) << 0) # define HDMI_AVI_INFO_LINE(x) (((x) & 0x3f) << 0)
# define HDMI_AVI_INFO_LINE_MASK (0x3f << 0)
# define HDMI_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8) # define HDMI_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8)
# define HDMI_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16) # define HDMI_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16)
#define HDMI_GENERIC_PACKET_CONTROL 0x704c #define HDMI_GENERIC_PACKET_CONTROL 0x704c
......
...@@ -78,6 +78,282 @@ MODULE_FIRMWARE("radeon/ARUBA_pfp.bin"); ...@@ -78,6 +78,282 @@ MODULE_FIRMWARE("radeon/ARUBA_pfp.bin");
MODULE_FIRMWARE("radeon/ARUBA_me.bin"); MODULE_FIRMWARE("radeon/ARUBA_me.bin");
MODULE_FIRMWARE("radeon/ARUBA_rlc.bin"); MODULE_FIRMWARE("radeon/ARUBA_rlc.bin");
static const u32 cayman_golden_registers2[] =
{
0x3e5c, 0xffffffff, 0x00000000,
0x3e48, 0xffffffff, 0x00000000,
0x3e4c, 0xffffffff, 0x00000000,
0x3e64, 0xffffffff, 0x00000000,
0x3e50, 0xffffffff, 0x00000000,
0x3e60, 0xffffffff, 0x00000000
};
static const u32 cayman_golden_registers[] =
{
0x5eb4, 0xffffffff, 0x00000002,
0x5e78, 0x8f311ff1, 0x001000f0,
0x3f90, 0xffff0000, 0xff000000,
0x9148, 0xffff0000, 0xff000000,
0x3f94, 0xffff0000, 0xff000000,
0x914c, 0xffff0000, 0xff000000,
0xc78, 0x00000080, 0x00000080,
0xbd4, 0x70073777, 0x00011003,
0xd02c, 0xbfffff1f, 0x08421000,
0xd0b8, 0x73773777, 0x02011003,
0x5bc0, 0x00200000, 0x50100000,
0x98f8, 0x33773777, 0x02011003,
0x98fc, 0xffffffff, 0x76541032,
0x7030, 0x31000311, 0x00000011,
0x2f48, 0x33773777, 0x42010001,
0x6b28, 0x00000010, 0x00000012,
0x7728, 0x00000010, 0x00000012,
0x10328, 0x00000010, 0x00000012,
0x10f28, 0x00000010, 0x00000012,
0x11b28, 0x00000010, 0x00000012,
0x12728, 0x00000010, 0x00000012,
0x240c, 0x000007ff, 0x00000000,
0x8a14, 0xf000001f, 0x00000007,
0x8b24, 0x3fff3fff, 0x00ff0fff,
0x8b10, 0x0000ff0f, 0x00000000,
0x28a4c, 0x07ffffff, 0x06000000,
0x10c, 0x00000001, 0x00010003,
0xa02c, 0xffffffff, 0x0000009b,
0x913c, 0x0000010f, 0x01000100,
0x8c04, 0xf8ff00ff, 0x40600060,
0x28350, 0x00000f01, 0x00000000,
0x9508, 0x3700001f, 0x00000002,
0x960c, 0xffffffff, 0x54763210,
0x88c4, 0x001f3ae3, 0x00000082,
0x88d0, 0xffffffff, 0x0f40df40,
0x88d4, 0x0000001f, 0x00000010,
0x8974, 0xffffffff, 0x00000000
};
static const u32 dvst_golden_registers2[] =
{
0x8f8, 0xffffffff, 0,
0x8fc, 0x00380000, 0,
0x8f8, 0xffffffff, 1,
0x8fc, 0x0e000000, 0
};
static const u32 dvst_golden_registers[] =
{
0x690, 0x3fff3fff, 0x20c00033,
0x918c, 0x0fff0fff, 0x00010006,
0x91a8, 0x0fff0fff, 0x00010006,
0x9150, 0xffffdfff, 0x6e944040,
0x917c, 0x0fff0fff, 0x00030002,
0x9198, 0x0fff0fff, 0x00030002,
0x915c, 0x0fff0fff, 0x00010000,
0x3f90, 0xffff0001, 0xff000000,
0x9178, 0x0fff0fff, 0x00070000,
0x9194, 0x0fff0fff, 0x00070000,
0x9148, 0xffff0001, 0xff000000,
0x9190, 0x0fff0fff, 0x00090008,
0x91ac, 0x0fff0fff, 0x00090008,
0x3f94, 0xffff0000, 0xff000000,
0x914c, 0xffff0000, 0xff000000,
0x929c, 0x00000fff, 0x00000001,
0x55e4, 0xff607fff, 0xfc000100,
0x8a18, 0xff000fff, 0x00000100,
0x8b28, 0xff000fff, 0x00000100,
0x9144, 0xfffc0fff, 0x00000100,
0x6ed8, 0x00010101, 0x00010000,
0x9830, 0xffffffff, 0x00000000,
0x9834, 0xf00fffff, 0x00000400,
0x9838, 0xfffffffe, 0x00000000,
0xd0c0, 0xff000fff, 0x00000100,
0xd02c, 0xbfffff1f, 0x08421000,
0xd0b8, 0x73773777, 0x12010001,
0x5bb0, 0x000000f0, 0x00000070,
0x98f8, 0x73773777, 0x12010001,
0x98fc, 0xffffffff, 0x00000010,
0x9b7c, 0x00ff0000, 0x00fc0000,
0x8030, 0x00001f0f, 0x0000100a,
0x2f48, 0x73773777, 0x12010001,
0x2408, 0x00030000, 0x000c007f,
0x8a14, 0xf000003f, 0x00000007,
0x8b24, 0x3fff3fff, 0x00ff0fff,
0x8b10, 0x0000ff0f, 0x00000000,
0x28a4c, 0x07ffffff, 0x06000000,
0x4d8, 0x00000fff, 0x00000100,
0xa008, 0xffffffff, 0x00010000,
0x913c, 0xffff03ff, 0x01000100,
0x8c00, 0x000000ff, 0x00000003,
0x8c04, 0xf8ff00ff, 0x40600060,
0x8cf0, 0x1fff1fff, 0x08e00410,
0x28350, 0x00000f01, 0x00000000,
0x9508, 0xf700071f, 0x00000002,
0x960c, 0xffffffff, 0x54763210,
0x20ef8, 0x01ff01ff, 0x00000002,
0x20e98, 0xfffffbff, 0x00200000,
0x2015c, 0xffffffff, 0x00000f40,
0x88c4, 0x001f3ae3, 0x00000082,
0x8978, 0x3fffffff, 0x04050140,
0x88d4, 0x0000001f, 0x00000010,
0x8974, 0xffffffff, 0x00000000
};
static const u32 scrapper_golden_registers[] =
{
0x690, 0x3fff3fff, 0x20c00033,
0x918c, 0x0fff0fff, 0x00010006,
0x918c, 0x0fff0fff, 0x00010006,
0x91a8, 0x0fff0fff, 0x00010006,
0x91a8, 0x0fff0fff, 0x00010006,
0x9150, 0xffffdfff, 0x6e944040,
0x9150, 0xffffdfff, 0x6e944040,
0x917c, 0x0fff0fff, 0x00030002,
0x917c, 0x0fff0fff, 0x00030002,
0x9198, 0x0fff0fff, 0x00030002,
0x9198, 0x0fff0fff, 0x00030002,
0x915c, 0x0fff0fff, 0x00010000,
0x915c, 0x0fff0fff, 0x00010000,
0x3f90, 0xffff0001, 0xff000000,
0x3f90, 0xffff0001, 0xff000000,
0x9178, 0x0fff0fff, 0x00070000,
0x9178, 0x0fff0fff, 0x00070000,
0x9194, 0x0fff0fff, 0x00070000,
0x9194, 0x0fff0fff, 0x00070000,
0x9148, 0xffff0001, 0xff000000,
0x9148, 0xffff0001, 0xff000000,
0x9190, 0x0fff0fff, 0x00090008,
0x9190, 0x0fff0fff, 0x00090008,
0x91ac, 0x0fff0fff, 0x00090008,
0x91ac, 0x0fff0fff, 0x00090008,
0x3f94, 0xffff0000, 0xff000000,
0x3f94, 0xffff0000, 0xff000000,
0x914c, 0xffff0000, 0xff000000,
0x914c, 0xffff0000, 0xff000000,
0x929c, 0x00000fff, 0x00000001,
0x929c, 0x00000fff, 0x00000001,
0x55e4, 0xff607fff, 0xfc000100,
0x8a18, 0xff000fff, 0x00000100,
0x8a18, 0xff000fff, 0x00000100,
0x8b28, 0xff000fff, 0x00000100,
0x8b28, 0xff000fff, 0x00000100,
0x9144, 0xfffc0fff, 0x00000100,
0x9144, 0xfffc0fff, 0x00000100,
0x6ed8, 0x00010101, 0x00010000,
0x9830, 0xffffffff, 0x00000000,
0x9830, 0xffffffff, 0x00000000,
0x9834, 0xf00fffff, 0x00000400,
0x9834, 0xf00fffff, 0x00000400,
0x9838, 0xfffffffe, 0x00000000,
0x9838, 0xfffffffe, 0x00000000,
0xd0c0, 0xff000fff, 0x00000100,
0xd02c, 0xbfffff1f, 0x08421000,
0xd02c, 0xbfffff1f, 0x08421000,
0xd0b8, 0x73773777, 0x12010001,
0xd0b8, 0x73773777, 0x12010001,
0x5bb0, 0x000000f0, 0x00000070,
0x98f8, 0x73773777, 0x12010001,
0x98f8, 0x73773777, 0x12010001,
0x98fc, 0xffffffff, 0x00000010,
0x98fc, 0xffffffff, 0x00000010,
0x9b7c, 0x00ff0000, 0x00fc0000,
0x9b7c, 0x00ff0000, 0x00fc0000,
0x8030, 0x00001f0f, 0x0000100a,
0x8030, 0x00001f0f, 0x0000100a,
0x2f48, 0x73773777, 0x12010001,
0x2f48, 0x73773777, 0x12010001,
0x2408, 0x00030000, 0x000c007f,
0x8a14, 0xf000003f, 0x00000007,
0x8a14, 0xf000003f, 0x00000007,
0x8b24, 0x3fff3fff, 0x00ff0fff,
0x8b24, 0x3fff3fff, 0x00ff0fff,
0x8b10, 0x0000ff0f, 0x00000000,
0x8b10, 0x0000ff0f, 0x00000000,
0x28a4c, 0x07ffffff, 0x06000000,
0x28a4c, 0x07ffffff, 0x06000000,
0x4d8, 0x00000fff, 0x00000100,
0x4d8, 0x00000fff, 0x00000100,
0xa008, 0xffffffff, 0x00010000,
0xa008, 0xffffffff, 0x00010000,
0x913c, 0xffff03ff, 0x01000100,
0x913c, 0xffff03ff, 0x01000100,
0x90e8, 0x001fffff, 0x010400c0,
0x8c00, 0x000000ff, 0x00000003,
0x8c00, 0x000000ff, 0x00000003,
0x8c04, 0xf8ff00ff, 0x40600060,
0x8c04, 0xf8ff00ff, 0x40600060,
0x8c30, 0x0000000f, 0x00040005,
0x8cf0, 0x1fff1fff, 0x08e00410,
0x8cf0, 0x1fff1fff, 0x08e00410,
0x900c, 0x00ffffff, 0x0017071f,
0x28350, 0x00000f01, 0x00000000,
0x28350, 0x00000f01, 0x00000000,
0x9508, 0xf700071f, 0x00000002,
0x9508, 0xf700071f, 0x00000002,
0x9688, 0x00300000, 0x0017000f,
0x960c, 0xffffffff, 0x54763210,
0x960c, 0xffffffff, 0x54763210,
0x20ef8, 0x01ff01ff, 0x00000002,
0x20e98, 0xfffffbff, 0x00200000,
0x2015c, 0xffffffff, 0x00000f40,
0x88c4, 0x001f3ae3, 0x00000082,
0x88c4, 0x001f3ae3, 0x00000082,
0x8978, 0x3fffffff, 0x04050140,
0x8978, 0x3fffffff, 0x04050140,
0x88d4, 0x0000001f, 0x00000010,
0x88d4, 0x0000001f, 0x00000010,
0x8974, 0xffffffff, 0x00000000,
0x8974, 0xffffffff, 0x00000000
};
static void ni_init_golden_registers(struct radeon_device *rdev)
{
switch (rdev->family) {
case CHIP_CAYMAN:
radeon_program_register_sequence(rdev,
cayman_golden_registers,
(const u32)ARRAY_SIZE(cayman_golden_registers));
radeon_program_register_sequence(rdev,
cayman_golden_registers2,
(const u32)ARRAY_SIZE(cayman_golden_registers2));
break;
case CHIP_ARUBA:
if ((rdev->pdev->device == 0x9900) ||
(rdev->pdev->device == 0x9901) ||
(rdev->pdev->device == 0x9903) ||
(rdev->pdev->device == 0x9904) ||
(rdev->pdev->device == 0x9905) ||
(rdev->pdev->device == 0x9906) ||
(rdev->pdev->device == 0x9907) ||
(rdev->pdev->device == 0x9908) ||
(rdev->pdev->device == 0x9909) ||
(rdev->pdev->device == 0x990A) ||
(rdev->pdev->device == 0x990B) ||
(rdev->pdev->device == 0x990C) ||
(rdev->pdev->device == 0x990D) ||
(rdev->pdev->device == 0x990E) ||
(rdev->pdev->device == 0x990F) ||
(rdev->pdev->device == 0x9910) ||
(rdev->pdev->device == 0x9913) ||
(rdev->pdev->device == 0x9917) ||
(rdev->pdev->device == 0x9918)) {
radeon_program_register_sequence(rdev,
dvst_golden_registers,
(const u32)ARRAY_SIZE(dvst_golden_registers));
radeon_program_register_sequence(rdev,
dvst_golden_registers2,
(const u32)ARRAY_SIZE(dvst_golden_registers2));
} else {
radeon_program_register_sequence(rdev,
scrapper_golden_registers,
(const u32)ARRAY_SIZE(scrapper_golden_registers));
radeon_program_register_sequence(rdev,
dvst_golden_registers2,
(const u32)ARRAY_SIZE(dvst_golden_registers2));
}
break;
default:
break;
}
}
#define BTC_IO_MC_REGS_SIZE 29 #define BTC_IO_MC_REGS_SIZE 29
static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = {
...@@ -1830,6 +2106,9 @@ int cayman_resume(struct radeon_device *rdev) ...@@ -1830,6 +2106,9 @@ int cayman_resume(struct radeon_device *rdev)
/* post card */ /* post card */
atom_asic_init(rdev->mode_info.atom_context); atom_asic_init(rdev->mode_info.atom_context);
/* init golden registers */
ni_init_golden_registers(rdev);
rdev->accel_working = true; rdev->accel_working = true;
r = cayman_startup(rdev); r = cayman_startup(rdev);
if (r) { if (r) {
...@@ -1888,6 +2167,8 @@ int cayman_init(struct radeon_device *rdev) ...@@ -1888,6 +2167,8 @@ int cayman_init(struct radeon_device *rdev)
DRM_INFO("GPU not posted. posting now...\n"); DRM_INFO("GPU not posted. posting now...\n");
atom_asic_init(rdev->mode_info.atom_context); atom_asic_init(rdev->mode_info.atom_context);
} }
/* init golden registers */
ni_init_golden_registers(rdev);
/* Initialize scratch registers */ /* Initialize scratch registers */
r600_scratch_init(rdev); r600_scratch_init(rdev);
/* Initialize surface registers */ /* Initialize surface registers */
......
...@@ -69,6 +69,38 @@ MODULE_FIRMWARE(FIRMWARE_R520); ...@@ -69,6 +69,38 @@ MODULE_FIRMWARE(FIRMWARE_R520);
* and others in some cases. * and others in some cases.
*/ */
static bool r100_is_in_vblank(struct radeon_device *rdev, int crtc)
{
if (crtc == 0) {
if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)
return true;
else
return false;
} else {
if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)
return true;
else
return false;
}
}
static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc)
{
u32 vline1, vline2;
if (crtc == 0) {
vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
} else {
vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
}
if (vline1 != vline2)
return true;
else
return false;
}
/** /**
* r100_wait_for_vblank - vblank wait asic callback. * r100_wait_for_vblank - vblank wait asic callback.
* *
...@@ -79,36 +111,33 @@ MODULE_FIRMWARE(FIRMWARE_R520); ...@@ -79,36 +111,33 @@ MODULE_FIRMWARE(FIRMWARE_R520);
*/ */
void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) void r100_wait_for_vblank(struct radeon_device *rdev, int crtc)
{ {
int i; unsigned i = 0;
if (crtc >= rdev->num_crtc) if (crtc >= rdev->num_crtc)
return; return;
if (crtc == 0) { if (crtc == 0) {
if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) { if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN))
for (i = 0; i < rdev->usec_timeout; i++) { return;
if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)) } else {
break; if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN))
udelay(1); return;
} }
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) /* depending on when we hit vblank, we may be close to active; if so,
* wait for another frame.
*/
while (r100_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!r100_is_counter_moving(rdev, crtc))
break; break;
udelay(1);
}
} }
} else {
if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN) {
for (i = 0; i < rdev->usec_timeout; i++) {
if (!(RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR))
break;
udelay(1);
} }
for (i = 0; i < rdev->usec_timeout; i++) {
if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) while (!r100_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!r100_is_counter_moving(rdev, crtc))
break; break;
udelay(1);
}
} }
} }
} }
......
...@@ -358,7 +358,9 @@ ...@@ -358,7 +358,9 @@
#define AVIVO_D1CRTC_STATUS_HV_COUNT 0x60ac #define AVIVO_D1CRTC_STATUS_HV_COUNT 0x60ac
#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4
#define AVIVO_D1MODE_MASTER_UPDATE_LOCK 0x60e0
#define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4 #define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4
#define AVIVO_D1CRTC_UPDATE_LOCK 0x60e8
/* master controls */ /* master controls */
#define AVIVO_DC_CRTC_MASTER_EN 0x60f8 #define AVIVO_DC_CRTC_MASTER_EN 0x60f8
......
...@@ -2625,7 +2625,7 @@ int r600_uvd_rbc_start(struct radeon_device *rdev) ...@@ -2625,7 +2625,7 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
radeon_ring_write(ring, 0x8); radeon_ring_write(ring, 0x8);
radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
radeon_ring_write(ring, 1); radeon_ring_write(ring, 3);
radeon_ring_unlock_commit(rdev, ring); radeon_ring_unlock_commit(rdev, ring);
...@@ -2645,6 +2645,9 @@ int r600_uvd_init(struct radeon_device *rdev) ...@@ -2645,6 +2645,9 @@ int r600_uvd_init(struct radeon_device *rdev)
{ {
int i, j, r; int i, j, r;
/* raise clocks while booting up the VCPU */
radeon_set_uvd_clocks(rdev, 53300, 40000);
/* disable clock gating */ /* disable clock gating */
WREG32(UVD_CGC_GATE, 0); WREG32(UVD_CGC_GATE, 0);
...@@ -2715,19 +2718,24 @@ int r600_uvd_init(struct radeon_device *rdev) ...@@ -2715,19 +2718,24 @@ int r600_uvd_init(struct radeon_device *rdev)
mdelay(10); mdelay(10);
r = -1; r = -1;
} }
if (r) { if (r) {
DRM_ERROR("UVD not responding, giving up!!!\n"); DRM_ERROR("UVD not responding, giving up!!!\n");
radeon_set_uvd_clocks(rdev, 0, 0);
return r; return r;
} }
/* enable interupt */ /* enable interupt */
WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
r = r600_uvd_rbc_start(rdev); r = r600_uvd_rbc_start(rdev);
if (r) if (!r)
return r;
DRM_INFO("UVD initialized successfully.\n"); DRM_INFO("UVD initialized successfully.\n");
return 0;
/* lower clocks again */
radeon_set_uvd_clocks(rdev, 0, 0);
return r;
} }
/* /*
...@@ -3566,28 +3574,36 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ...@@ -3566,28 +3574,36 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{ {
struct radeon_fence *fence; struct radeon_fence *fence = NULL;
int r; int r;
r = radeon_set_uvd_clocks(rdev, 53300, 40000);
if (r) {
DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
return r;
}
r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
if (r) { if (r) {
DRM_ERROR("radeon: failed to get create msg (%d).\n", r); DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
return r; goto error;
} }
r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence); r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence);
if (r) { if (r) {
DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
return r; goto error;
} }
r = radeon_fence_wait(fence, false); r = radeon_fence_wait(fence, false);
if (r) { if (r) {
DRM_ERROR("radeon: fence wait failed (%d).\n", r); DRM_ERROR("radeon: fence wait failed (%d).\n", r);
return r; goto error;
} }
DRM_INFO("ib test on ring %d succeeded\n", ring->idx); DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
error:
radeon_fence_unref(&fence); radeon_fence_unref(&fence);
radeon_set_uvd_clocks(rdev, 0, 0);
return r; return r;
} }
......
...@@ -57,10 +57,7 @@ static bool radeon_dig_encoder(struct drm_encoder *encoder) ...@@ -57,10 +57,7 @@ static bool radeon_dig_encoder(struct drm_encoder *encoder)
*/ */
static int r600_audio_chipset_supported(struct radeon_device *rdev) static int r600_audio_chipset_supported(struct radeon_device *rdev)
{ {
return (rdev->family >= CHIP_R600 && !ASIC_IS_DCE6(rdev)) return ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE6(rdev);
|| rdev->family == CHIP_RS600
|| rdev->family == CHIP_RS690
|| rdev->family == CHIP_RS740;
} }
struct r600_audio r600_audio_status(struct radeon_device *rdev) struct r600_audio r600_audio_status(struct radeon_device *rdev)
...@@ -183,65 +180,6 @@ int r600_audio_init(struct radeon_device *rdev) ...@@ -183,65 +180,6 @@ int r600_audio_init(struct radeon_device *rdev)
return 0; return 0;
} }
/*
* atach the audio codec to the clock source of the encoder
*/
void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
{
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;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
int base_rate = 48000;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
break;
default:
dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
radeon_encoder->encoder_id);
return;
}
if (ASIC_IS_DCE4(rdev)) {
/* TODO: other PLLs? */
WREG32(EVERGREEN_AUDIO_PLL1_MUL, base_rate * 10);
WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10);
WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071);
/* Select DTO source */
WREG32(0x5ac, radeon_crtc->crtc_id);
} else {
switch (dig->dig_encoder) {
case 0:
WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
WREG32(R600_AUDIO_CLK_SRCSEL, 0);
break;
case 1:
WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
WREG32(R600_AUDIO_CLK_SRCSEL, 1);
break;
default:
dev_err(rdev->dev,
"Unsupported DIG on encoder 0x%02X\n",
radeon_encoder->encoder_id);
return;
}
}
}
/* /*
* release the audio timer * release the audio timer
* TODO: How to do this correctly on SMP systems? * TODO: How to do this correctly on SMP systems?
......
...@@ -226,6 +226,39 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) ...@@ -226,6 +226,39 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
value, ~HDMI0_AUDIO_TEST_EN); value, ~HDMI0_AUDIO_TEST_EN);
} }
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
{
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;
u32 base_rate = 48000;
if (!dig || !dig->afmt)
return;
/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
* doesn't matter which one you use. Just use the first one.
*/
/* XXX: properly calculate this */
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
if (ASIC_IS_DCE3(rdev)) {
/* according to the reg specs, this should DCE3.2 only, but in
* practice it seems to cover DCE3.0 as well.
*/
WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 50);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
/* according to the reg specs, this should be DCE2.0 and DCE3.0 */
WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate * 50) |
AUDIO_DTO_MODULE(clock * 100));
}
}
/* /*
* update the info frames with the data from the current display mode * update the info frames with the data from the current display mode
...@@ -246,7 +279,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod ...@@ -246,7 +279,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
return; return;
offset = dig->afmt->offset; offset = dig->afmt->offset;
r600_audio_set_clock(encoder, mode->clock); r600_audio_set_dto(encoder, mode->clock);
WREG32(HDMI0_VBI_PACKET_CONTROL + offset, WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
HDMI0_NULL_SEND); /* send null packets when required */ HDMI0_NULL_SEND); /* send null packets when required */
...@@ -415,42 +448,51 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) ...@@ -415,42 +448,51 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
/* /*
* enable the HDMI engine * enable the HDMI engine
*/ */
void r600_hdmi_enable(struct drm_encoder *encoder) void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset; u32 hdmi = HDMI0_ERROR_ACK;
u32 hdmi;
if (ASIC_IS_DCE6(rdev))
return;
/* Silent, r600_hdmi_enable will raise WARN for us */ /* Silent, r600_hdmi_enable will raise WARN for us */
if (dig->afmt->enabled) if (enable && dig->afmt->enabled)
return;
if (!enable && !dig->afmt->enabled)
return; return;
offset = dig->afmt->offset;
/* Older chipsets require setting HDMI and routing manually */ /* Older chipsets require setting HDMI and routing manually */
if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { if (!ASIC_IS_DCE3(rdev)) {
hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; if (enable)
hdmi |= HDMI0_ENABLE;
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN, if (enable) {
~AVIVO_TMDSA_CNTL_HDMI_EN); WREG32_OR(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA); hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA);
} else {
WREG32_AND(AVIVO_TMDSA_CNTL, ~AVIVO_TMDSA_CNTL_HDMI_EN);
}
break; break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1: case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN, if (enable) {
~AVIVO_LVTMA_CNTL_HDMI_EN); WREG32_OR(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA); hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA);
} else {
WREG32_AND(AVIVO_LVTMA_CNTL, ~AVIVO_LVTMA_CNTL_HDMI_EN);
}
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DDI:
WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN); if (enable) {
WREG32_OR(DDIA_CNTL, DDIA_HDMI_EN);
hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA); hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA);
} else {
WREG32_AND(DDIA_CNTL, ~DDIA_HDMI_EN);
}
break; break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
if (enable)
hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA); hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA);
break; break;
default: default:
...@@ -458,71 +500,21 @@ void r600_hdmi_enable(struct drm_encoder *encoder) ...@@ -458,71 +500,21 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
radeon_encoder->encoder_id); radeon_encoder->encoder_id);
break; break;
} }
WREG32(HDMI0_CONTROL + offset, hdmi); WREG32(HDMI0_CONTROL + dig->afmt->offset, hdmi);
} }
if (rdev->irq.installed) { if (rdev->irq.installed) {
/* if irq is available use it */ /* if irq is available use it */
/* XXX: shouldn't need this on any asics. Double check DCE2/3 */
if (enable)
radeon_irq_kms_enable_afmt(rdev, dig->afmt->id); radeon_irq_kms_enable_afmt(rdev, dig->afmt->id);
else
radeon_irq_kms_disable_afmt(rdev, dig->afmt->id);
} }
dig->afmt->enabled = true; dig->afmt->enabled = enable;
DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n", DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
offset, radeon_encoder->encoder_id); enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
} }
/*
* disable the HDMI engine
*/
void r600_hdmi_disable(struct drm_encoder *encoder)
{
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;
uint32_t offset;
if (ASIC_IS_DCE6(rdev))
return;
/* Called for ATOM_ENCODER_MODE_HDMI only */
if (!dig || !dig->afmt) {
return;
}
if (!dig->afmt->enabled)
return;
offset = dig->afmt->offset;
DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n",
offset, radeon_encoder->encoder_id);
/* disable irq */
radeon_irq_kms_disable_afmt(rdev, dig->afmt->id);
/* Older chipsets not handled by AtomBIOS */
if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, 0,
~AVIVO_TMDSA_CNTL_HDMI_EN);
break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, 0,
~AVIVO_LVTMA_CNTL_HDMI_EN);
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN);
break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
break;
default:
dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n",
radeon_encoder->encoder_id);
break;
}
WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK);
}
dig->afmt->enabled = false;
}
...@@ -910,7 +910,12 @@ ...@@ -910,7 +910,12 @@
# define TARGET_LINK_SPEED_MASK (0xf << 0) # define TARGET_LINK_SPEED_MASK (0xf << 0)
# define SELECTABLE_DEEMPHASIS (1 << 6) # define SELECTABLE_DEEMPHASIS (1 << 6)
/* Audio clocks */ /* Audio clocks DCE 2.0/3.0 */
#define AUDIO_DTO 0x7340
# define AUDIO_DTO_PHASE(x) (((x) & 0xffff) << 0)
# define AUDIO_DTO_MODULE(x) (((x) & 0xffff) << 16)
/* Audio clocks DCE 3.2 */
#define DCCG_AUDIO_DTO0_PHASE 0x0514 #define DCCG_AUDIO_DTO0_PHASE 0x0514
#define DCCG_AUDIO_DTO0_MODULE 0x0518 #define DCCG_AUDIO_DTO0_MODULE 0x0518
#define DCCG_AUDIO_DTO0_LOAD 0x051c #define DCCG_AUDIO_DTO0_LOAD 0x051c
......
...@@ -1143,6 +1143,7 @@ struct radeon_uvd { ...@@ -1143,6 +1143,7 @@ struct radeon_uvd {
uint64_t gpu_addr; uint64_t gpu_addr;
atomic_t handles[RADEON_MAX_UVD_HANDLES]; atomic_t handles[RADEON_MAX_UVD_HANDLES];
struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES];
struct delayed_work idle_work;
}; };
int radeon_uvd_init(struct radeon_device *rdev); int radeon_uvd_init(struct radeon_device *rdev);
...@@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); ...@@ -1157,6 +1158,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo);
void radeon_uvd_free_handles(struct radeon_device *rdev, void radeon_uvd_free_handles(struct radeon_device *rdev,
struct drm_file *filp); struct drm_file *filp);
int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser);
void radeon_uvd_note_usage(struct radeon_device *rdev);
struct r600_audio { struct r600_audio {
int channels; int channels;
...@@ -1268,6 +1270,9 @@ struct radeon_asic { ...@@ -1268,6 +1270,9 @@ struct radeon_asic {
void (*set_backlight_level)(struct radeon_encoder *radeon_encoder, u8 level); void (*set_backlight_level)(struct radeon_encoder *radeon_encoder, u8 level);
/* get backlight level */ /* get backlight level */
u8 (*get_backlight_level)(struct radeon_encoder *radeon_encoder); u8 (*get_backlight_level)(struct radeon_encoder *radeon_encoder);
/* audio callbacks */
void (*hdmi_enable)(struct drm_encoder *encoder, bool enable);
void (*hdmi_setmode)(struct drm_encoder *encoder, struct drm_display_mode *mode);
} display; } display;
/* copy functions for bo handling */ /* copy functions for bo handling */
struct { struct {
...@@ -1741,6 +1746,8 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); ...@@ -1741,6 +1746,8 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
tmp_ |= ((val) & ~(mask)); \ tmp_ |= ((val) & ~(mask)); \
WREG32(reg, tmp_); \ WREG32(reg, tmp_); \
} while (0) } while (0)
#define WREG32_AND(reg, and) WREG32_P(reg, 0, and)
#define WREG32_OR(reg, or) WREG32_P(reg, or, ~or)
#define WREG32_PLL_P(reg, val, mask) \ #define WREG32_PLL_P(reg, val, mask) \
do { \ do { \
uint32_t tmp_ = RREG32_PLL(reg); \ uint32_t tmp_ = RREG32_PLL(reg); \
...@@ -1874,6 +1881,8 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); ...@@ -1874,6 +1881,8 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc)) #define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc))
#define radeon_set_backlight_level(rdev, e, l) (rdev)->asic->display.set_backlight_level((e), (l)) #define radeon_set_backlight_level(rdev, e, l) (rdev)->asic->display.set_backlight_level((e), (l))
#define radeon_get_backlight_level(rdev, e) (rdev)->asic->display.get_backlight_level((e)) #define radeon_get_backlight_level(rdev, e) (rdev)->asic->display.get_backlight_level((e))
#define radeon_hdmi_enable(rdev, e, b) (rdev)->asic->display.hdmi_enable((e), (b))
#define radeon_hdmi_setmode(rdev, e, m) (rdev)->asic->display.hdmi_setmode((e), (m))
#define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence)) #define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)].emit_fence((rdev), (fence))
#define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait)) #define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)].emit_semaphore((rdev), (cp), (semaphore), (emit_wait))
#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f)) #define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f))
...@@ -1937,6 +1946,9 @@ extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc ...@@ -1937,6 +1946,9 @@ extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc
extern int radeon_resume_kms(struct drm_device *dev); extern int radeon_resume_kms(struct drm_device *dev);
extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size); extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size);
extern void radeon_program_register_sequence(struct radeon_device *rdev,
const u32 *registers,
const u32 array_size);
/* /*
* vm * vm
...@@ -2009,9 +2021,6 @@ struct radeon_hdmi_acr { ...@@ -2009,9 +2021,6 @@ struct radeon_hdmi_acr {
extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock); extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock);
extern void r600_hdmi_enable(struct drm_encoder *encoder);
extern void r600_hdmi_disable(struct drm_encoder *encoder);
extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
extern u32 r6xx_remap_render_backend(struct radeon_device *rdev, extern u32 r6xx_remap_render_backend(struct radeon_device *rdev,
u32 tiling_pipe_num, u32 tiling_pipe_num,
u32 max_rb_num, u32 max_rb_num,
...@@ -2022,8 +2031,6 @@ extern u32 r6xx_remap_render_backend(struct radeon_device *rdev, ...@@ -2022,8 +2031,6 @@ extern u32 r6xx_remap_render_backend(struct radeon_device *rdev,
* evergreen functions used by radeon_encoder.c * evergreen functions used by radeon_encoder.c
*/ */
extern void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
extern int ni_init_microcode(struct radeon_device *rdev); extern int ni_init_microcode(struct radeon_device *rdev);
extern int ni_mc_load_microcode(struct radeon_device *rdev); extern int ni_mc_load_microcode(struct radeon_device *rdev);
......
...@@ -656,6 +656,8 @@ static struct radeon_asic rs600_asic = { ...@@ -656,6 +656,8 @@ static struct radeon_asic rs600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank, .wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r100_copy_blit, .blit = &r100_copy_blit,
...@@ -732,6 +734,8 @@ static struct radeon_asic rs690_asic = { ...@@ -732,6 +734,8 @@ static struct radeon_asic rs690_asic = {
.wait_for_vblank = &avivo_wait_for_vblank, .wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r100_copy_blit, .blit = &r100_copy_blit,
...@@ -970,6 +974,8 @@ static struct radeon_asic r600_asic = { ...@@ -970,6 +974,8 @@ static struct radeon_asic r600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank, .wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1056,6 +1062,8 @@ static struct radeon_asic rs780_asic = { ...@@ -1056,6 +1062,8 @@ static struct radeon_asic rs780_asic = {
.wait_for_vblank = &avivo_wait_for_vblank, .wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1151,6 +1159,8 @@ static struct radeon_asic rv770_asic = { ...@@ -1151,6 +1159,8 @@ static struct radeon_asic rv770_asic = {
.wait_for_vblank = &avivo_wait_for_vblank, .wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &r600_hdmi_enable,
.hdmi_setmode = &r600_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1247,6 +1257,8 @@ static struct radeon_asic evergreen_asic = { ...@@ -1247,6 +1257,8 @@ static struct radeon_asic evergreen_asic = {
.wait_for_vblank = &dce4_wait_for_vblank, .wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1343,6 +1355,8 @@ static struct radeon_asic sumo_asic = { ...@@ -1343,6 +1355,8 @@ static struct radeon_asic sumo_asic = {
.wait_for_vblank = &dce4_wait_for_vblank, .wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1439,6 +1453,8 @@ static struct radeon_asic btc_asic = { ...@@ -1439,6 +1453,8 @@ static struct radeon_asic btc_asic = {
.wait_for_vblank = &dce4_wait_for_vblank, .wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
...@@ -1578,6 +1594,8 @@ static struct radeon_asic cayman_asic = { ...@@ -1578,6 +1594,8 @@ static struct radeon_asic cayman_asic = {
.wait_for_vblank = &dce4_wait_for_vblank, .wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level, .set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level, .get_backlight_level = &atombios_get_backlight_level,
.hdmi_enable = &evergreen_hdmi_enable,
.hdmi_setmode = &evergreen_hdmi_setmode,
}, },
.copy = { .copy = {
.blit = &r600_copy_blit, .blit = &r600_copy_blit,
......
...@@ -374,11 +374,12 @@ void r600_disable_interrupts(struct radeon_device *rdev); ...@@ -374,11 +374,12 @@ void r600_disable_interrupts(struct radeon_device *rdev);
void r600_rlc_stop(struct radeon_device *rdev); void r600_rlc_stop(struct radeon_device *rdev);
/* r600 audio */ /* r600 audio */
int r600_audio_init(struct radeon_device *rdev); int r600_audio_init(struct radeon_device *rdev);
void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
struct r600_audio r600_audio_status(struct radeon_device *rdev); struct r600_audio r600_audio_status(struct radeon_device *rdev);
void r600_audio_fini(struct radeon_device *rdev); void r600_audio_fini(struct radeon_device *rdev);
int r600_hdmi_buffer_status_changed(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_update_audio_settings(struct drm_encoder *encoder);
void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
/* r600 blit */ /* r600 blit */
int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages, int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages,
struct radeon_fence **fence, struct radeon_sa_bo **vb, struct radeon_fence **fence, struct radeon_sa_bo **vb,
...@@ -477,6 +478,8 @@ int evergreen_copy_dma(struct radeon_device *rdev, ...@@ -477,6 +478,8 @@ int evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset, uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages, unsigned num_gpu_pages,
struct radeon_fence **fence); struct radeon_fence **fence);
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
/* /*
* cayman * cayman
......
...@@ -2710,8 +2710,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, ...@@ -2710,8 +2710,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
dividers->enable_post_div = (dividers->fb_div & 1) ? true : false; dividers->enable_post_div = (dividers->fb_div & 1) ? true : false;
} else { } else {
if (clock_type == COMPUTE_ENGINE_PLL_PARAM) { if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
args.v3.ulClock.ulComputeClockFlag = clock_type; args.v3.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
args.v3.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
...@@ -2726,8 +2725,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, ...@@ -2726,8 +2725,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
dividers->vco_mode = (args.v3.ucCntlFlag & dividers->vco_mode = (args.v3.ucCntlFlag &
ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0; ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
} else { } else {
args.v5.ulClock.ulComputeClockFlag = clock_type; args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
args.v5.ulClock.ulClockFreq = cpu_to_le32(clock); /* 10 khz */
if (strobe_mode) if (strobe_mode)
args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN; args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
......
...@@ -549,6 +549,10 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ...@@ -549,6 +549,10 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
r = radeon_cs_handle_lockup(rdev, r); r = radeon_cs_handle_lockup(rdev, r);
return r; return r;
} }
if (parser.ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
r = radeon_cs_ib_chunk(rdev, &parser); r = radeon_cs_ib_chunk(rdev, &parser);
if (r) { if (r) {
goto out; goto out;
......
...@@ -97,6 +97,42 @@ static const char radeon_family_name[][16] = { ...@@ -97,6 +97,42 @@ static const char radeon_family_name[][16] = {
"LAST", "LAST",
}; };
/**
* radeon_program_register_sequence - program an array of registers.
*
* @rdev: radeon_device pointer
* @registers: pointer to the register array
* @array_size: size of the register array
*
* Programs an array or registers with and and or masks.
* This is a helper for setting golden registers.
*/
void radeon_program_register_sequence(struct radeon_device *rdev,
const u32 *registers,
const u32 array_size)
{
u32 tmp, reg, and_mask, or_mask;
int i;
if (array_size % 3)
return;
for (i = 0; i < array_size; i +=3) {
reg = registers[i + 0];
and_mask = registers[i + 1];
or_mask = registers[i + 2];
if (and_mask == 0xffffffff) {
tmp = or_mask;
} else {
tmp = RREG32(reg);
tmp &= ~and_mask;
tmp |= or_mask;
}
WREG32(reg, tmp);
}
}
/** /**
* radeon_surface_init - Clear GPU surface registers. * radeon_surface_init - Clear GPU surface registers.
* *
......
...@@ -776,10 +776,9 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) ...@@ -776,10 +776,9 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
} else { } else {
/* put fence directly behind firmware */ /* put fence directly behind firmware */
rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index = ALIGN(rdev->uvd_fw->size, 8);
rdev->uvd_fw->size; rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index;
rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
rdev->uvd_fw->size;
} }
} else { } else {
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include "radeon.h" #include "radeon.h"
#include "r600d.h" #include "r600d.h"
/* 1 second timeout */
#define UVD_IDLE_TIMEOUT_MS 1000
/* Firmware Names */ /* Firmware Names */
#define FIRMWARE_RV710 "radeon/RV710_uvd.bin" #define FIRMWARE_RV710 "radeon/RV710_uvd.bin"
#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin"
...@@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS); ...@@ -47,6 +50,8 @@ MODULE_FIRMWARE(FIRMWARE_CYPRESS);
MODULE_FIRMWARE(FIRMWARE_SUMO); MODULE_FIRMWARE(FIRMWARE_SUMO);
MODULE_FIRMWARE(FIRMWARE_TAHITI); MODULE_FIRMWARE(FIRMWARE_TAHITI);
static void radeon_uvd_idle_work_handler(struct work_struct *work);
int radeon_uvd_init(struct radeon_device *rdev) int radeon_uvd_init(struct radeon_device *rdev)
{ {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -54,6 +59,8 @@ int radeon_uvd_init(struct radeon_device *rdev)
const char *fw_name; const char *fw_name;
int i, r; int i, r;
INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0);
r = IS_ERR(pdev); r = IS_ERR(pdev);
if (r) { if (r) {
...@@ -107,7 +114,7 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -107,7 +114,7 @@ int radeon_uvd_init(struct radeon_device *rdev)
platform_device_unregister(pdev); platform_device_unregister(pdev);
bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) + bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
...@@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev) ...@@ -188,8 +195,6 @@ int radeon_uvd_resume(struct radeon_device *rdev)
radeon_bo_unreserve(rdev->uvd.vcpu_bo); radeon_bo_unreserve(rdev->uvd.vcpu_bo);
radeon_set_uvd_clocks(rdev, 53300, 40000);
return 0; return 0;
} }
...@@ -415,24 +420,26 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, ...@@ -415,24 +420,26 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
return -EINVAL; return -EINVAL;
} }
if (cmd == 0) { if ((start >> 28) != (end >> 28)) {
if (end & 0xFFFFFFFFF0000000) { DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",
DRM_ERROR("msg buffer %LX-%LX out of 256MB segment!\n", start, end);
return -EINVAL;
}
/* TODO: is this still necessary on NI+ ? */
if ((cmd == 0 || cmd == 0x3) &&
(start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) {
DRM_ERROR("msg/fb buffer %LX-%LX out of 256MB segment!\n",
start, end); start, end);
return -EINVAL; return -EINVAL;
} }
if (cmd == 0) {
r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
if (r) if (r)
return r; return r;
} }
if ((start & 0xFFFFFFFFF0000000) != (end & 0xFFFFFFFFF0000000)) {
DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",
start, end);
return -EINVAL;
}
return 0; return 0;
} }
...@@ -664,3 +671,24 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, ...@@ -664,3 +671,24 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
return radeon_uvd_send_msg(rdev, ring, bo, fence); return radeon_uvd_send_msg(rdev, ring, bo, fence);
} }
static void radeon_uvd_idle_work_handler(struct work_struct *work)
{
struct radeon_device *rdev =
container_of(work, struct radeon_device, uvd.idle_work.work);
if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0)
radeon_set_uvd_clocks(rdev, 0, 0);
else
schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
}
void radeon_uvd_note_usage(struct radeon_device *rdev)
{
bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
if (set_clocks)
radeon_set_uvd_clocks(rdev, 53300, 40000);
}
...@@ -52,23 +52,59 @@ static const u32 crtc_offsets[2] = ...@@ -52,23 +52,59 @@ static const u32 crtc_offsets[2] =
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL
}; };
static bool avivo_is_in_vblank(struct radeon_device *rdev, int crtc)
{
if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)
return true;
else
return false;
}
static bool avivo_is_counter_moving(struct radeon_device *rdev, int crtc)
{
u32 pos1, pos2;
pos1 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]);
pos2 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]);
if (pos1 != pos2)
return true;
else
return false;
}
/**
* avivo_wait_for_vblank - vblank wait asic callback.
*
* @rdev: radeon_device pointer
* @crtc: crtc to wait for vblank on
*
* Wait for vblank on the requested crtc (r5xx-r7xx).
*/
void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
{ {
int i; unsigned i = 0;
if (crtc >= rdev->num_crtc) if (crtc >= rdev->num_crtc)
return; return;
if (RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN) { if (!(RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN))
for (i = 0; i < rdev->usec_timeout; i++) { return;
if (!(RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK))
/* depending on when we hit vblank, we may be close to active; if so,
* wait for another frame.
*/
while (avivo_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!avivo_is_counter_moving(rdev, crtc))
break; break;
udelay(1);
} }
for (i = 0; i < rdev->usec_timeout; i++) { }
if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)
while (!avivo_is_in_vblank(rdev, crtc)) {
if (i++ % 100 == 0) {
if (!avivo_is_counter_moving(rdev, crtc))
break; break;
udelay(1);
} }
} }
} }
......
...@@ -303,8 +303,10 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) ...@@ -303,8 +303,10 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]); tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) { if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) {
radeon_wait_for_vblank(rdev, i); radeon_wait_for_vblank(rdev, i);
WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
} }
/* wait for the next frame */ /* wait for the next frame */
frame_count = radeon_get_vblank_counter(rdev, i); frame_count = radeon_get_vblank_counter(rdev, i);
...@@ -313,6 +315,15 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) ...@@ -313,6 +315,15 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
break; break;
udelay(1); udelay(1);
} }
/* XXX this is a hack to avoid strange behavior with EFI on certain systems */
WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]);
tmp &= ~AVIVO_CRTC_EN;
WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp);
WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
save->crtc_enabled[i] = false;
/* ***** */
} else { } else {
save->crtc_enabled[i] = false; save->crtc_enabled[i] = false;
} }
...@@ -338,6 +349,22 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) ...@@ -338,6 +349,22 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
} }
/* wait for the MC to settle */ /* wait for the MC to settle */
udelay(100); udelay(100);
/* lock double buffered regs */
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]);
if (!(tmp & AVIVO_D1GRPH_UPDATE_LOCK)) {
tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp);
}
tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]);
if (!(tmp & 1)) {
tmp |= 1;
WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
}
}
}
} }
void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
...@@ -367,6 +394,33 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) ...@@ -367,6 +394,33 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
} }
WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
/* unlock regs and wait for update */
for (i = 0; i < rdev->num_crtc; i++) {
if (save->crtc_enabled[i]) {
tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]);
if ((tmp & 0x3) != 0) {
tmp &= ~0x3;
WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
}
tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]);
if (tmp & AVIVO_D1GRPH_UPDATE_LOCK) {
tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp);
}
tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]);
if (tmp & 1) {
tmp &= ~1;
WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp);
}
for (j = 0; j < rdev->usec_timeout; j++) {
tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]);
if ((tmp & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) == 0)
break;
udelay(1);
}
}
}
if (rdev->family >= CHIP_R600) { if (rdev->family >= CHIP_R600) {
/* unblackout the MC */ /* unblackout the MC */
if (rdev->family >= CHIP_RV770) if (rdev->family >= CHIP_RV770)
......
This diff is collapsed.
This diff is collapsed.
...@@ -244,12 +244,21 @@ struct edid { ...@@ -244,12 +244,21 @@ struct edid {
#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
/* Short Audio Descriptor */
struct cea_sad {
u8 format;
u8 channels; /* max number of channels - 1 */
u8 freq;
u8 byte2; /* meaning depends on format */
};
struct drm_encoder; struct drm_encoder;
struct drm_connector; struct drm_connector;
struct drm_display_mode; struct drm_display_mode;
struct hdmi_avi_infoframe; struct hdmi_avi_infoframe;
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid);
int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads);
int drm_av_sync_delay(struct drm_connector *connector, int drm_av_sync_delay(struct drm_connector *connector,
struct drm_display_mode *mode); struct drm_display_mode *mode);
struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment