This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

v4l2 FPGA capture crash in AM5728 based board

Other Parts Discussed in Thread: AM5728

Hi All

We are working on a custom board based on AM5728. We are capturing the video from FPGA. We are using ti-processor-sdk-linux-am57xx-

evm-02.00.02.11.

I have created v4l2_subdev based driver to capture the data, but the driver crashed at the subdev registration call.

This is my device tree:

evis_capture_driver1: evis_capture_driver1 {
                compatible = "EVIS,evis_capture_driver1";
                port {
                        cam1: endpoint {
                                remote-endpoint = <&vin4a>;
                                hsync-active = <0>;
                                vsync-active = <0>;
                                bus-width = <8>;
                                input-clock-freq = <27000000>;
                        };
                };
 };

&vip2 {
        status = "okay";
};


&vip3 {
        status = "okay";
};

&vin4a {
        status = "okay";
        endpoint {
                slave-mode;
                remote-endpoint = <&cam1>;
        };
};

When i try to insmod driver, it crashes with following logs:

Unable to handle kernel NULL pointer dereference at virtual address 0000013c

 Backtrace:
[   86.846734] [<c04aea94>] (match_of) from [<c04aeb10>] (v4l2_async_belongs+0x58/0xbc)
[   86.854513] [<c04aeab8>] (v4l2_async_belongs) from [<c04aeeac>] (v4l2_async_register_subdev+0x60/0xbc)
[   86.863857]  r7:c08e553c r6:c08e5554 r5:d4904010 r4:d4c7f64c
[   86.869583] [<c04aee4c>] (v4l2_async_register_subdev) from [<bf031400>] (evis_capture_probe+0x1e4/0x240 [evis_capture])
[   86.880410]  r9:d49040d4 r8:d4904080 r7:d4904010 r6:ee213210 r5:00000000 r4:ee213200
[   86.888237] [<bf03121c>] (evis_capture_probe [evis_capture]) from [<c03fc4ec>] (platform_drv_probe+0x4c/0xac)
[   86.898190]  r10:00000000 r9:d466b488 r8:00000043 r7:fffffdfb r6:bf031c74 r5:ee213210
[   86.906094]  r4:c092c5b4 r3:bf03121c
[   86.909702] [<c03fc4a0>] (platform_drv_probe) from [<c03fab54>] (driver_probe_device+0x184/0x2c4)
[   86.918609]  r7:bf031c74 r6:00000000 r5:ee213210 r4:c092c5b4
[   86.924328] [<c03fa9d0>] (driver_probe_device) from [<c03fad74>] (__driver_attach+0x94/0x98)
[   86.932800]  r9:d466b488 r8:2b994b9c r7:00000000 r6:ee213244 r5:bf031c74 r4:ee213210
[   86.940624] [<c03face0>] (__driver_attach) from [<c03f8ec8>] (bus_for_each_dev+0x70/0xa4)
[   86.948833]  r7:00000000 r6:c03face0 r5:bf031c74 r4:00000000
[   86.954553] [<c03f8e58>] (bus_for_each_dev) from [<c03fa5b4>] (driver_attach+0x24/0x28)
[   86.962588]  r6:c08d9898 r5:df970680 r4:bf031c74
[   86.967248] [<c03fa590>] (driver_attach) from [<c03fa25c>] (bus_add_driver+0x150/0x1f8)
[   86.975287] [<c03fa10c>] (bus_add_driver) from [<c03fb3e0>] (driver_register+0x80/0x100)
[   86.983409]  r7:d4940040 r6:c08b1120 r5:bf045000 r4:bf031c74
[   86.989127] [<c03fb360>] (driver_register) from [<c03fc430>] (__platform_driver_register+0x5c/0x64)
[   86.998209]  r5:bf045000 r4:c08b1120
[   87.001822] [<c03fc3d4>] (__platform_driver_register) from [<bf045020>] (evis_capture_driver_init+0x20/0x24 [evis_capture])


i have attached my driver code for your reference. Please let me know where can be the problem.

/*
 * drivers/media/evis/evis_capture.c
 *
 * EVIS FPGA driver
 *
 * Author: Amritpreet Singh <amritpreet.singh@logic-fruit.com>
 *
 * This package is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/module.h>
#include <linux/v4l2-mediabus.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-of.h>
#include <media/v4l2-ctrls.h>
#include <media/media-entity.h>
#include <linux/videodev2.h>

#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-common.h>
#include <media/v4l2-of.h>
#include "evis_capture.h"

/* Debug functions */
static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");

MODULE_AUTHOR("Amritpreet Singh");
MODULE_DESCRIPTION("EVIS Capture Driver");
MODULE_LICENSE("GPL");

struct evis_capture_info {
        u32 flags;
        struct v4l2_of_endpoint endpoint;
};

/*
static struct evis_capture_info* get_pdata(struct platform_device *pdev)
{
}
*/
struct evis_format {
        u32 code;
        u32 colorspace;
        u16 fmt;
        u16 order;
};

struct evis_framesize {
        u16 width;
        u16 height;                                                                                   
};



struct evis_capture {
	struct v4l2_subdev              subdev;
	#if defined(CONFIG_MEDIA_CONTROLLER)
	 struct media_pad                pad;
	#endif
	struct v4l2_ctrl_handler        handler;
	struct evis_capture_info       *info;
	struct v4l2_rect                frame;
	struct v4l2_clk                 *clk;
	const struct evis_format	*format;

};

static int evis_s_stream(struct v4l2_subdev *sd, int enable)
{
	v4l2_dbg(1, debug, sd, "Reached evis_s_stream\n");
	return 0;
}


static int evis_enum_mbus_code(struct v4l2_subdev *sd,
				  struct v4l2_subdev_pad_config *cfg,
				  struct v4l2_subdev_mbus_code_enum *code)
{
	u32 pad = code->pad;
	u32 index = code->index;

	printk(KERN_INFO "Entered eviscapture1 evis_enum_mbus_code");
	memset(code, 0, sizeof(*code));
	code->index = index;
	code->pad = pad;

	if (index != 0) {
		printk(KERN_INFO "eviscapture1 n index in evis_enum_mbus_code");
		return -EINVAL;
	}

	code->code = MEDIA_BUS_FMT_UYVY8_2X8;//MEDIA_BUS_FMT_UYVY8_1X16;

	return 0;
}

static int evis_get_format(struct v4l2_subdev *sd,
				  struct v4l2_subdev_pad_config *cfg,
				  struct v4l2_subdev_format *fmt)
{
	struct v4l2_mbus_framefmt *mf;
	printk(KERN_INFO "Entered eviscapture1 evis_get_format");
	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
                mf = v4l2_subdev_get_try_format(sd, cfg, 0);
                fmt->format = *mf;
                return 0;
        }

        mf = &fmt->format;
        mf->width       = 720;
        mf->height      = 576;
        mf->colorspace  = V4L2_COLORSPACE_JPEG;//done for discrete BT.601//V4L2_COLORSPACE_SMPTE170M;
        mf->code        = MEDIA_BUS_FMT_UYVY8_2X8;//MEDIA_BUS_FMT_UYVY8_1X16; 
        mf->field       = V4L2_FIELD_INTERLACED;

        return 0;
}

static int evis_set_format(struct v4l2_subdev *sd,
				  struct v4l2_subdev_pad_config *cfg,
				  struct v4l2_subdev_format *fmt)
{
	printk(KERN_INFO "Entered eviscapture1 evis_set_format");
        v4l2_dbg(1, debug, sd, "Reached set format");
	return 0;
}

static int
evis_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
	printk(KERN_INFO "Entered eviscapture1 evis_mbus_fmt");
        if (f == NULL) {
		printk(KERN_INFO "eviscapture1 f is NULL");
                return -EINVAL;
	}
        f->code = MEDIA_BUS_FMT_UYVY8_2X8;/*MEDIA_BUS_FMT_UYVY8_1X16;*/
        f->width = 720;
        f->height = 576;
        f->field = V4L2_FIELD_INTERLACED;
        f->colorspace = V4L2_COLORSPACE_JPEG;//done for discrete BT.601//V4L2_COLORSPACE_SMPTE170M;
        v4l2_dbg(1, debug, sd, "Reached mbus_fmt");
        return 0;
}

static const struct v4l2_subdev_core_ops evis_core_ops = {
	.log_status = v4l2_ctrl_subdev_log_status, 
        .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
        .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};

static int
evis_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
                                        u32 *code)
{
	printk(KERN_INFO "Entered eviscapture1 evis_enum_mbus_fmt");
        if (index) {
		printk(KERN_INFO "eviscapture1 evis_enum_mbus_fmt index not found");
                return -EINVAL;
	}

        *code = MEDIA_BUS_FMT_UYVY8_2X8;//MEDIA_BUS_FMT_UYVY8_1X16;
        return 0;
}

static const struct v4l2_subdev_video_ops evis_video_ops = {
	.enum_mbus_fmt = evis_enum_mbus_fmt,
	.g_mbus_fmt = evis_mbus_fmt,
	.try_mbus_fmt = evis_mbus_fmt,
	.s_mbus_fmt = evis_mbus_fmt,
	.s_stream = evis_s_stream,
};

static int evis_enum_frame_sizes(struct v4l2_subdev *sd,
                                    struct v4l2_subdev_pad_config *cfg,
                                    struct v4l2_subdev_frame_size_enum *fse)
{
	printk(KERN_INFO "Entered eviscapture1 evis_enum_frame_sizes");
	fse->min_width = 720;
	fse->max_width = 720;
	fse->max_height = 576;
	fse->min_height = 576;
        return 0;
}
static const struct v4l2_subdev_pad_ops evis_pad_ops = {
	.enum_mbus_code = evis_enum_mbus_code,
	.enum_frame_size = evis_enum_frame_sizes,
	.get_fmt = evis_get_format,
	.set_fmt = evis_set_format,
};

static const struct v4l2_subdev_ops evis_ops = {
	.core = &evis_core_ops,
	.video = &evis_video_ops,
	.pad = &evis_pad_ops,
};

static int evis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
        struct v4l2_mbus_framefmt *mf;

        mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
        return 0;
}

static const struct v4l2_subdev_internal_ops evis_subdev_internal_ops = {
        .open = evis_open,
};

static int evis_s_ctrl(struct v4l2_ctrl *ctrl)
{
	printk(KERN_INFO "Entered evis_s_ctrl");
	return 0;
}

//struct v4l2_subdev *g_sd;
static const struct v4l2_ctrl_ops evis_ctrl_ops = {
	.s_ctrl = evis_s_ctrl,
};

static int initialize_controls(struct evis_capture *capture)
{
	const struct v4l2_ctrl_ops *ops = &evis_ctrl_ops;
	struct v4l2_subdev *sd = &capture->subdev;
	struct v4l2_ctrl_handler *hdl = &capture->handler;
	int ret;
	
	printk(KERN_INFO "%s\n", __func__);

	ret = v4l2_ctrl_handler_init(hdl, 2);
	if (ret < 0) {
		printk(KERN_INFO "v4l2_ctrl_handler_init failed\n");
		return ret;
	}
	sd->ctrl_handler = hdl;
	if (capture->handler.error)
	                return capture->handler.error;

	return 0;
}

static struct evis_capture_info * get_pdata(struct platform_device *pdev)
{
	struct device_node *endpoint;
	struct v4l2_of_endpoint *v4l2_endpoint;
	struct evis_capture_info *pdata;

	printk(KERN_INFO "_get_pdata invoked\n");

	if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
                return pdev->dev.platform_data;
	printk(KERN_INFO "_get_pdata: DT Node found\n");

	endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
        if (!endpoint)
                return NULL;
	printk(KERN_INFO "_get_pdata: endpoint found\n");

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                goto done;

	v4l2_endpoint = &pdata->endpoint;
        v4l2_of_parse_endpoint(endpoint, v4l2_endpoint);

done:
        of_node_put(endpoint);
        return pdata;
}

static int evis_capture_probe(struct platform_device *pdev)
{
	struct v4l2_subdev *sd;
	struct evis_capture_info *info = get_pdata(pdev);
	struct evis_capture *capture;
	int ret;

	printk(KERN_INFO "Entered evis capture1 probe\n");
	capture = devm_kzalloc(&pdev->dev, sizeof(*capture), GFP_KERNEL);
	if (!capture) {
		printk(KERN_INFO "evis capture1 kzalloc failed\n");
		return -ENOMEM;
	}
	capture->info = info;
	/* Register with V4L2 layer as slave device */
	sd = &capture->subdev;
	v4l2_subdev_init(sd, &evis_ops);
	printk(KERN_INFO "evis capture1 subdev initialized\n");
	strlcpy(sd->name, "evis_capture_driver1", sizeof(sd->name));
	sd->internal_ops = &evis_subdev_internal_ops;
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		V4L2_SUBDEV_FL_HAS_EVENTS;
#if defined(CONFIG_MEDIA_CONTROLLER)
	printk(KERN_INFO "evis capture1 entered media controller\n");
	capture->pad.flags = MEDIA_PAD_FL_SOURCE;
	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
	ret = media_entity_init(&sd->entity, 1, &capture->pad, 0);
	if (ret < 0) {
		printk(KERN_INFO "EVIS capture driver failed to register media entity!!\n");
		return ret;
	}
#endif
	printk(KERN_INFO "evis capture1 exited media controller\n");
	ret = initialize_controls(capture);
	if (ret < 0)
		goto err_me;
	printk(KERN_INFO "evis capture1 controls initialized\n");
	printk(KERN_INFO "evis capture1 %s\n", pdev->dev.of_node->name);

//	ret = v4l2_async_register_subdev(&capture->subdev);
	ret = v4l2_async_register_subdev(sd);
        if (ret) {
		printk(KERN_INFO "evis capture1 v4l2_async_register_subdev failed\n");
                goto err_ctrls;
	} else
		printk(KERN_INFO "evis capture1 v4l2_async_register_subdev passed\n");

        dev_info(&pdev->dev, "%s EVIS Capture driver registered !!\n", sd->name);
        return 0;
err_ctrls:
	v4l2_ctrl_handler_free(sd->ctrl_handler);
err_me:
#if defined(CONFIG_MEDIA_CONTROLLER)
	media_entity_cleanup(&sd->entity);
#endif
	return ret;
}

static int evis_capture_remove(struct platform_device *pdev)
{
//	v4l2_async_unregister_subdev(g_sd);
//#if defined(CONFIG_MEDIA_CONTROLLER)
//	media_entity_cleanup(&g_sd->entity);
//#endif
	return 0;
}

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id evis_capture_of_match[] = {
	{ .compatible = "EVIS,evis_capture_driver1", },
	{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, evis_capture_of_match);
#endif

static struct platform_driver evis_capture_driver = {
	.driver = {
		.of_match_table = of_match_ptr(evis_capture_of_match),
		.owner = THIS_MODULE,
		.name = "evis_capture_driver1",
	},
	.probe = evis_capture_probe,
	.remove = evis_capture_remove,
};

module_platform_driver(evis_capture_driver);