/* * Init DSI DPI encoder. * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector * return pointer of newly allocated DPI encoder, NULL on error */ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, struct mdfld_dsi_connector *dsi_connector, const struct panel_funcs *p_funcs) { struct mdfld_dsi_dpi_output *dpi_output = NULL; struct mdfld_dsi_config *dsi_config; struct drm_connector *connector = NULL; struct drm_encoder *encoder = NULL; int pipe; u32 data; int ret; pipe = dsi_connector->pipe; if (mdfld_get_panel_type(dev, pipe) != TC35876X) { dsi_config = mdfld_dsi_get_config(dsi_connector); /* panel hard-reset */ if (p_funcs->reset) { ret = p_funcs->reset(pipe); if (ret) { DRM_ERROR("Panel %d hard-reset failed\n", pipe); return NULL; } } /* panel drvIC init */ if (p_funcs->drv_ic_init) p_funcs->drv_ic_init(dsi_config, pipe); /* panel power mode detect */ ret = mdfld_dsi_get_power_mode(dsi_config, &data, false); if (ret) { DRM_ERROR("Panel %d get power mode failed\n", pipe); dsi_connector->status = connector_status_disconnected; } else { DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); dsi_connector->status = connector_status_connected; } } dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); if (!dpi_output) { DRM_ERROR("No memory\n"); return NULL; } if (dsi_connector->pipe) dpi_output->panel_on = 0; else dpi_output->panel_on = 0; dpi_output->dev = dev; if (mdfld_get_panel_type(dev, pipe) != TC35876X) dpi_output->p_funcs = p_funcs; dpi_output->first_boot = 1; /*get fixed mode*/ dsi_config = mdfld_dsi_get_config(dsi_connector); /*create drm encoder object*/ connector = &dsi_connector->base.base; encoder = &dpi_output->base.base.base; drm_encoder_init(dev, encoder, p_funcs->encoder_funcs, DRM_MODE_ENCODER_LVDS); drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs); /*attach to given connector*/ drm_mode_connector_attach_encoder(connector, encoder); /*set possible crtcs and clones*/ if (dsi_connector->pipe) { encoder->possible_crtcs = (1 << 2); encoder->possible_clones = (1 << 1); } else { encoder->possible_crtcs = (1 << 0); encoder->possible_clones = (1 << 0); } dsi_connector->base.encoder = &dpi_output->base.base; return &dpi_output->base; }
/* * Init DSI DBI encoder. * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector * return pointer of newly allocated DBI encoder, NULL on error */ struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev, struct mdfld_dsi_connector *dsi_connector, struct panel_funcs *p_funcs) { struct drm_psb_private *dev_priv = dev->dev_private; struct mdfld_dsi_dbi_output *dbi_output = NULL; struct mdfld_dsi_config *dsi_config; struct drm_connector *connector = NULL; struct drm_encoder *encoder = NULL; struct drm_display_mode *fixed_mode = NULL; struct psb_gtt *pg = dev_priv ? (&dev_priv->gtt) : NULL; struct mdfld_dbi_dpu_info *dpu_info = dev_priv ? (dev_priv->dbi_dpu_info) : NULL; struct mdfld_dbi_dsr_info *dsr_info = dev_priv ? (dev_priv->dbi_dsr_info) : NULL; u32 data = 0; int pipe; int ret; if (!pg || !dsi_connector || !p_funcs) { WARN_ON(1); return NULL; } dsi_config = mdfld_dsi_get_config(dsi_connector); pipe = dsi_connector->pipe; /*panel hard-reset*/ if (p_funcs->reset) { ret = p_funcs->reset(pipe); if (ret) { DRM_ERROR("Panel %d hard-reset failed\n", pipe); return NULL; } } /* Panel drvIC init */ if (p_funcs->drv_ic_init) p_funcs->drv_ic_init(dsi_config, pipe); /* Panel power mode detect */ ret = mdfld_dsi_get_power_mode(dsi_config, &data, MDFLD_DSI_HS_TRANSMISSION); if (ret) { DRM_ERROR("Panel %d get power mode failed\n", pipe); dsi_connector->status = connector_status_disconnected; } else { DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); dsi_connector->status = connector_status_connected; } /*TODO: get panel info from DDB*/ dbi_output = kzalloc(sizeof(struct mdfld_dsi_dbi_output), GFP_KERNEL); if (!dbi_output) { dev_err(dev->dev, "No memory\n"); return NULL; } if (dsi_connector->pipe == 0) { dbi_output->channel_num = 0; dev_priv->dbi_output = dbi_output; } else if (dsi_connector->pipe == 2) { dbi_output->channel_num = 1; dev_priv->dbi_output2 = dbi_output; } else { dev_err(dev->dev, "only support 2 DSI outputs\n"); goto out_err1; } dbi_output->dev = dev; dbi_output->p_funcs = p_funcs; fixed_mode = dsi_config->fixed_mode; dbi_output->panel_fixed_mode = fixed_mode; /* Create drm encoder object */ connector = &dsi_connector->base.base; encoder = &dbi_output->base.base; drm_encoder_init(dev, encoder, p_funcs->encoder_funcs, DRM_MODE_ENCODER_MIPI); drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs); /* Attach to given connector */ drm_mode_connector_attach_encoder(connector, encoder); /* Set possible CRTCs and clones */ if (dsi_connector->pipe) { encoder->possible_crtcs = (1 << 2); encoder->possible_clones = (1 << 1); } else { encoder->possible_crtcs = (1 << 0); encoder->possible_clones = (1 << 0); } dev_priv->dsr_fb_update = 0; dev_priv->dsr_enable = false; dev_priv->exit_idle = mdfld_dsi_dbi_exit_dsr; dbi_output->first_boot = true; dbi_output->mode_flags = MODE_SETTING_IN_ENCODER; /* Add this output to dpu_info if in DPU mode */ if (dpu_info && dsi_connector->status == connector_status_connected) { if (dsi_connector->pipe == 0) dpu_info->dbi_outputs[0] = dbi_output; else dpu_info->dbi_outputs[1] = dbi_output; dpu_info->dbi_output_num++; } else if (dsi_connector->status == connector_status_connected) { /* Add this output to dsr_info if not */ if (dsi_connector->pipe == 0) dsr_info->dbi_outputs[0] = dbi_output; else dsr_info->dbi_outputs[1] = dbi_output; dsr_info->dbi_output_num++; } return &dbi_output->base; out_err1: kfree(dbi_output); return NULL; }
static void mdfld_dsi_dbi_set_power(struct drm_encoder *encoder, bool on) { int ret = 0; struct mdfld_dsi_encoder *dsi_encoder = MDFLD_DSI_ENCODER(encoder); struct mdfld_dsi_dbi_output *dbi_output = MDFLD_DSI_DBI_OUTPUT(dsi_encoder); struct mdfld_dsi_config *dsi_config = mdfld_dsi_encoder_get_config(dsi_encoder); struct mdfld_dsi_pkg_sender *sender = mdfld_dsi_encoder_get_pkg_sender(dsi_encoder); struct drm_device *dev = encoder->dev; struct drm_psb_private *dev_priv = dev->dev_private; u32 reg_offset = 0; int pipe = (dbi_output->channel_num == 0) ? 0 : 2; u32 data = 0; dev_dbg(dev->dev, "pipe %d : %s, panel on: %s\n", pipe, on ? "On" : "Off", dbi_output->dbi_panel_on ? "True" : "False"); if (pipe == 2) { if (on) dev_priv->dual_mipi = true; else dev_priv->dual_mipi = false; reg_offset = MIPIC_REG_OFFSET; } else { if (!on) dev_priv->dual_mipi = false; } if (!gma_power_begin(dev, true)) { dev_err(dev->dev, "hw begin failed\n"); return; } if (on) { if (dbi_output->dbi_panel_on) goto out_err; ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_ON); if (ret) { dev_err(dev->dev, "power on error\n"); goto out_err; } dbi_output->dbi_panel_on = true; if (pipe == 2) dev_priv->dbi_panel_on2 = true; else dev_priv->dbi_panel_on = true; mdfld_enable_te(dev, pipe); } else { if (!dbi_output->dbi_panel_on && !dbi_output->first_boot) goto out_err; dbi_output->dbi_panel_on = false; dbi_output->first_boot = false; if (pipe == 2) dev_priv->dbi_panel_on2 = false; else dev_priv->dbi_panel_on = false; mdfld_disable_te(dev, pipe); ret = mdfld_dsi_dbi_update_power(dbi_output, DRM_MODE_DPMS_OFF); if (ret) { dev_err(dev->dev, "power on error\n"); goto out_err; } } /* * FIXME: this is a WA for TPO panel crash on DPMS on & off around * 83 times. the root cause of this issue is that Booster in * drvIC crashed. Add this WA so that we can resume the driver IC * once we found that booster has a fault */ mdfld_dsi_get_power_mode(dsi_config, &data, MDFLD_DSI_HS_TRANSMISSION); if (on && data && !(data & (1 << 7))) { /* Soft reset */ mdfld_dsi_send_dcs(sender, DCS_SOFT_RESET, NULL, 0, CMD_DATA_SRC_PIPE, MDFLD_DSI_SEND_PACKAGE); /* Init drvIC */ if (dbi_output->p_funcs->drv_ic_init) dbi_output->p_funcs->drv_ic_init(dsi_config, pipe); } out_err: gma_power_end(dev); if (ret) dev_err(dev->dev, "failed\n"); }
/* * Init DSI DPI encoder. * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector * return pointer of newly allocated DPI encoder, NULL on error */ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, struct mdfld_dsi_connector *dsi_connector, struct panel_funcs *p_funcs) { struct mdfld_dsi_dpi_output *dpi_output = NULL; struct mdfld_dsi_config *dsi_config; struct drm_connector *connector = NULL; struct drm_encoder *encoder = NULL; struct drm_display_mode *fixed_mode = NULL; int pipe; u32 data; int ret; if (!dsi_connector || !p_funcs) { WARN_ON(1); return NULL; } dsi_config = mdfld_dsi_get_config(dsi_connector); pipe = dsi_connector->pipe; /* Panel hard-reset */ if (p_funcs->reset) { ret = p_funcs->reset(pipe); if (ret) { DRM_ERROR("Panel %d hard-reset failed\n", pipe); return NULL; } } /* Panel drvIC init */ if (p_funcs->drv_ic_init) p_funcs->drv_ic_init(dsi_config, pipe); /* Panel power mode detect */ ret = mdfld_dsi_get_power_mode(dsi_config, &data, MDFLD_DSI_LP_TRANSMISSION); if (ret) { DRM_ERROR("Panel %d get power mode failed\n", pipe); dsi_connector->status = connector_status_disconnected; } else { DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); dsi_connector->status = connector_status_connected; } dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); if(!dpi_output) { dev_err(dev->dev, "No memory for dsi_dpi_output\n"); return NULL; } if(dsi_connector->pipe) dpi_output->panel_on = 0; else dpi_output->panel_on = 0; dpi_output->dev = dev; dpi_output->p_funcs = p_funcs; dpi_output->first_boot = 1; /* Get fixed mode */ dsi_config = mdfld_dsi_get_config(dsi_connector); fixed_mode = dsi_config->fixed_mode; /* Create drm encoder object */ connector = &dsi_connector->base.base; encoder = &dpi_output->base.base; /* * On existing hardware this will be a panel of some form, * if future devices also have HDMI bridges this will need * revisiting */ drm_encoder_init(dev, encoder, p_funcs->encoder_funcs, DRM_MODE_ENCODER_LVDS); drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs); /* Attach to given connector */ drm_mode_connector_attach_encoder(connector, encoder); /* Set possible crtcs and clones */ if(dsi_connector->pipe) { encoder->possible_crtcs = (1 << 2); encoder->possible_clones = (1 << 1); } else { encoder->possible_crtcs = (1 << 0); encoder->possible_clones = (1 << 0); } return &dpi_output->base; }