Question
STM32MP257F-EV1 DCMIPP Parallel interface for BT.656
Hi:
Does
I have STM32MP257F-EV1 board and another board can generate BT.656 video source without I2c setting.
I want to use DCMIPP parallel interface to get the image.
I modify the device tree in stm32mp257f-ev1.dts
/ {
...
clocks {
cec_clock: cec-clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <12000000>;
};
dummy_cam_clk: dummy-cam-clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <54000000>;
};
pad_clk: pad-clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <100000000>;
};
};
...
};
&dcmipp {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&dcmipp_parallel_pins_a>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
dcmipp_parallel_in: endpoint {
remote-endpoint = <&dummy_camera_out>;
bus-type = <6>;
bus-width = <8>;
pclk-sample = <0>;
};
};
};
};
&i2c2 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c2_pins_a>;
pinctrl-1 = <&i2c2_sleep_pins_a>;
i2c-scl-rising-time-ns = <100>;
i2c-scl-falling-time-ns = <13>;
clock-frequency = <400000>;
status = "okay";
/* spare dmas for other usage */
/delete-property/dmas;
/delete-property/dma-names;
dummy_camera: camera@3c {
compatible = "linux,dummy-sensor";
reg = <0x3c>;
clocks = <&dummy_cam_clk>;
clock-names = "xclk";
status = "okay";
port {
dummy_camera_out: endpoint {
remote-endpoint = <&dcmipp_parallel_in>;
bus-type = <6>;
bus-width = <8>;
};
};
};
...
};
I use the eth1 and eth2 pin for DCMIPP parallel in stm32mp25-pinctrl.dtsi
&pinctrl {
dcmipp_parallel_pins_a: dmicpp_parallel-0 {
pins {
pinmux = <STM32_PINMUX('C', 0, AF9)>, /* DCMI_D0 */
<STM32_PINMUX('C', 7, AF14)>, /* DCMI_D1 */
<STM32_PINMUX('C', 8, AF14)>, /* DCMI_D2 */
<STM32_PINMUX('C', 3, AF14)>, /* DCMI_D3 */
<STM32_PINMUX('G', 0, AF14)>, /* DCMI_D4 */
<STM32_PINMUX('C', 12, AF14)>, /* DCMI_D5 */
<STM32_PINMUX('C', 10, AF14)>, /* DCMI_D6 */
<STM32_PINMUX('C', 9, AF14)>, /* DCMI_D7 */
<STM32_PINMUX('J', 9, AF14)>; /* DCMI_PIXCLK */
bias-disable;
slew-rate = <3>;
};
};
....
}
and create a dummy V4l2 driver in v4l2-dummy-cam.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-async.h>
#include <media/v4l2-mediabus.h>
struct dummy_cam_dev {
struct v4l2_subdev sd;
struct media_pad pad;
};
#define to_dummy_cam(sd) container_of(sd, struct dummy_cam_dev, sd)
static int dummy_cam_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
static int dummy_cam_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index > 0)
return -EINVAL;
fse->code = fse->code ? fse->code : MEDIA_BUS_FMT_YUYV8_2X8;
fse->min_width = 720;
fse->max_width = 720;
fse->min_height = 480;
fse->max_height = 480;
return 0;
}
static int dummy_cam_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
format->format.width = 720;
format->format.height = 480;
format->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
format->format.field = V4L2_FIELD_NONE;
format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
static int dummy_cam_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
return 0;
}
static const struct v4l2_subdev_pad_ops dummy_cam_pad_ops = {
.init_cfg = dummy_cam_init_cfg,
.enum_mbus_code = dummy_cam_enum_mbus_code,
.enum_frame_size = dummy_cam_enum_frame_size,
.get_fmt = dummy_cam_get_fmt,
.set_fmt = dummy_cam_get_fmt,
};
static int dummy_cam_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_info(&client->dev, "Virtual stream %s\n", enable ? "ON" : "OFF");
return 0;
}
static const struct v4l2_subdev_video_ops dummy_cam_video_ops = {
.s_stream = dummy_cam_s_stream,
};
static const struct v4l2_subdev_ops dummy_cam_ops = {
.pad = &dummy_cam_pad_ops,
.video = &dummy_cam_video_ops,
};
static int dummy_cam_probe(struct i2c_client *client)
{
struct dummy_cam_dev *vdev;
int ret;
vdev = devm_kzalloc(&client->dev, sizeof(*vdev), GFP_KERNEL);
if (!vdev)
return -ENOMEM;
v4l2_i2c_subdev_init(&vdev->sd, client, &dummy_cam_ops);
vdev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
vdev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
vdev->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&vdev->sd.entity, 1, &vdev->pad);
if (ret)
return ret;
dev_info(&client->dev, "STM32MP25 Dummy Sensor Probed Successfully!\n");
return v4l2_async_register_subdev(&vdev->sd);
}
static void dummy_cam_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&sd->entity);
}
static const struct of_device_id dummy_cam_of_match[] = {
{ .compatible = "linux,dummy-sensor" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dummy_cam_of_match);
static struct i2c_driver dummy_cam_driver = {
.driver = {
.name = "stm32-dummy-sensor",
.of_match_table = dummy_cam_of_match,
},
.probe = dummy_cam_probe,
.remove = dummy_cam_remove,
};
module_i2c_driver(dummy_cam_driver);
MODULE_VERSION("0.0.1");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AI Collaborator");
do the following configuration in device bash shell
v4l2-ctl --list-devices
media-ctl -d /dev/media2 -r
media-ctl -d /dev/media2 -l "'stm32-dummy-sensor 0-003c':0 -> 'dcmipp_input':0[1]"
media-ctl -d /dev/media2 -l "'dcmipp_input':1 -> 'dcmipp_dump_postproc':0[1]"
media-ctl -d /dev/media2 -V "'stm32-dummy-sensor 0-003c':0[fmt:YUYV8_2X8/720x480 field:none]"
media-ctl -d /dev/media2 -V "'dcmipp_input':1[fmt:YUYV8_2X8/720x480 field:none]"
#check dcmipp_dump_capture dev name
media-ctl -d /dev/media2 -e "dcmipp_dump_capture"
v4l2-ctl -d /dev/video0 --set-fmt-video=width=720,height=480,pixelformat=YUYV
#check the frame capture
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=30
