From fc45e821990781c13dba10e3aef1c9f11af8af08 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:09 +0530 Subject: drm/i915: Use the CRC gpio for panel enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CRC (Crystal Cove) PMIC, controls the panel enable and disable signals for BYT for dsi panels. This is indicated in the VBT fields. Use that to initialize and use GPIO based control for these signals. v2: Use the newer gpiod interface(Alexandre) v3: Remove the redundant checks and unused code (Ville) v4: Moved PWM vs SoC backlight #defines to intel_bios.h (Jani) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Linus Walleij Reviewed-by: Jani Nikula Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.h | 7 +++++++ drivers/gpu/drm/i915/intel_dsi.c | 32 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dsi.h | 3 +++ 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index af0b47652752..f7ad6a585129 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -778,6 +778,13 @@ int intel_parse_bios(struct drm_device *dev); #define MIPI_DSI_UNDEFINED_PANEL_ID 0 #define MIPI_DSI_GENERIC_PANEL_ID 1 +/* + * PMIC vs SoC Backlight support specified in pwm_blc + * field in mipi_config block below. +*/ +#define PPS_BLC_PMIC 0 +#define PPS_BLC_SOC 1 + struct mipi_config { u16 panel_id; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b5a5558ecd63..c4db74a5e4e7 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "i915_drv.h" #include "intel_drv.h" #include "intel_dsi.h" @@ -415,6 +416,12 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + /* Panel Enable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); + + msleep(intel_dsi->panel_on_delay); + /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); @@ -432,8 +439,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* put device in ready state */ intel_dsi_device_ready(encoder); - msleep(intel_dsi->panel_on_delay); - drm_panel_prepare(intel_dsi->panel); for_each_dsi_port(port, intel_dsi->ports) @@ -576,6 +581,10 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder) msleep(intel_dsi->panel_off_delay); msleep(intel_dsi->panel_pwr_cycle_delay); + + /* Panel Disable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0); } static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, @@ -955,6 +964,11 @@ static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) /* XXX: Logically this call belongs in the panel driver. */ drm_panel_remove(intel_dsi->panel); } + + /* dispose of the gpios */ + if (intel_dsi->gpio_panel) + gpiod_put(intel_dsi->gpio_panel); + intel_encoder_destroy(encoder); } @@ -1071,6 +1085,20 @@ void intel_dsi_init(struct drm_device *dev) goto err; } + /* + * In case of BYT with CRC PMIC, we need to use GPIO for + * Panel control. + */ + if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { + intel_dsi->gpio_panel = + gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH); + + if (IS_ERR(intel_dsi->gpio_panel)) { + DRM_ERROR("Failed to own gpio for panel control\n"); + intel_dsi->gpio_panel = NULL; + } + } + intel_encoder->type = INTEL_OUTPUT_DSI; intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dsi_connector_funcs, diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 2784ac442368..42a68593e32a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -42,6 +42,9 @@ struct intel_dsi { struct drm_panel *panel; struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS]; + /* GPIO Desc for CRC based Panel control */ + struct gpio_desc *gpio_panel; + struct intel_connector *attached_connector; /* bit mask of ports being driven */ -- cgit v1.2.1 From b029e66fa8e39ba10dcc47b114be8da8b082493b Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:10 +0530 Subject: drm/i915: Backlight control using CRC PMIC based PWM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the CRC PWM device in intel_panel.c and add new MIPI backlight specififc callbacks v2: Modify to use pwm_config callback v3: Addressed Jani's comments - Renamed all function as pwm_* instead of vlv_* - Call intel_panel_actually_set_backlight in enable function - Return -ENODEV in case pwm_get fails - in case pwm_config error return error cdoe from pwm_config - Cleanup pwm in intel_panel_destroy_backlight v4: Removed unused #defines and initialized backlight with INVALID_PIPE (Ville) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 4 ++ drivers/gpu/drm/i915/intel_dsi.c | 5 ++ drivers/gpu/drm/i915/intel_panel.c | 94 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 105928382e21..286127001c43 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -182,6 +182,10 @@ struct intel_panel { bool enabled; bool combination_mode; /* gen 2/4 only */ bool active_low_pwm; + + /* PWM chip */ + struct pwm_device *pwm; + struct backlight_device *device; } backlight; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index c4db74a5e4e7..892b936e14d4 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -402,6 +402,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) intel_dsi_port_enable(encoder); } + + intel_panel_enable_backlight(intel_dsi->attached_connector); } static void intel_dsi_pre_enable(struct intel_encoder *encoder) @@ -466,6 +468,8 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + intel_panel_disable_backlight(intel_dsi->attached_connector); + if (is_vid_mode(intel_dsi)) { /* Send Shutdown command to the panel in LP mode */ for_each_dsi_port(port, intel_dsi->ports) @@ -1132,6 +1136,7 @@ void intel_dsi_init(struct drm_device *dev) } intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_setup_backlight(connector, INVALID_PIPE); return; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 55aad2322e10..e2ab3f6ed022 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -32,8 +32,11 @@ #include #include +#include #include "intel_drv.h" +#define CRC_PMIC_PWM_PERIOD_NS 21333 + void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -544,6 +547,15 @@ static u32 bxt_get_backlight(struct intel_connector *connector) return I915_READ(BXT_BLC_PWM_DUTY1); } +static u32 pwm_get_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns; + + duty_ns = pwm_get_duty_cycle(panel->backlight.pwm); + return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); +} + static u32 intel_panel_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -632,6 +644,14 @@ static void bxt_set_backlight(struct intel_connector *connector, u32 level) I915_WRITE(BXT_BLC_PWM_DUTY1, level); } +static void pwm_set_backlight(struct intel_connector *connector, u32 level) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100); + + pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); +} + static void intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) { @@ -769,6 +789,16 @@ static void bxt_disable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE); } +static void pwm_disable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + /* Disable the backlight */ + pwm_config(panel->backlight.pwm, 0, CRC_PMIC_PWM_PERIOD_NS); + usleep_range(2000, 3000); + pwm_disable(panel->backlight.pwm); +} + void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1010,6 +1040,14 @@ static void bxt_enable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE); } +static void pwm_enable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + pwm_enable(panel->backlight.pwm); + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1386,6 +1424,40 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) return 0; } +static int pwm_setup_backlight(struct intel_connector *connector, + enum pipe pipe) +{ + struct drm_device *dev = connector->base.dev; + struct intel_panel *panel = &connector->panel; + int retval; + + /* Get the PWM chip for backlight control */ + panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight"); + if (IS_ERR(panel->backlight.pwm)) { + DRM_ERROR("Failed to own the pwm chip\n"); + panel->backlight.pwm = NULL; + return -ENODEV; + } + + retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS, + CRC_PMIC_PWM_PERIOD_NS); + if (retval < 0) { + DRM_ERROR("Failed to configure the pwm chip\n"); + pwm_put(panel->backlight.pwm); + panel->backlight.pwm = NULL; + return retval; + } + + panel->backlight.min = 0; /* 0% */ + panel->backlight.max = 100; /* 100% */ + panel->backlight.level = DIV_ROUND_UP( + pwm_get_duty_cycle(panel->backlight.pwm) * 100, + CRC_PMIC_PWM_PERIOD_NS); + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) { struct drm_device *dev = connector->dev; @@ -1429,6 +1501,10 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_panel *panel = &intel_connector->panel; + /* dispose of the pwm */ + if (panel->backlight.pwm) + pwm_put(panel->backlight.pwm); + panel->backlight.present = false; } @@ -1456,11 +1532,19 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) dev_priv->display.set_backlight = pch_set_backlight; dev_priv->display.get_backlight = pch_get_backlight; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.setup_backlight = vlv_setup_backlight; - dev_priv->display.enable_backlight = vlv_enable_backlight; - dev_priv->display.disable_backlight = vlv_disable_backlight; - dev_priv->display.set_backlight = vlv_set_backlight; - dev_priv->display.get_backlight = vlv_get_backlight; + if (dev_priv->vbt.has_mipi) { + dev_priv->display.setup_backlight = pwm_setup_backlight; + dev_priv->display.enable_backlight = pwm_enable_backlight; + dev_priv->display.disable_backlight = pwm_disable_backlight; + dev_priv->display.set_backlight = pwm_set_backlight; + dev_priv->display.get_backlight = pwm_get_backlight; + } else { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + } } else if (IS_GEN4(dev)) { dev_priv->display.setup_backlight = i965_setup_backlight; dev_priv->display.enable_backlight = i965_enable_backlight; -- cgit v1.2.1