struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, struct drm_encoder *encoder) { struct exynos_drm_connector *exynos_connector; struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); struct drm_connector *connector; int type; int err; DRM_DEBUG_KMS("%s\n", __FILE__); exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL); if (!exynos_connector) { DRM_ERROR("failed to allocate connector\n"); return NULL; } connector = &exynos_connector->drm_connector; switch (manager->display_ops->type) { case EXYNOS_DISPLAY_TYPE_HDMI: type = DRM_MODE_CONNECTOR_HDMIA; connector->interlace_allowed = true; connector->polled = DRM_CONNECTOR_POLL_HPD; break; case EXYNOS_DISPLAY_TYPE_VIDI: type = DRM_MODE_CONNECTOR_VIRTUAL; connector->polled = DRM_CONNECTOR_POLL_HPD; break; default: type = DRM_MODE_CONNECTOR_Unknown; break; } drm_connector_init(dev, connector, &exynos_connector_funcs, type); drm_connector_helper_add(connector, &exynos_connector_helper_funcs); err = drm_sysfs_connector_add(connector); if (err) goto err_connector; exynos_connector->encoder_id = encoder->base.id; exynos_connector->manager = manager; connector->encoder = encoder; err = drm_mode_connector_attach_encoder(connector, encoder); if (err) { DRM_ERROR("failed to attach a connector to a encoder\n"); goto err_sysfs; } DRM_DEBUG_KMS("connector has been created\n"); return connector; err_sysfs: drm_sysfs_connector_remove(connector); err_connector: drm_connector_cleanup(connector); kfree(exynos_connector); return NULL; }
static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); int num_mgrs = dss_feat_get_num_mgrs(); int num_crtcs; int i, id = 0; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* * We usually don't want to create a CRTC for each manager, at least * not until we have a way to expose private planes to userspace. * Otherwise there would not be enough video pipes left for drm planes. * We use the num_crtc argument to limit the number of crtcs we create. */ num_crtcs = min3(num_crtc, num_mgrs, num_ovls); dssdev = NULL; for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; enum omap_channel channel; struct omap_overlay_manager *mgr; if (!omapdss_device_is_connected(dssdev)) continue; encoder = omap_encoder_init(dev, dssdev); if (!encoder) { dev_err(dev->dev, "could not create encoder: %s\n", dssdev->name); return -ENOMEM; } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); if (!connector) { dev_err(dev->dev, "could not create connector: %s\n", dssdev->name); return -ENOMEM; } BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); priv->encoders[priv->num_encoders++] = encoder; priv->connectors[priv->num_connectors++] = connector; drm_mode_connector_attach_encoder(connector, encoder); /* * if we have reached the limit of the crtcs we are allowed to * create, let's not try to look for a crtc for this * panel/encoder and onwards, we will, of course, populate the * the possible_crtcs field for all the encoders with the final * set of crtcs we create */ if (id == num_crtcs) continue; /* * get the recommended DISPC channel for this encoder. For now, * we only try to get create a crtc out of the recommended, the * other possible channels to which the encoder can connect are * not considered. */ mgr = omapdss_find_mgr_from_display(dssdev); channel = mgr->id; /* * if this channel hasn't already been taken by a previously * allocated crtc, we create a new crtc for it */ if (!channel_used(dev, channel)) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, channel, id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; id++; } } /* * we have allocated crtcs according to the need of the panels/encoders, * adding more crtcs here if needed */ for (; id < num_crtcs; id++) { /* find a free manager for this crtc */ for (i = 0; i < num_mgrs; i++) { if (!channel_used(dev, i)) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, i, id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; break; } else { continue; } } if (i == num_mgrs) { /* this shouldn't really happen */ dev_err(dev->dev, "no managers left for crtc\n"); return -ENOMEM; } } /* * Create normal planes for the remaining overlays: */ for (; id < num_ovls; id++) { struct drm_plane *plane = omap_plane_init(dev, id, false); BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; } for (i = 0; i < priv->num_encoders; i++) { struct drm_encoder *encoder = priv->encoders[i]; struct omap_dss_device *dssdev = omap_encoder_get_dssdev(encoder); struct omap_dss_device *output; output = omapdss_find_output_from_display(dssdev); /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; for (id = 0; id < priv->num_crtcs; id++) { struct drm_crtc *crtc = priv->crtcs[id]; enum omap_channel crtc_channel; enum omap_dss_output_id supported_outputs; crtc_channel = omap_crtc_channel(crtc); supported_outputs = dss_feat_get_supported_outputs(crtc_channel); if (supported_outputs & output->id) encoder->possible_crtcs |= (1 << id); } omap_dss_put_device(output); } DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", priv->num_planes, priv->num_crtcs, priv->num_encoders, priv->num_connectors); dev->mode_config.min_width = 32; dev->mode_config.min_height = 32; /* note: eventually will need some cpu_is_omapXYZ() type stuff here * to fill in these limits properly on different OMAP generations.. */ dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; dev->mode_config.funcs = &omap_mode_config_funcs; return 0; }
/* * 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 drm_psb_private *dev_priv = dev->dev_private; 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; int ret; PSB_DEBUG_ENTRY("[DISPLAY] %s\n", __func__); if (!dsi_connector || !p_funcs) { DRM_ERROR("Invalid parameters\n"); return NULL; } dsi_config = mdfld_dsi_get_config(dsi_connector); pipe = dsi_connector->pipe; /*detect panel connection stauts*/ if (p_funcs->detect) { ret = p_funcs->detect(dsi_config); if (ret) { DRM_INFO("Detecting Panel %d, Not connected\n", pipe); dsi_connector->status = connector_status_disconnected; } else { PSB_DEBUG_ENTRY("Panel %d is connected\n", pipe); dsi_connector->status = connector_status_connected; } if (dsi_connector->status == connector_status_disconnected && pipe == 0) { DRM_ERROR("Primary panel disconnected\n"); return NULL; } } else { /*use the default config*/ if (pipe == 0) dsi_connector->status = connector_status_connected; else dsi_connector->status = connector_status_disconnected; } /*init DSI controller*/ if (p_funcs->dsi_controller_init) p_funcs->dsi_controller_init(dsi_config); /** * TODO: can we keep these code out of display driver as * it will make display driver hard to be maintained */ if (dsi_connector->status == connector_status_connected) { if (pipe == 0) dev_priv->panel_desc |= DISPLAY_A; if (pipe == 2) dev_priv->panel_desc |= DISPLAY_C; } dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); if (!dpi_output) { DRM_ERROR("No memory\n"); return NULL; } dpi_output->dev = dev; dpi_output->p_funcs = p_funcs; dpi_output->first_boot = 1; /*get fixed mode*/ fixed_mode = dsi_config->fixed_mode; /*create drm encoder object*/ connector = &dsi_connector->base.base; encoder = &dpi_output->base.base; drm_encoder_init(dev, encoder, &dsi_dpi_generic_encoder_funcs, DRM_MODE_ENCODER_DSI); drm_encoder_helper_add(encoder, &dsi_dpi_generic_encoder_helper_funcs); /*attach to given connector*/ drm_mode_connector_attach_encoder(connector, encoder); connector->encoder = 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->b_dsr_enable = false; dev_priv->exit_idle = NULL; #if defined(CONFIG_MDFLD_DSI_DPU) || defined(CONFIG_MDFLD_DSI_DSR) dev_priv->b_dsr_enable_config = true; #endif /*CONFIG_MDFLD_DSI_DSR*/ PSB_DEBUG_ENTRY("successfully\n"); return &dpi_output->base; }
/* * 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; }
struct drm_connector *sde_connector_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_panel *panel, void *display, const struct sde_connector_ops *ops, int connector_poll, int connector_type) { struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_kms_info *info; struct sde_connector *c_conn = NULL; int rc; if (!dev || !dev->dev_private || !encoder) { SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n", dev, encoder); return ERR_PTR(-EINVAL); } priv = dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid kms reference\n"); return ERR_PTR(-EINVAL); } c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL); if (!c_conn) { SDE_ERROR("failed to alloc sde connector\n"); return ERR_PTR(-ENOMEM); } rc = drm_connector_init(dev, &c_conn->base, &sde_connector_ops, connector_type); if (rc) goto error_free_conn; c_conn->connector_type = connector_type; c_conn->encoder = encoder; c_conn->panel = panel; c_conn->display = display; /* cache mmu_id's for later */ sde_kms = to_sde_kms(priv->kms); if (sde_kms->vbif[VBIF_NRT]) { c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE]; c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE]; } else { c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE]; c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE]; } if (ops) c_conn->ops = *ops; c_conn->base.helper_private = &sde_connector_helper_ops; c_conn->base.polled = connector_poll; c_conn->base.interlace_allowed = 0; c_conn->base.doublescan_allowed = 0; snprintf(c_conn->name, SDE_CONNECTOR_NAME_SIZE, "conn%u", c_conn->base.base.id); /* * Initialize retire fence support. Set fence offset to 0 for virtual * connectors so that the fence signals at the end of the current commit * and 1 for others so that the fence signals after one additional * commit. */ rc = sde_fence_init(dev, &c_conn->retire_fence, c_conn->name, connector_type == DRM_MODE_CONNECTOR_VIRTUAL ? 0 : 1); if (rc) { SDE_ERROR("failed to init fence, %d\n", rc); goto error_cleanup_conn; } rc = drm_connector_register(&c_conn->base); if (rc) { SDE_ERROR("failed to register drm connector, %d\n", rc); goto error_cleanup_fence; } rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder); if (rc) { SDE_ERROR("failed to attach encoder to connector, %d\n", rc); goto error_unregister_conn; } /* create properties */ msm_property_init(&c_conn->property_info, &c_conn->base.base, dev, priv->conn_property, c_conn->property_data, CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT, sizeof(struct sde_connector_state)); if (c_conn->ops.post_init) { info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) { SDE_ERROR("failed to allocate info buffer\n"); rc = -ENOMEM; goto error_unregister_conn; } sde_kms_info_reset(info); rc = c_conn->ops.post_init(&c_conn->base, info, display); if (rc) { SDE_ERROR("post-init failed, %d\n", rc); kfree(info); goto error_unregister_conn; } msm_property_install_blob(&c_conn->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); msm_property_set_blob(&c_conn->property_info, &c_conn->blob_caps, SDE_KMS_INFO_DATA(info), SDE_KMS_INFO_DATALEN(info), CONNECTOR_PROP_SDE_INFO); kfree(info); } msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, ARRAY_SIZE(e_topology_name), CONNECTOR_PROP_TOPOLOGY_NAME, 0); msm_property_install_enum(&c_conn->property_info, "topology_control", 0, 1, e_topology_control, ARRAY_SIZE(e_topology_control), CONNECTOR_PROP_TOPOLOGY_CONTROL, 0); rc = msm_property_install_get_status(&c_conn->property_info); if (rc) { SDE_ERROR("failed to create one or more properties\n"); goto error_destroy_property; } SDE_DEBUG("connector %d attach encoder %d\n", c_conn->base.base.id, encoder->base.id); priv->connectors[priv->num_connectors++] = &c_conn->base; return &c_conn->base; error_destroy_property: if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); msm_property_destroy(&c_conn->property_info); error_unregister_conn: drm_connector_unregister(&c_conn->base); error_cleanup_fence: sde_fence_deinit(&c_conn->retire_fence); error_cleanup_conn: drm_connector_cleanup(&c_conn->base); error_free_conn: kfree(c_conn); return ERR_PTR(rc); }
void cdv_intel_crt_init(struct drm_device *dev, struct psb_intel_mode_device *mode_dev) { struct psb_intel_output *psb_intel_output; struct drm_connector *connector; struct drm_encoder *encoder; u32 i2c_reg; psb_intel_output = kzalloc(sizeof(struct psb_intel_output), GFP_KERNEL); if (!psb_intel_output) return; psb_intel_output->mode_dev = mode_dev; connector = &psb_intel_output->base; drm_connector_init(dev, connector, &cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); encoder = &psb_intel_output->enc; drm_encoder_init(dev, encoder, &cdv_intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); drm_mode_connector_attach_encoder(&psb_intel_output->base, &psb_intel_output->enc); /* Set up the DDC bus. */ i2c_reg = GPIOA; /* Remove the following code for CDV */ /* if (dev_priv->crt_ddc_bus != 0) i2c_reg = dev_priv->crt_ddc_bus; }*/ psb_intel_output->ddc_bus = psb_intel_i2c_create(dev, i2c_reg, "CRTDDC_A"); if (!psb_intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); goto failed_ddc; } psb_intel_output->type = INTEL_OUTPUT_ANALOG; /* psb_intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT); psb_intel_output->crtc_mask = (1 << 0) | (1 << 1); */ connector->interlace_allowed = 0; connector->doublescan_allowed = 0; drm_encoder_helper_add(encoder, &cdv_intel_crt_helper_funcs); drm_connector_helper_add(connector, &cdv_intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); return; failed_ddc: drm_encoder_cleanup(&psb_intel_output->enc); drm_connector_cleanup(&psb_intel_output->base); kfree(psb_intel_output); return; }
/* * 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 int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) { struct vmw_screen_object_unit *sou; struct drm_device *dev = dev_priv->dev; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_plane *primary, *cursor; struct drm_crtc *crtc; int ret; sou = kzalloc(sizeof(*sou), GFP_KERNEL); if (!sou) return -ENOMEM; sou->base.unit = unit; crtc = &sou->base.crtc; encoder = &sou->base.encoder; connector = &sou->base.connector; primary = &sou->base.primary; cursor = &sou->base.cursor; sou->base.active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = dev_priv->initial_width; sou->base.pref_height = dev_priv->initial_height; sou->base.pref_mode = NULL; /* * Remove this after enabling atomic because property values can * only exist in a state object */ sou->base.is_implicit = false; /* Initialize primary plane */ vmw_du_plane_reset(primary); ret = drm_universal_plane_init(dev, &sou->base.primary, 0, &vmw_sou_plane_funcs, vmw_primary_plane_formats, ARRAY_SIZE(vmw_primary_plane_formats), DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) { DRM_ERROR("Failed to initialize primary plane"); goto err_free; } drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); /* Initialize cursor plane */ vmw_du_plane_reset(cursor); ret = drm_universal_plane_init(dev, &sou->base.cursor, 0, &vmw_sou_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), DRM_PLANE_TYPE_CURSOR, NULL); if (ret) { DRM_ERROR("Failed to initialize cursor plane"); drm_plane_cleanup(&sou->base.primary); goto err_free; } drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs); vmw_du_connector_reset(connector); ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); if (ret) { DRM_ERROR("Failed to initialize connector\n"); goto err_free; } drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); connector->status = vmw_du_connector_detect(connector, true); vmw_connector_state_to_vcs(connector->state)->is_implicit = false; ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) { DRM_ERROR("Failed to initialize encoder\n"); goto err_free_connector; } (void) drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; ret = drm_connector_register(connector); if (ret) { DRM_ERROR("Failed to register connector\n"); goto err_free_encoder; } vmw_du_crtc_reset(crtc); ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary, &sou->base.cursor, &vmw_screen_object_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); goto err_free_unregister; } drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, dev_priv->hotplug_mode_update_property, 1); drm_object_attach_property(&connector->base, dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.suggested_y_property, 0); if (dev_priv->implicit_placement_property) drm_object_attach_property (&connector->base, dev_priv->implicit_placement_property, sou->base.is_implicit); return 0; err_free_unregister: drm_connector_unregister(connector); err_free_encoder: drm_encoder_cleanup(encoder); err_free_connector: drm_connector_cleanup(connector); err_free: kfree(sou); return ret; }
/* * 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; }
/* * 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 = (struct drm_psb_private *)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->pg) : NULL; #ifdef CONFIG_MDFLD_DSI_DPU struct mdfld_dbi_dpu_info *dpu_info = dev_priv ? (dev_priv->dbi_dpu_info) : NULL; #else struct mdfld_dbi_dsr_info *dsr_info = dev_priv ? (dev_priv->dbi_dsr_info) : NULL; #endif int pipe; int ret; PSB_DEBUG_ENTRY("\n"); if (!pg || !dsi_connector || !p_funcs) { DRM_ERROR("Invalid parameters\n"); return NULL; } dsi_config = mdfld_dsi_get_config(dsi_connector); pipe = dsi_connector->pipe; if (p_funcs && p_funcs->reset) p_funcs->reset(dsi_config); /*detect panel connection stauts*/ if (p_funcs->detect) { ret = p_funcs->detect(dsi_config); if (ret) { DRM_INFO("Fail to detect Panel on pipe %d\n", pipe); dsi_connector->status = connector_status_disconnected; } else { DRM_INFO("Panel on pipe %d is connected\n", pipe); dsi_connector->status = connector_status_connected; } } else { /*use the default config*/ if (pipe == 0) dsi_connector->status = connector_status_connected; else dsi_connector->status = connector_status_disconnected; } /*init DSI controller*/ if (p_funcs->dsi_controller_init) p_funcs->dsi_controller_init(dsi_config); if (dsi_connector->status == connector_status_connected) { if (pipe == 0) dev_priv->panel_desc |= DISPLAY_A; if (pipe == 2) dev_priv->panel_desc |= DISPLAY_C; } /* TODO: get panel info from DDB */ dbi_output = kzalloc(sizeof(struct mdfld_dsi_dbi_output), GFP_KERNEL); if (!dbi_output) { DRM_ERROR("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 { DRM_ERROR("only support 2 DSI outputs\n"); goto out_err1; } dbi_output->dev = dev; dbi_output->p_funcs = p_funcs; /*get fixed mode*/ 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, &dsi_dbi_generic_encoder_funcs, DRM_MODE_ENCODER_DSI); drm_encoder_helper_add(encoder, &dsi_dbi_generic_encoder_helper_funcs); /*attach to given connector*/ drm_mode_connector_attach_encoder(connector, encoder); connector->encoder = 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->b_dsr_enable = false; dev_priv->exit_idle = mdfld_dsi_dbi_exit_dsr; dev_priv->b_async_flip_enable = false; #if defined(CONFIG_MDFLD_DSI_DPU) || defined(CONFIG_MDFLD_DSI_DSR) dev_priv->b_dsr_enable_config = true; #endif /*CONFIG_MDFLD_DSI_DSR*/ dbi_output->first_boot = true; dbi_output->mode_flags = MODE_SETTING_IN_ENCODER; #ifdef CONFIG_MDFLD_DSI_DPU /*add this output to dpu_info*/ if (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 /*CONFIG_MDFLD_DSI_DPU*/ if (dsi_connector->status == connector_status_connected) { /*add this output to dsr_info*/ 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++; } #endif PSB_DEBUG_ENTRY("successfully\n"); return &dbi_output->base; out_err1: kfree(dbi_output); return NULL; }
/* * 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 drm_psb_private *dev_priv = dev->dev_private; 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; PSB_DEBUG_ENTRY("\n"); if (!dsi_connector) { DRM_ERROR("Invalid parameters\n"); return NULL; } dsi_config = mdfld_dsi_get_config(dsi_connector); pipe = dsi_connector->pipe; 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; } dpi_output->dev = dev; dpi_output->first_boot = 1; if (pipe) dev_priv->dpi_output2 = dpi_output; else dev_priv->dpi_output = dpi_output; /*create drm encoder object*/ connector = &dsi_connector->base.base; encoder = &dpi_output->base.base; drm_encoder_init(dev, encoder, &dsi_dpi_generic_encoder_funcs, DRM_MODE_ENCODER_DSI); drm_encoder_helper_add(encoder, &dsi_dpi_generic_encoder_helper_funcs); /*attach to given connector*/ drm_mode_connector_attach_encoder(connector, encoder); connector->encoder = 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->b_dsr_enable = false; dev_priv->exit_idle = mdfld_dsi_dpi_exit_idle; #if defined(CONFIG_MDFLD_DSI_DPU) || defined(CONFIG_MDFLD_DSI_DSR) dev_priv->b_dsr_enable_config = true; #endif /*CONFIG_MDFLD_DSI_DSR*/ encoder_shutdown = encoder; PSB_DEBUG_ENTRY("successfully\n"); return &dpi_output->base; }
static int omap_modeset_init(struct drm_device *dev) { const struct omap_gpu_platform_data *pdata = dev->dev->platform_data; struct omap_gpu_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int i, j; unsigned int connected_connectors = 0; /* create encoders for each manager */ int create_encoder(int i) { struct omap_overlay_manager *mgr = omap_dss_get_overlay_manager(i); struct drm_encoder *encoder = omap_encoder_init(dev, mgr); if (!encoder) { dev_err(dev->dev, "could not create encoder\n"); return -ENOMEM; } priv->encoders[priv->num_encoders++] = encoder; return 0; } /* create connectors for each display device */ int create_connector(struct omap_dss_device *dssdev) { static struct notifier_block *notifier; struct drm_connector *connector; if (!dssdev->driver) { dev_warn(dev->dev, "%s has no driver.. skipping it\n", dssdev->name); return 0; } if (!(dssdev->driver->get_timings || dssdev->driver->get_edid)) { dev_warn(dev->dev, "%s driver does not support " "get_timings or get_edid.. skipping it!\n", dssdev->name); return 0; } connector = omap_connector_init(dev, get_connector_type(dssdev->type), dssdev); if (!connector) { dev_err(dev->dev, "could not create connector\n"); return -ENOMEM; } /* track what is already connected.. rather than looping thru all * connectors twice later, first for connected then for remainder * (which could be a race condition if connected status changes) */ if (omap_connector_detect (connector) == connector_status_connected) { connected_connectors |= (1 << priv->num_connectors); } priv->connectors[priv->num_connectors++] = connector; notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); notifier->notifier_call = omap_gpu_notifier; omap_dss_add_notify(dssdev, notifier); for (j = 0; j < priv->num_encoders; j++) { struct omap_overlay_manager *mgr = omap_encoder_get_manager(priv->encoders[j]); if (mgr->device == dssdev) { drm_mode_connector_attach_encoder(connector, priv->encoders[j]); } } return 0; } /* create up to max_overlays CRTCs mapping to overlays.. by default, * connect the overlays to different managers/encoders, giving priority * to encoders connected to connectors with a detected connection */ int create_crtc(int i) { struct omap_overlay *ovl = omap_dss_get_overlay(i); struct omap_overlay_manager *mgr = NULL; struct drm_crtc *crtc; if (ovl->manager) { DBG("disconnecting %s from %s", ovl->name, ovl->manager->name); ovl->unset_manager(ovl); } /* find next best connector... ones with detected connection first */ while (j < priv->num_connectors && !mgr) { if (connected_connectors & (1 << j)) { struct drm_encoder * encoder = omap_connector_attached_encoder (priv->connectors[j]); if (encoder) { mgr = omap_encoder_get_manager (encoder); } } j++; } /* if we couldn't find another connected connector, lets start looking * at the unconnected connectors: */ while (j < 2 * priv->num_connectors && !mgr) { int idx = j - priv->num_connectors; if (!(connected_connectors & (1 << idx))) { struct drm_encoder * encoder = omap_connector_attached_encoder (priv->connectors[idx]); if (encoder) { mgr = omap_encoder_get_manager (encoder); } } j++; } if (mgr) { DBG("connecting %s to %s", ovl->name, mgr->name); ovl->set_manager(ovl, mgr); } crtc = omap_crtc_init(dev, ovl); if (!crtc) { dev_err(dev->dev, "could not create CRTC\n"); return -ENOMEM; } priv->crtcs[priv->num_crtcs++] = crtc; return 0; } drm_mode_config_init(dev); if (pdata) { /* if platform data is provided by the board file, use it to control * which overlays, managers, and devices we own. */ for (i = 0; i < pdata->mgr_cnt; i++) { if (create_encoder(pdata->mgr_ids[i])) { goto fail; } } for (i = 0; i < pdata->dev_cnt; i++) { int m(struct omap_dss_device *dssdev, void *data) { return ! strcmp(dssdev->name, data); } struct omap_dss_device *dssdev = omap_dss_find_device((void *)pdata->dev_names[i], m); if (!dssdev) { dev_warn(dev->dev, "no such dssdev: %s\n", pdata->dev_names[i]); continue; } if (create_connector(dssdev)) { goto fail; } } j = 0; for (i = 0; i < pdata->ovl_cnt; i++) { if (create_crtc(pdata->ovl_ids[i])) { goto fail; } } } else {
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; struct intel_output *intel_output; struct intel_hdmi_priv *hdmi_priv; if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) { DRM_DEBUG_KMS("HDMI is not present. Ignored it \n"); return; } intel_output = kcalloc(sizeof(struct intel_output) + sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); if (!intel_output) return; hdmi_priv = (struct intel_hdmi_priv *)(intel_output + 1); connector = &intel_output->base; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); intel_output->type = INTEL_OUTPUT_HDMI; connector->interlace_allowed = 0; connector->doublescan_allowed = 0; intel_output->crtc_mask = (1 << 0) | (1 << 1); /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) { intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, "HDMIB"); dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, "HDMIC"); dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, "HDMID"); dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; } if (!intel_output->ddc_bus) goto err_connector; hdmi_priv->sdvox_reg = sdvox_reg; intel_output->dev_priv = hdmi_priv; drm_encoder_init(dev, &intel_output->enc, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_output->enc, &intel_hdmi_helper_funcs); drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); drm_sysfs_connector_add(connector); /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written * 0xd. Failure to do so will result in spurious interrupts being * generated on the port when a cable is not attached. */ if (IS_G4X(dev) && !IS_GM45(dev)) { u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } return; err_connector: drm_connector_cleanup(connector); kfree(intel_output); return; }
struct lcd_link *jzdrm_lcd_register(struct drm_device *dev) { struct platform_device *pdev = dev->platformdev; struct jzfb_platform_data *pdata = pdev->dev.platform_data; struct lcd_link *lcd_link; struct drm_encoder *encoder; struct drm_connector *connector; struct lcd_manager *subdev; int ret; lcd_link = kzalloc(sizeof(struct lcd_link), GFP_KERNEL); if (!lcd_link) return NULL; lcd_link->drm = dev; encoder = &lcd_link->encoder; connector = &lcd_link->connector; #ifdef CONFIG_LCD_BYD_8991FTGF subdev = rgb_lcd_register(lcd_link); #endif #ifdef CONFIG_LCD_X163 subdev = mipi_dsi_lcd_register(lcd_link); #endif if (!subdev) return NULL; connector->funcs = subdev->jzdrm_connector_funcs; encoder->funcs = subdev->jzdrm_encoder_funcs; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DisplayPort; encoder->possible_crtcs = 1; drm_encoder_helper_add(encoder, subdev->jzdrm_encoder_helper_funcs); drm_encoder_init(dev, encoder, encoder->funcs, encoder->encoder_type); drm_connector_helper_add(connector, subdev->jzdrm_connector_helper_funcs); drm_connector_init(dev, connector, connector->funcs, connector->connector_type); connector->encoder = encoder; connector->dpms = subdev->dpms; ret = drm_sysfs_connector_add(connector); if (ret) { dev_err(dev->dev, "[CONNECTOR:%d] drm_connector_register failed: %d\n", connector->base.id, ret); return NULL; } drm_mode_connector_attach_encoder(connector, encoder); lcd_link->dpms = subdev->dpms; return lcd_link; }
static int armada_drm_conn_slave_create(struct drm_connector *conn, const void *data) { const struct armada_drm_slave_config *config = data; struct drm_encoder_slave *slave; struct i2c_adapter *adap; int ret; conn->interlace_allowed = config->interlace_allowed; conn->doublescan_allowed = config->doublescan_allowed; conn->polled = config->polled; drm_connector_helper_add(conn, &armada_drm_slave_helper_funcs); slave = kzalloc(sizeof(*slave), GFP_KERNEL); if (!slave) return -ENOMEM; slave->base.possible_crtcs = config->crtcs; adap = i2c_get_adapter(config->i2c_adapter_id); if (!adap) { kfree(slave); return -EPROBE_DEFER; } ret = drm_encoder_init(conn->dev, &slave->base, &armada_drm_slave_encoder_funcs, DRM_MODE_ENCODER_TMDS); if (ret) { DRM_ERROR("unable to init encoder\n"); i2c_put_adapter(adap); kfree(slave); return ret; } ret = drm_i2c_encoder_init(conn->dev, slave, adap, &config->info); i2c_put_adapter(adap); if (ret) { DRM_ERROR("unable to init encoder slave\n"); armada_drm_slave_destroy(&slave->base); return ret; } drm_encoder_helper_add(&slave->base, &drm_slave_encoder_helpers); ret = slave->slave_funcs->create_resources(&slave->base, conn); if (ret) { armada_drm_slave_destroy(&slave->base); return ret; } ret = drm_mode_connector_attach_encoder(conn, &slave->base); if (ret) { armada_drm_slave_destroy(&slave->base); return ret; } conn->encoder = &slave->base; return ret; }
int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, struct i2c_client *client, struct device_node *node) { int ret; struct drm_bridge *bridge; struct ptn3460_bridge *ptn_bridge; bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL); if (!bridge) { DRM_ERROR("Failed to allocate drm bridge\n"); return -ENOMEM; } ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL); if (!ptn_bridge) { DRM_ERROR("Failed to allocate ptn bridge\n"); return -ENOMEM; } ptn_bridge->client = client; ptn_bridge->encoder = encoder; ptn_bridge->bridge = bridge; ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0); if (gpio_is_valid(ptn_bridge->gpio_pd_n)) { ret = gpio_request_one(ptn_bridge->gpio_pd_n, GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N"); if (ret) { DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret); return ret; } } ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0); if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { /* * Request the reset pin low to avoid the bridge being * initialized prematurely */ ret = gpio_request_one(ptn_bridge->gpio_rst_n, GPIOF_OUT_INIT_LOW, "PTN3460_RST_N"); if (ret) { DRM_ERROR("Request reset-gpio failed (%d)\n", ret); gpio_free(ptn_bridge->gpio_pd_n); return ret; } } ret = of_property_read_u32(node, "edid-emulation", &ptn_bridge->edid_emulation); if (ret) { DRM_ERROR("Can't read edid emulation value\n"); goto err; } ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs); if (ret) { DRM_ERROR("Failed to initialize bridge with drm\n"); goto err; } bridge->driver_private = ptn_bridge; encoder->bridge = bridge; ret = drm_connector_init(dev, &ptn_bridge->connector, &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); if (ret) { DRM_ERROR("Failed to initialize connector with drm\n"); goto err; } drm_connector_helper_add(&ptn_bridge->connector, &ptn3460_connector_helper_funcs); drm_sysfs_connector_add(&ptn_bridge->connector); drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); return 0; err: if (gpio_is_valid(ptn_bridge->gpio_pd_n)) gpio_free(ptn_bridge->gpio_pd_n); if (gpio_is_valid(ptn_bridge->gpio_rst_n)) gpio_free(ptn_bridge->gpio_rst_n); return ret; }
static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); int id; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* * Create private planes and CRTCs for the last NUM_CRTCs overlay * plus manager: */ for (id = 0; id < min(num_crtc, num_ovls); id++) { struct drm_plane *plane; struct drm_crtc *crtc; plane = omap_plane_init(dev, id, true); crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); priv->crtcs[id] = crtc; priv->num_crtcs++; priv->planes[id] = plane; priv->num_planes++; } /* * Create normal planes for the remaining overlays: */ for (; id < num_ovls; id++) { struct drm_plane *plane = omap_plane_init(dev, id, false); BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); priv->planes[priv->num_planes++] = plane; } for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; if (!dssdev->driver) { dev_warn(dev->dev, "%s has no driver.. skipping it\n", dssdev->name); return 0; } if (!(dssdev->driver->get_timings || dssdev->driver->read_edid)) { dev_warn(dev->dev, "%s driver does not support " "get_timings or read_edid.. skipping it!\n", dssdev->name); return 0; } encoder = omap_encoder_init(dev, dssdev); if (!encoder) { dev_err(dev->dev, "could not create encoder: %s\n", dssdev->name); return -ENOMEM; } connector = omap_connector_init(dev, get_connector_type(dssdev), dssdev, encoder); if (!connector) { dev_err(dev->dev, "could not create connector: %s\n", dssdev->name); return -ENOMEM; } BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); priv->encoders[priv->num_encoders++] = encoder; priv->connectors[priv->num_connectors++] = connector; drm_mode_connector_attach_encoder(connector, encoder); /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; for (id = 0; id < priv->num_crtcs; id++) { enum omap_dss_output_id supported_outputs = dss_feat_get_supported_outputs(pipe2chan(id)); if (supported_outputs & dssdev->output->id) encoder->possible_crtcs |= (1 << id); } } dev->mode_config.min_width = 32; dev->mode_config.min_height = 32; /* note: eventually will need some cpu_is_omapXYZ() type stuff here * to fill in these limits properly on different OMAP generations.. */ dev->mode_config.max_width = 2048; dev->mode_config.max_height = 2048; dev->mode_config.funcs = &omap_mode_config_funcs; return 0; }