From e4fa03f7ddb86720fa19cfc839689e1df72bb928 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 7 Oct 2008 14:10:39 -0400 Subject: [PATCH] radeon: pull in recent fixes from ddx - fixup atom digital encoder setup - pull in add get edid (currently disabled due to lack of support for atom fb/scratch space) --- linux-core/radeon_atombios.c | 57 +++++++++++ linux-core/radeon_combios.c | 2 + linux-core/radeon_encoders.c | 192 +++++++++++++++++------------------ linux-core/radeon_mode.h | 6 ++ 4 files changed, 159 insertions(+), 98 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index a763e766..61732274 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -72,11 +72,66 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de i2c.get_data_mask = (1 << gpio.ucDataY_Shift); i2c.a_clk_mask = (1 << gpio.ucClkA_Shift); i2c.a_data_mask = (1 << gpio.ucDataA_Shift); + i2c.hw_line = gpio.sucI2cId.sbfAccess.bfI2C_LineMux; + i2c.hw_capable = gpio.sucI2cId.sbfAccess.bfHW_Capable; i2c.valid = true; return i2c; } +#if 0 +// TODO fix atom FB/scratch space access +struct edid *radeon_atom_get_edid(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_param; + int i2c_clock = 50; + int prescale; + unsigned char *raw_edid; + struct edid *edid = NULL; + int index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C); + + if (!radeon_connector->ddc_bus) + return edid; + + if (!radeon_connector->ddc_bus->rec.hw_capable) + return edid; + + if (info->atomBIOS->fbBase) + raw_edid = (unsigned char *)info->FB + info->atomBIOS->fbBase; + else if (info->atomBIOS->scratchBase) + raw_edid = (unsigned char *)info->atomBIOS->scratchBase; + else + return edid; + + memset(raw_edid, 0, ATOM_EDID_RAW_DATASIZE); + + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) + prescale = (127 << 8) + (mode_info->sclk * 10) / (4 * 127 * i2c_clock); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) + prescale = (((mode_info->sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; + else + prescale = (mode_info->spll.reference_freq * 10) / i2c_clock; + + edid_param.usPrescale = prescale; + edid_param.usVRAMAddress = 0; + edid_param.ucSlaveAddr = 0xa0; + edid_param.ucLineNumber = radeon_connector->ddc_bus->rec.hw_line; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&edid_param); + + if (raw_edid[1] == 0xff) { + edid = kmalloc(size_of(struct edid), GFP_KERNEL); + *edid = raw_edid; + } + + return edid; + +} +#endif + static struct radeon_i2c_bus_rec radeon_parse_i2c_record(struct drm_device *dev, ATOM_I2C_RECORD *record) { return radeon_lookup_gpio(dev, record->sucI2cId.bfI2C_LineMux); @@ -591,6 +646,8 @@ void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder) encoder->voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); encoder->vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + encoder->lvds_misc = lvds_info->info.ucLVDS_Misc; + encoder->lvds_ss_id = lvds_info->info.ucSS_Id; } } diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index ae1ef2f9..f89bf88a 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -385,6 +385,8 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) { struct radeon_i2c_bus_rec i2c; + i2c.hw_line = 0; + i2c.hw_capable = false; // actually depends on chip i2c.mask_clk_mask = RADEON_GPIO_EN_1; i2c.mask_data_mask = RADEON_GPIO_EN_0; i2c.a_clk_mask = RADEON_GPIO_A_1; diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index e5c95c9a..87d9184f 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -228,58 +228,105 @@ void atombios_set_crtc_source(struct drm_encoder *encoder, int source) } -static void radeon_dfp_disable_dither(struct drm_encoder *encoder, int device) +static void atombios_output_digital_mode_set(struct drm_encoder *encoder, + int device, + struct drm_display_mode *mode) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - - if (!radeon_is_avivo(dev_priv)) - return; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + uint8_t frev, crev; + int index; + LVDS_ENCODER_CONTROL_PS_ALLOCATION args; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 args2; + uint32_t *param = NULL; switch (device) { case ATOM_DEVICE_DFP1_INDEX: - RADEON_WRITE(AVIVO_TMDSA_BIT_DEPTH_CONTROL, 0); /* TMDSA */ + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); break; - case ATOM_DEVICE_DFP2_INDEX: - if ((dev_priv->chip_family == CHIP_RS600) || - (dev_priv->chip_family == CHIP_RS690) || - (dev_priv->chip_family == CHIP_RS740)) - RADEON_WRITE(AVIVO_DDIA_BIT_DEPTH_CONTROL, 0); /* DDIA */ - else - RADEON_WRITE(AVIVO_DVOA_BIT_DEPTH_CONTROL, 0); /* DVO */ + case ATOM_DEVICE_LCD1_INDEX: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); break; - /*case ATOM_DEVICE_LCD1_INDEX:*/ /* LVDS panels need dither enabled */ case ATOM_DEVICE_DFP3_INDEX: - RADEON_WRITE(AVIVO_LVTMA_BIT_DEPTH_CONTROL, 0); /* LVTMA */ + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); break; default: + return; + } + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 0: + case 1: + switch (crev) { + case 0: + case 1: + memset(&args, 0, sizeof(args)); + args.ucAction = PANEL_ENCODER_ACTION_ENABLE; + // TODO HDMI + //if (radeon_encoder->type == OUTPUT_HDMI) + //disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.usPixelClock = cpu_to_le16(mode->clock / 10); + if (device == ATOM_DEVICE_LCD1_INDEX) { + if (radeon_encoder->lvds_misc & (1 << 0)) + args.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (radeon_encoder->lvds_misc & (1 << 1)) + args.ucMisc |= (1 << 1); + } else { + if (mode->clock > 165000) + args.ucMisc |= PANEL_ENCODER_MISC_DUAL; + // TODO 6-bit DAC + args.ucMisc |= (1 << 1); + } + param = (uint32_t *)&args; + break; + case 2: + case 3: + memset(&args2, 0, sizeof(args2)); + args2.ucAction = PANEL_ENCODER_ACTION_ENABLE; + if (crev == 3) { + // TODO coherent mode + //if (encoder->coherent_mode) + //args2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + // TODO HDMI + //if (radeon_encoder->type == OUTPUT_HDMI) + //args2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + if (device == ATOM_DEVICE_LCD1_INDEX) { + if (radeon_encoder->lvds_misc & (1 << 0)) + args2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (radeon_encoder->lvds_misc & (1 << 5)) { + args2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (radeon_encoder->lvds_misc & (1 << 1)) + args2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (radeon_encoder->lvds_misc & (1 << 6)) { + args2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (radeon_encoder->lvds_misc & (1 << 1)) + args2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + } + } else { + if (mode->clock > 165000) + args2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + param = (uint32_t *)&args2; + break; + } break; } -} + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)param); +} static void radeon_lvtma_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - LVDS_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - memset(&args, 0, sizeof(args)); atombios_scaler_setup(encoder, mode); atombios_set_crtc_source(encoder, ATOM_DEVICE_LCD1_INDEX); - - args.ucAction = 1; - if (adjusted_mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - args.usPixelClock = cpu_to_le16(adjusted_mode->clock / 10); - - printk("executing set LVDS encoder\n"); - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_LCD1_INDEX, adjusted_mode); } @@ -287,7 +334,6 @@ static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc; int index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); uint32_t bios_2_scratch, bios_3_scratch; int crtc_id = 0; @@ -593,7 +639,6 @@ static int atombios_tv1_setup(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); TV_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); @@ -617,7 +662,6 @@ static void radeon_atom_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); int atom_type = -1; @@ -724,69 +768,22 @@ static const struct drm_encoder_funcs radeon_atom_dac_enc_funcs = { . destroy = radeon_enc_destroy, }; - -static void atombios_tmds1_setup(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TMDS1_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); - - memset(&args, 0, sizeof(args)); - args.ucAction = 1; - if (mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - - args.usPixelClock = cpu_to_le16(mode->clock / 10); - - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); -} - -static void atombios_tmds2_setup(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TMDS2_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); - - memset(&args, 0, sizeof(args)); - args.ucAction = 1; - if (mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - - args.usPixelClock = cpu_to_le16(mode->clock / 10); - - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); -} - - void atombios_ext_tmds_setup(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); memset(&args, 0, sizeof(args)); - args.sXTmdsEncoder.ucEnable = 1; + args.sXTmdsEncoder.ucEnable = PANEL_ENCODER_ACTION_ENABLE; if (mode->clock > 165000) - args.sXTmdsEncoder.ucMisc = 1; - else - args.sXTmdsEncoder.ucMisc = 0; + args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; // TODO 6-bit DAC -// args.usPixelClock = cpu_to_le16(mode->clock / 10); + args.sXTmdsEncoder.ucMisc |= (1 << 1); atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -799,7 +796,8 @@ static void atombios_dig1_setup(struct drm_encoder *encoder, DIG_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - args.ucAction = 1; + memset(&args, 0, sizeof(args)); + args.ucAction = ATOM_ENABLE; args.usPixelClock = mode->clock / 10; args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1; @@ -827,13 +825,12 @@ static void atombios_ddia_setup(struct drm_encoder *encoder, DVO_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - args.sDVOEncoder.ucAction = ATOM_ENABLE; - args.sDVOEncoder.usPixelClock = mode->clock / 10; + memset(&args, 0, sizeof(args)); + args.sDVOEncoder.ucAction = PANEL_ENCODER_ACTION_ENABLE; + args.sDVOEncoder.usPixelClock = cpu_to_le16(mode->clock / 10); if (mode->clock > 165000) args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; - else - args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = 0; atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -846,8 +843,10 @@ struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios struct drm_encoder *encoder; int type = with_tv ? DRM_MODE_ENCODER_TVDAC : DRM_MODE_ENCODER_DAC; int found = 0; - int digital_enc_mask = ~(ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | - ATOM_DEVICE_LCD1_SUPPORT); + int digital_enc_mask = ~(ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_DFP3_SUPPORT | + ATOM_DEVICE_LCD1_SUPPORT); /* we may already have added this encoder */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC || @@ -1036,7 +1035,7 @@ static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, atombios_set_crtc_source(encoder, atom_type); if (atom_type == ATOM_DEVICE_DFP1_INDEX) - atombios_tmds1_setup(encoder, adjusted_mode); + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_DFP1_INDEX, adjusted_mode); if (atom_type == ATOM_DEVICE_DFP2_INDEX) { if ((dev_priv->chip_family == CHIP_RS600) || (dev_priv->chip_family == CHIP_RS690) || @@ -1046,10 +1045,7 @@ static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, atombios_ext_tmds_setup(encoder, adjusted_mode); } if (atom_type == ATOM_DEVICE_DFP3_INDEX) - atombios_tmds2_setup(encoder, adjusted_mode); - radeon_dfp_disable_dither(encoder, atom_type); - - + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_DFP3_INDEX, adjusted_mode); } static void radeon_atom_tmds_prepare(struct drm_encoder *encoder) @@ -1085,7 +1081,7 @@ struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bio struct drm_encoder *encoder; int analog_enc_mask = ~(ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT); - radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index fef27380..64608e35 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -116,6 +116,8 @@ struct radeon_i2c_bus_rec { uint32_t get_data_mask; uint32_t a_clk_mask; uint32_t a_data_mask; + int hw_line; + bool hw_capable; }; struct radeon_bios_connector { @@ -227,6 +229,10 @@ struct radeon_encoder { bool use_bios_dividers; uint32_t lvds_gen_cntl; + /* atom lvds */ + int lvds_misc; + int lvds_ss_id; + /* legacy primary dac */ uint32_t ps2_pdac_adj;