/* connect overlays to the new device, if not already connected. if force * selected, connect always. */ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) { int i; struct omap_overlay_manager *lcd_mgr; struct omap_overlay_manager *tv_mgr; struct omap_overlay_manager *lcd2_mgr = NULL; struct omap_overlay_manager *mgr = NULL; lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); if (dss_has_feature(FEAT_MGR_LCD2)) lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2); if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { if (!lcd2_mgr->device || force) { if (lcd2_mgr->device) lcd2_mgr->unset_device(lcd2_mgr); lcd2_mgr->set_device(lcd2_mgr, dssdev); mgr = lcd2_mgr; } } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { if (!lcd_mgr->device || force) { if (lcd_mgr->device) lcd_mgr->unset_device(lcd_mgr); lcd_mgr->set_device(lcd_mgr, dssdev); mgr = lcd_mgr; } } if (dssdev->type == OMAP_DISPLAY_TYPE_VENC || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { if (!tv_mgr->device || force) { if (tv_mgr->device) tv_mgr->unset_device(tv_mgr); tv_mgr->set_device(tv_mgr, dssdev); mgr = tv_mgr; } } if (mgr) { dispc_runtime_get(); for (i = 0; i < dss_feat_get_num_ovls(); i++) { struct omap_overlay *ovl; ovl = omap_dss_get_overlay(i); if (!ovl->manager || force) { if (ovl->manager) ovl->unset_manager(ovl); ovl->set_manager(ovl, mgr); } } dispc_runtime_put(); } }
static void dispc_dump_irqs(struct seq_file *s) { unsigned long flags; struct dispc_irq_stats stats; spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); stats = dispc_compat.irq_stats; memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); dispc_compat.irq_stats.last_reset = jiffies; spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); seq_printf(s, "period %u ms\n", jiffies_to_msecs(jiffies - stats.last_reset)); seq_printf(s, "irqs %d\n", stats.irq_count); #define PIS(x) \ seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); PIS(FRAMEDONE); PIS(VSYNC); PIS(EVSYNC_EVEN); PIS(EVSYNC_ODD); PIS(ACBIAS_COUNT_STAT); PIS(PROG_LINE_NUM); PIS(GFX_FIFO_UNDERFLOW); PIS(GFX_END_WIN); PIS(PAL_GAMMA_MASK); PIS(OCP_ERR); PIS(VID1_FIFO_UNDERFLOW); PIS(VID1_END_WIN); PIS(VID2_FIFO_UNDERFLOW); PIS(VID2_END_WIN); if (dss_feat_get_num_ovls() > 3) { PIS(VID3_FIFO_UNDERFLOW); PIS(VID3_END_WIN); } PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); if (dss_has_feature(FEAT_MGR_LCD2)) { PIS(FRAMEDONE2); PIS(VSYNC2); PIS(ACBIAS_COUNT_STAT2); PIS(SYNC_LOST2); } if (dss_has_feature(FEAT_MGR_LCD3)) { PIS(FRAMEDONE3); PIS(VSYNC3); PIS(ACBIAS_COUNT_STAT3); PIS(SYNC_LOST3); } #undef PIS }
void dss_init_overlays(struct platform_device *pdev) { int i, r; num_overlays = dss_feat_get_num_ovls(); overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, GFP_KERNEL); BUG_ON(overlays == NULL); for (i = 0; i < num_overlays; ++i) { struct omap_overlay *ovl = &overlays[i]; switch (i) { case 0: ovl->name = "gfx"; ovl->id = OMAP_DSS_GFX; break; case 1: ovl->name = "vid1"; ovl->id = OMAP_DSS_VIDEO1; break; case 2: ovl->name = "vid2"; ovl->id = OMAP_DSS_VIDEO2; break; case 3: ovl->name = "vid3"; ovl->id = OMAP_DSS_VIDEO3; break; } ovl->is_enabled = &dss_ovl_is_enabled; ovl->enable = &dss_ovl_enable; ovl->disable = &dss_ovl_disable; ovl->set_manager = &dss_ovl_set_manager; ovl->unset_manager = &dss_ovl_unset_manager; ovl->set_overlay_info = &dss_ovl_set_info; ovl->get_overlay_info = &dss_ovl_get_info; ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, &pdev->dev.kobj, "overlay%d", i); if (r) DSSERR("failed to create sysfs file\n"); } }
static void print_irq_status(u32 status) { if ((status & dispc_compat.irq_error_mask) == 0) return; #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", status, PIS(OCP_ERR), PIS(GFX_FIFO_UNDERFLOW), PIS(VID1_FIFO_UNDERFLOW), PIS(VID2_FIFO_UNDERFLOW), dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", PIS(SYNC_LOST), PIS(SYNC_LOST_DIGIT), dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); #undef PIS }
int dss_dispc_initialize_irq(void) { int r; #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spin_lock_init(&dispc_compat.irq_stats_lock); dispc_compat.irq_stats.last_reset = jiffies; dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); #endif spin_lock_init(&dispc_compat.irq_lock); memset(dispc_compat.registered_isr, 0, sizeof(dispc_compat.registered_isr)); dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; if (dss_has_feature(FEAT_MGR_LCD2)) dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; if (dss_has_feature(FEAT_MGR_LCD3)) dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; if (dss_feat_get_num_ovls() > 3) dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; /* * there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ dispc_clear_irqstatus(dispc_read_irqstatus()); INIT_WORK(&dispc_compat.error_work, dispc_error_worker); _omap_dispc_set_irqs(); r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); if (r) { DSSERR("dispc_request_irq failed\n"); return r; } return 0; }
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; crtc_channel = omap_crtc_channel(crtc); if (output->dispc_channel == crtc_channel) { encoder->possible_crtcs |= (1 << id); break; } } 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; }
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; }