Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] s5p-fimc: Rework the video pipeline control functions

There is getting more entities to manage within single video pipeline
in newer SoCs. To simplify code put subdevs' pointer into an array
rather than adding new member in struct fimc_pipeline for each subdev.
This allows to easier handle subdev operations in proper order.

Additionally walk graph in one direction only in fimc_pipeline_prepare()
function to make sure we properly gather only media entities that below
to single data pipeline. This avoids wrong initialization in case where,
for example there are multiple active links from s5p-mipi-csis subdev
output pad.

struct fimc_pipeline declaration is moved to the driver's public header
to allow other drivers to reuse the fimc-lite driver added in subsequent
patches.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Sylwester Nawrocki and committed by
Mauro Carvalho Chehab
0f735f52 2b511edb

+138 -87
+17 -15
drivers/media/video/s5p-fimc/fimc-capture.c
··· 34 34 static int fimc_init_capture(struct fimc_dev *fimc) 35 35 { 36 36 struct fimc_ctx *ctx = fimc->vid_cap.ctx; 37 + struct fimc_pipeline *p = &fimc->pipeline; 37 38 struct fimc_sensor_info *sensor; 38 39 unsigned long flags; 39 40 int ret = 0; 40 41 41 - if (fimc->pipeline.sensor == NULL || ctx == NULL) 42 + if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL) 42 43 return -ENXIO; 43 44 if (ctx->s_frame.fmt == NULL) 44 45 return -EINVAL; 45 46 46 - sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor); 47 + sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]); 47 48 48 49 spin_lock_irqsave(&fimc->slock, flags); 49 50 fimc_prepare_dma_offset(ctx, &ctx->d_frame); ··· 110 109 spin_unlock_irqrestore(&fimc->slock, flags); 111 110 112 111 if (streaming) 113 - return fimc_pipeline_s_stream(fimc, 0); 112 + return fimc_pipeline_s_stream(&fimc->pipeline, 0); 114 113 else 115 114 return 0; 116 115 } ··· 255 254 fimc_activate_capture(ctx); 256 255 257 256 if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) 258 - fimc_pipeline_s_stream(fimc, 1); 257 + fimc_pipeline_s_stream(&fimc->pipeline, 1); 259 258 } 260 259 261 260 return 0; ··· 282 281 int ret = fimc_stop_capture(fimc, suspend); 283 282 if (ret) 284 283 return ret; 285 - return fimc_pipeline_shutdown(fimc); 284 + return fimc_pipeline_shutdown(&fimc->pipeline); 286 285 } 287 286 288 287 static void buffer_queue(struct vb2_buffer *vb); ··· 298 297 299 298 INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); 300 299 vid_cap->buf_index = 0; 301 - fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity, 300 + fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity, 302 301 false); 303 302 fimc_init_capture(fimc); 304 303 ··· 415 414 spin_unlock_irqrestore(&fimc->slock, flags); 416 415 417 416 if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) 418 - fimc_pipeline_s_stream(fimc, 1); 417 + fimc_pipeline_s_stream(&fimc->pipeline, 1); 419 418 return; 420 419 } 421 420 spin_unlock_irqrestore(&fimc->slock, flags); ··· 465 464 return ret; 466 465 467 466 return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler, 468 - fimc->pipeline.sensor->ctrl_handler); 467 + fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler); 469 468 } 470 469 471 470 static int fimc_capture_set_default_format(struct fimc_dev *fimc); ··· 488 487 pm_runtime_get_sync(&fimc->pdev->dev); 489 488 490 489 if (++fimc->vid_cap.refcnt == 1) { 491 - ret = fimc_pipeline_initialize(fimc, 490 + ret = fimc_pipeline_initialize(&fimc->pipeline, 492 491 &fimc->vid_cap.vfd->entity, true); 493 492 if (ret < 0) { 494 493 dev_err(&fimc->pdev->dev, ··· 516 515 if (--fimc->vid_cap.refcnt == 0) { 517 516 clear_bit(ST_CAPT_BUSY, &fimc->state); 518 517 fimc_stop_capture(fimc, false); 519 - fimc_pipeline_shutdown(fimc); 518 + fimc_pipeline_shutdown(&fimc->pipeline); 520 519 clear_bit(ST_CAPT_SUSPENDED, &fimc->state); 521 520 } 522 521 ··· 737 736 bool set) 738 737 { 739 738 struct fimc_dev *fimc = ctx->fimc_dev; 740 - struct v4l2_subdev *sd = fimc->pipeline.sensor; 741 - struct v4l2_subdev *csis = fimc->pipeline.csis; 739 + struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; 740 + struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; 742 741 struct v4l2_subdev_format sfmt; 743 742 struct v4l2_mbus_framefmt *mf = &sfmt.format; 744 743 struct fimc_fmt *ffmt = NULL; ··· 946 945 struct v4l2_input *i) 947 946 { 948 947 struct fimc_dev *fimc = video_drvdata(file); 949 - struct v4l2_subdev *sd = fimc->pipeline.sensor; 948 + struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; 950 949 951 950 if (i->index != 0) 952 951 return -EINVAL; ··· 1038 1037 if (fimc_capture_active(fimc)) 1039 1038 return -EBUSY; 1040 1039 1041 - media_entity_pipeline_start(&p->sensor->entity, p->pipe); 1040 + media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity, 1041 + p->m_pipeline); 1042 1042 1043 1043 if (fimc->vid_cap.user_subdev_api) { 1044 1044 ret = fimc_pipeline_validate(fimc); ··· 1053 1051 enum v4l2_buf_type type) 1054 1052 { 1055 1053 struct fimc_dev *fimc = video_drvdata(file); 1056 - struct v4l2_subdev *sd = fimc->pipeline.sensor; 1054 + struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; 1057 1055 int ret; 1058 1056 1059 1057 ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
-5
drivers/media/video/s5p-fimc/fimc-core.h
··· 400 400 int num_entities; 401 401 }; 402 402 403 - struct fimc_pipeline { 404 - struct media_pipeline *pipe; 405 - struct v4l2_subdev *sensor; 406 - struct v4l2_subdev *csis; 407 - }; 408 403 409 404 struct fimc_ctx; 410 405
+100 -62
drivers/media/video/s5p-fimc/fimc-mdevice.c
··· 25 25 #include <media/media-device.h> 26 26 27 27 #include "fimc-core.h" 28 + #include "fimc-lite.h" 28 29 #include "fimc-mdevice.h" 29 30 #include "mipi-csis.h" 30 31 ··· 38 37 * 39 38 * Caller holds the graph mutex. 40 39 */ 41 - void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me) 40 + void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me) 42 41 { 43 - struct media_entity_graph graph; 42 + struct media_pad *pad = &me->pads[0]; 44 43 struct v4l2_subdev *sd; 44 + int i; 45 45 46 - media_entity_graph_walk_start(&graph, me); 46 + for (i = 0; i < IDX_MAX; i++) 47 + p->subdevs[i] = NULL; 47 48 48 - while ((me = media_entity_graph_walk_next(&graph))) { 49 - if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV) 50 - continue; 51 - sd = media_entity_to_v4l2_subdev(me); 49 + while (1) { 50 + if (!(pad->flags & MEDIA_PAD_FL_SINK)) 51 + break; 52 52 53 - if (sd->grp_id == SENSOR_GROUP_ID) 54 - fimc->pipeline.sensor = sd; 55 - else if (sd->grp_id == CSIS_GROUP_ID) 56 - fimc->pipeline.csis = sd; 53 + /* source pad */ 54 + pad = media_entity_remote_source(pad); 55 + if (pad == NULL || 56 + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) 57 + break; 58 + 59 + sd = media_entity_to_v4l2_subdev(pad->entity); 60 + 61 + switch (sd->grp_id) { 62 + case SENSOR_GROUP_ID: 63 + p->subdevs[IDX_SENSOR] = sd; 64 + break; 65 + case CSIS_GROUP_ID: 66 + p->subdevs[IDX_CSIS] = sd; 67 + break; 68 + case FIMC_GROUP_ID: 69 + /* No need to control FIMC subdev through subdev ops */ 70 + break; 71 + default: 72 + pr_warn("%s: Unknown subdev grp_id: %#x\n", 73 + __func__, sd->grp_id); 74 + } 75 + /* sink pad */ 76 + pad = &sd->entity.pads[0]; 57 77 } 58 78 } 59 79 ··· 107 85 /** 108 86 * fimc_pipeline_s_power - change power state of all pipeline subdevs 109 87 * @fimc: fimc device terminating the pipeline 110 - * @state: 1 to enable power or 0 for power down 88 + * @state: true to power on, false to power off 111 89 * 112 - * Need to be called with the graph mutex held. 90 + * Needs to be called with the graph mutex held. 113 91 */ 114 - int fimc_pipeline_s_power(struct fimc_dev *fimc, int state) 92 + int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) 115 93 { 116 - int ret = 0; 94 + unsigned int i; 95 + int ret; 117 96 118 - if (fimc->pipeline.sensor == NULL) 97 + if (p->subdevs[IDX_SENSOR] == NULL) 119 98 return -ENXIO; 120 99 121 - if (state) { 122 - ret = __subdev_set_power(fimc->pipeline.csis, 1); 123 - if (ret && ret != -ENXIO) 100 + for (i = 0; i < IDX_MAX; i++) { 101 + unsigned int idx = state ? (IDX_MAX - 1) - i : i; 102 + 103 + ret = __subdev_set_power(p->subdevs[idx], state); 104 + if (ret < 0 && ret != -ENXIO) 124 105 return ret; 125 - return __subdev_set_power(fimc->pipeline.sensor, 1); 126 106 } 127 107 128 - ret = __subdev_set_power(fimc->pipeline.sensor, 0); 129 - if (ret) 130 - return ret; 131 - ret = __subdev_set_power(fimc->pipeline.csis, 0); 132 - 133 - return ret == -ENXIO ? 0 : ret; 108 + return 0; 134 109 } 135 110 136 111 /** ··· 138 119 * 139 120 * This function must be called with the graph mutex held. 140 121 */ 141 - static int __fimc_pipeline_initialize(struct fimc_dev *fimc, 122 + static int __fimc_pipeline_initialize(struct fimc_pipeline *p, 142 123 struct media_entity *me, bool prep) 143 124 { 144 125 int ret; 145 126 146 127 if (prep) 147 - fimc_pipeline_prepare(fimc, me); 148 - if (fimc->pipeline.sensor == NULL) 128 + fimc_pipeline_prepare(p, me); 129 + 130 + if (p->subdevs[IDX_SENSOR] == NULL) 149 131 return -EINVAL; 150 - ret = fimc_md_set_camclk(fimc->pipeline.sensor, true); 132 + 133 + ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true); 151 134 if (ret) 152 135 return ret; 153 - return fimc_pipeline_s_power(fimc, 1); 136 + 137 + return fimc_pipeline_s_power(p, 1); 154 138 } 155 139 156 - int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, 140 + int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, 157 141 bool prep) 158 142 { 159 143 int ret; 160 144 161 145 mutex_lock(&me->parent->graph_mutex); 162 - ret = __fimc_pipeline_initialize(fimc, me, prep); 146 + ret = __fimc_pipeline_initialize(p, me, prep); 163 147 mutex_unlock(&me->parent->graph_mutex); 164 148 165 149 return ret; 166 150 } 151 + EXPORT_SYMBOL_GPL(fimc_pipeline_initialize); 167 152 168 153 /** 169 154 * __fimc_pipeline_shutdown - disable the sensor clock and pipeline power ··· 177 154 * sensor clock. 178 155 * Called with the graph mutex held. 179 156 */ 180 - int __fimc_pipeline_shutdown(struct fimc_dev *fimc) 157 + int __fimc_pipeline_shutdown(struct fimc_pipeline *p) 181 158 { 182 159 int ret = 0; 183 160 184 - if (fimc->pipeline.sensor) { 185 - ret = fimc_pipeline_s_power(fimc, 0); 186 - fimc_md_set_camclk(fimc->pipeline.sensor, false); 161 + if (p->subdevs[IDX_SENSOR]) { 162 + ret = fimc_pipeline_s_power(p, 0); 163 + fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false); 187 164 } 188 165 return ret == -ENXIO ? 0 : ret; 189 166 } 190 167 191 - int fimc_pipeline_shutdown(struct fimc_dev *fimc) 168 + int fimc_pipeline_shutdown(struct fimc_pipeline *p) 192 169 { 193 - struct media_entity *me = &fimc->vid_cap.vfd->entity; 170 + struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity; 194 171 int ret; 195 172 196 173 mutex_lock(&me->parent->graph_mutex); 197 - ret = __fimc_pipeline_shutdown(fimc); 174 + ret = __fimc_pipeline_shutdown(p); 198 175 mutex_unlock(&me->parent->graph_mutex); 199 176 200 177 return ret; 201 178 } 179 + EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown); 202 180 203 181 /** 204 182 * fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs 205 - * @fimc: fimc device terminating the pipeline 183 + * @pipeline: video pipeline structure 206 184 * @on: passed as the s_stream call argument 207 185 */ 208 - int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on) 186 + int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) 209 187 { 210 - struct fimc_pipeline *p = &fimc->pipeline; 211 - int ret = 0; 188 + int i, ret; 212 189 213 - if (p->sensor == NULL) 190 + if (p->subdevs[IDX_SENSOR] == NULL) 214 191 return -ENODEV; 215 192 216 - if ((on && p->csis) || !on) 217 - ret = v4l2_subdev_call(on ? p->csis : p->sensor, 218 - video, s_stream, on); 219 - if (ret < 0 && ret != -ENOIOCTLCMD) 220 - return ret; 221 - if ((!on && p->csis) || on) 222 - ret = v4l2_subdev_call(on ? p->sensor : p->csis, 223 - video, s_stream, on); 224 - return ret == -ENOIOCTLCMD ? 0 : ret; 193 + for (i = 0; i < IDX_MAX; i++) { 194 + unsigned int idx = on ? (IDX_MAX - 1) - i : i; 195 + 196 + ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); 197 + 198 + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) 199 + return ret; 200 + } 201 + 202 + return 0; 203 + 225 204 } 205 + EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream); 226 206 227 207 /* 228 208 * Sensor subdevice helper functions ··· 703 677 static int fimc_md_link_notify(struct media_pad *source, 704 678 struct media_pad *sink, u32 flags) 705 679 { 680 + struct fimc_pipeline *pipeline; 706 681 struct v4l2_subdev *sd; 707 682 struct fimc_dev *fimc; 708 683 int ret = 0; ··· 712 685 return 0; 713 686 714 687 sd = media_entity_to_v4l2_subdev(sink->entity); 715 - fimc = v4l2_get_subdevdata(sd); 688 + 689 + switch (sd->grp_id) { 690 + case FIMC_GROUP_ID: 691 + fimc = v4l2_get_subdevdata(sd); 692 + pipeline = &fimc->pipeline; 693 + break; 694 + default: 695 + return 0; 696 + } 716 697 717 698 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 718 - ret = __fimc_pipeline_shutdown(fimc); 719 - fimc->pipeline.sensor = NULL; 720 - fimc->pipeline.csis = NULL; 699 + ret = __fimc_pipeline_shutdown(pipeline); 700 + pipeline->subdevs[IDX_SENSOR] = NULL; 701 + pipeline->subdevs[IDX_CSIS] = NULL; 721 702 722 - mutex_lock(&fimc->lock); 723 - fimc_ctrls_delete(fimc->vid_cap.ctx); 724 - mutex_unlock(&fimc->lock); 703 + if (fimc) { 704 + mutex_lock(&fimc->lock); 705 + fimc_ctrls_delete(fimc->vid_cap.ctx); 706 + mutex_unlock(&fimc->lock); 707 + } 725 708 return ret; 726 709 } 727 710 /* ··· 741 704 */ 742 705 mutex_lock(&fimc->lock); 743 706 if (fimc->vid_cap.refcnt > 0) { 744 - ret = __fimc_pipeline_initialize(fimc, source->entity, true); 707 + ret = __fimc_pipeline_initialize(pipeline, 708 + source->entity, true); 745 709 if (!ret) 746 710 ret = fimc_capture_ctrls_create(fimc); 747 711 }
+5 -5
drivers/media/video/s5p-fimc/fimc-mdevice.h
··· 109 109 } 110 110 111 111 int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); 112 - void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me); 113 - int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me, 112 + void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me); 113 + int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me, 114 114 bool resume); 115 - int fimc_pipeline_shutdown(struct fimc_dev *fimc); 116 - int fimc_pipeline_s_power(struct fimc_dev *fimc, int state); 117 - int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state); 115 + int fimc_pipeline_shutdown(struct fimc_pipeline *p); 116 + int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state); 117 + int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool state); 118 118 119 119 #endif
+16
include/media/s5p_fimc.h
··· 64 64 */ 65 65 #define S5P_FIMC_TX_END_NOTIFY _IO('e', 0) 66 66 67 + enum fimc_subdev_index { 68 + IDX_SENSOR, 69 + IDX_CSIS, 70 + IDX_FLITE, 71 + IDX_FIMC, 72 + IDX_MAX, 73 + }; 74 + 75 + struct media_pipeline; 76 + struct v4l2_subdev; 77 + 78 + struct fimc_pipeline { 79 + struct v4l2_subdev *subdevs[IDX_MAX]; 80 + struct media_pipeline *m_pipeline; 81 + }; 82 + 67 83 #endif /* S5P_FIMC_H_ */