Commit 4ce001ab authored by Dave Airlie's avatar Dave Airlie

drm/radeon/kms: add initial radeon tv-out support.

This ports the tv-out code from the DDX to KMS.

adds a radeon.tv module option, radeon.tv=0 to disable tv
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 551ebd83
...@@ -47,7 +47,7 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \ ...@@ -47,7 +47,7 @@ radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \
radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \ radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.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 rs780.o rv770.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o \
radeon_test.o r200.o radeon_test.o r200.o radeon_legacy_tv.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
......
...@@ -2374,6 +2374,17 @@ typedef struct _ATOM_ANALOG_TV_INFO { ...@@ -2374,6 +2374,17 @@ typedef struct _ATOM_ANALOG_TV_INFO {
ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING];
} ATOM_ANALOG_TV_INFO; } ATOM_ANALOG_TV_INFO;
#define MAX_SUPPORTED_TV_TIMING_V1_2 3
typedef struct _ATOM_ANALOG_TV_INFO_V1_2 {
ATOM_COMMON_TABLE_HEADER sHeader;
UCHAR ucTV_SupportedStandard;
UCHAR ucTV_BootUpDefaultStandard;
UCHAR ucExt_TV_ASIC_ID;
UCHAR ucExt_TV_ASIC_SlaveAddr;
ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];
} ATOM_ANALOG_TV_INFO_V1_2;
/**************************************************************************/ /**************************************************************************/
/* VRAM usage and their defintions */ /* VRAM usage and their defintions */
......
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#include "atom.h" #include "atom.h"
#include "atom-bits.h" #include "atom-bits.h"
/* evil but including atombios.h is much worse */
bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing,
int32_t *pixel_clock);
static void atombios_overscan_setup(struct drm_crtc *crtc, static void atombios_overscan_setup(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
...@@ -89,17 +93,32 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) ...@@ -89,17 +93,32 @@ static void atombios_scaler_setup(struct drm_crtc *crtc)
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
ENABLE_SCALER_PS_ALLOCATION args; ENABLE_SCALER_PS_ALLOCATION args;
int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
/* fixme - fill in enc_priv for atom dac */ /* fixme - fill in enc_priv for atom dac */
enum radeon_tv_std tv_std = TV_STD_NTSC; enum radeon_tv_std tv_std = TV_STD_NTSC;
bool is_tv = false, is_cv = false;
struct drm_encoder *encoder;
if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id) if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
return; return;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
/* find tv std */
if (encoder->crtc == crtc) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
tv_std = tv_dac->tv_std;
is_tv = true;
}
}
}
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.ucScaler = radeon_crtc->crtc_id; args.ucScaler = radeon_crtc->crtc_id;
if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) { if (is_tv) {
switch (tv_std) { switch (tv_std) {
case TV_STD_NTSC: case TV_STD_NTSC:
default: default:
...@@ -128,7 +147,7 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) ...@@ -128,7 +147,7 @@ static void atombios_scaler_setup(struct drm_crtc *crtc)
break; break;
} }
args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
} else if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT)) { } else if (is_cv) {
args.ucTVStandard = ATOM_TV_CV; args.ucTVStandard = ATOM_TV_CV;
args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
} else { } else {
...@@ -151,9 +170,9 @@ static void atombios_scaler_setup(struct drm_crtc *crtc) ...@@ -151,9 +170,9 @@ static void atombios_scaler_setup(struct drm_crtc *crtc)
} }
} }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) if ((is_tv || is_cv)
&& rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) { && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
atom_rv515_force_tv_scaler(rdev); atom_rv515_force_tv_scaler(rdev, radeon_crtc);
} }
} }
...@@ -551,16 +570,41 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, ...@@ -551,16 +570,41 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder; struct drm_encoder *encoder;
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
int need_tv_timings = 0;
bool ret;
/* TODO color tiling */ /* TODO color tiling */
memset(&crtc_timing, 0, sizeof(crtc_timing)); memset(&crtc_timing, 0, sizeof(crtc_timing));
/* TODO tv */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
/* find tv std */
if (encoder->crtc == crtc) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
if (tv_dac) {
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M)
need_tv_timings = 1;
else
need_tv_timings = 2;
break;
}
}
}
} }
crtc_timing.ucCRTC = radeon_crtc->crtc_id; crtc_timing.ucCRTC = radeon_crtc->crtc_id;
if (need_tv_timings) {
ret = radeon_atom_get_tv_timings(rdev, need_tv_timings - 1,
&crtc_timing, &adjusted_mode->clock);
if (ret == false)
need_tv_timings = 0;
}
if (!need_tv_timings) {
crtc_timing.usH_Total = adjusted_mode->crtc_htotal; crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
...@@ -587,6 +631,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, ...@@ -587,6 +631,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
}
atombios_crtc_set_pll(crtc, adjusted_mode); atombios_crtc_set_pll(crtc, adjusted_mode);
atombios_crtc_set_timing(crtc, &crtc_timing); atombios_crtc_set_timing(crtc, &crtc_timing);
......
...@@ -66,6 +66,7 @@ extern int radeon_gart_size; ...@@ -66,6 +66,7 @@ extern int radeon_gart_size;
extern int radeon_benchmarking; extern int radeon_benchmarking;
extern int radeon_testing; extern int radeon_testing;
extern int radeon_connector_table; extern int radeon_connector_table;
extern int radeon_tv;
/* /*
* Copy from radeon_drv.h so we don't have to include both and have conflicting * Copy from radeon_drv.h so we don't have to include both and have conflicting
......
...@@ -471,11 +471,6 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct ...@@ -471,11 +471,6 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
continue; continue;
} }
if (i == ATOM_DEVICE_TV1_INDEX) {
DRM_DEBUG("Skipping TV Out\n");
continue;
}
bios_connectors[i].connector_type = bios_connectors[i].connector_type =
supported_devices_connector_convert[ci.sucConnectorInfo. supported_devices_connector_convert[ci.sucConnectorInfo.
sbfAccess. sbfAccess.
...@@ -858,6 +853,72 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) ...@@ -858,6 +853,72 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
return p_dac; return p_dac;
} }
bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing,
int32_t *pixel_clock)
{
struct radeon_mode_info *mode_info = &rdev->mode_info;
ATOM_ANALOG_TV_INFO *tv_info;
ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
ATOM_DTD_FORMAT *dtd_timings;
int data_index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
u8 frev, crev;
uint16_t data_offset;
atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset);
switch (crev) {
case 1:
tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
if (index > MAX_SUPPORTED_TV_TIMING)
return false;
crtc_timing->usH_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
crtc_timing->usH_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
crtc_timing->usH_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
crtc_timing->usH_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
crtc_timing->usV_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
crtc_timing->usV_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
crtc_timing->usV_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
crtc_timing->usV_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
crtc_timing->susModeMiscInfo = tv_info->aModeTimings[index].susModeMiscInfo;
crtc_timing->ucOverscanRight = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanRight);
crtc_timing->ucOverscanLeft = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanLeft);
crtc_timing->ucOverscanBottom = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanBottom);
crtc_timing->ucOverscanTop = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanTop);
*pixel_clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
if (index == 1) {
/* PAL timings appear to have wrong values for totals */
crtc_timing->usH_Total -= 1;
crtc_timing->usV_Total -= 1;
}
break;
case 2:
tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset);
if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
return false;
dtd_timings = &tv_info_v1_2->aModeTimings[index];
crtc_timing->usH_Total = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
crtc_timing->usH_Disp = le16_to_cpu(dtd_timings->usHActive);
crtc_timing->usH_SyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
crtc_timing->usH_SyncWidth = le16_to_cpu(dtd_timings->usHSyncWidth);
crtc_timing->usV_Total = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
crtc_timing->usV_Disp = le16_to_cpu(dtd_timings->usVActive);
crtc_timing->usV_SyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
crtc_timing->usV_SyncWidth = le16_to_cpu(dtd_timings->usVSyncWidth);
crtc_timing->susModeMiscInfo.usAccess = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
*pixel_clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
break;
}
return true;
}
struct radeon_encoder_tv_dac * struct radeon_encoder_tv_dac *
radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
{ {
...@@ -948,10 +1009,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) ...@@ -948,10 +1009,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
uint32_t bios_2_scratch, bios_6_scratch; uint32_t bios_2_scratch, bios_6_scratch;
if (rdev->family >= CHIP_R600) { if (rdev->family >= CHIP_R600) {
bios_2_scratch = RREG32(R600_BIOS_0_SCRATCH); bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH); bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
} else { } else {
bios_2_scratch = RREG32(RADEON_BIOS_0_SCRATCH); bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH); bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
} }
......
...@@ -94,6 +94,54 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) ...@@ -94,6 +94,54 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
return NULL; return NULL;
} }
/*
* radeon_connector_analog_encoder_conflict_solve
* - search for other connectors sharing this encoder
* if priority is true, then set them disconnected if this is connected
* if priority is false, set us disconnected if they are connected
*/
static enum drm_connector_status
radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
struct drm_encoder *encoder,
enum drm_connector_status current_status,
bool priority)
{
struct drm_device *dev = connector->dev;
struct drm_connector *conflict;
int i;
list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
if (conflict == connector)
continue;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (conflict->encoder_ids[i] == 0)
break;
/* if the IDs match */
if (conflict->encoder_ids[i] == encoder->base.id) {
if (conflict->status != connector_status_connected)
continue;
if (priority == true) {
DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
conflict->status = connector_status_disconnected;
radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
} else {
DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
current_status = connector_status_disconnected;
}
break;
}
}
}
return current_status;
}
static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
...@@ -213,7 +261,6 @@ static int radeon_vga_get_modes(struct drm_connector *connector) ...@@ -213,7 +261,6 @@ static int radeon_vga_get_modes(struct drm_connector *connector)
static int radeon_vga_mode_valid(struct drm_connector *connector, static int radeon_vga_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
return MODE_OK; return MODE_OK;
} }
...@@ -225,22 +272,22 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect ...@@ -225,22 +272,22 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
bool dret; bool dret;
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
radeon_i2c_do_lock(radeon_connector, 1); radeon_i2c_do_lock(radeon_connector, 1);
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0); radeon_i2c_do_lock(radeon_connector, 0);
if (dret) if (dret)
ret = connector_status_connected; ret = connector_status_connected;
else {
/* if EDID fails to a load detect */
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
else { else {
encoder_funcs = encoder->helper_private; encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector); ret = encoder_funcs->detect(encoder, connector);
} }
}
if (ret == connector_status_connected)
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
return ret; return ret;
} }
...@@ -259,21 +306,87 @@ struct drm_connector_funcs radeon_vga_connector_funcs = { ...@@ -259,21 +306,87 @@ struct drm_connector_funcs radeon_vga_connector_funcs = {
.set_property = radeon_connector_set_property, .set_property = radeon_connector_set_property,
}; };
static struct drm_display_mode tv_fixed_mode = {
DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 38250, 800, 832,
912, 1024, 0, 600, 603, 607, 624, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC),
};
static int radeon_tv_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *tv_mode;
tv_mode = drm_mode_duplicate(dev, &tv_fixed_mode);
tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, tv_mode);
return 1;
}
static int radeon_tv_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
return MODE_OK;
}
static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
{
struct drm_encoder *encoder;
struct drm_encoder_helper_funcs *encoder_funcs;
int ret;
encoder = radeon_best_single_encoder(connector);
if (!encoder)
ret = connector_status_disconnected;
else {
encoder_funcs = encoder->helper_private;
ret = encoder_funcs->detect(encoder, connector);
}
if (ret == connector_status_connected)
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
radeon_connector_update_scratch_regs(connector, ret);
return ret;
}
struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
.get_modes = radeon_tv_get_modes,
.mode_valid = radeon_tv_mode_valid,
.best_encoder = radeon_best_single_encoder,
};
struct drm_connector_funcs radeon_tv_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = radeon_tv_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = radeon_connector_destroy,
.set_property = radeon_connector_set_property,
};
static int radeon_dvi_get_modes(struct drm_connector *connector) static int radeon_dvi_get_modes(struct drm_connector *connector)
{ {
struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector *radeon_connector = to_radeon_connector(connector);
int ret; int ret;
ret = radeon_ddc_get_modes(radeon_connector); ret = radeon_ddc_get_modes(radeon_connector);
/* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */
radeon_connector_update_scratch_regs(connector, connector_status_connected);
return ret; return ret;
} }
/*
* DVI is complicated
* Do a DDC probe, if DDC probe passes, get the full EDID so
* we can do analog/digital monitor detection at this point.
* If the monitor is an analog monitor or we got no DDC,
* we need to find the DAC encoder object for this connector.
* If we got no DDC, we do load detection on the DAC encoder object.
* If we got analog DDC or load detection passes on the DAC encoder
* we have to check if this analog encoder is shared with anyone else (TV)
* if its shared we have to set the other connector to disconnected.
*/
static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
{ {
struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder; struct drm_encoder *encoder = NULL;
struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_mode_object *obj; struct drm_mode_object *obj;
int i; int i;
...@@ -283,9 +396,28 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect ...@@ -283,9 +396,28 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
radeon_i2c_do_lock(radeon_connector, 1); radeon_i2c_do_lock(radeon_connector, 1);
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector, 0); radeon_i2c_do_lock(radeon_connector, 0);
if (dret) if (dret) {
radeon_i2c_do_lock(radeon_connector, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector, 0);
if (!radeon_connector->edid) {
DRM_ERROR("DDC responded but not EDID found for %s\n",
drm_get_connector_name(connector));
} else {
radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
/* if this isn't a digital monitor
then we need to make sure we don't have any
TV conflicts */
ret = connector_status_connected; ret = connector_status_connected;
else { }
}
if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
goto out;
/* find analog encoder */
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0) if (connector->encoder_ids[i] == 0)
break; break;
...@@ -300,15 +432,22 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect ...@@ -300,15 +432,22 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
encoder_funcs = encoder->helper_private; encoder_funcs = encoder->helper_private;
if (encoder_funcs->detect) { if (encoder_funcs->detect) {
if (ret != connector_status_connected) {
ret = encoder_funcs->detect(encoder, connector); ret = encoder_funcs->detect(encoder, connector);
if (ret == connector_status_connected) { if (ret == connector_status_connected) {
radeon_connector->use_digital = 0; radeon_connector->use_digital = false;
break;
} }
} }
break;
}
} }
if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
encoder) {
ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
} }
out:
/* updated in get modes as well since we need to know if it's analog or digital */ /* updated in get modes as well since we need to know if it's analog or digital */
radeon_connector_update_scratch_regs(connector, ret); radeon_connector_update_scratch_regs(connector, ret);
return ret; return ret;
...@@ -332,7 +471,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) ...@@ -332,7 +471,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
encoder = obj_to_encoder(obj); encoder = obj_to_encoder(obj);
if (radeon_connector->use_digital) { if (radeon_connector->use_digital == true) {
if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
return encoder; return encoder;
} else { } else {
...@@ -385,10 +524,7 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -385,10 +524,7 @@ radeon_add_atom_connector(struct drm_device *dev,
uint32_t subpixel_order = SubPixelNone; uint32_t subpixel_order = SubPixelNone;
/* fixme - tv/cv/din */ /* fixme - tv/cv/din */
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || if (connector_type == DRM_MODE_CONNECTOR_Unknown)
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
(connector_type == DRM_MODE_CONNECTOR_Composite) ||
(connector_type == DRM_MODE_CONNECTOR_9PinDIN))
return; return;
/* see if we already added it */ /* see if we already added it */
...@@ -480,6 +616,10 @@ radeon_add_atom_connector(struct drm_device *dev, ...@@ -480,6 +616,10 @@ radeon_add_atom_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_9PinDIN: case DRM_MODE_CONNECTOR_9PinDIN:
if (radeon_tv == 1) {
drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
}
break; break;
case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_LVDS:
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
...@@ -522,10 +662,7 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -522,10 +662,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
uint32_t subpixel_order = SubPixelNone; uint32_t subpixel_order = SubPixelNone;
/* fixme - tv/cv/din */ /* fixme - tv/cv/din */
if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || if (connector_type == DRM_MODE_CONNECTOR_Unknown)
(connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
(connector_type == DRM_MODE_CONNECTOR_Composite) ||
(connector_type == DRM_MODE_CONNECTOR_9PinDIN))
return; return;
/* see if we already added it */ /* see if we already added it */
...@@ -578,6 +715,10 @@ radeon_add_legacy_connector(struct drm_device *dev, ...@@ -578,6 +715,10 @@ radeon_add_legacy_connector(struct drm_device *dev,
case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_SVIDEO:
case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_Composite:
case DRM_MODE_CONNECTOR_9PinDIN: case DRM_MODE_CONNECTOR_9PinDIN:
if (radeon_tv == 1) {
drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
}
break; break;
case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_LVDS:
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
......
...@@ -312,7 +312,7 @@ static void radeon_print_display_setup(struct drm_device *dev) ...@@ -312,7 +312,7 @@ static void radeon_print_display_setup(struct drm_device *dev)
} }
} }
bool radeon_setup_enc_conn(struct drm_device *dev) static bool radeon_setup_enc_conn(struct drm_device *dev)
{ {
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct drm_connector *drm_connector; struct drm_connector *drm_connector;
...@@ -346,9 +346,13 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) ...@@ -346,9 +346,13 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
if (!radeon_connector->ddc_bus) if (!radeon_connector->ddc_bus)
return -1; return -1;
if (!radeon_connector->edid) {
radeon_i2c_do_lock(radeon_connector, 1); radeon_i2c_do_lock(radeon_connector, 1);
edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector, 0); radeon_i2c_do_lock(radeon_connector, 0);
} else
edid = radeon_connector->edid;
if (edid) { if (edid) {
/* update digital bits here */ /* update digital bits here */
if (edid->input & DRM_EDID_INPUT_DIGITAL) if (edid->input & DRM_EDID_INPUT_DIGITAL)
...@@ -677,7 +681,6 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, ...@@ -677,7 +681,6 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
continue; continue;
if (first) { if (first) {
radeon_crtc->rmx_type = radeon_encoder->rmx_type; radeon_crtc->rmx_type = radeon_encoder->rmx_type;
radeon_crtc->devices = radeon_encoder->devices;
memcpy(&radeon_crtc->native_mode, memcpy(&radeon_crtc->native_mode,
&radeon_encoder->native_mode, &radeon_encoder->native_mode,
sizeof(struct radeon_native_mode)); sizeof(struct radeon_native_mode));
......
...@@ -91,6 +91,7 @@ int radeon_gart_size = 512; /* default gart size */ ...@@ -91,6 +91,7 @@ int radeon_gart_size = 512; /* default gart size */
int radeon_benchmarking = 0; int radeon_benchmarking = 0;
int radeon_testing = 0; int radeon_testing = 0;
int radeon_connector_table = 0; int radeon_connector_table = 0;
int radeon_tv = 1;
#endif #endif
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
...@@ -123,6 +124,9 @@ module_param_named(test, radeon_testing, int, 0444); ...@@ -123,6 +124,9 @@ module_param_named(test, radeon_testing, int, 0444);
MODULE_PARM_DESC(connector_table, "Force connector table"); MODULE_PARM_DESC(connector_table, "Force connector table");
module_param_named(connector_table, radeon_connector_table, int, 0444); module_param_named(connector_table, radeon_connector_table, int, 0444);
MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
module_param_named(tv, radeon_tv, int, 0444);
#endif #endif
static int radeon_suspend(struct drm_device *dev, pm_message_t state) static int radeon_suspend(struct drm_device *dev, pm_message_t state)
......
...@@ -126,6 +126,23 @@ radeon_link_encoder_connector(struct drm_device *dev) ...@@ -126,6 +126,23 @@ radeon_link_encoder_connector(struct drm_device *dev)
} }
} }
void radeon_encoder_set_active_device(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
radeon_encoder->active_device = radeon_encoder->devices & radeon_connector->devices;
DRM_INFO("setting active device to %08x from %08x %08x for encoder %d\n",
radeon_encoder->active_device, radeon_encoder->devices,
radeon_connector->devices, encoder->encoder_type);
}
}
}
static struct drm_connector * static struct drm_connector *
radeon_get_connector_for_encoder(struct drm_encoder *encoder) radeon_get_connector_for_encoder(struct drm_encoder *encoder)
{ {
...@@ -244,9 +261,9 @@ atombios_dac_setup(struct drm_encoder *encoder, int action) ...@@ -244,9 +261,9 @@ atombios_dac_setup(struct drm_encoder *encoder, int action)
args.ucAction = action; args.ucAction = action;
if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT))
args.ucDacStandard = ATOM_DAC1_PS2; args.ucDacStandard = ATOM_DAC1_PS2;
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.ucDacStandard = ATOM_DAC1_CV; args.ucDacStandard = ATOM_DAC1_CV;
else { else {
switch (tv_std) { switch (tv_std) {
...@@ -288,7 +305,7 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) ...@@ -288,7 +305,7 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
args.sTVEncoder.ucAction = action; args.sTVEncoder.ucAction = action;
if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.sTVEncoder.ucTvStandard = ATOM_TV_CV; args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
else { else {
switch (tv_std) { switch (tv_std) {
...@@ -825,10 +842,10 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable) ...@@ -825,10 +842,10 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
/* XXX: fix up scratch reg handling */ /* XXX: fix up scratch reg handling */
temp = RREG32(reg); temp = RREG32(reg);
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
WREG32(reg, (ATOM_S3_TV1_ACTIVE | WREG32(reg, (ATOM_S3_TV1_ACTIVE |
(radeon_crtc->crtc_id << 18))); (radeon_crtc->crtc_id << 18)));
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24)));
else else
WREG32(reg, 0); WREG32(reg, 0);
...@@ -851,9 +868,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) ...@@ -851,9 +868,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
int index = 0; int index = 0;
bool is_dig = false; bool is_dig = false;
int devices;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
/* on DPMS off we have no idea if active device is meaningful */
if (mode != DRM_MODE_DPMS_ON && !radeon_encoder->active_device)
devices = radeon_encoder->devices;
else
devices = radeon_encoder->active_device;
DRM_INFO("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
radeon_encoder->encoder_id, mode, radeon_encoder->devices,
radeon_encoder->active_device);
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
...@@ -881,18 +908,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) ...@@ -881,18 +908,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (devices & (ATOM_DEVICE_TV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (devices & (ATOM_DEVICE_CV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
else else
index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (devices & (ATOM_DEVICE_TV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (devices & (ATOM_DEVICE_CV_SUPPORT))
index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
else else
index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
...@@ -979,18 +1006,18 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) ...@@ -979,18 +1006,18 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DAC1: case ENCODER_OBJECT_ID_INTERNAL_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
else else
args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
else else
args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
...@@ -1019,17 +1046,17 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder) ...@@ -1019,17 +1046,17 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
else else
args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
else else
args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
...@@ -1097,7 +1124,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -1097,7 +1124,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
atombios_set_encoder_crtc_source(encoder); atombios_set_encoder_crtc_source(encoder);
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
atombios_yuv_setup(encoder, true); atombios_yuv_setup(encoder, true);
else else
atombios_yuv_setup(encoder, false); atombios_yuv_setup(encoder, false);
...@@ -1135,7 +1162,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -1135,7 +1162,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
case ENCODER_OBJECT_ID_INTERNAL_DAC2: case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
atombios_dac_setup(encoder, ATOM_ENABLE); atombios_dac_setup(encoder, ATOM_ENABLE);
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
atombios_tv_setup(encoder, ATOM_ENABLE); atombios_tv_setup(encoder, ATOM_ENABLE);
break; break;
} }
...@@ -1143,11 +1170,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, ...@@ -1143,11 +1170,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
} }
static bool static bool
atombios_dac_load_detect(struct drm_encoder *encoder) atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{ {
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_connector *radeon_connector = to_radeon_connector(connector);
if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT |
ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_CV_SUPPORT |
...@@ -1168,15 +1196,15 @@ atombios_dac_load_detect(struct drm_encoder *encoder) ...@@ -1168,15 +1196,15 @@ atombios_dac_load_detect(struct drm_encoder *encoder)
else else
args.sDacload.ucDacType = ATOM_DAC_B; args.sDacload.ucDacType = ATOM_DAC_B;
if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)
args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)
args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
if (crev >= 3) if (crev >= 3)
args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
} else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
if (crev >= 3) if (crev >= 3)
args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
...@@ -1195,9 +1223,10 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec ...@@ -1195,9 +1223,10 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
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_connector *radeon_connector = to_radeon_connector(connector);
uint32_t bios_0_scratch; uint32_t bios_0_scratch;
if (!atombios_dac_load_detect(encoder)) { if (!atombios_dac_load_detect(encoder, connector)) {
DRM_DEBUG("detect returned false \n"); DRM_DEBUG("detect returned false \n");
return connector_status_unknown; return connector_status_unknown;
} }
...@@ -1207,17 +1236,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec ...@@ -1207,17 +1236,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
else else
bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch); DRM_DEBUG("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
if (bios_0_scratch & ATOM_S0_CRT1_MASK) if (bios_0_scratch & ATOM_S0_CRT1_MASK)
return connector_status_connected; return connector_status_connected;
} else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { }
if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
if (bios_0_scratch & ATOM_S0_CRT2_MASK) if (bios_0_scratch & ATOM_S0_CRT2_MASK)
return connector_status_connected; return connector_status_connected;
} else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { }
if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
return connector_status_connected; return connector_status_connected;
} else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { }
if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
return connector_status_connected; /* CTV */ return connector_status_connected; /* CTV */
else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
...@@ -1230,6 +1262,8 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) ...@@ -1230,6 +1262,8 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
{ {
radeon_atom_output_lock(encoder, true); radeon_atom_output_lock(encoder, true);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_atom_encoder_commit(struct drm_encoder *encoder) static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
...@@ -1238,12 +1272,21 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder) ...@@ -1238,12 +1272,21 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
radeon_atom_output_lock(encoder, false); radeon_atom_output_lock(encoder, false);
} }
static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
DRM_INFO("setting active device to 0 for encoder %d\n", encoder->encoder_type);
radeon_encoder->active_device = 0;
}
static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
.dpms = radeon_atom_encoder_dpms, .dpms = radeon_atom_encoder_dpms,
.mode_fixup = radeon_atom_mode_fixup, .mode_fixup = radeon_atom_mode_fixup,
.prepare = radeon_atom_encoder_prepare, .prepare = radeon_atom_encoder_prepare,
.mode_set = radeon_atom_encoder_mode_set, .mode_set = radeon_atom_encoder_mode_set,
.commit = radeon_atom_encoder_commit, .commit = radeon_atom_encoder_commit,
.disable = radeon_atom_encoder_disable,
/* no detect for TMDS/LVDS yet */ /* no detect for TMDS/LVDS yet */
}; };
...@@ -1268,6 +1311,18 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = { ...@@ -1268,6 +1311,18 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = {
.destroy = radeon_enc_destroy, .destroy = radeon_enc_destroy,
}; };
struct radeon_encoder_atom_dac *
radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder)
{
struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL);
if (!dac)
return NULL;
dac->tv_std = TV_STD_NTSC;
return dac;
}
struct radeon_encoder_atom_dig * struct radeon_encoder_atom_dig *
radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
{ {
...@@ -1336,6 +1391,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su ...@@ -1336,6 +1391,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC);
radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
break; break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1: case ENCODER_OBJECT_ID_INTERNAL_DVO1:
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <drm/radeon_drm.h> #include <drm/radeon_drm.h>
#include "radeon_fixed.h" #include "radeon_fixed.h"
#include "radeon.h" #include "radeon.h"
#include "atom.h"
static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc, static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
...@@ -501,6 +502,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ...@@ -501,6 +502,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_encoder *encoder;
int format; int format;
int hsync_start; int hsync_start;
int hsync_wid; int hsync_wid;
...@@ -509,8 +511,19 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ...@@ -509,8 +511,19 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
uint32_t crtc_h_sync_strt_wid; uint32_t crtc_h_sync_strt_wid;
uint32_t crtc_v_total_disp; uint32_t crtc_v_total_disp;
uint32_t crtc_v_sync_strt_wid; uint32_t crtc_v_sync_strt_wid;
bool is_tv = false;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
is_tv = true;
DRM_INFO("crtc %d is connected to a TV\n", radeon_crtc->crtc_id);
break;
}
}
}
switch (crtc->fb->bits_per_pixel) { switch (crtc->fb->bits_per_pixel) {
case 15: /* 555 */ case 15: /* 555 */
...@@ -642,6 +655,11 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod ...@@ -642,6 +655,11 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
} }
if (is_tv)
radeon_legacy_tv_adjust_crtc_reg(encoder, &crtc_h_total_disp,
&crtc_h_sync_strt_wid, &crtc_v_total_disp,
&crtc_v_sync_strt_wid);
WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp); WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid); WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp); WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
...@@ -668,7 +686,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ...@@ -668,7 +686,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
uint32_t pll_ref_div = 0; uint32_t pll_ref_div = 0;
uint32_t pll_fb_post_div = 0; uint32_t pll_fb_post_div = 0;
uint32_t htotal_cntl = 0; uint32_t htotal_cntl = 0;
bool is_tv = false;
struct radeon_pll *pll; struct radeon_pll *pll;
struct { struct {
...@@ -703,6 +721,13 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ...@@ -703,6 +721,13 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) { if (encoder->crtc == crtc) {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
is_tv = true;
break;
}
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
...@@ -766,6 +791,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ...@@ -766,6 +791,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
~(RADEON_PIX2CLK_SRC_SEL_MASK)) | ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
if (is_tv) {
radeon_legacy_tv_adjust_pll2(encoder, &htotal_cntl,
&pll_ref_div, &pll_fb_post_div,
&pixclks_cntl);
}
WREG32_PLL_P(RADEON_PIXCLKS_CNTL, WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
RADEON_PIX2CLK_SRC_SEL_CPUCLK, RADEON_PIX2CLK_SRC_SEL_CPUCLK,
~(RADEON_PIX2CLK_SRC_SEL_MASK)); ~(RADEON_PIX2CLK_SRC_SEL_MASK));
...@@ -820,6 +851,15 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ...@@ -820,6 +851,15 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
} else { } else {
uint32_t pixclks_cntl;
if (is_tv) {
pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
radeon_legacy_tv_adjust_pll1(encoder, &htotal_cntl, &pll_ref_div,
&pll_fb_post_div, &pixclks_cntl);
}
if (rdev->flags & RADEON_IS_MOBILITY) { if (rdev->flags & RADEON_IS_MOBILITY) {
/* A temporal workaround for the occational blanking on certain laptop panels. /* A temporal workaround for the occational blanking on certain laptop panels.
This appears to related to the PLL divider registers (fail to lock?). This appears to related to the PLL divider registers (fail to lock?).
...@@ -914,6 +954,8 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) ...@@ -914,6 +954,8 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
RADEON_VCLK_SRC_SEL_PPLLCLK, RADEON_VCLK_SRC_SEL_PPLLCLK,
~(RADEON_VCLK_SRC_SEL_MASK)); ~(RADEON_VCLK_SRC_SEL_MASK));
if (is_tv)
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
} }
} }
......
...@@ -29,6 +29,15 @@ ...@@ -29,6 +29,15 @@
#include "radeon.h" #include "radeon.h"
#include "atom.h" #include "atom.h"
static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_encoder_helper_funcs *encoder_funcs;
encoder_funcs = encoder->helper_private;
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder->active_device = 0;
}
static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
{ {
...@@ -98,6 +107,8 @@ static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) ...@@ -98,6 +107,8 @@ static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
else else
radeon_combios_output_lock(encoder, true); radeon_combios_output_lock(encoder, true);
radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) static void radeon_legacy_lvds_commit(struct drm_encoder *encoder)
...@@ -195,6 +206,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { ...@@ -195,6 +206,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
.prepare = radeon_legacy_lvds_prepare, .prepare = radeon_legacy_lvds_prepare,
.mode_set = radeon_legacy_lvds_mode_set, .mode_set = radeon_legacy_lvds_mode_set,
.commit = radeon_legacy_lvds_commit, .commit = radeon_legacy_lvds_commit,
.disable = radeon_legacy_encoder_disable,
}; };
...@@ -260,6 +272,7 @@ static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) ...@@ -260,6 +272,7 @@ static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder)
else else
radeon_combios_output_lock(encoder, true); radeon_combios_output_lock(encoder, true);
radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder)
...@@ -402,6 +415,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_fu ...@@ -402,6 +415,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_fu
.mode_set = radeon_legacy_primary_dac_mode_set, .mode_set = radeon_legacy_primary_dac_mode_set,
.commit = radeon_legacy_primary_dac_commit, .commit = radeon_legacy_primary_dac_commit,
.detect = radeon_legacy_primary_dac_detect, .detect = radeon_legacy_primary_dac_detect,
.disable = radeon_legacy_encoder_disable,
}; };
...@@ -454,6 +468,7 @@ static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) ...@@ -454,6 +468,7 @@ static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder)
else else
radeon_combios_output_lock(encoder, true); radeon_combios_output_lock(encoder, true);
radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder)
...@@ -566,6 +581,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs ...@@ -566,6 +581,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs
.prepare = radeon_legacy_tmds_int_prepare, .prepare = radeon_legacy_tmds_int_prepare,
.mode_set = radeon_legacy_tmds_int_mode_set, .mode_set = radeon_legacy_tmds_int_mode_set,
.commit = radeon_legacy_tmds_int_commit, .commit = radeon_legacy_tmds_int_commit,
.disable = radeon_legacy_encoder_disable,
}; };
...@@ -620,6 +636,7 @@ static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) ...@@ -620,6 +636,7 @@ static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder)
else else
radeon_combios_output_lock(encoder, true); radeon_combios_output_lock(encoder, true);
radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder)
...@@ -706,6 +723,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs ...@@ -706,6 +723,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs
.prepare = radeon_legacy_tmds_ext_prepare, .prepare = radeon_legacy_tmds_ext_prepare,
.mode_set = radeon_legacy_tmds_ext_mode_set, .mode_set = radeon_legacy_tmds_ext_mode_set,
.commit = radeon_legacy_tmds_ext_commit, .commit = radeon_legacy_tmds_ext_commit,
.disable = radeon_legacy_encoder_disable,
}; };
...@@ -727,17 +745,21 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) ...@@ -727,17 +745,21 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
{ {
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);
uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0;
/* uint32_t tv_master_cntl = 0; */ uint32_t tv_master_cntl = 0;
bool is_tv;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
if (rdev->family == CHIP_R200) if (rdev->family == CHIP_R200)
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
else { else {
if (is_tv)
tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL);
else
crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL); crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
/* FIXME TV */
/* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
} }
...@@ -746,8 +768,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) ...@@ -746,8 +768,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
if (rdev->family == CHIP_R200) { if (rdev->family == CHIP_R200) {
fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
} else { } else {
if (is_tv)
tv_master_cntl |= RADEON_TV_ON;
else
crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
/* tv_master_cntl |= RADEON_TV_ON; */
if (rdev->family == CHIP_R420 || if (rdev->family == CHIP_R420 ||
rdev->family == CHIP_R423 || rdev->family == CHIP_R423 ||
rdev->family == CHIP_RV410) rdev->family == CHIP_RV410)
...@@ -768,8 +793,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) ...@@ -768,8 +793,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
if (rdev->family == CHIP_R200) if (rdev->family == CHIP_R200)
fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
else { else {
if (is_tv)
tv_master_cntl &= ~RADEON_TV_ON;
else
crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
/* tv_master_cntl &= ~RADEON_TV_ON; */
if (rdev->family == CHIP_R420 || if (rdev->family == CHIP_R420 ||
rdev->family == CHIP_R423 || rdev->family == CHIP_R423 ||
rdev->family == CHIP_RV410) rdev->family == CHIP_RV410)
...@@ -789,8 +817,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) ...@@ -789,8 +817,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
if (rdev->family == CHIP_R200) { if (rdev->family == CHIP_R200) {
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
} else { } else {
if (is_tv)
WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
else
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
/* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
} }
...@@ -809,6 +839,7 @@ static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) ...@@ -809,6 +839,7 @@ static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
else else
radeon_combios_output_lock(encoder, true); radeon_combios_output_lock(encoder, true);
radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
radeon_encoder_set_active_device(encoder);
} }
static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder)
...@@ -831,11 +862,15 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, ...@@ -831,11 +862,15 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0;
uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0;
bool is_tv = false;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
if (rdev->family != CHIP_R200) { if (rdev->family != CHIP_R200) {
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL); tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
if (rdev->family == CHIP_R420 || if (rdev->family == CHIP_R420 ||
...@@ -858,7 +893,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, ...@@ -858,7 +893,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
} }
/* FIXME TV */ /* FIXME TV */
if (radeon_encoder->enc_priv) { if (tv_dac) {
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
RADEON_TV_DAC_NHOLD | RADEON_TV_DAC_NHOLD |
...@@ -875,11 +910,52 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, ...@@ -875,11 +910,52 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
if (ASIC_IS_R300(rdev)) { if (ASIC_IS_R300(rdev)) {
gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1; gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1;
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL); disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
} else if (rdev->family == CHIP_R200) }
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev))
disp_tv_out_cntl = RREG32(RADEON_DISP_TV_OUT_CNTL);
else else
disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG); disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
if (rdev->family == CHIP_R200)
fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
if (is_tv) {
uint32_t dac_cntl;
dac_cntl = RREG32(RADEON_DAC_CNTL);
dac_cntl &= ~RADEON_DAC_TVO_EN;
WREG32(RADEON_DAC_CNTL, dac_cntl);
if (ASIC_IS_R300(rdev))
gpiopad_a = RREG32(RADEON_GPIOPAD_A) & ~1;
dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~RADEON_DAC2_DAC2_CLK_SEL;
if (radeon_crtc->crtc_id == 0) {
if (ASIC_IS_R300(rdev)) {
disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC |
RADEON_DISP_TV_SOURCE_CRTC);
}
if (rdev->family >= CHIP_R200) {
disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
} else {
disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
}
} else {
if (ASIC_IS_R300(rdev)) {
disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
}
if (rdev->family >= CHIP_R200) {
disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
} else {
disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
}
}
WREG32(RADEON_DAC_CNTL2, dac2_cntl);
} else {
dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL;
if (radeon_crtc->crtc_id == 0) { if (radeon_crtc->crtc_id == 0) {
...@@ -902,17 +978,25 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, ...@@ -902,17 +978,25 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
} else } else
disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
} }
WREG32(RADEON_DAC_CNTL2, dac2_cntl); WREG32(RADEON_DAC_CNTL2, dac2_cntl);
}
if (ASIC_IS_R300(rdev)) { if (ASIC_IS_R300(rdev)) {
WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl); WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
} else if (rdev->family == CHIP_R200) }
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
if (rdev->family >= CHIP_R200)
WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl);
else else
WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug); WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
if (rdev->family == CHIP_R200)
WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
if (is_tv)
radeon_legacy_tv_mode_set(encoder, mode, adjusted_mode);
if (rdev->is_atom_bios) if (rdev->is_atom_bios)
radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
else else
...@@ -920,6 +1004,141 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, ...@@ -920,6 +1004,141 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
} }
static bool r300_legacy_tv_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
uint32_t disp_output_cntl, gpiopad_a, tmp;
bool found = false;
/* save regs needed */
gpiopad_a = RREG32(RADEON_GPIOPAD_A);
dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
WREG32_P(RADEON_GPIOPAD_A, 0, ~1);
WREG32(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL);
WREG32(RADEON_CRTC2_GEN_CNTL,
RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT);
tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
WREG32(RADEON_DAC_EXT_CNTL,
RADEON_DAC2_FORCE_BLANK_OFF_EN |
RADEON_DAC2_FORCE_DATA_EN |
RADEON_DAC_FORCE_DATA_SEL_RGB |
(0xec << RADEON_DAC_FORCE_DATA_SHIFT));
WREG32(RADEON_TV_DAC_CNTL,
RADEON_TV_DAC_STD_NTSC |
(8 << RADEON_TV_DAC_BGADJ_SHIFT) |
(6 << RADEON_TV_DAC_DACADJ_SHIFT));
RREG32(RADEON_TV_DAC_CNTL);
mdelay(4);
WREG32(RADEON_TV_DAC_CNTL,
RADEON_TV_DAC_NBLANK |
RADEON_TV_DAC_NHOLD |
RADEON_TV_MONITOR_DETECT_EN |
RADEON_TV_DAC_STD_NTSC |
(8 << RADEON_TV_DAC_BGADJ_SHIFT) |
(6 << RADEON_TV_DAC_DACADJ_SHIFT));
RREG32(RADEON_TV_DAC_CNTL);
mdelay(6);
tmp = RREG32(RADEON_TV_DAC_CNTL);
if ((tmp & RADEON_TV_DAC_GDACDET) != 0) {
found = true;
DRM_DEBUG("S-video TV connection detected\n");
} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
found = true;
DRM_DEBUG("Composite TV connection detected\n");
}
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
WREG32(RADEON_DAC_CNTL2, dac_cntl2);
WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
return found;
}
static bool radeon_legacy_tv_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t tv_dac_cntl, dac_cntl2;
uint32_t config_cntl, tv_pre_dac_mux_cntl, tv_master_cntl, tmp;
bool found = false;
if (ASIC_IS_R300(rdev))
return r300_legacy_tv_detect(encoder, connector);
dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL);
tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
config_cntl = RREG32(RADEON_CONFIG_CNTL);
tv_pre_dac_mux_cntl = RREG32(RADEON_TV_PRE_DAC_MUX_CNTL);
tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL;
WREG32(RADEON_DAC_CNTL2, tmp);
tmp = tv_master_cntl | RADEON_TV_ON;
tmp &= ~(RADEON_TV_ASYNC_RST |
RADEON_RESTART_PHASE_FIX |
RADEON_CRT_FIFO_CE_EN |
RADEON_TV_FIFO_CE_EN |
RADEON_RE_SYNC_NOW_SEL_MASK);
tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST;
WREG32(RADEON_TV_MASTER_CNTL, tmp);
tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD |
RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC |
(8 << RADEON_TV_DAC_BGADJ_SHIFT);
if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK)
tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT);
else
tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT);
WREG32(RADEON_TV_DAC_CNTL, tmp);
tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN |
RADEON_RED_MX_FORCE_DAC_DATA |
RADEON_GRN_MX_FORCE_DAC_DATA |
RADEON_BLU_MX_FORCE_DAC_DATA |
(0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT);
WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp);
mdelay(3);
tmp = RREG32(RADEON_TV_DAC_CNTL);
if (tmp & RADEON_TV_DAC_GDACDET) {
found = true;
DRM_DEBUG("S-video TV connection detected\n");
} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
found = true;
DRM_DEBUG("Composite TV connection detected\n");
}
WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl);
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
WREG32(RADEON_DAC_CNTL2, dac_cntl2);
return found;
}
static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder,
struct drm_connector *connector) struct drm_connector *connector)
{ {
...@@ -928,9 +1147,29 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder ...@@ -928,9 +1147,29 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp;
enum drm_connector_status found = connector_status_disconnected; enum drm_connector_status found = connector_status_disconnected;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
bool color = true; bool color = true;
/* FIXME tv */ if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO ||
connector->connector_type == DRM_MODE_CONNECTOR_Composite ||
connector->connector_type == DRM_MODE_CONNECTOR_9PinDIN) {
bool tv_detect;
if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT))
return connector_status_disconnected;
tv_detect = radeon_legacy_tv_detect(encoder, connector);
if (tv_detect && tv_dac)
found = connector_status_connected;
return found;
}
/* don't probe if the encoder is being used for something else not CRT related */
if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_CRT_SUPPORT)) {
DRM_INFO("not detecting due to %08x\n", radeon_encoder->active_device);
return connector_status_disconnected;
}
/* save the regs we need */ /* save the regs we need */
pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
...@@ -1013,8 +1252,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder ...@@ -1013,8 +1252,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
} }
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
/* return found; */ return found;
return connector_status_disconnected;
} }
...@@ -1025,6 +1263,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = ...@@ -1025,6 +1263,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs =
.mode_set = radeon_legacy_tv_dac_mode_set, .mode_set = radeon_legacy_tv_dac_mode_set,
.commit = radeon_legacy_tv_dac_commit, .commit = radeon_legacy_tv_dac_commit,
.detect = radeon_legacy_tv_dac_detect, .detect = radeon_legacy_tv_dac_detect,
.disable = radeon_legacy_encoder_disable,
}; };
......
#include "drmP.h"
#include "drm_crtc_helper.h"
#include "radeon.h"
/*
* Integrated TV out support based on the GATOS code by
* Federico Ulivi <fulivi@lycos.com>
*/
/*
* Limits of h/v positions (hPos & vPos)
*/
#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */
#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */
/*
* Unit for hPos (in TV clock periods)
*/
#define H_POS_UNIT 10
/*
* Indexes in h. code timing table for horizontal line position adjustment
*/
#define H_TABLE_POS1 6
#define H_TABLE_POS2 8
/*
* Limits of hor. size (hSize)
*/
#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */
/* tv standard constants */
#define NTSC_TV_CLOCK_T 233
#define NTSC_TV_VFTOTAL 1
#define NTSC_TV_LINES_PER_FRAME 525
#define NTSC_TV_ZERO_H_SIZE 479166
#define NTSC_TV_H_SIZE_UNIT 9478
#define PAL_TV_CLOCK_T 188
#define PAL_TV_VFTOTAL 3
#define PAL_TV_LINES_PER_FRAME 625
#define PAL_TV_ZERO_H_SIZE 473200
#define PAL_TV_H_SIZE_UNIT 9360
/* tv pll setting for 27 mhz ref clk */
#define NTSC_TV_PLL_M_27 22
#define NTSC_TV_PLL_N_27 175
#define NTSC_TV_PLL_P_27 5
#define PAL_TV_PLL_M_27 113
#define PAL_TV_PLL_N_27 668
#define PAL_TV_PLL_P_27 3
/* tv pll setting for 14 mhz ref clk */
#define NTSC_TV_PLL_M_14 33
#define NTSC_TV_PLL_N_14 693
#define NTSC_TV_PLL_P_14 7
#define VERT_LEAD_IN_LINES 2
#define FRAC_BITS 0xe
#define FRAC_MASK 0x3fff
struct radeon_tv_mode_constants {
uint16_t hor_resolution;
uint16_t ver_resolution;
enum radeon_tv_std standard;
uint16_t hor_total;
uint16_t ver_total;
uint16_t hor_start;
uint16_t hor_syncstart;
uint16_t ver_syncstart;
unsigned def_restart;
uint16_t crtcPLL_N;
uint8_t crtcPLL_M;
uint8_t crtcPLL_post_div;
unsigned pix_to_tv;
};
static const uint16_t hor_timing_NTSC[] = {
0x0007,
0x003f,
0x0263,
0x0a24,
0x2a6b,
0x0a36,
0x126d, /* H_TABLE_POS1 */
0x1bfe,
0x1a8f, /* H_TABLE_POS2 */
0x1ec7,
0x3863,
0x1bfe,
0x1bfe,
0x1a2a,
0x1e95,
0x0e31,
0x201b,
0
};
static const uint16_t vert_timing_NTSC[] = {
0x2001,
0x200d,
0x1006,
0x0c06,
0x1006,
0x1818,
0x21e3,
0x1006,
0x0c06,
0x1006,
0x1817,
0x21d4,
0x0002,
0
};
static const uint16_t hor_timing_PAL[] = {
0x0007,
0x0058,
0x027c,
0x0a31,
0x2a77,
0x0a95,
0x124f, /* H_TABLE_POS1 */
0x1bfe,
0x1b22, /* H_TABLE_POS2 */
0x1ef9,
0x387c,
0x1bfe,
0x1bfe,
0x1b31,
0x1eb5,
0x0e43,
0x201b,
0
};
static const uint16_t vert_timing_PAL[] = {
0x2001,
0x200c,
0x1005,
0x0c05,
0x1005,
0x1401,
0x1821,
0x2240,
0x1005,
0x0c05,
0x1005,
0x1401,
0x1822,
0x2230,
0x0002,
0
};
/**********************************************************************
*
* availableModes
*
* Table of all allowed modes for tv output
*
**********************************************************************/
static const struct radeon_tv_mode_constants available_tv_modes[] = {
{ /* NTSC timing for 27 Mhz ref clk */
800, /* horResolution */
600, /* verResolution */
TV_STD_NTSC, /* standard */
990, /* horTotal */
740, /* verTotal */
813, /* horStart */
824, /* horSyncStart */
632, /* verSyncStart */
625592, /* defRestart */
592, /* crtcPLL_N */
91, /* crtcPLL_M */
4, /* crtcPLL_postDiv */
1022, /* pixToTV */
},
{ /* PAL timing for 27 Mhz ref clk */
800, /* horResolution */
600, /* verResolution */
TV_STD_PAL, /* standard */
1144, /* horTotal */
706, /* verTotal */
812, /* horStart */
824, /* horSyncStart */
669, /* verSyncStart */
696700, /* defRestart */
1382, /* crtcPLL_N */
231, /* crtcPLL_M */
4, /* crtcPLL_postDiv */
759, /* pixToTV */
},
{ /* NTSC timing for 14 Mhz ref clk */
800, /* horResolution */
600, /* verResolution */
TV_STD_NTSC, /* standard */
1018, /* horTotal */
727, /* verTotal */
813, /* horStart */
840, /* horSyncStart */
633, /* verSyncStart */
630627, /* defRestart */
347, /* crtcPLL_N */
14, /* crtcPLL_M */
8, /* crtcPLL_postDiv */
1022, /* pixToTV */
},
};
#define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes)
static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder,
uint16_t *pll_ref_freq)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_crtc *radeon_crtc;
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
const struct radeon_tv_mode_constants *const_ptr;
struct radeon_pll *pll;
radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
if (radeon_crtc->crtc_id == 1)
pll = &rdev->clock.p2pll;
else
pll = &rdev->clock.p1pll;
if (pll_ref_freq)
*pll_ref_freq = pll->reference_freq;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M) {
if (pll->reference_freq == 2700)
const_ptr = &available_tv_modes[0];
else
const_ptr = &available_tv_modes[2];
} else {
if (pll->reference_freq == 2700)
const_ptr = &available_tv_modes[1];
else
const_ptr = &available_tv_modes[1]; /* FIX ME */
}
return const_ptr;
}
static long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
static long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
static void radeon_wait_pll_lock(struct drm_encoder *encoder, unsigned n_tests,
unsigned n_wait_loops, unsigned cnt_threshold)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t save_pll_test;
unsigned int i, j;
WREG32(RADEON_TEST_DEBUG_MUX, (RREG32(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
save_pll_test = RREG32_PLL(RADEON_PLL_TEST_CNTL);
WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test & ~RADEON_PLL_MASK_READ_B);
WREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
for (i = 0; i < n_tests; i++) {
WREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
for (j = 0; j < n_wait_loops; j++)
if (RREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cnt_threshold)
break;
}
WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test);
WREG32(RADEON_TEST_DEBUG_MUX, RREG32(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
}
static void radeon_legacy_tv_write_fifo(struct radeon_encoder *radeon_encoder,
uint16_t addr, uint32_t value)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t tmp;
int i = 0;
WREG32(RADEON_TV_HOST_WRITE_DATA, value);
WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr);
WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
do {
tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL);
if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
break;
i++;
} while (i < 10000);
WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0);
}
#if 0 /* included for completeness */
static uint32_t radeon_legacy_tv_read_fifo(struct radeon_encoder *radeon_encoder, uint16_t addr)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
uint32_t tmp;
int i = 0;
WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr);
WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
do {
tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL);
if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
break;
i++;
} while (i < 10000);
WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0);
return RREG32(RADEON_TV_HOST_READ_DATA);
}
#endif
static uint16_t radeon_get_htiming_tables_addr(uint32_t tv_uv_adr)
{
uint16_t h_table;
switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
case 0:
h_table = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
break;
case 1:
h_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
break;
case 2:
h_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
break;
default:
h_table = 0;
break;
}
return h_table;
}
static uint16_t radeon_get_vtiming_tables_addr(uint32_t tv_uv_adr)
{
uint16_t v_table;
switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
case 0:
v_table = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
break;
case 1:
v_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
break;
case 2:
v_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
break;
default:
v_table = 0;
break;
}
return v_table;
}
static void radeon_restore_tv_timing_tables(struct radeon_encoder *radeon_encoder)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
uint16_t h_table, v_table;
uint32_t tmp;
int i;
WREG32(RADEON_TV_UV_ADR, tv_dac->tv.tv_uv_adr);
h_table = radeon_get_htiming_tables_addr(tv_dac->tv.tv_uv_adr);
v_table = radeon_get_vtiming_tables_addr(tv_dac->tv.tv_uv_adr);
for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, h_table--) {
tmp = ((uint32_t)tv_dac->tv.h_code_timing[i] << 14) | ((uint32_t)tv_dac->tv.h_code_timing[i+1]);
radeon_legacy_tv_write_fifo(radeon_encoder, h_table, tmp);
if (tv_dac->tv.h_code_timing[i] == 0 || tv_dac->tv.h_code_timing[i + 1] == 0)
break;
}
for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, v_table++) {
tmp = ((uint32_t)tv_dac->tv.v_code_timing[i+1] << 14) | ((uint32_t)tv_dac->tv.v_code_timing[i]);
radeon_legacy_tv_write_fifo(radeon_encoder, v_table, tmp);
if (tv_dac->tv.v_code_timing[i] == 0 || tv_dac->tv.v_code_timing[i + 1] == 0)
break;
}
}
static void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encoder)
{
struct drm_device *dev = radeon_encoder->base.dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
WREG32(RADEON_TV_FRESTART, tv_dac->tv.frestart);
WREG32(RADEON_TV_HRESTART, tv_dac->tv.hrestart);
WREG32(RADEON_TV_VRESTART, tv_dac->tv.vrestart);
}
static bool radeon_legacy_tv_init_restarts(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_tv_dac *tv_dac = radeon_encoder->enc_priv;
struct radeon_crtc *radeon_crtc;
int restart;
unsigned int h_total, v_total, f_total;
int v_offset, h_offset;
u16 p1, p2, h_inc;
bool h_changed;
const struct radeon_tv_mode_constants *const_ptr;
struct radeon_pll *pll;
radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
if (radeon_crtc->crtc_id == 1)
pll = &rdev->clock.p2pll;
else
pll = &rdev->clock.p1pll;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
if (!const_ptr)
return false;
h_total = const_ptr->hor_total;
v_total = const_ptr->ver_total;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60)
f_total = NTSC_TV_VFTOTAL + 1;
else
f_total = PAL_TV_VFTOTAL + 1;
/* adjust positions 1&2 in hor. cod timing table */
h_offset = tv_dac->h_pos * H_POS_UNIT;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M) {
h_offset -= 50;
p1 = hor_timing_NTSC[H_TABLE_POS1];
p2 = hor_timing_NTSC[H_TABLE_POS2];
} else {
p1 = hor_timing_PAL[H_TABLE_POS1];
p2 = hor_timing_PAL[H_TABLE_POS2];
}
p1 = (u16)((int)p1 + h_offset);
p2 = (u16)((int)p2 - h_offset);
h_changed = (p1 != tv_dac->tv.h_code_timing[H_TABLE_POS1] ||
p2 != tv_dac->tv.h_code_timing[H_TABLE_POS2]);
tv_dac->tv.h_code_timing[H_TABLE_POS1] = p1;
tv_dac->tv.h_code_timing[H_TABLE_POS2] = p2;
/* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
h_offset = (h_offset * (int)(const_ptr->pix_to_tv)) / 1000;
/* adjust restart */
restart = const_ptr->def_restart;
/*
* convert v_pos TV lines to n. of CRTC pixels
*/
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60)
v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(NTSC_TV_LINES_PER_FRAME);
else
v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(PAL_TV_LINES_PER_FRAME);
restart -= v_offset + h_offset;
DRM_DEBUG("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n",
const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart);
tv_dac->tv.hrestart = restart % h_total;
restart /= h_total;
tv_dac->tv.vrestart = restart % v_total;
restart /= v_total;
tv_dac->tv.frestart = restart % f_total;
DRM_DEBUG("compute_restart: F/H/V=%u,%u,%u\n",
(unsigned)tv_dac->tv.frestart,
(unsigned)tv_dac->tv.vrestart,
(unsigned)tv_dac->tv.hrestart);
/* compute h_inc from hsize */
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M)
h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * NTSC_TV_CLOCK_T) /
(tv_dac->h_size * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
else
h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * PAL_TV_CLOCK_T) /
(tv_dac->h_size * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) |
((u32)h_inc << RADEON_H_INC_SHIFT);
DRM_DEBUG("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc);
return h_changed;
}
void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_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_tv_dac *tv_dac = radeon_encoder->enc_priv;
const struct radeon_tv_mode_constants *const_ptr;
struct radeon_crtc *radeon_crtc;
int i;
uint16_t pll_ref_freq;
uint32_t vert_space, flicker_removal, tmp;
uint32_t tv_master_cntl, tv_rgb_cntl, tv_dac_cntl;
uint32_t tv_modulator_cntl1, tv_modulator_cntl2;
uint32_t tv_vscaler_cntl1, tv_vscaler_cntl2;
uint32_t tv_pll_cntl, tv_pll_cntl1, tv_ftotal;
uint32_t tv_y_fall_cntl, tv_y_rise_cntl, tv_y_saw_tooth_cntl;
uint32_t m, n, p;
const uint16_t *hor_timing;
const uint16_t *vert_timing;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, &pll_ref_freq);
if (!const_ptr)
return;
radeon_crtc = to_radeon_crtc(encoder->crtc);
tv_master_cntl = (RADEON_VIN_ASYNC_RST |
RADEON_CRT_FIFO_CE_EN |
RADEON_TV_FIFO_CE_EN |
RADEON_TV_ON);
if (!ASIC_IS_R300(rdev))
tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J)
tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
tv_modulator_cntl1 = (RADEON_SLEW_RATE_LIMIT |
RADEON_SYNC_TIP_LEVEL |
RADEON_YFLT_EN |
RADEON_UVFLT_EN |
(6 << RADEON_CY_FILT_BLEND_SHIFT));
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J) {
tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) |
(0x3b << RADEON_BLANK_LEVEL_SHIFT);
tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
} else if (tv_dac->tv_std == TV_STD_SCART_PAL) {
tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
} else {
tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN |
(0x3b << RADEON_SET_UP_LEVEL_SHIFT) |
(0x3b << RADEON_BLANK_LEVEL_SHIFT);
tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
}
tv_rgb_cntl = (RADEON_RGB_DITHER_EN
| RADEON_TVOUT_SCALE_EN
| (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
| (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT)
| RADEON_RGB_ATTEN_SEL(0x3)
| RADEON_RGB_ATTEN_VAL(0xc));
if (radeon_crtc->crtc_id == 1)
tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
else {
if (radeon_crtc->rmx_type != RMX_OFF)
tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
else
tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
}
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60)
vert_space = const_ptr->ver_total * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
else
vert_space = const_ptr->ver_total * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
tmp = RREG32(RADEON_TV_VSCALER_CNTL1);
tmp &= 0xe3ff0000;
tmp |= (vert_space * (1 << FRAC_BITS) / 10000);
tv_vscaler_cntl1 = tmp;
if (pll_ref_freq == 2700)
tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
if (const_ptr->hor_resolution == 1024)
tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
else
tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
/* scale up for int divide */
tmp = const_ptr->ver_total * 2 * 1000;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60) {
tmp /= NTSC_TV_LINES_PER_FRAME;
} else {
tmp /= PAL_TV_LINES_PER_FRAME;
}
flicker_removal = (tmp + 500) / 1000;
if (flicker_removal < 3)
flicker_removal = 3;
for (i = 0; i < 6; ++i) {
if (flicker_removal == SLOPE_limit[i])
break;
}
tv_y_saw_tooth_cntl = (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) +
5001) / 10000 / 8 | ((SLOPE_value[i] *
(1 << (FRAC_BITS - 1)) / 8) << 16);
tv_y_fall_cntl =
(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
1024;
tv_y_rise_cntl = RADEON_Y_RISE_PING_PONG|
(flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
tv_vscaler_cntl2 = RREG32(RADEON_TV_VSCALER_CNTL2) & 0x00fffff0;
tv_vscaler_cntl2 |= (0x10 << 24) |
RADEON_DITHER_MODE |
RADEON_Y_OUTPUT_DITHER_EN |
RADEON_UV_OUTPUT_DITHER_EN |
RADEON_UV_TO_BUF_DITHER_EN;
tmp = (tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
tv_dac->tv.timing_cntl = tmp;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60)
tv_dac_cntl = tv_dac->ntsc_tvdac_adj;
else
tv_dac_cntl = tv_dac->pal_tvdac_adj;
tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J)
tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
else
tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J) {
if (pll_ref_freq == 2700) {
m = NTSC_TV_PLL_M_27;
n = NTSC_TV_PLL_N_27;
p = NTSC_TV_PLL_P_27;
} else {
m = NTSC_TV_PLL_M_14;
n = NTSC_TV_PLL_N_14;
p = NTSC_TV_PLL_P_14;
}
} else {
if (pll_ref_freq == 2700) {
m = PAL_TV_PLL_M_27;
n = PAL_TV_PLL_N_27;
p = PAL_TV_PLL_P_27;
} else {
m = PAL_TV_PLL_M_27;
n = PAL_TV_PLL_N_27;
p = PAL_TV_PLL_P_27;
}
}
tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) |
(((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
(((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK) << RADEON_TVPCP_SHIFT) |
((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
((1 & RADEON_TVPDC_MASK) << RADEON_TVPDC_SHIFT) |
RADEON_TVCLK_SRC_SEL_TVPLL |
RADEON_TVPLL_TEST_DIS);
tv_dac->tv.tv_uv_adr = 0xc8;
if (tv_dac->tv_std == TV_STD_NTSC ||
tv_dac->tv_std == TV_STD_NTSC_J ||
tv_dac->tv_std == TV_STD_PAL_M ||
tv_dac->tv_std == TV_STD_PAL_60) {
tv_ftotal = NTSC_TV_VFTOTAL;
hor_timing = hor_timing_NTSC;
vert_timing = vert_timing_NTSC;
} else {
hor_timing = hor_timing_PAL;
vert_timing = vert_timing_PAL;
tv_ftotal = PAL_TV_VFTOTAL;
}
for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
if ((tv_dac->tv.h_code_timing[i] = hor_timing[i]) == 0)
break;
}
for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
if ((tv_dac->tv.v_code_timing[i] = vert_timing[i]) == 0)
break;
}
radeon_legacy_tv_init_restarts(encoder);
/* play with DAC_CNTL */
/* play with GPIOPAD_A */
/* DISP_OUTPUT_CNTL */
/* use reference freq */
/* program the TV registers */
WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST |
RADEON_CRT_ASYNC_RST | RADEON_TV_FIFO_ASYNC_RST));
tmp = RREG32(RADEON_TV_DAC_CNTL);
tmp &= ~RADEON_TV_DAC_NBLANK;
tmp |= RADEON_TV_DAC_BGSLEEP |
RADEON_TV_DAC_RDACPD |
RADEON_TV_DAC_GDACPD |
RADEON_TV_DAC_BDACPD;
WREG32(RADEON_TV_DAC_CNTL, tmp);
/* TV PLL */
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
WREG32_PLL(RADEON_TV_PLL_CNTL, tv_pll_cntl);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
radeon_wait_pll_lock(encoder, 200, 800, 135);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
radeon_wait_pll_lock(encoder, 300, 160, 27);
radeon_wait_pll_lock(encoder, 200, 800, 135);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~0xf);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
/* TV HV */
WREG32(RADEON_TV_RGB_CNTL, tv_rgb_cntl);
WREG32(RADEON_TV_HTOTAL, const_ptr->hor_total - 1);
WREG32(RADEON_TV_HDISP, const_ptr->hor_resolution - 1);
WREG32(RADEON_TV_HSTART, const_ptr->hor_start);
WREG32(RADEON_TV_VTOTAL, const_ptr->ver_total - 1);
WREG32(RADEON_TV_VDISP, const_ptr->ver_resolution - 1);
WREG32(RADEON_TV_FTOTAL, tv_ftotal);
WREG32(RADEON_TV_VSCALER_CNTL1, tv_vscaler_cntl1);
WREG32(RADEON_TV_VSCALER_CNTL2, tv_vscaler_cntl2);
WREG32(RADEON_TV_Y_FALL_CNTL, tv_y_fall_cntl);
WREG32(RADEON_TV_Y_RISE_CNTL, tv_y_rise_cntl);
WREG32(RADEON_TV_Y_SAW_TOOTH_CNTL, tv_y_saw_tooth_cntl);
WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST |
RADEON_CRT_ASYNC_RST));
/* TV restarts */
radeon_legacy_write_tv_restarts(radeon_encoder);
/* tv timings */
radeon_restore_tv_timing_tables(radeon_encoder);
WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST));
/* tv std */
WREG32(RADEON_TV_SYNC_CNTL, (RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE));
WREG32(RADEON_TV_TIMING_CNTL, tv_dac->tv.timing_cntl);
WREG32(RADEON_TV_MODULATOR_CNTL1, tv_modulator_cntl1);
WREG32(RADEON_TV_MODULATOR_CNTL2, tv_modulator_cntl2);
WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, (RADEON_Y_RED_EN |
RADEON_C_GRN_EN |
RADEON_CMP_BLU_EN |
RADEON_DAC_DITHER_EN));
WREG32(RADEON_TV_CRC_CNTL, 0);
WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
WREG32(RADEON_TV_GAIN_LIMIT_SETTINGS, ((0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) |
(0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT)));
WREG32(RADEON_TV_LINEAR_GAIN_SETTINGS, ((0x100 << RADEON_UV_GAIN_SHIFT) |
(0x100 << RADEON_Y_GAIN_SHIFT)));
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
}
void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder,
uint32_t *h_total_disp, uint32_t *h_sync_strt_wid,
uint32_t *v_total_disp, uint32_t *v_sync_strt_wid)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
const struct radeon_tv_mode_constants *const_ptr;
uint32_t tmp;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
if (!const_ptr)
return;
*h_total_disp = (((const_ptr->hor_resolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
(((const_ptr->hor_total / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
tmp = *h_sync_strt_wid;
tmp &= ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR);
tmp |= (((const_ptr->hor_syncstart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
(const_ptr->hor_syncstart & 7);
*h_sync_strt_wid = tmp;
*v_total_disp = ((const_ptr->ver_resolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
((const_ptr->ver_total - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
tmp = *v_sync_strt_wid;
tmp &= ~RADEON_CRTC_V_SYNC_STRT;
tmp |= ((const_ptr->ver_syncstart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
*v_sync_strt_wid = tmp;
}
static inline int get_post_div(int value)
{
int post_div;
switch (value) {
case 1: post_div = 0; break;
case 2: post_div = 1; break;
case 3: post_div = 4; break;
case 4: post_div = 2; break;
case 6: post_div = 6; break;
case 8: post_div = 3; break;
case 12: post_div = 7; break;
case 16:
default: post_div = 5; break;
}
return post_div;
}
void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder,
uint32_t *htotal_cntl, uint32_t *ppll_ref_div,
uint32_t *ppll_div_3, uint32_t *pixclks_cntl)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
const struct radeon_tv_mode_constants *const_ptr;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
if (!const_ptr)
return;
*htotal_cntl = (const_ptr->hor_total & 0x7) | RADEON_HTOT_CNTL_VGA_EN;
*ppll_ref_div = const_ptr->crtcPLL_M;
*ppll_div_3 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16);
*pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
*pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
}
void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div,
uint32_t *p2pll_div_0, uint32_t *pixclks_cntl)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
const struct radeon_tv_mode_constants *const_ptr;
const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
if (!const_ptr)
return;
*htotal2_cntl = (const_ptr->hor_total & 0x7);
*p2pll_ref_div = const_ptr->crtcPLL_M;
*p2pll_div_0 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16);
*pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
*pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK | RADEON_PIXCLK_TV_SRC_SEL;
}
...@@ -188,6 +188,21 @@ struct radeon_native_mode { ...@@ -188,6 +188,21 @@ struct radeon_native_mode {
uint32_t flags; uint32_t flags;
}; };
#define MAX_H_CODE_TIMING_LEN 32
#define MAX_V_CODE_TIMING_LEN 32
/* need to store these as reading
back code tables is excessive */
struct radeon_tv_regs {
uint32_t tv_uv_adr;
uint32_t timing_cntl;
uint32_t hrestart;
uint32_t vrestart;
uint32_t frestart;
uint16_t h_code_timing[MAX_H_CODE_TIMING_LEN];
uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN];
};
struct radeon_crtc { struct radeon_crtc {
struct drm_crtc base; struct drm_crtc base;
int crtc_id; int crtc_id;
...@@ -202,7 +217,6 @@ struct radeon_crtc { ...@@ -202,7 +217,6 @@ struct radeon_crtc {
uint32_t legacy_display_base_addr; uint32_t legacy_display_base_addr;
uint32_t legacy_cursor_offset; uint32_t legacy_cursor_offset;
enum radeon_rmx_type rmx_type; enum radeon_rmx_type rmx_type;
uint32_t devices;
fixed20_12 vsc; fixed20_12 vsc;
fixed20_12 hsc; fixed20_12 hsc;
struct radeon_native_mode native_mode; struct radeon_native_mode native_mode;
...@@ -234,7 +248,13 @@ struct radeon_encoder_tv_dac { ...@@ -234,7 +248,13 @@ struct radeon_encoder_tv_dac {
uint32_t ntsc_tvdac_adj; uint32_t ntsc_tvdac_adj;
uint32_t pal_tvdac_adj; uint32_t pal_tvdac_adj;
int h_pos;
int v_pos;
int h_size;
int supported_tv_stds;
bool tv_on;
enum radeon_tv_std tv_std; enum radeon_tv_std tv_std;
struct radeon_tv_regs tv;
}; };
struct radeon_encoder_int_tmds { struct radeon_encoder_int_tmds {
...@@ -253,10 +273,15 @@ struct radeon_encoder_atom_dig { ...@@ -253,10 +273,15 @@ struct radeon_encoder_atom_dig {
struct radeon_native_mode native_mode; struct radeon_native_mode native_mode;
}; };
struct radeon_encoder_atom_dac {
enum radeon_tv_std tv_std;
};
struct radeon_encoder { struct radeon_encoder {
struct drm_encoder base; struct drm_encoder base;
uint32_t encoder_id; uint32_t encoder_id;
uint32_t devices; uint32_t devices;
uint32_t active_device;
uint32_t flags; uint32_t flags;
uint32_t pixel_clock; uint32_t pixel_clock;
enum radeon_rmx_type rmx_type; enum radeon_rmx_type rmx_type;
...@@ -274,7 +299,10 @@ struct radeon_connector { ...@@ -274,7 +299,10 @@ struct radeon_connector {
uint32_t connector_id; uint32_t connector_id;
uint32_t devices; uint32_t devices;
struct radeon_i2c_chan *ddc_bus; struct radeon_i2c_chan *ddc_bus;
int use_digital; bool use_digital;
/* we need to mind the EDID between detect
and get modes due to analog/digital/tvencoder */
struct edid *edid;
void *con_priv; void *con_priv;
}; };
...@@ -308,6 +336,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i ...@@ -308,6 +336,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i
struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action); extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
extern int atombios_get_encoder_mode(struct drm_encoder *encoder); extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
...@@ -394,6 +423,19 @@ extern int radeon_static_clocks_init(struct drm_device *dev); ...@@ -394,6 +423,19 @@ extern int radeon_static_clocks_init(struct drm_device *dev);
bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
void atom_rv515_force_tv_scaler(struct radeon_device *rdev); void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *radeon_crtc);
/* legacy tv */
void radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder,
uint32_t *h_total_disp, uint32_t *h_sync_strt_wid,
uint32_t *v_total_disp, uint32_t *v_sync_strt_wid);
void radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder,
uint32_t *htotal_cntl, uint32_t *ppll_ref_div,
uint32_t *ppll_div_3, uint32_t *pixclks_cntl);
void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div,
uint32_t *p2pll_div_0, uint32_t *pixclks_cntl);
void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
#endif #endif
...@@ -3462,7 +3462,9 @@ ...@@ -3462,7 +3462,9 @@
# define RADEON_RGB_CONVERT_BY_PASS (1 << 10) # define RADEON_RGB_CONVERT_BY_PASS (1 << 10)
# define RADEON_UVRAM_READ_MARGIN_SHIFT 16 # define RADEON_UVRAM_READ_MARGIN_SHIFT 16
# define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20 # define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20
# define RADEON_RGB_ATTEN_SEL(x) ((x) << 24)
# define RADEON_TVOUT_SCALE_EN (1 << 26) # define RADEON_TVOUT_SCALE_EN (1 << 26)
# define RADEON_RGB_ATTEN_VAL(x) ((x) << 28)
#define RADEON_TV_SYNC_CNTL 0x0808 #define RADEON_TV_SYNC_CNTL 0x0808
# define RADEON_SYNC_OE (1 << 0) # define RADEON_SYNC_OE (1 << 0)
# define RADEON_SYNC_OUT (1 << 1) # define RADEON_SYNC_OUT (1 << 1)
......
...@@ -475,232 +475,234 @@ int rv515_init(struct radeon_device *rdev) ...@@ -475,232 +475,234 @@ int rv515_init(struct radeon_device *rdev)
return 0; return 0;
} }
void atom_rv515_force_tv_scaler(struct radeon_device *rdev) void atom_rv515_force_tv_scaler(struct radeon_device *rdev, struct radeon_crtc *crtc)
{ {
int index_reg = 0x6578 + crtc->crtc_offset;
WREG32(0x659C, 0x0); int data_reg = 0x657c + crtc->crtc_offset;
WREG32(0x6594, 0x705);
WREG32(0x65A4, 0x10001); WREG32(0x659C + crtc->crtc_offset, 0x0);
WREG32(0x65D8, 0x0); WREG32(0x6594 + crtc->crtc_offset, 0x705);
WREG32(0x65B0, 0x0); WREG32(0x65A4 + crtc->crtc_offset, 0x10001);
WREG32(0x65C0, 0x0); WREG32(0x65D8 + crtc->crtc_offset, 0x0);
WREG32(0x65D4, 0x0); WREG32(0x65B0 + crtc->crtc_offset, 0x0);
WREG32(0x6578, 0x0); WREG32(0x65C0 + crtc->crtc_offset, 0x0);
WREG32(0x657C, 0x841880A8); WREG32(0x65D4 + crtc->crtc_offset, 0x0);
WREG32(0x6578, 0x1); WREG32(index_reg, 0x0);
WREG32(0x657C, 0x84208680); WREG32(data_reg, 0x841880A8);
WREG32(0x6578, 0x2); WREG32(index_reg, 0x1);
WREG32(0x657C, 0xBFF880B0); WREG32(data_reg, 0x84208680);
WREG32(0x6578, 0x100); WREG32(index_reg, 0x2);
WREG32(0x657C, 0x83D88088); WREG32(data_reg, 0xBFF880B0);
WREG32(0x6578, 0x101); WREG32(index_reg, 0x100);
WREG32(0x657C, 0x84608680); WREG32(data_reg, 0x83D88088);
WREG32(0x6578, 0x102); WREG32(index_reg, 0x101);
WREG32(0x657C, 0xBFF080D0); WREG32(data_reg, 0x84608680);
WREG32(0x6578, 0x200); WREG32(index_reg, 0x102);
WREG32(0x657C, 0x83988068); WREG32(data_reg, 0xBFF080D0);
WREG32(0x6578, 0x201); WREG32(index_reg, 0x200);
WREG32(0x657C, 0x84A08680); WREG32(data_reg, 0x83988068);
WREG32(0x6578, 0x202); WREG32(index_reg, 0x201);
WREG32(0x657C, 0xBFF080F8); WREG32(data_reg, 0x84A08680);
WREG32(0x6578, 0x300); WREG32(index_reg, 0x202);
WREG32(0x657C, 0x83588058); WREG32(data_reg, 0xBFF080F8);
WREG32(0x6578, 0x301); WREG32(index_reg, 0x300);
WREG32(0x657C, 0x84E08660); WREG32(data_reg, 0x83588058);
WREG32(0x6578, 0x302); WREG32(index_reg, 0x301);
WREG32(0x657C, 0xBFF88120); WREG32(data_reg, 0x84E08660);
WREG32(0x6578, 0x400); WREG32(index_reg, 0x302);
WREG32(0x657C, 0x83188040); WREG32(data_reg, 0xBFF88120);
WREG32(0x6578, 0x401); WREG32(index_reg, 0x400);
WREG32(0x657C, 0x85008660); WREG32(data_reg, 0x83188040);
WREG32(0x6578, 0x402); WREG32(index_reg, 0x401);
WREG32(0x657C, 0xBFF88150); WREG32(data_reg, 0x85008660);
WREG32(0x6578, 0x500); WREG32(index_reg, 0x402);
WREG32(0x657C, 0x82D88030); WREG32(data_reg, 0xBFF88150);
WREG32(0x6578, 0x501); WREG32(index_reg, 0x500);
WREG32(0x657C, 0x85408640); WREG32(data_reg, 0x82D88030);
WREG32(0x6578, 0x502); WREG32(index_reg, 0x501);
WREG32(0x657C, 0xBFF88180); WREG32(data_reg, 0x85408640);
WREG32(0x6578, 0x600); WREG32(index_reg, 0x502);
WREG32(0x657C, 0x82A08018); WREG32(data_reg, 0xBFF88180);
WREG32(0x6578, 0x601); WREG32(index_reg, 0x600);
WREG32(0x657C, 0x85808620); WREG32(data_reg, 0x82A08018);
WREG32(0x6578, 0x602); WREG32(index_reg, 0x601);
WREG32(0x657C, 0xBFF081B8); WREG32(data_reg, 0x85808620);
WREG32(0x6578, 0x700); WREG32(index_reg, 0x602);
WREG32(0x657C, 0x82608010); WREG32(data_reg, 0xBFF081B8);
WREG32(0x6578, 0x701); WREG32(index_reg, 0x700);
WREG32(0x657C, 0x85A08600); WREG32(data_reg, 0x82608010);
WREG32(0x6578, 0x702); WREG32(index_reg, 0x701);
WREG32(0x657C, 0x800081F0); WREG32(data_reg, 0x85A08600);
WREG32(0x6578, 0x800); WREG32(index_reg, 0x702);
WREG32(0x657C, 0x8228BFF8); WREG32(data_reg, 0x800081F0);
WREG32(0x6578, 0x801); WREG32(index_reg, 0x800);
WREG32(0x657C, 0x85E085E0); WREG32(data_reg, 0x8228BFF8);
WREG32(0x6578, 0x802); WREG32(index_reg, 0x801);
WREG32(0x657C, 0xBFF88228); WREG32(data_reg, 0x85E085E0);
WREG32(0x6578, 0x10000); WREG32(index_reg, 0x802);
WREG32(0x657C, 0x82A8BF00); WREG32(data_reg, 0xBFF88228);
WREG32(0x6578, 0x10001); WREG32(index_reg, 0x10000);
WREG32(0x657C, 0x82A08CC0); WREG32(data_reg, 0x82A8BF00);
WREG32(0x6578, 0x10002); WREG32(index_reg, 0x10001);
WREG32(0x657C, 0x8008BEF8); WREG32(data_reg, 0x82A08CC0);
WREG32(0x6578, 0x10100); WREG32(index_reg, 0x10002);
WREG32(0x657C, 0x81F0BF28); WREG32(data_reg, 0x8008BEF8);
WREG32(0x6578, 0x10101); WREG32(index_reg, 0x10100);
WREG32(0x657C, 0x83608CA0); WREG32(data_reg, 0x81F0BF28);
WREG32(0x6578, 0x10102); WREG32(index_reg, 0x10101);
WREG32(0x657C, 0x8018BED0); WREG32(data_reg, 0x83608CA0);
WREG32(0x6578, 0x10200); WREG32(index_reg, 0x10102);
WREG32(0x657C, 0x8148BF38); WREG32(data_reg, 0x8018BED0);
WREG32(0x6578, 0x10201); WREG32(index_reg, 0x10200);
WREG32(0x657C, 0x84408C80); WREG32(data_reg, 0x8148BF38);
WREG32(0x6578, 0x10202); WREG32(index_reg, 0x10201);
WREG32(0x657C, 0x8008BEB8); WREG32(data_reg, 0x84408C80);
WREG32(0x6578, 0x10300); WREG32(index_reg, 0x10202);
WREG32(0x657C, 0x80B0BF78); WREG32(data_reg, 0x8008BEB8);
WREG32(0x6578, 0x10301); WREG32(index_reg, 0x10300);
WREG32(0x657C, 0x85008C20); WREG32(data_reg, 0x80B0BF78);
WREG32(0x6578, 0x10302); WREG32(index_reg, 0x10301);
WREG32(0x657C, 0x8020BEA0); WREG32(data_reg, 0x85008C20);
WREG32(0x6578, 0x10400); WREG32(index_reg, 0x10302);
WREG32(0x657C, 0x8028BF90); WREG32(data_reg, 0x8020BEA0);
WREG32(0x6578, 0x10401); WREG32(index_reg, 0x10400);
WREG32(0x657C, 0x85E08BC0); WREG32(data_reg, 0x8028BF90);
WREG32(0x6578, 0x10402); WREG32(index_reg, 0x10401);
WREG32(0x657C, 0x8018BE90); WREG32(data_reg, 0x85E08BC0);
WREG32(0x6578, 0x10500); WREG32(index_reg, 0x10402);
WREG32(0x657C, 0xBFB8BFB0); WREG32(data_reg, 0x8018BE90);
WREG32(0x6578, 0x10501); WREG32(index_reg, 0x10500);
WREG32(0x657C, 0x86C08B40); WREG32(data_reg, 0xBFB8BFB0);
WREG32(0x6578, 0x10502); WREG32(index_reg, 0x10501);
WREG32(0x657C, 0x8010BE90); WREG32(data_reg, 0x86C08B40);
WREG32(0x6578, 0x10600); WREG32(index_reg, 0x10502);
WREG32(0x657C, 0xBF58BFC8); WREG32(data_reg, 0x8010BE90);
WREG32(0x6578, 0x10601); WREG32(index_reg, 0x10600);
WREG32(0x657C, 0x87A08AA0); WREG32(data_reg, 0xBF58BFC8);
WREG32(0x6578, 0x10602); WREG32(index_reg, 0x10601);
WREG32(0x657C, 0x8010BE98); WREG32(data_reg, 0x87A08AA0);
WREG32(0x6578, 0x10700); WREG32(index_reg, 0x10602);
WREG32(0x657C, 0xBF10BFF0); WREG32(data_reg, 0x8010BE98);
WREG32(0x6578, 0x10701); WREG32(index_reg, 0x10700);
WREG32(0x657C, 0x886089E0); WREG32(data_reg, 0xBF10BFF0);
WREG32(0x6578, 0x10702); WREG32(index_reg, 0x10701);
WREG32(0x657C, 0x8018BEB0); WREG32(data_reg, 0x886089E0);
WREG32(0x6578, 0x10800); WREG32(index_reg, 0x10702);
WREG32(0x657C, 0xBED8BFE8); WREG32(data_reg, 0x8018BEB0);
WREG32(0x6578, 0x10801); WREG32(index_reg, 0x10800);
WREG32(0x657C, 0x89408940); WREG32(data_reg, 0xBED8BFE8);
WREG32(0x6578, 0x10802); WREG32(index_reg, 0x10801);
WREG32(0x657C, 0xBFE8BED8); WREG32(data_reg, 0x89408940);
WREG32(0x6578, 0x20000); WREG32(index_reg, 0x10802);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0xBFE8BED8);
WREG32(0x6578, 0x20001); WREG32(index_reg, 0x20000);
WREG32(0x657C, 0x90008000); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20002); WREG32(index_reg, 0x20001);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0x90008000);
WREG32(0x6578, 0x20003); WREG32(index_reg, 0x20002);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20100); WREG32(index_reg, 0x20003);
WREG32(0x657C, 0x80108000); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20101); WREG32(index_reg, 0x20100);
WREG32(0x657C, 0x8FE0BF70); WREG32(data_reg, 0x80108000);
WREG32(0x6578, 0x20102); WREG32(index_reg, 0x20101);
WREG32(0x657C, 0xBFE880C0); WREG32(data_reg, 0x8FE0BF70);
WREG32(0x6578, 0x20103); WREG32(index_reg, 0x20102);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0xBFE880C0);
WREG32(0x6578, 0x20200); WREG32(index_reg, 0x20103);
WREG32(0x657C, 0x8018BFF8); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20201); WREG32(index_reg, 0x20200);
WREG32(0x657C, 0x8F80BF08); WREG32(data_reg, 0x8018BFF8);
WREG32(0x6578, 0x20202); WREG32(index_reg, 0x20201);
WREG32(0x657C, 0xBFD081A0); WREG32(data_reg, 0x8F80BF08);
WREG32(0x6578, 0x20203); WREG32(index_reg, 0x20202);
WREG32(0x657C, 0xBFF88000); WREG32(data_reg, 0xBFD081A0);
WREG32(0x6578, 0x20300); WREG32(index_reg, 0x20203);
WREG32(0x657C, 0x80188000); WREG32(data_reg, 0xBFF88000);
WREG32(0x6578, 0x20301); WREG32(index_reg, 0x20300);
WREG32(0x657C, 0x8EE0BEC0); WREG32(data_reg, 0x80188000);
WREG32(0x6578, 0x20302); WREG32(index_reg, 0x20301);
WREG32(0x657C, 0xBFB082A0); WREG32(data_reg, 0x8EE0BEC0);
WREG32(0x6578, 0x20303); WREG32(index_reg, 0x20302);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0xBFB082A0);
WREG32(0x6578, 0x20400); WREG32(index_reg, 0x20303);
WREG32(0x657C, 0x80188000); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20401); WREG32(index_reg, 0x20400);
WREG32(0x657C, 0x8E00BEA0); WREG32(data_reg, 0x80188000);
WREG32(0x6578, 0x20402); WREG32(index_reg, 0x20401);
WREG32(0x657C, 0xBF8883C0); WREG32(data_reg, 0x8E00BEA0);
WREG32(0x6578, 0x20403); WREG32(index_reg, 0x20402);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0xBF8883C0);
WREG32(0x6578, 0x20500); WREG32(index_reg, 0x20403);
WREG32(0x657C, 0x80188000); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x20501); WREG32(index_reg, 0x20500);
WREG32(0x657C, 0x8D00BE90); WREG32(data_reg, 0x80188000);
WREG32(0x6578, 0x20502); WREG32(index_reg, 0x20501);
WREG32(0x657C, 0xBF588500); WREG32(data_reg, 0x8D00BE90);
WREG32(0x6578, 0x20503); WREG32(index_reg, 0x20502);
WREG32(0x657C, 0x80008008); WREG32(data_reg, 0xBF588500);
WREG32(0x6578, 0x20600); WREG32(index_reg, 0x20503);
WREG32(0x657C, 0x80188000); WREG32(data_reg, 0x80008008);
WREG32(0x6578, 0x20601); WREG32(index_reg, 0x20600);
WREG32(0x657C, 0x8BC0BE98); WREG32(data_reg, 0x80188000);
WREG32(0x6578, 0x20602); WREG32(index_reg, 0x20601);
WREG32(0x657C, 0xBF308660); WREG32(data_reg, 0x8BC0BE98);
WREG32(0x6578, 0x20603); WREG32(index_reg, 0x20602);
WREG32(0x657C, 0x80008008); WREG32(data_reg, 0xBF308660);
WREG32(0x6578, 0x20700); WREG32(index_reg, 0x20603);
WREG32(0x657C, 0x80108000); WREG32(data_reg, 0x80008008);
WREG32(0x6578, 0x20701); WREG32(index_reg, 0x20700);
WREG32(0x657C, 0x8A80BEB0); WREG32(data_reg, 0x80108000);
WREG32(0x6578, 0x20702); WREG32(index_reg, 0x20701);
WREG32(0x657C, 0xBF0087C0); WREG32(data_reg, 0x8A80BEB0);
WREG32(0x6578, 0x20703); WREG32(index_reg, 0x20702);
WREG32(0x657C, 0x80008008); WREG32(data_reg, 0xBF0087C0);
WREG32(0x6578, 0x20800); WREG32(index_reg, 0x20703);
WREG32(0x657C, 0x80108000); WREG32(data_reg, 0x80008008);
WREG32(0x6578, 0x20801); WREG32(index_reg, 0x20800);
WREG32(0x657C, 0x8920BED0); WREG32(data_reg, 0x80108000);
WREG32(0x6578, 0x20802); WREG32(index_reg, 0x20801);
WREG32(0x657C, 0xBED08920); WREG32(data_reg, 0x8920BED0);
WREG32(0x6578, 0x20803); WREG32(index_reg, 0x20802);
WREG32(0x657C, 0x80008010); WREG32(data_reg, 0xBED08920);
WREG32(0x6578, 0x30000); WREG32(index_reg, 0x20803);
WREG32(0x657C, 0x90008000); WREG32(data_reg, 0x80008010);
WREG32(0x6578, 0x30001); WREG32(index_reg, 0x30000);
WREG32(0x657C, 0x80008000); WREG32(data_reg, 0x90008000);
WREG32(0x6578, 0x30100); WREG32(index_reg, 0x30001);
WREG32(0x657C, 0x8FE0BF90); WREG32(data_reg, 0x80008000);
WREG32(0x6578, 0x30101); WREG32(index_reg, 0x30100);
WREG32(0x657C, 0xBFF880A0); WREG32(data_reg, 0x8FE0BF90);
WREG32(0x6578, 0x30200); WREG32(index_reg, 0x30101);
WREG32(0x657C, 0x8F60BF40); WREG32(data_reg, 0xBFF880A0);
WREG32(0x6578, 0x30201); WREG32(index_reg, 0x30200);
WREG32(0x657C, 0xBFE88180); WREG32(data_reg, 0x8F60BF40);
WREG32(0x6578, 0x30300); WREG32(index_reg, 0x30201);
WREG32(0x657C, 0x8EC0BF00); WREG32(data_reg, 0xBFE88180);
WREG32(0x6578, 0x30301); WREG32(index_reg, 0x30300);
WREG32(0x657C, 0xBFC88280); WREG32(data_reg, 0x8EC0BF00);
WREG32(0x6578, 0x30400); WREG32(index_reg, 0x30301);
WREG32(0x657C, 0x8DE0BEE0); WREG32(data_reg, 0xBFC88280);
WREG32(0x6578, 0x30401); WREG32(index_reg, 0x30400);
WREG32(0x657C, 0xBFA083A0); WREG32(data_reg, 0x8DE0BEE0);
WREG32(0x6578, 0x30500); WREG32(index_reg, 0x30401);
WREG32(0x657C, 0x8CE0BED0); WREG32(data_reg, 0xBFA083A0);
WREG32(0x6578, 0x30501); WREG32(index_reg, 0x30500);
WREG32(0x657C, 0xBF7884E0); WREG32(data_reg, 0x8CE0BED0);
WREG32(0x6578, 0x30600); WREG32(index_reg, 0x30501);
WREG32(0x657C, 0x8BA0BED8); WREG32(data_reg, 0xBF7884E0);
WREG32(0x6578, 0x30601); WREG32(index_reg, 0x30600);
WREG32(0x657C, 0xBF508640); WREG32(data_reg, 0x8BA0BED8);
WREG32(0x6578, 0x30700); WREG32(index_reg, 0x30601);
WREG32(0x657C, 0x8A60BEE8); WREG32(data_reg, 0xBF508640);
WREG32(0x6578, 0x30701); WREG32(index_reg, 0x30700);
WREG32(0x657C, 0xBF2087A0); WREG32(data_reg, 0x8A60BEE8);
WREG32(0x6578, 0x30800); WREG32(index_reg, 0x30701);
WREG32(0x657C, 0x8900BF00); WREG32(data_reg, 0xBF2087A0);
WREG32(0x6578, 0x30801); WREG32(index_reg, 0x30800);
WREG32(0x657C, 0xBF008900); WREG32(data_reg, 0x8900BF00);
WREG32(index_reg, 0x30801);
WREG32(data_reg, 0xBF008900);
} }
struct rv515_watermark { struct rv515_watermark {
......
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