drm/radeon/kms: add initial radeon tv-out support.
Dave Airlie [Thu, 13 Aug 2009 06:32:14 +0000 (16:32 +1000)]
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: Dave Airlie <airlied@redhat.com>

15 files changed:
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_legacy_tv.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/rv515.c

index 6fb8429..c5db0c4 100644 (file)
@@ -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_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 \
-       radeon_test.o r200.o
+       radeon_test.o r200.o radeon_legacy_tv.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 
index cf67928..5d40208 100644 (file)
@@ -2374,6 +2374,17 @@ typedef struct _ATOM_ANALOG_TV_INFO {
        ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING];
 } 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 */
 
index 74d034f..8e31e99 100644 (file)
 #include "atom.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,
                                    struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode)
@@ -89,17 +93,32 @@ static void atombios_scaler_setup(struct drm_crtc *crtc)
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        ENABLE_SCALER_PS_ALLOCATION args;
        int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
+
        /* fixme - fill in enc_priv for atom dac */
        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)
                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));
 
        args.ucScaler = radeon_crtc->crtc_id;
 
-       if (radeon_crtc->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+       if (is_tv) {
                switch (tv_std) {
                case TV_STD_NTSC:
                default:
@@ -128,7 +147,7 @@ static void atombios_scaler_setup(struct drm_crtc *crtc)
                        break;
                }
                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.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
        } else {
@@ -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);
-       if (radeon_crtc->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
-           && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) {
-               atom_rv515_force_tv_scaler(rdev);
+       if ((is_tv || is_cv)
+           && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
+               atom_rv515_force_tv_scaler(rdev, radeon_crtc);
        }
 }
 
@@ -551,42 +570,68 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *encoder;
        SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
+       int need_tv_timings = 0;
+       bool ret;
 
        /* TODO color tiling */
        memset(&crtc_timing, 0, sizeof(crtc_timing));
 
-       /* TODO tv */
        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.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;
+       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_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_Disp = adjusted_mode->crtc_vdisplay;
-       crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
-       crtc_timing.usV_SyncWidth =
-           adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+               crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
+               crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
+               crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
+               crtc_timing.usV_SyncWidth =
+                       adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
 
-       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
-               crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
 
-       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
-               crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                       crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
 
-       if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
-               crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
+                       crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
 
-       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
-               crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
 
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                       crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
+       }
 
        atombios_crtc_set_pll(crtc, adjusted_mode);
        atombios_crtc_set_timing(crtc, &crtc_timing);
index 6c35c3c..e47f2fc 100644 (file)
@@ -66,6 +66,7 @@ extern int radeon_gart_size;
 extern int radeon_benchmarking;
 extern int radeon_testing;
 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
index fcfe5c0..bba9b4b 100644 (file)
@@ -471,11 +471,6 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
                        continue;
                }
 
-               if (i == ATOM_DEVICE_TV1_INDEX) {
-                       DRM_DEBUG("Skipping TV Out\n");
-                       continue;
-               }
-
                bios_connectors[i].connector_type =
                    supported_devices_connector_convert[ci.sucConnectorInfo.
                                                        sbfAccess.
@@ -858,6 +853,72 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
        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 *
 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)
        uint32_t bios_2_scratch, bios_6_scratch;
 
        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);
        } 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);
        }
 
index 70ede6a..6a2b029 100644 (file)
@@ -94,6 +94,54 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
        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)
 {
        struct drm_device *dev = encoder->dev;
@@ -213,7 +261,6 @@ static int radeon_vga_get_modes(struct drm_connector *connector)
 static int radeon_vga_mode_valid(struct drm_connector *connector,
                                  struct drm_display_mode *mode)
 {
-
        return MODE_OK;
 }
 
@@ -225,22 +272,22 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
        bool dret;
        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);
        dret = radeon_ddc_probe(radeon_connector);
        radeon_i2c_do_lock(radeon_connector, 0);
        if (dret)
                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 {
-                       encoder_funcs = encoder->helper_private;
-                       ret = encoder_funcs->detect(encoder, connector);
-               }
+               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, true);
        radeon_connector_update_scratch_regs(connector, ret);
        return ret;
 }
@@ -259,21 +306,87 @@ struct drm_connector_funcs radeon_vga_connector_funcs = {
        .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)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        int ret;
 
        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;
 }
 
+/*
+ * 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)
 {
        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_mode_object *obj;
        int i;
@@ -283,32 +396,58 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
        radeon_i2c_do_lock(radeon_connector, 1);
        dret = radeon_ddc_probe(radeon_connector);
        radeon_i2c_do_lock(radeon_connector, 0);
-       if (dret)
-               ret = connector_status_connected;
-       else {
-               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-                       if (connector->encoder_ids[i] == 0)
-                               break;
+       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;
+               }
+       }
+
+       if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
+               goto out;
+
+       /* find analog encoder */
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
 
-                       obj = drm_mode_object_find(connector->dev,
-                                                  connector->encoder_ids[i],
-                                                  DRM_MODE_OBJECT_ENCODER);
-                       if (!obj)
-                               continue;
+               obj = drm_mode_object_find(connector->dev,
+                                          connector->encoder_ids[i],
+                                          DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
 
-                       encoder = obj_to_encoder(obj);
+               encoder = obj_to_encoder(obj);
 
-                       encoder_funcs = encoder->helper_private;
-                       if (encoder_funcs->detect) {
+               encoder_funcs = encoder->helper_private;
+               if (encoder_funcs->detect) {
+                       if (ret != connector_status_connected) {
                                ret = encoder_funcs->detect(encoder, connector);
                                if (ret == connector_status_connected) {
-                                       radeon_connector->use_digital = 0;
-                                       break;
+                                       radeon_connector->use_digital = false;
                                }
                        }
+                       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 */
        radeon_connector_update_scratch_regs(connector, ret);
        return ret;
@@ -332,7 +471,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
 
                encoder = obj_to_encoder(obj);
 
-               if (radeon_connector->use_digital) {
+               if (radeon_connector->use_digital == true) {
                        if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
                                return encoder;
                } else {
@@ -385,10 +524,7 @@ radeon_add_atom_connector(struct drm_device *dev,
        uint32_t subpixel_order = SubPixelNone;
 
        /* fixme - tv/cv/din */
-       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))
+       if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                return;
 
        /* see if we already added it */
@@ -480,6 +616,10 @@ radeon_add_atom_connector(struct drm_device *dev,
        case DRM_MODE_CONNECTOR_SVIDEO:
        case DRM_MODE_CONNECTOR_Composite:
        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;
        case DRM_MODE_CONNECTOR_LVDS:
                radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
@@ -522,10 +662,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
        uint32_t subpixel_order = SubPixelNone;
 
        /* fixme - tv/cv/din */
-       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))
+       if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                return;
 
        /* see if we already added it */
@@ -578,6 +715,10 @@ radeon_add_legacy_connector(struct drm_device *dev,
        case DRM_MODE_CONNECTOR_SVIDEO:
        case DRM_MODE_CONNECTOR_Composite:
        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;
        case DRM_MODE_CONNECTOR_LVDS:
                drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
index af03560..9d817a6 100644 (file)
@@ -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 drm_connector *drm_connector;
@@ -346,9 +346,13 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
 
        if (!radeon_connector->ddc_bus)
                return -1;
-       radeon_i2c_do_lock(radeon_connector, 1);
-       edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
-       radeon_i2c_do_lock(radeon_connector, 0);
+       if (!radeon_connector->edid) {
+               radeon_i2c_do_lock(radeon_connector, 1);
+               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) {
                /* update digital bits here */
                if (edid->input & DRM_EDID_INPUT_DIGITAL)
@@ -677,7 +681,6 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
                        continue;
                if (first) {
                        radeon_crtc->rmx_type = radeon_encoder->rmx_type;
-                       radeon_crtc->devices = radeon_encoder->devices;
                        memcpy(&radeon_crtc->native_mode,
                                &radeon_encoder->native_mode,
                                sizeof(struct radeon_native_mode));
index 0bd5879..133e975 100644 (file)
@@ -91,6 +91,7 @@ int radeon_gart_size = 512; /* default gart size */
 int radeon_benchmarking = 0;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
+int radeon_tv = 1;
 #endif
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
@@ -123,6 +124,9 @@ module_param_named(test, radeon_testing, int, 0444);
 
 MODULE_PARM_DESC(connector_table, "Force connector table");
 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
 
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
index 0a92706..5c4ede7 100644 (file)
@@ -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 *
 radeon_get_connector_for_encoder(struct drm_encoder *encoder)
 {
@@ -244,9 +261,9 @@ atombios_dac_setup(struct drm_encoder *encoder, int 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;
-       else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+       else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
                args.ucDacStandard = ATOM_DAC1_CV;
        else {
                switch (tv_std) {
@@ -288,7 +305,7 @@ atombios_tv_setup(struct drm_encoder *encoder, int 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;
        else {
                switch (tv_std) {
@@ -825,10 +842,10 @@ atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
 
        /* XXX: fix up scratch reg handling */
        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 |
                             (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)));
        else
                WREG32(reg, 0);
@@ -851,9 +868,19 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
        int index = 0;
        bool is_dig = false;
+       int devices;
 
        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) {
        case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
@@ -881,18 +908,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                break;
        case ENCODER_OBJECT_ID_INTERNAL_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);
-               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+               else if (devices & (ATOM_DEVICE_CV_SUPPORT))
                        index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
                else
                        index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_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);
-               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+               else if (devices & (ATOM_DEVICE_CV_SUPPORT))
                        index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
                else
                        index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
@@ -979,18 +1006,18 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_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;
-                               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;
                                else
                                        args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_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;
-                               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;
                                else
                                        args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
@@ -1019,17 +1046,17 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
                                args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
                                break;
                        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;
-                               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;
                                else
                                        args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
                                break;
                        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;
-                               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;
                                else
                                        args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
@@ -1097,7 +1124,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        atombios_set_encoder_crtc_source(encoder);
 
        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);
                else
                        atombios_yuv_setup(encoder, false);
@@ -1135,7 +1162,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        case ENCODER_OBJECT_ID_INTERNAL_DAC2:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
                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);
                break;
        }
@@ -1143,11 +1170,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
 }
 
 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 radeon_device *rdev = dev->dev_private;
        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 |
                                       ATOM_DEVICE_CV_SUPPORT |
@@ -1168,15 +1196,15 @@ atombios_dac_load_detect(struct drm_encoder *encoder)
                else
                        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);
-               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);
-               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);
                        if (crev >= 3)
                                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);
                        if (crev >= 3)
                                args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
@@ -1195,9 +1223,10 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        uint32_t bios_0_scratch;
 
-       if (!atombios_dac_load_detect(encoder)) {
+       if (!atombios_dac_load_detect(encoder, connector)) {
                DRM_DEBUG("detect returned false \n");
                return connector_status_unknown;
        }
@@ -1207,17 +1236,20 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec
        else
                bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
 
-       DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch);
-       if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+       DRM_DEBUG("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
+       if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
                if (bios_0_scratch & ATOM_S0_CRT1_MASK)
                        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)
                        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))
                        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))
                        return connector_status_connected; /* CTV */
                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)
 {
        radeon_atom_output_lock(encoder, true);
        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)
@@ -1238,12 +1272,21 @@ static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
        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 = {
        .dpms = radeon_atom_encoder_dpms,
        .mode_fixup = radeon_atom_mode_fixup,
        .prepare = radeon_atom_encoder_prepare,
        .mode_set = radeon_atom_encoder_mode_set,
        .commit = radeon_atom_encoder_commit,
+       .disable = radeon_atom_encoder_disable,
        /* no detect for TMDS/LVDS yet */
 };
 
@@ -1268,6 +1311,18 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = {
        .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 *
 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
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
                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);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DVO1:
index 0da72f1..0d29d15 100644 (file)
@@ -28,6 +28,7 @@
 #include <drm/radeon_drm.h>
 #include "radeon_fixed.h"
 #include "radeon.h"
+#include "atom.h"
 
 static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
                                       struct drm_display_mode *mode,
@@ -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 radeon_device *rdev = dev->dev_private;
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_encoder *encoder;
        int format;
        int hsync_start;
        int hsync_wid;
@@ -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_v_total_disp;
        uint32_t crtc_v_sync_strt_wid;
+       bool is_tv = false;
 
        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) {
        case 15:      /*  555 */
@@ -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);
        }
 
+       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_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);
@@ -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_fb_post_div = 0;
        uint32_t htotal_cntl = 0;
-
+       bool is_tv = false;
        struct radeon_pll *pll;
 
        struct {
@@ -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) {
                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)
                                pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
                        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)
                                          ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
                                         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,
                             RADEON_PIX2CLK_SRC_SEL_CPUCLK,
                             ~(RADEON_PIX2CLK_SRC_SEL_MASK));
@@ -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);
        } 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) {
                        /* A temporal workaround for the occational blanking on certain laptop panels.
                           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)
                             RADEON_VCLK_SRC_SEL_PPLLCLK,
                             ~(RADEON_VCLK_SRC_SEL_MASK));
 
+               if (is_tv)
+                       WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
        }
 }
 
index 9322675..0aaafcd 100644 (file)
 #include "radeon.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)
 {
@@ -98,6 +107,8 @@ static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
        else
                radeon_combios_output_lock(encoder, true);
        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)
@@ -195,6 +206,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
        .prepare = radeon_legacy_lvds_prepare,
        .mode_set = radeon_legacy_lvds_mode_set,
        .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)
        else
                radeon_combios_output_lock(encoder, true);
        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)
@@ -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,
        .commit = radeon_legacy_primary_dac_commit,
        .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)
        else
                radeon_combios_output_lock(encoder, true);
        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)
@@ -566,6 +581,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs
        .prepare = radeon_legacy_tmds_int_prepare,
        .mode_set = radeon_legacy_tmds_int_mode_set,
        .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)
        else
                radeon_combios_output_lock(encoder, true);
        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)
@@ -706,6 +723,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs
        .prepare = radeon_legacy_tmds_ext_prepare,
        .mode_set = radeon_legacy_tmds_ext_mode_set,
        .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)
 {
        struct drm_device *dev = encoder->dev;
        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 tv_master_cntl = 0; */
-
+       uint32_t tv_master_cntl = 0;
+       bool is_tv;
        DRM_DEBUG("\n");
 
+       is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
+
        if (rdev->family == CHIP_R200)
                fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
        else {
-               crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
-               /*  FIXME TV */
-               /* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */
+               if (is_tv)
+                       tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL);
+               else
+                       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
                tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
        }
 
@@ -746,20 +768,23 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
                if (rdev->family == CHIP_R200) {
                        fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
                } else {
-                       crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
-                       /* tv_master_cntl |= RADEON_TV_ON; */
+                       if (is_tv)
+                               tv_master_cntl |= RADEON_TV_ON;
+                       else
+                               crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
+
                        if (rdev->family == CHIP_R420 ||
-                                       rdev->family == CHIP_R423 ||
-                                       rdev->family == CHIP_RV410)
+                           rdev->family == CHIP_R423 ||
+                           rdev->family == CHIP_RV410)
                                tv_dac_cntl &= ~(R420_TV_DAC_RDACPD |
-                                               R420_TV_DAC_GDACPD |
-                                               R420_TV_DAC_BDACPD |
-                                               RADEON_TV_DAC_BGSLEEP);
+                                                R420_TV_DAC_GDACPD |
+                                                R420_TV_DAC_BDACPD |
+                                                RADEON_TV_DAC_BGSLEEP);
                        else
                                tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
-                                               RADEON_TV_DAC_GDACPD |
-                                               RADEON_TV_DAC_BDACPD |
-                                               RADEON_TV_DAC_BGSLEEP);
+                                                RADEON_TV_DAC_GDACPD |
+                                                RADEON_TV_DAC_BDACPD |
+                                                RADEON_TV_DAC_BGSLEEP);
                }
                break;
        case DRM_MODE_DPMS_STANDBY:
@@ -768,8 +793,11 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
                if (rdev->family == CHIP_R200)
                        fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
                else {
-                       crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
-                       /* tv_master_cntl &= ~RADEON_TV_ON; */
+                       if (is_tv)
+                               tv_master_cntl &= ~RADEON_TV_ON;
+                       else
+                               crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
+
                        if (rdev->family == CHIP_R420 ||
                                        rdev->family == CHIP_R423 ||
                                        rdev->family == CHIP_RV410)
@@ -789,8 +817,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
        if (rdev->family == CHIP_R200) {
                WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
        } else {
-               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
-               /* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */
+               if (is_tv)
+                       WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
+               else
+                       WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
                WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
        }
 
@@ -809,6 +839,7 @@ static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
        else
                radeon_combios_output_lock(encoder, true);
        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)
@@ -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_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
        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 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");
 
+       is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
+
        if (rdev->family != CHIP_R200) {
                tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
                if (rdev->family == CHIP_R420 ||
@@ -858,7 +893,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
                }
 
                /*  FIXME TV */
-               if (radeon_encoder->enc_priv) {
+               if (tv_dac) {
                        struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
                        tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
                                        RADEON_TV_DAC_NHOLD |
@@ -875,44 +910,93 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
        if (ASIC_IS_R300(rdev)) {
                gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1;
                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
                disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
 
-       dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL;
+       if (rdev->family == CHIP_R200)
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
 
-       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;
-               } else if (rdev->family == CHIP_R200) {
-                       fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
-                                         RADEON_FP2_DVO_RATE_SEL_SDR);
-               } else
-                       disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+       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 {
-               if (ASIC_IS_R300(rdev)) {
-                       disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
-                       disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
-               } else if (rdev->family == CHIP_R200) {
-                       fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
-                                         RADEON_FP2_DVO_RATE_SEL_SDR);
-                       fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
-               } else
-                       disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
-       }
 
-       WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+               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;
+                       } else if (rdev->family == CHIP_R200) {
+                               fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
+                                                 RADEON_FP2_DVO_RATE_SEL_SDR);
+                       } 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_TVDAC_SOURCE_CRTC2;
+                       } else if (rdev->family == CHIP_R200) {
+                               fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
+                                                 RADEON_FP2_DVO_RATE_SEL_SDR);
+                               fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
+                       } else
+                               disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
+               }
+               WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+       }
 
        if (ASIC_IS_R300(rdev)) {
                WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
-               WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl);
-       } else if (rdev->family == CHIP_R200)
-               WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+               WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+       }
+
+       if (rdev->family >= CHIP_R200)
+               WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl);
        else
                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)
                radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
        else
@@ -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,
                                                             struct drm_connector *connector)
 {
@@ -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 disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp;
        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;
 
-       /*  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 */
        pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
@@ -1013,8 +1252,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder
        }
        WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
 
-       /* return found; */
-       return connector_status_disconnected;
+       return found;
 
 }
 
@@ -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,
        .commit = radeon_legacy_tv_dac_commit,
        .detect = radeon_legacy_tv_dac_detect,
+       .disable = radeon_legacy_encoder_disable,
 };
 
 
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
new file mode 100644 (file)
index 0000000..3a12bb0
--- /dev/null
@@ -0,0 +1,904 @@
+#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;
+}
+
index 20e9509..523d6cb 100644 (file)
@@ -188,6 +188,21 @@ struct radeon_native_mode {
        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 drm_crtc base;
        int crtc_id;
@@ -202,7 +217,6 @@ struct radeon_crtc {
        uint32_t legacy_display_base_addr;
        uint32_t legacy_cursor_offset;
        enum radeon_rmx_type rmx_type;
-       uint32_t devices;
        fixed20_12 vsc;
        fixed20_12 hsc;
        struct radeon_native_mode native_mode;
@@ -234,7 +248,13 @@ struct radeon_encoder_tv_dac {
        uint32_t ntsc_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;
+       struct radeon_tv_regs tv;
 };
 
 struct radeon_encoder_int_tmds {
@@ -253,10 +273,15 @@ struct radeon_encoder_atom_dig {
        struct radeon_native_mode native_mode;
 };
 
+struct radeon_encoder_atom_dac {
+       enum radeon_tv_std tv_std;
+};
+
 struct radeon_encoder {
        struct drm_encoder base;
        uint32_t encoder_id;
        uint32_t devices;
+       uint32_t active_device;
        uint32_t flags;
        uint32_t pixel_clock;
        enum radeon_rmx_type rmx_type;
@@ -274,7 +299,10 @@ struct radeon_connector {
        uint32_t connector_id;
        uint32_t devices;
        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;
 };
 
@@ -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);
 extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
 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 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);
 bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
                                        struct drm_display_mode *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
index 404b39b..28be2f1 100644 (file)
 #       define RADEON_RGB_CONVERT_BY_PASS        (1 << 10)
 #       define RADEON_UVRAM_READ_MARGIN_SHIFT    16
 #       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_SYNC_OE                     (1 <<  0)
 #       define RADEON_SYNC_OUT                    (1 <<  1)
index 60a194f..97965c4 100644 (file)
@@ -475,232 +475,234 @@ int rv515_init(struct radeon_device *rdev)
        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)
 {
-
-       WREG32(0x659C, 0x0);
-       WREG32(0x6594, 0x705);
-       WREG32(0x65A4, 0x10001);
-       WREG32(0x65D8, 0x0);
-       WREG32(0x65B0, 0x0);
-       WREG32(0x65C0, 0x0);
-       WREG32(0x65D4, 0x0);
-       WREG32(0x6578, 0x0);
-       WREG32(0x657C, 0x841880A8);
-       WREG32(0x6578, 0x1);
-       WREG32(0x657C, 0x84208680);
-       WREG32(0x6578, 0x2);
-       WREG32(0x657C, 0xBFF880B0);
-       WREG32(0x6578, 0x100);
-       WREG32(0x657C, 0x83D88088);
-       WREG32(0x6578, 0x101);
-       WREG32(0x657C, 0x84608680);
-       WREG32(0x6578, 0x102);
-       WREG32(0x657C, 0xBFF080D0);
-       WREG32(0x6578, 0x200);
-       WREG32(0x657C, 0x83988068);
-       WREG32(0x6578, 0x201);
-       WREG32(0x657C, 0x84A08680);
-       WREG32(0x6578, 0x202);
-       WREG32(0x657C, 0xBFF080F8);
-       WREG32(0x6578, 0x300);
-       WREG32(0x657C, 0x83588058);
-       WREG32(0x6578, 0x301);
-       WREG32(0x657C, 0x84E08660);
-       WREG32(0x6578, 0x302);
-       WREG32(0x657C, 0xBFF88120);
-       WREG32(0x6578, 0x400);
-       WREG32(0x657C, 0x83188040);
-       WREG32(0x6578, 0x401);
-       WREG32(0x657C, 0x85008660);
-       WREG32(0x6578, 0x402);
-       WREG32(0x657C, 0xBFF88150);
-       WREG32(0x6578, 0x500);
-       WREG32(0x657C, 0x82D88030);
-       WREG32(0x6578, 0x501);
-       WREG32(0x657C, 0x85408640);
-       WREG32(0x6578, 0x502);
-       WREG32(0x657C, 0xBFF88180);
-       WREG32(0x6578, 0x600);
-       WREG32(0x657C, 0x82A08018);
-       WREG32(0x6578, 0x601);
-       WREG32(0x657C, 0x85808620);
-       WREG32(0x6578, 0x602);
-       WREG32(0x657C, 0xBFF081B8);
-       WREG32(0x6578, 0x700);
-       WREG32(0x657C, 0x82608010);
-       WREG32(0x6578, 0x701);
-       WREG32(0x657C, 0x85A08600);
-       WREG32(0x6578, 0x702);
-       WREG32(0x657C, 0x800081F0);
-       WREG32(0x6578, 0x800);
-       WREG32(0x657C, 0x8228BFF8);
-       WREG32(0x6578, 0x801);
-       WREG32(0x657C, 0x85E085E0);
-       WREG32(0x6578, 0x802);
-       WREG32(0x657C, 0xBFF88228);
-       WREG32(0x6578, 0x10000);
-       WREG32(0x657C, 0x82A8BF00);
-       WREG32(0x6578, 0x10001);
-       WREG32(0x657C, 0x82A08CC0);
-       WREG32(0x6578, 0x10002);
-       WREG32(0x657C, 0x8008BEF8);
-       WREG32(0x6578, 0x10100);
-       WREG32(0x657C, 0x81F0BF28);
-       WREG32(0x6578, 0x10101);
-       WREG32(0x657C, 0x83608CA0);
-       WREG32(0x6578, 0x10102);
-       WREG32(0x657C, 0x8018BED0);
-       WREG32(0x6578, 0x10200);
-       WREG32(0x657C, 0x8148BF38);
-       WREG32(0x6578, 0x10201);
-       WREG32(0x657C, 0x84408C80);
-       WREG32(0x6578, 0x10202);
-       WREG32(0x657C, 0x8008BEB8);
-       WREG32(0x6578, 0x10300);
-       WREG32(0x657C, 0x80B0BF78);
-       WREG32(0x6578, 0x10301);
-       WREG32(0x657C, 0x85008C20);
-       WREG32(0x6578, 0x10302);
-       WREG32(0x657C, 0x8020BEA0);
-       WREG32(0x6578, 0x10400);
-       WREG32(0x657C, 0x8028BF90);
-       WREG32(0x6578, 0x10401);
-       WREG32(0x657C, 0x85E08BC0);
-       WREG32(0x6578, 0x10402);
-       WREG32(0x657C, 0x8018BE90);
-       WREG32(0x6578, 0x10500);
-       WREG32(0x657C, 0xBFB8BFB0);
-       WREG32(0x6578, 0x10501);
-       WREG32(0x657C, 0x86C08B40);
-       WREG32(0x6578, 0x10502);
-       WREG32(0x657C, 0x8010BE90);
-       WREG32(0x6578, 0x10600);
-       WREG32(0x657C, 0xBF58BFC8);
-       WREG32(0x6578, 0x10601);
-       WREG32(0x657C, 0x87A08AA0);
-       WREG32(0x6578, 0x10602);
-       WREG32(0x657C, 0x8010BE98);
-       WREG32(0x6578, 0x10700);
-       WREG32(0x657C, 0xBF10BFF0);
-       WREG32(0x6578, 0x10701);
-       WREG32(0x657C, 0x886089E0);
-       WREG32(0x6578, 0x10702);
-       WREG32(0x657C, 0x8018BEB0);
-       WREG32(0x6578, 0x10800);
-       WREG32(0x657C, 0xBED8BFE8);
-       WREG32(0x6578, 0x10801);
-       WREG32(0x657C, 0x89408940);
-       WREG32(0x6578, 0x10802);
-       WREG32(0x657C, 0xBFE8BED8);
-       WREG32(0x6578, 0x20000);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20001);
-       WREG32(0x657C, 0x90008000);
-       WREG32(0x6578, 0x20002);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20003);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20100);
-       WREG32(0x657C, 0x80108000);
-       WREG32(0x6578, 0x20101);
-       WREG32(0x657C, 0x8FE0BF70);
-       WREG32(0x6578, 0x20102);
-       WREG32(0x657C, 0xBFE880C0);
-       WREG32(0x6578, 0x20103);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20200);
-       WREG32(0x657C, 0x8018BFF8);
-       WREG32(0x6578, 0x20201);
-       WREG32(0x657C, 0x8F80BF08);
-       WREG32(0x6578, 0x20202);
-       WREG32(0x657C, 0xBFD081A0);
-       WREG32(0x6578, 0x20203);
-       WREG32(0x657C, 0xBFF88000);
-       WREG32(0x6578, 0x20300);
-       WREG32(0x657C, 0x80188000);
-       WREG32(0x6578, 0x20301);
-       WREG32(0x657C, 0x8EE0BEC0);
-       WREG32(0x6578, 0x20302);
-       WREG32(0x657C, 0xBFB082A0);
-       WREG32(0x6578, 0x20303);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20400);
-       WREG32(0x657C, 0x80188000);
-       WREG32(0x6578, 0x20401);
-       WREG32(0x657C, 0x8E00BEA0);
-       WREG32(0x6578, 0x20402);
-       WREG32(0x657C, 0xBF8883C0);
-       WREG32(0x6578, 0x20403);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x20500);
-       WREG32(0x657C, 0x80188000);
-       WREG32(0x6578, 0x20501);
-       WREG32(0x657C, 0x8D00BE90);
-       WREG32(0x6578, 0x20502);
-       WREG32(0x657C, 0xBF588500);
-       WREG32(0x6578, 0x20503);
-       WREG32(0x657C, 0x80008008);
-       WREG32(0x6578, 0x20600);
-       WREG32(0x657C, 0x80188000);
-       WREG32(0x6578, 0x20601);
-       WREG32(0x657C, 0x8BC0BE98);
-       WREG32(0x6578, 0x20602);
-       WREG32(0x657C, 0xBF308660);
-       WREG32(0x6578, 0x20603);
-       WREG32(0x657C, 0x80008008);
-       WREG32(0x6578, 0x20700);
-       WREG32(0x657C, 0x80108000);
-       WREG32(0x6578, 0x20701);
-       WREG32(0x657C, 0x8A80BEB0);
-       WREG32(0x6578, 0x20702);
-       WREG32(0x657C, 0xBF0087C0);
-       WREG32(0x6578, 0x20703);
-       WREG32(0x657C, 0x80008008);
-       WREG32(0x6578, 0x20800);
-       WREG32(0x657C, 0x80108000);
-       WREG32(0x6578, 0x20801);
-       WREG32(0x657C, 0x8920BED0);
-       WREG32(0x6578, 0x20802);
-       WREG32(0x657C, 0xBED08920);
-       WREG32(0x6578, 0x20803);
-       WREG32(0x657C, 0x80008010);
-       WREG32(0x6578, 0x30000);
-       WREG32(0x657C, 0x90008000);
-       WREG32(0x6578, 0x30001);
-       WREG32(0x657C, 0x80008000);
-       WREG32(0x6578, 0x30100);
-       WREG32(0x657C, 0x8FE0BF90);
-       WREG32(0x6578, 0x30101);
-       WREG32(0x657C, 0xBFF880A0);
-       WREG32(0x6578, 0x30200);
-       WREG32(0x657C, 0x8F60BF40);
-       WREG32(0x6578, 0x30201);
-       WREG32(0x657C, 0xBFE88180);
-       WREG32(0x6578, 0x30300);
-       WREG32(0x657C, 0x8EC0BF00);
-       WREG32(0x6578, 0x30301);
-       WREG32(0x657C, 0xBFC88280);
-       WREG32(0x6578, 0x30400);
-       WREG32(0x657C, 0x8DE0BEE0);
-       WREG32(0x6578, 0x30401);
-       WREG32(0x657C, 0xBFA083A0);
-       WREG32(0x6578, 0x30500);
-       WREG32(0x657C, 0x8CE0BED0);
-       WREG32(0x6578, 0x30501);
-       WREG32(0x657C, 0xBF7884E0);
-       WREG32(0x6578, 0x30600);
-       WREG32(0x657C, 0x8BA0BED8);
-       WREG32(0x6578, 0x30601);
-       WREG32(0x657C, 0xBF508640);
-       WREG32(0x6578, 0x30700);
-       WREG32(0x657C, 0x8A60BEE8);
-       WREG32(0x6578, 0x30701);
-       WREG32(0x657C, 0xBF2087A0);
-       WREG32(0x6578, 0x30800);
-       WREG32(0x657C, 0x8900BF00);
-       WREG32(0x6578, 0x30801);
-       WREG32(0x657C, 0xBF008900);
+       int index_reg = 0x6578 + crtc->crtc_offset;
+       int data_reg = 0x657c + crtc->crtc_offset;
+
+       WREG32(0x659C + crtc->crtc_offset, 0x0);
+       WREG32(0x6594 + crtc->crtc_offset, 0x705);
+       WREG32(0x65A4 + crtc->crtc_offset, 0x10001);
+       WREG32(0x65D8 + crtc->crtc_offset, 0x0);
+       WREG32(0x65B0 + crtc->crtc_offset, 0x0);
+       WREG32(0x65C0 + crtc->crtc_offset, 0x0);
+       WREG32(0x65D4 + crtc->crtc_offset, 0x0);
+       WREG32(index_reg, 0x0);
+       WREG32(data_reg, 0x841880A8);
+       WREG32(index_reg, 0x1);
+       WREG32(data_reg, 0x84208680);
+       WREG32(index_reg, 0x2);
+       WREG32(data_reg, 0xBFF880B0);
+       WREG32(index_reg, 0x100);
+       WREG32(data_reg, 0x83D88088);
+       WREG32(index_reg, 0x101);
+       WREG32(data_reg, 0x84608680);
+       WREG32(index_reg, 0x102);
+       WREG32(data_reg, 0xBFF080D0);
+       WREG32(index_reg, 0x200);
+       WREG32(data_reg, 0x83988068);
+       WREG32(index_reg, 0x201);
+       WREG32(data_reg, 0x84A08680);
+       WREG32(index_reg, 0x202);
+       WREG32(data_reg, 0xBFF080F8);
+       WREG32(index_reg, 0x300);
+       WREG32(data_reg, 0x83588058);
+       WREG32(index_reg, 0x301);
+       WREG32(data_reg, 0x84E08660);
+       WREG32(index_reg, 0x302);
+       WREG32(data_reg, 0xBFF88120);
+       WREG32(index_reg, 0x400);
+       WREG32(data_reg, 0x83188040);
+       WREG32(index_reg, 0x401);
+       WREG32(data_reg, 0x85008660);
+       WREG32(index_reg, 0x402);
+       WREG32(data_reg, 0xBFF88150);
+       WREG32(index_reg, 0x500);
+       WREG32(data_reg, 0x82D88030);
+       WREG32(index_reg, 0x501);
+       WREG32(data_reg, 0x85408640);
+       WREG32(index_reg, 0x502);
+       WREG32(data_reg, 0xBFF88180);
+       WREG32(index_reg, 0x600);
+       WREG32(data_reg, 0x82A08018);
+       WREG32(index_reg, 0x601);
+       WREG32(data_reg, 0x85808620);
+       WREG32(index_reg, 0x602);
+       WREG32(data_reg, 0xBFF081B8);
+       WREG32(index_reg, 0x700);
+       WREG32(data_reg, 0x82608010);
+       WREG32(index_reg, 0x701);
+       WREG32(data_reg, 0x85A08600);
+       WREG32(index_reg, 0x702);
+       WREG32(data_reg, 0x800081F0);
+       WREG32(index_reg, 0x800);
+       WREG32(data_reg, 0x8228BFF8);
+       WREG32(index_reg, 0x801);
+       WREG32(data_reg, 0x85E085E0);
+       WREG32(index_reg, 0x802);
+       WREG32(data_reg, 0xBFF88228);
+       WREG32(index_reg, 0x10000);
+       WREG32(data_reg, 0x82A8BF00);
+       WREG32(index_reg, 0x10001);
+       WREG32(data_reg, 0x82A08CC0);
+       WREG32(index_reg, 0x10002);
+       WREG32(data_reg, 0x8008BEF8);
+       WREG32(index_reg, 0x10100);
+       WREG32(data_reg, 0x81F0BF28);
+       WREG32(index_reg, 0x10101);
+       WREG32(data_reg, 0x83608CA0);
+       WREG32(index_reg, 0x10102);
+       WREG32(data_reg, 0x8018BED0);
+       WREG32(index_reg, 0x10200);
+       WREG32(data_reg, 0x8148BF38);
+       WREG32(index_reg, 0x10201);
+       WREG32(data_reg, 0x84408C80);
+       WREG32(index_reg, 0x10202);
+       WREG32(data_reg, 0x8008BEB8);
+       WREG32(index_reg, 0x10300);
+       WREG32(data_reg, 0x80B0BF78);
+       WREG32(index_reg, 0x10301);
+       WREG32(data_reg, 0x85008C20);
+       WREG32(index_reg, 0x10302);
+       WREG32(data_reg, 0x8020BEA0);
+       WREG32(index_reg, 0x10400);
+       WREG32(data_reg, 0x8028BF90);
+       WREG32(index_reg, 0x10401);
+       WREG32(data_reg, 0x85E08BC0);
+       WREG32(index_reg, 0x10402);
+       WREG32(data_reg, 0x8018BE90);
+       WREG32(index_reg, 0x10500);
+       WREG32(data_reg, 0xBFB8BFB0);
+       WREG32(index_reg, 0x10501);
+       WREG32(data_reg, 0x86C08B40);
+       WREG32(index_reg, 0x10502);
+       WREG32(data_reg, 0x8010BE90);
+       WREG32(index_reg, 0x10600);
+       WREG32(data_reg, 0xBF58BFC8);
+       WREG32(index_reg, 0x10601);
+       WREG32(data_reg, 0x87A08AA0);
+       WREG32(index_reg, 0x10602);
+       WREG32(data_reg, 0x8010BE98);
+       WREG32(index_reg, 0x10700);
+       WREG32(data_reg, 0xBF10BFF0);
+       WREG32(index_reg, 0x10701);
+       WREG32(data_reg, 0x886089E0);
+       WREG32(index_reg, 0x10702);
+       WREG32(data_reg, 0x8018BEB0);
+       WREG32(index_reg, 0x10800);
+       WREG32(data_reg, 0xBED8BFE8);
+       WREG32(index_reg, 0x10801);
+       WREG32(data_reg, 0x89408940);
+       WREG32(index_reg, 0x10802);
+       WREG32(data_reg, 0xBFE8BED8);
+       WREG32(index_reg, 0x20000);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20001);
+       WREG32(data_reg, 0x90008000);
+       WREG32(index_reg, 0x20002);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20003);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20100);
+       WREG32(data_reg, 0x80108000);
+       WREG32(index_reg, 0x20101);
+       WREG32(data_reg, 0x8FE0BF70);
+       WREG32(index_reg, 0x20102);
+       WREG32(data_reg, 0xBFE880C0);
+       WREG32(index_reg, 0x20103);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20200);
+       WREG32(data_reg, 0x8018BFF8);
+       WREG32(index_reg, 0x20201);
+       WREG32(data_reg, 0x8F80BF08);
+       WREG32(index_reg, 0x20202);
+       WREG32(data_reg, 0xBFD081A0);
+       WREG32(index_reg, 0x20203);
+       WREG32(data_reg, 0xBFF88000);
+       WREG32(index_reg, 0x20300);
+       WREG32(data_reg, 0x80188000);
+       WREG32(index_reg, 0x20301);
+       WREG32(data_reg, 0x8EE0BEC0);
+       WREG32(index_reg, 0x20302);
+       WREG32(data_reg, 0xBFB082A0);
+       WREG32(index_reg, 0x20303);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20400);
+       WREG32(data_reg, 0x80188000);
+       WREG32(index_reg, 0x20401);
+       WREG32(data_reg, 0x8E00BEA0);
+       WREG32(index_reg, 0x20402);
+       WREG32(data_reg, 0xBF8883C0);
+       WREG32(index_reg, 0x20403);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x20500);
+       WREG32(data_reg, 0x80188000);
+       WREG32(index_reg, 0x20501);
+       WREG32(data_reg, 0x8D00BE90);
+       WREG32(index_reg, 0x20502);
+       WREG32(data_reg, 0xBF588500);
+       WREG32(index_reg, 0x20503);
+       WREG32(data_reg, 0x80008008);
+       WREG32(index_reg, 0x20600);
+       WREG32(data_reg, 0x80188000);
+       WREG32(index_reg, 0x20601);
+       WREG32(data_reg, 0x8BC0BE98);
+       WREG32(index_reg, 0x20602);
+       WREG32(data_reg, 0xBF308660);
+       WREG32(index_reg, 0x20603);
+       WREG32(data_reg, 0x80008008);
+       WREG32(index_reg, 0x20700);
+       WREG32(data_reg, 0x80108000);
+       WREG32(index_reg, 0x20701);
+       WREG32(data_reg, 0x8A80BEB0);
+       WREG32(index_reg, 0x20702);
+       WREG32(data_reg, 0xBF0087C0);
+       WREG32(index_reg, 0x20703);
+       WREG32(data_reg, 0x80008008);
+       WREG32(index_reg, 0x20800);
+       WREG32(data_reg, 0x80108000);
+       WREG32(index_reg, 0x20801);
+       WREG32(data_reg, 0x8920BED0);
+       WREG32(index_reg, 0x20802);
+       WREG32(data_reg, 0xBED08920);
+       WREG32(index_reg, 0x20803);
+       WREG32(data_reg, 0x80008010);
+       WREG32(index_reg, 0x30000);
+       WREG32(data_reg, 0x90008000);
+       WREG32(index_reg, 0x30001);
+       WREG32(data_reg, 0x80008000);
+       WREG32(index_reg, 0x30100);
+       WREG32(data_reg, 0x8FE0BF90);
+       WREG32(index_reg, 0x30101);
+       WREG32(data_reg, 0xBFF880A0);
+       WREG32(index_reg, 0x30200);
+       WREG32(data_reg, 0x8F60BF40);
+       WREG32(index_reg, 0x30201);
+       WREG32(data_reg, 0xBFE88180);
+       WREG32(index_reg, 0x30300);
+       WREG32(data_reg, 0x8EC0BF00);
+       WREG32(index_reg, 0x30301);
+       WREG32(data_reg, 0xBFC88280);
+       WREG32(index_reg, 0x30400);
+       WREG32(data_reg, 0x8DE0BEE0);
+       WREG32(index_reg, 0x30401);
+       WREG32(data_reg, 0xBFA083A0);
+       WREG32(index_reg, 0x30500);
+       WREG32(data_reg, 0x8CE0BED0);
+       WREG32(index_reg, 0x30501);
+       WREG32(data_reg, 0xBF7884E0);
+       WREG32(index_reg, 0x30600);
+       WREG32(data_reg, 0x8BA0BED8);
+       WREG32(index_reg, 0x30601);
+       WREG32(data_reg, 0xBF508640);
+       WREG32(index_reg, 0x30700);
+       WREG32(data_reg, 0x8A60BEE8);
+       WREG32(index_reg, 0x30701);
+       WREG32(data_reg, 0xBF2087A0);
+       WREG32(index_reg, 0x30800);
+       WREG32(data_reg, 0x8900BF00);
+       WREG32(index_reg, 0x30801);
+       WREG32(data_reg, 0xBF008900);
 }
 
 struct rv515_watermark {