cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adv748x-csi2.c (8315B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Driver for Analog Devices ADV748X CSI-2 Transmitter
      4 *
      5 * Copyright (C) 2017 Renesas Electronics Corp.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/mutex.h>
     10
     11#include <media/v4l2-ctrls.h>
     12#include <media/v4l2-device.h>
     13#include <media/v4l2-ioctl.h>
     14
     15#include "adv748x.h"
     16
     17int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
     18{
     19	return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
     20}
     21
     22/**
     23 * adv748x_csi2_register_link : Register and link internal entities
     24 *
     25 * @tx: CSI2 private entity
     26 * @v4l2_dev: Video registration device
     27 * @src: Source subdevice to establish link
     28 * @src_pad: Pad number of source to link to this @tx
     29 * @enable: Link enabled flag
     30 *
     31 * Ensure that the subdevice is registered against the v4l2_device, and link the
     32 * source pad to the sink pad of the CSI2 bus entity.
     33 */
     34static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
     35				      struct v4l2_device *v4l2_dev,
     36				      struct v4l2_subdev *src,
     37				      unsigned int src_pad,
     38				      bool enable)
     39{
     40	int ret;
     41
     42	if (!src->v4l2_dev) {
     43		ret = v4l2_device_register_subdev(v4l2_dev, src);
     44		if (ret)
     45			return ret;
     46	}
     47
     48	ret = media_create_pad_link(&src->entity, src_pad,
     49				    &tx->sd.entity, ADV748X_CSI2_SINK,
     50				    enable ? MEDIA_LNK_FL_ENABLED : 0);
     51	if (ret)
     52		return ret;
     53
     54	if (enable)
     55		tx->src = src;
     56
     57	return 0;
     58}
     59
     60/* -----------------------------------------------------------------------------
     61 * v4l2_subdev_internal_ops
     62 *
     63 * We use the internal registered operation to be able to ensure that our
     64 * incremental subdevices (not connected in the forward path) can be registered
     65 * against the resulting video path and media device.
     66 */
     67
     68static int adv748x_csi2_registered(struct v4l2_subdev *sd)
     69{
     70	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
     71	struct adv748x_state *state = tx->state;
     72	int ret;
     73
     74	adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB",
     75			sd->name);
     76
     77	/*
     78	 * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output
     79	 * HDMI.
     80	 *
     81	 * The HDMI->TXA link is enabled by default, as is the AFE->TXB one.
     82	 */
     83	if (is_afe_enabled(state)) {
     84		ret = adv748x_csi2_register_link(tx, sd->v4l2_dev,
     85						 &state->afe.sd,
     86						 ADV748X_AFE_SOURCE,
     87						 is_txb(tx));
     88		if (ret)
     89			return ret;
     90
     91		/* TXB can output AFE signals only. */
     92		if (is_txb(tx))
     93			state->afe.tx = tx;
     94	}
     95
     96	/* Register link to HDMI for TXA only. */
     97	if (is_txb(tx) || !is_hdmi_enabled(state))
     98		return 0;
     99
    100	ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd,
    101					 ADV748X_HDMI_SOURCE, true);
    102	if (ret)
    103		return ret;
    104
    105	/* The default HDMI output is TXA. */
    106	state->hdmi.tx = tx;
    107
    108	return 0;
    109}
    110
    111static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
    112	.registered = adv748x_csi2_registered,
    113};
    114
    115/* -----------------------------------------------------------------------------
    116 * v4l2_subdev_video_ops
    117 */
    118
    119static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable)
    120{
    121	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    122	struct v4l2_subdev *src;
    123
    124	src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]);
    125	if (!src)
    126		return -EPIPE;
    127
    128	return v4l2_subdev_call(src, video, s_stream, enable);
    129}
    130
    131static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
    132	.s_stream = adv748x_csi2_s_stream,
    133};
    134
    135/* -----------------------------------------------------------------------------
    136 * v4l2_subdev_pad_ops
    137 *
    138 * The CSI2 bus pads are ignorant to the data sizes or formats.
    139 * But we must support setting the pad formats for format propagation.
    140 */
    141
    142static struct v4l2_mbus_framefmt *
    143adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
    144			    struct v4l2_subdev_state *sd_state,
    145			    unsigned int pad, u32 which)
    146{
    147	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    148
    149	if (which == V4L2_SUBDEV_FORMAT_TRY)
    150		return v4l2_subdev_get_try_format(sd, sd_state, pad);
    151
    152	return &tx->format;
    153}
    154
    155static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
    156				   struct v4l2_subdev_state *sd_state,
    157				   struct v4l2_subdev_format *sdformat)
    158{
    159	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    160	struct adv748x_state *state = tx->state;
    161	struct v4l2_mbus_framefmt *mbusformat;
    162
    163	mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
    164						 sdformat->which);
    165	if (!mbusformat)
    166		return -EINVAL;
    167
    168	mutex_lock(&state->mutex);
    169
    170	sdformat->format = *mbusformat;
    171
    172	mutex_unlock(&state->mutex);
    173
    174	return 0;
    175}
    176
    177static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
    178				   struct v4l2_subdev_state *sd_state,
    179				   struct v4l2_subdev_format *sdformat)
    180{
    181	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    182	struct adv748x_state *state = tx->state;
    183	struct v4l2_mbus_framefmt *mbusformat;
    184	int ret = 0;
    185
    186	mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
    187						 sdformat->which);
    188	if (!mbusformat)
    189		return -EINVAL;
    190
    191	mutex_lock(&state->mutex);
    192
    193	if (sdformat->pad == ADV748X_CSI2_SOURCE) {
    194		const struct v4l2_mbus_framefmt *sink_fmt;
    195
    196		sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
    197						       ADV748X_CSI2_SINK,
    198						       sdformat->which);
    199
    200		if (!sink_fmt) {
    201			ret = -EINVAL;
    202			goto unlock;
    203		}
    204
    205		sdformat->format = *sink_fmt;
    206	}
    207
    208	*mbusformat = sdformat->format;
    209
    210unlock:
    211	mutex_unlock(&state->mutex);
    212
    213	return ret;
    214}
    215
    216static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
    217					struct v4l2_mbus_config *config)
    218{
    219	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    220
    221	if (pad != ADV748X_CSI2_SOURCE)
    222		return -EINVAL;
    223
    224	config->type = V4L2_MBUS_CSI2_DPHY;
    225	config->bus.mipi_csi2.num_data_lanes = tx->active_lanes;
    226
    227	return 0;
    228}
    229
    230static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
    231	.get_fmt = adv748x_csi2_get_format,
    232	.set_fmt = adv748x_csi2_set_format,
    233	.get_mbus_config = adv748x_csi2_get_mbus_config,
    234};
    235
    236/* -----------------------------------------------------------------------------
    237 * v4l2_subdev_ops
    238 */
    239
    240static const struct v4l2_subdev_ops adv748x_csi2_ops = {
    241	.video = &adv748x_csi2_video_ops,
    242	.pad = &adv748x_csi2_pad_ops,
    243};
    244
    245/* -----------------------------------------------------------------------------
    246 * Subdev module and controls
    247 */
    248
    249int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate)
    250{
    251	struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
    252
    253	if (!tx->pixel_rate)
    254		return -EINVAL;
    255
    256	return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate);
    257}
    258
    259static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl)
    260{
    261	switch (ctrl->id) {
    262	case V4L2_CID_PIXEL_RATE:
    263		return 0;
    264	default:
    265		return -EINVAL;
    266	}
    267}
    268
    269static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = {
    270	.s_ctrl = adv748x_csi2_s_ctrl,
    271};
    272
    273static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
    274{
    275
    276	v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1);
    277
    278	tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl,
    279					   &adv748x_csi2_ctrl_ops,
    280					   V4L2_CID_PIXEL_RATE, 1, INT_MAX,
    281					   1, 1);
    282
    283	tx->sd.ctrl_handler = &tx->ctrl_hdl;
    284	if (tx->ctrl_hdl.error) {
    285		v4l2_ctrl_handler_free(&tx->ctrl_hdl);
    286		return tx->ctrl_hdl.error;
    287	}
    288
    289	return v4l2_ctrl_handler_setup(&tx->ctrl_hdl);
    290}
    291
    292int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
    293{
    294	int ret;
    295
    296	if (!is_tx_enabled(tx))
    297		return 0;
    298
    299	adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops,
    300			    MEDIA_ENT_F_VID_IF_BRIDGE,
    301			    is_txa(tx) ? "txa" : "txb");
    302
    303	/* Ensure that matching is based upon the endpoint fwnodes */
    304	tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
    305
    306	/* Register internal ops for incremental subdev registration */
    307	tx->sd.internal_ops = &adv748x_csi2_internal_ops;
    308
    309	tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
    310	tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
    311
    312	ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS,
    313				     tx->pads);
    314	if (ret)
    315		return ret;
    316
    317	ret = adv748x_csi2_init_controls(tx);
    318	if (ret)
    319		goto err_free_media;
    320
    321	ret = v4l2_async_register_subdev(&tx->sd);
    322	if (ret)
    323		goto err_free_ctrl;
    324
    325	return 0;
    326
    327err_free_ctrl:
    328	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
    329err_free_media:
    330	media_entity_cleanup(&tx->sd.entity);
    331
    332	return ret;
    333}
    334
    335void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
    336{
    337	if (!is_tx_enabled(tx))
    338		return;
    339
    340	v4l2_async_unregister_subdev(&tx->sd);
    341	media_entity_cleanup(&tx->sd.entity);
    342	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
    343}