diff options
Diffstat (limited to 'drivers/gpu/drm/gma500/cdv_intel_lvds.c')
| -rw-r--r-- | drivers/gpu/drm/gma500/cdv_intel_lvds.c | 336 |
1 files changed, 102 insertions, 234 deletions
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index d81dbc3368f0..fbe7fe317393 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -1,38 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2006-2011 Intel Corporation * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Authors: * Eric Anholt <eric@anholt.net> * Dave Airlie <airlied@linux.ie> * Jesse Barnes <jesse.barnes@intel.com> */ -#include <linux/i2c.h> #include <linux/dmi.h> -#include <drm/drmP.h> +#include <linux/i2c.h> +#include <linux/pm_runtime.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_simple_kms_helper.h> + +#include "cdv_device.h" #include "intel_bios.h" +#include "power.h" #include "psb_drv.h" #include "psb_intel_drv.h" #include "psb_intel_reg.h" -#include "power.h" -#include <linux/pm_runtime.h> -#include "cdv_device.h" -/** +/* * LVDS I2C backlight control macros */ #define BRIGHTNESS_MAX_LEVEL 100 @@ -68,7 +60,7 @@ struct cdv_intel_lvds_priv { */ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 retval; if (gma_power_begin(dev, false)) { @@ -85,97 +77,14 @@ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) return retval; } -#if 0 -/* - * Set LVDS backlight level by I2C command - */ -static int cdv_lvds_i2c_set_brightness(struct drm_device *dev, - unsigned int level) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; - u8 out_buf[2]; - unsigned int blc_i2c_brightness; - - struct i2c_msg msgs[] = { - { - .addr = lvds_i2c_bus->slave_addr, - .flags = 0, - .len = 2, - .buf = out_buf, - } - }; - - blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * - BRIGHTNESS_MASK / - BRIGHTNESS_MAX_LEVEL); - - if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) - blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; - - out_buf[0] = dev_priv->lvds_bl->brightnesscmd; - out_buf[1] = (u8)blc_i2c_brightness; - - if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) - return 0; - - DRM_ERROR("I2C transfer error\n"); - return -1; -} - - -static int cdv_lvds_pwm_set_brightness(struct drm_device *dev, int level) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - - u32 max_pwm_blc; - u32 blc_pwm_duty_cycle; - - max_pwm_blc = cdv_intel_lvds_get_max_backlight(dev); - - /*BLC_PWM_CTL Should be initiated while backlight device init*/ - BUG_ON((max_pwm_blc & PSB_BLC_MAX_PWM_REG_FREQ) == 0); - - blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; - - if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) - blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; - - blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; - REG_WRITE(BLC_PWM_CTL, - (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | - (blc_pwm_duty_cycle)); - - return 0; -} - /* - * Set LVDS backlight level either by I2C or PWM - */ -void cdv_intel_lvds_set_brightness(struct drm_device *dev, int level) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - - if (!dev_priv->lvds_bl) { - DRM_ERROR("NO LVDS Backlight Info\n"); - return; - } - - if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) - cdv_lvds_i2c_set_brightness(dev, level); - else - cdv_lvds_pwm_set_brightness(dev, level); -} -#endif - -/** * Sets the backlight level. * * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight(). */ static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 blc_pwm_ctl; if (gma_power_begin(dev, false)) { @@ -193,13 +102,13 @@ static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) } } -/** +/* * Sets the power state for the panel. */ static void cdv_intel_lvds_set_power(struct drm_device *dev, struct drm_encoder *encoder, bool on) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); u32 pp_status; if (!gma_power_begin(dev, true)) @@ -244,11 +153,11 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector) { } -static int cdv_intel_lvds_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) +static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_display_mode *fixed_mode = dev_priv->mode_dev.panel_fixed_mode; @@ -274,7 +183,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; struct drm_encoder *tmp_encoder; struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; @@ -284,8 +193,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, head) { if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { - printk(KERN_ERR "Can't enable LVDS and another " - "encoder on the same pipe\n"); + pr_err("Can't enable LVDS and another encoder on the same pipe\n"); return false; } } @@ -322,7 +230,7 @@ static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (!gma_power_begin(dev, true)) @@ -340,7 +248,7 @@ static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) static void cdv_intel_lvds_commit(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; if (mode_dev->backlight_duty_cycle == 0) @@ -355,9 +263,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc( - encoder->crtc); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); u32 pfit_control; /* @@ -379,7 +286,7 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, else pfit_control = 0; - pfit_control |= psb_intel_crtc->pipe << PFIT_PIPE_SHIFT; + pfit_control |= gma_crtc->pipe << PFIT_PIPE_SHIFT; if (dev_priv->lvds_dither) pfit_control |= PANEL_8TO6_DITHER_ENABLE; @@ -387,47 +294,27 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, REG_WRITE(PFIT_CONTROL, pfit_control); } -/** - * Detect the LVDS connection. - * - * This always returns CONNECTOR_STATUS_CONNECTED. - * This connector should only have - * been set up if the LVDS was actually connected anyway. - */ -static enum drm_connector_status cdv_intel_lvds_detect( - struct drm_connector *connector, bool force) -{ - return connector_status_connected; -} - -/** +/* * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. */ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_psb_private *dev_priv = dev->dev_private; - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int ret; - ret = psb_intel_ddc_get_modes(connector, &psb_intel_encoder->i2c_bus->adapter); + ret = psb_intel_ddc_get_modes(connector, connector->ddc); if (ret) return ret; - /* Didn't get an EDID, so - * Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - connector->display_info.min_vfreq = 0; - connector->display_info.max_vfreq = 200; - connector->display_info.min_hfreq = 0; - connector->display_info.max_hfreq = 200; if (mode_dev->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); + if (!mode) + return 0; + drm_mode_probed_add(connector, mode); return 1; } @@ -435,23 +322,15 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector) return 0; } -/** - * cdv_intel_lvds_destroy - unregister and free LVDS structures - * @connector: connector to free - * - * Unregister the DDC bus for this connector then free the driver private - * structure. - */ static void cdv_intel_lvds_destroy(struct drm_connector *connector) { - struct psb_intel_encoder *psb_intel_encoder = - psb_intel_attached_encoder(connector); + struct gma_connector *gma_connector = to_gma_connector(connector); + struct gma_encoder *gma_encoder = gma_attached_encoder(connector); - if (psb_intel_encoder->i2c_bus) - psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); - drm_sysfs_connector_remove(connector); + gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); + gma_i2c_destroy(gma_encoder->i2c_bus); drm_connector_cleanup(connector); - kfree(connector); + kfree(gma_connector); } static int cdv_intel_lvds_set_property(struct drm_connector *connector, @@ -461,8 +340,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, struct drm_encoder *encoder = connector->encoder; if (!strcmp(property->name, "scaling mode") && encoder) { - struct psb_intel_crtc *crtc = - to_psb_intel_crtc(encoder->crtc); + struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); uint64_t curValue; if (!crtc) @@ -498,7 +376,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, &crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) return -1; } } else if (!strcmp(property->name, "backlight") && encoder) { @@ -509,7 +387,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, else gma_backlight_set(encoder->dev, value); } else if (!strcmp(property->name, "DPMS") && encoder) { - struct drm_encoder_helper_funcs *helpers = + const struct drm_encoder_helper_funcs *helpers = encoder->helper_private; helpers->dpms(encoder, value); } @@ -529,29 +407,16 @@ static const struct drm_connector_helper_funcs cdv_intel_lvds_connector_helper_funcs = { .get_modes = cdv_intel_lvds_get_modes, .mode_valid = cdv_intel_lvds_mode_valid, - .best_encoder = psb_intel_best_encoder, + .best_encoder = gma_best_encoder, }; static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = { .dpms = drm_helper_connector_dpms, - .save = cdv_intel_lvds_save, - .restore = cdv_intel_lvds_restore, - .detect = cdv_intel_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = cdv_intel_lvds_set_property, .destroy = cdv_intel_lvds_destroy, }; - -static void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { - .destroy = cdv_intel_lvds_enc_destroy, -}; - /* * Enumerate the child dev array parsed from VBT to check whether * the LVDS is present. @@ -562,7 +427,7 @@ static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { static bool lvds_is_present_in_vbt(struct drm_device *dev, u8 *i2c_pin) { - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); int i; if (!dev_priv->child_dev_num) @@ -605,6 +470,7 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, /** * cdv_intel_lvds_init - setup LVDS connectors on this device * @dev: drm device + * @mode_dev: PSB mode device * * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present). @@ -612,56 +478,71 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, void cdv_intel_lvds_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { - struct psb_intel_encoder *psb_intel_encoder; - struct psb_intel_connector *psb_intel_connector; + struct gma_encoder *gma_encoder; + struct gma_connector *gma_connector; struct cdv_intel_lvds_priv *lvds_priv; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_display_mode *scan; struct drm_crtc *crtc; - struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_psb_private *dev_priv = to_drm_psb_private(dev); + struct gma_i2c_chan *ddc_bus; u32 lvds; int pipe; + int ret; u8 pin; + if (!dev_priv->lvds_enabled_in_vbt) + return; + pin = GMBUS_PORT_PANEL; if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); return; } - psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), + gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); - if (!psb_intel_encoder) + if (!gma_encoder) return; - psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), + gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); - if (!psb_intel_connector) - goto failed_connector; + if (!gma_connector) + goto err_free_encoder; lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); if (!lvds_priv) - goto failed_lvds_priv; - - psb_intel_encoder->dev_priv = lvds_priv; + goto err_free_connector; - connector = &psb_intel_connector->base; - encoder = &psb_intel_encoder->base; + gma_encoder->dev_priv = lvds_priv; + connector = &gma_connector->base; + gma_connector->save = cdv_intel_lvds_save; + gma_connector->restore = cdv_intel_lvds_restore; + encoder = &gma_encoder->base; - drm_connector_init(dev, connector, - &cdv_intel_lvds_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + /* Set up the DDC bus. */ + ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!ddc_bus) { + dev_printk(KERN_ERR, dev->dev, + "DDC bus registration " "failed.\n"); + goto err_free_lvds_priv; + } - drm_encoder_init(dev, encoder, - &cdv_intel_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS); + ret = drm_connector_init_with_ddc(dev, connector, + &cdv_intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS, + &ddc_bus->base); + if (ret) + goto err_destroy_ddc; + ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); + if (ret) + goto err_connector_cleanup; - psb_intel_connector_attach_encoder(psb_intel_connector, - psb_intel_encoder); - psb_intel_encoder->type = INTEL_OUTPUT_LVDS; + gma_connector_attach_encoder(gma_connector, gma_encoder); + gma_encoder->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs); drm_connector_helper_add(connector, @@ -682,16 +563,14 @@ void cdv_intel_lvds_init(struct drm_device *dev, * Set up I2C bus * FIXME: distroy i2c_bus when exit */ - psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, - GPIOB, - "LVDSBLC_B"); - if (!psb_intel_encoder->i2c_bus) { + gma_encoder->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); + if (!gma_encoder->i2c_bus) { dev_printk(KERN_ERR, - &dev->pdev->dev, "I2C bus registration failed.\n"); - goto failed_blc_i2c; + dev->dev, "I2C bus registration failed.\n"); + goto err_encoder_cleanup; } - psb_intel_encoder->i2c_bus->slave_addr = 0x2C; - dev_priv->lvds_i2c_bus = psb_intel_encoder->i2c_bus; + gma_encoder->i2c_bus->target_addr = 0x2C; + dev_priv->lvds_i2c_bus = gma_encoder->i2c_bus; /* * LVDS discovery: @@ -703,22 +582,13 @@ void cdv_intel_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ - /* Set up the DDC bus. */ - psb_intel_encoder->ddc_bus = psb_intel_i2c_create(dev, - GPIOC, - "LVDSDDC_C"); - if (!psb_intel_encoder->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, - "DDC bus registration " "failed.\n"); - goto failed_ddc; - } - /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - psb_intel_ddc_get_modes(connector, - &psb_intel_encoder->ddc_bus->adapter); + mutex_lock(&dev->mode_config.mutex); + psb_intel_ddc_get_modes(connector, &ddc_bus->base); + list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { mode_dev->panel_fixed_mode = @@ -760,7 +630,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, if (!mode_dev->panel_fixed_mode) { DRM_DEBUG ("Found no modes on the lvds, ignoring the LVDS\n"); - goto failed_find; + goto err_unlock; } /* setup PWM */ @@ -777,24 +647,22 @@ void cdv_intel_lvds_init(struct drm_device *dev, } out: - drm_sysfs_connector_add(connector); + mutex_unlock(&dev->mode_config.mutex); return; -failed_find: - printk(KERN_ERR "Failed find\n"); - if (psb_intel_encoder->ddc_bus) - psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); -failed_ddc: - printk(KERN_ERR "Failed DDC\n"); - if (psb_intel_encoder->i2c_bus) - psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); -failed_blc_i2c: - printk(KERN_ERR "Failed BLC\n"); +err_unlock: + mutex_unlock(&dev->mode_config.mutex); + gma_i2c_destroy(gma_encoder->i2c_bus); +err_encoder_cleanup: drm_encoder_cleanup(encoder); +err_connector_cleanup: drm_connector_cleanup(connector); +err_destroy_ddc: + gma_i2c_destroy(ddc_bus); +err_free_lvds_priv: kfree(lvds_priv); -failed_lvds_priv: - kfree(psb_intel_connector); -failed_connector: - kfree(psb_intel_encoder); +err_free_connector: + kfree(gma_connector); +err_free_encoder: + kfree(gma_encoder); } |
