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,42 +570,68 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, ...@@ -551,42 +570,68 @@ 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;
crtc_timing.usH_Total = adjusted_mode->crtc_htotal; if (need_tv_timings) {
crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; ret = radeon_atom_get_tv_timings(rdev, need_tv_timings - 1,
crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; &crtc_timing, &adjusted_mode->clock);
crtc_timing.usH_SyncWidth = if (ret == false)
adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; need_tv_timings = 0;
}
if (!need_tv_timings) {
crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
crtc_timing.usH_SyncWidth =
adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
crtc_timing.usV_SyncWidth = crtc_timing.usV_SyncWidth =
adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
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);
} }
......
This diff is collapsed.
...@@ -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;
radeon_i2c_do_lock(radeon_connector, 1); if (!radeon_connector->edid) {
edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); radeon_i2c_do_lock(radeon_connector, 1);
radeon_i2c_do_lock(radeon_connector, 0); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
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)
......
This diff is collapsed.
...@@ -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);
} }
} }
......
This diff is collapsed.
...@@ -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_TVOUT_SCALE_EN (1 << 26) # define RADEON_RGB_ATTEN_SEL(x) ((x) << 24)
# 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)
......
This diff is collapsed.
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