diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dsi_vbt.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 445 |
1 files changed, 361 insertions, 84 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index e5b178660408..dd24aef925f2 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -25,22 +25,28 @@ */ #include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/mfd/intel_soc_pmic.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> #include <linux/slab.h> +#include <linux/string_helpers.h> -#include <asm/intel-mid.h> #include <asm/unaligned.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> -#include <drm/i915_drm.h> #include <video/mipi_display.h> #include "i915_drv.h" -#include "intel_drv.h" +#include "i915_reg.h" +#include "intel_display_types.h" #include "intel_dsi.h" -#include "intel_sideband.h" +#include "intel_dsi_vbt.h" +#include "vlv_dsi.h" +#include "vlv_dsi_regs.h" +#include "vlv_sideband.h" #define MIPI_TRANSFER_MODE_SHIFT 0 #define MIPI_VIRTUAL_CHANNEL_SHIFT 1 @@ -83,6 +89,12 @@ static struct gpio_map vlv_gpio_table[] = { { VLV_GPIO_NC_11_PANEL1_BKLTCTL }, }; +struct i2c_adapter_lookup { + u16 slave_addr; + struct intel_dsi *intel_dsi; + acpi_handle dev_handle; +}; + #define CHV_GPIO_IDX_START_N 0 #define CHV_GPIO_IDX_START_E 73 #define CHV_GPIO_IDX_START_SW 100 @@ -113,9 +125,25 @@ static struct gpio_map vlv_gpio_table[] = { #define ICL_GPIO_DDPA_CTRLCLK_2 8 #define ICL_GPIO_DDPA_CTRLDATA_2 9 -static inline enum port intel_dsi_seq_port_to_port(u8 port) +static enum port intel_dsi_seq_port_to_port(struct intel_dsi *intel_dsi, + u8 seq_port) { - return port ? PORT_C : PORT_A; + /* + * If single link DSI is being used on any port, the VBT sequence block + * send packet apparently always has 0 for the port. Just use the port + * we have configured, and ignore the sequence block port. + */ + if (hweight8(intel_dsi->ports) == 1) + return ffs(intel_dsi->ports) - 1; + + if (seq_port) { + if (intel_dsi->ports & PORT_B) + return PORT_B; + else if (intel_dsi->ports & PORT_C) + return PORT_C; + } + + return PORT_A; } static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, @@ -127,7 +155,7 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u16 len; enum port port; - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(&dev_priv->drm, "\n"); flags = *data++; type = *data++; @@ -137,19 +165,15 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, seq_port = (flags >> MIPI_PORT_SHIFT) & 3; - /* For DSI single link on Port A & C, the seq_port value which is - * parsed from Sequence Block#53 of VBT has been set to 0 - * Now, read/write of packets for the DSI single link on Port A and - * Port C will based on the DVO port from VBT block 2. - */ - if (intel_dsi->ports == (1 << PORT_C)) - port = PORT_C; - else - port = intel_dsi_seq_port_to_port(seq_port); + port = intel_dsi_seq_port_to_port(intel_dsi, seq_port); + + if (drm_WARN_ON(&dev_priv->drm, !intel_dsi->dsi_hosts[port])) + goto out; dsi_device = intel_dsi->dsi_hosts[port]->device; if (!dsi_device) { - DRM_DEBUG_KMS("no dsi device for port %c\n", port_name(port)); + drm_dbg_kms(&dev_priv->drm, "no dsi device for port %c\n", + port_name(port)); goto out; } @@ -173,7 +197,8 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: - DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n"); + drm_dbg(&dev_priv->drm, + "Generic Read not yet implemented or used\n"); break; case MIPI_DSI_GENERIC_LONG_WRITE: mipi_dsi_generic_write(dsi_device, data, len); @@ -185,14 +210,15 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, mipi_dsi_dcs_write_buffer(dsi_device, data, 2); break; case MIPI_DSI_DCS_READ: - DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n"); + drm_dbg(&dev_priv->drm, + "DCS Read not yet implemented or used\n"); break; case MIPI_DSI_DCS_LONG_WRITE: mipi_dsi_dcs_write_buffer(dsi_device, data, len); break; } - if (INTEL_GEN(dev_priv) < 11) + if (DISPLAY_VER(dev_priv) < 11) vlv_dsi_wait_for_fifo_empty(intel_dsi, port); out: @@ -203,9 +229,10 @@ out: static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) { + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); u32 delay = *((const u32 *) data); - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(&i915->drm, "\n"); usleep_range(delay, delay + 10); data += 4; @@ -222,7 +249,8 @@ static void vlv_exec_gpio(struct drm_i915_private *dev_priv, u8 port; if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) { - DRM_DEBUG_KMS("unknown gpio index %u\n", gpio_index); + drm_dbg_kms(&dev_priv->drm, "unknown gpio index %u\n", + gpio_index); return; } @@ -235,10 +263,11 @@ static void vlv_exec_gpio(struct drm_i915_private *dev_priv, if (gpio_source == 0) { port = IOSF_PORT_GPIO_NC; } else if (gpio_source == 1) { - DRM_DEBUG_KMS("SC gpio not supported\n"); + drm_dbg_kms(&dev_priv->drm, "SC gpio not supported\n"); return; } else { - DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source); + drm_dbg_kms(&dev_priv->drm, + "unknown gpio source %u\n", gpio_source); return; } } @@ -282,13 +311,15 @@ static void chv_exec_gpio(struct drm_i915_private *dev_priv, } else { /* XXX: The spec is unclear about CHV GPIO on seq v2 */ if (gpio_source != 0) { - DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source); + drm_dbg_kms(&dev_priv->drm, + "unknown gpio source %u\n", gpio_source); return; } if (gpio_index >= CHV_GPIO_IDX_START_E) { - DRM_DEBUG_KMS("invalid gpio index %u for GPIO N\n", - gpio_index); + drm_dbg_kms(&dev_priv->drm, + "invalid gpio index %u for GPIO N\n", + gpio_index); return; } @@ -323,8 +354,9 @@ static void bxt_exec_gpio(struct drm_i915_private *dev_priv, GPIOD_OUT_HIGH); if (IS_ERR_OR_NULL(gpio_desc)) { - DRM_ERROR("GPIO index %u request failed (%ld)\n", - gpio_index, PTR_ERR(gpio_desc)); + drm_err(&dev_priv->drm, + "GPIO index %u request failed (%ld)\n", + gpio_index, PTR_ERR(gpio_desc)); return; } @@ -337,7 +369,7 @@ static void bxt_exec_gpio(struct drm_i915_private *dev_priv, static void icl_exec_gpio(struct drm_i915_private *dev_priv, u8 gpio_source, u8 gpio_index, bool value) { - DRM_DEBUG_KMS("Skipping ICL GPIO element execution\n"); + drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n"); } static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) @@ -347,7 +379,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) u8 gpio_source, gpio_index = 0, gpio_number; bool value; - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(&dev_priv->drm, "\n"); if (dev_priv->vbt.dsi.seq_version >= 3) gpio_index = *data++; @@ -363,7 +395,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) /* pull up/down */ value = *data++ & 1; - if (INTEL_GEN(dev_priv) >= 11) + if (DISPLAY_VER(dev_priv) >= 11) icl_exec_gpio(dev_priv, gpio_source, gpio_index, value); else if (IS_VALLEYVIEW(dev_priv)) vlv_exec_gpio(dev_priv, gpio_source, gpio_number, value); @@ -375,22 +407,117 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) return data; } +#ifdef CONFIG_ACPI +static int i2c_adapter_lookup(struct acpi_resource *ares, void *data) +{ + struct i2c_adapter_lookup *lookup = data; + struct intel_dsi *intel_dsi = lookup->intel_dsi; + struct acpi_resource_i2c_serialbus *sb; + struct i2c_adapter *adapter; + acpi_handle adapter_handle; + acpi_status status; + + if (!i2c_acpi_get_i2c_resource(ares, &sb)) + return 1; + + if (lookup->slave_addr != sb->slave_address) + return 1; + + status = acpi_get_handle(lookup->dev_handle, + sb->resource_source.string_ptr, + &adapter_handle); + if (ACPI_FAILURE(status)) + return 1; + + adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); + if (adapter) + intel_dsi->i2c_bus_num = adapter->nr; + + return 1; +} + +static void i2c_acpi_find_adapter(struct intel_dsi *intel_dsi, + const u16 slave_addr) +{ + struct drm_device *drm_dev = intel_dsi->base.base.dev; + struct acpi_device *adev = ACPI_COMPANION(drm_dev->dev); + struct i2c_adapter_lookup lookup = { + .slave_addr = slave_addr, + .intel_dsi = intel_dsi, + .dev_handle = acpi_device_handle(adev), + }; + LIST_HEAD(resource_list); + + acpi_dev_get_resources(adev, &resource_list, i2c_adapter_lookup, &lookup); + acpi_dev_free_resource_list(&resource_list); +} +#else +static inline void i2c_acpi_find_adapter(struct intel_dsi *intel_dsi, + const u16 slave_addr) +{ +} +#endif + static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data) { - DRM_DEBUG_KMS("Skipping I2C element execution\n"); + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); + struct i2c_adapter *adapter; + struct i2c_msg msg; + int ret; + u8 vbt_i2c_bus_num = *(data + 2); + u16 slave_addr = *(u16 *)(data + 3); + u8 reg_offset = *(data + 5); + u8 payload_size = *(data + 6); + u8 *payload_data; + + if (intel_dsi->i2c_bus_num < 0) { + intel_dsi->i2c_bus_num = vbt_i2c_bus_num; + i2c_acpi_find_adapter(intel_dsi, slave_addr); + } + + adapter = i2c_get_adapter(intel_dsi->i2c_bus_num); + if (!adapter) { + drm_err(&i915->drm, "Cannot find a valid i2c bus for xfer\n"); + goto err_bus; + } - return data + *(data + 6) + 7; + payload_data = kzalloc(payload_size + 1, GFP_KERNEL); + if (!payload_data) + goto err_alloc; + + payload_data[0] = reg_offset; + memcpy(&payload_data[1], (data + 7), payload_size); + + msg.addr = slave_addr; + msg.flags = 0; + msg.len = payload_size + 1; + msg.buf = payload_data; + + ret = i2c_transfer(adapter, &msg, 1); + if (ret < 0) + drm_err(&i915->drm, + "Failed to xfer payload of size (%u) to reg (%u)\n", + payload_size, reg_offset); + + kfree(payload_data); +err_alloc: + i2c_put_adapter(adapter); +err_bus: + return data + payload_size + 7; } static const u8 *mipi_exec_spi(struct intel_dsi *intel_dsi, const u8 *data) { - DRM_DEBUG_KMS("Skipping SPI element execution\n"); + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); + + drm_dbg_kms(&i915->drm, "Skipping SPI element execution\n"); return data + *(data + 5) + 6; } static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data) { + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); #ifdef CONFIG_PMIC_OPREGION u32 value, mask, reg_address; u16 i2c_address; @@ -406,9 +533,10 @@ static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data) reg_address, value, mask); if (ret) - DRM_ERROR("%s failed, error: %d\n", __func__, ret); + drm_err(&i915->drm, "%s failed, error: %d\n", __func__, ret); #else - DRM_ERROR("Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n"); + drm_err(&i915->drm, + "Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n"); #endif return data + 15; @@ -453,24 +581,25 @@ static const char *sequence_name(enum mipi_seq seq_id) return "(unknown)"; } -void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, - enum mipi_seq seq_id) +static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, + enum mipi_seq seq_id) { struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); const u8 *data; fn_mipi_elem_exec mipi_elem_exec; - if (WARN_ON(seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence))) + if (drm_WARN_ON(&dev_priv->drm, + seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence))) return; data = dev_priv->vbt.dsi.sequence[seq_id]; if (!data) return; - WARN_ON(*data != seq_id); + drm_WARN_ON(&dev_priv->drm, *data != seq_id); - DRM_DEBUG_KMS("Starting MIPI sequence %d - %s\n", - seq_id, sequence_name(seq_id)); + drm_dbg_kms(&dev_priv->drm, "Starting MIPI sequence %d - %s\n", + seq_id, sequence_name(seq_id)); /* Skip Sequence Byte. */ data++; @@ -502,23 +631,42 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, /* Consistency check if we have size. */ if (operation_size && data != next) { - DRM_ERROR("Inconsistent operation size\n"); + drm_err(&dev_priv->drm, + "Inconsistent operation size\n"); return; } } else if (operation_size) { /* We have size, skip. */ - DRM_DEBUG_KMS("Unsupported MIPI operation byte %u\n", - operation_byte); + drm_dbg_kms(&dev_priv->drm, + "Unsupported MIPI operation byte %u\n", + operation_byte); data += operation_size; } else { /* No size, can't skip without parsing. */ - DRM_ERROR("Unsupported MIPI operation byte %u\n", - operation_byte); + drm_err(&dev_priv->drm, + "Unsupported MIPI operation byte %u\n", + operation_byte); return; } } } +void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, + enum mipi_seq seq_id) +{ + if (seq_id == MIPI_SEQ_POWER_ON && intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); + if (seq_id == MIPI_SEQ_BACKLIGHT_ON && intel_dsi->gpio_backlight) + gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 1); + + intel_dsi_vbt_exec(intel_dsi, seq_id); + + if (seq_id == MIPI_SEQ_POWER_OFF && intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0); + if (seq_id == MIPI_SEQ_BACKLIGHT_OFF && intel_dsi->gpio_backlight) + gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 0); +} + void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) { struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); @@ -532,40 +680,54 @@ void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) void intel_dsi_log_params(struct intel_dsi *intel_dsi) { - DRM_DEBUG_KMS("Pclk %d\n", intel_dsi->pclk); - DRM_DEBUG_KMS("Pixel overlap %d\n", intel_dsi->pixel_overlap); - DRM_DEBUG_KMS("Lane count %d\n", intel_dsi->lane_count); - DRM_DEBUG_KMS("DPHY param reg 0x%x\n", intel_dsi->dphy_reg); - DRM_DEBUG_KMS("Video mode format %s\n", - intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE ? - "non-burst with sync pulse" : - intel_dsi->video_mode_format == VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS ? - "non-burst with sync events" : - intel_dsi->video_mode_format == VIDEO_MODE_BURST ? - "burst" : "<unknown>"); - DRM_DEBUG_KMS("Burst mode ratio %d\n", intel_dsi->burst_mode_ratio); - DRM_DEBUG_KMS("Reset timer %d\n", intel_dsi->rst_timer_val); - DRM_DEBUG_KMS("Eot %s\n", enableddisabled(intel_dsi->eotp_pkt)); - DRM_DEBUG_KMS("Clockstop %s\n", enableddisabled(!intel_dsi->clock_stop)); - DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video"); + struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev); + + drm_dbg_kms(&i915->drm, "Pclk %d\n", intel_dsi->pclk); + drm_dbg_kms(&i915->drm, "Pixel overlap %d\n", + intel_dsi->pixel_overlap); + drm_dbg_kms(&i915->drm, "Lane count %d\n", intel_dsi->lane_count); + drm_dbg_kms(&i915->drm, "DPHY param reg 0x%x\n", intel_dsi->dphy_reg); + drm_dbg_kms(&i915->drm, "Video mode format %s\n", + intel_dsi->video_mode == NON_BURST_SYNC_PULSE ? + "non-burst with sync pulse" : + intel_dsi->video_mode == NON_BURST_SYNC_EVENTS ? + "non-burst with sync events" : + intel_dsi->video_mode == BURST_MODE ? + "burst" : "<unknown>"); + drm_dbg_kms(&i915->drm, "Burst mode ratio %d\n", + intel_dsi->burst_mode_ratio); + drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val); + drm_dbg_kms(&i915->drm, "Eot %s\n", + str_enabled_disabled(intel_dsi->eotp_pkt)); + drm_dbg_kms(&i915->drm, "Clockstop %s\n", + str_enabled_disabled(!intel_dsi->clock_stop)); + drm_dbg_kms(&i915->drm, "Mode %s\n", + intel_dsi->operation_mode ? "command" : "video"); if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) - DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n"); + drm_dbg_kms(&i915->drm, + "Dual link: DSI_DUAL_LINK_FRONT_BACK\n"); else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT) - DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n"); + drm_dbg_kms(&i915->drm, + "Dual link: DSI_DUAL_LINK_PIXEL_ALT\n"); else - DRM_DEBUG_KMS("Dual link: NONE\n"); - DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format); - DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div); - DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout); - DRM_DEBUG_KMS("Turnaround Timeout 0x%x\n", intel_dsi->turn_arnd_val); - DRM_DEBUG_KMS("Init Count 0x%x\n", intel_dsi->init_count); - DRM_DEBUG_KMS("HS to LP Count 0x%x\n", intel_dsi->hs_to_lp_count); - DRM_DEBUG_KMS("LP Byte Clock %d\n", intel_dsi->lp_byte_clk); - DRM_DEBUG_KMS("DBI BW Timer 0x%x\n", intel_dsi->bw_timer); - DRM_DEBUG_KMS("LP to HS Clock Count 0x%x\n", intel_dsi->clk_lp_to_hs_count); - DRM_DEBUG_KMS("HS to LP Clock Count 0x%x\n", intel_dsi->clk_hs_to_lp_count); - DRM_DEBUG_KMS("BTA %s\n", - enableddisabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA))); + drm_dbg_kms(&i915->drm, "Dual link: NONE\n"); + drm_dbg_kms(&i915->drm, "Pixel Format %d\n", intel_dsi->pixel_format); + drm_dbg_kms(&i915->drm, "TLPX %d\n", intel_dsi->escape_clk_div); + drm_dbg_kms(&i915->drm, "LP RX Timeout 0x%x\n", + intel_dsi->lp_rx_timeout); + drm_dbg_kms(&i915->drm, "Turnaround Timeout 0x%x\n", + intel_dsi->turn_arnd_val); + drm_dbg_kms(&i915->drm, "Init Count 0x%x\n", intel_dsi->init_count); + drm_dbg_kms(&i915->drm, "HS to LP Count 0x%x\n", + intel_dsi->hs_to_lp_count); + drm_dbg_kms(&i915->drm, "LP Byte Clock %d\n", intel_dsi->lp_byte_clk); + drm_dbg_kms(&i915->drm, "DBI BW Timer 0x%x\n", intel_dsi->bw_timer); + drm_dbg_kms(&i915->drm, "LP to HS Clock Count 0x%x\n", + intel_dsi->clk_lp_to_hs_count); + drm_dbg_kms(&i915->drm, "HS to LP Clock Count 0x%x\n", + intel_dsi->clk_hs_to_lp_count); + drm_dbg_kms(&i915->drm, "BTA %s\n", + str_enabled_disabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA))); } bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) @@ -578,7 +740,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) u16 burst_mode_ratio; enum port port; - DRM_DEBUG_KMS("\n"); + drm_dbg_kms(&dev_priv->drm, "\n"); intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1; intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0; @@ -590,7 +752,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->dual_link = mipi_config->dual_link; intel_dsi->pixel_overlap = mipi_config->pixel_overlap; intel_dsi->operation_mode = mipi_config->is_cmd_mode; - intel_dsi->video_mode_format = mipi_config->video_transfer_mode; + intel_dsi->video_mode = mipi_config->video_transfer_mode; intel_dsi->escape_clk_div = mipi_config->byte_clk_sel; intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout; intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout; @@ -621,7 +783,7 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) * Target ddr frequency from VBT / non burst ddr freq * multiply by 100 to preserve remainder */ - if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) { + if (intel_dsi->video_mode == BURST_MODE) { if (mipi_config->target_burst_mode_freq) { u32 bitrate = intel_dsi_bitrate(intel_dsi); @@ -637,7 +799,8 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) mipi_config->target_burst_mode_freq = bitrate; if (mipi_config->target_burst_mode_freq < bitrate) { - DRM_ERROR("Burst mode freq is less than computed\n"); + drm_err(&dev_priv->drm, + "Burst mode freq is less than computed\n"); return false; } @@ -647,7 +810,8 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100); } else { - DRM_ERROR("Burst mode target is not set\n"); + drm_err(&dev_priv->drm, + "Burst mode target is not set\n"); return false; } } else @@ -664,6 +828,8 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) intel_dsi->panel_off_delay = pps->panel_off_delay / 10; intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10; + intel_dsi->i2c_bus_num = -1; + /* a regular driver would get the device in probe */ for_each_dsi_port(port, intel_dsi->ports) { mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device); @@ -671,3 +837,114 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) return true; } + +/* + * On some BYT/CHT devs some sequences are incomplete and we need to manually + * control some GPIOs. We need to add a GPIO lookup table before we get these. + * If the GOP did not initialize the panel (HDMI inserted) we may need to also + * change the pinmux for the SoC's PWM0 pin from GPIO to PWM. + */ +static struct gpiod_lookup_table pmic_panel_gpio_table = { + /* Intel GFX is consumer */ + .dev_id = "0000:00:02.0", + .table = { + /* Panel EN/DISABLE */ + GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table soc_panel_gpio_table = { + .dev_id = "0000:00:02.0", + .table = { + GPIO_LOOKUP("INT33FC:01", 10, "backlight", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("INT33FC:01", 11, "panel", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static const struct pinctrl_map soc_pwm_pinctrl_map[] = { + PIN_MAP_MUX_GROUP("0000:00:02.0", "soc_pwm0", "INT33FC:00", + "pwm0_grp", "pwm"), +}; + +void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) +{ + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; + enum gpiod_flags flags = panel_is_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + bool want_backlight_gpio = false; + bool want_panel_gpio = false; + struct pinctrl *pinctrl; + int ret; + + if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + mipi_config->pwm_blc == PPS_BLC_PMIC) { + gpiod_add_lookup_table(&pmic_panel_gpio_table); + want_panel_gpio = true; + } + + if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { + gpiod_add_lookup_table(&soc_panel_gpio_table); + want_panel_gpio = true; + want_backlight_gpio = true; + + /* Ensure PWM0 pin is muxed as PWM instead of GPIO */ + ret = pinctrl_register_mappings(soc_pwm_pinctrl_map, + ARRAY_SIZE(soc_pwm_pinctrl_map)); + if (ret) + drm_err(&dev_priv->drm, + "Failed to register pwm0 pinmux mapping\n"); + + pinctrl = devm_pinctrl_get_select(dev->dev, "soc_pwm0"); + if (IS_ERR(pinctrl)) + drm_err(&dev_priv->drm, + "Failed to set pinmux to PWM\n"); + } + + if (want_panel_gpio) { + intel_dsi->gpio_panel = gpiod_get(dev->dev, "panel", flags); + if (IS_ERR(intel_dsi->gpio_panel)) { + drm_err(&dev_priv->drm, + "Failed to own gpio for panel control\n"); + intel_dsi->gpio_panel = NULL; + } + } + + if (want_backlight_gpio) { + intel_dsi->gpio_backlight = + gpiod_get(dev->dev, "backlight", flags); + if (IS_ERR(intel_dsi->gpio_backlight)) { + drm_err(&dev_priv->drm, + "Failed to own gpio for backlight control\n"); + intel_dsi->gpio_backlight = NULL; + } + } +} + +void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) +{ + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; + + if (intel_dsi->gpio_panel) { + gpiod_put(intel_dsi->gpio_panel); + intel_dsi->gpio_panel = NULL; + } + + if (intel_dsi->gpio_backlight) { + gpiod_put(intel_dsi->gpio_backlight); + intel_dsi->gpio_backlight = NULL; + } + + if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + mipi_config->pwm_blc == PPS_BLC_PMIC) + gpiod_remove_lookup_table(&pmic_panel_gpio_table); + + if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { + pinctrl_unregister_mappings(soc_pwm_pinctrl_map); + gpiod_remove_lookup_table(&soc_panel_gpio_table); + } +} |