drm/i915: Hook up pfit for DSI
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_dsi_panel_vbt.c
index e8113ad6547782ff5836839f1354a860aea5e464..e498f1c3221e368a5d2d53b20c609b7633baa744 100644 (file)
@@ -58,50 +58,41 @@ static inline struct vbt_panel *to_vbt_panel(struct drm_panel *panel)
 
 #define NS_KHZ_RATIO 1000000
 
-#define GPI0_NC_0_HV_DDI0_HPD           0x4130
-#define GPIO_NC_0_HV_DDI0_PAD           0x4138
-#define GPIO_NC_1_HV_DDI0_DDC_SDA       0x4120
-#define GPIO_NC_1_HV_DDI0_DDC_SDA_PAD   0x4128
-#define GPIO_NC_2_HV_DDI0_DDC_SCL       0x4110
-#define GPIO_NC_2_HV_DDI0_DDC_SCL_PAD   0x4118
-#define GPIO_NC_3_PANEL0_VDDEN          0x4140
-#define GPIO_NC_3_PANEL0_VDDEN_PAD      0x4148
-#define GPIO_NC_4_PANEL0_BLKEN          0x4150
-#define GPIO_NC_4_PANEL0_BLKEN_PAD      0x4158
-#define GPIO_NC_5_PANEL0_BLKCTL         0x4160
-#define GPIO_NC_5_PANEL0_BLKCTL_PAD     0x4168
-#define GPIO_NC_6_PCONF0                0x4180
-#define GPIO_NC_6_PAD                   0x4188
-#define GPIO_NC_7_PCONF0                0x4190
-#define GPIO_NC_7_PAD                   0x4198
-#define GPIO_NC_8_PCONF0                0x4170
-#define GPIO_NC_8_PAD                   0x4178
-#define GPIO_NC_9_PCONF0                0x4100
-#define GPIO_NC_9_PAD                   0x4108
-#define GPIO_NC_10_PCONF0               0x40E0
-#define GPIO_NC_10_PAD                  0x40E8
-#define GPIO_NC_11_PCONF0               0x40F0
-#define GPIO_NC_11_PAD                  0x40F8
-
-struct gpio_table {
-       u16 function_reg;
-       u16 pad_reg;
-       u8 init;
+/* base offsets for gpio pads */
+#define VLV_GPIO_NC_0_HV_DDI0_HPD      0x4130
+#define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA  0x4120
+#define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL  0x4110
+#define VLV_GPIO_NC_3_PANEL0_VDDEN     0x4140
+#define VLV_GPIO_NC_4_PANEL0_BKLTEN    0x4150
+#define VLV_GPIO_NC_5_PANEL0_BKLTCTL   0x4160
+#define VLV_GPIO_NC_6_HV_DDI1_HPD      0x4180
+#define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA  0x4190
+#define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL  0x4170
+#define VLV_GPIO_NC_9_PANEL1_VDDEN     0x4100
+#define VLV_GPIO_NC_10_PANEL1_BKLTEN   0x40E0
+#define VLV_GPIO_NC_11_PANEL1_BKLTCTL  0x40F0
+
+#define VLV_GPIO_PCONF0(base_offset)   (base_offset)
+#define VLV_GPIO_PAD_VAL(base_offset)  ((base_offset) + 8)
+
+struct gpio_map {
+       u16 base_offset;
+       bool init;
 };
 
-static struct gpio_table gtable[] = {
-       { GPI0_NC_0_HV_DDI0_HPD, GPIO_NC_0_HV_DDI0_PAD, 0 },
-       { GPIO_NC_1_HV_DDI0_DDC_SDA, GPIO_NC_1_HV_DDI0_DDC_SDA_PAD, 0 },
-       { GPIO_NC_2_HV_DDI0_DDC_SCL, GPIO_NC_2_HV_DDI0_DDC_SCL_PAD, 0 },
-       { GPIO_NC_3_PANEL0_VDDEN, GPIO_NC_3_PANEL0_VDDEN_PAD, 0 },
-       { GPIO_NC_4_PANEL0_BLKEN, GPIO_NC_4_PANEL0_BLKEN_PAD, 0 },
-       { GPIO_NC_5_PANEL0_BLKCTL, GPIO_NC_5_PANEL0_BLKCTL_PAD, 0 },
-       { GPIO_NC_6_PCONF0, GPIO_NC_6_PAD, 0 },
-       { GPIO_NC_7_PCONF0, GPIO_NC_7_PAD, 0 },
-       { GPIO_NC_8_PCONF0, GPIO_NC_8_PAD, 0 },
-       { GPIO_NC_9_PCONF0, GPIO_NC_9_PAD, 0 },
-       { GPIO_NC_10_PCONF0, GPIO_NC_10_PAD, 0},
-       { GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0}
+static struct gpio_map vlv_gpio_table[] = {
+       { VLV_GPIO_NC_0_HV_DDI0_HPD },
+       { VLV_GPIO_NC_1_HV_DDI0_DDC_SDA },
+       { VLV_GPIO_NC_2_HV_DDI0_DDC_SCL },
+       { VLV_GPIO_NC_3_PANEL0_VDDEN },
+       { VLV_GPIO_NC_4_PANEL0_BKLTEN },
+       { VLV_GPIO_NC_5_PANEL0_BKLTCTL },
+       { VLV_GPIO_NC_6_HV_DDI1_HPD },
+       { VLV_GPIO_NC_7_HV_DDI1_DDC_SDA },
+       { VLV_GPIO_NC_8_HV_DDI1_DDC_SCL },
+       { VLV_GPIO_NC_9_PANEL1_VDDEN },
+       { VLV_GPIO_NC_10_PANEL1_BKLTEN },
+       { VLV_GPIO_NC_11_PANEL1_BKLTCTL },
 };
 
 static inline enum port intel_dsi_seq_port_to_port(u8 port)
@@ -196,66 +187,91 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
        return data;
 }
 
-static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
+static void vlv_exec_gpio(struct drm_i915_private *dev_priv,
+                         u8 gpio_source, u8 gpio_index, bool value)
 {
-       u8 gpio, action;
-       u16 function, pad;
-       u32 val;
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->vbt.dsi.seq_version >= 3)
-               data++;
+       struct gpio_map *map;
+       u16 pconf0, padval;
+       u32 tmp;
+       u8 port;
 
-       gpio = *data++;
-
-       /* pull up/down */
-       action = *data++ & 1;
-
-       if (gpio >= ARRAY_SIZE(gtable)) {
-               DRM_DEBUG_KMS("unknown gpio %u\n", gpio);
-               goto out;
+       if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) {
+               DRM_DEBUG_KMS("unknown gpio index %u\n", gpio_index);
+               return;
        }
 
-       if (!IS_VALLEYVIEW(dev_priv)) {
-               DRM_DEBUG_KMS("GPIO element not supported on this platform\n");
-               goto out;
-       }
+       map = &vlv_gpio_table[gpio_index];
 
        if (dev_priv->vbt.dsi.seq_version >= 3) {
                DRM_DEBUG_KMS("GPIO element v3 not supported\n");
-               goto out;
+               return;
+       } else {
+               if (gpio_source == 0) {
+                       port = IOSF_PORT_GPIO_NC;
+               } else if (gpio_source == 1) {
+                       port = IOSF_PORT_GPIO_SC;
+               } else {
+                       DRM_DEBUG_KMS("unknown gpio source %u\n", gpio_source);
+                       return;
+               }
        }
 
-       function = gtable[gpio].function_reg;
-       pad = gtable[gpio].pad_reg;
+       pconf0 = VLV_GPIO_PCONF0(map->base_offset);
+       padval = VLV_GPIO_PAD_VAL(map->base_offset);
 
        mutex_lock(&dev_priv->sb_lock);
-       if (!gtable[gpio].init) {
-               /* program the function */
+       if (!map->init) {
                /* FIXME: remove constant below */
-               vlv_gpio_nc_write(dev_priv, function, 0x2000CC00);
-               gtable[gpio].init = 1;
+               vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00);
+               map->init = true;
        }
 
-       val = 0x4 | action;
+       tmp = 0x4 | value;
+       vlv_iosf_sb_write(dev_priv, port, padval, tmp);
+       mutex_unlock(&dev_priv->sb_lock);
+}
+
+static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       struct drm_device *dev = intel_dsi->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u8 gpio_source, gpio_index;
+       bool value;
+
+       if (dev_priv->vbt.dsi.seq_version >= 3)
+               data++;
+
+       gpio_index = *data++;
+
+       /* gpio source in sequence v2 only */
+       if (dev_priv->vbt.dsi.seq_version == 2)
+               gpio_source = (*data >> 1) & 3;
+       else
+               gpio_source = 0;
 
        /* pull up/down */
-       vlv_gpio_nc_write(dev_priv, pad, val);
-       mutex_unlock(&dev_priv->sb_lock);
+       value = *data++ & 1;
+
+       if (IS_VALLEYVIEW(dev_priv))
+               vlv_exec_gpio(dev_priv, gpio_source, gpio_index, value);
+       else
+               DRM_DEBUG_KMS("GPIO element not supported on this platform\n");
 
-out:
        return data;
 }
 
+static const u8 *mipi_exec_i2c_skip(struct intel_dsi *intel_dsi, const u8 *data)
+{
+       return data + *(data + 6) + 7;
+}
+
 typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
                                        const u8 *data);
 static const fn_mipi_elem_exec exec_elem[] = {
-       NULL, /* reserved */
-       mipi_exec_send_packet,
-       mipi_exec_delay,
-       mipi_exec_gpio,
-       NULL, /* status read; later */
+       [MIPI_SEQ_ELEM_SEND_PKT] = mipi_exec_send_packet,
+       [MIPI_SEQ_ELEM_DELAY] = mipi_exec_delay,
+       [MIPI_SEQ_ELEM_GPIO] = mipi_exec_gpio,
+       [MIPI_SEQ_ELEM_I2C] = mipi_exec_i2c_skip,
 };
 
 /*
@@ -265,107 +281,114 @@ static const fn_mipi_elem_exec exec_elem[] = {
  */
 
 static const char * const seq_name[] = {
-       "UNDEFINED",
-       "MIPI_SEQ_ASSERT_RESET",
-       "MIPI_SEQ_INIT_OTP",
-       "MIPI_SEQ_DISPLAY_ON",
-       "MIPI_SEQ_DISPLAY_OFF",
-       "MIPI_SEQ_DEASSERT_RESET"
+       [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
+       [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
+       [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
+       [MIPI_SEQ_DISPLAY_OFF]  = "MIPI_SEQ_DISPLAY_OFF",
+       [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
+       [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
+       [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
+       [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
+       [MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
+       [MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
+       [MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
 };
 
-static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
+static const char *sequence_name(enum mipi_seq seq_id)
+{
+       if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
+               return seq_name[seq_id];
+       else
+               return "(unknown)";
+}
+
+static void generic_exec_sequence(struct drm_panel *panel, enum mipi_seq seq_id)
 {
+       struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+       struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+       const u8 *data;
        fn_mipi_elem_exec mipi_elem_exec;
-       int index;
 
-       if (!data)
+       if (WARN_ON(seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence)))
                return;
 
-       DRM_DEBUG_DRIVER("Starting MIPI sequence - %s\n", seq_name[*data]);
+       data = dev_priv->vbt.dsi.sequence[seq_id];
+       if (!data) {
+               DRM_DEBUG_KMS("MIPI sequence %d - %s not available\n",
+                             seq_id, sequence_name(seq_id));
+               return;
+       }
 
-       /* go to the first element of the sequence */
-       data++;
+       WARN_ON(*data != seq_id);
 
-       /* parse each byte till we reach end of sequence byte - 0x00 */
-       while (1) {
-               index = *data;
-               mipi_elem_exec = exec_elem[index];
-               if (!mipi_elem_exec) {
-                       DRM_ERROR("Unsupported MIPI element, skipping sequence execution\n");
-                       return;
-               }
+       DRM_DEBUG_KMS("Starting MIPI sequence %d - %s\n",
+                     seq_id, sequence_name(seq_id));
 
-               /* goto element payload */
-               data++;
+       /* Skip Sequence Byte. */
+       data++;
 
-               /* execute the element specific rotines */
-               data = mipi_elem_exec(intel_dsi, data);
+       /* Skip Size of Sequence. */
+       if (dev_priv->vbt.dsi.seq_version >= 3)
+               data += 4;
 
-               /*
-                * After processing the element, data should point to
-                * next element or end of sequence
-                * check if have we reached end of sequence
-                */
-               if (*data == 0x00)
+       while (1) {
+               u8 operation_byte = *data++;
+               u8 operation_size = 0;
+
+               if (operation_byte == MIPI_SEQ_ELEM_END)
                        break;
+
+               if (operation_byte < ARRAY_SIZE(exec_elem))
+                       mipi_elem_exec = exec_elem[operation_byte];
+               else
+                       mipi_elem_exec = NULL;
+
+               /* Size of Operation. */
+               if (dev_priv->vbt.dsi.seq_version >= 3)
+                       operation_size = *data++;
+
+               if (mipi_elem_exec) {
+                       data = mipi_elem_exec(intel_dsi, data);
+               } else if (operation_size) {
+                       /* We have size, skip. */
+                       DRM_DEBUG_KMS("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);
+                       return;
+               }
        }
 }
 
 static int vbt_panel_prepare(struct drm_panel *panel)
 {
-       struct vbt_panel *vbt_panel = to_vbt_panel(panel);
-       struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       const u8 *sequence;
-
-       sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET];
-       generic_exec_sequence(intel_dsi, sequence);
-
-       sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
-       generic_exec_sequence(intel_dsi, sequence);
+       generic_exec_sequence(panel, MIPI_SEQ_ASSERT_RESET);
+       generic_exec_sequence(panel, MIPI_SEQ_INIT_OTP);
 
        return 0;
 }
 
 static int vbt_panel_unprepare(struct drm_panel *panel)
 {
-       struct vbt_panel *vbt_panel = to_vbt_panel(panel);
-       struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       const u8 *sequence;
-
-       sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET];
-       generic_exec_sequence(intel_dsi, sequence);
+       generic_exec_sequence(panel, MIPI_SEQ_DEASSERT_RESET);
 
        return 0;
 }
 
 static int vbt_panel_enable(struct drm_panel *panel)
 {
-       struct vbt_panel *vbt_panel = to_vbt_panel(panel);
-       struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       const u8 *sequence;
-
-       sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON];
-       generic_exec_sequence(intel_dsi, sequence);
+       generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_ON);
 
        return 0;
 }
 
 static int vbt_panel_disable(struct drm_panel *panel)
 {
-       struct vbt_panel *vbt_panel = to_vbt_panel(panel);
-       struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
-       struct drm_device *dev = intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       const u8 *sequence;
-
-       sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_OFF];
-       generic_exec_sequence(intel_dsi, sequence);
+       generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_OFF);
 
        return 0;
 }
@@ -408,7 +431,7 @@ struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
        struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
        struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
        struct vbt_panel *vbt_panel;
-       u32 bits_per_pixel = 24;
+       u32 bpp;
        u32 tlpx_ns, extra_byte_count, bitrate, tlpx_ui;
        u32 ui_num, ui_den;
        u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt;
@@ -424,15 +447,13 @@ struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
        intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
        intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
        intel_dsi->lane_count = mipi_config->lane_cnt + 1;
-       intel_dsi->pixel_format = mipi_config->videomode_color_format << 7;
+       intel_dsi->pixel_format =
+                       pixel_format_from_register_bits(
+                               mipi_config->videomode_color_format << 7);
+       bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+
        intel_dsi->dual_link = mipi_config->dual_link;
        intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
-
-       if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666)
-               bits_per_pixel = 18;
-       else if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB565)
-               bits_per_pixel = 16;
-
        intel_dsi->operation_mode = mipi_config->is_cmd_mode;
        intel_dsi->video_mode_format = mipi_config->video_transfer_mode;
        intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
@@ -466,8 +487,7 @@ struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
         */
        if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
                if (mipi_config->target_burst_mode_freq) {
-                       computed_ddr =
-                               (pclk * bits_per_pixel) / intel_dsi->lane_count;
+                       computed_ddr = (pclk * bpp) / intel_dsi->lane_count;
 
                        if (mipi_config->target_burst_mode_freq <
                                                                computed_ddr) {
@@ -490,7 +510,7 @@ struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
        intel_dsi->burst_mode_ratio = burst_mode_ratio;
        intel_dsi->pclk = pclk;
 
-       bitrate = (pclk * bits_per_pixel) / intel_dsi->lane_count;
+       bitrate = (pclk * bpp) / intel_dsi->lane_count;
 
        switch (intel_dsi->escape_clk_div) {
        case 0:
@@ -685,6 +705,8 @@ struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
 
        /* This is cheating a bit with the cleanup. */
        vbt_panel = devm_kzalloc(dev->dev, sizeof(*vbt_panel), GFP_KERNEL);
+       if (!vbt_panel)
+               return NULL;
 
        vbt_panel->intel_dsi = intel_dsi;
        drm_panel_init(&vbt_panel->panel);
This page took 0.032102 seconds and 5 git commands to generate.