static int __devinit mxr_acquire_layers(struct mxr_device *mdev, struct mxr_platform_data *pdata) { mdev->layer[0] = mxr_graph_layer_create(mdev, 0); mdev->layer[1] = mxr_graph_layer_create(mdev, 1); mdev->layer[2] = mxr_vp_layer_create(mdev, 0); if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) { mxr_err(mdev, "failed to acquire layers\n"); goto fail; } return 0; fail: mxr_release_layers(mdev); return -ENODEV; }
/* When mixer is connected to gscaler through local path, only gscaler's * video device can command alpha blending functionality for mixer */ static int mxr_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct mxr_device *mdev = sd_to_mdev(sd); struct mxr_layer *layer; int v = ctrl->value; int num = 0; mxr_dbg(mdev, "%s start\n", __func__); mxr_dbg(mdev, "id = %d, value = %d\n", ctrl->id, ctrl->value); if (!strcmp(sd->name, "s5p-mixer0")) num = MXR_SUB_MIXER0; else if (!strcmp(sd->name, "s5p-mixer1")) num = MXR_SUB_MIXER1; layer = mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO]; switch (ctrl->id) { case V4L2_CID_TV_LAYER_BLEND_ENABLE: layer->layer_blend_en = v; break; case V4L2_CID_TV_LAYER_BLEND_ALPHA: layer->layer_alpha = (u32)v; break; case V4L2_CID_TV_PIXEL_BLEND_ENABLE: layer->pixel_blend_en = v; break; case V4L2_CID_TV_CHROMA_ENABLE: layer->chroma_en = v; break; case V4L2_CID_TV_CHROMA_VALUE: layer->chroma_val = (u32)v; break; case V4L2_CID_TV_LAYER_PRIO: layer->prio = (u8)v; if (layer->pipe.state == MXR_PIPELINE_STREAMING) mxr_reg_set_layer_prio(mdev); break; default: mxr_err(mdev, "invalid control id\n"); return -EINVAL; } return 0; }
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx) { struct mxr_layer *layer; int ret; struct mxr_layer_ops ops = { .release = mxr_graph_layer_release, .buffer_set = mxr_graph_buffer_set, .stream_set = mxr_graph_stream_set, .format_set = mxr_graph_format_set, .fix_geometry = mxr_graph_fix_geometry, .chromakey_enable = mixer_graph_chromakey_enable, .chromakey_value = mixer_graph_chromakey_value, .change_priority = mixer_graph_change_priority, .layer_blend_enable = mixer_graph_layer_blend_enable, .layer_blend_alpha = mixer_graph_layer_blend_alpha, .pixel_blend_enable= mixer_graph_pixel_blend_enable, }; char name[32]; sprintf(name, "graph%d", idx); layer = mxr_base_layer_create(mdev, idx, name, &ops); if (layer == NULL) { mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); goto fail; } layer->fmt_array = mxr_graph_format; layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format); ret = mxr_base_layer_register(layer); if (ret) goto fail_layer; return layer; fail_layer: mxr_base_layer_release(layer); fail: return NULL; }
static int mxr_acquire_clocks(struct mxr_device *mdev) { struct mxr_resources *res = &mdev->res; struct device *dev = mdev->dev; struct s5p_mxr_platdata *pdata = mdev->pdata; #if defined(CONFIG_ARCH_EXYNOS4) res->vp = clk_get(dev, "vp"); if (IS_ERR_OR_NULL(res->vp)) { mxr_err(mdev, "failed to get clock 'vp'\n"); goto fail; } res->sclk_mixer = clk_get(dev, "sclk_mixer"); if (IS_ERR_OR_NULL(res->sclk_mixer)) { mxr_err(mdev, "failed to get clock 'sclk_mixer'\n"); goto fail; } #endif #if defined(CONFIG_CPU_EXYNOS4210) res->sclk_dac = clk_get(dev, "sclk_dac"); if (IS_ERR_OR_NULL(res->sclk_dac)) { mxr_err(mdev, "failed to get clock 'sclk_dac'\n"); goto fail; } #endif if (is_ip_ver_5a_0 || is_ip_ver_5a_1) { res->axi_disp1 = clk_get(dev, "axi_disp1"); if (IS_ERR_OR_NULL(res->axi_disp1)) { mxr_err(mdev, "failed to get clock 'axi_disp1'\n"); goto fail; } } res->mixer = clk_get(dev, "mixer"); if (IS_ERR_OR_NULL(res->mixer)) { mxr_err(mdev, "failed to get clock 'mixer'\n"); goto fail; } res->sclk_hdmi = clk_get(dev, "sclk_hdmi"); if (IS_ERR_OR_NULL(res->sclk_hdmi)) { mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n"); goto fail; } return 0; fail: mxr_release_clocks(mdev); return -ENODEV; }
static int mxr_acquire_resources(struct mxr_device *mdev, struct platform_device *pdev) { int ret; ret = mxr_acquire_plat_resources(mdev, pdev); if (ret) goto fail; ret = mxr_acquire_clocks(mdev); if (ret) goto fail_plat; mxr_info(mdev, "resources acquired\n"); return 0; fail_plat: mxr_release_plat_resources(mdev); fail: mxr_err(mdev, "resources acquire failed\n"); return ret; }
struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr, int idx, int nr) { struct mxr_layer *layer; int ret; struct mxr_layer_ops ops = { .release = mxr_vp_layer_release, .buffer_set = mxr_vp_buffer_set, .stream_set = mxr_vp_stream_set, .format_set = mxr_vp_format_set, .fix_geometry = mxr_vp_fix_geometry, }; char name[32]; sprintf(name, "mxr%d_video%d", cur_mxr, idx); layer = mxr_base_layer_create(mdev, idx, name, &ops); if (layer == NULL) { mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); goto fail; } layer->fmt_array = mxr_video_format; layer->fmt_array_size = ARRAY_SIZE(mxr_video_format); layer->minor = nr; layer->type = MXR_LAYER_TYPE_VIDEO; ret = mxr_base_layer_register(layer); if (ret) goto fail_layer; layer->cur_mxr = cur_mxr; return layer; fail_layer: mxr_base_layer_release(layer); fail: return NULL; }
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx) { struct mxr_layer *layer; int ret; const struct mxr_layer_ops ops = { .release = mxr_graph_layer_release, .buffer_set = mxr_graph_buffer_set, .stream_set = mxr_graph_stream_set, .format_set = mxr_graph_format_set, .fix_geometry = mxr_graph_fix_geometry, }; char name[32]; sprintf(name, "graph%d", idx); layer = mxr_base_layer_create(mdev, idx, name, &ops); if (layer == NULL) { mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); goto fail; } layer->fmt_array = mxr_graph_format; layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format); ret = mxr_base_layer_register(layer); if (ret) goto fail_layer; return layer; fail_layer: mxr_base_layer_release(layer); fail: return NULL; }
static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd) { int i; int ret = 0; int local = 1; struct sub_mxr_device *sub_mxr; struct mxr_layer *layer; struct media_pad *pad; struct v4l2_mbus_framefmt mbus_fmt; #if defined(CONFIG_CPU_EXYNOS4210) struct mxr_resources *res = &mdev->res; #endif struct v4l2_control ctrl; mutex_lock(&mdev->s_mutex); ++mdev->n_streamer; mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); /* If pipeline is started from Gscaler input video device, * TV basic configuration must be set before running mixer */ if (mdev->mxr_data_from == FROM_GSC_SD) { mxr_dbg(mdev, "%s: from gscaler\n", __func__); local = 0; /* enable mixer clock */ ret = mxr_power_get(mdev); if (ret) { mxr_err(mdev, "power on failed\n"); ret = -ENODEV; goto out; } /* turn on connected output device through link * with mixer */ mxr_output_get(mdev); for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) { layer = sub_mxr->layer[MXR_LAYER_VIDEO]; layer->pipe.state = MXR_PIPELINE_STREAMING; mxr_layer_geo_fix(layer); layer->ops.format_set(layer, layer->fmt, &layer->geo); layer->ops.stream_set(layer, 1); local += sub_mxr->local; } } if (local == 2) mxr_layer_sync(mdev, MXR_ENABLE); /* Set the TVOUT register about gsc-mixer local path */ mxr_reg_local_path_set(mdev, mdev->mxr0_gsc, mdev->mxr1_gsc, mdev->flags); } /* Alpha blending configuration always can be changed * whenever streaming */ mxr_set_alpha_blend(mdev); mxr_reg_set_color_range(mdev); mxr_reg_set_layer_prio(mdev); if ((mdev->n_streamer == 1 && local == 1) || (mdev->n_streamer == 2 && local == 2)) { for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) { pad = &sd->entity.pads[i]; /* find sink pad of output via enabled link*/ pad = media_entity_remote_source(pad); if (pad) if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) break; if (i == MXR_PAD_SOURCE_GRP1) { ret = -ENODEV; goto out; } } sd = media_entity_to_v4l2_subdev(pad->entity); mxr_dbg(mdev, "cookie of current output = (%d)\n", to_output(mdev)->cookie); #if defined(CONFIG_CPU_EXYNOS4210) if (to_output(mdev)->cookie == 0) clk_set_parent(res->sclk_mixer, res->sclk_dac); else clk_set_parent(res->sclk_mixer, res->sclk_hdmi); #endif mxr_reg_s_output(mdev, to_output(mdev)->cookie); ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt); if (ret) { mxr_err(mdev, "failed to get mbus_fmt for output %s\n", sd->name); goto out; } ctrl.id = V4L2_CID_TV_GET_DVI_MODE; ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl); if (ret) { mxr_err(mdev, "failed to get DVI or HDMI mode %s\n", sd->name); goto out; } mxr_reg_set_mbus_fmt(mdev, &mbus_fmt, ctrl.value); ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt); if (ret) { mxr_err(mdev, "failed to set mbus_fmt for output %s\n", sd->name); goto out; } mxr_reg_streamon(mdev); ret = v4l2_subdev_call(sd, video, s_stream, 1); if (ret) { mxr_err(mdev, "starting stream failed for output %s\n", sd->name); goto out; } ret = mxr_reg_wait4update(mdev); if (ret) { mxr_err(mdev, "failed to get vsync (%d) from output\n", ret); goto out; } } out: mutex_unlock(&mdev->s_mutex); mxr_reg_dump(mdev); return ret; }
static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev, struct platform_device *pdev) { struct resource *res; int ret; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr"); if (res == NULL) { mxr_err(mdev, "get memory resource failed.\n"); ret = -ENXIO; goto fail; } mdev->res.mxr_regs = ioremap(res->start, resource_size(res)); if (mdev->res.mxr_regs == NULL) { mxr_err(mdev, "register mapping failed.\n"); ret = -ENXIO; goto fail; } #if defined(CONFIG_ARCH_EXYNOS4) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp"); if (res == NULL) { mxr_err(mdev, "get memory resource failed.\n"); ret = -ENXIO; goto fail_mxr_regs; } mdev->res.vp_regs = ioremap(res->start, resource_size(res)); if (mdev->res.vp_regs == NULL) { mxr_err(mdev, "register mapping failed.\n"); ret = -ENXIO; goto fail_mxr_regs; } #endif res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq"); if (res == NULL) { mxr_err(mdev, "get interrupt resource failed.\n"); ret = -ENXIO; goto fail_vp_regs; } ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev); if (ret) { mxr_err(mdev, "request interrupt failed.\n"); goto fail_vp_regs; } mdev->res.irq = res->start; return 0; fail_vp_regs: #if defined(CONFIG_ARCH_EXYNOS4) iounmap(mdev->res.vp_regs); fail_mxr_regs: #endif iounmap(mdev->res.mxr_regs); fail: return ret; }
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd) { int i; int ret = 0; int local = 1; struct media_pad *pad; struct sub_mxr_device *sub_mxr; struct mxr_layer *layer; struct v4l2_subdev *hdmi_sd; struct v4l2_subdev *gsc_sd; struct exynos_entity_data *md_data; mutex_lock(&mdev->s_mutex); --mdev->n_streamer; mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); /* distinction number of local path */ if (mdev->mxr_data_from == FROM_GSC_SD) { local = 0; for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) local += sub_mxr->local; } if (local == 2) mxr_layer_sync(mdev, MXR_DISABLE); } if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) { pad = &sd->entity.pads[i]; /* find sink pad of output via enabled link*/ pad = media_entity_remote_source(pad); if (pad) if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) break; if (i == MXR_PAD_SOURCE_GRP1) { ret = -ENODEV; goto out; } } hdmi_sd = media_entity_to_v4l2_subdev(pad->entity); mxr_reg_streamoff(mdev); /* vsync applies Mixer setup */ ret = mxr_reg_wait4update(mdev); if (ret) { mxr_err(mdev, "failed to get vsync (%d) from output\n", ret); goto out; } } /* When using local path between gscaler and mixer, below stop sequence * must be processed */ if (mdev->mxr_data_from == FROM_GSC_SD) { pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER]; pad = media_entity_remote_source(pad); if (pad) { gsc_sd = media_entity_to_v4l2_subdev( pad->entity); mxr_dbg(mdev, "stop from %s\n", gsc_sd->name); md_data = (struct exynos_entity_data *) gsc_sd->dev_priv; md_data->media_ops->power_off(gsc_sd); } } if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0); if (ret) { mxr_err(mdev, "stopping stream failed for output %s\n", hdmi_sd->name); goto out; } } /* turn off connected output device through link * with mixer */ if (mdev->mxr_data_from == FROM_GSC_SD) { for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) { layer = sub_mxr->layer[MXR_LAYER_VIDEO]; layer->ops.stream_set(layer, 0); layer->pipe.state = MXR_PIPELINE_IDLE; } } mxr_reg_local_path_clear(mdev); mxr_output_put(mdev); /* disable mixer clock */ mxr_power_put(mdev); } WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n", mdev->n_streamer); out: mutex_unlock(&mdev->s_mutex); mxr_reg_dump(mdev); return ret; }
static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd) { int i; int ret = 0; int local = 1; struct sub_mxr_device *sub_mxr; struct mxr_layer *layer; struct media_pad *pad; struct s5p_mxr_platdata *pdata = mdev->pdata; struct v4l2_mbus_framefmt mbus_fmt; struct v4l2_control ctrl; mutex_lock(&mdev->s_mutex); ++mdev->n_streamer; mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); /* If pipeline is started from Gscaler input video device, * TV basic configuration must be set before running mixer */ if (mdev->mxr_data_from == FROM_GSC_SD) { mxr_dbg(mdev, "%s: from gscaler\n", __func__); local = 0; /* enable mixer clock */ ret = mxr_power_get(mdev); if (ret < 0) { mxr_err(mdev, "power on failed for video layer\n"); ret = -ENODEV; goto out; } for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) { layer = sub_mxr->layer[MXR_LAYER_VIDEO]; layer->pipe.state = MXR_PIPELINE_STREAMING; mxr_layer_geo_fix(layer); layer->ops.format_set(layer, layer->fmt, &layer->geo); layer->ops.stream_set(layer, 1); local += sub_mxr->local; } } if (local == 2) mxr_layer_sync(mdev, MXR_ENABLE); /* Set the TVOUT register about gsc-mixer local path */ mxr_reg_local_path_set(mdev); } /* Alpha blending configuration always can be changed * whenever streaming */ mxr_set_alpha_blend(mdev); mxr_reg_set_color_range(mdev); mxr_reg_set_layer_prio(mdev); if (is_ip_ver_5s || is_ip_ver_5s2) mxr_reg_set_resolution(mdev); if ((mdev->n_streamer == 1 && local == 1) || (mdev->n_streamer == 2 && local == 2)) { #if defined(CONFIG_TV_USE_BUS_DEVFREQ) if (is_ip_ver_5a) pm_qos_add_request(&exynos5_tv_mif_qos, PM_QOS_BUS_THROUGHPUT, 800000); pm_qos_add_request(&exynos5_tv_int_qos, PM_QOS_DEVICE_THROUGHPUT, 400000); #endif for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) { pad = &sd->entity.pads[i]; /* find sink pad of output via enabled link*/ pad = media_entity_remote_source(pad); if (pad) if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) break; if (i == MXR_PAD_SOURCE_GRP1) { ret = -ENODEV; goto out; } } sd = media_entity_to_v4l2_subdev(pad->entity); mxr_dbg(mdev, "cookie of current output = (%d)\n", to_output(mdev)->cookie); mxr_reg_s_output(mdev, to_output(mdev)->cookie); ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt); if (ret) { mxr_err(mdev, "failed to get mbus_fmt for output %s\n", sd->name); goto out; } ctrl.id = V4L2_CID_TV_GET_DVI_MODE; ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl); if (ret) { mxr_err(mdev, "failed to get DVI or HDMI mode %s\n", sd->name); goto out; } mxr_reg_set_mbus_fmt(mdev, &mbus_fmt, ctrl.value); ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt); if (ret) { mxr_err(mdev, "failed to set mbus_fmt for output %s\n", sd->name); goto out; } mxr_reg_streamon(mdev); /* start hdmi */ ctrl.id = V4L2_CID_TV_HDMI_STATUS; ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl); if (ret) { mxr_err(mdev, "failed to get output %s status for start\n", sd->name); goto out; } if (ctrl.value == (HDMI_STOP | HPD_HIGH)) { ret = v4l2_subdev_call(sd, core, s_power, 1); if (ret) { mxr_err(mdev, "failed to get power for output %s\n", sd->name); goto out; } ret = v4l2_subdev_call(sd, video, s_stream, 1); if (ret) { mxr_err(mdev, "starting stream failed for output %s\n", sd->name); goto out; } } ret = mxr_reg_wait4update(mdev); if (ret) { mxr_err(mdev, "failed to get vsync (%d) from output\n", ret); goto out; } } out: mutex_unlock(&mdev->s_mutex); mxr_reg_dump(mdev); return ret; }
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd) { int i; int ret = 0; int local = 1; struct media_pad *pad; struct sub_mxr_device *sub_mxr; struct mxr_layer *layer; struct v4l2_subdev *hdmi_sd; struct v4l2_subdev *gsc_sd; struct exynos_entity_data *md_data; struct s5p_mxr_platdata *pdata = mdev->pdata; struct v4l2_control ctrl; mutex_lock(&mdev->s_mutex); --mdev->n_streamer; mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); /* distinction number of local path */ if (mdev->mxr_data_from == FROM_GSC_SD) { local = 0; for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) local += sub_mxr->local; } if (local == 2) mxr_layer_sync(mdev, MXR_DISABLE); /* stop gscaler --> waiting for frame done */ pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER]; pad = media_entity_remote_source(pad); if (pad) { gsc_sd = media_entity_to_v4l2_subdev( pad->entity); mxr_dbg(mdev, "stop from %s\n", gsc_sd->name); md_data = (struct exynos_entity_data *) gsc_sd->dev_priv; if (is_ip_ver_5g_1 || is_ip_ver_5a_0) md_data->media_ops->power_off(gsc_sd); } /* disable video layer */ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) { layer = sub_mxr->layer[MXR_LAYER_VIDEO]; layer->ops.stream_set(layer, 0); layer->pipe.state = MXR_PIPELINE_IDLE; } } } if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) { pad = &sd->entity.pads[i]; /* find sink pad of output via enabled link*/ pad = media_entity_remote_source(pad); if (pad) if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) break; if (i == MXR_PAD_SOURCE_GRP1) { ret = -ENODEV; goto out; } } hdmi_sd = media_entity_to_v4l2_subdev(pad->entity); mxr_reg_streamoff(mdev); /* vsync applies Mixer setup */ ret = mxr_reg_wait4update(mdev); if (ret) { mxr_err(mdev, "failed to get vsync (%d) from output\n", ret); goto out; } /* stop hdmi */ ctrl.id = V4L2_CID_TV_HDMI_STATUS; ret = v4l2_subdev_call(hdmi_sd, core, g_ctrl, &ctrl); if (ret) { mxr_err(mdev, "failed to get output %s status for stop\n", hdmi_sd->name); goto out; } /* * HDMI should be turn off only when not in use. * 1. cable out * 2. suspend (blank is called at suspend) */ if (ctrl.value == (HDMI_STREAMING | HPD_LOW) || mdev->blank) { ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0); if (ret) { mxr_err(mdev, "stopping stream failed for output %s\n", hdmi_sd->name); goto out; } ret = v4l2_subdev_call(hdmi_sd, core, s_power, 0); if (ret) { mxr_err(mdev, "failed to put power for output %s\n", hdmi_sd->name); goto out; } mdev->blank = 0; } } /* disable mixer clock */ if (mdev->mxr_data_from == FROM_GSC_SD) mxr_power_put(mdev); WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n", mdev->n_streamer); out: #if defined(CONFIG_TV_USE_BUS_DEVFREQ) if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { if (is_ip_ver_5a) pm_qos_remove_request(&exynos5_tv_mif_qos); pm_qos_remove_request(&exynos5_tv_int_qos); } #endif mutex_unlock(&mdev->s_mutex); mxr_reg_dump(mdev); return ret; }
static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd) { int i; int ret = 0; int local = 1; struct media_pad *pad; struct sub_mxr_device *sub_mxr; struct mxr_layer *layer; struct v4l2_subdev *gsc_sd; struct exynos_entity_data *md_data; struct s5p_mxr_platdata *pdata = mdev->pdata; mutex_lock(&mdev->s_mutex); --mdev->n_streamer; mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); /* distinction number of local path */ if (mdev->mxr_data_from == FROM_GSC_SD) { local = 0; for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) local += sub_mxr->local; } if (local == 2) mxr_layer_sync(mdev, MXR_DISABLE); /* stop gscaler --> waiting for frame done */ pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER]; pad = media_entity_remote_source(pad); if (pad) { gsc_sd = media_entity_to_v4l2_subdev( pad->entity); mxr_dbg(mdev, "stop from %s\n", gsc_sd->name); md_data = (struct exynos_entity_data *) gsc_sd->dev_priv; if (is_ip_ver_5g_1 || is_ip_ver_5a_0) md_data->media_ops->power_off(gsc_sd); } /* disable video layer */ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) { sub_mxr = &mdev->sub_mxr[i]; if (sub_mxr->local) { layer = sub_mxr->layer[MXR_LAYER_VIDEO]; layer->ops.stream_set(layer, 0); layer->pipe.state = MXR_PIPELINE_IDLE; } } } if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { mxr_reg_streamoff(mdev); /* vsync applies Mixer setup */ ret = mxr_reg_wait4update(mdev); if (ret) { mxr_err(mdev, "failed to get vsync (%d) from output\n", ret); goto out; } } /* disable mixer clock */ if (mdev->mxr_data_from == FROM_GSC_SD) mxr_power_put(mdev); WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n", mdev->n_streamer); out: #if defined(CONFIG_ARM_EXYNOS5410_BUS_DEVFREQ) if ((mdev->n_streamer == 0 && local == 1) || (mdev->n_streamer == 1 && local == 2)) { pm_qos_remove_request(&exynos5_tv_mif_qos); pm_qos_remove_request(&exynos5_tv_int_qos); } #endif mutex_unlock(&mdev->s_mutex); mxr_reg_dump(mdev); return ret; }
static int mxr_s_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) { struct mxr_layer *layer = video_drvdata(file); struct mxr_device *mdev = layer->mdev; int v = ctrl->value; int ret; mxr_dbg(mdev, "%s start\n", __func__); ret = mxr_check_ctrl_val(ctrl); if (ret) { mxr_err(mdev, "alpha value is out of range\n"); return ret; } switch (ctrl->id) { case V4L2_CID_TV_LAYER_BLEND_ENABLE: layer->layer_blend_en = v; break; case V4L2_CID_TV_LAYER_BLEND_ALPHA: layer->layer_alpha = (u32)v; break; case V4L2_CID_TV_PIXEL_BLEND_ENABLE: layer->pixel_blend_en = v; break; case V4L2_CID_TV_CHROMA_ENABLE: layer->chroma_en = v; break; case V4L2_CID_TV_CHROMA_VALUE: layer->chroma_val = (u32)v; break; case V4L2_CID_TV_SET_COLOR_RANGE: mdev->color_range = v; v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl); break; case V4L2_CID_TV_BLANK: mdev->blank = v; break; case V4L2_CID_TV_ENABLE_HDMI_AUDIO: case V4L2_CID_TV_SET_NUM_CHANNELS: case V4L2_CID_TV_HPD_STATUS: case V4L2_CID_TV_SET_DVI_MODE: case V4L2_CID_TV_SET_ASPECT_RATIO: case V4L2_CID_TV_HDCP_ENABLE: v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl); break; case V4L2_CID_TV_LAYER_PRIO: layer->prio = (u8)v; /* This can be turned on/off each layer while streaming */ if (layer->pipe.state == MXR_PIPELINE_STREAMING) mxr_reg_set_layer_prio(mdev); break; case V4L2_CID_TV_UPDATE: ret = mxr_update(mdev); break; default: mxr_err(mdev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
int __devinit mxr_acquire_video(struct mxr_device *mdev, struct mxr_output_conf *output_conf, int output_count) { int i; int ret = 0; struct v4l2_subdev *sd; struct s5p_mxr_platdata *pdata = mdev->pdata; mdev->alloc_ctx = mdev->vb2->init(mdev); if (IS_ERR_OR_NULL(mdev->alloc_ctx)) { mxr_err(mdev, "could not acquire vb2 allocator\n"); ret = PTR_ERR(mdev->alloc_ctx); goto fail; } if (is_ip_ver_5r) { exynos_create_iovmm(mdev->dev, 1, 0); iovmm_reserve(mdev->dev, MXR_VA, MXR_VA); } else { exynos_create_iovmm(mdev->dev, 3, 0); } /* registering outputs */ mdev->output_cnt = 0; for (i = 0; i < output_count; ++i) { struct mxr_output_conf *conf = &output_conf[i]; struct mxr_output *out; /* find subdev of output devices */ sd = (struct v4l2_subdev *) module_name_to_driver_data(conf->module_name); /* trying to register next output */ if (sd == NULL) continue; out = kzalloc(sizeof *out, GFP_KERNEL); if (out == NULL) { mxr_err(mdev, "no memory for '%s'\n", conf->output_name); ret = -ENOMEM; /* registered subdevs are removed in fail_v4l2_dev */ goto fail_output; } strlcpy(out->name, conf->output_name, sizeof(out->name)); out->sd = sd; out->cookie = conf->cookie; mdev->output[mdev->output_cnt++] = out; mxr_info(mdev, "added output '%s' from module '%s'\n", conf->output_name, conf->module_name); /* checking if maximal number of outputs is reached */ if (mdev->output_cnt >= MXR_MAX_OUTPUTS) break; } if (mdev->output_cnt == 0) { mxr_err(mdev, "failed to register any output\n"); ret = -ENODEV; /* skipping fail_output because there is nothing to free */ goto fail_vb2_allocator; } return 0; fail_output: /* kfree is NULL-safe */ for (i = 0; i < mdev->output_cnt; ++i) kfree(mdev->output[i]); memset(mdev->output, 0, sizeof mdev->output); fail_vb2_allocator: /* freeing allocator context */ mdev->vb2->cleanup(mdev->alloc_ctx); fail: return ret; }