From 82a0bc41cd1158ba7c5beac72c0bc1e48eb71e45 Mon Sep 17 00:00:00 2001 From: Erik Tagirov Date: Wed, 20 Oct 2021 09:51:26 +0200 Subject: [PATCH 001/155] configs: Add CONFIG_FB_SIMPLE to bcmrpi3_defconfig See: https://github.com/raspberrypi/linux/pull/4640 Signed-off-by: Erik Tagirov --- arch/arm64/configs/bcmrpi3_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index 00352da73009..a137f1c0721a 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -885,6 +885,7 @@ CONFIG_DRM_GUD=m CONFIG_FB=y CONFIG_FB_BCM2708=y CONFIG_FB_UDL=m +CONFIG_FB_SIMPLE=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m CONFIG_BACKLIGHT_RPI=m -- Gitee From fe35952f0b651b8539df6b31cf4f7584d7e9997e Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:41:55 +0100 Subject: [PATCH 002/155] media: i2c: imx219: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/imx219.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 79faa8cce94e..6aed851865ec 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -681,7 +681,7 @@ static void imx219_set_default_format(struct imx219 *imx219) fmt = &imx219->fmt; fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; - fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->colorspace = V4L2_COLORSPACE_RAW; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->colorspace, @@ -877,7 +877,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd, static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt) { - fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->colorspace = V4L2_COLORSPACE_RAW; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->colorspace, -- Gitee From 7c27b0bb83bf0c6c5c20c9380289ab2bc68aaebe Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:44:01 +0100 Subject: [PATCH 003/155] media: i2c: imx290: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/imx290.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index a26106c41cc6..def912308daa 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -885,7 +885,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, fmt->format.code = imx290->formats[i].code; fmt->format.field = V4L2_FIELD_NONE; - fmt->format.colorspace = V4L2_COLORSPACE_SRGB; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; fmt->format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); fmt->format.quantization = -- Gitee From 33ddab5a8306706cb73040c86a97c36ca7783f6e Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:44:43 +0100 Subject: [PATCH 004/155] media: i2c: imx477: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/imx477.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx477.c b/drivers/media/i2c/imx477.c index 05cb530d331e..cd3296f8ab41 100644 --- a/drivers/media/i2c/imx477.c +++ b/drivers/media/i2c/imx477.c @@ -1471,7 +1471,7 @@ static int imx477_enum_frame_size(struct v4l2_subdev *sd, static void imx477_reset_colorspace(struct v4l2_mbus_framefmt *fmt) { - fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->colorspace = V4L2_COLORSPACE_RAW; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->colorspace, -- Gitee From 1e944e9c550289900f5f46795b4fae5bac24ca90 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:45:07 +0100 Subject: [PATCH 005/155] media: i2c: imx519: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/imx519.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx519.c b/drivers/media/i2c/imx519.c index 4e98704a6834..675b4a94e065 100644 --- a/drivers/media/i2c/imx519.c +++ b/drivers/media/i2c/imx519.c @@ -1317,7 +1317,7 @@ static int imx519_enum_frame_size(struct v4l2_subdev *sd, static void imx519_reset_colorspace(struct v4l2_mbus_framefmt *fmt) { - fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->colorspace = V4L2_COLORSPACE_RAW; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, fmt->colorspace, -- Gitee From 86ef9df63c79e52c7612e93bfae34fb3e8368125 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:47:00 +0100 Subject: [PATCH 006/155] media: i2c: ov5647: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/ov5647.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 98a5329d68fb..03c92e419806 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -601,7 +601,7 @@ static struct ov5647_mode supported_modes_8bit[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .field = V4L2_FIELD_NONE, .width = 640, .height = 480 @@ -627,7 +627,7 @@ static struct ov5647_mode supported_modes_10bit[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .field = V4L2_FIELD_NONE, .width = 2592, .height = 1944 @@ -651,7 +651,7 @@ static struct ov5647_mode supported_modes_10bit[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .field = V4L2_FIELD_NONE, .width = 1920, .height = 1080 @@ -674,7 +674,7 @@ static struct ov5647_mode supported_modes_10bit[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .field = V4L2_FIELD_NONE, .width = 1296, .height = 972 @@ -698,7 +698,7 @@ static struct ov5647_mode supported_modes_10bit[] = { { .format = { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, + .colorspace = V4L2_COLORSPACE_RAW, .field = V4L2_FIELD_NONE, .width = 640, .height = 480 -- Gitee From 1141e62f7ecbd775830ac71b3dcc91ca2ca59eda Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:47:20 +0100 Subject: [PATCH 007/155] media: i2c: ov9281: Sensor should report RAW color space Tested on Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/ov9281.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov9281.c b/drivers/media/i2c/ov9281.c index a6ffcdd47b21..f7ec4470d356 100644 --- a/drivers/media/i2c/ov9281.c +++ b/drivers/media/i2c/ov9281.c @@ -507,7 +507,7 @@ static int ov9281_set_fmt(struct v4l2_subdev *sd, fmt->format.width = mode->width; fmt->format.height = mode->height; fmt->format.field = V4L2_FIELD_NONE; - fmt->format.colorspace = V4L2_COLORSPACE_SRGB; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; fmt->format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); fmt->format.quantization = @@ -557,7 +557,7 @@ static int ov9281_get_fmt(struct v4l2_subdev *sd, fmt->format.height = mode->height; fmt->format.code = ov9281->code; fmt->format.field = V4L2_FIELD_NONE; - fmt->format.colorspace = V4L2_COLORSPACE_SRGB; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; fmt->format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->format.colorspace); fmt->format.quantization = @@ -908,7 +908,7 @@ static int ov9281_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) try_fmt->height = def_mode->height; try_fmt->code = MEDIA_BUS_FMT_Y10_1X10; try_fmt->field = V4L2_FIELD_NONE; - try_fmt->colorspace = V4L2_COLORSPACE_SRGB; + try_fmt->colorspace = V4L2_COLORSPACE_RAW; try_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(try_fmt->colorspace); try_fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, try_fmt->colorspace, -- Gitee From 920917bd91f10ed07fddc3356e0dc96828f525cf Mon Sep 17 00:00:00 2001 From: David Plowman Date: Thu, 21 Oct 2021 14:49:15 +0100 Subject: [PATCH 008/155] vc04_services: isp: Report input node as wanting full range RAW color space RAW color spaces are more usually reported as having full range quantization. Tested using libcamera. Signed-off-by: David Plowman --- drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c index 08dce8bba9bb..df57c2f74a03 100644 --- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c @@ -1032,7 +1032,9 @@ static int bcm2835_isp_node_try_fmt(struct file *file, void *priv, /* In all cases, we only support the defaults for these: */ f->fmt.pix.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(f->fmt.pix.colorspace); f->fmt.pix.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(f->fmt.pix.colorspace); - is_rgb = f->fmt.pix.colorspace == V4L2_COLORSPACE_SRGB; + /* RAW counts as sRGB here so that we get full range. */ + is_rgb = f->fmt.pix.colorspace == V4L2_COLORSPACE_SRGB || + f->fmt.pix.colorspace == V4L2_COLORSPACE_RAW; f->fmt.pix.quantization = V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, f->fmt.pix.colorspace, f->fmt.pix.ycbcr_enc); -- Gitee From 0ead67f0e1939b2ab6a453e3f6480aca7ccd08e1 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 23 Sep 2020 15:16:18 +0100 Subject: [PATCH 009/155] media/bcm2835-unicam: Parse pad numbers correctly The driver was making big assumptions about the source device using pad 0 and 1, which doesn't follow for more complex devices where Unicam's source device may be a sink device for something else. Read the pad numbers through media controller, and reference them appropriately. Signed-off-by: Dave Stevenson --- .../media/platform/bcm2835/bcm2835-unicam.c | 89 ++++++++++++------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c index 59163f93b207..bbcaa1bd419f 100644 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -380,6 +380,8 @@ struct unicam_node { int open; bool streaming; unsigned int pad_id; + /* Source pad id on the sensor for this node */ + unsigned int src_pad_id; /* Pointer pointing to current v4l2_buffer */ struct unicam_buffer *cur_frm; /* Pointer pointing to next v4l2_buffer */ @@ -590,7 +592,7 @@ static int __subdev_get_format(struct unicam_device *dev, { struct v4l2_subdev_format sd_fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = pad_id + .pad = dev->node[pad_id].src_pad_id, }; int ret; @@ -612,7 +614,7 @@ static int __subdev_set_format(struct unicam_device *dev, { struct v4l2_subdev_format sd_fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = pad_id + .pad = dev->node[pad_id].src_pad_id, }; int ret; @@ -1977,7 +1979,7 @@ static int unicam_enum_framesizes(struct file *file, void *priv, fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; fse.index = fsize->index; - fse.pad = node->pad_id; + fse.pad = node->src_pad_id; ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse); if (ret) @@ -2002,6 +2004,7 @@ static int unicam_enum_frameintervals(struct file *file, void *priv, const struct unicam_fmt *fmt; struct v4l2_subdev_frame_interval_enum fie = { .index = fival->index, + .pad = node->src_pad_id, .width = fival->width, .height = fival->height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -2093,8 +2096,13 @@ static int unicam_enum_dv_timings(struct file *file, void *priv, { struct unicam_node *node = video_drvdata(file); struct unicam_device *dev = node->dev; + int ret; + + timings->pad = node->src_pad_id; + ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); + timings->pad = node->pad_id; - return v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); + return ret; } static int unicam_dv_timings_cap(struct file *file, void *priv, @@ -2102,8 +2110,13 @@ static int unicam_dv_timings_cap(struct file *file, void *priv, { struct unicam_node *node = video_drvdata(file); struct unicam_device *dev = node->dev; + int ret; + + cap->pad = node->src_pad_id; + ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); + cap->pad = node->pad_id; - return v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); + return ret; } static int unicam_subscribe_event(struct v4l2_fh *fh, @@ -2374,14 +2387,12 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, */ fmt = get_first_supported_format(unicam); - if (!fmt) - /* No compatible formats */ - return -EINVAL; - - mbus_fmt.code = fmt->code; - ret = __subdev_set_format(unicam, &mbus_fmt, pad_id); - if (ret) - return -EINVAL; + if (fmt) { + mbus_fmt.code = fmt->code; + ret = __subdev_set_format(unicam, &mbus_fmt, pad_id); + if (ret) + return -EINVAL; + } } if (mbus_fmt.field != V4L2_FIELD_NONE) { /* Interlaced not supported - disable it now. */ @@ -2391,7 +2402,8 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, return -EINVAL; } - node->v_fmt.fmt.pix.pixelformat = fmt->fourcc ? fmt->fourcc + if (fmt) + node->v_fmt.fmt.pix.pixelformat = fmt->fourcc ? fmt->fourcc : fmt->repacked_fourcc; } else { /* Fix this node format as embedded data. */ @@ -2404,7 +2416,8 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, node->fmt = fmt; /* Read current subdev format */ - unicam_reset_format(node); + if (fmt) + unicam_reset_format(node); if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) { v4l2_std_id tvnorms; @@ -2493,6 +2506,7 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, unicam_err(unicam, "Unable to allocate dummy buffer.\n"); return -ENOMEM; } + if (pad_id == METADATA_PAD || !v4l2_subdev_has_op(unicam->sensor, video, s_std)) { v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); @@ -2551,7 +2565,8 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, node->registered = true; if (pad_id != METADATA_PAD || unicam->sensor_embedded_data) { - ret = media_create_pad_link(&unicam->sensor->entity, pad_id, + ret = media_create_pad_link(&unicam->sensor->entity, + node->src_pad_id, &node->video_dev.entity, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); @@ -2583,8 +2598,10 @@ static void unregister_nodes(struct unicam_device *unicam) } } -static int unicam_probe_complete(struct unicam_device *unicam) +static int unicam_async_complete(struct v4l2_async_notifier *notifier) { + struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev); + unsigned int i, source_pads = 0; int ret; unicam->v4l2_dev.notify = unicam_notify; @@ -2593,7 +2610,20 @@ static int unicam_probe_complete(struct unicam_device *unicam) if (!unicam->sensor_config) return -ENOMEM; - unicam->sensor_embedded_data = (unicam->sensor->entity.num_pads >= 2); + for (i = 0; i < unicam->sensor->entity.num_pads; i++) { + if (unicam->sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) { + if (source_pads < MAX_NODES) { + unicam->node[source_pads].src_pad_id = i; + unicam_err(unicam, "source pad %u is index %u\n", + source_pads, i); + } + source_pads++; + } + } + if (!source_pads) { + unicam_err(unicam, "No source pads on sensor.\n"); + goto unregister; + } ret = register_node(unicam, &unicam->node[IMAGE_PAD], V4L2_BUF_TYPE_VIDEO_CAPTURE, IMAGE_PAD); @@ -2602,11 +2632,15 @@ static int unicam_probe_complete(struct unicam_device *unicam) goto unregister; } - ret = register_node(unicam, &unicam->node[METADATA_PAD], - V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD); - if (ret) { - unicam_err(unicam, "Unable to register metadata video device.\n"); - goto unregister; + if (source_pads >= 2) { + unicam->sensor_embedded_data = true; + + ret = register_node(unicam, &unicam->node[METADATA_PAD], + V4L2_BUF_TYPE_META_CAPTURE, METADATA_PAD); + if (ret) { + unicam_err(unicam, "Unable to register metadata video device.\n"); + goto unregister; + } } ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); @@ -2629,13 +2663,6 @@ unregister: return ret; } -static int unicam_async_complete(struct v4l2_async_notifier *notifier) -{ - struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev); - - return unicam_probe_complete(unicam); -} - static const struct v4l2_async_notifier_operations unicam_async_ops = { .bound = unicam_async_bound, .complete = unicam_async_complete, @@ -2744,7 +2771,7 @@ static int of_unicam_connect_subdevs(struct unicam_device *dev) dev->notifier.ops = &unicam_async_ops; dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - dev->asd.match.fwnode = of_fwnode_handle(sensor_node); + dev->asd.match.fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep_node)); ret = v4l2_async_notifier_add_subdev(&dev->notifier, &dev->asd); if (ret) { unicam_err(dev, "Error adding subdevice: %d\n", ret); -- Gitee From 7e43e899511b76e86f5ea3c4b42ca09ebf6c1806 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 15 Oct 2021 17:57:27 +0100 Subject: [PATCH 010/155] media/bcm2835-unicam: Add support for configuration via MC API Adds Media Controller API support for more complex pipelines. libcamera is about to switch to using this mechanism for configuring sensors. This can be enabled by either a module parameter, or device tree. Various functions have been moved to group video-centric and mc-centric functions together. Based on a similar conversion done to ti-vpe. Signed-off-by: Dave Stevenson --- .../media/platform/bcm2835/bcm2835-unicam.c | 2125 ++++++++++------- 1 file changed, 1314 insertions(+), 811 deletions(-) diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c index bbcaa1bd419f..d4a005657ca2 100644 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -81,6 +81,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-3"); +static int media_controller; +module_param(media_controller, int, 0644); +MODULE_PARM_DESC(media_controller, "Use media controller API"); + #define unicam_dbg(level, dev, fmt, arg...) \ v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ##arg) #define unicam_info(dev, fmt, arg...) \ @@ -117,7 +121,7 @@ MODULE_PARM_DESC(debug, "Debug level 0-3"); #define MIN_WIDTH 16 #define MIN_HEIGHT 16 /* Default size of the embedded buffer */ -#define UNICAM_EMBEDDED_SIZE 8192 +#define UNICAM_EMBEDDED_SIZE 16384 /* * Size of the dummy buffer. Can be any size really, but the DMA @@ -131,6 +135,22 @@ enum pad_types { MAX_NODES }; +#define MASK_CS_DEFAULT BIT(V4L2_COLORSPACE_DEFAULT) +#define MASK_CS_SMPTE170M BIT(V4L2_COLORSPACE_SMPTE170M) +#define MASK_CS_SMPTE240M BIT(V4L2_COLORSPACE_SMPTE240M) +#define MASK_CS_REC709 BIT(V4L2_COLORSPACE_REC709) +#define MASK_CS_BT878 BIT(V4L2_COLORSPACE_BT878) +#define MASK_CS_470_M BIT(V4L2_COLORSPACE_470_SYSTEM_M) +#define MASK_CS_470_BG BIT(V4L2_COLORSPACE_470_SYSTEM_BG) +#define MASK_CS_JPEG BIT(V4L2_COLORSPACE_JPEG) +#define MASK_CS_SRGB BIT(V4L2_COLORSPACE_SRGB) +#define MASK_CS_OPRGB BIT(V4L2_COLORSPACE_OPRGB) +#define MASK_CS_BT2020 BIT(V4L2_COLORSPACE_BT2020) +#define MASK_CS_RAW BIT(V4L2_COLORSPACE_RAW) +#define MASK_CS_DCI_P3 BIT(V4L2_COLORSPACE_DCI_P3) + +#define MAX_COLORSPACE 32 + /* * struct unicam_fmt - Unicam media bus format information * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a. @@ -139,8 +159,14 @@ enum pad_types { * @code: V4L2 media bus format code. * @depth: Bits per pixel as delivered from the source. * @csi_dt: CSI data type. + * @valid_colorspaces: Bitmask of valid colorspaces so that the Media Controller + * centric try_fmt can validate the colorspace and pass + * v4l2-compliance. * @check_variants: Flag to denote that there are multiple mediabus formats * still in the list that could match this V4L2 format. + * @mc_skip: Media Controller shouldn't list this format via ENUM_FMT as it is + * a duplicate of an earlier format. + * @metadata_fmt: This format only applies to the metadata pad. */ struct unicam_fmt { u32 fourcc; @@ -148,7 +174,10 @@ struct unicam_fmt { u32 code; u8 depth; u8 csi_dt; - u8 check_variants; + u32 valid_colorspaces; + u8 check_variants:1; + u8 mc_skip:1; + u8 metadata_fmt:1; }; static const struct unicam_fmt formats[] = { @@ -159,173 +188,216 @@ static const struct unicam_fmt formats[] = { .depth = 16, .csi_dt = 0x1e, .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_UYVY, .code = MEDIA_BUS_FMT_UYVY8_2X8, .depth = 16, .csi_dt = 0x1e, .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_YVYU, .code = MEDIA_BUS_FMT_YVYU8_2X8, .depth = 16, .csi_dt = 0x1e, .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_VYUY, .code = MEDIA_BUS_FMT_VYUY8_2X8, .depth = 16, .csi_dt = 0x1e, .check_variants = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_YUYV, .code = MEDIA_BUS_FMT_YUYV8_1X16, .depth = 16, .csi_dt = 0x1e, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_UYVY, .code = MEDIA_BUS_FMT_UYVY8_1X16, .depth = 16, .csi_dt = 0x1e, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_YVYU, .code = MEDIA_BUS_FMT_YVYU8_1X16, .depth = 16, .csi_dt = 0x1e, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { .fourcc = V4L2_PIX_FMT_VYUY, .code = MEDIA_BUS_FMT_VYUY8_1X16, .depth = 16, .csi_dt = 0x1e, + .mc_skip = 1, + .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 | + MASK_CS_JPEG, }, { /* RGB Formats */ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ .code = MEDIA_BUS_FMT_RGB565_2X8_LE, .depth = 16, .csi_dt = 0x22, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ .code = MEDIA_BUS_FMT_RGB565_2X8_BE, .depth = 16, - .csi_dt = 0x22 + .csi_dt = 0x22, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, .depth = 16, .csi_dt = 0x21, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, .depth = 16, .csi_dt = 0x21, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ .code = MEDIA_BUS_FMT_RGB888_1X24, .depth = 24, .csi_dt = 0x24, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ .code = MEDIA_BUS_FMT_BGR888_1X24, .depth = 24, .csi_dt = 0x24, + .valid_colorspaces = MASK_CS_SRGB, }, { .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ .code = MEDIA_BUS_FMT_ARGB8888_1X32, .depth = 32, .csi_dt = 0x0, + .valid_colorspaces = MASK_CS_SRGB, }, { /* Bayer Formats */ .fourcc = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .depth = 8, .csi_dt = 0x2a, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .depth = 8, .csi_dt = 0x2a, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .depth = 8, .csi_dt = 0x2a, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .depth = 8, .csi_dt = 0x2a, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR10P, .repacked_fourcc = V4L2_PIX_FMT_SBGGR10, .code = MEDIA_BUS_FMT_SBGGR10_1X10, .depth = 10, .csi_dt = 0x2b, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG10P, .repacked_fourcc = V4L2_PIX_FMT_SGBRG10, .code = MEDIA_BUS_FMT_SGBRG10_1X10, .depth = 10, .csi_dt = 0x2b, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG10P, .repacked_fourcc = V4L2_PIX_FMT_SGRBG10, .code = MEDIA_BUS_FMT_SGRBG10_1X10, .depth = 10, .csi_dt = 0x2b, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB10P, .repacked_fourcc = V4L2_PIX_FMT_SRGGB10, .code = MEDIA_BUS_FMT_SRGGB10_1X10, .depth = 10, .csi_dt = 0x2b, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR12P, .repacked_fourcc = V4L2_PIX_FMT_SBGGR12, .code = MEDIA_BUS_FMT_SBGGR12_1X12, .depth = 12, .csi_dt = 0x2c, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG12P, .repacked_fourcc = V4L2_PIX_FMT_SGBRG12, .code = MEDIA_BUS_FMT_SGBRG12_1X12, .depth = 12, .csi_dt = 0x2c, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG12P, .repacked_fourcc = V4L2_PIX_FMT_SGRBG12, .code = MEDIA_BUS_FMT_SGRBG12_1X12, .depth = 12, .csi_dt = 0x2c, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB12P, .repacked_fourcc = V4L2_PIX_FMT_SRGGB12, .code = MEDIA_BUS_FMT_SRGGB12_1X12, .depth = 12, .csi_dt = 0x2c, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR14P, .repacked_fourcc = V4L2_PIX_FMT_SBGGR14, .code = MEDIA_BUS_FMT_SBGGR14_1X14, .depth = 14, .csi_dt = 0x2d, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG14P, .repacked_fourcc = V4L2_PIX_FMT_SGBRG14, .code = MEDIA_BUS_FMT_SGBRG14_1X14, .depth = 14, .csi_dt = 0x2d, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG14P, .repacked_fourcc = V4L2_PIX_FMT_SGRBG14, .code = MEDIA_BUS_FMT_SGRBG14_1X14, .depth = 14, .csi_dt = 0x2d, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB14P, .repacked_fourcc = V4L2_PIX_FMT_SRGGB14, .code = MEDIA_BUS_FMT_SRGGB14_1X14, .depth = 14, .csi_dt = 0x2d, + .valid_colorspaces = MASK_CS_RAW, }, { /* * 16 bit Bayer formats could be supported, but there is no CSI2 @@ -338,30 +410,35 @@ static const struct unicam_fmt formats[] = { .code = MEDIA_BUS_FMT_Y8_1X8, .depth = 8, .csi_dt = 0x2a, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_Y10P, .repacked_fourcc = V4L2_PIX_FMT_Y10, .code = MEDIA_BUS_FMT_Y10_1X10, .depth = 10, .csi_dt = 0x2b, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_Y12P, .repacked_fourcc = V4L2_PIX_FMT_Y12, .code = MEDIA_BUS_FMT_Y12_1X12, .depth = 12, .csi_dt = 0x2c, + .valid_colorspaces = MASK_CS_RAW, }, { .fourcc = V4L2_PIX_FMT_Y14P, .repacked_fourcc = V4L2_PIX_FMT_Y14, .code = MEDIA_BUS_FMT_Y14_1X14, .depth = 14, .csi_dt = 0x2d, + .valid_colorspaces = MASK_CS_RAW, }, /* Embedded data format */ { .fourcc = V4L2_META_FMT_SENSOR_DATA, .code = MEDIA_BUS_FMT_SENSOR_DATA, .depth = 8, + .metadata_fmt = 1, } }; @@ -406,6 +483,7 @@ struct unicam_node { struct unicam_device *dev; struct media_pad pad; unsigned int embedded_lines; + struct media_pipeline pipe; /* * Dummy buffer intended to be used by unicam * if we have no other queued buffers to swap to. @@ -459,6 +537,8 @@ struct unicam_device { struct unicam_node node[MAX_NODES]; struct v4l2_ctrl_handler ctrl_handler; + + bool mc_api; }; static inline struct unicam_device * @@ -908,6 +988,7 @@ static irqreturn_t unicam_isr(int irq, void *dev) return IRQ_HANDLED; } +/* V4L2 Common IOCTLs */ static int unicam_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -925,6 +1006,38 @@ static int unicam_querycap(struct file *file, void *priv, return 0; } +static int unicam_log_status(struct file *file, void *fh) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + u32 reg; + + /* status for sub devices */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status); + + unicam_info(dev, "-----Receiver status-----\n"); + unicam_info(dev, "V4L2 width/height: %ux%u\n", + node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height); + unicam_info(dev, "Mediabus format: %08x\n", node->fmt->code); + unicam_info(dev, "V4L2 format: %08x\n", + node->v_fmt.fmt.pix.pixelformat); + reg = reg_read(dev, UNICAM_IPIPE); + unicam_info(dev, "Unpacking/packing: %u / %u\n", + get_field(reg, UNICAM_PUM_MASK), + get_field(reg, UNICAM_PPM_MASK)); + unicam_info(dev, "----Live data----\n"); + unicam_info(dev, "Programmed stride: %4u\n", + reg_read(dev, UNICAM_IBLS)); + unicam_info(dev, "Detected resolution: %ux%u\n", + reg_read(dev, UNICAM_IHSTA), + reg_read(dev, UNICAM_IVSTA)); + unicam_info(dev, "Write pointer: %08x\n", + reg_read(dev, UNICAM_IBWP)); + + return 0; +} + +/* V4L2 Video Centric IOCTLs */ static int unicam_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -1269,913 +1382,1271 @@ static int unicam_g_fmt_meta_cap(struct file *file, void *priv, return 0; } -static int unicam_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, - unsigned int sizes[], - struct device *alloc_devs[]) +static int unicam_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) { - struct unicam_node *node = vb2_get_drv_priv(vq); + struct unicam_node *node = video_drvdata(file); struct unicam_device *dev = node->dev; - unsigned int size = node->pad_id == IMAGE_PAD ? - node->v_fmt.fmt.pix.sizeimage : - node->v_fmt.fmt.meta.buffersize; + int ret; - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; + if (inp->index != 0) + return -EINVAL; - if (*nplanes) { - if (sizes[0] < size) { - unicam_err(dev, "sizes[0] %i < size %u\n", sizes[0], - size); - return -EINVAL; - } - size = sizes[0]; + inp->type = V4L2_INPUT_TYPE_CAMERA; + if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) { + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->std = 0; + } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) { + inp->capabilities = V4L2_IN_CAP_STD; + if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) < 0) + inp->std = V4L2_STD_ALL; + } else { + inp->capabilities = 0; + inp->std = 0; } - *nplanes = 1; - sizes[0] = size; + if (v4l2_subdev_has_op(dev->sensor, video, g_input_status)) { + ret = v4l2_subdev_call(dev->sensor, video, g_input_status, + &inp->status); + if (ret < 0) + return ret; + } + snprintf(inp->name, sizeof(inp->name), "Camera 0"); return 0; } -static int unicam_buffer_prepare(struct vb2_buffer *vb) +static int unicam_g_input(struct file *file, void *priv, unsigned int *i) { - struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); - struct unicam_device *dev = node->dev; - struct unicam_buffer *buf = to_unicam_buffer(vb); - unsigned long size; + *i = 0; - if (WARN_ON(!node->fmt)) - return -EINVAL; + return 0; +} - size = node->pad_id == IMAGE_PAD ? node->v_fmt.fmt.pix.sizeimage : - node->v_fmt.fmt.meta.buffersize; - if (vb2_plane_size(vb, 0) < size) { - unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); +static int unicam_s_input(struct file *file, void *priv, unsigned int i) +{ + /* + * FIXME: Ideally we would like to be able to query the source + * subdevice for information over the input connectors it supports, + * and map that through in to a call to video_ops->s_routing. + * There is no infrastructure support for defining that within + * devicetree at present. Until that is implemented we can't + * map a user physical connector number to s_routing input number. + */ + if (i > 0) return -EINVAL; - } - vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); return 0; } -static void unicam_buffer_queue(struct vb2_buffer *vb) +static int unicam_querystd(struct file *file, void *priv, + v4l2_std_id *std) { - struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); - struct unicam_buffer *buf = to_unicam_buffer(vb); - unsigned long flags; + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - spin_lock_irqsave(&node->dma_queue_lock, flags); - list_add_tail(&buf->list, &node->dma_queue); - spin_unlock_irqrestore(&node->dma_queue_lock, flags); + return v4l2_subdev_call(dev->sensor, video, querystd, std); } -static void unicam_set_packing_config(struct unicam_device *dev) +static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std) { - u32 pack, unpack; - u32 val; + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - if (dev->node[IMAGE_PAD].v_fmt.fmt.pix.pixelformat == - dev->node[IMAGE_PAD].fmt->fourcc) { - unpack = UNICAM_PUM_NONE; - pack = UNICAM_PPM_NONE; - } else { - switch (dev->node[IMAGE_PAD].fmt->depth) { - case 8: - unpack = UNICAM_PUM_UNPACK8; - break; - case 10: - unpack = UNICAM_PUM_UNPACK10; - break; - case 12: - unpack = UNICAM_PUM_UNPACK12; - break; - case 14: - unpack = UNICAM_PUM_UNPACK14; - break; - case 16: - unpack = UNICAM_PUM_UNPACK16; - break; - default: - unpack = UNICAM_PUM_NONE; - break; - } + return v4l2_subdev_call(dev->sensor, video, g_std, std); +} - /* Repacking is always to 16bpp */ - pack = UNICAM_PPM_PACK16; - } +static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + int ret; + v4l2_std_id current_std; - val = 0; - set_field(&val, unpack, UNICAM_PUM_MASK); - set_field(&val, pack, UNICAM_PPM_MASK); - reg_write(dev, UNICAM_IPIPE, val); + ret = v4l2_subdev_call(dev->sensor, video, g_std, ¤t_std); + if (ret) + return ret; + + if (std == current_std) + return 0; + + if (vb2_is_busy(&node->buffer_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(dev->sensor, video, s_std, std); + + /* Force recomputation of bytesperline */ + node->v_fmt.fmt.pix.bytesperline = 0; + + unicam_reset_format(node); + + return ret; } -static void unicam_cfg_image_id(struct unicam_device *dev) +static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { - if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { - /* CSI2 mode, hardcode VC 0 for now. */ - reg_write(dev, UNICAM_IDI0, - (0 << 6) | dev->node[IMAGE_PAD].fmt->csi_dt); - } else { - /* CCP2 mode */ - reg_write(dev, UNICAM_IDI0, - 0x80 | dev->node[IMAGE_PAD].fmt->csi_dt); - } + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + + return v4l2_subdev_call(dev->sensor, pad, set_edid, edid); } -static void unicam_enable_ed(struct unicam_device *dev) +static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { - u32 val = reg_read(dev, UNICAM_DCS); - - set_field(&val, 2, UNICAM_EDL_MASK); - /* Do not wrap at the end of the embedded data buffer */ - set_field(&val, 0, UNICAM_DBOB); + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - reg_write(dev, UNICAM_DCS, val); + return v4l2_subdev_call(dev->sensor, pad, get_edid, edid); } -static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr) +static int unicam_s_selection(struct file *file, void *priv, + struct v4l2_selection *sel) { - int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2; - unsigned int size, i; - u32 val; + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + struct v4l2_subdev_selection sdsel = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .target = sel->target, + .flags = sel->flags, + .r = sel->r, + }; - if (line_int_freq < 128) - line_int_freq = 128; + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; - /* Enable lane clocks */ - val = 1; - for (i = 0; i < dev->active_data_lanes; i++) - val = val << 2 | 1; - clk_write(dev, val); + return v4l2_subdev_call(dev->sensor, pad, set_selection, NULL, &sdsel); +} - /* Basic init */ - reg_write(dev, UNICAM_CTRL, UNICAM_MEM); +static int unicam_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + struct v4l2_subdev_selection sdsel = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .target = sel->target, + }; + int ret; - /* Enable analogue control, and leave in reset. */ - val = UNICAM_AR; - set_field(&val, 7, UNICAM_CTATADJ_MASK); - set_field(&val, 7, UNICAM_PTATADJ_MASK); - reg_write(dev, UNICAM_ANA, val); - usleep_range(1000, 2000); + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; - /* Come out of reset */ - reg_write_field(dev, UNICAM_ANA, 0, UNICAM_AR); + ret = v4l2_subdev_call(dev->sensor, pad, get_selection, NULL, &sdsel); + if (!ret) + sel->r = sdsel.r; - /* Peripheral reset */ - reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR); - reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR); + return ret; +} - reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE); +static int unicam_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + struct v4l2_subdev_frame_size_enum fse; + int ret; - /* Enable Rx control. */ - val = reg_read(dev, UNICAM_CTRL); - if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { - set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK); - set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK); - } else { - set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK); - set_field(&val, dev->bus_flags, UNICAM_DCM_MASK); + /* check for valid format */ + fmt = find_format_by_pix(dev, fsize->pixel_format); + if (!fmt) { + unicam_dbg(3, dev, "Invalid pixel code: %x\n", + fsize->pixel_format); + return -EINVAL; } - /* Packet framer timeout */ - set_field(&val, 0xf, UNICAM_PFT_MASK); - set_field(&val, 128, UNICAM_OET_MASK); - reg_write(dev, UNICAM_CTRL, val); - - reg_write(dev, UNICAM_IHWIN, 0); - reg_write(dev, UNICAM_IVWIN, 0); - - /* AXI bus access QoS setup */ - val = reg_read(dev, UNICAM_PRI); - set_field(&val, 0, UNICAM_BL_MASK); - set_field(&val, 0, UNICAM_BS_MASK); - set_field(&val, 0xe, UNICAM_PP_MASK); - set_field(&val, 8, UNICAM_NP_MASK); - set_field(&val, 2, UNICAM_PT_MASK); - set_field(&val, 1, UNICAM_PE); - reg_write(dev, UNICAM_PRI, val); - - reg_write_field(dev, UNICAM_ANA, 0, UNICAM_DDL); + fse.code = fmt->code; - /* Always start in trigger frame capture mode (UNICAM_FCM set) */ - val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB; - set_field(&val, line_int_freq, UNICAM_LCIE_MASK); - reg_write(dev, UNICAM_ICTL, val); - reg_write(dev, UNICAM_STA, UNICAM_STA_MASK_ALL); - reg_write(dev, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL); + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fse.index = fsize->index; + fse.pad = node->src_pad_id; - /* tclk_term_en */ - reg_write_field(dev, UNICAM_CLT, 2, UNICAM_CLT1_MASK); - /* tclk_settle */ - reg_write_field(dev, UNICAM_CLT, 6, UNICAM_CLT2_MASK); - /* td_term_en */ - reg_write_field(dev, UNICAM_DLT, 2, UNICAM_DLT1_MASK); - /* ths_settle */ - reg_write_field(dev, UNICAM_DLT, 6, UNICAM_DLT2_MASK); - /* trx_enable */ - reg_write_field(dev, UNICAM_DLT, 0, UNICAM_DLT3_MASK); + ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse); + if (ret) + return ret; - reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_SOE); + unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", + __func__, fse.index, fse.code, fse.min_width, fse.max_width, + fse.min_height, fse.max_height); - /* Packet compare setup - required to avoid missing frame ends */ - val = 0; - set_field(&val, 1, UNICAM_PCE); - set_field(&val, 1, UNICAM_GI); - set_field(&val, 1, UNICAM_CPH); - set_field(&val, 0, UNICAM_PCVC_MASK); - set_field(&val, 1, UNICAM_PCDT_MASK); - reg_write(dev, UNICAM_CMP0, val); + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; - /* Enable clock lane and set up terminations */ - val = 0; - if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { - /* CSI2 */ - set_field(&val, 1, UNICAM_CLE); - set_field(&val, 1, UNICAM_CLLPE); - if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { - set_field(&val, 1, UNICAM_CLTRE); - set_field(&val, 1, UNICAM_CLHSE); - } - } else { - /* CCP2 */ - set_field(&val, 1, UNICAM_CLE); - set_field(&val, 1, UNICAM_CLHSE); - set_field(&val, 1, UNICAM_CLTRE); - } - reg_write(dev, UNICAM_CLK, val); + return 0; +} - /* - * Enable required data lanes with appropriate terminations. - * The same value needs to be written to UNICAM_DATn registers for - * the active lanes, and 0 for inactive ones. - */ - val = 0; - if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { - /* CSI2 */ - set_field(&val, 1, UNICAM_DLE); - set_field(&val, 1, UNICAM_DLLPE); - if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { - set_field(&val, 1, UNICAM_DLTRE); - set_field(&val, 1, UNICAM_DLHSE); - } - } else { - /* CCP2 */ - set_field(&val, 1, UNICAM_DLE); - set_field(&val, 1, UNICAM_DLHSE); - set_field(&val, 1, UNICAM_DLTRE); - } - reg_write(dev, UNICAM_DAT0, val); +static int unicam_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, + .pad = node->src_pad_id, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret; - if (dev->active_data_lanes == 1) - val = 0; - reg_write(dev, UNICAM_DAT1, val); + fmt = find_format_by_pix(dev, fival->pixel_format); + if (!fmt) + return -EINVAL; - if (dev->max_data_lanes > 2) { - /* - * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the - * instance supports more than 2 data lanes. - */ - if (dev->active_data_lanes == 2) - val = 0; - reg_write(dev, UNICAM_DAT2, val); + fie.code = fmt->code; + ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval, + NULL, &fie); + if (ret) + return ret; - if (dev->active_data_lanes == 3) - val = 0; - reg_write(dev, UNICAM_DAT3, val); - } + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; - reg_write(dev, UNICAM_IBLS, - dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline); - size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage; - unicam_wr_dma_addr(dev, addr[IMAGE_PAD], size, IMAGE_PAD); - unicam_set_packing_config(dev); - unicam_cfg_image_id(dev); + return 0; +} - val = reg_read(dev, UNICAM_MISC); - set_field(&val, 1, UNICAM_FL0); - set_field(&val, 1, UNICAM_FL1); - reg_write(dev, UNICAM_MISC, val); +static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) { - size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; - unicam_enable_ed(dev); - unicam_wr_dma_addr(dev, addr[METADATA_PAD], size, METADATA_PAD); - } + return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a); +} - /* Enable peripheral */ - reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPE); +static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - /* Load image pointers */ - reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_LIP_MASK); + return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a); +} - /* Load embedded data buffer pointers if needed */ - if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) - reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP); +static int unicam_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - /* - * Enable trigger only for the first frame to - * sync correctly to the FS from the source. - */ - reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_TFC); + return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings); } -static void unicam_disable(struct unicam_device *dev) +static int unicam_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) { - /* Analogue lane control disable */ - reg_write_field(dev, UNICAM_ANA, 1, UNICAM_DDL); + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + struct v4l2_dv_timings current_timings; + int ret; - /* Stop the output engine */ - reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_SOE); + ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings, + ¤t_timings); - /* Disable the data lanes. */ - reg_write(dev, UNICAM_DAT0, 0); - reg_write(dev, UNICAM_DAT1, 0); + if (ret < 0) + return ret; - if (dev->max_data_lanes > 2) { - reg_write(dev, UNICAM_DAT2, 0); - reg_write(dev, UNICAM_DAT3, 0); - } + if (v4l2_match_dv_timings(timings, ¤t_timings, 0, false)) + return 0; - /* Peripheral reset */ - reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR); - usleep_range(50, 100); - reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR); + if (vb2_is_busy(&node->buffer_queue)) + return -EBUSY; - /* Disable peripheral */ - reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE); + ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings); - /* Clear ED setup */ - reg_write(dev, UNICAM_DCS, 0); + /* Force recomputation of bytesperline */ + node->v_fmt.fmt.pix.bytesperline = 0; - /* Disable all lane clocks */ - clk_write(dev, 0); -} + unicam_reset_format(node); -static void unicam_return_buffers(struct unicam_node *node, - enum vb2_buffer_state state) -{ - struct unicam_buffer *buf, *tmp; - unsigned long flags; - - spin_lock_irqsave(&node->dma_queue_lock, flags); - list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, state); - } + return ret; +} - if (node->cur_frm) - vb2_buffer_done(&node->cur_frm->vb.vb2_buf, - state); - if (node->next_frm && node->cur_frm != node->next_frm) - vb2_buffer_done(&node->next_frm->vb.vb2_buf, - state); +static int unicam_query_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; - node->cur_frm = NULL; - node->next_frm = NULL; - spin_unlock_irqrestore(&node->dma_queue_lock, flags); + return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings); } -static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) +static int unicam_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) { - struct unicam_node *node = vb2_get_drv_priv(vq); + struct unicam_node *node = video_drvdata(file); struct unicam_device *dev = node->dev; - dma_addr_t buffer_addr[MAX_NODES] = { 0 }; - unsigned long flags; - unsigned int i; int ret; - node->streaming = true; - if (!(dev->node[IMAGE_PAD].open && dev->node[IMAGE_PAD].streaming && - (!dev->node[METADATA_PAD].open || - dev->node[METADATA_PAD].streaming))) { - /* - * Metadata pad must be enabled before image pad if it is - * wanted. - */ - unicam_dbg(3, dev, "Not all nodes are streaming yet."); - return 0; - } + timings->pad = node->src_pad_id; + ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); + timings->pad = node->pad_id; - dev->sequence = 0; - ret = unicam_runtime_get(dev); - if (ret < 0) { - unicam_dbg(3, dev, "unicam_runtime_get failed\n"); - goto err_streaming; - } + return ret; +} - dev->active_data_lanes = dev->max_data_lanes; +static int unicam_dv_timings_cap(struct file *file, void *priv, + struct v4l2_dv_timings_cap *cap) +{ + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + int ret; - if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { - struct v4l2_mbus_config mbus_config = { 0 }; + cap->pad = node->src_pad_id; + ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); + cap->pad = node->pad_id; - ret = v4l2_subdev_call(dev->sensor, pad, get_mbus_config, - 0, &mbus_config); - if (ret < 0 && ret != -ENOIOCTLCMD) { - unicam_dbg(3, dev, "g_mbus_config failed\n"); - goto err_pm_put; - } + return ret; +} - dev->active_data_lanes = - (mbus_config.flags & V4L2_MBUS_CSI2_LANE_MASK) >> - __ffs(V4L2_MBUS_CSI2_LANE_MASK); - if (!dev->active_data_lanes) - dev->active_data_lanes = dev->max_data_lanes; - if (dev->active_data_lanes > dev->max_data_lanes) { - unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", - dev->active_data_lanes, - dev->max_data_lanes); - ret = -EINVAL; - goto err_pm_put; - } +static int unicam_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_event_subscribe(fh, sub, 4, NULL); } - unicam_dbg(1, dev, "Running with %u data lanes\n", - dev->active_data_lanes); - - dev->vpu_req = clk_request_start(dev->vpu_clock, MIN_VPU_CLOCK_RATE); - if (!dev->vpu_req) { - unicam_err(dev, "failed to set up VPU clock\n"); - goto err_pm_put; - } + return v4l2_ctrl_subscribe_event(fh, sub); +} - ret = clk_prepare_enable(dev->vpu_clock); - if (ret) { - unicam_err(dev, "Failed to enable VPU clock: %d\n", ret); - goto err_pm_put; - } +static void unicam_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct unicam_device *dev = to_unicam_device(sd->v4l2_dev); - ret = clk_set_rate(dev->clock, 100 * 1000 * 1000); - if (ret) { - unicam_err(dev, "failed to set up CSI clock\n"); - goto err_vpu_clock; + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: + v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg); + break; + default: + break; } +} - ret = clk_prepare_enable(dev->clock); - if (ret) { - unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); - goto err_vpu_clock; - } +/* unicam capture ioctl operations */ +static const struct v4l2_ioctl_ops unicam_ioctl_ops = { + .vidioc_querycap = unicam_querycap, + .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap, - for (i = 0; i < ARRAY_SIZE(dev->node); i++) { - struct unicam_buffer *buf; + .vidioc_enum_fmt_meta_cap = unicam_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = unicam_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = unicam_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = unicam_g_fmt_meta_cap, - if (!dev->node[i].streaming) - continue; + .vidioc_enum_input = unicam_enum_input, + .vidioc_g_input = unicam_g_input, + .vidioc_s_input = unicam_s_input, - spin_lock_irqsave(&dev->node[i].dma_queue_lock, flags); - buf = list_first_entry(&dev->node[i].dma_queue, - struct unicam_buffer, list); - dev->node[i].cur_frm = buf; - dev->node[i].next_frm = buf; - list_del(&buf->list); - spin_unlock_irqrestore(&dev->node[i].dma_queue_lock, flags); + .vidioc_querystd = unicam_querystd, + .vidioc_s_std = unicam_s_std, + .vidioc_g_std = unicam_g_std, - buffer_addr[i] = - vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - } + .vidioc_g_edid = unicam_g_edid, + .vidioc_s_edid = unicam_s_edid, - unicam_start_rx(dev, buffer_addr); + .vidioc_enum_framesizes = unicam_enum_framesizes, + .vidioc_enum_frameintervals = unicam_enum_frameintervals, - ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); - if (ret < 0) { - unicam_err(dev, "stream on failed in subdev\n"); - goto err_disable_unicam; - } + .vidioc_g_selection = unicam_g_selection, + .vidioc_s_selection = unicam_s_selection, - dev->clocks_enabled = true; - return 0; + .vidioc_g_parm = unicam_g_parm, + .vidioc_s_parm = unicam_s_parm, -err_disable_unicam: - unicam_disable(dev); - clk_disable_unprepare(dev->clock); -err_vpu_clock: - clk_request_done(dev->vpu_req); - clk_disable_unprepare(dev->vpu_clock); -err_pm_put: - unicam_runtime_put(dev); -err_streaming: - unicam_return_buffers(node, VB2_BUF_STATE_QUEUED); - node->streaming = false; + .vidioc_s_dv_timings = unicam_s_dv_timings, + .vidioc_g_dv_timings = unicam_g_dv_timings, + .vidioc_query_dv_timings = unicam_query_dv_timings, + .vidioc_enum_dv_timings = unicam_enum_dv_timings, + .vidioc_dv_timings_cap = unicam_dv_timings_cap, - return ret; -} + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, -static void unicam_stop_streaming(struct vb2_queue *vq) -{ - struct unicam_node *node = vb2_get_drv_priv(vq); - struct unicam_device *dev = node->dev; + .vidioc_log_status = unicam_log_status, + .vidioc_subscribe_event = unicam_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; - node->streaming = false; +/* V4L2 Media Controller Centric IOCTLs */ - if (node->pad_id == IMAGE_PAD) { - /* - * Stop streaming the sensor and disable the peripheral. - * We cannot continue streaming embedded data with the - * image pad disabled. - */ - if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) - unicam_err(dev, "stream off failed in subdev\n"); +static int unicam_mc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int i, j; - unicam_disable(dev); + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { + if (f->mbus_code && formats[i].code != f->mbus_code) + continue; + if (formats[i].mc_skip || formats[i].metadata_fmt) + continue; - if (dev->clocks_enabled) { - clk_request_done(dev->vpu_req); - clk_disable_unprepare(dev->vpu_clock); - clk_disable_unprepare(dev->clock); - dev->clocks_enabled = false; + if (formats[i].fourcc) { + if (j == f->index) { + f->pixelformat = formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + j++; + } + if (formats[i].repacked_fourcc) { + if (j == f->index) { + f->pixelformat = formats[i].repacked_fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + j++; } - unicam_runtime_put(dev); - - } else if (node->pad_id == METADATA_PAD) { - /* - * Allow the hardware to spin in the dummy buffer. - * This is only really needed if the embedded data pad is - * disabled before the image pad. - */ - unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, - DUMMY_BUF_SIZE, METADATA_PAD); } - /* Clear all queued buffers for the node */ - unicam_return_buffers(node, VB2_BUF_STATE_ERROR); + return -EINVAL; } -static int unicam_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) +static int unicam_mc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - int ret; - if (inp->index != 0) + if (node->pad_id != IMAGE_PAD) return -EINVAL; - inp->type = V4L2_INPUT_TYPE_CAMERA; - if (v4l2_subdev_has_op(dev->sensor, video, s_dv_timings)) { - inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; - inp->std = 0; - } else if (v4l2_subdev_has_op(dev->sensor, video, s_std)) { - inp->capabilities = V4L2_IN_CAP_STD; - if (v4l2_subdev_call(dev->sensor, video, g_tvnorms, &inp->std) < 0) - inp->std = V4L2_STD_ALL; - } else { - inp->capabilities = 0; - inp->std = 0; + *f = node->v_fmt; + + return 0; +} + +static void unicam_mc_try_fmt(struct unicam_node *node, struct v4l2_format *f, + const struct unicam_fmt **ret_fmt) +{ + struct v4l2_pix_format *v4l2_format = &f->fmt.pix; + struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + int is_rgb; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmt = find_format_by_pix(dev, v4l2_format->pixelformat); + if (!fmt) { + fmt = &formats[0]; + v4l2_format->pixelformat = fmt->fourcc; } - if (v4l2_subdev_has_op(dev->sensor, video, g_input_status)) { - ret = v4l2_subdev_call(dev->sensor, video, g_input_status, - &inp->status); - if (ret < 0) - return ret; + unicam_calc_format_size_bpl(dev, fmt, f); + + if (v4l2_format->field == V4L2_FIELD_ANY) + v4l2_format->field = V4L2_FIELD_NONE; + + if (ret_fmt) + *ret_fmt = fmt; + + if (v4l2_format->colorspace >= MAX_COLORSPACE || + !(fmt->valid_colorspaces & (1 << v4l2_format->colorspace))) { + v4l2_format->colorspace = __ffs(fmt->valid_colorspaces); + + v4l2_format->xfer_func = + V4L2_MAP_XFER_FUNC_DEFAULT(v4l2_format->colorspace); + v4l2_format->ycbcr_enc = + V4L2_MAP_YCBCR_ENC_DEFAULT(v4l2_format->colorspace); + is_rgb = v4l2_format->colorspace == V4L2_COLORSPACE_SRGB; + v4l2_format->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, + v4l2_format->colorspace, + v4l2_format->ycbcr_enc); } - snprintf(inp->name, sizeof(inp->name), "Camera 0"); + unicam_dbg(3, dev, "%s: %08x %ux%u (bytesperline %u sizeimage %u)\n", + __func__, v4l2_format->pixelformat, + v4l2_format->width, v4l2_format->height, + v4l2_format->bytesperline, v4l2_format->sizeimage); +} + +static int unicam_mc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct unicam_node *node = video_drvdata(file); + + unicam_mc_try_fmt(node, f, NULL); return 0; } -static int unicam_g_input(struct file *file, void *priv, unsigned int *i) +static int unicam_mc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { - *i = 0; + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + const struct unicam_fmt *fmt; + + if (vb2_is_busy(&node->buffer_queue)) { + unicam_dbg(3, dev, "%s device busy\n", __func__); + return -EBUSY; + } + + unicam_mc_try_fmt(node, f, &fmt); + + node->v_fmt = *f; + node->fmt = fmt; return 0; } -static int unicam_s_input(struct file *file, void *priv, unsigned int i) +static int unicam_mc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) { - /* - * FIXME: Ideally we would like to be able to query the source - * subdevice for information over the input connectors it supports, - * and map that through in to a call to video_ops->s_routing. - * There is no infrastructure support for defining that within - * devicetree at present. Until that is implemented we can't - * map a user physical connector number to s_routing input number. - */ - if (i > 0) + struct unicam_node *node = video_drvdata(file); + struct unicam_device *dev = node->dev; + + if (fsize->index > 0) + return -EINVAL; + + if (!find_format_by_pix(dev, fsize->pixel_format)) { + unicam_dbg(3, dev, "Invalid pixel format 0x%08x\n", + fsize->pixel_format); return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT; + fsize->stepwise.step_height = 1; return 0; } -static int unicam_querystd(struct file *file, void *priv, - v4l2_std_id *std) +static int unicam_mc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { + if (f->mbus_code && formats[i].code != f->mbus_code) + continue; + if (!formats[i].metadata_fmt) + continue; + + if (formats[i].fourcc) { + if (j == f->index) { + f->pixelformat = formats[i].fourcc; + f->type = V4L2_BUF_TYPE_META_CAPTURE; + return 0; + } + j++; + } + } + + return -EINVAL; +} + +static int unicam_mc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - return v4l2_subdev_call(dev->sensor, video, querystd, std); + if (node->pad_id != METADATA_PAD) + return -EINVAL; + + *f = node->v_fmt; + + return 0; } -static int unicam_g_std(struct file *file, void *priv, v4l2_std_id *std) +static int unicam_mc_try_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - return v4l2_subdev_call(dev->sensor, video, g_std, std); + if (node->pad_id != METADATA_PAD) + return -EINVAL; + + f->fmt.meta.dataformat = V4L2_META_FMT_SENSOR_DATA; + + return 0; } -static int unicam_s_std(struct file *file, void *priv, v4l2_std_id std) +static int unicam_mc_s_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + + if (node->pad_id != METADATA_PAD) + return -EINVAL; + + unicam_mc_try_fmt_meta_cap(file, priv, f); + + node->v_fmt = *f; + + return 0; +} + +static const struct v4l2_ioctl_ops unicam_mc_ioctl_ops = { + .vidioc_querycap = unicam_querycap, + .vidioc_enum_fmt_vid_cap = unicam_mc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = unicam_mc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = unicam_mc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = unicam_mc_s_fmt_vid_cap, + + .vidioc_enum_fmt_meta_cap = unicam_mc_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = unicam_mc_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = unicam_mc_try_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = unicam_mc_s_fmt_meta_cap, + + .vidioc_enum_framesizes = unicam_mc_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = unicam_log_status, + .vidioc_subscribe_event = unicam_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int +unicam_mc_subdev_link_validate_get_format(struct media_pad *pad, + struct v4l2_subdev_format *fmt) +{ + if (is_media_entity_v4l2_subdev(pad->entity)) { + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(pad->entity); + + fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt->pad = pad->index; + return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); + } + + return -EINVAL; +} + +static int unicam_mc_video_link_validate(struct media_link *link) +{ + struct video_device *vd = container_of(link->sink->entity, + struct video_device, entity); + struct unicam_node *node = container_of(vd, struct unicam_node, + video_dev); + struct unicam_device *unicam = node->dev; + struct v4l2_subdev_format source_fmt; int ret; - v4l2_std_id current_std; - ret = v4l2_subdev_call(dev->sensor, video, g_std, ¤t_std); - if (ret) - return ret; + if (!media_entity_remote_pad(link->sink->entity->pads)) { + unicam_dbg(1, unicam, + "video node %s pad not connected\n", vd->name); + return -ENOTCONN; + } - if (std == current_std) + ret = unicam_mc_subdev_link_validate_get_format(link->source, + &source_fmt); + if (ret < 0) return 0; - if (vb2_is_busy(&node->buffer_queue)) - return -EBUSY; + if (node->pad_id == IMAGE_PAD) { + struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix; + const struct unicam_fmt *fmt; - ret = v4l2_subdev_call(dev->sensor, video, s_std, std); + if (source_fmt.format.width != pix_fmt->width || + source_fmt.format.height != pix_fmt->height) { + unicam_err(unicam, + "Wrong width or height %ux%u (remote pad set to %ux%u)\n", + pix_fmt->width, pix_fmt->height, + source_fmt.format.width, + source_fmt.format.height); + return -EINVAL; + } + + fmt = find_format_by_code(source_fmt.format.code); + + if (!fmt || (fmt->fourcc != pix_fmt->pixelformat && + fmt->repacked_fourcc != pix_fmt->pixelformat)) + return -EINVAL; + } else { + struct v4l2_meta_format *meta_fmt = &node->v_fmt.fmt.meta; + + if (source_fmt.format.width != meta_fmt->buffersize || + source_fmt.format.height != 1 || + source_fmt.format.code != MEDIA_BUS_FMT_SENSOR_DATA) { + unicam_err(unicam, + "Wrong metadata width/height/code %ux%u %08x (remote pad set to %ux%u %08x)\n", + meta_fmt->buffersize, 1, + MEDIA_BUS_FMT_SENSOR_DATA, + source_fmt.format.width, + source_fmt.format.height, + source_fmt.format.code); + return -EINVAL; + } + } + + return 0; +} + +static const struct media_entity_operations unicam_mc_entity_ops = { + .link_validate = unicam_mc_video_link_validate, +}; + +/* videobuf2 Operations */ + +static int unicam_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct unicam_node *node = vb2_get_drv_priv(vq); + struct unicam_device *dev = node->dev; + unsigned int size = node->pad_id == IMAGE_PAD ? + node->v_fmt.fmt.pix.sizeimage : + node->v_fmt.fmt.meta.buffersize; + + if (vq->num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->num_buffers; + + if (*nplanes) { + if (sizes[0] < size) { + unicam_err(dev, "sizes[0] %i < size %u\n", sizes[0], + size); + return -EINVAL; + } + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int unicam_buffer_prepare(struct vb2_buffer *vb) +{ + struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct unicam_device *dev = node->dev; + struct unicam_buffer *buf = to_unicam_buffer(vb); + unsigned long size; + + if (WARN_ON(!node->fmt)) + return -EINVAL; + + size = node->pad_id == IMAGE_PAD ? node->v_fmt.fmt.pix.sizeimage : + node->v_fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + unicam_err(dev, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + return 0; +} + +static void unicam_buffer_queue(struct vb2_buffer *vb) +{ + struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct unicam_buffer *buf = to_unicam_buffer(vb); + unsigned long flags; + + spin_lock_irqsave(&node->dma_queue_lock, flags); + list_add_tail(&buf->list, &node->dma_queue); + spin_unlock_irqrestore(&node->dma_queue_lock, flags); +} + +static void unicam_set_packing_config(struct unicam_device *dev) +{ + u32 pack, unpack; + u32 val; + + if (dev->node[IMAGE_PAD].v_fmt.fmt.pix.pixelformat == + dev->node[IMAGE_PAD].fmt->fourcc) { + unpack = UNICAM_PUM_NONE; + pack = UNICAM_PPM_NONE; + } else { + switch (dev->node[IMAGE_PAD].fmt->depth) { + case 8: + unpack = UNICAM_PUM_UNPACK8; + break; + case 10: + unpack = UNICAM_PUM_UNPACK10; + break; + case 12: + unpack = UNICAM_PUM_UNPACK12; + break; + case 14: + unpack = UNICAM_PUM_UNPACK14; + break; + case 16: + unpack = UNICAM_PUM_UNPACK16; + break; + default: + unpack = UNICAM_PUM_NONE; + break; + } + + /* Repacking is always to 16bpp */ + pack = UNICAM_PPM_PACK16; + } + + val = 0; + set_field(&val, unpack, UNICAM_PUM_MASK); + set_field(&val, pack, UNICAM_PPM_MASK); + reg_write(dev, UNICAM_IPIPE, val); +} + +static void unicam_cfg_image_id(struct unicam_device *dev) +{ + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + /* CSI2 mode, hardcode VC 0 for now. */ + reg_write(dev, UNICAM_IDI0, + (0 << 6) | dev->node[IMAGE_PAD].fmt->csi_dt); + } else { + /* CCP2 mode */ + reg_write(dev, UNICAM_IDI0, + 0x80 | dev->node[IMAGE_PAD].fmt->csi_dt); + } +} + +static void unicam_enable_ed(struct unicam_device *dev) +{ + u32 val = reg_read(dev, UNICAM_DCS); + + set_field(&val, 2, UNICAM_EDL_MASK); + /* Do not wrap at the end of the embedded data buffer */ + set_field(&val, 0, UNICAM_DBOB); + + reg_write(dev, UNICAM_DCS, val); +} + +static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr) +{ + int line_int_freq = dev->node[IMAGE_PAD].v_fmt.fmt.pix.height >> 2; + unsigned int size, i; + u32 val; + + if (line_int_freq < 128) + line_int_freq = 128; + + /* Enable lane clocks */ + val = 1; + for (i = 0; i < dev->active_data_lanes; i++) + val = val << 2 | 1; + clk_write(dev, val); + + /* Basic init */ + reg_write(dev, UNICAM_CTRL, UNICAM_MEM); + + /* Enable analogue control, and leave in reset. */ + val = UNICAM_AR; + set_field(&val, 7, UNICAM_CTATADJ_MASK); + set_field(&val, 7, UNICAM_PTATADJ_MASK); + reg_write(dev, UNICAM_ANA, val); + usleep_range(1000, 2000); + + /* Come out of reset */ + reg_write_field(dev, UNICAM_ANA, 0, UNICAM_AR); + + /* Peripheral reset */ + reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR); + reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR); + + reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE); + + /* Enable Rx control. */ + val = reg_read(dev, UNICAM_CTRL); + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK); + set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK); + } else { + set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK); + set_field(&val, dev->bus_flags, UNICAM_DCM_MASK); + } + /* Packet framer timeout */ + set_field(&val, 0xf, UNICAM_PFT_MASK); + set_field(&val, 128, UNICAM_OET_MASK); + reg_write(dev, UNICAM_CTRL, val); + + reg_write(dev, UNICAM_IHWIN, 0); + reg_write(dev, UNICAM_IVWIN, 0); + + /* AXI bus access QoS setup */ + val = reg_read(dev, UNICAM_PRI); + set_field(&val, 0, UNICAM_BL_MASK); + set_field(&val, 0, UNICAM_BS_MASK); + set_field(&val, 0xe, UNICAM_PP_MASK); + set_field(&val, 8, UNICAM_NP_MASK); + set_field(&val, 2, UNICAM_PT_MASK); + set_field(&val, 1, UNICAM_PE); + reg_write(dev, UNICAM_PRI, val); + + reg_write_field(dev, UNICAM_ANA, 0, UNICAM_DDL); + + /* Always start in trigger frame capture mode (UNICAM_FCM set) */ + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB; + set_field(&val, line_int_freq, UNICAM_LCIE_MASK); + reg_write(dev, UNICAM_ICTL, val); + reg_write(dev, UNICAM_STA, UNICAM_STA_MASK_ALL); + reg_write(dev, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL); + + /* tclk_term_en */ + reg_write_field(dev, UNICAM_CLT, 2, UNICAM_CLT1_MASK); + /* tclk_settle */ + reg_write_field(dev, UNICAM_CLT, 6, UNICAM_CLT2_MASK); + /* td_term_en */ + reg_write_field(dev, UNICAM_DLT, 2, UNICAM_DLT1_MASK); + /* ths_settle */ + reg_write_field(dev, UNICAM_DLT, 6, UNICAM_DLT2_MASK); + /* trx_enable */ + reg_write_field(dev, UNICAM_DLT, 0, UNICAM_DLT3_MASK); + + reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_SOE); + + /* Packet compare setup - required to avoid missing frame ends */ + val = 0; + set_field(&val, 1, UNICAM_PCE); + set_field(&val, 1, UNICAM_GI); + set_field(&val, 1, UNICAM_CPH); + set_field(&val, 0, UNICAM_PCVC_MASK); + set_field(&val, 1, UNICAM_PCDT_MASK); + reg_write(dev, UNICAM_CMP0, val); + + /* Enable clock lane and set up terminations */ + val = 0; + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + /* CSI2 */ + set_field(&val, 1, UNICAM_CLE); + set_field(&val, 1, UNICAM_CLLPE); + if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { + set_field(&val, 1, UNICAM_CLTRE); + set_field(&val, 1, UNICAM_CLHSE); + } + } else { + /* CCP2 */ + set_field(&val, 1, UNICAM_CLE); + set_field(&val, 1, UNICAM_CLHSE); + set_field(&val, 1, UNICAM_CLTRE); + } + reg_write(dev, UNICAM_CLK, val); + + /* + * Enable required data lanes with appropriate terminations. + * The same value needs to be written to UNICAM_DATn registers for + * the active lanes, and 0 for inactive ones. + */ + val = 0; + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + /* CSI2 */ + set_field(&val, 1, UNICAM_DLE); + set_field(&val, 1, UNICAM_DLLPE); + if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) { + set_field(&val, 1, UNICAM_DLTRE); + set_field(&val, 1, UNICAM_DLHSE); + } + } else { + /* CCP2 */ + set_field(&val, 1, UNICAM_DLE); + set_field(&val, 1, UNICAM_DLHSE); + set_field(&val, 1, UNICAM_DLTRE); + } + reg_write(dev, UNICAM_DAT0, val); + + if (dev->active_data_lanes == 1) + val = 0; + reg_write(dev, UNICAM_DAT1, val); + + if (dev->max_data_lanes > 2) { + /* + * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the + * instance supports more than 2 data lanes. + */ + if (dev->active_data_lanes == 2) + val = 0; + reg_write(dev, UNICAM_DAT2, val); + + if (dev->active_data_lanes == 3) + val = 0; + reg_write(dev, UNICAM_DAT3, val); + } + + reg_write(dev, UNICAM_IBLS, + dev->node[IMAGE_PAD].v_fmt.fmt.pix.bytesperline); + size = dev->node[IMAGE_PAD].v_fmt.fmt.pix.sizeimage; + unicam_wr_dma_addr(dev, addr[IMAGE_PAD], size, IMAGE_PAD); + unicam_set_packing_config(dev); + unicam_cfg_image_id(dev); + + val = reg_read(dev, UNICAM_MISC); + set_field(&val, 1, UNICAM_FL0); + set_field(&val, 1, UNICAM_FL1); + reg_write(dev, UNICAM_MISC, val); - /* Force recomputation of bytesperline */ - node->v_fmt.fmt.pix.bytesperline = 0; + if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) { + size = dev->node[METADATA_PAD].v_fmt.fmt.meta.buffersize; + unicam_enable_ed(dev); + unicam_wr_dma_addr(dev, addr[METADATA_PAD], size, METADATA_PAD); + } - unicam_reset_format(node); + /* Enable peripheral */ + reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPE); - return ret; -} + /* Load image pointers */ + reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_LIP_MASK); -static int unicam_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + /* Load embedded data buffer pointers if needed */ + if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) + reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP); - return v4l2_subdev_call(dev->sensor, pad, set_edid, edid); + /* + * Enable trigger only for the first frame to + * sync correctly to the FS from the source. + */ + reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_TFC); } -static int unicam_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) +static void unicam_disable(struct unicam_device *dev) { - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - - return v4l2_subdev_call(dev->sensor, pad, get_edid, edid); -} + /* Analogue lane control disable */ + reg_write_field(dev, UNICAM_ANA, 1, UNICAM_DDL); -static int unicam_s_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - .flags = sel->flags, - .r = sel->r, - }; + /* Stop the output engine */ + reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_SOE); - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + /* Disable the data lanes. */ + reg_write(dev, UNICAM_DAT0, 0); + reg_write(dev, UNICAM_DAT1, 0); - return v4l2_subdev_call(dev->sensor, pad, set_selection, NULL, &sdsel); -} + if (dev->max_data_lanes > 2) { + reg_write(dev, UNICAM_DAT2, 0); + reg_write(dev, UNICAM_DAT3, 0); + } -static int unicam_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - }; - int ret; + /* Peripheral reset */ + reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR); + usleep_range(50, 100); + reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR); - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + /* Disable peripheral */ + reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE); - ret = v4l2_subdev_call(dev->sensor, pad, get_selection, NULL, &sdsel); - if (!ret) - sel->r = sdsel.r; + /* Clear ED setup */ + reg_write(dev, UNICAM_DCS, 0); - return ret; + /* Disable all lane clocks */ + clk_write(dev, 0); } -static int unicam_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) +static void unicam_return_buffers(struct unicam_node *node, + enum vb2_buffer_state state) { - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - const struct unicam_fmt *fmt; - struct v4l2_subdev_frame_size_enum fse; - int ret; + struct unicam_buffer *buf, *tmp; + unsigned long flags; - /* check for valid format */ - fmt = find_format_by_pix(dev, fsize->pixel_format); - if (!fmt) { - unicam_dbg(3, dev, "Invalid pixel code: %x\n", - fsize->pixel_format); - return -EINVAL; + spin_lock_irqsave(&node->dma_queue_lock, flags); + list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); } - fse.code = fmt->code; - - fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fse.index = fsize->index; - fse.pad = node->src_pad_id; - - ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_size, NULL, &fse); - if (ret) - return ret; - - unicam_dbg(1, dev, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", - __func__, fse.index, fse.code, fse.min_width, fse.max_width, - fse.min_height, fse.max_height); - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fse.max_width; - fsize->discrete.height = fse.max_height; + if (node->cur_frm) + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, + state); + if (node->next_frm && node->cur_frm != node->next_frm) + vb2_buffer_done(&node->next_frm->vb.vb2_buf, + state); - return 0; + node->cur_frm = NULL; + node->next_frm = NULL; + spin_unlock_irqrestore(&node->dma_queue_lock, flags); } -static int unicam_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) +static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct unicam_node *node = video_drvdata(file); + struct unicam_node *node = vb2_get_drv_priv(vq); struct unicam_device *dev = node->dev; - const struct unicam_fmt *fmt; - struct v4l2_subdev_frame_interval_enum fie = { - .index = fival->index, - .pad = node->src_pad_id, - .width = fival->width, - .height = fival->height, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; + dma_addr_t buffer_addr[MAX_NODES] = { 0 }; + unsigned long flags; + unsigned int i; int ret; - fmt = find_format_by_pix(dev, fival->pixel_format); - if (!fmt) - return -EINVAL; - - fie.code = fmt->code; - ret = v4l2_subdev_call(dev->sensor, pad, enum_frame_interval, - NULL, &fie); - if (ret) - return ret; - - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = fie.interval; - - return 0; -} + node->streaming = true; + if (!(dev->node[IMAGE_PAD].open && dev->node[IMAGE_PAD].streaming && + (!dev->node[METADATA_PAD].open || + dev->node[METADATA_PAD].streaming))) { + /* + * Metadata pad must be enabled before image pad if it is + * wanted. + */ + unicam_dbg(3, dev, "Not all nodes are streaming yet."); + return 0; + } -static int unicam_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + dev->sequence = 0; + ret = unicam_runtime_get(dev); + if (ret < 0) { + unicam_dbg(3, dev, "unicam_runtime_get failed\n"); + goto err_streaming; + } - return v4l2_g_parm_cap(video_devdata(file), dev->sensor, a); -} + ret = media_pipeline_start(&node->video_dev.entity, &node->pipe); + if (ret < 0) { + unicam_err(dev, "Failed to start media pipeline: %d\n", ret); + goto err_pm_put; + } -static int unicam_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + dev->active_data_lanes = dev->max_data_lanes; - return v4l2_s_parm_cap(video_devdata(file), dev->sensor, a); -} + if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) { + struct v4l2_mbus_config mbus_config = { 0 }; -static int unicam_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + ret = v4l2_subdev_call(dev->sensor, pad, get_mbus_config, + 0, &mbus_config); + if (ret < 0 && ret != -ENOIOCTLCMD) { + unicam_dbg(3, dev, "g_mbus_config failed\n"); + goto error_pipeline; + } - return v4l2_subdev_call(dev->sensor, video, g_dv_timings, timings); -} + dev->active_data_lanes = + (mbus_config.flags & V4L2_MBUS_CSI2_LANE_MASK) >> + __ffs(V4L2_MBUS_CSI2_LANE_MASK); + if (!dev->active_data_lanes) + dev->active_data_lanes = dev->max_data_lanes; + if (dev->active_data_lanes > dev->max_data_lanes) { + unicam_err(dev, "Device has requested %u data lanes, which is >%u configured in DT\n", + dev->active_data_lanes, + dev->max_data_lanes); + ret = -EINVAL; + goto error_pipeline; + } + } -static int unicam_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - struct v4l2_dv_timings current_timings; - int ret; + unicam_dbg(1, dev, "Running with %u data lanes\n", + dev->active_data_lanes); - ret = v4l2_subdev_call(dev->sensor, video, g_dv_timings, - ¤t_timings); + dev->vpu_req = clk_request_start(dev->vpu_clock, MIN_VPU_CLOCK_RATE); + if (!dev->vpu_req) { + unicam_err(dev, "failed to set up VPU clock\n"); + goto error_pipeline; + } - if (ret < 0) - return ret; + ret = clk_prepare_enable(dev->vpu_clock); + if (ret) { + unicam_err(dev, "Failed to enable VPU clock: %d\n", ret); + goto error_pipeline; + } - if (v4l2_match_dv_timings(timings, ¤t_timings, 0, false)) - return 0; + ret = clk_set_rate(dev->clock, 100 * 1000 * 1000); + if (ret) { + unicam_err(dev, "failed to set up CSI clock\n"); + goto err_vpu_clock; + } - if (vb2_is_busy(&node->buffer_queue)) - return -EBUSY; + ret = clk_prepare_enable(dev->clock); + if (ret) { + unicam_err(dev, "Failed to enable CSI clock: %d\n", ret); + goto err_vpu_clock; + } - ret = v4l2_subdev_call(dev->sensor, video, s_dv_timings, timings); + for (i = 0; i < ARRAY_SIZE(dev->node); i++) { + struct unicam_buffer *buf; - /* Force recomputation of bytesperline */ - node->v_fmt.fmt.pix.bytesperline = 0; + if (!dev->node[i].streaming) + continue; - unicam_reset_format(node); + spin_lock_irqsave(&dev->node[i].dma_queue_lock, flags); + buf = list_first_entry(&dev->node[i].dma_queue, + struct unicam_buffer, list); + dev->node[i].cur_frm = buf; + dev->node[i].next_frm = buf; + list_del(&buf->list); + spin_unlock_irqrestore(&dev->node[i].dma_queue_lock, flags); - return ret; -} + buffer_addr[i] = + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + } -static int unicam_query_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; + unicam_start_rx(dev, buffer_addr); - return v4l2_subdev_call(dev->sensor, video, query_dv_timings, timings); -} + ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1); + if (ret < 0) { + unicam_err(dev, "stream on failed in subdev\n"); + goto err_disable_unicam; + } -static int unicam_enum_dv_timings(struct file *file, void *priv, - struct v4l2_enum_dv_timings *timings) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - int ret; + dev->clocks_enabled = true; + return 0; - timings->pad = node->src_pad_id; - ret = v4l2_subdev_call(dev->sensor, pad, enum_dv_timings, timings); - timings->pad = node->pad_id; +err_disable_unicam: + unicam_disable(dev); + clk_disable_unprepare(dev->clock); +err_vpu_clock: + clk_request_done(dev->vpu_req); + clk_disable_unprepare(dev->vpu_clock); +error_pipeline: + media_pipeline_stop(&node->video_dev.entity); +err_pm_put: + unicam_runtime_put(dev); +err_streaming: + unicam_return_buffers(node, VB2_BUF_STATE_QUEUED); + node->streaming = false; return ret; } -static int unicam_dv_timings_cap(struct file *file, void *priv, - struct v4l2_dv_timings_cap *cap) +static void unicam_stop_streaming(struct vb2_queue *vq) { - struct unicam_node *node = video_drvdata(file); + struct unicam_node *node = vb2_get_drv_priv(vq); struct unicam_device *dev = node->dev; - int ret; - cap->pad = node->src_pad_id; - ret = v4l2_subdev_call(dev->sensor, pad, dv_timings_cap, cap); - cap->pad = node->pad_id; - - return ret; -} + node->streaming = false; -static int unicam_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_FRAME_SYNC: - return v4l2_event_subscribe(fh, sub, 2, NULL); - case V4L2_EVENT_SOURCE_CHANGE: - return v4l2_event_subscribe(fh, sub, 4, NULL); - } + if (node->pad_id == IMAGE_PAD) { + /* + * Stop streaming the sensor and disable the peripheral. + * We cannot continue streaming embedded data with the + * image pad disabled. + */ + if (v4l2_subdev_call(dev->sensor, video, s_stream, 0) < 0) + unicam_err(dev, "stream off failed in subdev\n"); - return v4l2_ctrl_subscribe_event(fh, sub); -} + unicam_disable(dev); -static int unicam_log_status(struct file *file, void *fh) -{ - struct unicam_node *node = video_drvdata(file); - struct unicam_device *dev = node->dev; - u32 reg; + media_pipeline_stop(&node->video_dev.entity); - /* status for sub devices */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status); + if (dev->clocks_enabled) { + clk_request_done(dev->vpu_req); + clk_disable_unprepare(dev->vpu_clock); + clk_disable_unprepare(dev->clock); + dev->clocks_enabled = false; + } + unicam_runtime_put(dev); - unicam_info(dev, "-----Receiver status-----\n"); - unicam_info(dev, "V4L2 width/height: %ux%u\n", - node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height); - unicam_info(dev, "Mediabus format: %08x\n", node->fmt->code); - unicam_info(dev, "V4L2 format: %08x\n", - node->v_fmt.fmt.pix.pixelformat); - reg = reg_read(dev, UNICAM_IPIPE); - unicam_info(dev, "Unpacking/packing: %u / %u\n", - get_field(reg, UNICAM_PUM_MASK), - get_field(reg, UNICAM_PPM_MASK)); - unicam_info(dev, "----Live data----\n"); - unicam_info(dev, "Programmed stride: %4u\n", - reg_read(dev, UNICAM_IBLS)); - unicam_info(dev, "Detected resolution: %ux%u\n", - reg_read(dev, UNICAM_IHSTA), - reg_read(dev, UNICAM_IVSTA)); - unicam_info(dev, "Write pointer: %08x\n", - reg_read(dev, UNICAM_IBWP)); + } else if (node->pad_id == METADATA_PAD) { + /* + * Allow the hardware to spin in the dummy buffer. + * This is only really needed if the embedded data pad is + * disabled before the image pad. + */ + unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, + DUMMY_BUF_SIZE, METADATA_PAD); + } - return 0; + /* Clear all queued buffers for the node */ + unicam_return_buffers(node, VB2_BUF_STATE_ERROR); } -static void unicam_notify(struct v4l2_subdev *sd, - unsigned int notification, void *arg) -{ - struct unicam_device *dev = to_unicam_device(sd->v4l2_dev); - - switch (notification) { - case V4L2_DEVICE_NOTIFY_EVENT: - v4l2_event_queue(&dev->node[IMAGE_PAD].video_dev, arg); - break; - default: - break; - } -} static const struct vb2_ops unicam_video_qops = { .wait_prepare = vb2_ops_wait_prepare, @@ -2258,60 +2729,6 @@ static const struct v4l2_file_operations unicam_fops = { .mmap = vb2_fop_mmap, }; -/* unicam capture ioctl operations */ -static const struct v4l2_ioctl_ops unicam_ioctl_ops = { - .vidioc_querycap = unicam_querycap, - .vidioc_enum_fmt_vid_cap = unicam_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = unicam_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = unicam_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = unicam_try_fmt_vid_cap, - - .vidioc_enum_fmt_meta_cap = unicam_enum_fmt_meta_cap, - .vidioc_g_fmt_meta_cap = unicam_g_fmt_meta_cap, - .vidioc_s_fmt_meta_cap = unicam_g_fmt_meta_cap, - .vidioc_try_fmt_meta_cap = unicam_g_fmt_meta_cap, - - .vidioc_enum_input = unicam_enum_input, - .vidioc_g_input = unicam_g_input, - .vidioc_s_input = unicam_s_input, - - .vidioc_querystd = unicam_querystd, - .vidioc_s_std = unicam_s_std, - .vidioc_g_std = unicam_g_std, - - .vidioc_g_edid = unicam_g_edid, - .vidioc_s_edid = unicam_s_edid, - - .vidioc_enum_framesizes = unicam_enum_framesizes, - .vidioc_enum_frameintervals = unicam_enum_frameintervals, - - .vidioc_g_selection = unicam_g_selection, - .vidioc_s_selection = unicam_s_selection, - - .vidioc_g_parm = unicam_g_parm, - .vidioc_s_parm = unicam_s_parm, - - .vidioc_s_dv_timings = unicam_s_dv_timings, - .vidioc_g_dv_timings = unicam_g_dv_timings, - .vidioc_query_dv_timings = unicam_query_dv_timings, - .vidioc_enum_dv_timings = unicam_enum_dv_timings, - .vidioc_dv_timings_cap = unicam_dv_timings_cap, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - - .vidioc_log_status = unicam_log_status, - .vidioc_subscribe_event = unicam_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - static int unicam_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, @@ -2362,11 +2779,11 @@ static void unicam_node_release(struct video_device *vdev) unicam_put(node->dev); } -static int register_node(struct unicam_device *unicam, struct unicam_node *node, - enum v4l2_buf_type type, int pad_id) +static int unicam_set_default_format(struct unicam_device *unicam, + struct unicam_node *node, + int pad_id, + const struct unicam_fmt **ret_fmt) { - struct video_device *vdev; - struct vb2_queue *q; struct v4l2_mbus_framefmt mbus_fmt = {0}; const struct unicam_fmt *fmt; int ret; @@ -2411,15 +2828,69 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, node->v_fmt.fmt.meta.dataformat = fmt->fourcc; } + *ret_fmt = fmt; + + return 0; +} + +static void unicam_mc_set_default_format(struct unicam_node *node, int pad_id) +{ + if (pad_id == IMAGE_PAD) { + struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_fmt->pixelformat = formats[0].fourcc; + unicam_calc_format_size_bpl(node->dev, &formats[0], + &node->v_fmt); + node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + node->fmt = &formats[0]; + } else { + const struct unicam_fmt *fmt; + + /* Fix this node format as embedded data. */ + fmt = find_format_by_code(MEDIA_BUS_FMT_SENSOR_DATA); + node->v_fmt.fmt.meta.dataformat = fmt->fourcc; + node->fmt = fmt; + + node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE; + node->embedded_lines = 1; + node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; + } +} + +static int register_node(struct unicam_device *unicam, struct unicam_node *node, + enum v4l2_buf_type type, int pad_id) +{ + struct video_device *vdev; + struct vb2_queue *q; + int ret; + node->dev = unicam; node->pad_id = pad_id; - node->fmt = fmt; - /* Read current subdev format */ - if (fmt) - unicam_reset_format(node); + if (!unicam->mc_api) { + const struct unicam_fmt *fmt; + + ret = unicam_set_default_format(unicam, node, pad_id, &fmt); + if (ret) + return ret; + node->fmt = fmt; + /* Read current subdev format */ + if (fmt) + unicam_reset_format(node); + } else { + unicam_mc_set_default_format(node, pad_id); + } - if (v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + if (!unicam->mc_api && + v4l2_subdev_has_op(unicam->sensor, video, s_std)) { v4l2_std_id tvnorms; if (WARN_ON(!v4l2_subdev_has_op(unicam->sensor, video, @@ -2442,12 +2913,15 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, vdev = &node->video_dev; if (pad_id == IMAGE_PAD) { - /* Add controls from the subdevice */ - ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, - unicam->sensor->ctrl_handler, NULL, - true); - if (ret < 0) - return ret; + if (!unicam->mc_api) { + /* Add controls from the subdevice */ + ret = v4l2_ctrl_add_handler(&unicam->ctrl_handler, + unicam->sensor->ctrl_handler, + NULL, + true); + if (ret < 0) + return ret; + } /* * If the sensor subdevice has any controls, associate the node @@ -2479,7 +2953,8 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, vdev->release = unicam_node_release; vdev->fops = &unicam_fops; - vdev->ioctl_ops = &unicam_ioctl_ops; + vdev->ioctl_ops = unicam->mc_api ? &unicam_mc_ioctl_ops : + &unicam_ioctl_ops; vdev->v4l2_dev = &unicam->v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; @@ -2487,6 +2962,10 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, vdev->device_caps = (pad_id == IMAGE_PAD) ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_META_CAPTURE; vdev->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (unicam->mc_api) { + vdev->device_caps |= V4L2_CAP_IO_MC; + vdev->entity.ops = &unicam_mc_entity_ops; + } /* Define the device names */ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME, @@ -2506,48 +2985,61 @@ static int register_node(struct unicam_device *unicam, struct unicam_node *node, unicam_err(unicam, "Unable to allocate dummy buffer.\n"); return -ENOMEM; } - - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, video, s_std)) { - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD); - } - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, video, querystd)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD); - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_DV_TIMINGS_CAP); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_DV_TIMINGS); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_DV_TIMINGS); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_DV_TIMINGS); - v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERY_DV_TIMINGS); - } - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_interval)) - v4l2_disable_ioctl(&node->video_dev, - VIDIOC_ENUM_FRAMEINTERVALS); - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, video, g_frame_interval)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM); - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, video, s_frame_interval)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM); - - if (pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, pad, enum_frame_size)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); - - if (node->pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, pad, set_selection)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_SELECTION); - - if (node->pad_id == METADATA_PAD || - !v4l2_subdev_has_op(unicam->sensor, pad, get_selection)) - v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_SELECTION); + if (!unicam->mc_api) { + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, s_std)) { + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUMSTD); + } + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, querystd)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_QUERYSTD); + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, s_dv_timings)) { + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_EDID); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_DV_TIMINGS); + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_QUERY_DV_TIMINGS); + } + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, pad, + enum_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, + g_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_G_PARM); + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, video, + s_frame_interval)) + v4l2_disable_ioctl(&node->video_dev, VIDIOC_S_PARM); + + if (pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, pad, + enum_frame_size)) + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMESIZES); + + if (node->pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, pad, set_selection)) + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_S_SELECTION); + + if (node->pad_id == METADATA_PAD || + !v4l2_subdev_has_op(unicam->sensor, pad, get_selection)) + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_G_SELECTION); + } ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { @@ -2614,7 +3106,7 @@ static int unicam_async_complete(struct v4l2_async_notifier *notifier) if (unicam->sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) { if (source_pads < MAX_NODES) { unicam->node[source_pads].src_pad_id = i; - unicam_err(unicam, "source pad %u is index %u\n", + unicam_dbg(3, unicam, "source pad %u is index %u\n", source_pads, i); } source_pads++; @@ -2643,7 +3135,10 @@ static int unicam_async_complete(struct v4l2_async_notifier *notifier) } } - ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); + if (unicam->mc_api) + ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev); + else + ret = v4l2_device_register_ro_subdev_nodes(&unicam->v4l2_dev); if (ret) { unicam_err(unicam, "Unable to register subdev nodes.\n"); goto unregister; @@ -2803,6 +3298,14 @@ static int unicam_probe(struct platform_device *pdev) kref_init(&unicam->kref); unicam->pdev = pdev; + /* + * Adopt the current setting of the module parameter, and check if + * device tree requests it. + */ + unicam->mc_api = media_controller; + if (of_property_read_bool(pdev->dev.of_node, "brcm,media-controller")) + unicam->mc_api = true; + unicam->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(unicam->base)) { unicam_err(unicam, "Failed to get main io block\n"); -- Gitee From 753160ebd71ec80d1a91ee5bf5e044b5fa8eb506 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 5 Jul 2016 11:41:15 +0200 Subject: [PATCH 011/155] media: v4l: subdev: Improve link format validation debug messages Commit db8e94e7cf27d8bc101ef5b8ee5c1af77cd5b1c9 upstream The existing link format validation failure debug message in media-entity.c helped to pinpoint the point of failure but provided no additional information what's wrong. Tell the user exactly why the validation failed. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 48 +++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index fbf0dcb313c8..bf3aa9252458 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -768,21 +768,55 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt) { + bool pass = true; + /* The width, height and code must match. */ - if (source_fmt->format.width != sink_fmt->format.width - || source_fmt->format.height != sink_fmt->format.height - || source_fmt->format.code != sink_fmt->format.code) - return -EPIPE; + if (source_fmt->format.width != sink_fmt->format.width) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: width does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.width, sink_fmt->format.width); + pass = false; + } + + if (source_fmt->format.height != sink_fmt->format.height) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: height does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.height, sink_fmt->format.height); + pass = false; + } + + if (source_fmt->format.code != sink_fmt->format.code) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n", + __func__, + source_fmt->format.code, sink_fmt->format.code); + pass = false; + } /* The field order must match, or the sink field order must be NONE * to support interlaced hardware connected to bridges that support * progressive formats only. */ if (source_fmt->format.field != sink_fmt->format.field && - sink_fmt->format.field != V4L2_FIELD_NONE) - return -EPIPE; + sink_fmt->format.field != V4L2_FIELD_NONE) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: field does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.field, sink_fmt->format.field); + pass = false; + } - return 0; + if (pass) + return 0; + + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: link was \"%s\":%u -> \"%s\":%u\n", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + return -EPIPE; } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); -- Gitee From a6ec106ff6cd0f1d75f9a0f909141239083000c3 Mon Sep 17 00:00:00 2001 From: John Cox Date: Fri, 22 Oct 2021 13:11:38 +0100 Subject: [PATCH 012/155] media: bcm2835-codec: Limit video callbacks Limit the number of allowed video callbacks. This helps with limiting the size of the coded input FIFO which in turn helps to control latency. Choose -5 as the magic number as it translates to DPB+5 buffers which has been proven to be a good number in the past. Ideally coded buffers would not be returned to the user until they had been decoded into the DPB or been discarded as bad, but that grade of control is unavailable to us. Signed-off-by: John Cox --- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 6078d6e2ace0..e8452c82d088 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -2510,6 +2510,14 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx) MMAL_PARAMETER_VIDEO_STOP_ON_PAR_COLOUR_CHANGE, &enable, sizeof(enable)); + + enable = (unsigned int)-5; + vchiq_mmal_port_parameter_set(dev->instance, + &ctx->component->control, + MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS, + &enable, + sizeof(enable)); + } else if (dev->role == DEINTERLACE) { /* Select the default deinterlace algorithm. */ int half_framerate = 0; -- Gitee From ca8b1c0981b0de3c9095aadace27013873f15eff Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 25 Oct 2021 11:48:18 +0100 Subject: [PATCH 013/155] ARM: dts: vc4-kms-v3d: Always disable firmware HDMI Both the firmware audio driver and the vc4-kms-v3d driver are capable of providing HDMI audio, but only one should be active at any time. The vc4-kms-v3d overlays disable the firmware audio driver, but they also have a noaudio parameter that as well as disabling the ARM-side HDMI audio also re-enables the firmware HDMI audio. This is not guaranteed to work and has been seen to break the display completely. Modify the noaudio parameters so that the firmware HDMI audio support remains disabled. See: https://github.com/raspberrypi/linux/issues/4651 Signed-off-by: Phil Elwell --- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 4 ++-- arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts index 5a4efdeed663..62e1d77a8182 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts @@ -116,8 +116,8 @@ }; __overrides__ { - audio = <0>,"!13", <0>,"=14"; - noaudio = <0>,"=13", <0>,"!14"; + audio = <0>,"!13"; + noaudio = <0>,"=13"; nocomposite = <0>, "!11"; }; }; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts index 4285e12a4e53..76229cad7803 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-pi4-overlay.dts @@ -180,7 +180,7 @@ __overrides__ { audio = <0>,"!17"; audio1 = <0>,"!18"; - noaudio = <0>,"=17", <0>,"=18", <0>,"!19"; + noaudio = <0>,"=17", <0>,"=18"; composite = <0>, "!1", <0>, "!2", <0>, "!3", -- Gitee From 62d4560f35fce9f8253aa88690b63a56a9fd768d Mon Sep 17 00:00:00 2001 From: soyer Date: Sat, 23 Oct 2021 12:23:50 +0200 Subject: [PATCH 014/155] staging/bcm2835-camera: Add support for H264_MIN_QP, H264_MAX_QP Signed-off-by: Gergo Koteles --- .../bcm2835-camera/bcm2835-camera.h | 2 +- .../vc04_services/bcm2835-camera/controls.c | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h index 75524adff0f5..a78973ae94de 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h @@ -13,7 +13,7 @@ * core driver device */ -#define V4L2_CTRL_COUNT 29 /* number of v4l controls */ +#define V4L2_CTRL_COUNT 31 /* number of v4l controls */ enum { COMP_CAMERA = 0, diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index f3480a5c5170..de59f435696d 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -1270,6 +1270,28 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { .mmal_id = MMAL_PARAMETER_INTRAPERIOD, .setter = ctrl_set_video_encode_param_output, }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 51, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, + .setter = ctrl_set_video_encode_param_output, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 51, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, + .setter = ctrl_set_video_encode_param_output, + }, }; int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) -- Gitee From c7b362a27ae3a7229e41fbe6b4be58c57a56cda3 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Sun, 24 Oct 2021 23:18:09 +0200 Subject: [PATCH 015/155] staging/bcm2835-camera: Add support for MPEG_VIDEO_FORCE_KEY_FRAME Signed-off-by: Gergo Koteles --- .../vc04_services/bcm2835-camera/bcm2835-camera.h | 2 +- .../staging/vc04_services/bcm2835-camera/controls.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h index a78973ae94de..fdbcc35ece5b 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h @@ -13,7 +13,7 @@ * core driver device */ -#define V4L2_CTRL_COUNT 31 /* number of v4l controls */ +#define V4L2_CTRL_COUNT 32 /* number of v4l controls */ enum { COMP_CAMERA = 0, diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index de59f435696d..b1b02fbc473d 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -1292,6 +1292,17 @@ static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { .mmal_id = MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, .setter = ctrl_set_video_encode_param_output, }, + { + .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 0, + .def = 0, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, + .setter = ctrl_set_video_encode_param_output, + }, }; int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) -- Gitee From 98ac7c1ac0b1d981c6b5425e083235998f3d6713 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Tue, 19 Oct 2021 14:13:53 +0100 Subject: [PATCH 016/155] clk-raspberrypi: Support VEC clock Signed-off-by: Dom Cobley --- drivers/clk/bcm/clk-raspberrypi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 94ce38a2d5aa..0e3be5ec61ca 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -33,6 +33,7 @@ enum rpi_firmware_clk_id { RPI_FIRMWARE_EMMC2_CLK_ID, RPI_FIRMWARE_M2MC_CLK_ID, RPI_FIRMWARE_PIXEL_BVB_CLK_ID, + RPI_FIRMWARE_VEC_CLK_ID, RPI_FIRMWARE_NUM_CLK_ID, }; @@ -51,6 +52,7 @@ static char *rpi_firmware_clk_names[] = { [RPI_FIRMWARE_EMMC2_CLK_ID] = "emmc2", [RPI_FIRMWARE_M2MC_CLK_ID] = "m2mc", [RPI_FIRMWARE_PIXEL_BVB_CLK_ID] = "pixel-bvb", + [RPI_FIRMWARE_VEC_CLK_ID] = "vec", }; #define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) @@ -273,6 +275,7 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, case RPI_FIRMWARE_V3D_CLK_ID: case RPI_FIRMWARE_HEVC_CLK_ID: case RPI_FIRMWARE_PIXEL_BVB_CLK_ID: + case RPI_FIRMWARE_VEC_CLK_ID: hw = raspberrypi_clk_register(rpi, clks->parent, clks->id); if (IS_ERR(hw)) -- Gitee From 6d6b92639d6fd2dc69beb3702ab22a7d08e21c7c Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Tue, 19 Oct 2021 14:15:45 +0100 Subject: [PATCH 017/155] dt: Move VEC clock to clk-raspberrypi clk-2835 is deprecated and gets an innacurate clock for VEC (107MHz). Switch to clk-raspberrypi which uses the right PLL to get an accurate 108MHz. Signed-off-by: Dom Cobley --- arch/arm/boot/dts/bcm2711.dtsi | 2 +- arch/arm/boot/dts/bcm2835-common.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index adc402fa376b..7ec51452d384 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -303,7 +303,7 @@ vec: vec@7ec13000 { compatible = "brcm,bcm2711-vec"; reg = <0x7ec13000 0x1000>; - clocks = <&clocks BCM2835_CLOCK_VEC>; + clocks = <&firmware_clocks 15>; interrupts = ; status = "disabled"; }; diff --git a/arch/arm/boot/dts/bcm2835-common.dtsi b/arch/arm/boot/dts/bcm2835-common.dtsi index 06d8c3882cb7..15f3975f1ca1 100644 --- a/arch/arm/boot/dts/bcm2835-common.dtsi +++ b/arch/arm/boot/dts/bcm2835-common.dtsi @@ -109,7 +109,7 @@ vec: vec@7e806000 { compatible = "brcm,bcm2835-vec"; reg = <0x7e806000 0x1000>; - clocks = <&clocks BCM2835_CLOCK_VEC>; + clocks = <&firmware_clocks 15>; interrupts = <2 27>; status = "disabled"; }; -- Gitee From f53d15cb31713b8a23167ddd8917f7589deb384d Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Tue, 19 Oct 2021 14:14:55 +0100 Subject: [PATCH 018/155] clk-bcm2835: Remove VEC clock support Signed-off-by: Dom Cobley --- drivers/clk/bcm/clk-bcm2835.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 39fabced602a..7fc2d55add2e 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -2214,21 +2214,6 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .frac_bits = 12, .tcnt_mux = 28), - /* TV encoder clock. Only operating frequency is 108Mhz. */ - [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( - SOC_ALL, - .name = "vec", - .ctl_reg = CM_VECCTL, - .div_reg = CM_VECDIV, - .int_bits = 4, - .frac_bits = 0, - /* - * Allow rate change propagation only on PLLH_AUX which is - * assigned index 7 in the parent array. - */ - .set_rate_parent = BIT(7), - .tcnt_mux = 29), - /* dsi clocks */ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( SOC_ALL, -- Gitee From b26136e71c5899b27b3a7423ad4ad98a9d23bf85 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 27 Apr 2021 14:24:21 +0200 Subject: [PATCH 019/155] drm/vc4: Add support for gamma on BCM2711 BCM2711 changes from a 256 entry lookup table to a 16 point piecewise linear function as the pipeline bitdepth has increased to make a LUT unwieldy. Implement a simple conversion from a 256 entry LUT that userspace is likely to expect to 16 evenly spread points in the PWL. This could be improved with curve fitting at a later date. Co-developed-by: Juerg Haefliger Signed-off-by: Juerg Haefliger Signed-off-by: Dave Stevenson Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 35 +++++++++++--- drivers/gpu/drm/vc4/vc4_drv.h | 28 +++++++++-- drivers/gpu/drm/vc4/vc4_hvs.c | 87 ++++++++++++++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_regs.h | 22 +++++++++ 4 files changed, 159 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 59e10c37b740..0f9d57a7762a 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1189,19 +1189,42 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, if (!vc4->hvs->hvs5) { drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); + } else { + /* This is a lie for hvs5 which uses a 16 point PWL, but it + * allows for something smarter than just 16 linearly spaced + * segments. Conversion is done in vc5_hvs_update_gamma_lut. + */ + drm_mode_crtc_set_gamma_size(crtc, 256); + } - drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); + if (!vc4->hvs->hvs5) { /* We support CTM, but only for one CRTC at a time. It's therefore * implemented as private driver state in vc4_kms, not here. */ drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); - } - for (i = 0; i < crtc->gamma_size; i++) { - vc4_crtc->lut_r[i] = i; - vc4_crtc->lut_g[i] = i; - vc4_crtc->lut_b[i] = i; + /* Initialize the VC4 gamma LUTs */ + for (i = 0; i < crtc->gamma_size; i++) { + vc4_crtc->lut_r[i] = i; + vc4_crtc->lut_g[i] = i; + vc4_crtc->lut_b[i] = i; + } + } else { + /* Initialize the VC5 gamma PWL entries. Assume 12-bit pipeline, + * evenly spread over full range. + */ + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { + vc4_crtc->pwl_r[i] = + VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); + vc4_crtc->pwl_g[i] = + VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); + vc4_crtc->pwl_b[i] = + VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); + vc4_crtc->pwl_a[i] = + VC5_HVS_SET_GAMMA_ENTRY(i << 8, i << 12, 1 << 8); + } } return 0; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 7c749e08cb0c..0a07755b7b5e 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -19,6 +19,7 @@ #include #include "uapi/drm/vc4_drm.h" +#include "vc4_regs.h" struct drm_device; struct drm_gem_object; @@ -482,6 +483,17 @@ struct vc4_pv_data { }; +struct vc5_gamma_entry { + u32 x_c_terms; + u32 grad_term; +}; + +#define VC5_HVS_SET_GAMMA_ENTRY(x, c, g) (struct vc5_gamma_entry){ \ + .x_c_terms = VC4_SET_FIELD((x), SCALER5_DSPGAMMA_OFF_X) | \ + VC4_SET_FIELD((c), SCALER5_DSPGAMMA_OFF_C), \ + .grad_term = (g) \ +} + struct vc4_crtc { struct drm_crtc base; struct platform_device *pdev; @@ -491,9 +503,19 @@ struct vc4_crtc { /* Timestamp at start of vblank irq - unaffected by lock delays. */ ktime_t t_vblank; - u8 lut_r[256]; - u8 lut_g[256]; - u8 lut_b[256]; + union { + struct { /* VC4 gamma LUT */ + u8 lut_r[256]; + u8 lut_g[256]; + u8 lut_b[256]; + }; + struct { /* VC5 gamma PWL entries */ + struct vc5_gamma_entry pwl_r[SCALER5_DSPGAMMA_NUM_POINTS]; + struct vc5_gamma_entry pwl_g[SCALER5_DSPGAMMA_NUM_POINTS]; + struct vc5_gamma_entry pwl_b[SCALER5_DSPGAMMA_NUM_POINTS]; + struct vc5_gamma_entry pwl_a[SCALER5_DSPGAMMA_NUM_POINTS]; + }; + }; struct drm_pending_vblank_event *event; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 6049923422d0..c4851e1436c2 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -236,6 +236,80 @@ static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc) vc4_hvs_lut_load(crtc); } +static void vc5_hvs_write_gamma_entry(struct vc4_dev *vc4, + u32 offset, + struct vc5_gamma_entry *gamma) +{ + HVS_WRITE(offset, gamma->x_c_terms); + HVS_WRITE(offset + 4, gamma->grad_term); +} + +static void vc5_hvs_lut_load(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + u32 i; + u32 offset = SCALER5_DSPGAMMA_START + + vc4_state->assigned_channel * SCALER5_DSPGAMMA_CHAN_OFFSET; + + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) + vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_r[i]); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) + vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_g[i]); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) + vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_b[i]); + + if (vc4_state->assigned_channel == 2) { + /* Alpha only valid on channel 2 */ + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) + vc5_hvs_write_gamma_entry(vc4, offset, &vc4_crtc->pwl_a[i]); + } +} + +static void vc5_hvs_update_gamma_lut(struct drm_crtc *crtc) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_color_lut *lut = crtc->state->gamma_lut->data; + unsigned int step, i; + u32 start, end; + +#define VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl, chan) \ + start = drm_color_lut_extract(lut[i * step].chan, 12); \ + end = drm_color_lut_extract(lut[(i + 1) * step - 1].chan, 12); \ + \ + /* Negative gradients not permitted by the hardware, so \ + * flatten such points out. \ + */ \ + if (end < start) \ + end = start; \ + \ + /* Assume 12bit pipeline. \ + * X evenly spread over full range (12 bit). \ + * C as U12.4 format. \ + * Gradient as U4.8 format. \ + */ \ + vc4_crtc->pwl[i] = \ + VC5_HVS_SET_GAMMA_ENTRY(i << 8, start << 4, \ + ((end - start) << 4) / (step - 1)) + + /* HVS5 has a 16 point piecewise linear function for each colour + * channel (including alpha on channel 2) on each display channel. + * + * Currently take a crude subsample of the gamma LUT, but this could + * be improved to implement curve fitting. + */ + step = crtc->gamma_size / SCALER5_DSPGAMMA_NUM_POINTS; + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++) { + VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_r, red); + VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_g, green); + VC5_HVS_UPDATE_GAMMA_ENTRY_FROM_LUT(pwl_b, blue); + } + + vc5_hvs_lut_load(crtc); +} + int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output) { struct vc4_dev *vc4 = to_vc4_dev(dev); @@ -329,14 +403,16 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc, dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | - SCALER_DISPBKGND_AUTOHS | - ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) | + SCALER_DISPBKGND_AUTOHS | SCALER_DISPBKGND_GAMMA | (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); /* Reload the LUT, since the SRAMs would have been disabled if * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once. */ - vc4_hvs_lut_load(crtc); + if (!vc4->hvs->hvs5) + vc4_hvs_lut_load(crtc); + else + vc5_hvs_lut_load(crtc); return 0; } @@ -520,7 +596,10 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)); if (crtc->state->gamma_lut) { - vc4_hvs_update_gamma_lut(crtc); + if (!vc4->hvs->hvs5) + vc4_hvs_update_gamma_lut(crtc); + else + vc5_hvs_update_gamma_lut(crtc); dispbkgndx |= SCALER_DISPBKGND_GAMMA; } else { /* Unsetting DISPBKGND_GAMMA skips the gamma lut step diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 7538b84a6dca..5989b2ff28c7 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -491,6 +491,28 @@ #define SCALER_DLIST_START 0x00002000 #define SCALER_DLIST_SIZE 0x00004000 +/* Gamma PWL for each channel. 16 points for each of 4 colour channels (alpha + * only on channel 2). 8 bytes per entry, offsets first, then gradient: + * Y = GRAD * X + C + * + * Values for X and C are left justified, and vary depending on the width of + * the HVS channel: + * 8-bit pipeline: X uses [31:24], C is U8.8 format, and GRAD is U4.8. + * 12-bit pipeline: X uses [31:20], C is U12.4 format, and GRAD is U4.8. + * + * The 3 HVS channels start at 0x400 offsets (ie chan 1 starts at 0x2400, and + * chan 2 at 0x2800). + */ +#define SCALER5_DSPGAMMA_NUM_POINTS 16 +#define SCALER5_DSPGAMMA_START 0x00002000 +#define SCALER5_DSPGAMMA_CHAN_OFFSET 0x400 +# define SCALER5_DSPGAMMA_OFF_X_MASK VC4_MASK(31, 20) +# define SCALER5_DSPGAMMA_OFF_X_SHIFT 20 +# define SCALER5_DSPGAMMA_OFF_C_MASK VC4_MASK(15, 0) +# define SCALER5_DSPGAMMA_OFF_C_SHIFT 0 +# define SCALER5_DSPGAMMA_GRAD_MASK VC4_MASK(11, 0) +# define SCALER5_DSPGAMMA_GRAD_SHIFT 0 + #define SCALER5_DLIST_START 0x00004000 # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1) -- Gitee From 7a230c0ae2a0c80d46ada966994767962f95350d Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 28 Apr 2021 12:32:10 +0200 Subject: [PATCH 020/155] drm/vc4: Add debugfs node that dumps the vc5 gamma PWL entries This helps with debugging the conversion from a 256 point gamma LUT to 16 point PWL entries as used by the BCM2711. Co-developed-by: Juerg Haefliger Signed-off-by: Juerg Haefliger Signed-off-by: Dave Stevenson Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hvs.c | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index c4851e1436c2..941c7e3b6ed4 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -134,6 +134,84 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) return 0; } +static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_printer p = drm_seq_file_printer(m); + unsigned int i, chan; + u32 dispstat, dispbkgndx; + + for (chan = 0; chan < SCALER_CHANNELS_COUNT; chan++) { + u32 x_c, grad; + u32 offset = SCALER5_DSPGAMMA_START + + chan * SCALER5_DSPGAMMA_CHAN_OFFSET; + + dispstat = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)), + SCALER_DISPSTATX_MODE); + if (dispstat == SCALER_DISPSTATX_MODE_DISABLED || + dispstat == SCALER_DISPSTATX_MODE_EOF) { + drm_printf(&p, "HVS channel %u: Channel disabled\n", chan); + continue; + } + + dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan)); + if (!(dispbkgndx & SCALER_DISPBKGND_GAMMA)) { + drm_printf(&p, "HVS channel %u: Gamma disabled\n", chan); + continue; + } + + drm_printf(&p, "HVS channel %u:\n", chan); + drm_printf(&p, " red:\n"); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { + x_c = HVS_READ(offset); + grad = HVS_READ(offset + 4); + drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", + x_c, grad, + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), + grad); + } + drm_printf(&p, " green:\n"); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { + x_c = HVS_READ(offset); + grad = HVS_READ(offset + 4); + drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", + x_c, grad, + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), + grad); + } + drm_printf(&p, " blue:\n"); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { + x_c = HVS_READ(offset); + grad = HVS_READ(offset + 4); + drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", + x_c, grad, + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), + grad); + } + + /* Alpha only valid on channel 2 */ + if (chan != 2) + continue; + + drm_printf(&p, " alpha:\n"); + for (i = 0; i < SCALER5_DSPGAMMA_NUM_POINTS; i++, offset += 8) { + x_c = HVS_READ(offset); + grad = HVS_READ(offset + 4); + drm_printf(&p, " %08x %08x - x %u, c %u, grad %u\n", + x_c, grad, + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_X), + VC4_GET_FIELD(x_c, SCALER5_DSPGAMMA_OFF_C), + grad); + } + } + return 0; +} + /* The filter kernel is composed of dwords each containing 3 9-bit * signed integers packed next to each other. */ @@ -795,6 +873,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) NULL); vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL); + if (hvs->hvs5) + vc4_debugfs_add_file(drm, "hvs_gamma", vc5_hvs_debugfs_gamma, + NULL); return 0; } -- Gitee From 523f57df7b3351f994cef977afefb0096103876f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 14 Jun 2021 15:28:30 +0200 Subject: [PATCH 021/155] drm/vc4: hvs: Force modeset on gamma lut change The HVS Gamma block can only be updated when idle, so we need to disable the HVS channel when the gamma property is set in an atomic commit. Since the pixelvalve cannot have its assigned channel halted without stalling unless it's disabled as well, in our case that means forcing a full disable / enable cycle on the pipeline. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 17 +++++++++++++++++ drivers/gpu/drm/vc4/vc4_drv.h | 3 +++ drivers/gpu/drm/vc4/vc4_hvs.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 0f9d57a7762a..e349a5a55c67 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -292,6 +292,23 @@ struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, return NULL; } +#define drm_for_each_connector_mask(connector, dev, connector_mask) \ + list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \ + for_each_if ((connector_mask) & drm_connector_mask(connector)) + +struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_connector *connector; + + WARN_ON(hweight32(state->connector_mask) > 1); + + drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask) + return connector; + + return NULL; +} + static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 0a07755b7b5e..6a260b1e60ad 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -542,6 +542,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) return container_of(data, struct vc4_pv_data, base); } +struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, + struct drm_crtc_state *state); + struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, struct drm_crtc_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 941c7e3b6ed4..1eeb0cd73a2b 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -519,6 +519,36 @@ void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan) SCALER_DISPSTATX_EMPTY); } +static int vc4_hvs_gamma_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + + if (!vc4->hvs->hvs5) + return 0; + + if (!crtc_state->color_mgmt_changed) + return 0; + + connector = vc4_get_crtc_connector(crtc, crtc_state); + if (!connector) + return -EINVAL; + + if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) + return 0; + + conn_state = drm_atomic_get_connector_state(state, connector); + if (!conn_state) + return -EINVAL; + + crtc_state->mode_changed = true; + return 0; +} + int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); @@ -549,7 +579,7 @@ int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) if (ret) return ret; - return 0; + return vc4_hvs_gamma_check(crtc, state); } static void vc4_hvs_update_dlist(struct drm_crtc *crtc) -- Gitee From 9c3162619d6f1bd73532464fc38a8375bb47842b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Sep 2021 10:37:15 +0100 Subject: [PATCH 022/155] ARM: dts: Add Pi Zero 2 support Signed-off-by: Phil Elwell --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/bcm2710-rpi-zero-2.dts | 177 ++++++++++++++++++ arch/arm64/boot/dts/broadcom/Makefile | 1 + .../boot/dts/broadcom/bcm2710-rpi-zero-2.dts | 1 + 4 files changed, 180 insertions(+) create mode 100644 arch/arm/boot/dts/bcm2710-rpi-zero-2.dts create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 12cd8bf582e1..66956d0f2c18 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -7,6 +7,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ bcm2708-rpi-cm.dtb \ bcm2708-rpi-zero.dtb \ bcm2708-rpi-zero-w.dtb \ + bcm2710-rpi-zero-2.dtb \ bcm2709-rpi-2-b.dtb \ bcm2710-rpi-2-b.dtb \ bcm2710-rpi-3-b.dtb \ diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts new file mode 100644 index 000000000000..42185a450666 --- /dev/null +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts @@ -0,0 +1,177 @@ +/dts-v1/; + +#include "bcm2710.dtsi" +#include "bcm2709-rpi.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm2708-rpi-bt.dtsi" +#include "bcm283x-rpi-cam1-regulator.dtsi" + +/ { + compatible = "raspberrypi,model-zero-2", "brcm,bcm2837"; + model = "Raspberry Pi Zero 2"; + + chosen { + bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; + }; + + aliases { + serial0 = &uart1; + serial1 = &uart0; + mmc1 = &mmcnr; + }; +}; + +&gpio { + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ + }; + + spi0_cs_pins: spi0_cs_pins { + brcm,pins = <8 7>; + brcm,function = <1>; /* output */ + }; + + i2c0_pins: i2c0 { + brcm,pins = <0 1>; + brcm,function = <4>; + }; + + i2c1_pins: i2c1 { + brcm,pins = <2 3>; + brcm,function = <4>; + }; + + i2s_pins: i2s { + brcm,pins = <18 19 20 21>; + brcm,function = <4>; /* alt0 */ + }; + + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = <7>; // alt3 = SD1 + brcm,pull = <0 2 2 2 2 2>; + }; + + bt_pins: bt_pins { + brcm,pins = <43>; + brcm,function = <4>; /* alt0:GPCLK2 */ + brcm,pull = <0>; + }; + + uart0_pins: uart0_pins { + brcm,pins = <30 31 32 33>; + brcm,function = <7>; /* alt3=UART0 */ + brcm,pull = <2 0 0 2>; /* up none none up */ + }; + + uart1_pins: uart1_pins { + brcm,pins; + brcm,function; + brcm,pull; + }; + + audio_pins: audio_pins { + brcm,pins = <>; + brcm,function = <>; + }; +}; + +&mmcnr { + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + bus-width = <4>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins &bt_pins>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins &spi0_cs_pins>; + cs-gpios = <&gpio 8 1>, <&gpio 7 1>; + + spidev0: spidev@0{ + compatible = "spidev"; + reg = <0>; /* CE0 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; + + spidev1: spidev@1{ + compatible = "spidev"; + reg = <1>; /* CE1 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; +}; + +&i2c0if { + clock-frequency = <100000>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; +}; + +&i2c2 { + clock-frequency = <100000>; +}; + +&i2s { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; +}; + +&leds { + act_led: led-act { + label = "led0"; + linux,default-trigger = "actpwr"; + gpios = <&gpio 29 GPIO_ACTIVE_LOW>; + }; +}; + +&hdmi { + hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; +}; + +&audio { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; + brcm,disable-headphones = <1>; +}; + +&bt { + shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +}; + +&minibt { + shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +}; + +&cam1_reg { + gpio = <&gpio 40 GPIO_ACTIVE_HIGH>; +}; + +/ { + __overrides__ { + act_led_gpio = <&act_led>,"gpios:4"; + act_led_activelow = <&act_led>,"gpios:8"; + act_led_trigger = <&act_led>,"linux,default-trigger"; + }; +}; diff --git a/arch/arm64/boot/dts/broadcom/Makefile b/arch/arm64/boot/dts/broadcom/Makefile index 69809bf2f45d..e7c2c4fd59a8 100644 --- a/arch/arm64/boot/dts/broadcom/Makefile +++ b/arch/arm64/boot/dts/broadcom/Makefile @@ -3,6 +3,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rpi-3-a-plus.dtb \ bcm2837-rpi-3-b.dtb \ bcm2837-rpi-3-b-plus.dtb \ bcm2837-rpi-cm3-io3.dtb +dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-zero-2.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb diff --git a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts new file mode 100644 index 000000000000..f76f553599ef --- /dev/null +++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-zero-2.dts @@ -0,0 +1 @@ +#include "../../../../arm/boot/dts/bcm2710-rpi-zero-2.dts" -- Gitee From b10c31dd61325f96cd9446161586effc96544458 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 28 Oct 2021 12:16:00 +0100 Subject: [PATCH 023/155] Revert "ARM: proc-v7: Retry uncached stmia if necessary" This reverts commit 3e1698ed5013c1054e3dbf8a9fcd3a8549a95ece. --- arch/arm/mm/proc-v7.S | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index fae01bd02629..2fcffcc60cc6 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -297,11 +297,7 @@ __v7_ca17mp_setup: 1: adr r0, __v7_setup_stack_ptr ldr r12, [r0] add r12, r12, r0 @ the local stack -1: stmia r12, {r1-r6, lr} @ v7_invalidate_l1 touches r0-r6 - ldr r0, [r12, #(6 * 4)] @ read back the return address - teq r0, lr @ confirm it is correct - bne 1b @ retrying if not bl v7_invalidate_l1 ldmia r12, {r1-r6, lr} #ifdef CONFIG_SMP @@ -487,11 +483,7 @@ __v7_setup: adr r0, __v7_setup_stack_ptr ldr r12, [r0] add r12, r12, r0 @ the local stack -1: stmia r12, {r1-r6, lr} @ v7_invalidate_l1 touches r0-r6 - ldr r0, [r12, #(6 * 4)] @ read back the return address - teq r0, lr @ confirm it is correct - bne 1b @ retrying if not bl v7_invalidate_l1 ldmia r12, {r1-r6, lr} -- Gitee From e208f369dc67c2db7a68bd6a2498235f6933b6c9 Mon Sep 17 00:00:00 2001 From: neocortex-vision Date: Thu, 28 Oct 2021 17:37:36 +0100 Subject: [PATCH 024/155] media: i2c: imx477: Add vsync trigger_mode parameter trigger_mode == 0 (default) => no effect / no registers written trigger_mode == 1 => source trigger_mode == 2 => sink This can be set e.g. in /boot/cmdline.txt as imx477.trigger_mode=N Signed-off-by: Jonas Jacob --- drivers/media/i2c/imx477.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/media/i2c/imx477.c b/drivers/media/i2c/imx477.c index cd3296f8ab41..b2d4fb54cb1e 100644 --- a/drivers/media/i2c/imx477.c +++ b/drivers/media/i2c/imx477.c @@ -25,6 +25,10 @@ static int dpc_enable = 1; module_param(dpc_enable, int, 0644); MODULE_PARM_DESC(dpc_enable, "Enable on-sensor DPC"); +static int trigger_mode; +module_param(trigger_mode, int, 0644); +MODULE_PARM_DESC(trigger_mode, "Set vsync trigger mode: 1=source, 2=sink"); + #define IMX477_REG_VALUE_08BIT 1 #define IMX477_REG_VALUE_16BIT 2 @@ -98,6 +102,12 @@ MODULE_PARM_DESC(dpc_enable, "Enable on-sensor DPC"); #define IMX477_TEST_PATTERN_B_DEFAULT 0 #define IMX477_TEST_PATTERN_GB_DEFAULT 0 +/* Trigger mode */ +#define IMX477_REG_MC_MODE 0x3f0b +#define IMX477_REG_MS_SEL 0x3041 +#define IMX477_REG_XVS_IO_CTRL 0x3040 +#define IMX477_REG_EXTOUT_EN 0x4b81 + /* Embedded metadata stream structure */ #define IMX477_EMBEDDED_LINE_WIDTH 16384 #define IMX477_NUM_EMBEDDED_LINES 1 @@ -1719,6 +1729,21 @@ static int imx477_start_streaming(struct imx477 *imx477) imx477_write_reg(imx477, 0x0b05, IMX477_REG_VALUE_08BIT, !!dpc_enable); imx477_write_reg(imx477, 0x0b06, IMX477_REG_VALUE_08BIT, !!dpc_enable); + /* Set vsync trigger mode */ + if (trigger_mode != 0) { + /* trigger_mode == 1 for source, 2 for sink */ + const u32 val = (trigger_mode == 1) ? 1 : 0; + + imx477_write_reg(imx477, IMX477_REG_MC_MODE, + IMX477_REG_VALUE_08BIT, 1); + imx477_write_reg(imx477, IMX477_REG_MS_SEL, + IMX477_REG_VALUE_08BIT, val); + imx477_write_reg(imx477, IMX477_REG_XVS_IO_CTRL, + IMX477_REG_VALUE_08BIT, val); + imx477_write_reg(imx477, IMX477_REG_EXTOUT_EN, + IMX477_REG_VALUE_08BIT, val); + } + /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx477->sd.ctrl_handler); if (ret) -- Gitee From 09d9d852eb681e14848902b975c04a50a61ae173 Mon Sep 17 00:00:00 2001 From: Mateusz Kwiatkowski Date: Thu, 15 Jul 2021 01:08:08 +0200 Subject: [PATCH 025/155] drm/vc4: Relax VEC modeline requirements and add progressive mode support Make vc4_vec_encoder_atomic_check() accept arbitrary modelines, as long as they result in somewhat sane output from the VEC. The bounds have been determined empirically. Additionally, add support for the progressive 262-line and 312-line modes. Signed-off-by: Mateusz Kwiatkowski --- drivers/gpu/drm/vc4/vc4_crtc.c | 1 + drivers/gpu/drm/vc4/vc4_vec.c | 97 ++++++++++++++++++++++++++++------ 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index e349a5a55c67..8a7b09c6ce80 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -408,6 +408,7 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode CRTC_WRITE(PV_V_CONTROL, PV_VCONTROL_CONTINUOUS | (is_dsi ? PV_VCONTROL_DSI : 0)); + CRTC_WRITE(PV_VSYNCD_EVEN, 0); } CRTC_WRITE(PV_VERTA, diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 596b59ff6c9a..c4250dd0d368 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -429,18 +429,11 @@ static int vc4_vec_connector_atomic_check(struct drm_connector *conn, struct drm_connector_state *new_state = drm_atomic_get_new_connector_state(state, conn); - const struct vc4_vec_tv_mode *vec_mode = - &vc4_vec_tv_modes[new_state->tv.mode]; - - if (new_state->crtc) { + if (new_state->crtc && old_state->tv.mode != new_state->tv.mode) { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc); - if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode)) - return -EINVAL; - - if (old_state->tv.mode != new_state->tv.mode) - crtc_state->mode_changed = true; + crtc_state->mode_changed = true; } return 0; @@ -565,7 +558,10 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) VEC_WRITE(VEC_CLMP0_START, 0xac); VEC_WRITE(VEC_CLMP0_END, 0xec); VEC_WRITE(VEC_CONFIG2, - VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS); + VEC_CONFIG2_UV_DIG_DIS | + VEC_CONFIG2_RGB_DIG_DIS | + ((encoder->crtc->state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN)); VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD); VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config); @@ -588,17 +584,88 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) } -static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { - return true; + const struct drm_display_mode *reference_mode = + vc4_vec_tv_modes[conn_state->tv.mode].mode; + + if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock || + crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal || + crtc_state->adjusted_mode.crtc_hdisplay % 4 != 0 || + crtc_state->adjusted_mode.crtc_hsync_end - + crtc_state->adjusted_mode.crtc_hsync_start < 1) + return -EINVAL; + + switch (reference_mode->vtotal) { + case 525: + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vdisplay > 253 || + crtc_state->adjusted_mode.crtc_vsync_start - + crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vsync_end - + crtc_state->adjusted_mode.crtc_vsync_start != 3 || + crtc_state->adjusted_mode.crtc_vtotal - + crtc_state->adjusted_mode.crtc_vsync_end < 4 || + crtc_state->adjusted_mode.crtc_vtotal > 262) + return -EINVAL; + + if ((crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + (crtc_state->adjusted_mode.vdisplay % 2 != 0 || + crtc_state->adjusted_mode.vsync_start % 2 != 1 || + crtc_state->adjusted_mode.vsync_end % 2 != 1 || + crtc_state->adjusted_mode.vtotal % 2 != 1)) + return -EINVAL; + + /* progressive mode is hard-wired to 262 total lines */ + if (!(crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + crtc_state->adjusted_mode.crtc_vtotal != 262) + return -EINVAL; + + break; + + case 625: + if (crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vdisplay > 305 || + crtc_state->adjusted_mode.crtc_vsync_start - + crtc_state->adjusted_mode.crtc_vdisplay < 1 || + crtc_state->adjusted_mode.crtc_vsync_end - + crtc_state->adjusted_mode.crtc_vsync_start != 3 || + crtc_state->adjusted_mode.crtc_vtotal - + crtc_state->adjusted_mode.crtc_vsync_end < 2 || + crtc_state->adjusted_mode.crtc_vtotal > 312) + return -EINVAL; + + if ((crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + (crtc_state->adjusted_mode.vdisplay % 2 != 0 || + crtc_state->adjusted_mode.vsync_start % 2 != 0 || + crtc_state->adjusted_mode.vsync_end % 2 != 0 || + crtc_state->adjusted_mode.vtotal % 2 != 1)) + return -EINVAL; + + /* progressive mode is hard-wired to 312 total lines */ + if (!(crtc_state->adjusted_mode.flags & + DRM_MODE_FLAG_INTERLACE) && + crtc_state->adjusted_mode.crtc_vtotal != 312) + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + return 0; } static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = { .disable = vc4_vec_encoder_disable, .enable = vc4_vec_encoder_enable, - .mode_fixup = vc4_vec_encoder_mode_fixup, + .atomic_check = vc4_vec_encoder_atomic_check, }; static const struct vc4_vec_variant bcm2835_vec_variant = { -- Gitee From 1ad39e889053c9c697ea773de8e058ab11a83fa1 Mon Sep 17 00:00:00 2001 From: Mateusz Kwiatkowski Date: Thu, 15 Jul 2021 01:08:11 +0200 Subject: [PATCH 026/155] drm/vc4: Make VEC progressive modes readily accessible Add predefined modelines for the 240p (NTSC) and 288p (PAL) progressive modes, and report them through vc4_vec_connector_get_modes(). Signed-off-by: Mateusz Kwiatkowski --- drivers/gpu/drm/vc4/vc4_vec.c | 73 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index c4250dd0d368..255e5c6c48e0 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -251,7 +251,8 @@ enum vc4_vec_tv_mode_id { }; struct vc4_vec_tv_mode { - const struct drm_display_mode *mode; + const struct drm_display_mode *interlaced_mode; + const struct drm_display_mode *progressive_mode; u32 config0; u32 config1; u32 custom_freq; @@ -285,61 +286,81 @@ static const struct debugfs_reg32 vec_regs[] = { }; static const struct drm_display_mode drm_mode_480i = { - DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500, + DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, 480, 480 + 7, 480 + 7 + 6, 525, 0, DRM_MODE_FLAG_INTERLACE) }; +static const struct drm_display_mode drm_mode_240p = { + DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0, + 240, 240 + 3, 240 + 3 + 3, 262, 0, 0) +}; + static const struct drm_display_mode drm_mode_576i = { - DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500, + DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, 576, 576 + 4, 576 + 4 + 6, 625, 0, DRM_MODE_FLAG_INTERLACE) }; +static const struct drm_display_mode drm_mode_288p = { + DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, + 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0, + 288, 288 + 2, 288 + 2 + 3, 312, 0, 0) +}; + static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = { [VC4_VEC_TV_MODE_NTSC] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_NTSC_J] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_NTSC_443] = { /* NTSC with PAL chroma frequency */ - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_NTSC_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, .custom_freq = 0x2a098acb, }, [VC4_VEC_TV_MODE_PAL] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_PAL_BDGHI_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL_M] = { - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_PAL_M_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL_N] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_PAL_N_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, }, [VC4_VEC_TV_MODE_PAL60] = { /* PAL-M with chroma frequency of regular PAL */ - .mode = &drm_mode_480i, + .interlaced_mode = &drm_mode_480i, + .progressive_mode = &drm_mode_240p, .config0 = VEC_CONFIG0_PAL_M_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ, .custom_freq = 0x2a098acb, }, [VC4_VEC_TV_MODE_SECAM] = { - .mode = &drm_mode_576i, + .interlaced_mode = &drm_mode_576i, + .progressive_mode = &drm_mode_288p, .config0 = VEC_CONFIG0_SECAM_STD, .config1 = VEC_CONFIG1_C_CVBS_CVBS, .custom_freq = 0x29c71c72, @@ -399,16 +420,32 @@ static void vc4_vec_connector_destroy(struct drm_connector *connector) static int vc4_vec_connector_get_modes(struct drm_connector *connector) { struct drm_connector_state *state = connector->state; - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, - vc4_vec_tv_modes[state->tv.mode].mode); - if (!mode) { + struct drm_display_mode *interlaced_mode, *progressive_mode; + + interlaced_mode = + drm_mode_duplicate(connector->dev, + vc4_vec_tv_modes[state->tv.mode].interlaced_mode); + progressive_mode = + drm_mode_duplicate(connector->dev, + vc4_vec_tv_modes[state->tv.mode].progressive_mode); + if (!interlaced_mode || !progressive_mode) { DRM_ERROR("Failed to create a new display mode\n"); + drm_mode_destroy(connector->dev, interlaced_mode); + drm_mode_destroy(connector->dev, progressive_mode); return -ENOMEM; } - drm_mode_probed_add(connector, mode); + if (connector->cmdline_mode.specified && + connector->cmdline_mode.refresh_specified && + !connector->cmdline_mode.interlace) + /* progressive mode set at boot, let's make it preferred */ + progressive_mode->type |= DRM_MODE_TYPE_PREFERRED; + else + /* otherwise, interlaced mode is preferred */ + interlaced_mode->type |= DRM_MODE_TYPE_PREFERRED; + + drm_mode_probed_add(connector, interlaced_mode); + drm_mode_probed_add(connector, progressive_mode); return 1; } @@ -589,7 +626,7 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { const struct drm_display_mode *reference_mode = - vc4_vec_tv_modes[conn_state->tv.mode].mode; + vc4_vec_tv_modes[conn_state->tv.mode].interlaced_mode; if (crtc_state->adjusted_mode.crtc_clock != reference_mode->clock || crtc_state->adjusted_mode.crtc_htotal != reference_mode->htotal || -- Gitee From 3813d552caed25ca0a3d76c2383d8cc61e6ceb54 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Sun, 31 Oct 2021 11:47:59 +0000 Subject: [PATCH 027/155] bcm2835-v4l2-codec: Remove advertised support of VP8 The support for this format by firmware is very limited and won't be faster than the arm. Signed-off-by: Dom Cobley --- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index e8452c82d088..351d693873ed 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -597,11 +597,6 @@ static const struct bcm2835_codec_fmt supported_formats[] = { .depth = 0, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal_fmt = MMAL_ENCODING_MP2V, - }, { - .fourcc = V4L2_PIX_FMT_VP8, - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal_fmt = MMAL_ENCODING_VP8, }, { .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, .depth = 0, -- Gitee From ff684e05825defacb2f4544a2415da2ac60edca5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 1 Nov 2021 15:44:31 +0000 Subject: [PATCH 028/155] ARM: dts: Rename Zero 2 W DT files Retain the old names for backwards compatibility for a while, while the necessary firmware change rolls out. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 177 ++++++++++++++++++++ arch/arm/boot/dts/bcm2710-rpi-zero-2.dts | 178 +-------------------- 3 files changed, 179 insertions(+), 177 deletions(-) create mode 100644 arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 66956d0f2c18..c961dfbbad69 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -8,6 +8,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ bcm2708-rpi-zero.dtb \ bcm2708-rpi-zero-w.dtb \ bcm2710-rpi-zero-2.dtb \ + bcm2710-rpi-zero-2-w.dtb \ bcm2709-rpi-2-b.dtb \ bcm2710-rpi-2-b.dtb \ bcm2710-rpi-3-b.dtb \ diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts new file mode 100644 index 000000000000..6d0f0c9aae0f --- /dev/null +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts @@ -0,0 +1,177 @@ +/dts-v1/; + +#include "bcm2710.dtsi" +#include "bcm2709-rpi.dtsi" +#include "bcm283x-rpi-csi1-2lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm2708-rpi-bt.dtsi" +#include "bcm283x-rpi-cam1-regulator.dtsi" + +/ { + compatible = "raspberrypi,model-zero-2-w", "brcm,bcm2837"; + model = "Raspberry Pi Zero 2 W"; + + chosen { + bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; + }; + + aliases { + serial0 = &uart1; + serial1 = &uart0; + mmc1 = &mmcnr; + }; +}; + +&gpio { + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = <4>; /* alt0 */ + }; + + spi0_cs_pins: spi0_cs_pins { + brcm,pins = <8 7>; + brcm,function = <1>; /* output */ + }; + + i2c0_pins: i2c0 { + brcm,pins = <0 1>; + brcm,function = <4>; + }; + + i2c1_pins: i2c1 { + brcm,pins = <2 3>; + brcm,function = <4>; + }; + + i2s_pins: i2s { + brcm,pins = <18 19 20 21>; + brcm,function = <4>; /* alt0 */ + }; + + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = <7>; // alt3 = SD1 + brcm,pull = <0 2 2 2 2 2>; + }; + + bt_pins: bt_pins { + brcm,pins = <43>; + brcm,function = <4>; /* alt0:GPCLK2 */ + brcm,pull = <0>; + }; + + uart0_pins: uart0_pins { + brcm,pins = <30 31 32 33>; + brcm,function = <7>; /* alt3=UART0 */ + brcm,pull = <2 0 0 2>; /* up none none up */ + }; + + uart1_pins: uart1_pins { + brcm,pins; + brcm,function; + brcm,pull; + }; + + audio_pins: audio_pins { + brcm,pins = <>; + brcm,function = <>; + }; +}; + +&mmcnr { + pinctrl-names = "default"; + pinctrl-0 = <&sdio_pins>; + bus-width = <4>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins &bt_pins>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins &spi0_cs_pins>; + cs-gpios = <&gpio 8 1>, <&gpio 7 1>; + + spidev0: spidev@0{ + compatible = "spidev"; + reg = <0>; /* CE0 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; + + spidev1: spidev@1{ + compatible = "spidev"; + reg = <1>; /* CE1 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; +}; + +&i2c0if { + clock-frequency = <100000>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; +}; + +&i2c2 { + clock-frequency = <100000>; +}; + +&i2s { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; +}; + +&leds { + act_led: led-act { + label = "led0"; + linux,default-trigger = "actpwr"; + gpios = <&gpio 29 GPIO_ACTIVE_LOW>; + }; +}; + +&hdmi { + hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; +}; + +&audio { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; + brcm,disable-headphones = <1>; +}; + +&bt { + shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +}; + +&minibt { + shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +}; + +&cam1_reg { + gpio = <&gpio 40 GPIO_ACTIVE_HIGH>; +}; + +/ { + __overrides__ { + act_led_gpio = <&act_led>,"gpios:4"; + act_led_activelow = <&act_led>,"gpios:8"; + act_led_trigger = <&act_led>,"linux,default-trigger"; + }; +}; diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts index 42185a450666..daa12bd30d6b 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2.dts @@ -1,177 +1 @@ -/dts-v1/; - -#include "bcm2710.dtsi" -#include "bcm2709-rpi.dtsi" -#include "bcm283x-rpi-csi1-2lane.dtsi" -#include "bcm283x-rpi-i2c0mux_0_44.dtsi" -#include "bcm2708-rpi-bt.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" - -/ { - compatible = "raspberrypi,model-zero-2", "brcm,bcm2837"; - model = "Raspberry Pi Zero 2"; - - chosen { - bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; - }; - - aliases { - serial0 = &uart1; - serial1 = &uart0; - mmc1 = &mmcnr; - }; -}; - -&gpio { - spi0_pins: spi0_pins { - brcm,pins = <9 10 11>; - brcm,function = <4>; /* alt0 */ - }; - - spi0_cs_pins: spi0_cs_pins { - brcm,pins = <8 7>; - brcm,function = <1>; /* output */ - }; - - i2c0_pins: i2c0 { - brcm,pins = <0 1>; - brcm,function = <4>; - }; - - i2c1_pins: i2c1 { - brcm,pins = <2 3>; - brcm,function = <4>; - }; - - i2s_pins: i2s { - brcm,pins = <18 19 20 21>; - brcm,function = <4>; /* alt0 */ - }; - - sdio_pins: sdio_pins { - brcm,pins = <34 35 36 37 38 39>; - brcm,function = <7>; // alt3 = SD1 - brcm,pull = <0 2 2 2 2 2>; - }; - - bt_pins: bt_pins { - brcm,pins = <43>; - brcm,function = <4>; /* alt0:GPCLK2 */ - brcm,pull = <0>; - }; - - uart0_pins: uart0_pins { - brcm,pins = <30 31 32 33>; - brcm,function = <7>; /* alt3=UART0 */ - brcm,pull = <2 0 0 2>; /* up none none up */ - }; - - uart1_pins: uart1_pins { - brcm,pins; - brcm,function; - brcm,pull; - }; - - audio_pins: audio_pins { - brcm,pins = <>; - brcm,function = <>; - }; -}; - -&mmcnr { - pinctrl-names = "default"; - pinctrl-0 = <&sdio_pins>; - bus-width = <4>; - status = "okay"; -}; - -&uart0 { - pinctrl-names = "default"; - pinctrl-0 = <&uart0_pins &bt_pins>; - status = "okay"; -}; - -&uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&uart1_pins>; - status = "okay"; -}; - -&spi0 { - pinctrl-names = "default"; - pinctrl-0 = <&spi0_pins &spi0_cs_pins>; - cs-gpios = <&gpio 8 1>, <&gpio 7 1>; - - spidev0: spidev@0{ - compatible = "spidev"; - reg = <0>; /* CE0 */ - #address-cells = <1>; - #size-cells = <0>; - spi-max-frequency = <125000000>; - }; - - spidev1: spidev@1{ - compatible = "spidev"; - reg = <1>; /* CE1 */ - #address-cells = <1>; - #size-cells = <0>; - spi-max-frequency = <125000000>; - }; -}; - -&i2c0if { - clock-frequency = <100000>; -}; - -&i2c1 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c1_pins>; - clock-frequency = <100000>; -}; - -&i2c2 { - clock-frequency = <100000>; -}; - -&i2s { - pinctrl-names = "default"; - pinctrl-0 = <&i2s_pins>; -}; - -&leds { - act_led: led-act { - label = "led0"; - linux,default-trigger = "actpwr"; - gpios = <&gpio 29 GPIO_ACTIVE_LOW>; - }; -}; - -&hdmi { - hpd-gpios = <&gpio 28 GPIO_ACTIVE_LOW>; -}; - -&audio { - pinctrl-names = "default"; - pinctrl-0 = <&audio_pins>; - brcm,disable-headphones = <1>; -}; - -&bt { - shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -}; - -&minibt { - shutdown-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -}; - -&cam1_reg { - gpio = <&gpio 40 GPIO_ACTIVE_HIGH>; -}; - -/ { - __overrides__ { - act_led_gpio = <&act_led>,"gpios:4"; - act_led_activelow = <&act_led>,"gpios:8"; - act_led_trigger = <&act_led>,"linux,default-trigger"; - }; -}; +#include "bcm2710-rpi-zero-2-w.dts" -- Gitee From eaa226f7c308127d0eea272a7994918312e56a6e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 2 Nov 2021 11:13:42 +0000 Subject: [PATCH 029/155] brcmfmac: Don't promote INFO logging to ERR An unwanted side effect of enabling the BRCMDBG config setting is redefining brcmf_info to be brcmf_err. This can be alarming to users and makes it harder to spot real errors, so don't do it. See: https://github.com/raspberrypi/linux/issues/4663 Signed-off-by: Phil Elwell --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index 4146faeed344..d7d0f84f3693 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -63,7 +63,12 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...); #if defined(DEBUG) || defined(CONFIG_BRCM_TRACING) /* For debug/tracing purposes treat info messages as errors */ -#define brcmf_info brcmf_err +// #define brcmf_info brcmf_err + +#define brcmf_info(fmt, ...) \ + do { \ + pr_info("%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) __printf(3, 4) void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...); -- Gitee From 65cfcd0f5385090cf64781b01d6aaeec5a46fbf2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 26 Oct 2021 16:38:44 +0100 Subject: [PATCH 030/155] ARM: dt: Add DT nodes for the WLAN interfaces Mirror upstream changes into the downstream dts files. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 7 +++++++ arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 7 +++++++ arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 7 +++++++ arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts index 75a5b41514f9..63faf4986987 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts @@ -83,6 +83,13 @@ pinctrl-0 = <&sdio_pins>; bus-width = <4>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts index 7e12c05cc28b..a1b169e554ba 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts @@ -84,6 +84,13 @@ pinctrl-0 = <&sdio_pins>; bus-width = <4>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; }; &firmware { diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts index d40722ddc286..5cfb9ad76ca9 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts @@ -84,6 +84,13 @@ pinctrl-0 = <&sdio_pins>; bus-width = <4>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; }; &soc { diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts index 6d0f0c9aae0f..2bd223a405a7 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts @@ -83,6 +83,13 @@ pinctrl-0 = <&sdio_pins>; bus-width = <4>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; }; &uart0 { -- Gitee From f719b92451c493b031ff5f7ba3a58a64ec700c84 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 26 Oct 2021 11:24:54 +0100 Subject: [PATCH 031/155] Revert "brcmfmac: BCM43436 needs dedicated firmware" This reverts commit c52581ffa49b9c0e5de3349436c283fe20128073. Replace the hardcoded alternate firmware names with mappings provided from Device Tree. Signed-off-by: Phil Elwell --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 3ab944c39677..f6c51680988d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -618,7 +618,6 @@ BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); -BRCMF_FW_DEF(43436, "brcmfmac43436-sdio"); BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); @@ -641,8 +640,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFA, 43430A1), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000004, 43436), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), -- Gitee From b29df0a3d4d941217861bb89aa73478aac6986b2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 28 Oct 2021 15:03:16 +0100 Subject: [PATCH 032/155] brcmfmac: Read alternative firmware names from DT Add the ability to load the names of alternative firmwares from the Device Tree node. This permits separate firmwares for 43436s and 43438 and allows downstream firmwares to coexist with upstream. Signed-off-by: Phil Elwell --- .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++ .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 +++ .../broadcom/brcm80211/brcmfmac/sdio.c | 47 +++++++++++++++++-- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index a7554265f95f..db4ac19f0800 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -10,6 +10,7 @@ #include "debug.h" #include "core.h" #include "common.h" +#include "firmware.h" #include "of.h" void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, @@ -65,3 +66,38 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, sdio->oob_irq_nr = irq; sdio->oob_irq_flags = irqf; } + +struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *fwname_count) +{ + struct device_node *np = dev->of_node; + struct brcmf_firmware_mapping *fwnames; + struct device_node *map_np, *fw_np; + int of_count; + int count = 0; + + map_np = of_get_child_by_name(np, "firmwares"); + of_count = of_get_child_count(map_np); + if (!of_count) + return NULL; + + fwnames = devm_kcalloc(dev, of_count, + sizeof(struct brcmf_firmware_mapping), + GFP_KERNEL); + + for_each_child_of_node(map_np, fw_np) + { + struct brcmf_firmware_mapping *cur = &fwnames[count]; + + if (of_property_read_u32(fw_np, "chipid", &cur->chipid) || + of_property_read_u32(fw_np, "revmask", &cur->revmask)) + continue; + cur->fw_base = of_get_property(fw_np, "fw_base", NULL); + if (cur->fw_base) + count++; + } + + *fwname_count = count; + + return count ? fwnames : NULL; +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 10bf52253337..5b39a39812d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -5,9 +5,16 @@ #ifdef CONFIG_OF void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings); +struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *map_count); #else static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { } +static struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *map_count) +{ + return NULL; +} #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index f6c51680988d..e22699bf3ec3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -35,6 +35,7 @@ #include "core.h" #include "common.h" #include "bcdc.h" +#include "of.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) @@ -626,7 +627,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); -static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { +static const struct brcmf_firmware_mapping sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), @@ -650,6 +651,9 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) }; +static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames; +static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); + #define TXCTL_CREDITS 2 static void pkt_align(struct sk_buff *p, int len, int align) @@ -4135,7 +4139,7 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name, } fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), + brcmf_sdio_fwnames_count, fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return -ENOMEM; @@ -4191,6 +4195,9 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { #define BRCMF_SDIO_FW_CODE 0 #define BRCMF_SDIO_FW_NVRAM 1 +static struct brcmf_fw_request * +brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); + static void brcmf_sdio_firmware_callback(struct device *dev, int err, struct brcmf_fw_request *fwreq) { @@ -4206,6 +4213,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); + if (err && brcmf_sdio_fwnames != sdio_fwnames) { + /* Try again with the standard firmware names */ + brcmf_sdio_fwnames = sdio_fwnames; + brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); + kfree(fwreq); + fwreq = brcmf_sdio_prepare_fw_request(bus); + if (!fwreq) { + err = -ENOMEM; + goto fail; + } + err = brcmf_fw_get_firmwares(dev, fwreq, + brcmf_sdio_firmware_callback); + if (!err) + return; + } + if (err) goto fail; @@ -4413,7 +4436,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), + brcmf_sdio_fwnames_count, fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return NULL; @@ -4431,6 +4454,9 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) struct brcmf_sdio *bus; struct workqueue_struct *wq; struct brcmf_fw_request *fwreq; + struct brcmf_firmware_mapping *of_fwnames, *fwnames; + const int fwname_size = sizeof(struct brcmf_firmware_mapping); + u32 of_fw_count; brcmf_dbg(TRACE, "Enter\n"); @@ -4513,6 +4539,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(INFO, "completed!!\n"); + of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); + if (of_fwnames) + fwnames = devm_kcalloc(sdiodev->dev, + of_fw_count + brcmf_sdio_fwnames_count, + fwname_size, GFP_KERNEL); + + if (fwnames) { + /* The array is scanned in order, so overrides come first */ + memcpy(fwnames, of_fwnames, of_fw_count * fwname_size); + memcpy(fwnames + of_fw_count, sdio_fwnames, + brcmf_sdio_fwnames_count * fwname_size); + brcmf_sdio_fwnames = fwnames; + brcmf_sdio_fwnames_count += of_fw_count; + } + fwreq = brcmf_sdio_prepare_fw_request(bus); if (!fwreq) { ret = -ENOMEM; -- Gitee From aa8e79bc5d0996fbb00f0659bff61e4bebf20d4c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 28 Oct 2021 15:09:25 +0100 Subject: [PATCH 033/155] ARM: dts: Provide WLAN firmware names for Zero 2 W BCM43430/2 may be BCM43430B0 or BCM43436P, and BCM43430/1 can be either BCM43430A1 or BCM43436S, the former being upstream names and the latter downstream names for differently-sourced sister parts. Make the choice of firmwares board-specific (without making the actual firmwares board-specific) by placing the alternative firmware names for each part in the DT node. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts index 2bd223a405a7..1cd3d01a166d 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts @@ -89,6 +89,19 @@ brcmf: wifi@1 { reg = <1>; compatible = "brcm,bcm4329-fmac"; + + firmwares { + fw_43436p { + chipid = <43430>; + revmask = <4>; + fw_base = "brcm/brcmfmac43436-sdio"; + }; + fw_43436s { + chipid = <43430>; + revmask = <2>; + fw_base = "brcm/brcmfmac43436s-sdio"; + }; + }; }; }; -- Gitee From 481229fbc14b9014c3f98ca683a551a58b7ca003 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 2 Nov 2021 12:08:49 +0000 Subject: [PATCH 034/155] Revert "brcmfmac: Read alternative firmware names from DT" This reverts commit cb02a9793d53ccfcc3368be3a278637955d81f75. --- .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 -------------- .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 --- .../broadcom/brcm80211/brcmfmac/sdio.c | 47 ++----------------- 3 files changed, 3 insertions(+), 87 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index db4ac19f0800..a7554265f95f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -10,7 +10,6 @@ #include "debug.h" #include "core.h" #include "common.h" -#include "firmware.h" #include "of.h" void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, @@ -66,38 +65,3 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, sdio->oob_irq_nr = irq; sdio->oob_irq_flags = irqf; } - -struct brcmf_firmware_mapping * -brcmf_of_fwnames(struct device *dev, u32 *fwname_count) -{ - struct device_node *np = dev->of_node; - struct brcmf_firmware_mapping *fwnames; - struct device_node *map_np, *fw_np; - int of_count; - int count = 0; - - map_np = of_get_child_by_name(np, "firmwares"); - of_count = of_get_child_count(map_np); - if (!of_count) - return NULL; - - fwnames = devm_kcalloc(dev, of_count, - sizeof(struct brcmf_firmware_mapping), - GFP_KERNEL); - - for_each_child_of_node(map_np, fw_np) - { - struct brcmf_firmware_mapping *cur = &fwnames[count]; - - if (of_property_read_u32(fw_np, "chipid", &cur->chipid) || - of_property_read_u32(fw_np, "revmask", &cur->revmask)) - continue; - cur->fw_base = of_get_property(fw_np, "fw_base", NULL); - if (cur->fw_base) - count++; - } - - *fwname_count = count; - - return count ? fwnames : NULL; -} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 5b39a39812d0..10bf52253337 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -5,16 +5,9 @@ #ifdef CONFIG_OF void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings); -struct brcmf_firmware_mapping * -brcmf_of_fwnames(struct device *dev, u32 *map_count); #else static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { } -static struct brcmf_firmware_mapping * -brcmf_of_fwnames(struct device *dev, u32 *map_count) -{ - return NULL; -} #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index e22699bf3ec3..f6c51680988d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -35,7 +35,6 @@ #include "core.h" #include "common.h" #include "bcdc.h" -#include "of.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) @@ -627,7 +626,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); -static const struct brcmf_firmware_mapping sdio_fwnames[] = { +static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), @@ -651,9 +650,6 @@ static const struct brcmf_firmware_mapping sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) }; -static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames; -static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); - #define TXCTL_CREDITS 2 static void pkt_align(struct sk_buff *p, int len, int align) @@ -4139,7 +4135,7 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name, } fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, brcmf_sdio_fwnames, - brcmf_sdio_fwnames_count, + ARRAY_SIZE(brcmf_sdio_fwnames), fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return -ENOMEM; @@ -4195,9 +4191,6 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { #define BRCMF_SDIO_FW_CODE 0 #define BRCMF_SDIO_FW_NVRAM 1 -static struct brcmf_fw_request * -brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); - static void brcmf_sdio_firmware_callback(struct device *dev, int err, struct brcmf_fw_request *fwreq) { @@ -4213,22 +4206,6 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); - if (err && brcmf_sdio_fwnames != sdio_fwnames) { - /* Try again with the standard firmware names */ - brcmf_sdio_fwnames = sdio_fwnames; - brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); - kfree(fwreq); - fwreq = brcmf_sdio_prepare_fw_request(bus); - if (!fwreq) { - err = -ENOMEM; - goto fail; - } - err = brcmf_fw_get_firmwares(dev, fwreq, - brcmf_sdio_firmware_callback); - if (!err) - return; - } - if (err) goto fail; @@ -4436,7 +4413,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, brcmf_sdio_fwnames, - brcmf_sdio_fwnames_count, + ARRAY_SIZE(brcmf_sdio_fwnames), fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return NULL; @@ -4454,9 +4431,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) struct brcmf_sdio *bus; struct workqueue_struct *wq; struct brcmf_fw_request *fwreq; - struct brcmf_firmware_mapping *of_fwnames, *fwnames; - const int fwname_size = sizeof(struct brcmf_firmware_mapping); - u32 of_fw_count; brcmf_dbg(TRACE, "Enter\n"); @@ -4539,21 +4513,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(INFO, "completed!!\n"); - of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); - if (of_fwnames) - fwnames = devm_kcalloc(sdiodev->dev, - of_fw_count + brcmf_sdio_fwnames_count, - fwname_size, GFP_KERNEL); - - if (fwnames) { - /* The array is scanned in order, so overrides come first */ - memcpy(fwnames, of_fwnames, of_fw_count * fwname_size); - memcpy(fwnames + of_fw_count, sdio_fwnames, - brcmf_sdio_fwnames_count * fwname_size); - brcmf_sdio_fwnames = fwnames; - brcmf_sdio_fwnames_count += of_fw_count; - } - fwreq = brcmf_sdio_prepare_fw_request(bus); if (!fwreq) { ret = -ENOMEM; -- Gitee From bbbd12c4d00ac7b38bc4f2a890686f9692e6508d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 2 Nov 2021 12:09:14 +0000 Subject: [PATCH 035/155] Revert "Revert "brcmfmac: BCM43436 needs dedicated firmware"" This reverts commit 7ca0827aed02da8a5b3b94b37328706fba3675f9. --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index f6c51680988d..3ab944c39677 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -618,6 +618,7 @@ BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); +BRCMF_FW_DEF(43436, "brcmfmac43436-sdio"); BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); @@ -640,7 +641,8 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFA, 43430A1), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000004, 43436), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), -- Gitee From dbaa21f70f4ca6dd7342fc76d76bc0a3787bfebf Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 21 Oct 2021 15:06:02 +0100 Subject: [PATCH 036/155] dtoverlays: Update all image sensor overlays for Media Controller option Add an option to enable configuration via the Media Controller API (rather than the video-node-centric /dev/videoN) as about to be used by libcamera as it enables more complex pipelines to be handled. Any source that has a libcamera tuning merged has MC enabled by default. Sources with no libcamera tuning merged have it disabled by default. In either case it can be overridden with the overlay parameter "media-controller". Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/README | 27 +++++++++++++++++-- .../boot/dts/overlays/adv7282m-overlay.dts | 8 ++++++ arch/arm/boot/dts/overlays/imx219-overlay.dts | 8 ++++++ .../boot/dts/overlays/imx290_327-overlay.dtsi | 8 ++++++ .../boot/dts/overlays/imx477_378-overlay.dtsi | 8 ++++++ arch/arm/boot/dts/overlays/imx519-overlay.dts | 8 ++++++ .../arm/boot/dts/overlays/irs1125-overlay.dts | 11 ++++++++ arch/arm/boot/dts/overlays/ov5647-overlay.dts | 8 ++++++ arch/arm/boot/dts/overlays/ov7251-overlay.dts | 8 ++++++ arch/arm/boot/dts/overlays/ov9281-overlay.dts | 8 ++++++ .../boot/dts/overlays/tc358743-overlay.dts | 8 ++++++ 11 files changed, 108 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 5064d8eb2040..1404de8444f2 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -416,6 +416,8 @@ Info: Analog Devices ADV7282M analogue video to CSI2 bridge. variants. Load: dtoverlay=adv7282m,= Params: addr Overrides the I2C address (default 0x21) + media-controller Configure use of Media Controller API for + configuring the sensor (default off) Name: adv728x-m @@ -426,6 +428,8 @@ Params: addr Overrides the I2C address (default 0x21) adv7280m Select ADV7280-M. adv7281m Select ADV7281-M. adv7281ma Select ADV7281-MA. + media-controller Configure use of Media Controller API for + configuring the sensor (default off) Name: akkordion-iqdacplus @@ -1708,6 +1712,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 180) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: imx290 @@ -1728,6 +1734,8 @@ Params: 4lane Enable 4 CSI2 lanes. This requires a Compute 2 = external, default external) rotation Mounting rotation of the camera sensor (0 or 180, default 0) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: imx378 @@ -1739,6 +1747,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 180) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: imx477 @@ -1750,6 +1760,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 180) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: imx519 @@ -1761,6 +1773,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 0) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: iqaudio-codec @@ -1824,8 +1838,9 @@ Name: irs1125 Info: Infineon irs1125 TOF camera module. Uses Unicam 1, which is the standard camera connector on most Pi variants. -Load: dtoverlay=irs1125 -Params: +Load: dtoverlay=irs1125,= +Params: media-controller Configure use of Media Controller API for + configuring the sensor (default off) Name: jedec-spi-nor @@ -2237,6 +2252,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 0) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: ov7251 @@ -2248,6 +2265,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 0) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default off) Name: ov9281 @@ -2259,6 +2278,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 180, default 0) orientation Sensor orientation (0 = front, 1 = rear, 2 = external, default external) + media-controller Configure use of Media Controller API for + configuring the sensor (default on) Name: papirus @@ -3239,6 +3260,8 @@ Params: 4lane Use 4 lanes (only applicable to Compute Modules link-frequency Set the link frequency. Only values of 297000000 (574Mbit/s) and 486000000 (972Mbit/s - default) are supported by the driver. + media-controller Configure use of Media Controller API for + configuring the sensor (default off) Name: tc358743-audio diff --git a/arch/arm/boot/dts/overlays/adv7282m-overlay.dts b/arch/arm/boot/dts/overlays/adv7282m-overlay.dts index 5d85dfd0595c..f7e97c4a13d8 100644 --- a/arch/arm/boot/dts/overlays/adv7282m-overlay.dts +++ b/arch/arm/boot/dts/overlays/adv7282m-overlay.dts @@ -59,7 +59,15 @@ }; }; + fragment@4 { + target = <&csi1>; + __dormant__ { + brcm,media-controller; + }; + }; + __overrides__ { addr = <&adv728x>,"reg:0"; + media-controller = <0>,"=4"; }; }; diff --git a/arch/arm/boot/dts/overlays/imx219-overlay.dts b/arch/arm/boot/dts/overlays/imx219-overlay.dts index 0c065bf09f54..5b5ba70aff7f 100644 --- a/arch/arm/boot/dts/overlays/imx219-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts @@ -108,8 +108,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&imx219>,"rotation:0"; orientation = <&imx219>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi index d4a5ed6dbbcf..2696daed523c 100644 --- a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi @@ -134,11 +134,19 @@ }; }; + fragment@10 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { 4lane = <0>, "-6+7-8+9"; clock-frequency = <&imx290_clk>,"clock-frequency:0", <&imx290>,"clock-frequency:0"; rotation = <&imx290>,"rotation:0"; orientation = <&imx290>,"orientation:0"; + media-controller = <0>,"=10"; }; }; diff --git a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi index bb9a9acdbbd7..d785e6cb5d82 100644 --- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi @@ -103,8 +103,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&imx477>,"rotation:0"; orientation = <&imx477>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/imx519-overlay.dts b/arch/arm/boot/dts/overlays/imx519-overlay.dts index 693c267af1f0..b8593a980bbf 100644 --- a/arch/arm/boot/dts/overlays/imx519-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx519-overlay.dts @@ -108,8 +108,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&imx519>,"rotation:0"; orientation = <&imx519>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/irs1125-overlay.dts b/arch/arm/boot/dts/overlays/irs1125-overlay.dts index e926e18e71fc..065569830ded 100644 --- a/arch/arm/boot/dts/overlays/irs1125-overlay.dts +++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts @@ -82,4 +82,15 @@ }; }; }; + + fragment@6 { + target = <&csi1>; + __dormant__ { + brcm,media-controller; + }; + }; + + __overrides__ { + media-controller = <0>,"=6"; + }; }; diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts index d7ed4703c9b0..f57b25c38794 100644 --- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts @@ -87,8 +87,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&ov5647>,"rotation:0"; orientation = <&ov5647>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/ov7251-overlay.dts b/arch/arm/boot/dts/overlays/ov7251-overlay.dts index 09dbeda39d06..6fe652fe011b 100644 --- a/arch/arm/boot/dts/overlays/ov7251-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov7251-overlay.dts @@ -106,8 +106,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __dormant__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&ov7251>,"rotation:0"; orientation = <&ov7251>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/ov9281-overlay.dts b/arch/arm/boot/dts/overlays/ov9281-overlay.dts index 277236c03358..b2b9a47c6d27 100644 --- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts @@ -106,8 +106,16 @@ }; }; + fragment@6 { + target = <&csi1>; + __overlay__ { + brcm,media-controller; + }; + }; + __overrides__ { rotation = <&ov9281>,"rotation:0"; orientation = <&ov9281>,"orientation:0"; + media-controller = <0>,"=6"; }; }; diff --git a/arch/arm/boot/dts/overlays/tc358743-overlay.dts b/arch/arm/boot/dts/overlays/tc358743-overlay.dts index a1f8af36d2e7..d679d9ba84b6 100644 --- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts +++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts @@ -100,8 +100,16 @@ }; }; + fragment@9 { + target = <&csi1>; + __dormant__ { + brcm,media-controller; + }; + }; + __overrides__ { 4lane = <0>, "-2+3-7+8"; link-frequency = <&tc358743>,"link-frequencies#0"; + media-controller = <0>,"=9"; }; }; -- Gitee From a4ec539e7bfb3493961090e7f4beffc7c5c5cd57 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 26 Oct 2021 11:24:54 +0100 Subject: [PATCH 037/155] Revert "brcmfmac: BCM43436 needs dedicated firmware" This reverts commit c52581ffa49b9c0e5de3349436c283fe20128073. Replace the hardcoded alternate firmware names with mappings provided from Device Tree. Signed-off-by: Phil Elwell --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 3ab944c39677..f6c51680988d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -618,7 +618,6 @@ BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); -BRCMF_FW_DEF(43436, "brcmfmac43436-sdio"); BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); @@ -641,8 +640,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFA, 43430A1), - BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000004, 43436), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0x00000200, 43456), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), -- Gitee From 21fac27bd2db222d060fba8a5df8e633d4eac3ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 28 Oct 2021 15:03:16 +0100 Subject: [PATCH 038/155] brcmfmac: Read alternative firmware names from DT Add the ability to load the names of alternative firmwares from the Device Tree node. This permits separate firmwares for 43436s and 43438 and allows downstream firmwares to coexist with upstream. Signed-off-by: Phil Elwell --- .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++ .../wireless/broadcom/brcm80211/brcmfmac/of.h | 7 +++ .../broadcom/brcm80211/brcmfmac/sdio.c | 47 +++++++++++++++++-- 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index a7554265f95f..db4ac19f0800 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -10,6 +10,7 @@ #include "debug.h" #include "core.h" #include "common.h" +#include "firmware.h" #include "of.h" void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, @@ -65,3 +66,38 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, sdio->oob_irq_nr = irq; sdio->oob_irq_flags = irqf; } + +struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *fwname_count) +{ + struct device_node *np = dev->of_node; + struct brcmf_firmware_mapping *fwnames; + struct device_node *map_np, *fw_np; + int of_count; + int count = 0; + + map_np = of_get_child_by_name(np, "firmwares"); + of_count = of_get_child_count(map_np); + if (!of_count) + return NULL; + + fwnames = devm_kcalloc(dev, of_count, + sizeof(struct brcmf_firmware_mapping), + GFP_KERNEL); + + for_each_child_of_node(map_np, fw_np) + { + struct brcmf_firmware_mapping *cur = &fwnames[count]; + + if (of_property_read_u32(fw_np, "chipid", &cur->chipid) || + of_property_read_u32(fw_np, "revmask", &cur->revmask)) + continue; + cur->fw_base = of_get_property(fw_np, "fw_base", NULL); + if (cur->fw_base) + count++; + } + + *fwname_count = count; + + return count ? fwnames : NULL; +} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 10bf52253337..5b39a39812d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -5,9 +5,16 @@ #ifdef CONFIG_OF void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings); +struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *map_count); #else static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { } +static struct brcmf_firmware_mapping * +brcmf_of_fwnames(struct device *dev, u32 *map_count) +{ + return NULL; +} #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index f6c51680988d..21dbbf969906 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -35,6 +35,7 @@ #include "core.h" #include "common.h" #include "bcdc.h" +#include "of.h" #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) @@ -626,7 +627,7 @@ BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); -static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { +static const struct brcmf_firmware_mapping sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), @@ -650,6 +651,9 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) }; +static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames; +static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); + #define TXCTL_CREDITS 2 static void pkt_align(struct sk_buff *p, int len, int align) @@ -4135,7 +4139,7 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name, } fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), + brcmf_sdio_fwnames_count, fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return -ENOMEM; @@ -4191,6 +4195,9 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { #define BRCMF_SDIO_FW_CODE 0 #define BRCMF_SDIO_FW_NVRAM 1 +static struct brcmf_fw_request * +brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); + static void brcmf_sdio_firmware_callback(struct device *dev, int err, struct brcmf_fw_request *fwreq) { @@ -4206,6 +4213,22 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); + if (err && brcmf_sdio_fwnames != sdio_fwnames) { + /* Try again with the standard firmware names */ + brcmf_sdio_fwnames = sdio_fwnames; + brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); + kfree(fwreq); + fwreq = brcmf_sdio_prepare_fw_request(bus); + if (!fwreq) { + err = -ENOMEM; + goto fail; + } + err = brcmf_fw_get_firmwares(dev, fwreq, + brcmf_sdio_firmware_callback); + if (!err) + return; + } + if (err) goto fail; @@ -4413,7 +4436,7 @@ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), + brcmf_sdio_fwnames_count, fwnames, ARRAY_SIZE(fwnames)); if (!fwreq) return NULL; @@ -4431,6 +4454,9 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) struct brcmf_sdio *bus; struct workqueue_struct *wq; struct brcmf_fw_request *fwreq; + struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL; + const int fwname_size = sizeof(struct brcmf_firmware_mapping); + u32 of_fw_count; brcmf_dbg(TRACE, "Enter\n"); @@ -4513,6 +4539,21 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(INFO, "completed!!\n"); + of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); + if (of_fwnames) + fwnames = devm_kcalloc(sdiodev->dev, + of_fw_count + brcmf_sdio_fwnames_count, + fwname_size, GFP_KERNEL); + + if (fwnames) { + /* The array is scanned in order, so overrides come first */ + memcpy(fwnames, of_fwnames, of_fw_count * fwname_size); + memcpy(fwnames + of_fw_count, sdio_fwnames, + brcmf_sdio_fwnames_count * fwname_size); + brcmf_sdio_fwnames = fwnames; + brcmf_sdio_fwnames_count += of_fw_count; + } + fwreq = brcmf_sdio_prepare_fw_request(bus); if (!fwreq) { ret = -ENOMEM; -- Gitee From 894ecfb39be7a05499ea33d05bfe3f22cf298ebf Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 2 Nov 2021 16:01:36 +0000 Subject: [PATCH 039/155] drm: Check whether the gamma lut has changed before updating drm_crtc_legacy_gamma_set updates the gamma_lut blob unconditionally, which leads to unnecessary reprogramming of hardware. Check whether the blob contents has actually changed before signalling that it has been updated. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/drm_color_mgmt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 8c225fb7441d..ec4a9a00a298 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -313,7 +313,11 @@ static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc, /* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */ replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); - replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); + if (!crtc_state->gamma_lut || !crtc_state->gamma_lut->data || + memcmp(crtc_state->gamma_lut->data, blob_data, blob->length)) + replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); + else + drm_property_blob_put(blob); crtc_state->color_mgmt_changed |= replaced; ret = drm_atomic_commit(state); -- Gitee From 2f6179e6f939a3b632bce5ceb00a126584e9ff27 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 3 Nov 2021 11:53:13 +0000 Subject: [PATCH 040/155] brcmfmac: Protect against reprobing It is important to reinitialise the firmware array pointers to protect against the case that the brcmfmac driver is reprobed without first being unloaded. The potential hazard was noticed while investigating https://github.com/raspberrypi/firmware/issues/1644 . Signed-off-by: Phil Elwell --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 21dbbf969906..c8609fed3c32 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -651,8 +651,8 @@ static const struct brcmf_firmware_mapping sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) }; -static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames; -static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); +static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames; +static u32 brcmf_sdio_fwnames_count; #define TXCTL_CREDITS 2 @@ -4539,6 +4539,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(INFO, "completed!!\n"); + brcmf_sdio_fwnames = sdio_fwnames; + brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames); of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count); if (of_fwnames) fwnames = devm_kcalloc(sdiodev->dev, -- Gitee From 8a44b056db17c6970164068a2959ac072d28621d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 Oct 2021 15:19:30 +0200 Subject: [PATCH 041/155] drm/vc4: crtc: Drop feed_txp from state Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. In VC4, a number of users of that pointers have crept in over the years, the first one being whether or not the downstream controller of the pixelvalve is our writeback controller. Fortunately for us, Since commit 39fcb2808376 ("drm/vc4: txp: Turn the TXP into a CRTC of its own") this is no longer something that can change from one commit to the other and is hardcoded. Let's set this flag in struct vc4_crtc if we happen to be the TXP, and drop the flag from our private state structure. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 008095e065a8 ("drm/vc4: Add support for the transposer block") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 3 +-- drivers/gpu/drm/vc4/vc4_drv.h | 6 +++++- drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++---- drivers/gpu/drm/vc4/vc4_kms.c | 3 ++- drivers/gpu/drm/vc4/vc4_txp.c | 3 +-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 8a7b09c6ce80..d3fe8f485a7a 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -742,7 +742,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) spin_lock_irqsave(&dev->event_lock, flags); if (vc4_crtc->event && (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || - vc4_state->feed_txp)) { + vc4_crtc->feeds_txp)) { drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; drm_crtc_vblank_put(crtc); @@ -966,7 +966,6 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) return NULL; old_vc4_state = to_vc4_crtc_state(crtc->state); - vc4_state->feed_txp = old_vc4_state->feed_txp; vc4_state->margins = old_vc4_state->margins; vc4_state->assigned_channel = old_vc4_state->assigned_channel; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 6a260b1e60ad..81d73478e6f0 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -520,6 +520,11 @@ struct vc4_crtc { struct drm_pending_vblank_event *event; struct debugfs_regset32 regset; + + /** + * @feeds_txp: True if the CRTC feeds our writeback controller. + */ + bool feeds_txp; }; static inline struct vc4_crtc * @@ -552,7 +557,6 @@ struct vc4_crtc_state { struct drm_crtc_state base; /* Dlist area for this CRTC configuration. */ struct drm_mm_node mm; - bool feed_txp; bool txp_armed; unsigned int assigned_channel; diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 1eeb0cd73a2b..81d4298c426b 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -598,7 +598,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) spin_lock_irqsave(&dev->event_lock, flags); - if (!vc4_state->feed_txp || vc4_state->txp_armed) { + if (!vc4_crtc->feeds_txp || vc4_state->txp_armed) { vc4_crtc->event = crtc->state->event; crtc->state->event = NULL; } @@ -618,10 +618,9 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state); struct drm_display_mode *mode = &crtc->state->adjusted_mode; - bool oneshot = vc4_state->feed_txp; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + bool oneshot = vc4_crtc->feeds_txp; vc4_hvs_update_dlist(crtc); vc4_hvs_init_channel(vc4, crtc, mode, oneshot); diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index fb2465964d46..422f2c211abd 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -222,6 +222,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, unsigned int i; for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); u32 dispctrl; u32 dsp3_mux; @@ -242,7 +243,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4, * TXP IP, and we need to disable the FIFO2 -> pixelvalve1 * route. */ - if (vc4_state->feed_txp) + if (vc4_crtc->feeds_txp) dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX); else dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 2fc7f4b5fa09..26eda7542f74 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -391,7 +391,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc, { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); int ret; ret = vc4_hvs_atomic_check(crtc, state); @@ -399,7 +398,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc, return ret; crtc_state->no_vblank = true; - vc4_state->feed_txp = true; return 0; } @@ -482,6 +480,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) vc4_crtc->pdev = pdev; vc4_crtc->data = &vc4_txp_crtc_data; + vc4_crtc->feeds_txp = true; txp->pdev = pdev; -- Gitee From 76d7fb11df3da7668c901be26f608ca7542e4ce0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 10 Jun 2021 17:48:28 +0200 Subject: [PATCH 042/155] drm/vc4: Fix non-blocking commit getting stuck forever In some situation, we can end up being stuck on a non-blocking that went through properly. The situation that seems to trigger it reliably is to first start a non-blocking commit, and then right after, and before we had any vblank interrupt), start a blocking commit. This will lead to the first commit workqueue to be scheduled, setup the display, while the second commit is waiting for the first one to be completed. The vblank interrupt will then be raised, vc4_crtc_handle_vblank() will run and will compare the active dlist in the HVS channel to the one associated with the crtc->state. However, at that point, the second commit is waiting using drm_atomic_helper_wait_for_dependencies that occurs after drm_atomic_helper_swap_state has been called, so crtc->state points to the second commit state. vc4_crtc_handle_vblank() will compare the two dlist addresses and since they don't match will ignore the interrupt. The vblank event will never be reported, and the first and second commit will wait for the first commit completion until they timeout. The underlying reason is that it was never safe to do so. Indeed, accessing the ->state pointer access synchronization is based on ownership guarantees that can only occur within the functions and hooks defined as part of the KMS framework, and obviously the irq handler isn't one of them. The rework to move to generic helpers only uncovered the underlying issue. However, since the code path between drm_atomic_helper_wait_for_dependencies() and drm_atomic_helper_wait_for_vblanks() is serialised and we can't get two commits in that path at the same time, we can work around this issue by setting a variable associated to struct drm_crtc to the dlist we expect, and then using it from the vc4_crtc_handle_vblank() function. Since that state is shared with the modesetting path, we also need to introduce a spinlock to protect the code shared between the interrupt handler and the modesetting path, protecting only our new variable for now. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 56d1fe0979dc ("drm/vc4: Make pageflip completion handling more robust.") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 5 ++++- drivers/gpu/drm/vc4/vc4_drv.h | 14 ++++++++++++++ drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index d3fe8f485a7a..cafdfe8fb2e6 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -740,8 +740,9 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); + spin_lock(&vc4_crtc->irq_lock); if (vc4_crtc->event && - (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) || + (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) || vc4_crtc->feeds_txp)) { drm_crtc_send_vblank_event(crtc, vc4_crtc->event); vc4_crtc->event = NULL; @@ -755,6 +756,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) */ vc4_hvs_unmask_underrun(dev, chan); } + spin_unlock(&vc4_crtc->irq_lock); spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -1200,6 +1202,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, return PTR_ERR(primary_plane); } + spin_lock_init(&vc4_crtc->irq_lock); drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, crtc_funcs, NULL); drm_crtc_helper_add(crtc, crtc_helper_funcs); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 81d73478e6f0..803eb7385cd8 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -525,6 +525,20 @@ struct vc4_crtc { * @feeds_txp: True if the CRTC feeds our writeback controller. */ bool feeds_txp; + + /** + * @irq_lock: Spinlock protecting the resources shared between + * the atomic code and our vblank handler. + */ + spinlock_t irq_lock; + + /** + * @current_dlist: Start offset of the display list currently + * set in the HVS for that CRTC. Protected by @irq_lock, and + * copied in vc4_hvs_update_dlist() for the CRTC interrupt + * handler to have access to that value. + */ + unsigned int current_dlist; }; static inline struct vc4_crtc * diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 81d4298c426b..440f19c3f9ed 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -588,10 +588,9 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + unsigned long flags; if (crtc->state->event) { - unsigned long flags; - crtc->state->event->pipe = drm_crtc_index(crtc); WARN_ON(drm_crtc_vblank_get(crtc) != 0); @@ -611,6 +610,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), vc4_state->mm.start); } + + spin_lock_irqsave(&vc4_crtc->irq_lock, flags); + vc4_crtc->current_dlist = vc4_state->mm.start; + spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); } void vc4_hvs_atomic_enable(struct drm_crtc *crtc, -- Gitee From 3a4f35c3634d55682f961cea89d4fb3129ade191 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 Oct 2021 15:56:44 +0200 Subject: [PATCH 043/155] drm/vc4: crtc: Copy assigned channel to the CRTC Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. In VC4, a number of users of that pointers have crept in over the years, and the previous commits removed them all but the HVS channel a CRTC has been assigned. Let's move this channel in struct vc4_crtc at atomic_begin() time, drop it from our private state structure, and remove our use of crtc->state from our vblank handler entirely. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: 87ebcd42fb7b ("drm/vc4: crtc: Assign output to channel automatically") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++-- drivers/gpu/drm/vc4/vc4_drv.h | 9 +++++++++ drivers/gpu/drm/vc4/vc4_hvs.c | 12 ++++++++++++ drivers/gpu/drm/vc4/vc4_txp.c | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index cafdfe8fb2e6..9a18e695f65e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -735,8 +735,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) struct drm_crtc *crtc = &vc4_crtc->base; struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); - u32 chan = vc4_state->assigned_channel; + u32 chan = vc4_crtc->current_hvs_channel; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); @@ -1028,6 +1027,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { .mode_valid = vc4_crtc_mode_valid, .atomic_check = vc4_crtc_atomic_check, + .atomic_begin = vc4_hvs_atomic_begin, .atomic_flush = vc4_hvs_atomic_flush, .atomic_enable = vc4_crtc_atomic_enable, .atomic_disable = vc4_crtc_atomic_disable, diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 803eb7385cd8..dd34de6e677b 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -539,6 +539,14 @@ struct vc4_crtc { * handler to have access to that value. */ unsigned int current_dlist; + + /** + * @current_hvs_channel: HVS channel currently assigned to the + * CRTC. Protected by @irq_lock, and copied in + * vc4_hvs_atomic_begin() for the CRTC interrupt handler to have + * access to that value. + */ + unsigned int current_hvs_channel; }; static inline struct vc4_crtc * @@ -971,6 +979,7 @@ extern struct platform_driver vc4_hvs_driver; void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output); int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output); int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state); +void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state); void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 440f19c3f9ed..6372c48097d5 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -616,6 +616,18 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc) spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); } +void vc4_hvs_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + unsigned long flags; + + spin_lock_irqsave(&vc4_crtc->irq_lock, flags); + vc4_crtc->current_hvs_channel = vc4_state->assigned_channel; + spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags); +} + void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) { diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 26eda7542f74..9809ca3e2945 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -435,6 +435,7 @@ static void vc4_txp_atomic_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = { .atomic_check = vc4_txp_atomic_check, + .atomic_begin = vc4_hvs_atomic_begin, .atomic_flush = vc4_hvs_atomic_flush, .atomic_enable = vc4_txp_atomic_enable, .atomic_disable = vc4_txp_atomic_disable, -- Gitee From ff530fb4310650b5523ba30d21f5f9063cc68dd4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 19 Oct 2021 12:25:17 +0200 Subject: [PATCH 044/155] drm/vc4: hdmi: Add a spinlock to protect register access The vc4 HDMI driver has multiple path shared between the CEC, ALSA and KMS frameworks, plus two interrupt handlers (CEC and hotplug) that will read and modify a number of registers. Even though not bug has been reported so far, it's definitely unsafe, so let's just add a spinlock to protect the register access of the HDMI controller. Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 202 ++++++++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 +++++ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 + 4 files changed, 237 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f1adaa9dc5f3..45227b3d289c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -128,6 +128,10 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST); udelay(1); HDMI_WRITE(HDMI_M_CTL, 0); @@ -139,24 +143,36 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) VC4_HDMI_SW_RESET_FORMAT_DETECT); HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + reset_control_reset(vc4_hdmi->reset); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_DVP_CTL, 0); HDMI_WRITE(HDMI_CLOCK_STOP, HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } #ifdef CONFIG_DRM_VC4_HDMI_CEC static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) { + unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock); + unsigned long flags; u16 clk_cnt; u32 value; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + value = HDMI_READ(HDMI_CEC_CNTRL_1); value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK; @@ -164,9 +180,11 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) * Set the clock divider: the hsm_clock rate and this divider * setting will give a 40 kHz CEC clock. */ - clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ; + clk_cnt = cec_rate / CEC_CLOCK_FREQ; value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } #else static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {} @@ -187,8 +205,16 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ vc4_hdmi->hpd_active_low) connected = true; - } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { - connected = true; + } else { + unsigned long flags; + u32 hotplug; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + hotplug = HDMI_READ(HDMI_HOTPLUG); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED) + connected = true; } if (connected) { @@ -386,9 +412,12 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); u32 packet_id = type - 0x80; + unsigned long flags; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); if (!poll) return 0; @@ -410,6 +439,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi, ram_packet_start->reg); uint8_t buffer[VC4_HDMI_PACKET_STRIDE] = {}; + unsigned long flags; ssize_t len, i; int ret; @@ -427,6 +457,8 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, return; } + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + for (i = 0; i < len; i += 7) { writel(buffer[i + 0] << 0 | buffer[i + 1] << 8 | @@ -451,6 +483,9 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) & BIT(packet_id)), 100); if (ret) @@ -570,6 +605,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) { struct drm_display_mode *mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + unsigned long flags; if (!encoder->crtc || !encoder->crtc->state) return; @@ -584,8 +620,10 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); drm_scdc_set_scrambling(vc4_hdmi->ddc, true); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) | VC5_HDMI_SCRAMBLER_CTL_ENABLE); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work, msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS)); @@ -595,6 +633,7 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_crtc *crtc = encoder->crtc; + unsigned long flags; /* * At boot, encoder->crtc will be NULL. Since we don't know the @@ -610,8 +649,10 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) if (delayed_work_pending(&vc4_hdmi->scrambling_work)) cancel_delayed_work_sync(&vc4_hdmi->scrambling_work); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) & ~VC5_HDMI_SCRAMBLER_CTL_ENABLE); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); drm_scdc_set_scrambling(vc4_hdmi->ddc, false); drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false); @@ -637,15 +678,23 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + mdelay(1); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + vc4_hdmi_disable_scrambling(encoder); } @@ -653,10 +702,13 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + unsigned long flags; int ret; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); if (vc4_hdmi->variant->phy_disable) vc4_hdmi->variant->phy_disable(vc4_hdmi); @@ -678,8 +730,11 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) { + unsigned long flags; u32 csc_ctl; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, VC4_HD_CSC_CTL_ORDER); @@ -709,14 +764,19 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) /* The RGB order applies even when CSC is disabled. */ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) { + unsigned long flags; u32 csc_ctl; csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + if (enable) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. @@ -748,6 +808,8 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) } HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, @@ -771,6 +833,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, VC4_HDMI_VERTB_VBP)); + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_HORZA, (vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) | @@ -794,6 +859,8 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VERTB0, vertb_even); HDMI_WRITE(HDMI_VERTB1, vertb); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, @@ -817,10 +884,13 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, VC4_HDMI_VERTB_VBP)); + unsigned long flags; unsigned char gcp; bool gcp_en; u32 reg; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); HDMI_WRITE(HDMI_HORZA, (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | @@ -884,13 +954,18 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_MISC_CONTROL, reg); HDMI_WRITE(HDMI_CLOCK_STOP, 0); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; u32 drift; int ret; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + drift = HDMI_READ(HDMI_FIFO_CTL); drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; @@ -898,12 +973,20 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) drift & ~VC4_HDMI_FIFO_CTL_RECENTER); HDMI_WRITE(HDMI_FIFO_CTL, drift | VC4_HDMI_FIFO_CTL_RECENTER); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + usleep_range(1000, 1100); + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_FIFO_CTL, drift & ~VC4_HDMI_FIFO_CTL_RECENTER); HDMI_WRITE(HDMI_FIFO_CTL, drift | VC4_HDMI_FIFO_CTL_RECENTER); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) & VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); WARN_ONCE(ret, "Timeout waiting for " @@ -921,6 +1004,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, conn_state_to_vc4_hdmi_conn_state(conn_state); struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; unsigned long bvb_rate, pixel_rate, hsm_rate; + unsigned long flags; int ret; ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); @@ -975,11 +1059,15 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, if (vc4_hdmi->variant->phy_init) vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_SCHEDULER_CONTROL, HDMI_READ(HDMI_SCHEDULER_CONTROL) | VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT | VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + if (vc4_hdmi->variant->set_timings) vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode); @@ -1003,6 +1091,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + unsigned long flags; if (vc4_encoder->hdmi_monitor && drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { @@ -1017,7 +1106,9 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, vc4_encoder->limited_rgb_range = false; } + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, @@ -1028,8 +1119,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; + unsigned long flags; int ret; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_VID_CTL, VC4_HD_VID_CTL_ENABLE | VC4_HD_VID_CTL_CLRRGB | @@ -1046,6 +1140,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, HDMI_READ(HDMI_SCHEDULER_CONTROL) | VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) & VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000); WARN_ONCE(ret, "Timeout waiting for " @@ -1058,6 +1154,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, HDMI_READ(HDMI_SCHEDULER_CONTROL) & ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000); WARN_ONCE(ret, "Timeout waiting for " @@ -1065,6 +1163,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, } if (vc4_encoder->hdmi_monitor) { + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) & VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE)); HDMI_WRITE(HDMI_SCHEDULER_CONTROL, @@ -1074,6 +1174,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, VC4_HDMI_RAM_PACKET_ENABLE); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + vc4_hdmi_set_infoframes(encoder); } @@ -1230,6 +1332,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) { u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock); + unsigned long flags; unsigned long n, m; rational_best_approximation(hsm_clock, samplerate, @@ -1239,9 +1342,11 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, VC4_HD_MAI_SMP_M_SHIFT) + 1, &n, &m); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_SMP, VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) @@ -1252,6 +1357,8 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat u32 n, cts; u64 tmp; + lockdep_assert_held(&vc4_hdmi->hw_lock); + n = 128 * samplerate / 1000; tmp = (u64)(mode->clock * 1000) * n; do_div(tmp, 128 * samplerate); @@ -1281,6 +1388,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + unsigned long flags; /* * If the HDMI encoder hasn't probed, or the encoder is @@ -1292,12 +1400,14 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) vc4_hdmi->audio.streaming = true; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET | VC4_HD_MAI_CTL_FLUSH | VC4_HD_MAI_CTL_DLATE | VC4_HD_MAI_CTL_ERRORE | VC4_HD_MAI_CTL_ERRORF); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); if (vc4_hdmi->variant->phy_rng_enable) vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); @@ -1309,6 +1419,7 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) { struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; struct device *dev = &vc4_hdmi->pdev->dev; + unsigned long flags; int ret; vc4_hdmi->audio.streaming = false; @@ -1316,20 +1427,29 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) if (ret) dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET); HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_DLATE | VC4_HD_MAI_CTL_ERRORE | VC4_HD_MAI_CTL_ERRORF); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + if (vc4_hdmi->variant->phy_rng_disable) vc4_hdmi->variant->phy_rng_disable(vc4_hdmi); @@ -1384,6 +1504,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; unsigned int sample_rate = params->sample_rate; unsigned int channels = params->channels; + unsigned long flags; u32 audio_packet_config, channel_mask; u32 channel_map; u32 mai_audio_format; @@ -1392,14 +1513,15 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, sample_rate, params->sample_width, channels); + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_CTL, VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) | VC4_HD_MAI_CTL_WHOLSMP | VC4_HD_MAI_CTL_CHALIGN | VC4_HD_MAI_CTL_ENABLE); - vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); - mai_sample_rate = sample_rate_to_mai_fmt(sample_rate); if (params->iec.status[0] & IEC958_AES0_NONAUDIO && params->channels == 8) @@ -1437,8 +1559,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask); HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map); HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); + vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); vc4_hdmi_set_audio_infoframe(encoder); @@ -1729,6 +1854,8 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) struct cec_msg *msg = &vc4_hdmi->cec_rx_msg; unsigned int i; + lockdep_assert_held(&vc4_hdmi->hw_lock); + msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >> VC4_HDMI_CEC_REC_WRD_CNT_SHIFT); @@ -1747,11 +1874,12 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1) } } -static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv) +static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi) { - struct vc4_hdmi *vc4_hdmi = priv; u32 cntrl1; + lockdep_assert_held(&vc4_hdmi->hw_lock); + cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD; cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN; @@ -1760,11 +1888,24 @@ static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv) return IRQ_WAKE_THREAD; } -static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv) +static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv) { struct vc4_hdmi *vc4_hdmi = priv; + irqreturn_t ret; + + spin_lock(&vc4_hdmi->hw_lock); + ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi); + spin_unlock(&vc4_hdmi->hw_lock); + + return ret; +} + +static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi) +{ u32 cntrl1; + lockdep_assert_held(&vc4_hdmi->hw_lock); + vc4_hdmi->cec_rx_msg.len = 0; cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); vc4_cec_read_msg(vc4_hdmi, cntrl1); @@ -1777,6 +1918,18 @@ static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv) return IRQ_WAKE_THREAD; } +static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv) +{ + struct vc4_hdmi *vc4_hdmi = priv; + irqreturn_t ret; + + spin_lock(&vc4_hdmi->hw_lock); + ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi); + spin_unlock(&vc4_hdmi->hw_lock); + + return ret; +} + static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) { struct vc4_hdmi *vc4_hdmi = priv; @@ -1787,14 +1940,17 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) if (!(stat & VC4_HDMI_CPU_CEC)) return IRQ_NONE; + spin_lock(&vc4_hdmi->hw_lock); cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5); vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT; if (vc4_hdmi->cec_irq_was_rx) - ret = vc4_cec_irq_handler_rx_bare(irq, priv); + ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi); else - ret = vc4_cec_irq_handler_tx_bare(irq, priv); + ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi); HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC); + spin_unlock(&vc4_hdmi->hw_lock); + return ret; } @@ -1803,6 +1959,7 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); /* clock period in microseconds */ const u32 usecs = 1000000 / CEC_CLOCK_FREQ; + unsigned long flags; u32 val; int ret; @@ -1810,6 +1967,8 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) if (ret) return ret; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + val = HDMI_READ(HDMI_CEC_CNTRL_5); val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET | VC4_HDMI_CEC_CNT_TO_4700_US_MASK | @@ -1840,12 +1999,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) if (!vc4_hdmi->variant->external_irq_controller) HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + return 0; } static int vc4_hdmi_cec_disable(struct cec_adapter *adap) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); if (!vc4_hdmi->variant->external_irq_controller) HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC); @@ -1853,6 +2017,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap) HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) | VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + pm_runtime_put(&vc4_hdmi->pdev->dev); return 0; @@ -1869,10 +2035,14 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + unsigned long flags; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_CEC_CNTRL_1, (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + return 0; } @@ -1881,6 +2051,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); struct drm_device *dev = vc4_hdmi->connector.dev; + unsigned long flags; u32 val; unsigned int i; @@ -1889,6 +2060,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, return -ENOMEM; } + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + for (i = 0; i < msg->len; i += 4) HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2), (msg->msg[i]) | @@ -1904,6 +2077,9 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, val |= VC4_HDMI_CEC_START_XMIT_BEGIN; HDMI_WRITE(HDMI_CEC_CNTRL_1, val); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + return 0; } @@ -1918,6 +2094,7 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) struct cec_connector_info conn_info; struct platform_device *pdev = vc4_hdmi->pdev; struct device *dev = &pdev->dev; + unsigned long flags; u32 value; int ret; @@ -1937,10 +2114,12 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); value = HDMI_READ(HDMI_CEC_CNTRL_1); /* Set the logical address to Unregistered */ value |= VC4_HDMI_CEC_ADDR_MASK; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); vc4_hdmi_cec_update_clk_div(vc4_hdmi); @@ -1959,7 +2138,9 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) if (ret) goto err_remove_cec_rx_handler; } else { + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); ret = request_threaded_irq(platform_get_irq(pdev, 0), vc4_cec_irq_handler, @@ -2265,6 +2446,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); if (!vc4_hdmi) return -ENOMEM; + spin_lock_init(&vc4_hdmi->hw_lock); INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); dev_set_drvdata(dev, vc4_hdmi); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 49fc91962fe4..e26fa193fd65 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -186,6 +186,7 @@ struct vc4_hdmi { /* Common debugfs regset */ struct debugfs_regset32 hdmi_regset; struct debugfs_regset32 hd_regset; + /* VC5 debugfs regset */ struct debugfs_regset32 cec_regset; struct debugfs_regset32 csc_regset; @@ -193,6 +194,11 @@ struct vc4_hdmi { struct debugfs_regset32 phy_regset; struct debugfs_regset32 ram_regset; struct debugfs_regset32 rm_regset; + + /** + * @hw_lock: Spinlock protecting device register access. + */ + spinlock_t hw_lock; }; static inline struct vc4_hdmi * diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c index 36535480f8e2..62148f0dc284 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c @@ -130,31 +130,49 @@ void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct vc4_hdmi_connector_state *conn_state) { + unsigned long flags; + /* PHY should be in reset, like * vc4_hdmi_encoder_disable() does. */ + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_TX_PHY_CTL_0, HDMI_READ(HDMI_TX_PHY_CTL_0) & ~VC4_HDMI_TX_PHY_RNG_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_TX_PHY_CTL_0, HDMI_READ(HDMI_TX_PHY_CTL_0) | VC4_HDMI_TX_PHY_RNG_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } static unsigned long long @@ -336,6 +354,8 @@ phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) { + lockdep_assert_held(&vc4_hdmi->hw_lock); + HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f); HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10)); } @@ -348,10 +368,13 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, unsigned long long pixel_freq = conn_state->pixel_rate; unsigned long long vco_freq; unsigned char word_sel; + unsigned long flags; u8 vco_sel, vco_div; vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + vc5_hdmi_reset_phy(vc4_hdmi); HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, @@ -501,23 +524,37 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, HDMI_READ(HDMI_TX_PHY_RESET_CTL) | VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB); + + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); vc5_hdmi_reset_phy(vc4_hdmi); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) & ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) { + unsigned long flags; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) | VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 23930a8fa376..24056441a4bb 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -445,6 +445,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi, const struct vc4_hdmi_variant *variant = hdmi->variant; void __iomem *base; + lockdep_assert_held(&hdmi->hw_lock); + WARN_ON(!pm_runtime_active(&hdmi->pdev->dev)); if (reg >= variant->num_registers) { -- Gitee From 815757f6c321e089675b37df35a00e073aa83b1d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 19 Oct 2021 14:19:04 +0200 Subject: [PATCH 045/155] drm/vc4: hdmi: Use a mutex to prevent concurrent framework access The vc4 HDMI controller registers into the KMS, CEC and ALSA frameworks. However, no particular care is done to prevent the concurrent execution of different framework hooks from happening at the same time. In order to protect against that scenario, let's introduce a mutex that relevant ALSA and KMS hooks will need to take to prevent concurrent execution. CEC is left out at the moment though, since the .get_modes and .detect KMS hooks, when running cec_s_phys_addr_from_edid, can end up calling CEC's .adap_enable hook. This introduces some reentrancy that isn't easy to deal with properly. The CEC hooks also don't share much state with the rest of the driver: the registers are entirely separate, we don't share any variable, the only thing that can conflict is the CEC clock divider setup that can be affected by a mode set. However, after discussing it, it looks like CEC should be able to recover from this if it was to happen. Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 114 +++++++++++++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_hdmi.h | 14 ++++ 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 45227b3d289c..1228ff0121bf 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -199,6 +199,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; bool connected = false; + mutex_lock(&vc4_hdmi->mutex); + WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev)); if (vc4_hdmi->hpd_gpio) { @@ -238,6 +240,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) out: pm_runtime_put(&vc4_hdmi->pdev->dev); + mutex_unlock(&vc4_hdmi->mutex); return ret; } @@ -254,10 +257,14 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) int ret = 0; struct edid *edid; + mutex_lock(&vc4_hdmi->mutex); + edid = drm_get_edid(connector, vc4_hdmi->ddc); cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - if (!edid) - return -ENODEV; + if (!edid) { + ret = -ENODEV; + goto out; + } vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); @@ -277,6 +284,9 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) } } +out: + mutex_unlock(&vc4_hdmi->mutex); + return ret; } @@ -503,6 +513,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) union hdmi_infoframe frame; int ret; + lockdep_assert_held(&vc4_hdmi->mutex); + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, connector, mode); if (ret < 0) { @@ -554,6 +566,8 @@ static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder) struct drm_connector_state *conn_state = connector->state; union hdmi_infoframe frame; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!vc4_hdmi->variant->supports_hdr) return; @@ -570,6 +584,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + lockdep_assert_held(&vc4_hdmi->mutex); + vc4_hdmi_set_avi_infoframe(encoder); vc4_hdmi_set_spd_infoframe(encoder); /* @@ -589,6 +605,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_display_info *display = &vc4_hdmi->connector.display_info; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!vc4_encoder->hdmi_monitor) return false; @@ -607,6 +625,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long flags; + lockdep_assert_held(&vc4_hdmi->mutex); + if (!encoder->crtc || !encoder->crtc->state) return; @@ -680,6 +700,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long flags; + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); @@ -696,6 +718,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); vc4_hdmi_disable_scrambling(encoder); + + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, @@ -705,6 +729,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, unsigned long flags; int ret; + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); @@ -722,6 +748,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, ret = pm_runtime_put(&vc4_hdmi->pdev->dev); if (ret < 0) DRM_ERROR("Failed to release power domain: %d\n", ret); + + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) @@ -1007,10 +1035,12 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, unsigned long flags; int ret; + mutex_lock(&vc4_hdmi->mutex); + ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); if (ret < 0) { DRM_ERROR("Failed to retain power domain: %d\n", ret); - return; + goto out; } pixel_rate = vc4_conn_state->pixel_rate; @@ -1071,6 +1101,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, if (vc4_hdmi->variant->set_timings) vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode); + mutex_unlock(&vc4_hdmi->mutex); + return; err_remove_bvb_req: @@ -1082,6 +1114,8 @@ err_disable_pixel_clk: clk_disable_unprepare(vc4_hdmi->pixel_clock); err_runtime_pm: pm_runtime_put(&vc4_hdmi->pdev->dev); +out: + mutex_unlock(&vc4_hdmi->mutex); return; } @@ -1093,6 +1127,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long flags; + mutex_lock(&vc4_hdmi->mutex); + if (vc4_encoder->hdmi_monitor && drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { if (vc4_hdmi->variant->csc_setup) @@ -1109,6 +1145,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, @@ -1122,6 +1160,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, unsigned long flags; int ret; + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, @@ -1181,6 +1221,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, vc4_hdmi_recenter_fifo(vc4_hdmi); vc4_hdmi_enable_scrambling(encoder); + + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) @@ -1357,6 +1399,7 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat u32 n, cts; u64 tmp; + lockdep_assert_held(&vc4_hdmi->mutex); lockdep_assert_held(&vc4_hdmi->hw_lock); n = 128 * samplerate / 1000; @@ -1390,13 +1433,17 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; unsigned long flags; + mutex_lock(&vc4_hdmi->mutex); + /* * If the HDMI encoder hasn't probed, or the encoder is * currently in DVI mode, treat the codec dai as missing. */ if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & - VC4_HDMI_RAM_PACKET_ENABLE)) + VC4_HDMI_RAM_PACKET_ENABLE)) { + mutex_unlock(&vc4_hdmi->mutex); return -ENODEV; + } vc4_hdmi->audio.streaming = true; @@ -1412,6 +1459,8 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) if (vc4_hdmi->variant->phy_rng_enable) vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); + mutex_unlock(&vc4_hdmi->mutex); + return 0; } @@ -1422,6 +1471,8 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) unsigned long flags; int ret; + lockdep_assert_held(&vc4_hdmi->mutex); + vc4_hdmi->audio.streaming = false; ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false); if (ret) @@ -1441,6 +1492,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); unsigned long flags; + mutex_lock(&vc4_hdmi->mutex); + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_CTL, @@ -1455,6 +1508,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) vc4_hdmi->audio.streaming = false; vc4_hdmi_audio_reset(vc4_hdmi); + + mutex_unlock(&vc4_hdmi->mutex); } static int sample_rate_to_mai_fmt(int samplerate) @@ -1513,6 +1568,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, sample_rate, params->sample_width, channels); + mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -1567,6 +1624,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); vc4_hdmi_set_audio_infoframe(encoder); + mutex_unlock(&vc4_hdmi->mutex); + return 0; } @@ -1630,7 +1689,9 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data, struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); struct drm_connector *connector = &vc4_hdmi->connector; + mutex_lock(&vc4_hdmi->mutex); memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); + mutex_unlock(&vc4_hdmi->mutex); return 0; } @@ -1963,6 +2024,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) u32 val; int ret; + /* + * NOTE: This function should really take vc4_hdmi->mutex, but doing so + * results in a reentrancy since cec_s_phys_addr_from_edid() called in + * .detect or .get_modes might call .adap_enable, which leads to this + * function being called with that mutex held. + * + * Concurrency is not an issue for the moment since we don't share any + * state with KMS, so we can ignore the lock for now, but we need to + * keep it in mind if we were to change that assumption. + */ + ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); if (ret) return ret; @@ -2009,6 +2081,17 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap) struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); unsigned long flags; + /* + * NOTE: This function should really take vc4_hdmi->mutex, but doing so + * results in a reentrancy since cec_s_phys_addr_from_edid() called in + * .detect or .get_modes might call .adap_enable, which leads to this + * function being called with that mutex held. + * + * Concurrency is not an issue for the moment since we don't share any + * state with KMS, so we can ignore the lock for now, but we need to + * keep it in mind if we were to change that assumption. + */ + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); if (!vc4_hdmi->variant->external_irq_controller) @@ -2037,6 +2120,17 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); unsigned long flags; + /* + * NOTE: This function should really take vc4_hdmi->mutex, but doing so + * results in a reentrancy since cec_s_phys_addr_from_edid() called in + * .detect or .get_modes might call .adap_enable, which leads to this + * function being called with that mutex held. + * + * Concurrency is not an issue for the moment since we don't share any + * state with KMS, so we can ignore the lock for now, but we need to + * keep it in mind if we were to change that assumption. + */ + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_CEC_CNTRL_1, (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | @@ -2055,6 +2149,17 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, u32 val; unsigned int i; + /* + * NOTE: This function should really take vc4_hdmi->mutex, but doing so + * results in a reentrancy since cec_s_phys_addr_from_edid() called in + * .detect or .get_modes might call .adap_enable, which leads to this + * function being called with that mutex held. + * + * Concurrency is not an issue for the moment since we don't share any + * state with KMS, so we can ignore the lock for now, but we need to + * keep it in mind if we were to change that assumption. + */ + if (msg->len > 16) { drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len); return -ENOMEM; @@ -2446,6 +2551,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); if (!vc4_hdmi) return -ENOMEM; + mutex_init(&vc4_hdmi->mutex); spin_lock_init(&vc4_hdmi->hw_lock); INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index e26fa193fd65..242898b53312 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -199,6 +199,20 @@ struct vc4_hdmi { * @hw_lock: Spinlock protecting device register access. */ spinlock_t hw_lock; + + /** + * @mutex: Mutex protecting the driver access across multiple + * frameworks (KMS, ALSA). + * + * NOTE: While supported, CEC has been left out since + * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a + * reentrancy issue between .get_modes (or .detect) and .adap_enable. + * Since we don't share any state between the CEC hooks and KMS', it's + * not a big deal. The only trouble might come from updating the CEC + * clock divider which might be affected by a modeset, but CEC should + * be resilient to that. + */ + struct mutex mutex; }; static inline struct vc4_hdmi * -- Gitee From de013881db50483eff7c02e03a4fe2b6e90b751a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 19 Oct 2021 14:19:29 +0200 Subject: [PATCH 046/155] drm/vc4: hdmi: Prevent access to crtc->state outside of KMS Accessing the crtc->state pointer from outside the modesetting context is not allowed. We thus need to copy whatever we need from the KMS state to our structure in order to access it. However, in the vc4 HDMI driver we do use that pointer in the ALSA code path, and potentially in the hotplug interrupt handler path. These paths both need access to the CRTC adjusted mode in order for the proper dividers to be set for ALSA, and the scrambler state to be reinstated properly for hotplug. Let's copy this mode into our private encoder structure and reference it from there when needed. Since that part is shared between KMS and other paths, we need to protect it using our mutex. Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/ Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 39 ++++++++++++++++++++++------------ drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1228ff0121bf..d7a7ad99ebe4 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -508,8 +508,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct drm_connector *connector = &vc4_hdmi->connector; struct drm_connector_state *cstate = connector->state; - struct drm_crtc *crtc = encoder->crtc; - const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; union hdmi_infoframe frame; int ret; @@ -621,8 +620,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) { - struct drm_display_mode *mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long flags; lockdep_assert_held(&vc4_hdmi->mutex); @@ -630,7 +629,6 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) if (!encoder->crtc || !encoder->crtc->state) return; - mode = &encoder->crtc->state->adjusted_mode; if (!vc4_hdmi_supports_scrambling(encoder, mode)) return; @@ -652,18 +650,21 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_crtc *crtc = encoder->crtc; unsigned long flags; + lockdep_assert_held(&vc4_hdmi->mutex); + /* * At boot, encoder->crtc will be NULL. Since we don't know the * state of the scrambler and in order to avoid any * inconsistency, let's disable it all the time. */ - if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode)) + if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode)) return; - if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode)) + if (crtc && !vc4_hdmi_mode_needs_scrambling(mode)) return; if (delayed_work_pending(&vc4_hdmi->scrambling_work)) @@ -1030,7 +1031,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, drm_atomic_get_new_connector_state(state, connector); struct vc4_hdmi_connector_state *vc4_conn_state = conn_state_to_vc4_hdmi_conn_state(conn_state); - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long bvb_rate, pixel_rate, hsm_rate; unsigned long flags; int ret; @@ -1122,9 +1123,9 @@ out: static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); unsigned long flags; mutex_lock(&vc4_hdmi->mutex); @@ -1152,8 +1153,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; @@ -1229,6 +1230,19 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) { } +static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + mutex_lock(&vc4_hdmi->mutex); + memcpy(&vc4_hdmi->saved_adjusted_mode, + &crtc_state->adjusted_mode, + sizeof(vc4_hdmi->saved_adjusted_mode)); + mutex_unlock(&vc4_hdmi->mutex); +} + #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL #define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL @@ -1307,6 +1321,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { .atomic_check = vc4_hdmi_encoder_atomic_check, + .atomic_mode_set = vc4_hdmi_encoder_atomic_mode_set, .mode_valid = vc4_hdmi_encoder_mode_valid, .disable = vc4_hdmi_encoder_disable, .enable = vc4_hdmi_encoder_enable, @@ -1393,9 +1408,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) { - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; - struct drm_crtc *crtc = encoder->crtc; - const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; u32 n, cts; u64 tmp; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 242898b53312..285b751c5f2d 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -213,6 +213,12 @@ struct vc4_hdmi { * be resilient to that. */ struct mutex mutex; + + /** + * @saved_adjusted_mode: Copy of @drm_crtc_state.adjusted_mode + * for use by ALSA hooks and interrupt handlers. Protected by @mutex. + */ + struct drm_display_mode saved_adjusted_mode; }; static inline struct vc4_hdmi * -- Gitee From e8a232bb53d1696a4f5cf35477b1d8523b857fe1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 24 Sep 2021 14:27:38 +0200 Subject: [PATCH 047/155] drm/vc4: hdmi: Check the device state in prepare() Even though we already check that the encoder->crtc pointer is there during in startup(), which is part of the open() path in ASoC, nothing guarantees that our encoder state won't change between the time when we open the device and the time we prepare it. Move the sanity checks we do in startup() to a helper and call it from prepare(). Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d7a7ad99ebe4..3ce765c92fc5 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1440,20 +1440,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) return snd_soc_card_get_drvdata(card); } +static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) +{ + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + + lockdep_assert_held(&vc4_hdmi->mutex); + + /* + * The encoder doesn't have a CRTC until the first modeset. + */ + if (!encoder->crtc) + return false; + + /* + * If the encoder is currently in DVI mode, treat the codec DAI + * as missing. + */ + if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE)) + return false; + + return true; +} + static int vc4_hdmi_audio_startup(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; unsigned long flags; mutex_lock(&vc4_hdmi->mutex); - /* - * If the HDMI encoder hasn't probed, or the encoder is - * currently in DVI mode, treat the codec dai as missing. - */ - if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & - VC4_HDMI_RAM_PACKET_ENABLE)) { + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { mutex_unlock(&vc4_hdmi->mutex); return -ENODEV; } @@ -1583,6 +1599,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, mutex_lock(&vc4_hdmi->mutex); + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { + mutex_unlock(&vc4_hdmi->mutex); + return -EINVAL; + } + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); -- Gitee From ee60c5b600316378b65fab2bd62833bf80fb1fe7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 19 Oct 2021 17:31:58 +0200 Subject: [PATCH 048/155] drm/vc4: hdmi: Introduce an output_enabled flag We currently poke at encoder->crtc in the ALSA code path to determine whether the HDMI output is enabled or not, and thus whether we should allow the audio output. However, that pointer is deprecated and shouldn't really be used by atomic drivers anymore. Since we have the infrastructure in place now, let's just create a flag that we toggle to report whether the controller is currently enabled and use that instead of encoder->crtc in ALSA. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++++++++++---- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 3ce765c92fc5..d5f53a065ab2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -755,6 +755,11 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_enabled = false; + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) @@ -1228,6 +1233,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) { + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_enabled = true; + mutex_unlock(&vc4_hdmi->mutex); } static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, @@ -1442,14 +1452,12 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) { - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; - lockdep_assert_held(&vc4_hdmi->mutex); /* - * The encoder doesn't have a CRTC until the first modeset. + * If the controller is disabled, prevent any ALSA output. */ - if (!encoder->crtc) + if (!vc4_hdmi->output_enabled) return false; /* diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 285b751c5f2d..33a865a9b601 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -219,6 +219,12 @@ struct vc4_hdmi { * for use by ALSA hooks and interrupt handlers. Protected by @mutex. */ struct drm_display_mode saved_adjusted_mode; + + /** + * @output_enabled: Is the HDMI controller currently active? + * Protected by @mutex. + */ + bool output_enabled; }; static inline struct vc4_hdmi * -- Gitee From 10c442fd12fade2a25cc0ebdf8c387ec77c3f4cc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 19 Oct 2021 19:13:46 +0200 Subject: [PATCH 049/155] drm/vc4: hdmi: Introduce a scdc_enabled flag We currently rely on two functions, vc4_hdmi_supports_scrambling() and vc4_hdmi_mode_needs_scrambling() to determine if we should enable and disable the scrambler for any given mode. Since we might need to disable the controller at boot, we also always run vc4_hdmi_disable_scrambling() and thus call those functions without a mode yet, which in turns need to make some special casing in order for it to work. Instead of duplicating the check for whether or not we need to take care of the scrambler in both vc4_hdmi_enable_scrambling() and vc4_hdmi_disable_scrambling(), we can do that check only when we enable it and store whether or not it's been enabled in our private structure. We also need to initialize that flag at true to make sure we disable the scrambler at boot since we can't really know its state yet. This allows to simplify a bit that part of the driver, and removes one user of our copy of the CRTC adjusted mode outside of KMS (since vc4_hdmi_disable_scrambling() might be called from the hotplug interrupt handler). It also removes our last user of the legacy encoder->crtc pointer. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 22 ++++++++++++---------- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d5f53a065ab2..245fa882598a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -643,6 +643,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) VC5_HDMI_SCRAMBLER_CTL_ENABLE); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + vc4_hdmi->scdc_enabled = true; + queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work, msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS)); } @@ -650,22 +652,14 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - struct drm_crtc *crtc = encoder->crtc; unsigned long flags; lockdep_assert_held(&vc4_hdmi->mutex); - /* - * At boot, encoder->crtc will be NULL. Since we don't know the - * state of the scrambler and in order to avoid any - * inconsistency, let's disable it all the time. - */ - if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode)) + if (!vc4_hdmi->scdc_enabled) return; - if (crtc && !vc4_hdmi_mode_needs_scrambling(mode)) - return; + vc4_hdmi->scdc_enabled = false; if (delayed_work_pending(&vc4_hdmi->scrambling_work)) cancel_delayed_work_sync(&vc4_hdmi->scrambling_work); @@ -2608,6 +2602,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->pdev = pdev; vc4_hdmi->variant = variant; + /* + * Since we don't know the state of the controller and its + * display (if any), let's assume it's always enabled. + * vc4_hdmi_disable_scrambling() will thus run at boot, make + * sure it's disabled, and avoid any inconsistency. + */ + vc4_hdmi->scdc_enabled = true; + ret = variant->init_resources(vc4_hdmi); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 33a865a9b601..ad7d4b275ed8 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -225,6 +225,12 @@ struct vc4_hdmi { * Protected by @mutex. */ bool output_enabled; + + /** + * @scdc_enabled: Is the HDMI controller currently running with + * the scrambler on? Protected by @mutex. + */ + bool scdc_enabled; }; static inline struct vc4_hdmi * -- Gitee From d965ab81ca77f8bd7c94cd0f511ec8bd3a2d5faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 3 Nov 2021 12:21:14 +0100 Subject: [PATCH 050/155] overlays: Add fbtft overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an overlay that provides much of the functionality that fbtft_device did. Signed-off-by: Noralf Trønnes --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/README | 124 ++++ arch/arm/boot/dts/overlays/fbtft-overlay.dts | 611 +++++++++++++++++++ 3 files changed, 736 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/fbtft-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index b36c618b01d0..a6b0d9ea0385 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -49,6 +49,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ enc28j60.dtbo \ enc28j60-spi2.dtbo \ exc3000.dtbo \ + fbtft.dtbo \ fe-pi-audio.dtbo \ fsm-demo.dtbo \ ghost-amp.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 1404de8444f2..9ad2ed3b3b7e 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -857,6 +857,130 @@ Params: interrupt GPIO used for interrupt (default 4) swapxy Touchscreen swapped x y axis +Name: fbtft +Info: Overlay for SPI-connected displays using the fbtft drivers. + + This overlay seeks to replace the functionality provided by fbtft_device + which is now gone from the kernel. + + Most displays from fbtft_device have been ported over. + Example: + dtoverlay=fbtft,spi0-0,rpi-display,reset_pin=23,dc_pin=24,led_pin=18,rotate=270 + + It is also possible to specify the controller (this will use the default + init sequence in the driver). + Example: + dtoverlay=fbtft,spi0-0,ili9341,bgr,reset_pin=23,dc_pin=24,led_pin=18,rotate=270 + + For devices on spi1 or spi2, the interfaces should be enabled + with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays. + + The following features of fbtft_device have not been ported over: + - parallel bus is not supported + - the init property which overrides the controller initialization + sequence is not supported as a parameter due to memory limitations in + the bootloader responsible for applying the overlay. + + See https://github.com/notro/fbtft/wiki/FBTFT-RPI-overlays for how to + create an overlay. + +Load: dtoverlay=fbtft,= +Params: + spi- Configure device at spi, cs + (boolean, required) + speed SPI bus speed in Hz (default 32000000) + cpha Shifted clock phase (CPHA) mode + cpol Inverse clock polarity (CPOL) mode + + adafruit18 Adafruit 1.8 + adafruit22 Adafruit 2.2 (old) + adafruit22a Adafruit 2.2 + adafruit28 Adafruit 2.8 + adafruit13m Adafruit 1.3 OLED + admatec_c-berry28 C-Berry28 + dogs102 EA DOGS102 + er_tftm050_2 ER-TFTM070-2 + er_tftm070_5 ER-TFTM070-5 + ew24ha0 EW24HA0 + ew24ha0_9bit EW24HA0 in 9-bit mode + freetronicsoled128 Freetronics OLED128 + hy28a HY28A + hy28b HY28B + itdb28_spi ITDB02-2.8 with SPI interface circuit + mi0283qt-2 Watterott MI0283QT-2 + mi0283qt-9a Watterott MI0283QT-9A + nokia3310 Nokia 3310 + nokia3310a Nokia 3310a + nokia5110 Nokia 5110 + piscreen PiScreen + pitft Adafruit PiTFT 2.8 + pioled ILSoft OLED + rpi-display Watterott rpi-display + sainsmart18 Sainsmart 1.8 + sainsmart32_spi Sainsmart 3.2 with SPI interfce circuit + tinylcd35 TinyLCD 3.5 + tm022hdh26 Tianma TM022HDH26 + tontec35_9481 Tontect 3.5 with ILI9481 controller + tontec35_9486 Tontect 3.5 with ILI9486 controller + waveshare32b Waveshare 3.2 + waveshare22 Waveshare 2.2 + + bd663474 BD663474 display controller + hx8340bn HX8340BN display controller + hx8347d HX8347D display controller + hx8353d HX8353D display controller + hx8357d HX8357D display controller + ili9163 ILI9163 display controller + ili9320 ILI9320 display controller + ili9325 ILI9325 display controller + ili9340 ILI9340 display controller + ili9341 ILI9341 display controller + ili9481 ILI9481 display controller + ili9486 ILI9486 display controller + pcd8544 PCD8544 display controller + ra8875 RA8875 display controller + s6d02a1 S6D02A1 display controller + s6d1121 S6D1121 display controller + seps525 SEPS525 display controller + sh1106 SH1106 display controller + ssd1289 SSD1289 display controller + ssd1305 SSD1305 display controller + ssd1306 SSD1306 display controller + ssd1325 SSD1325 display controller + ssd1331 SSD1331 display controller + ssd1351 SSD1351 display controller + st7735r ST7735R display controller + st7789v ST7789V display controller + tls8204 TLS8204 display controller + uc1611 UC1611 display controller + uc1701 UC1701 display controller + upd161704 UPD161704 display controller + + width Display width in pixels + height Display height in pixels + regwidth Display controller register width (default is + driver specific) + buswidth Display bus interface width (default 8) + debug Debug output level {0-7} + rotate Display rotation {0, 90, 180, 270} (counter + clockwise). Not supported by all drivers. + bgr Enable BGR mode (default off). Use if Red and + Blue are swapped. Not supported by all drivers. + fps Frames per second (default 30). In effect this + states how long the driver will wait after video + memory has been changed until display update + transfer is started. + txbuflen Length of the FBTFT transmit buffer + (default 4096) + startbyte Sets the Start byte used by fb_ili9320, + fb_ili9325 and fb_hx8347d. Common value is 0x70. + gamma String representation of Gamma Curve(s). Driver + specific. Not supported by all drivers. + reset_pin GPIO pin for RESET + dc_pin GPIO pin for D/C + led_pin GPIO pin for LED backlight + + Name: fe-pi-audio Info: Configures the Fe-Pi Audio Sound Card Load: dtoverlay=fe-pi-audio diff --git a/arch/arm/boot/dts/overlays/fbtft-overlay.dts b/arch/arm/boot/dts/overlays/fbtft-overlay.dts new file mode 100644 index 000000000000..db45f8c53bcc --- /dev/null +++ b/arch/arm/boot/dts/overlays/fbtft-overlay.dts @@ -0,0 +1,611 @@ +/* + * Device Tree overlay for fbtft drivers + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2835"; + + /* adafruit18 */ + fragment@0 { + target = <&display>; + __dormant__ { + compatible = "sitronix,st7735r"; + spi-max-frequency = <32000000>; + gamma = "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"; + }; + }; + + /* adafruit22 */ + fragment@1 { + target = <&display>; + __dormant__ { + compatible = "himax,hx8340bn"; + spi-max-frequency = <32000000>; + buswidth = <9>; + bgr; + }; + }; + + /* adafruit22a */ + fragment@2 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9340"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* adafruit28 */ + fragment@3 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9341"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* adafruit13m */ + fragment@4 { + target = <&display>; + __dormant__ { + compatible = "solomon,ssd1306"; + spi-max-frequency = <16000000>; + }; + }; + + /* admatec_c-berry28 */ + fragment@5 { + target = <&display>; + __dormant__ { + compatible = "sitronix,st7789v"; + spi-max-frequency = <48000000>; + init = <0x01000011 + 0x02000078 + 0x0100003A 0x05 + 0x010000B2 0x0C 0x0C 0x00 0x33 0x33 + 0x010000B7 0x35 + 0x010000C2 0x01 0xFF + 0x010000C3 0x17 + 0x010000C4 0x20 + 0x010000BB 0x17 + 0x010000C5 0x20 + 0x010000D0 0xA4 0xA1 + 0x01000029>; + gamma = "D0 00 14 15 13 2C 42 43 4E 09 16 14 18 21\nD0 00 14 15 13 0B 43 55 53 0C 17 14 23 20"; + }; + }; + + /* dogs102 */ + fragment@6 { + target = <&display>; + __dormant__ { + compatible = "UltraChip,uc1701"; + spi-max-frequency = <8000000>; + bgr; + }; + }; + + /* er_tftm050_2 */ + fragment@7 { + target = <&display>; + __dormant__ { + compatible = "raio,ra8875"; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + width = <480>; + height = <272>; + bgr; + }; + }; + + /* er_tftm070_5 */ + fragment@8 { + target = <&display>; + __dormant__ { + compatible = "raio,ra8875"; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + width = <800>; + height = <480>; + bgr; + }; + }; + + /* ew24ha0 */ + fragment@9 { + target = <&display>; + __dormant__ { + compatible = "ultrachip,uc1611"; + spi-max-frequency = <32000000>; + spi-cpha; + spi-cpol; + }; + }; + + /* ew24ha0_9bit */ + fragment@10 { + target = <&display>; + __dormant__ { + compatible = "ultrachip,uc1611"; + spi-max-frequency = <32000000>; + spi-cpha; + spi-cpol; + buswidth = <9>; + }; + }; + + /* freetronicsoled128 */ + fragment@11 { + target = <&display>; + __dormant__ { + compatible = "solomon,ssd1351"; + spi-max-frequency = <20000000>; + backlight = <2>; /* FBTFT_ONBOARD_BACKLIGHT */ + bgr; + }; + }; + + /* hy28a */ + fragment@12 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9320"; + spi-max-frequency = <32000000>; + spi-cpha; + spi-cpol; + startbyte = <0x70>; + bgr; + }; + }; + + /* hy28b */ + fragment@13 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9325"; + spi-max-frequency = <48000000>; + spi-cpha; + spi-cpol; + init = <0x010000e7 0x0010 + 0x01000000 0x0001 + 0x01000001 0x0100 + 0x01000002 0x0700 + 0x01000003 0x1030 + 0x01000004 0x0000 + 0x01000008 0x0207 + 0x01000009 0x0000 + 0x0100000a 0x0000 + 0x0100000c 0x0001 + 0x0100000d 0x0000 + 0x0100000f 0x0000 + 0x01000010 0x0000 + 0x01000011 0x0007 + 0x01000012 0x0000 + 0x01000013 0x0000 + 0x02000032 + 0x01000010 0x1590 + 0x01000011 0x0227 + 0x02000032 + 0x01000012 0x009c + 0x02000032 + 0x01000013 0x1900 + 0x01000029 0x0023 + 0x0100002b 0x000e + 0x02000032 + 0x01000020 0x0000 + 0x01000021 0x0000 + 0x02000032 + 0x01000050 0x0000 + 0x01000051 0x00ef + 0x01000052 0x0000 + 0x01000053 0x013f + 0x01000060 0xa700 + 0x01000061 0x0001 + 0x0100006a 0x0000 + 0x01000080 0x0000 + 0x01000081 0x0000 + 0x01000082 0x0000 + 0x01000083 0x0000 + 0x01000084 0x0000 + 0x01000085 0x0000 + 0x01000090 0x0010 + 0x01000092 0x0000 + 0x01000093 0x0003 + 0x01000095 0x0110 + 0x01000097 0x0000 + 0x01000098 0x0000 + 0x01000007 0x0133 + 0x01000020 0x0000 + 0x01000021 0x0000 + 0x02000064>; + startbyte = <0x70>; + bgr; + fps = <50>; + gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; + }; + }; + + /* itdb28_spi */ + fragment@14 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9325"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* mi0283qt-2 */ + fragment@15 { + target = <&display>; + __dormant__ { + compatible = "himax,hx8347d"; + spi-max-frequency = <32000000>; + startbyte = <0x70>; + bgr; + }; + }; + + /* mi0283qt-9a */ + fragment@16 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9341"; + spi-max-frequency = <32000000>; + buswidth = <9>; + bgr; + }; + }; + + /* nokia3310 */ + fragment@17 { + target = <&display>; + __dormant__ { + compatible = "philips,pcd8544"; + spi-max-frequency = <400000>; + }; + }; + + /* nokia3310a */ + fragment@18 { + target = <&display>; + __dormant__ { + compatible = "teralane,tls8204"; + spi-max-frequency = <1000000>; + }; + }; + + /* nokia5110 */ + fragment@19 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9163"; + spi-max-frequency = <12000000>; + bgr; + }; + }; + + /* piscreen */ + fragment@20 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9486"; + spi-max-frequency = <32000000>; + regwidth = <16>; + bgr; + }; + }; + + /* pitft */ + fragment@21 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9340"; + spi-max-frequency = <32000000>; + init = <0x01000001 + 0x02000005 + 0x01000028 + 0x010000EF 0x03 0x80 0x02 + 0x010000CF 0x00 0xC1 0x30 + 0x010000ED 0x64 0x03 0x12 0x81 + 0x010000E8 0x85 0x00 0x78 + 0x010000CB 0x39 0x2C 0x00 0x34 0x02 + 0x010000F7 0x20 + 0x010000EA 0x00 0x00 + 0x010000C0 0x23 + 0x010000C1 0x10 + 0x010000C5 0x3E 0x28 + 0x010000C7 0x86 + 0x0100003A 0x55 + 0x010000B1 0x00 0x18 + 0x010000B6 0x08 0x82 0x27 + 0x010000F2 0x00 + 0x01000026 0x01 + 0x010000E0 0x0F 0x31 0x2B 0x0C 0x0E 0x08 0x4E 0xF1 0x37 0x07 0x10 0x03 0x0E 0x09 0x00 + 0x010000E1 0x00 0x0E 0x14 0x03 0x11 0x07 0x31 0xC1 0x48 0x08 0x0F 0x0C 0x31 0x36 0x0F + 0x01000011 + 0x02000064 + 0x01000029 + 0x02000014>; + bgr; + }; + }; + + /* pioled */ + fragment@22 { + target = <&display>; + __dormant__ { + compatible = "solomon,ssd1351"; + spi-max-frequency = <20000000>; + bgr; + gamma = "0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4"; + }; + }; + + /* rpi-display */ + fragment@23 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9341"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* sainsmart18 */ + fragment@24 { + target = <&display>; + __dormant__ { + compatible = "sitronix,st7735r"; + spi-max-frequency = <32000000>; + }; + }; + + /* sainsmart32_spi */ + fragment@25 { + target = <&display>; + __dormant__ { + compatible = "solomon,ssd1289"; + spi-max-frequency = <16000000>; + bgr; + }; + }; + + /* tinylcd35 */ + fragment@26 { + target = <&display>; + __dormant__ { + compatible = "neosec,tinylcd"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* tm022hdh26 */ + fragment@27 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9341"; + spi-max-frequency = <32000000>; + bgr; + }; + }; + + /* tontec35_9481 - boards before 02 July 2014 */ + fragment@28 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9481"; + spi-max-frequency = <128000000>; + spi-cpha; + spi-cpol; + bgr; + }; + }; + + /* tontec35_9486 - boards after 02 July 2014 */ + fragment@29 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9486"; + spi-max-frequency = <128000000>; + spi-cpha; + spi-cpol; + bgr; + }; + }; + + /* waveshare32b */ + fragment@30 { + target = <&display>; + __dormant__ { + compatible = "ilitek,ili9340"; + spi-max-frequency = <48000000>; + init = <0x010000CB 0x39 0x2C 0x00 0x34 0x02 + 0x010000CF 0x00 0xC1 0x30 + 0x010000E8 0x85 0x00 0x78 + 0x010000EA 0x00 0x00 + 0x010000ED 0x64 0x03 0x12 0x81 + 0x010000F7 0x20 + 0x010000C0 0x23 + 0x010000C1 0x10 + 0x010000C5 0x3E 0x28 + 0x010000C7 0x86 + 0x01000036 0x28 + 0x0100003A 0x55 + 0x010000B1 0x00 0x18 + 0x010000B6 0x08 0x82 0x27 + 0x010000F2 0x00 + 0x01000026 0x01 + 0x010000E0 0x0F 0x31 0x2B 0x0C 0x0E 0x08 0x4E 0xF1 0x37 0x07 0x10 0x03 0x0E 0x09 0x00 + 0x010000E1 0x00 0x0E 0x14 0x03 0x11 0x07 0x31 0xC1 0x48 0x08 0x0F 0x0C 0x31 0x36 0x0F + 0x01000011 + 0x02000078 + 0x01000029 + 0x0100002C>; + bgr; + }; + }; + + /* waveshare22 */ + fragment@31 { + target = <&display>; + __dormant__ { + compatible = "hitachi,bd663474"; + spi-max-frequency = <32000000>; + spi-cpha; + spi-cpol; + }; + }; + + spidev_fragment: fragment@100 { + target-path = "spi0/spidev@0"; + __overlay__ { + status = "disabled"; + }; + }; + + display_fragment: fragment@101 { + target = <&spi0>; + __overlay__ { + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + + display: display@0{ + reg = <0>; + spi-max-frequency = <32000000>; + fps = <30>; + buswidth = <8>; + }; + }; + }; + + __overrides__ { + spi0-0 = <&display_fragment>, "target:0=",<&spi0>, + <&spidev_fragment>, "target-path=spi0/spidev@0", + <&display>, "reg:0=0"; + spi0-1 = <&display_fragment>, "target:0=",<&spi0>, + <&spidev_fragment>, "target-path=spi0/spidev@1", + <&display>, "reg:0=1"; + spi1-0 = <&display_fragment>, "target:0=",<&spi1>, + <&spidev_fragment>, "target-path=spi1/spidev@0", + <&display>, "reg:0=0"; + spi1-1 = <&display_fragment>, "target:0=",<&spi1>, + <&spidev_fragment>, "target-path=spi1/spidev@1", + <&display>, "reg:0=1"; + spi1-2 = <&display_fragment>, "target:0=",<&spi1>, + <&spidev_fragment>, "target-path=spi1/spidev@2", + <&display>, "reg:0=2"; + spi2-0 = <&display_fragment>, "target:0=",<&spi2>, + <&spidev_fragment>, "target-path=spi2/spidev@0", + <&display>, "reg:0=0"; + spi2-1 = <&display_fragment>, "target:0=",<&spi2>, + <&spidev_fragment>, "target-path=spi2/spidev@1", + <&display>, "reg:0=1"; + spi2-2 = <&display_fragment>, "target:0=",<&spi2>, + <&spidev_fragment>, "target-path=spi2/spidev@2", + <&display>, "reg:0=2"; + + speed = <&display>, "spi-max-frequency:0"; + cpha = <&display>, "spi-cpha?"; + cpol = <&display>, "spi-cpol?"; + + /* Displays */ + adafruit18 = <0>, "+0"; + adafruit22 = <0>, "+1"; + adafruit22a = <0>, "+2"; + adafruit28 = <0>, "+3"; + adafruit13m = <0>, "+4"; + admatec_c-berry28 = <0>, "+5"; + dogs102 = <0>, "+6"; + er_tftm050_2 = <0>, "+7"; + er_tftm070_5 = <0>, "+8"; + ew24ha0 = <0>, "+9"; + ew24ha0_9bit = <0>, "+10"; + freetronicsoled128 = <0>, "+11"; + hy28a = <0>, "+12"; + hy28b = <0>, "+13"; + itdb28_spi = <0>, "+14"; + mi0283qt-2 = <0>, "+15"; + mi0283qt-9a = <0>, "+16"; + nokia3310 = <0>, "+17"; + nokia3310a = <0>, "+18"; + nokia5110 = <0>, "+19"; + piscreen = <0>, "+20"; + pitft = <0>, "+21"; + pioled = <0>, "+22"; + rpi-display = <0>, "+23"; + sainsmart18 = <0>, "+24"; + sainsmart32_spi = <0>, "+25"; + tinylcd35 = <0>, "+26"; + tm022hdh26 = <0>, "+27"; + tontec35_9481 = <0>, "+28"; + tontec35_9486 = <0>, "+29"; + waveshare32b = <0>, "+30"; + waveshare22 = <0>, "+31"; + + /* Controllers */ + bd663474 = <&display>, "compatible=hitachi,bd663474"; + hx8340bn = <&display>, "compatible=himax,hx8340bn"; + hx8347d = <&display>, "compatible=himax,hx8347d"; + hx8353d = <&display>, "compatible=himax,hx8353d"; + hx8357d = <&display>, "compatible=himax,hx8357d"; + ili9163 = <&display>, "compatible=ilitek,ili9163"; + ili9320 = <&display>, "compatible=ilitek,ili9320"; + ili9325 = <&display>, "compatible=ilitek,ili9325"; + ili9340 = <&display>, "compatible=ilitek,ili9340"; + ili9341 = <&display>, "compatible=ilitek,ili9341"; + ili9481 = <&display>, "compatible=ilitek,ili9481"; + ili9486 = <&display>, "compatible=ilitek,ili9486"; + pcd8544 = <&display>, "compatible=philips,pcd8544"; + ra8875 = <&display>, "compatible=raio,ra8875"; + s6d02a1 = <&display>, "compatible=samsung,s6d02a1"; + s6d1121 = <&display>, "compatible=samsung,s6d1121"; + seps525 = <&display>, "compatible=syncoam,seps525"; + sh1106 = <&display>, "compatible=sinowealth,sh1106"; + ssd1289 = <&display>, "compatible=solomon,ssd1289"; + ssd1305 = <&display>, "compatible=solomon,ssd1305"; + ssd1306 = <&display>, "compatible=solomon,ssd1306"; + ssd1325 = <&display>, "compatible=solomon,ssd1325"; + ssd1331 = <&display>, "compatible=solomon,ssd1331"; + ssd1351 = <&display>, "compatible=solomon,ssd1351"; + st7735r = <&display>, "compatible=sitronix,st7735r"; + st7789v = <&display>, "compatible=sitronix,st7789v"; + tls8204 = <&display>, "compatible=teralane,tls8204"; + uc1611 = <&display>, "compatible=ultrachip,uc1611"; + uc1701 = <&display>, "compatible=UltraChip,uc1701"; + upd161704 = <&display>, "compatible=nec,upd161704"; + + width = <&display>, "width:0"; + height = <&display>, "height:0"; + regwidth = <&display>, "regwidth:0"; + buswidth = <&display>, "buswidth:0"; + debug = <&display>, "debug:0"; + rotate = <&display>, "rotate:0"; + bgr = <&display>, "bgr?"; + fps = <&display>, "fps:0"; + txbuflen = <&display>, "txbuflen:0"; + startbyte = <&display>, "startbyte:0"; + gamma = <&display>, "gamma"; + + reset_pin = <&display>, "reset-gpios:0=", <&gpio>, + <&display>, "reset-gpios:4", + <&display>, "reset-gpios:8=1"; /* GPIO_ACTIVE_LOW */ + dc_pin = <&display>, "dc-gpios:0=", <&gpio>, + <&display>, "dc-gpios:4", + <&display>, "dc-gpios:8=0"; /* GPIO_ACTIVE_HIGH */ + led_pin = <&display>, "led-gpios:0=", <&gpio>, + <&display>, "led-gpios:4", + <&display>, "led-gpios:8=0"; /* GPIO_ACTIVE_HIGH */ + }; +}; -- Gitee From 435c6125cb64b6d5b84b989fdace6f5290e811a4 Mon Sep 17 00:00:00 2001 From: arturo182 Date: Tue, 9 Nov 2021 16:21:56 +0100 Subject: [PATCH 051/155] config: Set TCA8418 to module This chip is a popular way to add a matrix keyboard using I2C. --- arch/arm/configs/bcm2709_defconfig | 1 + arch/arm/configs/bcm2711_defconfig | 1 + arch/arm/configs/bcmrpi_defconfig | 1 + arch/arm64/configs/bcm2711_defconfig | 1 + arch/arm64/configs/bcmrpi3_defconfig | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 7b4c28badf91..7097774f1ff1 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -608,6 +608,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index a4543d42fc55..df60d6cbaa0c 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -621,6 +621,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index 5f1bd057138d..866c80bea091 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -602,6 +602,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 88fa0a35d802..96b58b858432 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -616,6 +616,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m # CONFIG_INPUT_MOUSE is not set diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index a137f1c0721a..bd0b6cfb0608 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -596,6 +596,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m # CONFIG_INPUT_MOUSE is not set -- Gitee From 350053a66b20d3a0c2a8b5fcdc48e36dfd26b4bf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 11 Nov 2021 10:24:02 +0000 Subject: [PATCH 052/155] overlays: Additional parameters for gpio-poweroff The gpio-poweroff driver supports active-delay-ms and inactive-delay-ms properties. Add parameters to set these parameters - active_delay_ms and inactive_delay_ms. See: https://forums.raspberrypi.com/viewtopic.php?t=323508 Signed-off-by: Phil Elwell --- arch/arm/boot/dts/overlays/README | 7 +++++++ arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 9ad2ed3b3b7e..8e4939377c40 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -1155,6 +1155,11 @@ Info: Drives a GPIO high or low on poweroff (including halt). Using this or reboot). This also disables the ability to trigger a boot by driving GPIO3 low. + The GPIO starts in an inactive state. At poweroff time it is driven + active for 100ms, then inactive for 100ms, then active again. It is + safe to remove the power at any point after the initial activation of + the GPIO. + Users of this overlay are required to provide an external mechanism to switch off the power supply when signalled - failure to do so results in a kernel BUG, increased power consumption and undefined behaviour. @@ -1170,6 +1175,8 @@ Params: gpiopin GPIO for signalling (default 26) input Set if the gpio pin should be configured as an input. export Set to export the configured pin to sysfs + active_delay_ms Initial GPIO active period (default 100) + inactive_delay_ms Subsequent GPIO inactive period (default 100) timeout_ms Specify (in ms) how long the kernel waits for power-down before issuing a WARN (default 3000). diff --git a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts index 416aa2bc797a..8153f83f0427 100644 --- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts +++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts @@ -33,5 +33,7 @@ input = <&power_ctrl>,"input?"; export = <&power_ctrl>,"export?"; timeout_ms = <&power_ctrl>,"timeout-ms:0"; + active_delay_ms = <&power_ctrl>,"active-delay-ms:0"; + inactive_delay_ms = <&power_ctrl>,"inactive-delay-ms:0"; }; }; -- Gitee From 576438c88b88e2bc3de6fb5086dca6d432175188 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 11 Nov 2021 13:33:25 +0000 Subject: [PATCH 053/155] overlays: vc4-kms-v3d: Change composite handling On a Pi 4, enabling composite video disables the HDMI output. As a consequence, the composite output is disabled by default. Change the vc4-kms-v3d overlay used on older Pis to also disable composite by default, replacing the "nocomposite" parameter with a "composite" parameter. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/overlays/README | 4 ++-- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 8e4939377c40..bedb501b3ce5 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3620,8 +3620,8 @@ Params: cma-512 CMA is 512MB (needs 1GB) cma-default Use upstream's default value audio Enable or disable audio over HDMI (default "on") noaudio Disable all HDMI audio (default "off") - nocomposite Disable the composite video output (default - "off") + composite Enable the composite output (default "off") + N.B. Disables all other outputs on a Pi 4. Name: vc4-kms-v3d-pi4 diff --git a/arch/arm/boot/dts/overlays/upstream-overlay.dts b/arch/arm/boot/dts/overlays/upstream-overlay.dts index 7c4071a7cb27..2852bea52309 100644 --- a/arch/arm/boot/dts/overlays/upstream-overlay.dts +++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts @@ -1,4 +1,4 @@ -// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg +// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default,composite dwc2-overlay.dts,dr_mode=otg /dts-v1/; /plugin/; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts index 62e1d77a8182..351fc160e803 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts @@ -89,7 +89,7 @@ fragment@11 { target = <&vec>; - __overlay__ { + __dormant__ { status = "okay"; }; }; @@ -118,6 +118,6 @@ __overrides__ { audio = <0>,"!13"; noaudio = <0>,"=13"; - nocomposite = <0>, "!11"; + composite = <0>, "=11"; }; }; -- Gitee From 0b0cc38cc56e80805b64305c4ee46732f8b83237 Mon Sep 17 00:00:00 2001 From: VMsunghwan Date: Tue, 16 Nov 2021 03:24:36 +0900 Subject: [PATCH 054/155] configs: Add TCA6416 driver module Add a matrix keyboard on I2C See: https://github.com/raspberrypi/linux/pull/4700 --- arch/arm/configs/bcm2709_defconfig | 1 + arch/arm/configs/bcm2711_defconfig | 1 + arch/arm/configs/bcmrpi_defconfig | 1 + arch/arm64/configs/bcm2711_defconfig | 1 + arch/arm64/configs/bcmrpi3_defconfig | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 7097774f1ff1..6ec7f27aaa1d 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -608,6 +608,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index df60d6cbaa0c..9dd5ed5ffae0 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -621,6 +621,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index 866c80bea091..b06d59de9537 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -602,6 +602,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 96b58b858432..2d4b746c72a0 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -616,6 +616,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index bd0b6cfb0608..e66a37e8dd48 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -596,6 +596,7 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y # CONFIG_KEYBOARD_ATKBD is not set CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_TCA6416=m CONFIG_KEYBOARD_TCA8418=m CONFIG_KEYBOARD_MATRIX=m CONFIG_KEYBOARD_CAP11XX=m -- Gitee From 0d8277ed02aff065c9f42015deb3b21d3188ab30 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 8 Nov 2021 13:55:15 +0000 Subject: [PATCH 055/155] drm: Fix double free from checking if gamma lut has been updated The code falls through to "fail" under all conditions, so there is no need for the drm_property_blob_put if the gamma lut hasn't been changed. Fixes: 9cca26674a2b "drm: Check whether the gamma lut has changed before updating" Signed-off-by: Dave Stevenson --- drivers/gpu/drm/drm_color_mgmt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index ec4a9a00a298..78933e2a5f44 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -316,8 +316,7 @@ static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc, if (!crtc_state->gamma_lut || !crtc_state->gamma_lut->data || memcmp(crtc_state->gamma_lut->data, blob_data, blob->length)) replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); - else - drm_property_blob_put(blob); + crtc_state->color_mgmt_changed |= replaced; ret = drm_atomic_commit(state); -- Gitee From ffab4b0e8c9838dca4a38a48f154a460383c4ba6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 8 Nov 2021 17:32:45 +0000 Subject: [PATCH 056/155] drm/vc4: Enable gamma block only when required. With HVS5 the gamma block is now only reprogrammed with a disable/enable. Loading the table from vc4_hvs_init_channel (called from vc4_hvs_atomic_enable) appears to be at an invalid point in time and so isn't applied. Switch to enabling and disabling the gamma table instead. This isn't safe if the pipeline is running, but it isn't now. For HVS4 it is safe to enable and disable dynamically, so adopt that approach there too. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hvs.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 6372c48097d5..1302260d7d87 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -480,8 +480,12 @@ static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc, dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE; + if (crtc->state->gamma_lut) + /* Enable gamma on if required */ + dispbkgndx |= SCALER_DISPBKGND_GAMMA; + HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx | - SCALER_DISPBKGND_AUTOHS | SCALER_DISPBKGND_GAMMA | + SCALER_DISPBKGND_AUTOHS | (interlace ? SCALER_DISPBKGND_INTERLACE : 0)); /* Reload the LUT, since the SRAMs would have been disabled if @@ -718,17 +722,25 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)); if (crtc->state->gamma_lut) { - if (!vc4->hvs->hvs5) + if (!vc4->hvs->hvs5) { vc4_hvs_update_gamma_lut(crtc); - else + dispbkgndx |= SCALER_DISPBKGND_GAMMA; + } else { vc5_hvs_update_gamma_lut(crtc); - dispbkgndx |= SCALER_DISPBKGND_GAMMA; + } } else { /* Unsetting DISPBKGND_GAMMA skips the gamma lut step * in hardware, which is the same as a linear lut that * DRM expects us to use in absence of a user lut. + * + * Do NOT change state dynamically for hvs5 as it + * inserts a delay in the pipeline that will cause + * stalls if enabled/disabled whilst running. The other + * should already be disabling/enabling the pipeline + * when gamma changes. */ - dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; + if (!vc4->hvs->hvs5) + dispbkgndx &= ~SCALER_DISPBKGND_GAMMA; } HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx); } -- Gitee From dcdb90c3930a0f0a3d4f2bf9b09cf5caaddee01d Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 8 Nov 2021 18:25:49 +0000 Subject: [PATCH 057/155] drm/vc4: Only add gamma properties once. Two calls were made to drm_crtc_enable_color_mgmt to add gamma and CTM, however they were both set to add the gamma properties, so they ended up added twice. Fixes: 766cc6b1f7fc "drm/vc4: Add CTM support" Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 9a18e695f65e..b6b41b3c664f 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1223,7 +1223,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, /* We support CTM, but only for one CRTC at a time. It's therefore * implemented as private driver state in vc4_kms, not here. */ - drm_crtc_enable_color_mgmt(crtc, 0, true, crtc->gamma_size); + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); /* Initialize the VC4 gamma LUTs */ for (i = 0; i < crtc->gamma_size; i++) { -- Gitee From 61a08d7fa22d388ac47e46d91194851083c40caa Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 10 Nov 2021 15:55:32 +0000 Subject: [PATCH 058/155] dtoverlays: Remove i2c0mux and i20if status from edt-ft5406.dtsi edt-ft5406.dtsi is included from vc4-kms-dsi-7inch which was also setting i2c0mux and i2c0if status fields. This meant that dtoverlay wouldn't apply the overlay due to multiple fragments changing the same parameter. Move the enable from edt-ft5406.dtsi to edt-ft5406-overlay.dts for when it should be needed as an independent overlay. Signed-off-by: Dave Stevenson --- .../arm/boot/dts/overlays/edt-ft5406-overlay.dts | 16 ++++++++++++++++ arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 8 -------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts index f82b4d0e5047..1210e4b8e6dc 100644 --- a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts +++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts @@ -8,3 +8,19 @@ /plugin/; #include "edt-ft5406.dtsi" + +/ { + fragment@0 { + target = <&i2c0if>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@1 { + target = <&i2c0mux>; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi index 0473ff17f19f..6f9b4d02460b 100644 --- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi @@ -27,7 +27,6 @@ __overlay__ { #address-cells = <1>; #size-cells = <0>; - status = "okay"; ft5406: ts@38 { compatible = "edt,edt-ft5406"; reg = <0x38>; @@ -38,13 +37,6 @@ }; }; - fragment@13 { - target = <&i2c0if>; - __overlay__ { - status = "okay"; - }; - }; - __overrides__ { sizex = <&ft5406>,"touchscreen-size-x:0"; sizey = <&ft5406>,"touchscreen-size-y:0"; -- Gitee From 14d8ac083fd95b5931bc7e1fa7aadc71c2999c71 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 10 Nov 2021 16:36:12 +0000 Subject: [PATCH 059/155] drm/vc4: Validate the size of the gamma_lut Add a check to vc4_hvs_gamma_check to ensure a new non-empty gamma LUT is of the correct length before accepting it. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hvs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 1302260d7d87..a873d9d8fd58 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -538,6 +538,16 @@ static int vc4_hvs_gamma_check(struct drm_crtc *crtc, if (!crtc_state->color_mgmt_changed) return 0; + if (crtc_state->gamma_lut) { + unsigned int len = drm_color_lut_size(crtc_state->gamma_lut); + + if (len != crtc->gamma_size) { + DRM_DEBUG_KMS("Invalid LUT size; got %u, expected %u\n", + len, crtc->gamma_size); + return -EINVAL; + } + } + connector = vc4_get_crtc_connector(crtc, crtc_state); if (!connector) return -EINVAL; -- Gitee From 569c27949c30eb5203487fe5508f409b52335359 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 16 Nov 2021 10:34:34 +0000 Subject: [PATCH 060/155] drm/vc4: Don't try disabling SCDC on Pi0-3. The code that set the scdc_enabled flag to ensure it was disabled at boot time also ran on Pi0-3 where there is no SCDC support. This lead to a warning in vc4_hdmi_encoder_post_crtc_disable due to vc4_hdmi_disable_scrambling being called and trying to read (and write) register HDMI_SCRAMBLER_CTL which doesn't exist on those platforms. Only set the flag should the interface be configured to support more than HDMI 1.4. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 245fa882598a..d121aca14439 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2608,7 +2608,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) * vc4_hdmi_disable_scrambling() will thus run at boot, make * sure it's disabled, and avoid any inconsistency. */ - vc4_hdmi->scdc_enabled = true; + if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK) + vc4_hdmi->scdc_enabled = true; ret = variant->init_resources(vc4_hdmi); if (ret) -- Gitee From 2336d81ed62cd69a201841e1648f53e49ddc7fea Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 16 Nov 2021 11:25:26 +0000 Subject: [PATCH 061/155] dtoverlays: Remove incorrect disable-touch fragment in vc4-kms-dsi-7inch It referenced fragment@13 which used to be part of edt-ft5406.dtsi, but has now been removed. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts index ecd3bef3d65a..5e1700d0367a 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts @@ -113,6 +113,6 @@ }; __overrides__ { - disable_touch = <0>, "-10-11-12-13"; + disable_touch = <0>, "-10-11-12"; }; }; -- Gitee From 210aefa7efaef03f53b7a544b5e3be09e7da46f6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Nov 2021 12:07:29 +0000 Subject: [PATCH 062/155] Revert "overlays: vc4-kms-v3d: Change composite handling" This reverts commit 063a326cbaff498c7cd001648b400f12c0ec4237. Reverting temporarily because not enabling the composite output has been seen to break HDMI on older Pis. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/overlays/README | 4 ++-- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index bedb501b3ce5..8e4939377c40 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3620,8 +3620,8 @@ Params: cma-512 CMA is 512MB (needs 1GB) cma-default Use upstream's default value audio Enable or disable audio over HDMI (default "on") noaudio Disable all HDMI audio (default "off") - composite Enable the composite output (default "off") - N.B. Disables all other outputs on a Pi 4. + nocomposite Disable the composite video output (default + "off") Name: vc4-kms-v3d-pi4 diff --git a/arch/arm/boot/dts/overlays/upstream-overlay.dts b/arch/arm/boot/dts/overlays/upstream-overlay.dts index 2852bea52309..7c4071a7cb27 100644 --- a/arch/arm/boot/dts/overlays/upstream-overlay.dts +++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts @@ -1,4 +1,4 @@ -// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default,composite dwc2-overlay.dts,dr_mode=otg +// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg /dts-v1/; /plugin/; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts index 351fc160e803..62e1d77a8182 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts @@ -89,7 +89,7 @@ fragment@11 { target = <&vec>; - __dormant__ { + __overlay__ { status = "okay"; }; }; @@ -118,6 +118,6 @@ __overrides__ { audio = <0>,"!13"; noaudio = <0>,"=13"; - composite = <0>, "=11"; + nocomposite = <0>, "!11"; }; }; -- Gitee From ea7d92ec5e2426de0ef63569aae7890439e7b4fd Mon Sep 17 00:00:00 2001 From: Sean McAvoy Date: Fri, 19 Nov 2021 02:36:24 -0500 Subject: [PATCH 063/155] enable several virtual devices for hosting virtual machines --- arch/arm64/configs/bcm2711_defconfig | 3 +++ arch/arm64/configs/bcmrpi3_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 2d4b746c72a0..592783a9cf65 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -396,6 +396,7 @@ CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m CONFIG_BATMAN_ADV=m CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m CONFIG_CGROUP_NET_PRIO=y CONFIG_NET_PKTGEN=m CONFIG_HAMRADIO=y @@ -505,6 +506,7 @@ CONFIG_NETCONSOLE=m CONFIG_TUN=m CONFIG_VETH=m CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m CONFIG_BCMGENET=y CONFIG_ENC28J60=m CONFIG_QCA7000_SPI=m @@ -1329,6 +1331,7 @@ CONFIG_HD44780=m CONFIG_UIO=m CONFIG_UIO_PDRV_GENIRQ=m CONFIG_VHOST_NET=m +CONFIG_VHOST_VSOCK=m CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y CONFIG_STAGING=y CONFIG_PRISM2_USB=m diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index e66a37e8dd48..8c33a255865a 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -392,6 +392,7 @@ CONFIG_NET_ACT_SKBEDIT=m CONFIG_NET_ACT_CSUM=m CONFIG_BATMAN_ADV=m CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m CONFIG_CGROUP_NET_PRIO=y CONFIG_NET_PKTGEN=m CONFIG_HAMRADIO=y @@ -491,6 +492,7 @@ CONFIG_NETCONSOLE=m CONFIG_TUN=m CONFIG_VETH=m CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m CONFIG_ENC28J60=m CONFIG_QCA7000_SPI=m CONFIG_QCA7000_UART=m @@ -1189,6 +1191,7 @@ CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMABUF_HEAPS_CMA=y CONFIG_UIO=m CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_VHOST_VSOCK=m CONFIG_STAGING=y CONFIG_PRISM2_USB=m CONFIG_R8712U=m -- Gitee From ff943d283798f289d34d3d96642dc00661fae9dd Mon Sep 17 00:00:00 2001 From: Michael Heimpold Date: Thu, 4 Nov 2021 23:09:07 +0100 Subject: [PATCH 064/155] configs: add LEDS_PWM=y Enable support for PWM driven LEDs. Signed-off-by: Michael Heimpold --- arch/arm/configs/bcm2709_defconfig | 1 + arch/arm/configs/bcm2711_defconfig | 1 + arch/arm/configs/bcmrpi_defconfig | 1 + arch/arm64/configs/bcm2711_defconfig | 1 + arch/arm64/configs/bcmrpi3_defconfig | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 6ec7f27aaa1d..c5a908955bc1 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -1225,6 +1225,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_PWM=y CONFIG_LEDS_IS31FL32XX=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index 9dd5ed5ffae0..6ef776884744 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -1263,6 +1263,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_PWM=y CONFIG_LEDS_IS31FL32XX=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index b06d59de9537..434f4aedd246 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1236,6 +1236,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_PWM=y CONFIG_LEDS_IS31FL32XX=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 592783a9cf65..c3bfafea4815 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -1266,6 +1266,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_PWM=y CONFIG_LEDS_IS31FL32XX=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index 8c33a255865a..a86ef9c5ee4d 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -1129,6 +1129,7 @@ CONFIG_LEDS_PCA9532=m CONFIG_LEDS_GPIO=y CONFIG_LEDS_PCA955X=m CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_PWM=y CONFIG_LEDS_IS31FL32XX=m CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_ONESHOT=y -- Gitee From 61fcfb82affa6f5a8417adcc87b93b8bade98d55 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 22 Nov 2021 10:28:55 +0000 Subject: [PATCH 065/155] configs: Add USB gadget support (for Zero 2 W) Bring the Pi 3 kernel in line with the Pi Zero and Pi 4 by enabling USB gadget support, which is useful on Zero 2 W. See: https://github.com/raspberrypi/firmware/issues/1654 Signed-off-by: Phil Elwell --- arch/arm/configs/bcm2709_defconfig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index c5a908955bc1..90810323667d 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -1199,6 +1199,24 @@ CONFIG_USB_CXACRU=m CONFIG_USB_UEAGLEATM=m CONFIG_USB_XUSBATM=m CONFIG_USB_GADGET=m +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y CONFIG_USB_ZERO=m CONFIG_USB_AUDIO=m CONFIG_USB_ETH=m -- Gitee From 1bc8af387132ae7879ffd23a12bbfd6541d2b70e Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Tue, 16 Nov 2021 12:38:44 +0000 Subject: [PATCH 066/155] drivers: bcm2835_isp: Allow multiple users for the ISP driver. Add a second (identical) set of device nodes to allow concurrent use of the ISP hardware by another user. This change effectively creates a second state structure (struct bcm2835_isp_dev) to maintain independent state for the second user. Node and media entity names are appened with the instance index appropriately. Further users can be added by changing the BCM2835_ISP_NUM_INSTANCES define. Signed-off-by: Naushir Patuck --- .../bcm2835-isp/bcm2835-v4l2-isp.c | 76 +++++++++++++++---- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c index df57c2f74a03..5a0245b70b11 100644 --- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c @@ -26,13 +26,19 @@ #include "bcm2835-isp-ctrls.h" #include "bcm2835-isp-fmts.h" +/* + * We want to instantiate 2 independent instances allowing 2 simultaneous users + * of the ISP hardware. + */ +#define BCM2835_ISP_NUM_INSTANCES 2 + static unsigned int debug; module_param(debug, uint, 0644); MODULE_PARM_DESC(debug, "activates debug info"); -static unsigned int video_nr = 13; -module_param(video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "base video device number"); +static unsigned int video_nr[BCM2835_ISP_NUM_INSTANCES] = { 13, 20 }; +module_param_array(video_nr, uint, NULL, 0644); +MODULE_PARM_DESC(video_nr, "base video device numbers"); #define BCM2835_ISP_NAME "bcm2835-isp" #define BCM2835_ISP_ENTITY_NAME_LEN 32 @@ -1279,6 +1285,7 @@ static int bcm2835_isp_get_supported_fmts(struct bcm2835_isp_node *node) * or output nodes. */ static int register_node(struct bcm2835_isp_dev *dev, + unsigned int instance, struct bcm2835_isp_node *node, int index) { @@ -1439,7 +1446,7 @@ static int register_node(struct bcm2835_isp_dev *dev, snprintf(vfd->name, sizeof(node->vfd.name), "%s-%s%d", BCM2835_ISP_NAME, node->name, node->id); - ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr + index); + ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr[instance]); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video %s[%d] device node\n", @@ -1660,9 +1667,8 @@ done: return ret; } -static int bcm2835_isp_remove(struct platform_device *pdev) +static void bcm2835_isp_remove_instance(struct bcm2835_isp_dev *dev) { - struct bcm2835_isp_dev *dev = platform_get_drvdata(pdev); unsigned int i; media_controller_unregister(dev); @@ -1677,11 +1683,11 @@ static int bcm2835_isp_remove(struct platform_device *pdev) dev->component); vchiq_mmal_finalise(dev->mmal_instance); - - return 0; } -static int bcm2835_isp_probe(struct platform_device *pdev) +static int bcm2835_isp_probe_instance(struct platform_device *pdev, + struct bcm2835_isp_dev **dev_int, + unsigned int instance) { struct bcm2835_isp_dev *dev; unsigned int i; @@ -1691,6 +1697,7 @@ static int bcm2835_isp_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; + *dev_int = dev; dev->dev = &pdev->dev; ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); @@ -1708,7 +1715,7 @@ static int bcm2835_isp_probe(struct platform_device *pdev) if (ret) { v4l2_err(&dev->v4l2_dev, "%s: failed to create ril.isp component\n", __func__); - goto error; + return ret; } if (dev->component->inputs < BCM2835_ISP_NUM_OUTPUTS || @@ -1720,7 +1727,7 @@ static int bcm2835_isp_probe(struct platform_device *pdev) BCM2835_ISP_NUM_OUTPUTS, dev->component->outputs, BCM2835_ISP_NUM_CAPTURES + BCM2835_ISP_NUM_METADATA); - goto error; + return -EINVAL; } atomic_set(&dev->num_streaming, 0); @@ -1728,17 +1735,54 @@ static int bcm2835_isp_probe(struct platform_device *pdev) for (i = 0; i < BCM2835_ISP_NUM_NODES; i++) { struct bcm2835_isp_node *node = &dev->node[i]; - ret = register_node(dev, node, i); + ret = register_node(dev, instance, node, i); if (ret) - goto error; + return ret; } ret = media_controller_register(dev); if (ret) - goto error; + return ret; + + return 0; +} + +static int bcm2835_isp_remove(struct platform_device *pdev) +{ + struct bcm2835_isp_dev **bcm2835_isp_instances; + unsigned int i; + + bcm2835_isp_instances = platform_get_drvdata(pdev); + for (i = 0; i < BCM2835_ISP_NUM_INSTANCES; i++) { + if (bcm2835_isp_instances[i]) + bcm2835_isp_remove_instance(bcm2835_isp_instances[i]); + } + + return 0; +} + +static int bcm2835_isp_probe(struct platform_device *pdev) +{ + struct bcm2835_isp_dev **bcm2835_isp_instances; + unsigned int i; + int ret; + + bcm2835_isp_instances = devm_kzalloc(&pdev->dev, + sizeof(bcm2835_isp_instances) * + BCM2835_ISP_NUM_INSTANCES, + GFP_KERNEL); + if (!bcm2835_isp_instances) + return -ENOMEM; + + for (i = 0; i < BCM2835_ISP_NUM_INSTANCES; i++) { + ret = bcm2835_isp_probe_instance(pdev, + &bcm2835_isp_instances[i], i); + if (ret) + goto error; + } - platform_set_drvdata(pdev, dev); - v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", BCM2835_ISP_NAME); + platform_set_drvdata(pdev, bcm2835_isp_instances); + dev_info(&pdev->dev, "Loaded V4L2 %s\n", BCM2835_ISP_NAME); return 0; error: -- Gitee From 6ae8a6ed103fe7aa7033c51dc0801689a8d68a91 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Mon, 22 Nov 2021 13:10:39 +0000 Subject: [PATCH 067/155] media: i2c: ov5647: Support HFLIP and VFLIP Add these missing V4L2 controls. Tested binned and full resolution modes in all four orientations using Raspberry Pi running libcamera. Signed-off-by: David Plowman --- drivers/media/i2c/ov5647.c | 97 +++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 03c92e419806..b92c07477639 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -64,6 +64,8 @@ #define OV5647_REG_GAIN_LO 0x350B #define OV5647_REG_VTS_HI 0x380e #define OV5647_REG_VTS_LO 0x380f +#define OV5647_REG_VFLIP 0x3820 +#define OV5647_REG_HFLIP 0x3821 #define OV5647_REG_FRAME_OFF_NUMBER 0x4202 #define OV5647_REG_MIPI_CTRL00 0x4800 #define OV5647_REG_MIPI_CTRL14 0x4814 @@ -124,6 +126,8 @@ struct ov5647 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; bool write_mode_regs; }; @@ -152,7 +156,7 @@ static struct regval_list ov5647_640x480_8bit[] = { {0x3036, 0x46}, {0x303c, 0x11}, {0x3106, 0xf5}, - {0x3821, 0x07}, + {0x3821, 0x01}, {0x3820, 0x41}, {0x3827, 0xec}, {0x370c, 0x0f}, @@ -240,7 +244,7 @@ static struct regval_list ov5647_2592x1944_10bit[] = { {0x3036, 0x69}, {0x303c, 0x11}, {0x3106, 0xf5}, - {0x3821, 0x06}, + {0x3821, 0x00}, {0x3820, 0x00}, {0x3827, 0xec}, {0x370c, 0x03}, @@ -329,7 +333,7 @@ static struct regval_list ov5647_1080p30_10bit[] = { {0x3036, 0x62}, {0x303c, 0x11}, {0x3106, 0xf5}, - {0x3821, 0x06}, + {0x3821, 0x00}, {0x3820, 0x00}, {0x3827, 0xec}, {0x370c, 0x03}, @@ -493,7 +497,7 @@ static struct regval_list ov5647_2x2binned_10bit[] = { {0x4800, 0x24}, {0x3503, 0x03}, {0x3820, 0x41}, - {0x3821, 0x07}, + {0x3821, 0x01}, {0x350A, 0x00}, {0x350B, 0x10}, {0x3500, 0x00}, @@ -509,7 +513,7 @@ static struct regval_list ov5647_640x480_10bit[] = { {0x3035, 0x11}, {0x3036, 0x46}, {0x303c, 0x11}, - {0x3821, 0x07}, + {0x3821, 0x01}, {0x3820, 0x41}, {0x370c, 0x03}, {0x3612, 0x59}, @@ -1116,18 +1120,45 @@ static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { .s_stream = ov5647_s_stream, }; +/* This function returns the mbus code for the current settings of the + HFLIP and VFLIP controls. */ + +static u32 ov5647_get_mbus_code(struct v4l2_subdev *sd, int mode_8bit) +{ + struct ov5647 *state = to_state(sd); + /* The control values are only 0 or 1. */ + int index = state->hflip->val | (state->vflip->val << 1); + + static const u32 codes[2][4] = { + { + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10 + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8 + } + }; + + return codes[mode_8bit][index]; +} + static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit)) - code->code = MEDIA_BUS_FMT_SBGGR8_1X8; + code->code = ov5647_get_mbus_code(sd, 1); else if (code->index == 0 && ARRAY_SIZE(supported_modes_8bit) == 0 && ARRAY_SIZE(supported_modes_10bit)) - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + code->code = ov5647_get_mbus_code(sd, 0); else if (code->index == 1 && ARRAY_SIZE(supported_modes_8bit) && ARRAY_SIZE(supported_modes_10bit)) - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + code->code = ov5647_get_mbus_code(sd, 0); else return -EINVAL; @@ -1140,11 +1171,11 @@ static int ov5647_enum_frame_size(struct v4l2_subdev *sd, { struct ov5647_mode *mode = NULL; - if (fse->code == MEDIA_BUS_FMT_SBGGR8_1X8) { + if (fse->code == ov5647_get_mbus_code(sd, 1)) { if (fse->index >= ARRAY_SIZE(supported_modes_8bit)) return -EINVAL; mode = &supported_modes_8bit[fse->index]; - } else if (fse->code == MEDIA_BUS_FMT_SBGGR10_1X10) { + } else if (fse->code == ov5647_get_mbus_code(sd, 0)) { if (fse->index >= ARRAY_SIZE(supported_modes_10bit)) return -EINVAL; mode = &supported_modes_10bit[fse->index]; @@ -1188,9 +1219,9 @@ static int ov5647_set_fmt(struct v4l2_subdev *sd, format.width, format.height, format->format.width, format->format.height); - if (format->format.code == MEDIA_BUS_FMT_SBGGR8_1X8 && mode_8bit) + if (format->format.code == ov5647_get_mbus_code(sd, 1) && mode_8bit) mode = mode_8bit; - else if (format->format.code == MEDIA_BUS_FMT_SBGGR10_1X10 && + else if (format->format.code == ov5647_get_mbus_code(sd, 0) && mode_10bit) mode = mode_10bit; else if (mode_10bit) @@ -1204,6 +1235,8 @@ static int ov5647_set_fmt(struct v4l2_subdev *sd, } *fmt = mode->format; + /* The mbus code we pass back must reflect the current H/VFLIP settings. */ + fmt->code = ov5647_get_mbus_code(sd, mode == mode_8bit); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { framefmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); *framefmt = format->format; @@ -1265,6 +1298,8 @@ static int ov5647_get_fmt(struct v4l2_subdev *sd, *fmt = *v4l2_subdev_get_try_format(sd, cfg, format->pad); else *fmt = state->mode->format; + /* The mbus code we pass back must reflect the current H/VFLIP settings. */ + fmt->code = ov5647_get_mbus_code(sd, fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8); mutex_unlock(&state->lock); @@ -1424,6 +1459,25 @@ static int ov5647_s_exposure(struct v4l2_subdev *sd, u32 val) return ret; } +static int ov5647_s_flip( struct v4l2_subdev *sd, u16 reg, u32 ctrl_val) +{ + int ret; + u8 reg_val; + + /* Set or clear bit 1 and leave everything else alone. */ + ret = ov5647_read(sd, reg, ®_val); + if (ret == 0) { + if (ctrl_val) + reg_val |= 2; + else + reg_val &= ~2; + + ret = ov5647_write(sd, reg, reg_val); + } + + return ret; +} + static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov5647 *state = container_of(ctrl->handler, @@ -1481,6 +1535,13 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) ret = ov5647_write16(sd, OV5647_REG_VTS_HI, state->mode->format.height + ctrl->val); break; + case V4L2_CID_HFLIP: + /* There's an in-built hflip in the sensor, so account for that here. */ + ov5647_s_flip(sd, OV5647_REG_HFLIP, !ctrl->val); + break; + case V4L2_CID_VFLIP: + ov5647_s_flip(sd, OV5647_REG_VFLIP, ctrl->val); + break; default: dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", @@ -1539,7 +1600,7 @@ static int ov5647_probe(struct i2c_client *client) mutex_init(&sensor->lock); /* Initialise controls. */ - v4l2_ctrl_handler_init(&sensor->ctrls, 9); + v4l2_ctrl_handler_init(&sensor->ctrls, 11); v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, V4L2_CID_AUTOGAIN, 0, /* min */ @@ -1597,6 +1658,16 @@ static int ov5647_probe(struct i2c_client *client) sensor->mode->vts_def - sensor->mode->format.height); + sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + if (sensor->hflip) + sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (sensor->vflip) + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + if (sensor->ctrls.error) { ret = sensor->ctrls.error; dev_err(&client->dev, "%s control init failed (%d)\n", -- Gitee From 2069b91b0e411d51dbbca4fa52263a047f001340 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Thu, 25 Nov 2021 08:59:58 +0000 Subject: [PATCH 068/155] drivers: bcm2835_isp: Fix div by 0 bug. Fix a possible division by 0 bug when setting up the mmal port for the stats port. Signed-off-by: Naushir Patuck --- drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h index f6d6c88d13ba..a545dbf2b5dd 100644 --- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-isp-fmts.h @@ -544,6 +544,7 @@ static const struct bcm2835_isp_fmt supported_formats[] = { .step_size = 2, }, { .fourcc = V4L2_META_FMT_BCM2835_ISP_STATS, + .depth = 8, .mmal_fmt = MMAL_ENCODING_BRCM_STATS, /* The rest are not valid fields for stats. */ } -- Gitee From 8ab9732405f35788d0e6a9f5065fa6becaf15907 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Wed, 17 Nov 2021 04:57:56 +0300 Subject: [PATCH 069/155] Pass V4L2_CID_MPEG_VIDEO_H264_MIN_QP/MAX_QP to bcm2835-v4l2-codec Following raspberrypi/linux#4704. This is necessary to set up quantization for variable bitrate to avoid video flickering. --- .../bcm2835-codec/bcm2835-v4l2-codec.c | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 351d693873ed..357c05916efb 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -2187,6 +2187,28 @@ static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl) ret = bcm2835_codec_set_level_profile(ctx, ctrl); break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + if (!ctx->component) + break; + + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, + &ctx->component->output[0], + MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, + &ctrl->val, + sizeof(ctrl->val)); + break; + + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + if (!ctx->component) + break; + + ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, + &ctx->component->output[0], + MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, + &ctrl->val, + sizeof(ctrl->val)); + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: { u32 mmal_bool = 1; @@ -3111,7 +3133,7 @@ static int bcm2835_codec_open(struct file *file) case ENCODE: { /* Encode controls */ - v4l2_ctrl_handler_init(hdl, 9); + v4l2_ctrl_handler_init(hdl, 11); v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, @@ -3159,6 +3181,14 @@ static int bcm2835_codec_open(struct file *file) BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + 0, 51, + 1, 20); + v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + 0, 51, + 1, 51); v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0); -- Gitee From c9335e0e1e4c901f2e9ecc2baa32dd3c56ee012b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 25 Nov 2021 14:45:33 +0000 Subject: [PATCH 070/155] drm/vc4: Add support for composite syncs to vc4_dpi The hardware can combine H&V syncs onto the output enable line as composite syncs, so add the relevant configuration to do that. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_dpi.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index dde2c6014748..4dd8df6ddcbe 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -131,7 +131,7 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) struct vc4_dpi *dpi = vc4_encoder->dpi; struct drm_connector_list_iter conn_iter; struct drm_connector *connector = NULL, *connector_scan; - u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE; + u32 dpi_c = DPI_ENABLE; int ret; /* Look up the connector attached to DPI so we can get the @@ -192,15 +192,22 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT); } - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - dpi_c |= DPI_HSYNC_INVERT; - else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) - dpi_c |= DPI_HSYNC_DISABLE; + if (mode->flags & DRM_MODE_FLAG_CSYNC) { + if (mode->flags & DRM_MODE_FLAG_NCSYNC) + dpi_c |= DPI_OUTPUT_ENABLE_INVERT; + } else { + dpi_c |= DPI_OUTPUT_ENABLE_MODE; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + dpi_c |= DPI_HSYNC_INVERT; + else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) + dpi_c |= DPI_HSYNC_DISABLE; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - dpi_c |= DPI_VSYNC_INVERT; - else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) - dpi_c |= DPI_VSYNC_DISABLE; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + dpi_c |= DPI_VSYNC_INVERT; + else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) + dpi_c |= DPI_VSYNC_DISABLE; + } DPI_WRITE(DPI_C, dpi_c); -- Gitee From 90dfc9d8338baec74450d13f41295f0a88fc76aa Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 19 Nov 2021 16:16:40 +0000 Subject: [PATCH 071/155] drm/vc4: Ensure vc4_hdmi doesn't use 2711 HPD registers on Pi0-3 The existing logic was flawed in that it could try reading the 2711 specific registers for HPD on a CM1/3 where the HPD GPIO hadn't been defined in DT. Ensure we don't do the 2711 register read on invalid hardware, and then Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hdmi.c | 24 ++++++++++++++++-------- drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d121aca14439..96a731b5cdac 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -208,14 +208,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) vc4_hdmi->hpd_active_low) connected = true; } else { - unsigned long flags; - u32 hotplug; - - spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - hotplug = HDMI_READ(HDMI_HOTPLUG); - spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - - if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED) + if (vc4_hdmi->variant->hp_detect && + vc4_hdmi->variant->hp_detect(vc4_hdmi)) connected = true; } @@ -1388,6 +1382,18 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) return channel_map; } +static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi) +{ + unsigned long flags; + u32 hotplug; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + hotplug = HDMI_READ(HDMI_HOTPLUG); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + return !!(hotplug & VC4_HDMI_HOTPLUG_CONNECTED); +} + /* HDMI audio codec callbacks */ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) @@ -2851,6 +2857,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { .calc_hsm_clock = vc5_hdmi_calc_hsm_clock, .channel_map = vc5_hdmi_channel_map, .supports_hdr = true, + .hp_detect = vc5_hdmi_hp_detect, }; static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { @@ -2880,6 +2887,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { .calc_hsm_clock = vc5_hdmi_calc_hsm_clock, .channel_map = vc5_hdmi_channel_map, .supports_hdr = true, + .hp_detect = vc5_hdmi_hp_detect, }; static const struct of_device_id vc4_hdmi_dt_match[] = { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index ad7d4b275ed8..d49c6f3a98ed 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -105,6 +105,9 @@ struct vc4_hdmi_variant { /* Enables HDR metadata */ bool supports_hdr; + + /* Callback for hardware specific hotplug detect */ + bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi); }; /* HDMI audio information */ -- Gitee From 78f8a1f9a46ee9d1e89cb05fb855a508a8838b42 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Nov 2021 11:06:50 +0000 Subject: [PATCH 072/155] ARM: dts: gpio-ranges property is now required Since [1], added in 5.7, the absence of a gpio-ranges property has prevented GPIOs from being restored to inputs when released. See: https://forums.raspberrypi.com/viewtopic.php?t=324585 [1] commit 2ab73c6d8323 ("gpio: Support GPIO controllers without pin-ranges") Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2711.dtsi | 2 ++ arch/arm/boot/dts/bcm283x.dtsi | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index 7ec51452d384..544633a84433 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -595,6 +595,8 @@ , ; + gpio-ranges = <&gpio 0 0 58>; + gpclk0_gpio49: gpclk0_gpio49 { pin-gpclk { pins = "gpio49"; diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index 06d04cde52b9..62d7ee513549 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -126,6 +126,8 @@ interrupt-controller; #interrupt-cells = <2>; + gpio-ranges = <&gpio 0 0 54>; + /* Defines common pin muxing groups * * While each pin can have its mux selected -- Gitee From c39167be72cb8d8f67c039d272734df57a59a8ac Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 26 Nov 2021 16:41:23 +0000 Subject: [PATCH 073/155] ARM: dts: Update rpi-400 and cm4 dts to match 4-b The Pi 4B dts file has had numerous updates since the Pi 400 and CM4 dts files were written. Apply those updates to the other files to minimise the differences. The change is largely cosmetic, except for the PCI "device-type" to "device_type" rename, and the correction of the labels on the Pi 400 GPIO expander pins. Also set the wifi-2.4ghz-coexistence property on RPi 4 B, which appears to have been missed. Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++ arch/arm/boot/dts/bcm2711-rpi-400.dts | 11 ++++++----- arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 7 ++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 2fdeba0b95d7..44da9fc870be 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -181,12 +181,14 @@ &hdmi0 { clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; clock-names = "hdmi", "bvb", "audio", "cec"; + wifi-2.4ghz-coexistence; status = "okay"; }; &hdmi1 { clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 1>, <&clk_27MHz>; clock-names = "hdmi", "bvb", "audio", "cec"; + wifi-2.4ghz-coexistence; status = "okay"; }; diff --git a/arch/arm/boot/dts/bcm2711-rpi-400.dts b/arch/arm/boot/dts/bcm2711-rpi-400.dts index c25a97465d2b..ec0c75810754 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-400.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-400.dts @@ -93,9 +93,9 @@ "PWR_LED_OFF", "GLOBAL_RESET", "VDD_SD_IO_SEL", - "CAM_GPIO", + "GLOBAL_SHUTDOWN", "SD_PWR_ON", - "SD_OC_N"; + "SHUTDOWN_REQUEST"; status = "okay"; }; @@ -273,15 +273,16 @@ }; &pcie0 { - pci@1,0 { + pci@0,0 { + device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges; reg = <0 0 0 0 0>; - usb@1,0 { - reg = <0x10000 0 0 0 0>; + usb@0,0 { + reg = <0 0 0 0 0>; resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; }; }; diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts index 1dcbb2173f5d..bc256aebab65 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts @@ -286,15 +286,16 @@ }; &pcie0 { - pci@1,0 { + pci@0,0 { + device_type = "pci"; #address-cells = <3>; #size-cells = <2>; ranges; reg = <0 0 0 0 0>; - usb@1,0 { - reg = <0x10000 0 0 0 0>; + usb@0,0 { + reg = <0 0 0 0 0>; resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; }; }; -- Gitee From 1177dff9abc1602c377946427e0b4e1b0c3a943b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 26 Nov 2021 14:37:40 +0000 Subject: [PATCH 074/155] input: edt-ft5x06: Handle unreliable TOUCH_UP events The ft5x06 is unreliable in sending touch up events, so some touch IDs can become stuck in the detected state. Ensure that IDs that are unreported by the controller are released. Signed-off-by: Dave Stevenson --- drivers/input/touchscreen/edt-ft5x06.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index d4060bc89ce9..e33b5f0775de 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -123,6 +123,7 @@ struct edt_ft5x06_ts_data { int offset_y; int report_rate; int max_support_points; + unsigned int known_ids; char name[EDT_NAME_LEN]; @@ -197,6 +198,9 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) int i, type, x, y, id; int offset, tplen, datalen, crclen; int error; + unsigned int active_ids = 0, known_ids = tsdata->known_ids; + long released_ids; + int b = 0; switch (tsdata->version) { case EDT_M06: @@ -268,10 +272,25 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) input_mt_slot(tsdata->input, id); if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, - type != TOUCH_EVENT_UP)) + type != TOUCH_EVENT_UP)) { touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y, true); + active_ids |= BIT(id); + } else { + known_ids &= ~BIT(id); + } + } + + /* One issue with the device is the TOUCH_UP message is not always + * returned. Instead track which ids we know about and report when they + * are no longer updated + */ + released_ids = known_ids & ~active_ids; + for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) { + input_mt_slot(tsdata->input, b); + input_mt_report_slot_inactive(tsdata->input); } + tsdata->known_ids = active_ids; input_mt_report_pointer_emulation(tsdata->input, true); input_sync(tsdata->input); -- Gitee From 6d145dbaa51c1b13dee8c9b99e0b097d2b184857 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 26 Nov 2021 16:56:37 +0000 Subject: [PATCH 075/155] dtoverlays: Use edt-ft5506 for 10 points, instead of edt-ft5x06 Whilst all the datasheets describe FT5x06 as supporting "up to 10 points of absolution X and Y coordinates", the driver implementation for the compatible string "edt,edt-ft5x06" only allows for 5. Switch to the "edt,edt-ft5506" compatible string which allows for 10 points with no other differences. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi index 6f9b4d02460b..2d0ff0e8b24e 100644 --- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi +++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; ft5406: ts@38 { - compatible = "edt,edt-ft5406"; + compatible = "edt,edt-ft5506"; reg = <0x38>; touchscreen-size-x = < 800 >; -- Gitee From 827826385ec9709b7e51ab444e50beebec25237c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 29 Nov 2021 13:11:56 +0000 Subject: [PATCH 076/155] dtoverlays: Drop i2c baudrate for Pi 7inch DSI screen to 50kHz Whilst investigations continue as to why the 7" DSI screen doesn't work on Pi3 with KMS, drop the I2C baudrate to 50kHz as that seems to be a reliable workaround. This will be reverted once the full issue is understood. https://github.com/raspberrypi/linux/issues/4686 Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts index 5e1700d0367a..5b6f82aaa6fb 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts @@ -95,6 +95,7 @@ target = <&i2c0if>; __overlay__ { status = "okay"; + clock-frequency = <50000>; }; }; -- Gitee From d8ff7e562960af42bfbe5f5771d6ac607177f865 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 29 Nov 2021 14:42:05 +0000 Subject: [PATCH 077/155] drm/vc4: Use dev_err_probe when logging error registering HDMI audio Avoid logging a spurious error message with error -517 (-EPROBE_DEFER) whilst trying to load HDMI audio. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 96a731b5cdac..f673c04dad12 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1848,7 +1848,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) snd_soc_card_set_drvdata(card, vc4_hdmi); ret = devm_snd_soc_register_card(dev, card); if (ret) - dev_err(dev, "Could not register sound card: %d\n", ret); + dev_err_probe(dev, ret, "Could not register sound card: %d\n"); return ret; -- Gitee From 958570dc705f9fac3558850ce9d212b2843fd402 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 26 Nov 2021 16:46:22 +0000 Subject: [PATCH 078/155] staging/bcm2835-codec: bytesperline for YUV420/YVU420 needs to be 64 Matching https://github.com/raspberrypi/linux/pull/4419, the ISP block (which is also used on the input of the encoder, and output of the decoder) needs the base address of all planes to be aligned to multiples of 32. This includes the chroma planes of YUV420 and YVU420. If the height is only a multiple of 2 (not 4), then you get an odd number of lines in the second plane, which means the 3rd plane starts at a multiple of bytesperline/2. Set the minimum bytesperline alignment to 64 for those formats so that the plane alignment is always right. Signed-off-by: Dave Stevenson --- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 357c05916efb..641ee202a9b2 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -157,14 +157,14 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* YUV formats */ .fourcc = V4L2_PIX_FMT_YUV420, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = 64, .flags = 0, .mmal_fmt = MMAL_ENCODING_I420, .size_multiplier_x2 = 3, }, { .fourcc = V4L2_PIX_FMT_YVU420, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = 64, .flags = 0, .mmal_fmt = MMAL_ENCODING_YV12, .size_multiplier_x2 = 3, -- Gitee From db6511213613581db9ea6f33a198e222ccfbb78c Mon Sep 17 00:00:00 2001 From: John Cox Date: Mon, 29 Nov 2021 16:39:35 +0000 Subject: [PATCH 079/155] media: rpivid: remove min_buffers_needed from src queue Remove min_buffers_needed=1 from src queue init. Src buffers are bound to media requests therefore this setting is not needed and generates a WARN in kernel 5.16. Signed-off-by: John Cox --- drivers/staging/media/rpivid/rpivid_video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/rpivid/rpivid_video.c b/drivers/staging/media/rpivid/rpivid_video.c index 1efaa99a55f6..93b3d86b41e3 100644 --- a/drivers/staging/media/rpivid/rpivid_video.c +++ b/drivers/staging/media/rpivid/rpivid_video.c @@ -680,7 +680,6 @@ int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->io_modes = VB2_MMAP | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct rpivid_buffer); - src_vq->min_buffers_needed = 1; src_vq->ops = &rpivid_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -- Gitee From 6b30ec1ebe162f63eb7f5d42ec1f3f63f19ee78c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 29 Nov 2021 19:11:29 +0000 Subject: [PATCH 080/155] staging/bcm2835-codec: Allow a different stride alignment per role Deinterlace and decode aren't affected in the same way as encode and ISP by the alignment requirement on 3 plane YUV420. Decode would be affected, but it always aligns the height up to a macroblock, and uses the selection API to reflect that. Add in the facility to set the bytesperline alignment per role. Signed-off-by: Dave Stevenson --- .../bcm2835-codec/bcm2835-v4l2-codec.c | 135 ++++++++++-------- 1 file changed, 74 insertions(+), 61 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 641ee202a9b2..4cd940211b54 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -88,6 +88,7 @@ enum bcm2835_codec_role { ENCODE, ISP, DEINTERLACE, + NUM_ROLES }; static const char * const roles[] = { @@ -145,7 +146,7 @@ static const char * const components[] = { struct bcm2835_codec_fmt { u32 fourcc; int depth; - int bytesperline_align; + u8 bytesperline_align[NUM_ROLES]; u32 flags; u32 mmal_fmt; int size_multiplier_x2; @@ -157,63 +158,63 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* YUV formats */ .fourcc = V4L2_PIX_FMT_YUV420, .depth = 8, - .bytesperline_align = 64, + .bytesperline_align = { 32, 64, 64, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_I420, .size_multiplier_x2 = 3, }, { .fourcc = V4L2_PIX_FMT_YVU420, .depth = 8, - .bytesperline_align = 64, + .bytesperline_align = { 32, 64, 64, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_YV12, .size_multiplier_x2 = 3, }, { .fourcc = V4L2_PIX_FMT_NV12, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_NV12, .size_multiplier_x2 = 3, }, { .fourcc = V4L2_PIX_FMT_NV21, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_NV21, .size_multiplier_x2 = 3, }, { .fourcc = V4L2_PIX_FMT_RGB565, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_RGB16, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_YUYV, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_UYVY, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_YVYU, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_YVYU, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_VYUY, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_VYUY, .size_multiplier_x2 = 2, @@ -221,21 +222,21 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* RGB formats */ .fourcc = V4L2_PIX_FMT_RGB24, .depth = 24, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_RGB24, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_BGR24, .depth = 24, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BGR24, .size_multiplier_x2 = 2, }, { .fourcc = V4L2_PIX_FMT_BGR32, .depth = 32, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BGRA, .size_multiplier_x2 = 2, @@ -244,7 +245,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 8 bit */ .fourcc = V4L2_PIX_FMT_SRGGB8, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, .size_multiplier_x2 = 2, @@ -252,7 +253,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR8, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, .size_multiplier_x2 = 2, @@ -260,7 +261,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, .size_multiplier_x2 = 2, @@ -268,7 +269,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, .size_multiplier_x2 = 2, @@ -277,7 +278,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 10 bit */ .fourcc = V4L2_PIX_FMT_SRGGB10P, .depth = 10, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, .size_multiplier_x2 = 2, @@ -285,7 +286,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR10P, .depth = 10, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, .size_multiplier_x2 = 2, @@ -293,7 +294,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG10P, .depth = 10, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, .size_multiplier_x2 = 2, @@ -301,7 +302,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG10P, .depth = 10, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, .size_multiplier_x2 = 2, @@ -310,7 +311,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 12 bit */ .fourcc = V4L2_PIX_FMT_SRGGB12P, .depth = 12, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, .size_multiplier_x2 = 2, @@ -318,7 +319,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR12P, .depth = 12, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, .size_multiplier_x2 = 2, @@ -326,7 +327,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG12P, .depth = 12, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, .size_multiplier_x2 = 2, @@ -334,7 +335,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG12P, .depth = 12, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, .size_multiplier_x2 = 2, @@ -343,7 +344,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 14 bit */ .fourcc = V4L2_PIX_FMT_SRGGB14P, .depth = 14, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB14P, .size_multiplier_x2 = 2, @@ -351,7 +352,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR14P, .depth = 14, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR14P, .size_multiplier_x2 = 2, @@ -360,7 +361,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG14P, .depth = 14, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG14P, .size_multiplier_x2 = 2, @@ -368,7 +369,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG14P, .depth = 14, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG14P, .size_multiplier_x2 = 2, @@ -377,7 +378,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 16 bit */ .fourcc = V4L2_PIX_FMT_SRGGB16, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, .size_multiplier_x2 = 2, @@ -385,7 +386,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR16, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, .size_multiplier_x2 = 2, @@ -393,7 +394,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG16, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, .size_multiplier_x2 = 2, @@ -401,7 +402,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG16, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, .size_multiplier_x2 = 2, @@ -411,7 +412,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 10 bit */ .fourcc = V4L2_PIX_FMT_SRGGB10, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10, .size_multiplier_x2 = 2, @@ -419,7 +420,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR10, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10, .size_multiplier_x2 = 2, @@ -427,7 +428,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG10, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10, .size_multiplier_x2 = 2, @@ -435,7 +436,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG10, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10, .size_multiplier_x2 = 2, @@ -444,7 +445,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 12 bit */ .fourcc = V4L2_PIX_FMT_SRGGB12, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12, .size_multiplier_x2 = 2, @@ -452,7 +453,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR12, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12, .size_multiplier_x2 = 2, @@ -460,7 +461,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG12, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12, .size_multiplier_x2 = 2, @@ -468,7 +469,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG12, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12, .size_multiplier_x2 = 2, @@ -477,7 +478,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 14 bit */ .fourcc = V4L2_PIX_FMT_SRGGB14, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB14, .size_multiplier_x2 = 2, @@ -485,7 +486,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SBGGR14, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR14, .size_multiplier_x2 = 2, @@ -493,7 +494,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGRBG14, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG14, .size_multiplier_x2 = 2, @@ -501,7 +502,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { }, { .fourcc = V4L2_PIX_FMT_SGBRG14, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG14, .size_multiplier_x2 = 2, @@ -511,7 +512,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 8 bit */ .fourcc = V4L2_PIX_FMT_GREY, .depth = 8, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_GREY, .size_multiplier_x2 = 2, @@ -519,7 +520,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 10 bit */ .fourcc = V4L2_PIX_FMT_Y10P, .depth = 10, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y10P, .size_multiplier_x2 = 2, @@ -527,7 +528,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 12 bit */ .fourcc = V4L2_PIX_FMT_Y12P, .depth = 12, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y12P, .size_multiplier_x2 = 2, @@ -535,7 +536,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 14 bit */ .fourcc = V4L2_PIX_FMT_Y14P, .depth = 14, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y14P, .size_multiplier_x2 = 2, @@ -543,7 +544,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 16 bit */ .fourcc = V4L2_PIX_FMT_Y16, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y16, .size_multiplier_x2 = 2, @@ -551,7 +552,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 10 bit as 16bpp */ .fourcc = V4L2_PIX_FMT_Y10, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y10, .size_multiplier_x2 = 2, @@ -559,7 +560,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 12 bit as 16bpp */ .fourcc = V4L2_PIX_FMT_Y12, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y12, .size_multiplier_x2 = 2, @@ -567,7 +568,7 @@ static const struct bcm2835_codec_fmt supported_formats[] = { /* 14 bit as 16bpp */ .fourcc = V4L2_PIX_FMT_Y14, .depth = 16, - .bytesperline_align = 32, + .bytesperline_align = { 32, 32, 32, 32 }, .flags = 0, .mmal_fmt = MMAL_ENCODING_Y14, .size_multiplier_x2 = 2, @@ -840,9 +841,10 @@ static inline unsigned int get_sizeimage(int bpl, int width, int height, } static inline unsigned int get_bytesperline(int width, - struct bcm2835_codec_fmt *fmt) + struct bcm2835_codec_fmt *fmt, + enum bcm2835_codec_role role) { - return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align); + return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align[role]); } static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, @@ -1040,7 +1042,7 @@ static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx, */ q_data->selection_set = true; q_data->bytesperline = get_bytesperline(format->es.video.width, - q_data->fmt); + q_data->fmt, ctx->dev->role); q_data->height = format->es.video.height; q_data->sizeimage = format->buffer_size_min; @@ -1422,11 +1424,13 @@ static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); } f->fmt.pix_mp.num_planes = 1; - min_bytesperline = get_bytesperline(f->fmt.pix_mp.width, fmt); + min_bytesperline = get_bytesperline(f->fmt.pix_mp.width, fmt, + ctx->dev->role); if (f->fmt.pix_mp.plane_fmt[0].bytesperline < min_bytesperline) f->fmt.pix_mp.plane_fmt[0].bytesperline = min_bytesperline; f->fmt.pix_mp.plane_fmt[0].bytesperline = - ALIGN(f->fmt.pix_mp.plane_fmt[0].bytesperline, fmt->bytesperline_align); + ALIGN(f->fmt.pix_mp.plane_fmt[0].bytesperline, + fmt->bytesperline_align[ctx->dev->role]); sizeimage = get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline, f->fmt.pix_mp.width, f->fmt.pix_mp.height, @@ -1581,7 +1585,8 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, q_data_dst->height = ALIGN(q_data->crop_height, 16); q_data_dst->bytesperline = - get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt); + get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt, + ctx->dev->role); q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, q_data_dst->crop_width, q_data_dst->height, @@ -1810,6 +1815,8 @@ static int vidioc_g_selection(struct file *file, void *priv, } } break; + case NUM_ROLES: + break; } return 0; @@ -1920,6 +1927,8 @@ static int vidioc_s_selection(struct file *file, void *priv, } break; } + case NUM_ROLES: + break; } return 0; @@ -3095,7 +3104,8 @@ static int bcm2835_codec_open(struct file *file) ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; ctx->q_data[V4L2_M2M_SRC].bytesperline = get_bytesperline(DEFAULT_WIDTH, - ctx->q_data[V4L2_M2M_SRC].fmt); + ctx->q_data[V4L2_M2M_SRC].fmt, + dev->role); ctx->q_data[V4L2_M2M_SRC].sizeimage = get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, ctx->q_data[V4L2_M2M_SRC].crop_width, @@ -3108,7 +3118,8 @@ static int bcm2835_codec_open(struct file *file) ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; ctx->q_data[V4L2_M2M_DST].bytesperline = get_bytesperline(DEFAULT_WIDTH, - ctx->q_data[V4L2_M2M_DST].fmt); + ctx->q_data[V4L2_M2M_DST].fmt, + dev->role); ctx->q_data[V4L2_M2M_DST].sizeimage = get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, ctx->q_data[V4L2_M2M_DST].crop_width, @@ -3238,6 +3249,8 @@ static int bcm2835_codec_open(struct file *file) v4l2_ctrl_handler_init(hdl, 0); } break; + case NUM_ROLES: + break; } ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); -- Gitee From e9368135733fb750bab146c4b76d66f12876e272 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Tue, 30 Nov 2021 10:39:41 +0000 Subject: [PATCH 081/155] drivers: bcm2835_unicam: Add logging message when a frame is dropped. If a dummy buffer is still active on a frame start, it indicates that this frame will be dropped. The explicit logging helps users identify performance issues. Signed-off-by: Naushir Patuck --- drivers/media/platform/bcm2835/bcm2835-unicam.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c index d4a005657ca2..3329a7b006f2 100644 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -951,6 +951,9 @@ static irqreturn_t unicam_isr(int irq, void *dev) if (unicam->node[i].cur_frm) unicam->node[i].cur_frm->vb.vb2_buf.timestamp = ts; + else + unicam_dbg(2, unicam, "ISR: [%d] Dropping frame, buffer not available at FS\n", + i); /* * Set the next frame output to go to a dummy frame * if we have not managed to obtain another frame -- Gitee From 3cf5d02201aff6c04113e70178e186618ad5ecca Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 29 Nov 2021 18:31:37 +0000 Subject: [PATCH 082/155] regulator/rpi-panel-attiny: Don't read the LCD power status The I2C to the Atmel is very fussy, and locks up easily on Pi0-3 particularly on reads. The LCD power status is controlled solely by this driver, so rather than reading it back from the Atmel, use the cached status last set. Signed-off-by: Dave Stevenson --- drivers/regulator/rpi-panel-attiny-regulator.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 8090b9a485b5..8b80c0de1022 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -144,24 +144,8 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { struct attiny_lcd *state = rdev_get_drvdata(rdev); - unsigned int data; - int ret, i; - - mutex_lock(&state->lock); - - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTC, &data); - if (!ret) - break; - usleep_range(10000, 12000); - } - - mutex_unlock(&state->lock); - - if (ret < 0) - return ret; - return data & PC_RST_BRIDGE_N; + return state->port_states[REG_PORTC - REG_PORTA] & PC_RST_BRIDGE_N; } static const struct regulator_init_data attiny_regulator_default = { -- Gitee From cf580213e9a813e29aeed26b139d570244808e4b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 25 Nov 2021 14:50:10 +0000 Subject: [PATCH 083/155] regulator/rpi-panel-attiny: Use two transactions for I2C read The I2C to the Atmel is very fussy, and locks up easily on Pi0-3 particularly on reads. If running at 100kHz on Pi3, reading the ID register generally locks up the Atmel, but splitting the register select write and read into two transactions is reliable. Signed-off-by: Dave Stevenson --- .../regulator/rpi-panel-attiny-regulator.c | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 8b80c0de1022..e3decc419814 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -234,6 +234,39 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) mutex_unlock(&state->lock); } +static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) +{ + struct i2c_msg msgs[1]; + u8 addr_buf[1] = { reg }; + u8 data_buf[1] = { 0, }; + int ret; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + usleep_range(5000, 10000); + + /* Read data from register */ + msgs[0].addr = client->addr; + msgs[0].flags = I2C_M_RD; + msgs[0].len = 1; + msgs[0].buf = data_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *buf = data_buf[0]; + return 0; +} + /* * I2C driver interface functions */ @@ -264,7 +297,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c, goto error; } - ret = regmap_read(regmap, REG_ID, &data); + ret = attiny_i2c_read(i2c, REG_ID, &data); if (ret < 0) { dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); goto error; -- Gitee From da044ceb475d2cba40d7d9dc9f13d199aa58f63e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 30 Nov 2021 17:39:17 +0000 Subject: [PATCH 084/155] Revert "dtoverlays: Drop i2c baudrate for Pi 7inch DSI screen to 50kHz" This reverts commit 0c41710df564f76275c2868beaa0c316553e8247. The regulator driver is now hopefully fixed, therefore revert the workaround that dropped the I2C frequency. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts index 5b6f82aaa6fb..5e1700d0367a 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-7inch-overlay.dts @@ -95,7 +95,6 @@ target = <&i2c0if>; __overlay__ { status = "okay"; - clock-frequency = <50000>; }; }; -- Gitee From 89ed91477cbf2c6b91d16391b329ad26b4d557b3 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 30 Nov 2021 17:28:50 +0000 Subject: [PATCH 085/155] input: edt-ft5x06: Only look at the number of points reported Register 0x02 in the FT5x06 is TD_STATUS containing the number of valid touch points being reported. Iterate over that number of points rather than all that are supported on the device. Signed-off-by: Dave Stevenson --- drivers/input/touchscreen/edt-ft5x06.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index e33b5f0775de..9be7a6aba409 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -201,6 +201,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) unsigned int active_ids = 0, known_ids = tsdata->known_ids; long released_ids; int b = 0; + unsigned int num_points; switch (tsdata->version) { case EDT_M06: @@ -248,9 +249,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) goto out; + num_points = tsdata->max_support_points; + } else { + /* Register 2 is TD_STATUS, containing the number of touch + * points. + */ + num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points); } - for (i = 0; i < tsdata->max_support_points; i++) { + for (i = 0; i < num_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; type = buf[0] >> 6; -- Gitee From 6233354aa6d97d1dbe12989fc46ff8f96e5b1855 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 30 Nov 2021 17:35:06 +0000 Subject: [PATCH 086/155] drm/vc4: Correct logging string for dev_err_probe The commit that changed from dev_err to dev_err_probe left the %d in the format string, but removed the parameter, leading to a compile warning. Fixes: "6505412df625 drm/vc4: Use dev_err_probe when logging error registering HDMI audio" Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f673c04dad12..807cf15e2130 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1848,7 +1848,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) snd_soc_card_set_drvdata(card, vc4_hdmi); ret = devm_snd_soc_register_card(dev, card); if (ret) - dev_err_probe(dev, ret, "Could not register sound card: %d\n"); + dev_err_probe(dev, ret, "Could not register sound card.\n"); return ret; -- Gitee From fc809c11f9f5a13858c77a6656b5ab81f5036267 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 25 Nov 2021 14:46:55 +0000 Subject: [PATCH 087/155] drm/vc4: Move HDMI reset to pm_resume Pi0-3 have power domains attached to the pm_runtime hooks for the HDMI block. Initialisation done in the reset called from bind is therefore lost if all users of the domain are suspended. The VEC shares the same lowest level clock/power gating as the HDMI block, so whilst that is enabled the block is never actually powered down, but if it isn't enabled then we lose the state. Reset and initialise the HDMI block from pm_resume. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hdmi.c | 61 ++++++++++++++++++----------- drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 +- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 807cf15e2130..702101b3fdf1 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2242,7 +2242,6 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) struct platform_device *pdev = vc4_hdmi->pdev; struct device *dev = &pdev->dev; unsigned long flags; - u32 value; int ret; if (!of_find_property(dev->of_node, "interrupts", NULL)) { @@ -2261,15 +2260,6 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector); cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); - spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - value = HDMI_READ(HDMI_CEC_CNTRL_1); - /* Set the logical address to Unregistered */ - value |= VC4_HDMI_CEC_ADDR_MASK; - HDMI_WRITE(HDMI_CEC_CNTRL_1, value); - spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - - vc4_hdmi_cec_update_clk_div(vc4_hdmi); - if (vc4_hdmi->variant->external_irq_controller) { ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_cec_irq_handler_rx_bare, @@ -2332,6 +2322,29 @@ static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) cec_unregister_adapter(vc4_hdmi->cec_adap); } + +static int vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + value = HDMI_READ(HDMI_CEC_CNTRL_1); + /* Set the logical address to Unregistered */ + value |= VC4_HDMI_CEC_ADDR_MASK; + HDMI_WRITE(HDMI_CEC_CNTRL_1, value); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + vc4_hdmi_cec_update_clk_div(vc4_hdmi); + + if (!vc4_hdmi->variant->external_irq_controller) { + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff); + spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + } + + return 0; +} #else static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { @@ -2340,6 +2353,10 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {}; +static void vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) +{ + return 0; +} #endif static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, @@ -2575,6 +2592,15 @@ static int vc4_hdmi_runtime_resume(struct device *dev) if (ret) return ret; + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + + ret = vc4_hdmi_cec_resume(vc4_hdmi); + if (ret) { + clk_disable_unprepare(vc4_hdmi->hsm_clock); + return ret; + } + return 0; } #endif @@ -2688,20 +2714,11 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (ret) goto err_put_ddc; - /* - * We need to have the device powered up at this point to call - * our reset hook and for the CEC init. - */ - ret = vc4_hdmi_runtime_resume(dev); - if (ret) - goto err_put_ddc; - - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); pm_runtime_enable(dev); - if (vc4_hdmi->variant->reset) - vc4_hdmi->variant->reset(vc4_hdmi); + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto err_put_ddc; if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 24056441a4bb..72b769412482 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -417,7 +417,7 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi, const struct vc4_hdmi_variant *variant = hdmi->variant; void __iomem *base; - WARN_ON(!pm_runtime_active(&hdmi->pdev->dev)); + WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev)); if (reg >= variant->num_registers) { dev_warn(&hdmi->pdev->dev, @@ -447,7 +447,7 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi, lockdep_assert_held(&hdmi->hw_lock); - WARN_ON(!pm_runtime_active(&hdmi->pdev->dev)); + WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev)); if (reg >= variant->num_registers) { dev_warn(&hdmi->pdev->dev, -- Gitee From 7830f66bc4192d829694709d6a9d8eefa76b2bee Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 13:53:36 +0000 Subject: [PATCH 088/155] clk: bcm: rpi: Add the BCM283x pixel clock. The clk-bcm2835 handling of the pixel clock does not function correctly when the HDMI power domain is disabled. The firmware supports it correctly, so add it to the firmware clock driver. Signed-off-by: Dave Stevenson --- drivers/clk/bcm/clk-raspberrypi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index 0e3be5ec61ca..c307e054f805 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -276,6 +276,7 @@ static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi, case RPI_FIRMWARE_HEVC_CLK_ID: case RPI_FIRMWARE_PIXEL_BVB_CLK_ID: case RPI_FIRMWARE_VEC_CLK_ID: + case RPI_FIRMWARE_PIXEL_CLK_ID: hw = raspberrypi_clk_register(rpi, clks->parent, clks->id); if (IS_ERR(hw)) -- Gitee From c6adf0c209cd6d9dc1e07e9d1329e141b8853db9 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 14:11:09 +0000 Subject: [PATCH 089/155] dt: bcm283x: Change BCM283x HDMI to use firmware clock driver The clk-bcm2835 handling of the pixel clock does not function correctly when the HDMI power domain is disabled. The firmware supports it correctly, and the firmware clock driver now supports it, so switch the vc4-hdmi driver to use the firmware clock driver. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/bcm2835-common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/bcm2835-common.dtsi b/arch/arm/boot/dts/bcm2835-common.dtsi index 15f3975f1ca1..7f46a6ec512c 100644 --- a/arch/arm/boot/dts/bcm2835-common.dtsi +++ b/arch/arm/boot/dts/bcm2835-common.dtsi @@ -128,7 +128,7 @@ "hd"; interrupts = <2 8>, <2 9>; ddc = <&i2c2>; - clocks = <&clocks BCM2835_PLLH_PIX>, + clocks = <&firmware_clocks 9>, <&clocks BCM2835_CLOCK_HSM>; clock-names = "pixel", "hdmi"; dmas = <&dma (17|(1<<27)|(1<<24))>; -- Gitee From 25fa3927e84d4a6cb1fa5dc0323699d0c2664279 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 26 Nov 2021 17:59:07 +0000 Subject: [PATCH 090/155] Revert "Revert "overlays: vc4-kms-v3d: Change composite handling"" Reinstates the new handling. This reverts commit 46c99e3d7cf38446491b3c2a826fc05dcebc588d. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/README | 4 ++-- arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +- arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 8e4939377c40..bedb501b3ce5 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3620,8 +3620,8 @@ Params: cma-512 CMA is 512MB (needs 1GB) cma-default Use upstream's default value audio Enable or disable audio over HDMI (default "on") noaudio Disable all HDMI audio (default "off") - nocomposite Disable the composite video output (default - "off") + composite Enable the composite output (default "off") + N.B. Disables all other outputs on a Pi 4. Name: vc4-kms-v3d-pi4 diff --git a/arch/arm/boot/dts/overlays/upstream-overlay.dts b/arch/arm/boot/dts/overlays/upstream-overlay.dts index 7c4071a7cb27..2852bea52309 100644 --- a/arch/arm/boot/dts/overlays/upstream-overlay.dts +++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts @@ -1,4 +1,4 @@ -// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default dwc2-overlay.dts,dr_mode=otg +// redo: ovmerge -c vc4-kms-v3d-overlay.dts,cma-default,composite dwc2-overlay.dts,dr_mode=otg /dts-v1/; /plugin/; diff --git a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts index 62e1d77a8182..351fc160e803 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-v3d-overlay.dts @@ -89,7 +89,7 @@ fragment@11 { target = <&vec>; - __overlay__ { + __dormant__ { status = "okay"; }; }; @@ -118,6 +118,6 @@ __overrides__ { audio = <0>,"!13"; noaudio = <0>,"=13"; - nocomposite = <0>, "!11"; + composite = <0>, "=11"; }; }; -- Gitee From edf159bb8cf0a52a81a2a42e6c2cea6412102d22 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:10:55 +0000 Subject: [PATCH 091/155] drm/panel-simple: Populate bpc when using panel-dpi panel-dpi doesn't know the bit depth, so in the same way that DPI is guessed for the connector type, guess that it'll be 8bpc. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/panel/panel-simple.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 8becb0e31814..c0cd50edd045 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -447,6 +447,8 @@ static int panel_dpi_probe(struct device *dev, /* We do not know the connector for the DT node, so guess it */ desc->connector_type = DRM_MODE_CONNECTOR_DPI; + /* Likewise for the bit depth. */ + desc->bpc = 8; panel->desc = desc; -- Gitee From c5e1c7defbec0d306cebfffa0fa54e63a2202c65 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:13:02 +0000 Subject: [PATCH 092/155] drm/panel-simple: When using panel-dpi, update desc When using the "panel-dpi" compatible string, desc as passed from DT is a dumy entry, and panel_dpi_probe allocates a new one and attaches it to the panel. However panel_simple_probe has already taken a local copy of the variable, which means all the validation is done against the empty dummy structure, not the configured data. Update the local variable after panel_dpi_probe. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/panel/panel-simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index c0cd50edd045..81f874745e2b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -559,6 +559,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) err = panel_dpi_probe(dev, panel); if (err) goto free_ddc; + desc = panel->desc; } else { if (!of_get_display_timing(dev->of_node, "panel-timing", &dt)) panel_simple_parse_panel_timing_node(dev, panel, &dt); -- Gitee From 8875f1213c4e2a7d4ac2d9c3700260e58752211c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:16:21 +0000 Subject: [PATCH 093/155] drm/panel-simple: Allow the bus format to be read from DT for panel-dpi The "panel-dpi" compatible string configures panel from device tree, but it doesn't provide any way of configuring the bus format (colour representation), nor does it populate it. Add a DT parameter "bus-format" that allows the MEDIA_BUS_FMT_xxx value to be specified from device tree. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/panel/panel-simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 81f874745e2b..e99168cc2ae4 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -438,6 +438,7 @@ static int panel_dpi_probe(struct device *dev, of_property_read_u32(np, "width-mm", &desc->size.width); of_property_read_u32(np, "height-mm", &desc->size.height); + of_property_read_u32(np, "bus-format", &desc->bus_format); /* Extract bus_flags from display_timing */ bus_flags = 0; -- Gitee From 7f75290c901d10bbb809b10834517043ee36909f Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:21:46 +0000 Subject: [PATCH 094/155] drm/vc4: dpi: Add option for inverting pixel clock and output enable DRM provides flags for inverting pixel clock and output enable signals, but these were not mapped to the relevant registers. Add those mappings. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_dpi.c | 89 ++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 4dd8df6ddcbe..e19c34d5dbd6 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -148,45 +148,58 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) } drm_connector_list_iter_end(&conn_iter); - if (connector && connector->display_info.num_bus_formats) { - u32 bus_format = connector->display_info.bus_formats[0]; - - switch (bus_format) { - case MEDIA_BUS_FMT_RGB888_1X24: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, - DPI_FORMAT); - break; - case MEDIA_BUS_FMT_BGR888_1X24: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, - DPI_FORMAT); - dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); - break; - case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, - DPI_FORMAT); - break; - case MEDIA_BUS_FMT_BGR666_1X24_CPADHI: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, - DPI_FORMAT); - dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); - break; - case MEDIA_BUS_FMT_RGB666_1X18: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, - DPI_FORMAT); - break; - case MEDIA_BUS_FMT_BGR666_1X18: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, - DPI_FORMAT); - dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); - break; - case MEDIA_BUS_FMT_RGB565_1X16: - dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, - DPI_FORMAT); - break; - default: - DRM_ERROR("Unknown media bus format %d\n", bus_format); - break; + if (connector) { + if (connector->display_info.num_bus_formats) { + u32 bus_format = connector->display_info.bus_formats[0]; + + switch (bus_format) { + case MEDIA_BUS_FMT_RGB888_1X24: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, + DPI_FORMAT); + break; + case MEDIA_BUS_FMT_BGR888_1X24: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, + DPI_FORMAT); + dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, + DPI_ORDER); + break; + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, + DPI_FORMAT); + break; + case MEDIA_BUS_FMT_BGR666_1X24_CPADHI: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, + DPI_FORMAT); + dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, + DPI_ORDER); + break; + case MEDIA_BUS_FMT_RGB666_1X18: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, + DPI_FORMAT); + break; + case MEDIA_BUS_FMT_BGR666_1X18: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, + DPI_FORMAT); + dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, + DPI_ORDER); + break; + case MEDIA_BUS_FMT_RGB565_1X16: + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, + DPI_FORMAT); + break; + default: + DRM_ERROR("Unknown media bus format %d\n", + bus_format); + break; + } } + + if (connector->display_info.bus_flags & + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) + dpi_c |= DPI_PIXEL_CLK_INVERT; + + if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) + dpi_c |= DPI_OUTPUT_ENABLE_INVERT; } else { /* Default to 18bit if no connector found. */ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT); -- Gitee From 2d20c7fbaaa32f7f9be98bec2d2bd2d72b08d97c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:28:29 +0000 Subject: [PATCH 095/155] drm/vc4: dpi: Ensure a default format is selected In a couple of error/incomplete configuration cases, the DPI_FORMAT bits wouldn't get set. Adopt a default of RGB666 in all these cases. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_dpi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index e19c34d5dbd6..08147d0eab83 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -173,6 +173,10 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER); break; + default: + DRM_ERROR("Unknown media bus format %d\n", + bus_format); + fallthrough; case MEDIA_BUS_FMT_RGB666_1X18: dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT); @@ -187,11 +191,12 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, DPI_FORMAT); break; - default: - DRM_ERROR("Unknown media bus format %d\n", - bus_format); - break; } + } else { + /* Default to 18bit if no connector found. */ + dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, + DPI_FORMAT); + } if (connector->display_info.bus_flags & -- Gitee From 11a2e72c9333bb4c95cd72c9d1e191e1d55c67e7 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:24:44 +0000 Subject: [PATCH 096/155] dt: bcm270x: Add GPIO defines for RGB565 DPI output modes Adds the pinctrl defines for the RGB565 DPI output modes. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/bcm270x.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi index badcf341ecd2..49f9019dc125 100644 --- a/arch/arm/boot/dts/bcm270x.dtsi +++ b/arch/arm/boot/dts/bcm270x.dtsi @@ -189,6 +189,28 @@ 20 21>; brcm,function = ; }; + dpi_16bit_gpio0: dpi_16bit_gpio0 { + brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 + 12 13 14 15 16 17 18 19>; + brcm,function = ; + }; + dpi_16bit_gpio2: dpi_16bit_gpio2 { + brcm,pins = <2 3 4 5 6 7 8 9 10 11 + 12 13 14 15 16 17 18 19>; + brcm,function = ; + }; + dpi_16bit_cpadhi_gpio0: dpi_16bit_cpadhi_gpio0 { + brcm,pins = <0 1 2 3 4 5 6 7 8 + 12 13 14 15 16 17 + 20 21 22 23 24>; + brcm,function = ; + }; + dpi_16bit_cpadhi_gpio2: dpi_16bit_cpadhi_gpio2 { + brcm,pins = <2 3 4 5 6 7 8 + 12 13 14 15 16 17 + 20 21 22 23 24>; + brcm,function = ; + }; }; &uart0 { -- Gitee From a8a88e5f0658869452ccd6c364176cb0ba5b5cd9 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Dec 2021 18:06:37 +0000 Subject: [PATCH 097/155] dtoverlays: Add a generic DPI panel overlay for KMS Uses the "panel-dpi" compatible to set panel timings from DT. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/README | 28 ++++++ .../overlays/vc4-kms-dpi-generic-overlay.dts | 92 +++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index a6b0d9ea0385..1c0da564b3c1 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -232,6 +232,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ vc4-fkms-v3d.dtbo \ vc4-fkms-v3d-pi4.dtbo \ vc4-kms-dpi-at056tn53v1.dtbo \ + vc4-kms-dpi-generic.dtbo \ vc4-kms-dsi-7inch.dtbo \ vc4-kms-dsi-lt070me05000.dtbo \ vc4-kms-dsi-lt070me05000-v2.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index bedb501b3ce5..4ae0bc9d22ae 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3563,6 +3563,34 @@ Load: dtoverlay=vc4-kms-dpi-at056tn53v1 Params: +Name: vc4-kms-dpi-generic +Info: Enable a generic DPI display under KMS. Default timings are for the + Adafruit Kippah with 800x480 panel and RGB666 (GPIOs 0-21) + Requires vc4-kms-v3d to be loaded. +Load: dtoverlay=vc4-kms-dpi-generic,= +Params: clock-frequency Display clock frequency (Hz) + hactive Horizontal active pixels + hfp Horizontal front porch + hsync Horizontal sync pulse width + hbp Horizontal back porch + vactive Vertical active lines + vfp Vertical front porch + vsync Vertical sync pulse width + vbp Vertical back porch + hsync-invert Horizontal sync active low + vsync-invert Vertical sync active low + de-invert Data Enable active low + pixclk-invert Negative edge pixel clock + width-mm Define the screen width in mm + height-mm Define the screen height in mm + rgb565 Change to RGB565 output on GPIOs 0-19 + rgb666-padhi Change to RGB666 output on GPIOs 0-9, 12-17, and + 20-25 + rgb888 Change to RGB888 output on GPIOs 0-27 + bus-format Override the bus format for a MEDIA_BUS_FMT_* + value. NB also overridden by rgbXXX overrides. + + Name: vc4-kms-dsi-7inch Info: Enable the Raspberry Pi DSI 7" screen. Includes the edt-ft5406 for the touchscreen element. diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts new file mode 100644 index 000000000000..def175746f66 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts @@ -0,0 +1,92 @@ +/* + * vc4-kms-dpi-at056tn53v1-overlay.dts + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/ { + compatible = "brcm,bcm2835"; + + fragment@0 { + target-path = "/"; + __overlay__ { + panel: panel { + compatible = "panel-dpi"; + + width-mm = <154>; + height-mm = <83>; + bus-format = <0x1009>; + + timing: panel-timing { + clock-frequency = <29500000>; + hactive = <800>; + hfront-porch = <24>; + hsync-len = <72>; + hback-porch = <96>; + hsync-active = <0>; + vactive = <480>; + vfront-porch = <3>; + vsync-len = <10>; + vback-porch = <7>; + vsync-active = <0>; + + de-active = <1>; + pixelclk-active = <1>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + }; + }; + + fragment@1 { + target = <&dpi>; + dpi_node: __overlay__ { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&dpi_18bit_gpio0>; + + port { + dpi_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; + + __overrides__ { + clock-frequency = <&timing>, "clock-frequency:0"; + hactive = <&timing>, "hactive:0"; + hfp = <&timing>, "hfront-porch:0"; + hsync = <&timing>, "hsync-len:0"; + hbp = <&timing>, "hback-porch:0"; + vactive = <&timing>, "vactive:0"; + vfp = <&timing>, "vfront-porch:0"; + vsync = <&timing>, "vsync-len:0"; + vbp = <&timing>, "vback-porch:0"; + hsync-invert = <&timing>, "hsync-active:0=0"; + vsync-invert = <&timing>, "vsync-active:0=0"; + de-invert = <&timing>, "de-active:0=0"; + pixclk-invert = <&timing>, "pixelclk-active:0=0"; + + width-mm = <&panel>, "width-mm:0"; + height-mm = <&panel>, "height-mm:0"; + + rgb565 = <&panel>, "bus-format:0=0x1017", + <&dpi_node>, "pinctrl-0:0=",<&dpi_16bit_gpio0>; + rgb666-padhi = <&panel>, "bus-format:0=0x1015", + <&dpi_node>, "pinctrl-0:0=",<&dpi_18bit_cpadhi_gpio0>; + rgb888 = <&panel>, "bus-format:0=0x100a", + <&dpi_node>, "pinctrl-0:0=",<&dpi_gpio0>; + bus-format = <&panel>, "bus-format:0"; + }; +}; -- Gitee From 5a1ee358341ac8a4a33632d0c615140e90293e28 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Fri, 3 Dec 2021 14:32:05 +0000 Subject: [PATCH 098/155] xhci: correct room_on_ring() for cases where there is a single segment Don't calculate space based on the number of TRBs in the current segment, as it's OK to wrap to the start (and flip the cycle state bit). Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci-ring.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index f4cbf6628c98..3b9bb0f481d7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -265,6 +265,12 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, return 0; if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) { + /* + * If the ring has a single segment the dequeue segment + * never changes, so don't use it as measure of free space. + */ + if (ring->num_segs == 1) + return ring->num_trbs_free >= num_trbs; num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs; if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg) return 0; -- Gitee From 7fe287d347dea235a785cd87bce9587cb1aaefc4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Dec 2021 15:57:15 +0000 Subject: [PATCH 099/155] vc4/drm: Ignore vc4_hdmi->output_enabled for allowing audio (#4759) Otherwise we reject audio playback when switching hdmi modes Signed-off-by: Dom Cobley --- drivers/gpu/drm/vc4/vc4_hdmi.c | 29 ++--------------------------- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ------ 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 702101b3fdf1..6aa074714305 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -213,6 +213,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) connected = true; } + vc4_hdmi->encoder.hdmi_monitor = false; if (connected) { if (connector->status != connector_status_connected) { struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc); @@ -741,15 +742,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, mutex_unlock(&vc4_hdmi->mutex); } -static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) -{ - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - - mutex_lock(&vc4_hdmi->mutex); - vc4_hdmi->output_enabled = false; - mutex_unlock(&vc4_hdmi->mutex); -} - static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) { unsigned long flags; @@ -1219,15 +1211,6 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, mutex_unlock(&vc4_hdmi->mutex); } -static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) -{ - struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - - mutex_lock(&vc4_hdmi->mutex); - vc4_hdmi->output_enabled = true; - mutex_unlock(&vc4_hdmi->mutex); -} - static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) @@ -1321,8 +1304,6 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { .atomic_check = vc4_hdmi_encoder_atomic_check, .atomic_mode_set = vc4_hdmi_encoder_atomic_mode_set, .mode_valid = vc4_hdmi_encoder_mode_valid, - .disable = vc4_hdmi_encoder_disable, - .enable = vc4_hdmi_encoder_enable, }; static u32 vc4_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate) @@ -1454,17 +1435,11 @@ static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) { lockdep_assert_held(&vc4_hdmi->mutex); - /* - * If the controller is disabled, prevent any ALSA output. - */ - if (!vc4_hdmi->output_enabled) - return false; - /* * If the encoder is currently in DVI mode, treat the codec DAI * as missing. */ - if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE)) + if (!vc4_hdmi->encoder.hdmi_monitor) return false; return true; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index d49c6f3a98ed..8fa1d3054eb6 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -223,12 +223,6 @@ struct vc4_hdmi { */ struct drm_display_mode saved_adjusted_mode; - /** - * @output_enabled: Is the HDMI controller currently active? - * Protected by @mutex. - */ - bool output_enabled; - /** * @scdc_enabled: Is the HDMI controller currently running with * the scrambler on? Protected by @mutex. -- Gitee From 4f242d9f3a05ab76f1d0408704f60c0d58125ee5 Mon Sep 17 00:00:00 2001 From: peterharperuk <77111776+peterharperuk@users.noreply.github.com> Date: Mon, 13 Dec 2021 14:00:35 +0000 Subject: [PATCH 100/155] ARM: dts: Create bcm2711-rpi-cm4s.dts (#4761) Signed-off-by: Peter Harper --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/bcm2711-rpi-cm4s.dts | 450 +++++++++++++++++++++++++ 2 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 arch/arm/boot/dts/bcm2711-rpi-cm4s.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index c961dfbbad69..ee163c52577e 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -16,7 +16,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ bcm2711-rpi-4-b.dtb \ bcm2711-rpi-400.dtb \ bcm2710-rpi-cm3.dtb \ - bcm2711-rpi-cm4.dtb + bcm2711-rpi-cm4.dtb \ + bcm2711-rpi-cm4s.dtb dtb-$(CONFIG_ARCH_ALPINE) += \ alpine-db.dtb diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts new file mode 100644 index 000000000000..c4c2ed3ec52a --- /dev/null +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#include "bcm2711.dtsi" +#include "bcm2835-rpi.dtsi" + +#include + +/ { + compatible = "raspberrypi,4-compute-module-s", "brcm,bcm2711"; + model = "Raspberry Pi Compute Module 4S"; + + chosen { + /* 8250 auxiliary UART instead of pl011 */ + stdout-path = "serial1:115200n8"; + }; + + /* Will be filled by the bootloader */ + memory@0 { + device_type = "memory"; + reg = <0 0 0>; + }; + + aliases { + emmc2bus = &emmc2bus; + blconfig = &blconfig; + }; + + leds { + led-act { + gpios = <&virtgpio 0 0>; + }; + }; +}; + +&ddc0 { + status = "okay"; +}; + +&firmware { + firmware_clocks: clocks { + compatible = "raspberrypi,firmware-clocks"; + #clock-cells = <1>; + }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; +}; + +&gpio { + /* + * Parts taken from rpi_SCH_4b_4p0_reduced.pdf and + * the official GPU firmware DT blob. + * + * Legend: + * "FOO" = GPIO line named "FOO" on the schematic + * "FOO_N" = GPIO line named "FOO" on schematic, active low + */ + gpio-line-names = "ID_SDA", + "ID_SCL", + "SDA1", + "SCL1", + "GPIO_GCLK", + "GPIO5", + "GPIO6", + "SPI_CE1_N", + "SPI_CE0_N", + "SPI_MISO", + "SPI_MOSI", + "SPI_SCLK", + "GPIO12", + "GPIO13", + /* Serial port */ + "TXD1", + "RXD1", + "GPIO16", + "GPIO17", + "GPIO18", + "GPIO19", + "GPIO20", + "GPIO21", + "GPIO22", + "GPIO23", + "GPIO24", + "GPIO25", + "GPIO26", + "GPIO27", + "GPIO28", + "GPIO29", + "GPIO30", + "GPIO31", + "GPIO32", + "GPIO33", + "GPIO34", + "GPIO35", + "GPIO36", + "GPIO37", + "GPIO38", + "GPIO39", + "PWM0_MISO", + "PWM1_MOSI", + "GPIO42", + "GPIO43", + "GPIO44", + "GPIO45"; +}; + +&hdmi0 { + clocks = <&firmware_clocks 13>, <&firmware_clocks 14>, <&dvp 0>, <&clk_27MHz>; + clock-names = "hdmi", "bvb", "audio", "cec"; + wifi-2.4ghz-coexistence; + status = "okay"; +}; + + +&hvs { + clocks = <&firmware_clocks 4>; +}; + +&pixelvalve0 { + status = "okay"; +}; + +&pixelvalve1 { + status = "okay"; +}; + +&pixelvalve2 { + status = "okay"; +}; + +&pixelvalve4 { + status = "okay"; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; + status = "okay"; +}; + +&rmem { + /* + * RPi4's co-processor will copy the board's bootloader configuration + * into memory for the OS to consume. It'll also update this node with + * its placement information. + */ + blconfig: nvram@0 { + compatible = "raspberrypi,bootloader-config", "nvmem-rmem"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x0 0x0>; + no-map; + status = "disabled"; + }; +}; + +/* EMMC2 is used to drive the EMMC card */ +&emmc2 { + bus-width = <8>; + broken-cd; + status = "okay"; +}; + +&pcie0 { + status = "disabled"; +}; + +&vchiq { + interrupts = ; +}; + +&vc4 { + status = "okay"; +}; + +&vec { + status = "disabled"; +}; + +// ============================================= +// Downstream rpi- changes + +#define BCM2711 + +#include "bcm270x.dtsi" + +/ { + soc { + /delete-node/ pixelvalve@7e807000; + /delete-node/ hdmi@7e902000; + + virtgpio: virtgpio { + compatible = "brcm,bcm2835-virtgpio"; + gpio-controller; + #gpio-cells = <2>; + firmware = <&firmware>; + status = "okay"; + }; + }; +}; + +#include "bcm2711-rpi.dtsi" +#include "bcm283x-rpi-csi0-2lane.dtsi" +#include "bcm283x-rpi-csi1-4lane.dtsi" +#include "bcm283x-rpi-i2c0mux_0_44.dtsi" +#include "bcm283x-rpi-cam1-regulator.dtsi" + +/delete-node/ &hdmi1; + +/ { + chosen { + bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; + }; + + aliases { + serial0 = &uart0; + mmc0 = &emmc2; + mmc1 = &mmcnr; + mmc2 = &sdhost; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + spi3 = &spi3; + spi4 = &spi4; + spi5 = &spi5; + spi6 = &spi6; + /delete-property/ intc; + }; + + /delete-node/ wifi-pwrseq; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins &spi0_cs_pins>; + cs-gpios = <&gpio 8 1>, <&gpio 7 1>; + + spidev0: spidev@0{ + compatible = "spidev"; + reg = <0>; /* CE0 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; + + spidev1: spidev@1{ + compatible = "spidev"; + reg = <1>; /* CE1 */ + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <125000000>; + }; +}; + +&gpio { + spi0_pins: spi0_pins { + brcm,pins = <9 10 11>; + brcm,function = ; + }; + + spi0_cs_pins: spi0_cs_pins { + brcm,pins = <8 7>; + brcm,function = ; + }; + + spi3_pins: spi3_pins { + brcm,pins = <1 2 3>; + brcm,function = ; + }; + + spi3_cs_pins: spi3_cs_pins { + brcm,pins = <0 24>; + brcm,function = ; + }; + + spi4_pins: spi4_pins { + brcm,pins = <5 6 7>; + brcm,function = ; + }; + + spi4_cs_pins: spi4_cs_pins { + brcm,pins = <4 25>; + brcm,function = ; + }; + + spi5_pins: spi5_pins { + brcm,pins = <13 14 15>; + brcm,function = ; + }; + + spi5_cs_pins: spi5_cs_pins { + brcm,pins = <12 26>; + brcm,function = ; + }; + + spi6_pins: spi6_pins { + brcm,pins = <19 20 21>; + brcm,function = ; + }; + + spi6_cs_pins: spi6_cs_pins { + brcm,pins = <18 27>; + brcm,function = ; + }; + + i2c0_pins: i2c0 { + brcm,pins = <0 1>; + brcm,function = ; + brcm,pull = ; + }; + + i2c1_pins: i2c1 { + brcm,pins = <2 3>; + brcm,function = ; + brcm,pull = ; + }; + + i2c3_pins: i2c3 { + brcm,pins = <4 5>; + brcm,function = ; + brcm,pull = ; + }; + + i2c4_pins: i2c4 { + brcm,pins = <8 9>; + brcm,function = ; + brcm,pull = ; + }; + + i2c5_pins: i2c5 { + brcm,pins = <12 13>; + brcm,function = ; + brcm,pull = ; + }; + + i2c6_pins: i2c6 { + brcm,pins = <22 23>; + brcm,function = ; + brcm,pull = ; + }; + + i2s_pins: i2s { + brcm,pins = <18 19 20 21>; + brcm,function = ; + }; + + sdio_pins: sdio_pins { + brcm,pins = <34 35 36 37 38 39>; + brcm,function = ; // alt3 = SD1 + brcm,pull = <0 2 2 2 2 2>; + }; + + uart0_pins: uart0_pins { + brcm,pins; + brcm,function; + brcm,pull; + }; + + uart2_pins: uart2_pins { + brcm,pins = <0 1>; + brcm,function = ; + brcm,pull = <0 2>; + }; + + uart3_pins: uart3_pins { + brcm,pins = <4 5>; + brcm,function = ; + brcm,pull = <0 2>; + }; + + uart4_pins: uart4_pins { + brcm,pins = <8 9>; + brcm,function = ; + brcm,pull = <0 2>; + }; + + uart5_pins: uart5_pins { + brcm,pins = <12 13>; + brcm,function = ; + brcm,pull = <0 2>; + }; +}; + +&i2c0if { + clock-frequency = <100000>; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; +}; + +&i2s { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; +}; + +// ============================================= +// Board specific stuff here + +&sdhost { + status = "disabled"; +}; + +&gpio { + audio_pins: audio_pins { + brcm,pins = <>; + brcm,function = <>; + }; +}; + +&leds { + act_led: led-act { + label = "led0"; + linux,default-trigger = "mmc0"; + gpios = <&virtgpio 0 0>; + }; +}; + +&pwm1 { + status = "disabled"; +}; + +&audio { + pinctrl-names = "default"; + pinctrl-0 = <&audio_pins>; + brcm,disable-headphones = <1>; +}; + +/ { + __overrides__ { + act_led_gpio = <&act_led>,"gpios:4"; + act_led_activelow = <&act_led>,"gpios:8"; + act_led_trigger = <&act_led>,"linux,default-trigger"; + + sd_poll_once = <&emmc2>, "non-removable?"; + spi_dma4 = <&spi0>, "dmas:0=", <&dma40>, + <&spi0>, "dmas:8=", <&dma40>; + }; +}; -- Gitee From 22442043827742da29be6e04f4a652ce3940d50a Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 13 Dec 2021 15:05:56 +0000 Subject: [PATCH 101/155] xhci: refactor out TRBS_PER_SEGMENT define in runtime code In anticipation of adjusting the number of utilised TRBs in a ring segment, add trbs_per_seg to struct xhci_ring and use this instead of a compile-time define. Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci-mem.c | 48 +++++++++++++++++++----------------- drivers/usb/host/xhci-ring.c | 12 +++++---- drivers/usb/host/xhci.c | 6 ++--- drivers/usb/host/xhci.h | 1 + 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 796122ac737b..5cdf4e2e9bd4 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -98,6 +98,7 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, */ static void xhci_link_segments(struct xhci_segment *prev, struct xhci_segment *next, + unsigned int trbs_per_seg, enum xhci_ring_type type, bool chain_links) { u32 val; @@ -106,16 +107,16 @@ static void xhci_link_segments(struct xhci_segment *prev, return; prev->next = next; if (type != TYPE_EVENT) { - prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = + prev->trbs[trbs_per_seg - 1].link.segment_ptr = cpu_to_le64(next->dma); /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ - val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); + val = le32_to_cpu(prev->trbs[trbs_per_seg - 1].link.control); val &= ~TRB_TYPE_BITMASK; val |= TRB_TYPE(TRB_LINK); if (chain_links) val |= TRB_CHAIN; - prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); + prev->trbs[trbs_per_seg - 1].link.control = cpu_to_le32(val); } } @@ -139,15 +140,17 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, (xhci->quirks & XHCI_AMD_0x96_HOST))); next = ring->enq_seg->next; - xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); - xhci_link_segments(last, next, ring->type, chain_links); + xhci_link_segments(ring->enq_seg, first, ring->trbs_per_seg, + ring->type, chain_links); + xhci_link_segments(last, next, ring->trbs_per_seg, + ring->type, chain_links); ring->num_segs += num_segs; - ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; + ring->num_trbs_free += (ring->trbs_per_seg - 1) * num_segs; if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { - ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control + ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control &= ~cpu_to_le32(LINK_TOGGLE); - last->trbs[TRBS_PER_SEGMENT-1].link.control + last->trbs[ring->trbs_per_seg - 1].link.control |= cpu_to_le32(LINK_TOGGLE); ring->last_seg = last; } @@ -314,14 +317,15 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, * Each segment has a link TRB, and leave an extra TRB for SW * accounting purpose */ - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; } /* Allocate segments and link them for a ring */ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_segment **first, struct xhci_segment **last, - unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) + unsigned int num_segs, unsigned int trbs_per_seg, + unsigned int cycle_state, enum xhci_ring_type type, + unsigned int max_packet, gfp_t flags) { struct xhci_segment *prev; bool chain_links; @@ -350,12 +354,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, } return -ENOMEM; } - xhci_link_segments(prev, next, type, chain_links); + xhci_link_segments(prev, next, trbs_per_seg, type, chain_links); prev = next; num_segs--; } - xhci_link_segments(prev, *first, type, chain_links); + xhci_link_segments(prev, *first, trbs_per_seg, type, chain_links); *last = prev; return 0; @@ -387,16 +391,17 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, if (num_segs == 0) return ring; + ring->trbs_per_seg = TRBS_PER_SEGMENT; ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, - &ring->last_seg, num_segs, cycle_state, type, - max_packet, flags); + &ring->last_seg, num_segs, ring->trbs_per_seg, + cycle_state, type, max_packet, flags); if (ret) goto fail; /* Only event ring does not use link TRB */ if (type != TYPE_EVENT) { /* See section 4.9.2.1 and 6.4.4.1 */ - ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= + ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control |= cpu_to_le32(LINK_TOGGLE); } xhci_initialize_ring_info(ring, cycle_state); @@ -429,16 +434,15 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_segs_needed; int ret; - num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / - (TRBS_PER_SEGMENT - 1); - + num_segs_needed = (num_trbs + (ring->trbs_per_seg - 1) - 1) / + (ring->trbs_per_seg - 1); /* Allocate number of segments we needed, or double the ring size */ num_segs = ring->num_segs > num_segs_needed ? ring->num_segs : num_segs_needed; ret = xhci_alloc_segments_for_ring(xhci, &first, &last, - num_segs, ring->cycle_state, ring->type, - ring->bounce_buf_len, flags); + num_segs, ring->trbs_per_seg, ring->cycle_state, + ring->type, ring->bounce_buf_len, flags); if (ret) return -ENOMEM; @@ -1825,7 +1829,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, for (val = 0; val < evt_ring->num_segs; val++) { entry = &erst->entries[val]; entry->seg_addr = cpu_to_le64(seg->dma); - entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); + entry->seg_size = cpu_to_le32(evt_ring->trbs_per_seg); entry->rsvd = 0; seg = seg->next; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3b9bb0f481d7..545387a0679a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -87,15 +87,16 @@ static bool trb_is_link(union xhci_trb *trb) return TRB_TYPE_LINK_LE32(trb->link.control); } -static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb) +static bool last_trb_on_seg(struct xhci_segment *seg, + unsigned int trbs_per_seg, union xhci_trb *trb) { - return trb == &seg->trbs[TRBS_PER_SEGMENT - 1]; + return trb == &seg->trbs[trbs_per_seg - 1]; } static bool last_trb_on_ring(struct xhci_ring *ring, struct xhci_segment *seg, union xhci_trb *trb) { - return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg); + return last_trb_on_seg(seg, ring->trbs_per_seg, trb) && (seg->next == ring->first_seg); } static bool link_trb_toggles_cycle(union xhci_trb *trb) @@ -157,7 +158,8 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) { /* event ring doesn't have link trbs, check for last trb */ if (ring->type == TYPE_EVENT) { - if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) { + if (!last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg, + ring->dequeue)) { ring->dequeue++; goto out; } @@ -2982,7 +2984,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) * that clears the EHB. */ while (xhci_handle_event(xhci) > 0) { - if (event_loop++ < TRBS_PER_SEGMENT / 2) + if (event_loop++ < xhci->event_ring->trbs_per_seg / 2) continue; xhci_update_erst_dequeue(xhci, event_ring_deq); event_loop = 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 940c6b80967d..16b4a4b76da0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -858,8 +858,8 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) seg = ring->deq_seg; do { memset(seg->trbs, 0, - sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); - seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= + sizeof(union xhci_trb) * (ring->trbs_per_seg - 1)); + seg->trbs[ring->trbs_per_seg - 1].link.control &= cpu_to_le32(~TRB_CYCLE); seg = seg->next; } while (seg != ring->deq_seg); @@ -870,7 +870,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) ring->enq_seg = ring->deq_seg; ring->enqueue = ring->dequeue; - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; + ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 1) - 1; /* * Ring is now zeroed, so the HW should look for change of ownership * when the cycle bit is set to 1. diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 0f8542045677..f9f02031ff92 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1615,6 +1615,7 @@ struct xhci_ring { unsigned int num_trbs_free; unsigned int num_trbs_free_temp; unsigned int bounce_buf_len; + unsigned int trbs_per_seg; enum xhci_ring_type type; bool last_td_was_short; struct radix_tree_root *trb_address_map; -- Gitee From 78c2e478904544f6a72c7afb61c434f5fbe2a652 Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 13 Dec 2021 16:04:03 +0000 Subject: [PATCH 102/155] usb: xhci: add VLI_TRB_CACHE_BUG quirk The VL805 fetches up to 4 transfer TRBs at a time. TRB reads don't cross a 64B boundary, and if a TRB is fetched and is not on a 64B boundary, the read is sized up to the next 64B boundary. However the VL805 implements a readahead prefetch for TRBs on a transfer ring. This fetches the next 64B after any TRB read has happened. Near the end of a ring segment, the prefetcher can read the first 64B of the next page in physical memory and this is where the behaviour causes a bug. The controller does not tag reads with which endpoint they are for, so if the start of the next page is a ring segment used by a victim endpoint, and the victim endpoint is about to fetch TRBs from the start of the segment, the victim endpoint will read from the prefetched data and not perform a read to main memory. If the data is stale, the ring cycle state bit may not be correct and the endpoint will silently halt. Adjust trbs_per_seg for transfer rings allocated for this controller. See https://github.com/raspberrypi/linux/issues/4685 Signed-off-by: Jonathan Bell --- drivers/usb/host/xhci-mem.c | 11 +++++++++++ drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 5cdf4e2e9bd4..dce3990ea33b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -392,6 +392,17 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, return ring; ring->trbs_per_seg = TRBS_PER_SEGMENT; + /* + * The Via VL805 has a bug where cache readahead will fetch off the end + * of a page if the Link TRB of a transfer ring is in the last 4 slots. + * Where there are consecutive physical pages containing ring segments, + * this can cause a desync between the controller's view of a ring + * and the host. + */ + if (xhci->quirks & XHCI_VLI_TRB_CACHE_BUG && + type != TYPE_EVENT && type != TYPE_COMMAND) + ring->trbs_per_seg -= 4; + ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, &ring->last_seg, num_segs, ring->trbs_per_seg, cycle_state, type, max_packet, flags); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 0746ec9393e0..239094b5c40b 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -293,6 +293,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; xhci->quirks |= XHCI_AVOID_DQ_ON_LINK; + xhci->quirks |= XHCI_VLI_TRB_CACHE_BUG; } if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN && diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f9f02031ff92..3a75a4dfed3c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1889,6 +1889,7 @@ struct xhci_hcd { #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(42) #define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(43) #define XHCI_AVOID_DQ_ON_LINK BIT_ULL(44) +#define XHCI_VLI_TRB_CACHE_BUG BIT_ULL(45) unsigned int num_active_eps; unsigned int limit_active_eps; -- Gitee From 69b664bbef4bd693aae68d333e73ddcedfce66d7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Dec 2021 21:53:18 +0000 Subject: [PATCH 103/155] drm/vc4: Fix build without DRM_VC4_HDMI_CEC As reported by @asavah. Fixes: https://github.com/raspberrypi/linux/issues/4771 Signed-off-by: Phil Elwell --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 6aa074714305..b621fc3b1750 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2328,7 +2328,7 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {}; -static void vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) +static int vc4_hdmi_cec_resume(struct vc4_hdmi *vc4_hdmi) { return 0; } -- Gitee From 026e1e685da465cc1b5f5d746373d654d92e939e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Sat, 20 Nov 2021 10:48:36 +0000 Subject: [PATCH 104/155] dt: Create static regulators and clocks for camera nodes Unloading regulators through dynamic device tree doesn't work as the regulators will unregister whilst clients are still registered. Whilst the regulator framework does WARN when that happens, the client putting the regulator then typically results in a NULL dereference and badness. Instead of creating regulators and clocks from the overlays, create regulators and clocks for the sensors in the base DT. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 4 ++- arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts | 4 ++- arch/arm/boot/dts/bcm2708-rpi-b.dts | 4 ++- arch/arm/boot/dts/bcm2708-rpi-cm.dts | 21 ++++-------- arch/arm/boot/dts/bcm2708-rpi-zero-w.dts | 4 ++- arch/arm/boot/dts/bcm2708-rpi-zero.dts | 4 ++- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 4 ++- arch/arm/boot/dts/bcm270x.dtsi | 33 +++++++++++++++++++ arch/arm/boot/dts/bcm2710-rpi-2-b.dts | 4 ++- arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 4 ++- arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 4 ++- arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 21 ++++-------- arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts | 4 ++- arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 4 ++- arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 1 - .../boot/dts/bcm283x-rpi-cam1-regulator.dtsi | 10 ------ 16 files changed, 80 insertions(+), 50 deletions(-) delete mode 100644 arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts index e42cba84ab0e..a7d6427671b4 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; @@ -116,6 +115,9 @@ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts b/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts index 4ea1e68f5e29..af1b477f7927 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-b-rev1.dts @@ -4,7 +4,6 @@ #include "bcm2708-rpi.dtsi" #include "bcm283x-rpi-smsc9512.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-b", "brcm,bcm2835"; @@ -123,6 +122,9 @@ i2c_csi_dsi: &i2c1 { gpio = <&gpio 27 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2708-rpi-b.dts b/arch/arm/boot/dts/bcm2708-rpi-b.dts index a152c1c8e648..a5316257a18b 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-b.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-smsc9512.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-b", "brcm,bcm2835"; @@ -110,6 +109,9 @@ gpio = <&gpio 21 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts index f61e3418425a..d65f9db354dd 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts @@ -8,21 +8,14 @@ / { compatible = "raspberrypi,compute-module", "brcm,bcm2835"; model = "Raspberry Pi Compute Module"; +}; - cam1_reg: cam1_reg { - compatible = "regulator-fixed"; - regulator-name = "cam1-regulator"; - gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; - cam0_reg: cam0_reg { - compatible = "regulator-fixed"; - regulator-name = "cam0-regulator"; - gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; +&cam1_reg { + gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; +}; + +cam0_reg: &cam0_regulator { + gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts index 63faf4986987..e4c6c352f3aa 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-zero-w.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" #include "bcm2708-rpi-bt.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; @@ -167,6 +166,9 @@ gpio = <&gpio 44 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2708-rpi-zero.dts b/arch/arm/boot/dts/bcm2708-rpi-zero.dts index 84591bd7d423..19dae0d682ed 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-zero.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-zero.dts @@ -4,7 +4,6 @@ #include "bcm2708-rpi.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-zero", "brcm,bcm2835"; @@ -114,6 +113,9 @@ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts index e1381d2b3a2c..4c80d15981fe 100644 --- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; @@ -116,6 +115,9 @@ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi index 49f9019dc125..a5cabb5bc4a1 100644 --- a/arch/arm/boot/dts/bcm270x.dtsi +++ b/arch/arm/boot/dts/bcm270x.dtsi @@ -153,6 +153,39 @@ }; }; + cam1_reg: cam1_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam1-reg"; + enable-active-high; + /* Needs to be enabled, as removing a regulator is very unsafe */ + status = "okay"; + }; + + cam1_clk: cam1_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + status = "disabled"; + }; + + cam0_regulator: cam0_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam0-reg"; + enable-active-high; + status = "disabled"; + }; + + cam0_clk: cam0_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + status = "disabled"; + }; + + cam_dummy_reg: cam_dummy_reg { + compatible = "regulator-fixed"; + regulator-name = "cam-dummy-reg"; + status = "okay"; + }; + __overrides__ { cam0-pwdn-ctrl; cam0-pwdn; diff --git a/arch/arm/boot/dts/bcm2710-rpi-2-b.dts b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts index ae9db1b1be1b..a8a18ef4d1bf 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-2-b.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_28.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,2-model-b-rev2", "brcm,bcm2837"; @@ -116,6 +115,9 @@ gpio = <&gpio 41 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts index a1b169e554ba..93f9c8dddbca 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts @@ -6,7 +6,6 @@ #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_44.dtsi" #include "bcm271x-rpi-bt.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837"; @@ -188,6 +187,9 @@ gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts index 5cfb9ad76ca9..bc5d086beb93 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts @@ -6,7 +6,6 @@ #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_44.dtsi" #include "bcm271x-rpi-bt.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; @@ -197,6 +196,9 @@ gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts index c386a855cdc3..e3bb24ff99ba 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts @@ -8,21 +8,14 @@ / { compatible = "raspberrypi,3-compute-module", "brcm,bcm2837"; model = "Raspberry Pi Compute Module 3"; +}; - cam1_reg: cam1_reg { - compatible = "regulator-fixed"; - regulator-name = "cam1-regulator"; - gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; - cam0_reg: cam0_reg { - compatible = "regulator-fixed"; - regulator-name = "cam0-regulator"; - gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; +&cam1_reg { + gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; +}; + +cam0_reg: &cam0_regulator { + gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; }; &uart0 { diff --git a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts index 1cd3d01a166d..38629ebfa47f 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-zero-2-w.dts @@ -5,7 +5,6 @@ #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_44.dtsi" #include "bcm2708-rpi-bt.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { compatible = "raspberrypi,model-zero-2-w", "brcm,bcm2837"; @@ -188,6 +187,9 @@ gpio = <&gpio 40 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 44da9fc870be..fb44c89f3b0c 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -339,7 +339,6 @@ #include "bcm2711-rpi.dtsi" #include "bcm283x-rpi-csi1-2lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_44.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { chosen { @@ -608,6 +607,9 @@ gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>; }; +cam0_reg: &cam_dummy_reg { +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts index bc256aebab65..86de6bed42fb 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts @@ -353,7 +353,6 @@ #include "bcm283x-rpi-csi0-2lane.dtsi" #include "bcm283x-rpi-csi1-4lane.dtsi" #include "bcm283x-rpi-i2c0mux_0_44.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" / { chosen { diff --git a/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi b/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi deleted file mode 100644 index 55237d03ed94..000000000000 --- a/arch/arm/boot/dts/bcm283x-rpi-cam1-regulator.dtsi +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/ { - cam1_reg: cam1_reg { - compatible = "regulator-fixed"; - regulator-name = "cam1-reg"; - enable-active-high; - status = "disabled"; - }; -}; -- Gitee From f91611dcc37e6efb2305e451daa568988820d7b3 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Sat, 20 Nov 2021 14:43:29 +0000 Subject: [PATCH 105/155] dtoverlays: Convert the camera sensor overlays to use the new regs and clks. Now that we have regulators and clocks defined in the base DT for image sensors, switch the overlays to use them. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/imx219-overlay.dts | 40 ++++--------------- .../boot/dts/overlays/imx290_327-overlay.dtsi | 40 ++++--------------- .../boot/dts/overlays/imx477_378-overlay.dtsi | 31 +++----------- arch/arm/boot/dts/overlays/imx519-overlay.dts | 38 +++--------------- arch/arm/boot/dts/overlays/ov5647-overlay.dts | 18 +++++---- arch/arm/boot/dts/overlays/ov7251-overlay.dts | 37 +++-------------- arch/arm/boot/dts/overlays/ov9281-overlay.dts | 39 ++++-------------- 7 files changed, 50 insertions(+), 193 deletions(-) diff --git a/arch/arm/boot/dts/overlays/imx219-overlay.dts b/arch/arm/boot/dts/overlays/imx219-overlay.dts index 5b5ba70aff7f..7e39d4a70abf 100644 --- a/arch/arm/boot/dts/overlays/imx219-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts @@ -20,12 +20,12 @@ reg = <0x10>; status = "okay"; - clocks = <&imx219_clk>; + clocks = <&cam1_clk>; clock-names = "xclk"; VANA-supply = <&cam1_reg>; /* 2.8v */ - VDIG-supply = <&imx219_vdig>; /* 1.8v */ - VDDL-supply = <&imx219_vddl>; /* 1.2v */ + VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ + VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ rotation = <180>; orientation = <2>; @@ -68,26 +68,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - imx219_vdig: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "imx219_vdig"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - imx219_vddl: fixedregulator@2 { - compatible = "regulator-fixed"; - regulator-name = "imx219_vddl"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - - imx219_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + status = "okay"; + clock-frequency = <24000000>; }; }; @@ -99,16 +83,6 @@ }; fragment@5 { - target = <&cam1_reg>; - __overlay__ { - status = "okay"; - regulator-name = "imx219_vana"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - }; - - fragment@6 { target = <&csi1>; __overlay__ { brcm,media-controller; @@ -118,6 +92,6 @@ __overrides__ { rotation = <&imx219>,"rotation:0"; orientation = <&imx219>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <0>,"=5"; }; }; diff --git a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi index 2696daed523c..ba3f11631973 100644 --- a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi @@ -20,7 +20,7 @@ reg = <0x1a>; status = "okay"; - clocks = <&imx290_clk>; + clocks = <&cam1_clk>; clock-names = "xclk"; clock-frequency = <37125000>; @@ -28,8 +28,8 @@ orientation = <2>; vdda-supply = <&cam1_reg>; /* 2.8v */ - vdddo-supply = <&imx290_vdddo>; /* 1.8v */ - vddd-supply = <&imx290_vddd>; /* 1.5v */ + vdddo-supply = <&cam_dummy_reg>; /* 1.8v */ + vddd-supply = <&cam_dummy_reg>; /* 1.5v */ port { imx290_0: endpoint { @@ -62,26 +62,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - imx290_vdddo: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "imx290_vdddo"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - imx290_vddd: fixedregulator@2 { - compatible = "regulator-fixed"; - regulator-name = "imx290_vddd"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <1500000>; - }; - - imx290_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <37125000>; - }; + status = "okay"; + clock-frequency = <37125000>; }; }; @@ -92,16 +76,6 @@ }; }; - fragment@5 { - target = <&cam1_reg>; - __overlay__ { - status = "okay"; - regulator-name = "imx290_vdda"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - }; - fragment@6 { target = <&imx290_0>; __overlay__ { @@ -143,7 +117,7 @@ __overrides__ { 4lane = <0>, "-6+7-8+9"; - clock-frequency = <&imx290_clk>,"clock-frequency:0", + clock-frequency = <&cam1_clk>,"clock-frequency:0", <&imx290>,"clock-frequency:0"; rotation = <&imx290>,"rotation:0"; orientation = <&imx290>,"orientation:0"; diff --git a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi index d785e6cb5d82..433ab1958a15 100644 --- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi @@ -15,12 +15,12 @@ reg = <0x1a>; status = "okay"; - clocks = <&imx477_clk>; + clocks = <&cam1_clk>; clock-names = "xclk"; VANA-supply = <&cam1_reg>; /* 2.8v */ - VDIG-supply = <&imx477_vdig>; /* 1.05v */ - VDDL-supply = <&imx477_vddl>; /* 1.8v */ + VDIG-supply = <&cam_dummy_reg>; /* 1.05v */ + VDDL-supply = <&cam_dummy_reg>; /* 1.8v */ rotation = <180>; orientation = <2>; @@ -63,25 +63,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - imx477_vdig: fixedregulator@0 { - compatible = "regulator-fixed"; - regulator-name = "imx477_vdig"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - }; - imx477_vddl: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "imx477_vddl"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - imx477_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + clock-frequency = <24000000>; + status = "okay"; }; }; @@ -95,11 +80,7 @@ fragment@5 { target = <&cam1_reg>; __overlay__ { - status = "okay"; - regulator-name = "imx477_vana"; startup-delay-us = <300000>; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; }; }; diff --git a/arch/arm/boot/dts/overlays/imx519-overlay.dts b/arch/arm/boot/dts/overlays/imx519-overlay.dts index b8593a980bbf..dfc54ea34396 100644 --- a/arch/arm/boot/dts/overlays/imx519-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx519-overlay.dts @@ -20,12 +20,12 @@ reg = <0x1a>; status = "okay"; - clocks = <&imx519_clk>; + clocks = <&cam1_clk>; clock-names = "xclk"; VANA-supply = <&cam1_reg>; /* 2.8v */ - VDIG-supply = <&imx519_vdig>; /* 1.8v */ - VDDL-supply = <&imx519_vddl>; /* 1.2v */ + VDIG-supply = <&cam_dummy_reg>; /* 1.8v */ + VDDL-supply = <&cam_dummy_reg>; /* 1.2v */ rotation = <0>; orientation = <2>; @@ -68,26 +68,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - imx519_vdig: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "imx519_vdig"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - imx519_vddl: fixedregulator@2 { - compatible = "regulator-fixed"; - regulator-name = "imx519_vddl"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - - imx519_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + clock-frequency = <24000000>; + status = "okay"; }; }; @@ -98,16 +82,6 @@ }; }; - fragment@5 { - target = <&cam1_reg>; - __overlay__ { - status = "okay"; - regulator-name = "imx519_vana"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - }; - fragment@6 { target = <&csi1>; __overlay__ { diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts index f57b25c38794..a7b4085d4e57 100644 --- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts @@ -19,7 +19,7 @@ status = "okay"; pwdn-gpios = <&gpio 41 1>, <&gpio 32 1>; - clocks = <&ov5647_clk>; + clocks = <&cam1_clk>; rotation = <0>; orientation = <2>; @@ -77,13 +77,10 @@ }; fragment@5 { - target-path = "/"; + target = <&cam1_clk>; __overlay__ { - ov5647_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; - }; + status = "okay"; + clock-frequency = <25000000>; }; }; @@ -94,6 +91,13 @@ }; }; + fragment@7 { + target = <&cam1_reg>; + __overlay__ { + status = "disabled"; + }; + }; + __overrides__ { rotation = <&ov5647>,"rotation:0"; orientation = <&ov5647>,"orientation:0"; diff --git a/arch/arm/boot/dts/overlays/ov7251-overlay.dts b/arch/arm/boot/dts/overlays/ov7251-overlay.dts index 6fe652fe011b..0cf9966a48bf 100644 --- a/arch/arm/boot/dts/overlays/ov7251-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov7251-overlay.dts @@ -20,13 +20,13 @@ reg = <0x60>; status = "okay"; - clocks = <&ov7251_clk>; + clocks = <&cam1_clk>; clock-names = "xclk"; clock-frequency = <24000000>; - vdddo-supply = <&ov7251_dovdd>; + vdddo-supply = <&cam_dummy_reg>; vdda-supply = <&cam1_reg>; - vddd-supply = <&ov7251_dvdd>; + vddd-supply = <&cam_dummy_reg>; rotation = <0>; orientation = <2>; @@ -67,25 +67,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - ov7251_dovdd: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "ov7251_dovdd"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - ov7251_dvdd: fixedregulator@2 { - compatible = "regulator-fixed"; - regulator-name = "ov7251_dvdd"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - ov7251_clk: ov7251-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + status = "okay"; + clock-frequency = <24000000>; }; }; @@ -96,16 +81,6 @@ }; }; - fragment@5 { - target = <&cam1_reg>; - __overlay__ { - status = "okay"; - regulator-name = "ov7251_avdd"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - }; - fragment@6 { target = <&csi1>; __dormant__ { diff --git a/arch/arm/boot/dts/overlays/ov9281-overlay.dts b/arch/arm/boot/dts/overlays/ov9281-overlay.dts index b2b9a47c6d27..35d9f79980fe 100644 --- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts @@ -20,12 +20,12 @@ reg = <0x60>; status = "okay"; - clocks = <&ov9281_clk>; + clocks = <&cam1_clk>; clock-names = "xvclk"; avdd-supply = <&cam1_reg>; - dovdd-supply = <&ov9281_dovdd>; - dvdd-supply = <&ov9281_dvdd>; + dovdd-supply = <&cam_dummy_reg>; + dvdd-supply = <&cam_dummy_reg>; rotation = <0>; orientation = <2>; @@ -67,25 +67,10 @@ }; fragment@3 { - target-path="/"; + target = <&cam1_clk>; __overlay__ { - ov9281_dovdd: fixedregulator@1 { - compatible = "regulator-fixed"; - regulator-name = "ov9281_dovdd"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - }; - ov9281_dvdd: fixedregulator@2 { - compatible = "regulator-fixed"; - regulator-name = "ov9281_dvdd"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - }; - ov9281_clk: ov9281-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - }; + status = "okay"; + clock-frequency = <24000000>; }; }; @@ -97,16 +82,6 @@ }; fragment@5 { - target = <&cam1_reg>; - __overlay__ { - status = "okay"; - regulator-name = "ov9281_avdd"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - }; - }; - - fragment@6 { target = <&csi1>; __overlay__ { brcm,media-controller; @@ -116,6 +91,6 @@ __overrides__ { rotation = <&ov9281>,"rotation:0"; orientation = <&ov9281>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <0>,"=5"; }; }; -- Gitee From 2f32a80fcf1f51430aef2f147b4ee2f872075b18 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 22 Nov 2021 12:31:35 +0000 Subject: [PATCH 106/155] media: i2c: ov5647: Add support for regulator control. The driver supported using GPIOs to control the shutdown line, but no regulator control. Add regulator hooks. Signed-off-by: Dave Stevenson --- drivers/media/i2c/ov5647.c | 54 +++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index b92c07477639..3b7a15852c5d 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,15 @@ #define OV5647_EXPOSURE_DEFAULT 1000 #define OV5647_EXPOSURE_MAX 65535 +/* regulator supplies */ +static const char * const ov5647_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV5647_NUM_SUPPLIES ARRAY_SIZE(ov5647_supply_names) + struct regval_list { u16 addr; u8 data; @@ -120,6 +130,7 @@ struct ov5647 { int power_count; struct clk *xclk; struct gpio_desc *pwdn; + struct regulator_bulk_data supplies[OV5647_NUM_SUPPLIES]; unsigned int flags; struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *pixel_rate; @@ -949,6 +960,13 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) if (on && !ov5647->power_count) { dev_dbg(&client->dev, "OV5647 power on\n"); + ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES, + ov5647->supplies); + if (ret < 0) { + dev_err(&client->dev, "Failed to enable regulators\n"); + goto out; + } + if (ov5647->pwdn) { gpiod_set_value_cansleep(ov5647->pwdn, 0); msleep(PWDN_ACTIVE_DELAY_MS); @@ -956,6 +974,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) ret = clk_prepare_enable(ov5647->xclk); if (ret < 0) { + regulator_bulk_disable(OV5647_NUM_SUPPLIES, + ov5647->supplies); dev_err(&client->dev, "clk prepare enable failed\n"); goto out; } @@ -964,6 +984,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) ARRAY_SIZE(sensor_oe_enable_regs)); if (ret < 0) { clk_disable_unprepare(ov5647->xclk); + regulator_bulk_disable(OV5647_NUM_SUPPLIES, + ov5647->supplies); dev_err(&client->dev, "write sensor_oe_enable_regs error\n"); goto out; @@ -975,6 +997,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) ret = ov5647_stream_off(sd); if (ret < 0) { clk_disable_unprepare(ov5647->xclk); + regulator_bulk_disable(OV5647_NUM_SUPPLIES, + ov5647->supplies); dev_err(&client->dev, "Camera not available, check Power\n"); goto out; @@ -999,6 +1023,8 @@ static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) clk_disable_unprepare(ov5647->xclk); gpiod_set_value_cansleep(ov5647->pwdn, 1); + + regulator_bulk_disable(OV5647_NUM_SUPPLIES, ov5647->supplies); } /* Update the power count. */ @@ -1557,6 +1583,18 @@ static const struct v4l2_ctrl_ops ov5647_ctrl_ops = { .s_ctrl = ov5647_s_ctrl, }; +static int ov5647_configure_regulators(struct device *dev, + struct ov5647 *ov5647) +{ + unsigned int i; + + for (i = 0; i < OV5647_NUM_SUPPLIES; i++) + ov5647->supplies[i].supply = ov5647_supply_names[i]; + + return devm_regulator_bulk_get(dev, OV5647_NUM_SUPPLIES, + ov5647->supplies); +} + static int ov5647_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -1597,6 +1635,12 @@ static int ov5647_probe(struct i2c_client *client) sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn", GPIOD_OUT_HIGH); + ret = ov5647_configure_regulators(dev, sensor); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + mutex_init(&sensor->lock); /* Initialise controls. */ @@ -1701,6 +1745,12 @@ static int ov5647_probe(struct i2c_client *client) if (ret < 0) goto mutex_remove; + ret = regulator_bulk_enable(OV5647_NUM_SUPPLIES, sensor->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto error; + } + if (sensor->pwdn) { gpiod_set_value_cansleep(sensor->pwdn, 0); msleep(PWDN_ACTIVE_DELAY_MS); @@ -1711,7 +1761,7 @@ static int ov5647_probe(struct i2c_client *client) gpiod_set_value_cansleep(sensor->pwdn, 1); if (ret < 0) - goto error; + goto power_down; ret = v4l2_async_register_subdev(sd); if (ret < 0) @@ -1719,6 +1769,8 @@ static int ov5647_probe(struct i2c_client *client) dev_dbg(dev, "OmniVision OV5647 camera driver probed\n"); return 0; +power_down: + regulator_bulk_disable(OV5647_NUM_SUPPLIES, sensor->supplies); error: media_entity_cleanup(&sd->entity); mutex_remove: -- Gitee From 52ad9222125865a1026d3a7cc065150ffc59dac0 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 22 Nov 2021 12:30:18 +0000 Subject: [PATCH 107/155] dtoverlays: Convert ov5647 to use the regulator framework Fixing up shutdown GPIOs via overrides is ugly, and doesn't work on eg CM4 where both cameras share the same shutdown GPIO. The driver is now updated to use the regulator framework, so switch to using that instead. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/ov5647-overlay.dts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts index a7b4085d4e57..018d424a0f71 100644 --- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts @@ -18,9 +18,12 @@ reg = <0x36>; status = "okay"; - pwdn-gpios = <&gpio 41 1>, <&gpio 32 1>; clocks = <&cam1_clk>; + avdd-supply = <&cam1_reg>; + dovdd-supply = <&cam_dummy_reg>; + dvdd-supply = <&cam_dummy_reg>; + rotation = <0>; orientation = <2>; @@ -67,12 +70,9 @@ }; fragment@4 { - target-path="/__overrides__"; + target = <&cam1_reg>; __overlay__ { - cam0-pwdn-ctrl = <&ov5647>,"pwdn-gpios:0"; - cam0-pwdn = <&ov5647>,"pwdn-gpios:4"; - cam0-led-ctrl = <&ov5647>,"pwdn-gpios:12"; - cam0-led = <&ov5647>,"pwdn-gpios:16"; + startup-delay-us = <20000>; }; }; -- Gitee From 87578ef2643c377abb13ac8ad2134a0f30434cae Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 14 Dec 2021 17:18:49 +0000 Subject: [PATCH 108/155] media: i2c: ov7251: Make the enable GPIO optional. Not all implementations wire up the enable GPIO and may just tie it to a supply rail. Make it optional. Signed-off-by: Dave Stevenson --- drivers/media/i2c/ov7251.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 2c554626319d..f2d77aaed798 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1331,7 +1331,8 @@ static int ov7251_probe(struct i2c_client *client) return PTR_ERR(ov7251->analog_regulator); } - ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); + ov7251->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_HIGH); if (IS_ERR(ov7251->enable_gpio)) { dev_err(dev, "cannot get enable gpio\n"); return PTR_ERR(ov7251->enable_gpio); -- Gitee From 0f7bfb1e9fc8b29c5f99b96c0a2a2652c04b32f7 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 14 Dec 2021 14:54:15 +0000 Subject: [PATCH 109/155] ARM: dts: bcm2711-cm4s Correct i2c0mux to use 0/1 and 28/29 & 2 regulators CM4S follows CM1/3, so based on the documentation cameras/displays connect to 0/1 and 28/29, not 0/1 and 44/45. Likewise the camera regulator controls are independent as on CM1/3. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/bcm2711-rpi-cm4s.dts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts index c4c2ed3ec52a..e5e3202feb34 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts @@ -204,8 +204,7 @@ #include "bcm2711-rpi.dtsi" #include "bcm283x-rpi-csi0-2lane.dtsi" #include "bcm283x-rpi-csi1-4lane.dtsi" -#include "bcm283x-rpi-i2c0mux_0_44.dtsi" -#include "bcm283x-rpi-cam1-regulator.dtsi" +#include "bcm283x-rpi-i2c0mux_0_28.dtsi" /delete-node/ &hdmi1; @@ -214,6 +213,21 @@ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; }; + cam1_reg: cam1_reg { + compatible = "regulator-fixed"; + regulator-name = "cam1-regulator"; + gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + status = "disabled"; + }; + cam0_reg: cam0_reg { + compatible = "regulator-fixed"; + regulator-name = "cam0-regulator"; + gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; + enable-active-high; + status = "disabled"; + }; + aliases { serial0 = &uart0; mmc0 = &emmc2; -- Gitee From 42fa4d595645c1099eddcfa976aa156670d37bc6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 22 Nov 2021 12:44:29 +0000 Subject: [PATCH 110/155] dtoverlays: Add option to select camera as on CAM0 of CM Parameterise the overlays so that they can have an optional cam0 parameter to switch to i2c_vc and csi0. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 + arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 4 + arch/arm/boot/dts/bcm2710-rpi-cm3.dts | 5 ++ arch/arm/boot/dts/bcm2711-rpi-cm4s.dts | 25 +++--- arch/arm/boot/dts/overlays/README | 30 +++++++ arch/arm/boot/dts/overlays/imx219-overlay.dts | 67 ++++++++------- .../boot/dts/overlays/imx290_327-overlay.dtsi | 27 +++--- .../boot/dts/overlays/imx477_378-overlay.dtsi | 84 +++++++++---------- arch/arm/boot/dts/overlays/imx519-overlay.dts | 23 +++-- .../arm/boot/dts/overlays/irs1125-overlay.dts | 35 ++++---- arch/arm/boot/dts/overlays/ov5647-overlay.dts | 33 +++----- arch/arm/boot/dts/overlays/ov7251-overlay.dts | 28 +++---- arch/arm/boot/dts/overlays/ov9281-overlay.dts | 29 ++++--- .../boot/dts/overlays/tc358743-overlay.dts | 43 ++++------ 14 files changed, 221 insertions(+), 213 deletions(-) diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dts b/arch/arm/boot/dts/bcm2708-rpi-cm.dts index d65f9db354dd..863bd207e323 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts +++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts @@ -12,6 +12,7 @@ &cam1_reg { gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; + status = "disabled"; }; cam0_reg: &cam0_regulator { diff --git a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi index d5572b2d2103..dd59f884d796 100644 --- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi +++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi @@ -14,5 +14,9 @@ act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; act_led_trigger = <&act_led>,"linux,default-trigger"; + cam0_reg = <&cam0_reg>,"status"; + cam0_reg_gpio = <&cam0_reg>,"gpios:4"; + cam1_reg = <&cam1_reg>,"status"; + cam1_reg_gpio = <&cam1_reg>,"gpios:4"; }; }; diff --git a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts index e3bb24ff99ba..517ed47c257d 100644 --- a/arch/arm/boot/dts/bcm2710-rpi-cm3.dts +++ b/arch/arm/boot/dts/bcm2710-rpi-cm3.dts @@ -12,6 +12,7 @@ &cam1_reg { gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; + status = "disabled"; }; cam0_reg: &cam0_regulator { @@ -137,5 +138,9 @@ cam0_reg: &cam0_regulator { act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; act_led_trigger = <&act_led>,"linux,default-trigger"; + cam0_reg = <&cam0_reg>,"status"; + cam0_reg_gpio = <&cam0_reg>,"gpios:4"; + cam1_reg = <&cam1_reg>,"status"; + cam1_reg_gpio = <&cam1_reg>,"gpios:4"; }; }; diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts index e5e3202feb34..c0808eca28b3 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4s.dts @@ -213,21 +213,6 @@ bootargs = "coherent_pool=1M 8250.nr_uarts=1 snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1"; }; - cam1_reg: cam1_reg { - compatible = "regulator-fixed"; - regulator-name = "cam1-regulator"; - gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; - cam0_reg: cam0_reg { - compatible = "regulator-fixed"; - regulator-name = "cam0-regulator"; - gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; - enable-active-high; - status = "disabled"; - }; - aliases { serial0 = &uart0; mmc0 = &emmc2; @@ -451,6 +436,16 @@ brcm,disable-headphones = <1>; }; +&cam1_reg { + gpio = <&gpio 2 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + +cam0_reg: &cam0_regulator { + gpio = <&gpio 30 GPIO_ACTIVE_HIGH>; + status = "disabled"; +}; + / { __overrides__ { act_led_gpio = <&act_led>,"gpios:4"; diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 4ae0bc9d22ae..7e414672eafd 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -144,6 +144,16 @@ Params: See /sys/kernel/debug/raspberrypi_axi_monitor for the results. + cam0_reg Enables CAM 0 regulator. CM1 & 3 only. + + cam0_reg_gpio Set GPIO for CAM 0 regulator. Default 30. + CM1 & 3 only. + + cam1_reg Enables CAM 1 regulator. CM1 & 3 only. + + cam1_reg_gpio Set GPIO for CAM 1 regulator. Default 2. + CM1 & 3 only. + eee Enable Energy Efficient Ethernet support for compatible devices (default "on"). See also "tx_lpi_timer". Pi3B+ only. @@ -1845,6 +1855,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: imx290 @@ -1867,6 +1879,8 @@ Params: 4lane Enable 4 CSI2 lanes. This requires a Compute 180, default 0) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: imx378 @@ -1880,6 +1894,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: imx477 @@ -1893,6 +1909,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: imx519 @@ -1906,6 +1924,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: iqaudio-codec @@ -1972,6 +1992,8 @@ Info: Infineon irs1125 TOF camera module. Load: dtoverlay=irs1125,= Params: media-controller Configure use of Media Controller API for configuring the sensor (default off) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: jedec-spi-nor @@ -2385,6 +2407,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: ov7251 @@ -2398,6 +2422,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default off) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: ov9281 @@ -2411,6 +2437,8 @@ Params: rotation Mounting rotation of the camera sensor (0 or 2 = external, default external) media-controller Configure use of Media Controller API for configuring the sensor (default on) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: papirus @@ -3393,6 +3421,8 @@ Params: 4lane Use 4 lanes (only applicable to Compute Modules are supported by the driver. media-controller Configure use of Media Controller API for configuring the sensor (default off) + cam0 Adopt the default configuration for CAM0 on a + Compute Module (CSI0, i2c_vc, and cam0_reg). Name: tc358743-audio diff --git a/arch/arm/boot/dts/overlays/imx219-overlay.dts b/arch/arm/boot/dts/overlays/imx219-overlay.dts index 7e39d4a70abf..bc1217397dd5 100644 --- a/arch/arm/boot/dts/overlays/imx219-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts @@ -9,6 +9,28 @@ compatible = "brcm,bcm2835"; fragment@0 { + target = <&i2c0if>; + __overlay__ { + status = "okay"; + }; + }; + + clk_frag: fragment@1 { + target = <&cam1_clk>; + __overlay__ { + status = "okay"; + clock-frequency = <24000000>; + }; + }; + + fragment@2 { + target = <&i2c0mux>; + __overlay__ { + status = "okay"; + }; + }; + + i2c_frag: fragment@100 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -32,7 +54,7 @@ port { imx219_0: endpoint { - remote-endpoint = <&csi1_ep>; + remote-endpoint = <&csi_ep>; clock-lanes = <0>; data-lanes = <1 2>; clock-noncontinuous; @@ -44,13 +66,14 @@ }; }; - fragment@1 { + csi_frag: fragment@101 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port { - csi1_ep: endpoint { + csi_ep: endpoint { remote-endpoint = <&imx219_0>; clock-lanes = <0>; data-lanes = <1 2>; @@ -60,38 +83,14 @@ }; }; - fragment@2 { - target = <&i2c0if>; - __overlay__ { - status = "okay"; - }; - }; - - fragment@3 { - target = <&cam1_clk>; - __overlay__ { - status = "okay"; - clock-frequency = <24000000>; - }; - }; - - fragment@4 { - target = <&i2c0mux>; - __overlay__ { - status = "okay"; - }; - }; - - fragment@5 { - target = <&csi1>; - __overlay__ { - brcm,media-controller; - }; - }; - __overrides__ { rotation = <&imx219>,"rotation:0"; orientation = <&imx219>,"orientation:0"; - media-controller = <0>,"=5"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&imx219>, "clocks:0=",<&cam0_clk>, + <&imx219>, "VANA-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi index ba3f11631973..111d69597554 100644 --- a/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx290_327-overlay.dtsi @@ -9,7 +9,7 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -41,10 +41,11 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port { csi1_ep: endpoint { @@ -61,9 +62,9 @@ }; }; - fragment@3 { + clk_frag: fragment@3 { target = <&cam1_clk>; - __overlay__ { + cam_clk: __overlay__ { status = "okay"; clock-frequency = <37125000>; }; @@ -108,19 +109,17 @@ }; }; - fragment@10 { - target = <&csi1>; - __overlay__ { - brcm,media-controller; - }; - }; - __overrides__ { 4lane = <0>, "-6+7-8+9"; - clock-frequency = <&cam1_clk>,"clock-frequency:0", + clock-frequency = <&cam_clk>,"clock-frequency:0", <&imx290>,"clock-frequency:0"; rotation = <&imx290>,"rotation:0"; orientation = <&imx290>,"orientation:0"; - media-controller = <0>,"=10"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&imx290>, "clocks:0=",<&cam0_clk>, + <&imx290>, "vdda-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi index 433ab1958a15..bfea40ce98d6 100644 --- a/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi +++ b/arch/arm/boot/dts/overlays/imx477_378-overlay.dtsi @@ -4,7 +4,36 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + fragment@2 { + target = <&i2c0if>; + __overlay__ { + status = "okay"; + }; + }; + + clk_frag: fragment@3 { + target = <&cam1_clk>; + cam_clk: __overlay__ { + clock-frequency = <24000000>; + status = "okay"; + }; + }; + + fragment@4 { + target = <&i2c0mux>; + __overlay__ { + status = "okay"; + }; + }; + + reg_frag: fragment@5 { + target = <&cam1_reg>; + cam_reg: __overlay__ { + startup-delay-us = <300000>; + }; + }; + + i2c_frag: fragment@100 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -27,7 +56,7 @@ port { imx477_0: endpoint { - remote-endpoint = <&csi1_ep>; + remote-endpoint = <&csi_ep>; clock-lanes = <0>; data-lanes = <1 2>; clock-noncontinuous; @@ -39,13 +68,14 @@ }; }; - fragment@1 { + csi_frag: fragment@101 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port { - csi1_ep: endpoint { + csi_ep: endpoint { remote-endpoint = <&imx477_0>; clock-lanes = <0>; data-lanes = <1 2>; @@ -55,45 +85,15 @@ }; }; - fragment@2 { - target = <&i2c0if>; - __overlay__ { - status = "okay"; - }; - }; - - fragment@3 { - target = <&cam1_clk>; - __overlay__ { - clock-frequency = <24000000>; - status = "okay"; - }; - }; - - fragment@4 { - target = <&i2c0mux>; - __overlay__ { - status = "okay"; - }; - }; - - fragment@5 { - target = <&cam1_reg>; - __overlay__ { - startup-delay-us = <300000>; - }; - }; - - fragment@6 { - target = <&csi1>; - __overlay__ { - brcm,media-controller; - }; - }; - __overrides__ { rotation = <&imx477>,"rotation:0"; orientation = <&imx477>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <®_frag>, "target:0=",<&cam0_reg>, + <&imx477>, "clocks:0=",<&cam0_clk>, + <&imx477>, "vdda-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/imx519-overlay.dts b/arch/arm/boot/dts/overlays/imx519-overlay.dts index dfc54ea34396..ada1224dd19b 100644 --- a/arch/arm/boot/dts/overlays/imx519-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx519-overlay.dts @@ -8,7 +8,7 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -44,10 +44,11 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port{ csi1_ep: endpoint{ @@ -67,7 +68,7 @@ }; }; - fragment@3 { + clk_frag: fragment@3 { target = <&cam1_clk>; __overlay__ { clock-frequency = <24000000>; @@ -82,16 +83,14 @@ }; }; - fragment@6 { - target = <&csi1>; - __overlay__ { - brcm,media-controller; - }; - }; - __overrides__ { rotation = <&imx519>,"rotation:0"; orientation = <&imx519>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&imx519>, "clocks:0=",<&cam0_clk>, + <&imx519>, "VANA-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/irs1125-overlay.dts b/arch/arm/boot/dts/overlays/irs1125-overlay.dts index 065569830ded..0cdef42c3d16 100644 --- a/arch/arm/boot/dts/overlays/irs1125-overlay.dts +++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts @@ -6,20 +6,20 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; #size-cells = <0>; status = "okay"; - irs1125: irs1125@3D { + irs1125: irs1125@3d { compatible = "infineon,irs1125"; - reg = <0x3D>; + reg = <0x3d>; status = "okay"; pwdn-gpios = <&gpio 5 0>; - clocks = <&irs1125_clk>; + clocks = <&cam1_clk>; port { irs1125_0: endpoint { @@ -35,9 +35,9 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; port { @@ -72,25 +72,18 @@ }; }; - fragment@5 { - target-path = "/"; + clk_frag: fragment@5 { + target = <&cam1_clk>; __overlay__ { - irs1125_clk: camera-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <26000000>; - }; - }; - }; - - fragment@6 { - target = <&csi1>; - __dormant__ { - brcm,media-controller; + clock-frequency = <26000000>; }; }; __overrides__ { - media-controller = <0>,"=6"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&irs1125>, "clocks:0=",<&cam0_clk>; }; }; diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts index 018d424a0f71..a1221024d334 100644 --- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts @@ -6,7 +6,7 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -41,10 +41,11 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port { csi1_ep: endpoint { @@ -69,14 +70,14 @@ }; }; - fragment@4 { + reg_frag: fragment@4 { target = <&cam1_reg>; __overlay__ { startup-delay-us = <20000>; }; }; - fragment@5 { + clk_frag: fragment@5 { target = <&cam1_clk>; __overlay__ { status = "okay"; @@ -84,23 +85,15 @@ }; }; - fragment@6 { - target = <&csi1>; - __overlay__ { - brcm,media-controller; - }; - }; - - fragment@7 { - target = <&cam1_reg>; - __overlay__ { - status = "disabled"; - }; - }; - __overrides__ { rotation = <&ov5647>,"rotation:0"; orientation = <&ov5647>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <®_frag>, "target:0=",<&cam0_reg>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&ov5647>, "clocks:0=",<&cam0_clk>, + <&ov5647>, "avdd-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/ov7251-overlay.dts b/arch/arm/boot/dts/overlays/ov7251-overlay.dts index 0cf9966a48bf..0e44be8a4468 100644 --- a/arch/arm/boot/dts/overlays/ov7251-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov7251-overlay.dts @@ -8,7 +8,7 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -45,9 +45,9 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; port { @@ -67,30 +67,28 @@ }; fragment@3 { - target = <&cam1_clk>; + target = <&i2c0mux>; __overlay__ { status = "okay"; - clock-frequency = <24000000>; }; }; - fragment@4 { - target = <&i2c0mux>; + clk_frag: fragment@4 { + target = <&cam1_clk>; __overlay__ { status = "okay"; - }; - }; - - fragment@6 { - target = <&csi1>; - __dormant__ { - brcm,media-controller; + clock-frequency = <24000000>; }; }; __overrides__ { rotation = <&ov7251>,"rotation:0"; orientation = <&ov7251>,"orientation:0"; - media-controller = <0>,"=6"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&ov7251>, "clocks:0=",<&cam0_clk>, + <&ov7251>, "vdda-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/ov9281-overlay.dts b/arch/arm/boot/dts/overlays/ov9281-overlay.dts index 35d9f79980fe..8c08a3a1077c 100644 --- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts @@ -8,7 +8,7 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; @@ -44,10 +44,11 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; + brcm,media-controller; port { csi1_ep: endpoint { @@ -67,30 +68,28 @@ }; fragment@3 { - target = <&cam1_clk>; - __overlay__ { - status = "okay"; - clock-frequency = <24000000>; - }; - }; - - fragment@4 { target = <&i2c0mux>; __overlay__ { status = "okay"; }; }; - fragment@5 { - target = <&csi1>; + clk_frag: fragment@4 { + target = <&cam1_clk>; __overlay__ { - brcm,media-controller; + status = "okay"; + clock-frequency = <24000000>; }; }; __overrides__ { rotation = <&ov9281>,"rotation:0"; orientation = <&ov9281>,"orientation:0"; - media-controller = <0>,"=5"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&ov9281>, "clocks:0=",<&cam0_clk>, + <&ov9281>, "avdd-supply:0=",<&cam0_reg>; }; }; diff --git a/arch/arm/boot/dts/overlays/tc358743-overlay.dts b/arch/arm/boot/dts/overlays/tc358743-overlay.dts index d679d9ba84b6..c85782688e39 100644 --- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts +++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts @@ -6,23 +6,23 @@ /{ compatible = "brcm,bcm2835"; - fragment@0 { + i2c_frag: fragment@0 { target = <&i2c_csi_dsi>; __overlay__ { #address-cells = <1>; #size-cells = <0>; status = "okay"; - tc358743@0f { + tc358743: tc358743@f { compatible = "toshiba,tc358743"; reg = <0x0f>; status = "okay"; - clocks = <&tc358743_clk>; + clocks = <&cam1_clk>; clock-names = "refclk"; port { - tc358743: endpoint { + tc358743_0: endpoint { remote-endpoint = <&csi1_ep>; clock-lanes = <0>; clock-noncontinuous; @@ -34,28 +34,28 @@ }; }; - fragment@1 { + csi_frag: fragment@1 { target = <&csi1>; - __overlay__ { + csi: __overlay__ { status = "okay"; port { csi1_ep: endpoint { - remote-endpoint = <&tc358743>; + remote-endpoint = <&tc358743_0>; }; }; }; }; fragment@2 { - target = <&tc358743>; + target = <&tc358743_0>; __overlay__ { data-lanes = <1 2>; }; }; fragment@3 { - target = <&tc358743>; + target = <&tc358743_0>; __dormant__ { data-lanes = <1 2 3 4>; }; @@ -75,14 +75,10 @@ }; }; - fragment@6 { - target-path = "/"; + clk_frag: fragment@6 { + target = <&cam1_clk>; __overlay__ { - tc358743_clk: bridge-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <27000000>; - }; + clock-frequency = <27000000>; }; }; @@ -100,16 +96,13 @@ }; }; - fragment@9 { - target = <&csi1>; - __dormant__ { - brcm,media-controller; - }; - }; - __overrides__ { 4lane = <0>, "-2+3-7+8"; - link-frequency = <&tc358743>,"link-frequencies#0"; - media-controller = <0>,"=9"; + link-frequency = <&tc358743_0>,"link-frequencies#0"; + media-controller = <&csi>,"brcm,media-controller?"; + cam0 = <&i2c_frag>, "target:0=",<&i2c_vc>, + <&csi_frag>, "target:0=",<&csi0>, + <&clk_frag>, "target:0=",<&cam0_clk>, + <&tc358743>, "clocks:0=",<&cam0_clk>; }; }; -- Gitee From 728ae66713ced2b6f1b8489b296ab8ddf2d52327 Mon Sep 17 00:00:00 2001 From: Joerg Schambacher Date: Wed, 15 Dec 2021 19:27:00 +0100 Subject: [PATCH 111/155] ASoC:ma120x0p: Increase maximum sample rate to 192KHz Change the maximum sample rate for the amplifier to 192KHz as given in the Infineon specification. Signed-off-by: Joerg Schambacher --- sound/soc/codecs/ma120x0p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ma120x0p.c b/sound/soc/codecs/ma120x0p.c index e1591b6aff43..c447d37450b7 100644 --- a/sound/soc/codecs/ma120x0p.c +++ b/sound/soc/codecs/ma120x0p.c @@ -1002,7 +1002,7 @@ static struct snd_soc_dai_driver ma120x0p_dai = { .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 44100, - .rate_max = 96000, + .rate_max = 192000, .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE }, .ops = &ma120x0p_dai_ops, -- Gitee From f631a091d081d25364a758fe23e8ffce39e213d3 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Thu, 16 Dec 2021 12:11:54 +0000 Subject: [PATCH 112/155] Revert "kbuild: Disable gcc plugins" This reverts commit d62b4f2f5742bf39892acf8c6804fffee174d371. --- scripts/gcc-plugin.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh index c3d0c8fedbdd..b79fd0bea838 100755 --- a/scripts/gcc-plugin.sh +++ b/scripts/gcc-plugin.sh @@ -1,6 +1,5 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 -exit 1 # Disable plugins set -e -- Gitee From 9fc962bdf0e9c47f5bc4f8f01242917004f8e0fe Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Thu, 16 Dec 2021 14:22:37 +0000 Subject: [PATCH 113/155] Revert "media: bcm2835-codec: Limit video callbacks" This reverts commit f814bfc5f4d3005eb266a1556be8b7b8770629bd. The commit caused media stalls with kodi and stateful v4l2 video decode. John is now using a different way of limiting latency through stateful v4l2 so this is not required. --- .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index 4cd940211b54..fdbaa96c25a0 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -2536,14 +2536,6 @@ static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx) MMAL_PARAMETER_VIDEO_STOP_ON_PAR_COLOUR_CHANGE, &enable, sizeof(enable)); - - enable = (unsigned int)-5; - vchiq_mmal_port_parameter_set(dev->instance, - &ctx->component->control, - MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS, - &enable, - sizeof(enable)); - } else if (dev->role == DEINTERLACE) { /* Select the default deinterlace algorithm. */ int half_framerate = 0; -- Gitee From 3d77b98d04bb0157b8d404ee028e65d4dcd38b20 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 16 Dec 2021 16:25:00 +0000 Subject: [PATCH 114/155] staging/bcm2835-isp: Fix cleanup after init fail bcm2835_isp_remove is called on an initialisation failure, but at that point the drvdata hasn't been set. This causes a crash when e.g. using the cutdown firmware (gpu_mem=16). Move platform_set_drvdata before the instance probing loop to avoid the problem. See: https://github.com/raspberrypi/linux/issues/4774 Signed-off-by: Phil Elwell --- drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c index 5a0245b70b11..8166f8e62347 100644 --- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c @@ -1774,6 +1774,8 @@ static int bcm2835_isp_probe(struct platform_device *pdev) if (!bcm2835_isp_instances) return -ENOMEM; + platform_set_drvdata(pdev, bcm2835_isp_instances); + for (i = 0; i < BCM2835_ISP_NUM_INSTANCES; i++) { ret = bcm2835_isp_probe_instance(pdev, &bcm2835_isp_instances[i], i); @@ -1781,7 +1783,6 @@ static int bcm2835_isp_probe(struct platform_device *pdev) goto error; } - platform_set_drvdata(pdev, bcm2835_isp_instances); dev_info(&pdev->dev, "Loaded V4L2 %s\n", BCM2835_ISP_NAME); return 0; -- Gitee From d4e53c1e243b178e06984b7599cae342c3bcc1eb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 13 Dec 2021 13:47:51 +0100 Subject: [PATCH 115/155] drm/edid: Don't clear YUV422 if using deep color The current code, when parsing the EDID Deep Color depths, that the YUV422 cannot be used, referring to the HDMI 1.3 Specification. This specification, in its section 6.2.4, indeed states: For each supported Deep Color mode, RGB 4:4:4 shall be supported and optionally YCBCR 4:4:4 may be supported. YCBCR 4:2:2 is not permitted for any Deep Color mode. This indeed can be interpreted like the code does, but the HDMI 1.4 specification further clarifies that statement in its section 6.2.4: For each supported Deep Color mode, RGB 4:4:4 shall be supported and optionally YCBCR 4:4:4 may be supported. YCBCR 4:2:2 is also 36-bit mode but does not require the further use of the Deep Color modes described in section 6.5.2 and 6.5.3. This means that, even though YUV422 can be used with 12 bit per color, it shouldn't be treated as a deep color mode. This deviates from the interpretation of the code and comment, so let's fix those. Fixes: d0c94692e0a3 ("drm/edid: Parse and handle HDMI deep color modes.") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_edid.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index add317bd8d55..30b52a3c8f36 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4961,10 +4961,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, /* * Deep color support mandates RGB444 support for all video - * modes and forbids YCRCB422 support for all video modes per - * HDMI 1.3 spec. + * modes. */ - info->color_formats = DRM_COLOR_FORMAT_RGB444; + info->color_formats |= DRM_COLOR_FORMAT_RGB444; /* YCRCB444 is optional according to spec. */ if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { -- Gitee From 9cad0a17032479473b1199bce6922c78ca43f1a7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 14 Apr 2021 16:21:08 +0200 Subject: [PATCH 116/155] drm/edid: Rename drm_hdmi_avi_infoframe_colorspace to _colorimetry The drm_hdmi_avi_infoframe_colorspace() function actually sets the colorimetry and extended_colorimetry fields in the hdmi_avi_infoframe structure with DRM_MODE_COLORIMETRY_* values. To make things worse, the hdmi_avi_infoframe structure also has a colorspace field used to signal whether an RGB or YUV output is being used. Let's remove the inconsistency and allow for the colorspace usage by renaming the function. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/drm_edid.c | 8 ++++---- drivers/gpu/drm/i915/display/intel_hdmi.c | 2 +- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- include/drm/drm_edid.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 30b52a3c8f36..46e41ad5e44f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5711,13 +5711,13 @@ static const u32 hdmi_colorimetry_val[] = { #undef ACE /** - * drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe - * colorspace information + * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe + * colorimetry information * @frame: HDMI AVI infoframe * @conn_state: connector state */ void -drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, +drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state) { u32 colorimetry_val; @@ -5736,7 +5736,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, frame->extended_colorimetry = (colorimetry_val >> 2) & EXTENDED_COLORIMETRY_MASK; } -EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); +EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); /** * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index bf4da68260b9..030b4d5ab829 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -746,7 +746,7 @@ intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, else frame->colorspace = HDMI_COLORSPACE_RGB; - drm_hdmi_avi_infoframe_colorspace(frame, conn_state); + drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); /* nonsense combination */ drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b621fc3b1750..09ec4c1d1ac7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -521,7 +521,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) vc4_encoder->limited_rgb_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL); - drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate); + drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); vc4_hdmi_write_infoframe(encoder, &frame); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index e97daf6ffbb1..1d0ace87a6e8 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -371,8 +371,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode); void -drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, - const struct drm_connector_state *conn_state); +drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, + const struct drm_connector_state *conn_state); void drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, -- Gitee From 938bd05d2ce1127f539f8ce4624879972fec0e7a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 12 Jan 2021 15:55:07 +0100 Subject: [PATCH 117/155] drm/vc4: hdmi: Add full range RGB helper We're going to need to tell whether we want to run with a full or limited range RGB output in multiple places in the code, so let's create a helper that will return whether we need with full range or not. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 09ec4c1d1ac7..f4f4489db46e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -108,6 +108,15 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; } +static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, + const struct drm_display_mode *mode) +{ + struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; + + return !vc4_encoder->hdmi_monitor || + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; +} + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *)m->private; @@ -1115,8 +1124,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, mutex_lock(&vc4_hdmi->mutex); - if (vc4_encoder->hdmi_monitor && - drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { if (vc4_hdmi->variant->csc_setup) vc4_hdmi->variant->csc_setup(vc4_hdmi, true); -- Gitee From 551cbcf981060f6e17ad94ef26c2f044342b28ff Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 12 Jan 2021 15:57:50 +0100 Subject: [PATCH 118/155] drm/vc4: hdmi: Use full range helper in csc functions The CSC callbacks takes a boolean as an argument to tell whether we're using the full range or limited range RGB. However, with the upcoming YUV support, the logic will be a bit more complex. In order to address this, let's make the callbacks take the entire mode, and call our new helper to tell whether the full or limited range RGB should be used. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 31 +++++++++++-------------------- drivers/gpu/drm/vc4/vc4_hdmi.h | 4 ++-- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f4f4489db46e..72ecbaf0e333 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -509,7 +509,6 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); struct drm_connector *connector = &vc4_hdmi->connector; struct drm_connector_state *cstate = connector->state; const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; @@ -527,9 +526,9 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) drm_hdmi_avi_infoframe_quant_range(&frame.avi, connector, mode, - vc4_encoder->limited_rgb_range ? - HDMI_QUANTIZATION_RANGE_LIMITED : - HDMI_QUANTIZATION_RANGE_FULL); + vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? + HDMI_QUANTIZATION_RANGE_FULL : + HDMI_QUANTIZATION_RANGE_LIMITED); drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); @@ -751,7 +750,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, mutex_unlock(&vc4_hdmi->mutex); } -static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) +static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, + const struct drm_display_mode *mode) { unsigned long flags; u32 csc_ctl; @@ -761,7 +761,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, VC4_HD_CSC_CTL_ORDER); - if (enable) { + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. * Apply a colorspace conversion to squash 0-255 down @@ -791,7 +791,8 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } -static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) +static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, + const struct drm_display_mode *mode) { unsigned long flags; u32 csc_ctl; @@ -800,7 +801,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - if (enable) { + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. * Apply a colorspace conversion to squash 0-255 down @@ -1119,22 +1120,12 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); unsigned long flags; mutex_lock(&vc4_hdmi->mutex); - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { - if (vc4_hdmi->variant->csc_setup) - vc4_hdmi->variant->csc_setup(vc4_hdmi, true); - - vc4_encoder->limited_rgb_range = true; - } else { - if (vc4_hdmi->variant->csc_setup) - vc4_hdmi->variant->csc_setup(vc4_hdmi, false); - - vc4_encoder->limited_rgb_range = false; - } + if (vc4_hdmi->variant->csc_setup) + vc4_hdmi->variant->csc_setup(vc4_hdmi, mode); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 8fa1d3054eb6..6daecd8a2e1f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -12,7 +12,6 @@ struct vc4_hdmi_encoder { struct vc4_encoder base; bool hdmi_monitor; - bool limited_rgb_range; }; static inline struct vc4_hdmi_encoder * @@ -77,7 +76,8 @@ struct vc4_hdmi_variant { void (*reset)(struct vc4_hdmi *vc4_hdmi); /* Callback to enable / disable the CSC */ - void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); + void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, + const struct drm_display_mode *mode); /* Callback to configure the video timings in the HDMI block */ void (*set_timings)(struct vc4_hdmi *vc4_hdmi, -- Gitee From 8d365b18f0633310b30dcf3c4802485fb816746c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 13 Jan 2021 11:07:48 +0100 Subject: [PATCH 119/155] drm/vc4: hdmi: Move XBAR setup to csc_setup On the BCM2711, the HDMI_VEC_INTERFACE_XBAR register configuration depends on whether we're using an RGB or YUV output. Let's move that configuration to the CSC setup. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 72ecbaf0e333..db3c0961189a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -801,6 +801,8 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); + HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. @@ -915,7 +917,6 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); HDMI_WRITE(HDMI_HORZA, (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | -- Gitee From 3b109aab7f0888f829854703cadf1abb5d1ae672 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 13 Jan 2021 11:20:08 +0100 Subject: [PATCH 120/155] drm/vc4: hdmi: Replace CSC_CTL hardcoded value by defines On BCM2711, the HDMI_CSC_CTL register value has been hardcoded to an opaque value. Let's replace it with properly defined values. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++--- drivers/gpu/drm/vc4/vc4_regs.h | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index db3c0961189a..dd46b687da52 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -795,9 +795,8 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, const struct drm_display_mode *mode) { unsigned long flags; - u32 csc_ctl; - - csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ + u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, + VC5_MT_CP_CSC_CTL_MODE); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 5989b2ff28c7..82d46cf9f298 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -796,6 +796,9 @@ enum { # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) # define VC4_HD_CSC_CTL_ENABLE BIT(0) +# define VC5_MT_CP_CSC_CTL_ENABLE BIT(2) +# define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0) + # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) /* HVS display list information. */ -- Gitee From c898ee37b5082ef921fe5bc263b0795ef8b4c91c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 13 Jan 2021 11:30:21 +0100 Subject: [PATCH 121/155] drm/vc4: hdmi: Define colorspace matrices The current CSC setup code for the BCM2711 uses a sequence of register writes to configure the CSC depending on whether we output using a full or limited range. However, with the upcoming introduction of the YUV output, we're going to add new matrices to perform the conversions, so we should switch to something a bit more flexible that takes the matrix as an argument and programs the CSC accordingly. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 79 +++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index dd46b687da52..f3b29821e746 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -791,6 +791,52 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); } + +/* + * If we need to output Full Range RGB, then use the unity matrix + * + * [ 1 0 0 0] + * [ 0 1 0 0] + * [ 0 0 1 0] + * + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + */ +static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = { + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 }, +}; + +/* + * CEA VICs other than #1 require limited range RGB output unless + * overridden by an AVI infoframe. Apply a colorspace conversion to + * squash 0-255 down to 16-235. The matrix here is: + * + * [ 0.8594 0 0 16] + * [ 0 0.8594 0 16] + * [ 0 0 0.8594 16] + * + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + */ +static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { + { 0x1b80, 0x0000, 0x0000, 0x0400 }, + { 0x0000, 0x1b80, 0x0000, 0x0400 }, + { 0x0000, 0x0000, 0x1b80, 0x0400 }, +}; + +static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, + const u16 coeffs[3][4]) +{ + lockdep_assert_held(&vc4_hdmi->hw_lock); + + HDMI_WRITE(HDMI_CSC_12_11, (coeffs[0][1] << 16) | coeffs[0][0]); + HDMI_WRITE(HDMI_CSC_14_13, (coeffs[0][3] << 16) | coeffs[0][2]); + HDMI_WRITE(HDMI_CSC_22_21, (coeffs[1][1] << 16) | coeffs[1][0]); + HDMI_WRITE(HDMI_CSC_24_23, (coeffs[1][3] << 16) | coeffs[1][2]); + HDMI_WRITE(HDMI_CSC_32_31, (coeffs[2][1] << 16) | coeffs[2][0]); + HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]); +} + static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, const struct drm_display_mode *mode) { @@ -802,35 +848,10 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { - /* CEA VICs other than #1 requre limited range RGB - * output unless overridden by an AVI infoframe. - * Apply a colorspace conversion to squash 0-255 down - * to 16-235. The matrix here is: - * - * [ 0.8594 0 0 16] - * [ 0 0.8594 0 16] - * [ 0 0 0.8594 16] - * [ 0 0 0 1] - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets - */ - HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); - HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); - } else { - /* Still use the matrix for full range, but make it unity. - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets - */ - HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); - HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); - HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); - } + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); + else + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); -- Gitee From 2ea8e9f7067fd8e6135db60b73b012ddf3f700df Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 Jan 2021 09:51:12 +0100 Subject: [PATCH 122/155] drm/vc4: hdmi: Change CSC callback prototype In order to support the YUV output, we'll need the atomic state to know what is the state of the associated property in the CSC setup callback. Let's change the prototype of that callback to allow us to access it. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 7 ++++++- drivers/gpu/drm/vc4/vc4_hdmi.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f3b29821e746..1eee9e09f3e8 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -751,6 +751,7 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, } static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, const struct drm_display_mode *mode) { unsigned long flags; @@ -838,6 +839,7 @@ static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, } static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, const struct drm_display_mode *mode) { unsigned long flags; @@ -1140,13 +1142,16 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_connector *connector = &vc4_hdmi->connector; struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; + struct drm_connector_state *conn_state = + drm_atomic_get_new_connector_state(state, connector); unsigned long flags; mutex_lock(&vc4_hdmi->mutex); if (vc4_hdmi->variant->csc_setup) - vc4_hdmi->variant->csc_setup(vc4_hdmi, mode); + vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 6daecd8a2e1f..6c354eb47261 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -77,6 +77,7 @@ struct vc4_hdmi_variant { /* Callback to enable / disable the CSC */ void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, + struct drm_connector_state *state, const struct drm_display_mode *mode); /* Callback to configure the video timings in the HDMI block */ -- Gitee From 6ebeb35c3dc7eb1d91f62bfa0b7579a706c8938e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Dec 2021 16:58:17 +0100 Subject: [PATCH 123/155] drm/vc4: hdmi: Move clock validation to its own function Our code is doing the same clock rate validation in multiple instances. Let's create a helper to share the rate validation. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1eee9e09f3e8..addbec7af86e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1249,6 +1249,19 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, mutex_unlock(&vc4_hdmi->mutex); } +static enum drm_mode_status +vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, + unsigned long long clock) +{ + if (clock > vc4_hdmi->variant->max_pixel_clock) + return MODE_CLOCK_HIGH; + + if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL #define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL @@ -1293,10 +1306,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, if (mode->flags & DRM_MODE_FLAG_DBLCLK) pixel_rate = pixel_rate * 2; - if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) - return -EINVAL; - - if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK)) + if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, pixel_rate) != MODE_OK) return -EINVAL; vc4_state->pixel_rate = pixel_rate; @@ -1316,13 +1326,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, (mode->hsync_end % 2) || (mode->htotal % 2))) return MODE_H_ILLEGAL; - if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) - return MODE_CLOCK_HIGH; - - if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode)) - return MODE_CLOCK_HIGH; - - return MODE_OK; + return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000); } static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { -- Gitee From 25e3737c68a5a92debb62a076833f24fea7c61b0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 2 Dec 2021 17:04:18 +0100 Subject: [PATCH 124/155] drm/vc4: hdmi: Move clock calculation into its own function The code to compute our clock rate for a given setup will be called in multiple places in the next patches, so let's create a separate function for it. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 49 +++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index addbec7af86e..845635166740 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1262,6 +1262,35 @@ vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, return MODE_OK; } +static unsigned long long +vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, + unsigned int bpc) +{ + unsigned long long clock = mode->crtc_clock * 1000; + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + clock = clock * 2; + + return clock * bpc / 8; +} + +static int +vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *vc4_state, + const struct drm_display_mode *mode, + unsigned int bpc) +{ + unsigned long long clock; + + clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc); + if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK) + return -EINVAL; + + vc4_state->pixel_rate = clock; + + return 0; +} + #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL #define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL @@ -1274,6 +1303,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); unsigned long long pixel_rate = mode->clock * 1000; unsigned long long tmds_rate; + int ret; if (vc4_hdmi->variant->unsupported_odd_h_timings && !(mode->flags & DRM_MODE_FLAG_DBLCLK) && @@ -1295,21 +1325,10 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, pixel_rate = mode->clock * 1000; } - if (conn_state->max_bpc == 12) { - pixel_rate = pixel_rate * 150; - do_div(pixel_rate, 100); - } else if (conn_state->max_bpc == 10) { - pixel_rate = pixel_rate * 125; - do_div(pixel_rate, 100); - } - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - pixel_rate = pixel_rate * 2; - - if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, pixel_rate) != MODE_OK) - return -EINVAL; - - vc4_state->pixel_rate = pixel_rate; + ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, mode, + conn_state->max_bpc); + if (ret) + return ret; return 0; } -- Gitee From 21755811c5aaacccde0c980c671a3ee906faaa37 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 13 Dec 2021 15:33:11 +0100 Subject: [PATCH 125/155] drm/vc4: hdmi: Take the sink maximum TMDS clock into account In the function that validates that the clock isn't too high, we've only taken our controller limitations into account so far. However, the sink can have a limit on the maximum TMDS clock it can deal with too which is exposed through the EDID and the drm_display_info. Make sure we check it. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 845635166740..a5cada08ad64 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1253,12 +1253,18 @@ static enum drm_mode_status vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, unsigned long long clock) { + const struct drm_connector *connector = &vc4_hdmi->connector; + const struct drm_display_info *info = &connector->display_info; + if (clock > vc4_hdmi->variant->max_pixel_clock) return MODE_CLOCK_HIGH; if (vc4_hdmi->disable_4kp60 && clock > HDMI_14_MAX_TMDS_CLK) return MODE_CLOCK_HIGH; + if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000)) + return MODE_CLOCK_HIGH; + return MODE_OK; } -- Gitee From ab774a35b12f53d303e55e9be497855d3653a3d7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 10 Dec 2021 15:00:04 +0100 Subject: [PATCH 126/155] drm/vc4: hdmi: Take bpp into account for the scrambler The current code only base its decision for whether the scrambler must be enabled or not on the pixel clock of the mode, but doesn't take the bits per color into account. Let's leverage the new function to compute the clock rate in the scrambler setup code. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 17 +++++++++++++---- drivers/gpu/drm/vc4/vc4_hdmi.h | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index a5cada08ad64..998f1fc294db 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -103,9 +103,17 @@ #define CEC_CLOCK_FREQ 40000 #define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) -static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) + +static unsigned long long +vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, + unsigned int bpc); + +static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, + unsigned int bpc) { - return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; + unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc); + + return clock > HDMI_14_MAX_TMDS_CLK; } static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, @@ -281,7 +289,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode; list_for_each_entry(mode, &connector->probed_modes, head) { - if (vc4_hdmi_mode_needs_scrambling(mode)) { + if (vc4_hdmi_mode_needs_scrambling(mode, 8)) { drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz."); drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60."); } @@ -635,7 +643,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) if (!vc4_hdmi_supports_scrambling(encoder, mode)) return; - if (!vc4_hdmi_mode_needs_scrambling(mode)) + if (!vc4_hdmi_mode_needs_scrambling(mode, vc4_hdmi->output_bpc)) return; drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); @@ -1243,6 +1251,7 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_bpc = conn_state->max_bpc; memcpy(&vc4_hdmi->saved_adjusted_mode, &crtc_state->adjusted_mode, sizeof(vc4_hdmi->saved_adjusted_mode)); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 6c354eb47261..e13e681f61d4 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -229,6 +229,11 @@ struct vc4_hdmi { * the scrambler on? Protected by @mutex. */ bool scdc_enabled; + + /** + * @output_bpc: BPC currently being used. Protected by @mutex. + */ + unsigned int output_bpc; }; static inline struct vc4_hdmi * -- Gitee From 891915437ee6b0cb03fda694475b38e5fb6f8ccf Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 10 Dec 2021 15:29:56 +0100 Subject: [PATCH 127/155] drm/vc4: hdmi: Always try to have the highest bpc Currently we take the max_bpc property as the bpc value and do not try anything else. However, what the other drivers seem to be doing is that they would try with the highest bpc allowed by the max_bpc property and the hardware capabilities, test if it results in an acceptable configuration, and if not decrease the bpc and try again. Let's use the same logic. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 44 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/vc4/vc4_hdmi.h | 4 +++- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 998f1fc294db..1b7ffc6ab885 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -361,6 +361,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) return NULL; new_state->pixel_rate = vc4_state->pixel_rate; + new_state->output_bpc = vc4_state->output_bpc; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -923,6 +924,8 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, struct drm_display_mode *mode) { + const struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(state); bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; @@ -970,7 +973,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_VERTB0, vertb_even); HDMI_WRITE(HDMI_VERTB1, vertb); - switch (state->max_bpc) { + switch (vc4_state->output_bpc) { case 12: gcp = 6; gcp_en = true; @@ -1249,9 +1252,11 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(conn_state); mutex_lock(&vc4_hdmi->mutex); - vc4_hdmi->output_bpc = conn_state->max_bpc; + vc4_hdmi->output_bpc = vc4_state->output_bpc; memcpy(&vc4_hdmi->saved_adjusted_mode, &crtc_state->adjusted_mode, sizeof(vc4_hdmi->saved_adjusted_mode)); @@ -1306,6 +1311,38 @@ vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, return 0; } +static int +vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *vc4_state, + const struct drm_display_mode *mode) +{ + struct drm_connector_state *conn_state = &vc4_state->base; + unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12); + unsigned int bpc; + int ret; + + for (bpc = max_bpc; bpc >= 8; bpc -= 2) { + drm_dbg(dev, "Trying with a %d bpc output\n", bpc); + + ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, + mode, bpc); + if (ret) + continue; + + vc4_state->output_bpc = bpc; + + drm_dbg(dev, + "Mode %ux%u @ %uHz: Found configuration: bpc: %u, clock: %llu\n", + mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), + vc4_state->output_bpc, + vc4_state->pixel_rate); + + break; + } + + return ret; +} + #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL #define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL @@ -1340,8 +1377,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, pixel_rate = mode->clock * 1000; } - ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, mode, - conn_state->max_bpc); + ret = vc4_hdmi_encoder_compute_config(vc4_hdmi, vc4_state, mode); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index e13e681f61d4..fd4a793fd8be 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -231,7 +231,8 @@ struct vc4_hdmi { bool scdc_enabled; /** - * @output_bpc: BPC currently being used. Protected by @mutex. + * @output_bpc: Copy of @vc4_connector_state.output_bpc for use + * outside of KMS hooks. Protected by @mutex. */ unsigned int output_bpc; }; @@ -253,6 +254,7 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder) struct vc4_hdmi_connector_state { struct drm_connector_state base; unsigned long long pixel_rate; + unsigned int output_bpc; }; static inline struct vc4_hdmi_connector_state * -- Gitee From 8f1cc1d9d591cf790e9a8d9d98cd46e3390b821b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 4 Dec 2020 17:12:06 +0100 Subject: [PATCH 128/155] drm/vc4: hdmi: Support HDMI YUV output In addition to the RGB444 output, the BCM2711 HDMI controller supports the YUV444 and YUV422 output formats. Let's add support for them in the driver, but still use RGB as the preferred format. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 289 ++++++++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_hdmi.h | 14 ++ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 6 + drivers/gpu/drm/vc4/vc4_regs.h | 16 ++ 4 files changed, 309 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1b7ffc6ab885..e9f726ca92df 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -103,15 +103,30 @@ #define CEC_CLOCK_FREQ 40000 #define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) +static const char * const output_format_str[] = { + [VC4_HDMI_OUTPUT_RGB] = "RGB", + [VC4_HDMI_OUTPUT_YUV420] = "YUV 4:2:0", + [VC4_HDMI_OUTPUT_YUV422] = "YUV 4:2:2", + [VC4_HDMI_OUTPUT_YUV444] = "YUV 4:4:4", +}; + +static const char *vc4_hdmi_output_fmt_str(enum vc4_hdmi_output_format fmt) +{ + if (fmt >= ARRAY_SIZE(output_format_str)) + return "invalid"; + + return output_format_str[fmt]; +} static unsigned long long vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, - unsigned int bpc); + unsigned int bpc, enum vc4_hdmi_output_format fmt); static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, - unsigned int bpc) + unsigned int bpc, + enum vc4_hdmi_output_format fmt) { - unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc); + unsigned long long clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt); return clock > HDMI_14_MAX_TMDS_CLK; } @@ -289,7 +304,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode; list_for_each_entry(mode, &connector->probed_modes, head) { - if (vc4_hdmi_mode_needs_scrambling(mode, 8)) { + if (vc4_hdmi_mode_needs_scrambling(mode, 8, VC4_HDMI_OUTPUT_RGB)) { drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz."); drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60."); } @@ -346,6 +361,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) new_state->base.max_bpc = 8; new_state->base.max_requested_bpc = 8; + new_state->output_format = VC4_HDMI_OUTPUT_RGB; drm_atomic_helper_connector_tv_reset(connector); } @@ -362,6 +378,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) new_state->pixel_rate = vc4_state->pixel_rate; new_state->output_bpc = vc4_state->output_bpc; + new_state->output_format = vc4_state->output_format; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -515,11 +532,38 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); } +static void vc4_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, + enum vc4_hdmi_output_format fmt) +{ + switch (fmt) { + case VC4_HDMI_OUTPUT_RGB: + frame->colorspace = HDMI_COLORSPACE_RGB; + break; + + case VC4_HDMI_OUTPUT_YUV420: + frame->colorspace = HDMI_COLORSPACE_YUV420; + break; + + case VC4_HDMI_OUTPUT_YUV422: + frame->colorspace = HDMI_COLORSPACE_YUV422; + break; + + case VC4_HDMI_OUTPUT_YUV444: + frame->colorspace = HDMI_COLORSPACE_YUV444; + break; + + default: + break; + } +} + static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); struct drm_connector *connector = &vc4_hdmi->connector; struct drm_connector_state *cstate = connector->state; + struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(cstate); const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; union hdmi_infoframe frame; int ret; @@ -539,6 +583,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) HDMI_QUANTIZATION_RANGE_FULL : HDMI_QUANTIZATION_RANGE_LIMITED); drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); + vc4_hdmi_avi_infoframe_colorspace(&frame.avi, vc4_state->output_format); drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); vc4_hdmi_write_infoframe(encoder, &frame); @@ -644,7 +689,9 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) if (!vc4_hdmi_supports_scrambling(encoder, mode)) return; - if (!vc4_hdmi_mode_needs_scrambling(mode, vc4_hdmi->output_bpc)) + if (!vc4_hdmi_mode_needs_scrambling(mode, + vc4_hdmi->output_bpc, + vc4_hdmi->output_format)) return; drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); @@ -834,6 +881,38 @@ static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { { 0x0000, 0x0000, 0x1b80, 0x0400 }, }; +/* + * Conversion between Full Range RGB and Full Range YUV422 using the + * BT.709 Colorspace + * + * [ 0.212639 0.715169 0.072192 0 ] + * [ -0.117208 -0.394207 0.511416 128 ] + * [ 0.511416 -0.464524 -0.046891 128 ] + * + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + */ +static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709[3][4] = { + { 0x06ce, 0x16e3, 0x024f, 0x0000 }, + { 0xfc41, 0xf364, 0x105e, 0x2000 }, + { 0x105e, 0xf124, 0xfe81, 0x2000 }, +}; + +/* + * Conversion between Full Range RGB and Full Range YUV444 using the + * BT.709 Colorspace + * + * [ -0.117208 -0.394207 0.511416 128 ] + * [ 0.511416 -0.464524 -0.046891 128 ] + * [ 0.212639 0.715169 0.072192 0 ] + * + * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + */ +static const u16 vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709[3][4] = { + { 0xfc41, 0xf364, 0x105e, 0x2000 }, + { 0x105e, 0xf124, 0xfe81, 0x2000 }, + { 0x06ce, 0x16e3, 0x024f, 0x0000 }, +}; + static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, const u16 coeffs[3][4]) { @@ -851,19 +930,53 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) { + struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(state); unsigned long flags; + u32 if_cfg = 0; + u32 if_xbar = 0x543210; + u32 csc_chan_ctl = 0; u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, VC5_MT_CP_CSC_CTL_MODE); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); - HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); + switch (vc4_state->output_format) { + case VC4_HDMI_OUTPUT_YUV444: + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv444_bt709); + break; - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); - else - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); + case VC4_HDMI_OUTPUT_YUV422: + csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD, + VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) | + VC5_MT_CP_CSC_CTL_USE_444_TO_422 | + VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION; + + csc_chan_ctl |= VC4_SET_FIELD(VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE, + VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP); + if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY, + VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422); + + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_full_yuv422_bt709); + break; + + case VC4_HDMI_OUTPUT_RGB: + if_xbar = 0x354021; + + if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); + else + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); + break; + + default: + break; + } + + HDMI_WRITE(HDMI_VEC_INTERFACE_CFG, if_cfg); + HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, if_xbar); + HDMI_WRITE(HDMI_CSC_CHANNEL_CTL, csc_chan_ctl); HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); @@ -989,6 +1102,15 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, break; } + /* + * YCC422 is always 36-bit and not considered deep colour so + * doesn't signal in GCP + */ + if (vc4_state->output_format == VC4_HDMI_OUTPUT_YUV422) { + gcp = 4; + gcp_en = false; + } + reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1); reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK | VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK); @@ -1257,12 +1379,97 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, mutex_lock(&vc4_hdmi->mutex); vc4_hdmi->output_bpc = vc4_state->output_bpc; + vc4_hdmi->output_format = vc4_state->output_format; memcpy(&vc4_hdmi->saved_adjusted_mode, &crtc_state->adjusted_mode, sizeof(vc4_hdmi->saved_adjusted_mode)); mutex_unlock(&vc4_hdmi->mutex); } +static bool +vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, + const struct drm_display_info *info, + const struct drm_display_mode *mode, + unsigned int format, unsigned int bpc) +{ + struct drm_device *dev = vc4_hdmi->connector.dev; + u8 vic = drm_match_cea_mode(mode); + + if (vic == 1 && bpc != 8) { + drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc); + return false; + } + + if (!info->is_hdmi && + (format != VC4_HDMI_OUTPUT_RGB || bpc != 8)) { + drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n"); + return false; + } + + switch (format) { + case VC4_HDMI_OUTPUT_RGB: + drm_dbg(dev, "RGB Format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) + return false; + + if (bpc == 10 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) { + drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + return false; + } + + if (bpc == 12 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)) { + drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + return false; + } + + drm_dbg(dev, "RGB format supported in that configuration.\n"); + + return true; + + case VC4_HDMI_OUTPUT_YUV422: + drm_dbg(dev, "YUV422 format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB422)) { + drm_dbg(dev, "Sink doesn't support YUV422.\n"); + return false; + } + + if (bpc != 12) { + drm_dbg(dev, "YUV422 only supports 12 bpc.\n"); + return false; + } + + drm_dbg(dev, "YUV422 format supported in that configuration.\n"); + + return true; + + case VC4_HDMI_OUTPUT_YUV444: + drm_dbg(dev, "YUV444 format, checking the constraints.\n"); + + if (!(info->color_formats & DRM_COLOR_FORMAT_YCRCB444)) { + drm_dbg(dev, "Sink doesn't support YUV444.\n"); + return false; + } + + if (bpc == 10 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) { + drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + return false; + } + + if (bpc == 12 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36)) { + drm_dbg(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + return false; + } + + drm_dbg(dev, "YUV444 format supported in that configuration.\n"); + + return true; + } + + return false; +} + static enum drm_mode_status vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, unsigned long long clock) @@ -1284,13 +1491,17 @@ vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi, static unsigned long long vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, - unsigned int bpc) + unsigned int bpc, + enum vc4_hdmi_output_format fmt) { unsigned long long clock = mode->crtc_clock * 1000; if (mode->flags & DRM_MODE_FLAG_DBLCLK) clock = clock * 2; + if (fmt == VC4_HDMI_OUTPUT_YUV422) + bpc = 8; + return clock * bpc / 8; } @@ -1298,11 +1509,11 @@ static int vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, struct vc4_hdmi_connector_state *vc4_state, const struct drm_display_mode *mode, - unsigned int bpc) + unsigned int bpc, unsigned int fmt) { unsigned long long clock; - clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc); + clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt); if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK) return -EINVAL; @@ -1311,11 +1522,56 @@ vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi, return 0; } +static int +vc4_hdmi_encoder_compute_format(const struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *vc4_state, + const struct drm_display_mode *mode, + unsigned int bpc) +{ + struct drm_device *dev = vc4_hdmi->connector.dev; + const struct drm_connector *connector = &vc4_hdmi->connector; + const struct drm_display_info *info = &connector->display_info; + unsigned int format; + + drm_dbg(dev, "Trying with an RGB output\n"); + + format = VC4_HDMI_OUTPUT_RGB; + if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) { + int ret; + + ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, + mode, bpc, format); + if (!ret) { + vc4_state->output_format = format; + return 0; + } + } + + drm_dbg(dev, "Failed, Trying with an YUV422 output\n"); + + format = VC4_HDMI_OUTPUT_YUV422; + if (vc4_hdmi_sink_supports_format_bpc(vc4_hdmi, info, mode, format, bpc)) { + int ret; + + ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, + mode, bpc, format); + if (!ret) { + vc4_state->output_format = format; + return 0; + } + } + + drm_dbg(dev, "Failed. No Format Supported for that bpc count.\n"); + + return -EINVAL; +} + static int vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, struct vc4_hdmi_connector_state *vc4_state, const struct drm_display_mode *mode) { + struct drm_device *dev = vc4_hdmi->connector.dev; struct drm_connector_state *conn_state = &vc4_state->base; unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12); unsigned int bpc; @@ -1324,17 +1580,18 @@ vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi, for (bpc = max_bpc; bpc >= 8; bpc -= 2) { drm_dbg(dev, "Trying with a %d bpc output\n", bpc); - ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, - mode, bpc); + ret = vc4_hdmi_encoder_compute_format(vc4_hdmi, vc4_state, + mode, bpc); if (ret) continue; vc4_state->output_bpc = bpc; drm_dbg(dev, - "Mode %ux%u @ %uHz: Found configuration: bpc: %u, clock: %llu\n", + "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n", mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), vc4_state->output_bpc, + vc4_hdmi_output_fmt_str(vc4_state->output_format), vc4_state->pixel_rate); break; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index fd4a793fd8be..0a3310c1fbfc 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -123,6 +123,13 @@ struct vc4_hdmi_audio { bool streaming; }; +enum vc4_hdmi_output_format { + VC4_HDMI_OUTPUT_RGB, + VC4_HDMI_OUTPUT_YUV422, + VC4_HDMI_OUTPUT_YUV444, + VC4_HDMI_OUTPUT_YUV420, +}; + /* General HDMI hardware state. */ struct vc4_hdmi { struct vc4_hdmi_audio audio; @@ -235,6 +242,12 @@ struct vc4_hdmi { * outside of KMS hooks. Protected by @mutex. */ unsigned int output_bpc; + + /** + * @output_format: Copy of @vc4_connector_state.output_format + * for use outside of KMS hooks. Protected by @mutex. + */ + enum vc4_hdmi_output_format output_format; }; static inline struct vc4_hdmi * @@ -255,6 +268,7 @@ struct vc4_hdmi_connector_state { struct drm_connector_state base; unsigned long long pixel_rate; unsigned int output_bpc; + enum vc4_hdmi_output_format output_format; }; static inline struct vc4_hdmi_connector_state * diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 72b769412482..0198de96c7b2 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -54,6 +54,7 @@ enum vc4_hdmi_field { HDMI_CSC_24_23, HDMI_CSC_32_31, HDMI_CSC_34_33, + HDMI_CSC_CHANNEL_CTL, HDMI_CSC_CTL, /* @@ -119,6 +120,7 @@ enum vc4_hdmi_field { HDMI_TX_PHY_POWERDOWN_CTL, HDMI_TX_PHY_RESET_CTL, HDMI_TX_PHY_TMDS_CLK_WORD_SEL, + HDMI_VEC_INTERFACE_CFG, HDMI_VEC_INTERFACE_XBAR, HDMI_VERTA0, HDMI_VERTA1, @@ -246,6 +248,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = { VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), + VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec), VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), @@ -291,6 +294,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi0_fields[] = { VC5_CSC_REG(HDMI_CSC_24_23, 0x010), VC5_CSC_REG(HDMI_CSC_32_31, 0x014), VC5_CSC_REG(HDMI_CSC_34_33, 0x018), + VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), }; static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = { @@ -327,6 +331,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = { VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), + VC5_DVP_REG(HDMI_VEC_INTERFACE_CFG, 0x0ec), VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), @@ -372,6 +377,7 @@ static const struct vc4_hdmi_register __maybe_unused vc5_hdmi_hdmi1_fields[] = { VC5_CSC_REG(HDMI_CSC_24_23, 0x010), VC5_CSC_REG(HDMI_CSC_32_31, 0x014), VC5_CSC_REG(HDMI_CSC_34_33, 0x018), + VC5_CSC_REG(HDMI_CSC_CHANNEL_CTL, 0x02c), }; static inline diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index 82d46cf9f298..f40dd93f2cdd 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -796,11 +796,27 @@ enum { # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) # define VC4_HD_CSC_CTL_ENABLE BIT(0) +# define VC5_MT_CP_CSC_CTL_USE_444_TO_422 BIT(6) +# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_MASK \ + VC4_MASK(5, 4) +# define VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD \ + 3 +# define VC5_MT_CP_CSC_CTL_USE_RNG_SUPPRESSION BIT(3) # define VC5_MT_CP_CSC_CTL_ENABLE BIT(2) # define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0) +# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_MASK \ + VC4_MASK(7, 6) +# define VC5_MT_CP_CHANNEL_CTL_OUTPUT_REMAP_LEGACY_STYLE \ + 2 + # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) +# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_MASK \ + VC4_MASK(3, 2) +# define VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY \ + 2 + /* HVS display list information. */ #define HVS_BOOTLOADER_DLIST_END 32 -- Gitee From d511b8d93e55067189a7fbfb33e24010aa15f5c9 Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Fri, 10 Dec 2021 18:03:18 +0000 Subject: [PATCH 129/155] drm/vc4: Skip writes to disabled packet RAM This path actually occurs when audio is started during a hdmi mode set. As the data will be written by vc4_hdmi_set_infoframes when packet RAM is enabled again, don't treat as an error Signed-off-by: Dom Cobley --- drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++++- drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index e9f726ca92df..8489e1e1fe44 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -756,6 +756,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, mutex_lock(&vc4_hdmi->mutex); + vc4_hdmi->output_enabled = false; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); @@ -1359,6 +1360,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, VC4_HDMI_RAM_PACKET_ENABLE); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + vc4_hdmi->output_enabled = true; vc4_hdmi_set_infoframes(encoder); } @@ -1995,7 +1997,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); - vc4_hdmi_set_audio_infoframe(encoder); + if (vc4_hdmi->output_enabled) + vc4_hdmi_set_audio_infoframe(encoder); mutex_unlock(&vc4_hdmi->mutex); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 0a3310c1fbfc..3dd0d2a53a44 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -231,6 +231,12 @@ struct vc4_hdmi { */ struct drm_display_mode saved_adjusted_mode; + /** + * @output_enabled: Is the HDMI controller currently active? + * Protected by @mutex. + */ + bool output_enabled; + /** * @scdc_enabled: Is the HDMI controller currently running with * the scrambler on? Protected by @mutex. -- Gitee From d76ce85b3157e11a59efa627d1b6d43ce0d94cea Mon Sep 17 00:00:00 2001 From: David Plowman Date: Mon, 16 Aug 2021 13:39:08 +0200 Subject: [PATCH 130/155] media: v4l2-ctrls: Add V4L2_CID_NOTIFY_GAINS control Commit a9c80593ff80ddb7c6496624e5384e1ea3460a72 upstream. We add a new control V4L2_CID_NOTIFY_GAINS which allows the sensor to be notified what gains will be applied to the different colour channels by subsequent processing (such as by an ISP), even though the sensor will not apply any of these gains itself. For Bayer sensors this will be an array control taking 4 values which are the 4 gains arranged in the fixed order B, Gb, Gr and R, irrespective of the exact Bayer order of the sensor itself. The use of an array makes it straightforward to extend this control to non-Bayer sensors (for example, sensors with an RGBW pattern) in future. The units are in all cases linear with the default value indicating a gain of exactly 1.0. For example, if the default value were reported as 128 then the value 192 would represent a gain of exactly 1.5. Signed-off-by: David Plowman Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 1 + include/uapi/linux/v4l2-controls.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 517c4499f56d..2099a4d814e4 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1132,6 +1132,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; + case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 0b8ae128b961..773e24a1427d 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1083,6 +1083,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) +#define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) /* Image processing controls */ -- Gitee From fe3b0f495ad460315ee4478ec690f78935162ff9 Mon Sep 17 00:00:00 2001 From: David Plowman Date: Mon, 16 Aug 2021 13:39:09 +0200 Subject: [PATCH 131/155] media: v4l2-ctrls: Document V4L2_CID_NOTIFY_GAINS control Commit 311a839a1ad255ebcb7291fb4e0d2ec2f32312a7 upstream. Add documentation for the V4L2_CID_NOTIFY_GAINS control. This control is required by sensors that need to know what colour gains will be applied to pixels by downstream processing (such as by an ISP), though the sensor does not apply these gains itself. Signed-off-by: David Plowman Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-image-source.rst | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst index 9457dc340c31..af8fa25026c0 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst @@ -58,3 +58,23 @@ Image Source Control IDs The unit cell consists of the whole area of the pixel, sensitive and non-sensitive. This control is required for automatic calibration of sensors/cameras. + +``V4L2_CID_NOTIFY_GAINS (integer array)`` + The sensor is notified what gains will be applied to the different + colour channels by subsequent processing (such as by an ISP). The + sensor is merely informed of these values in case it performs + processing that requires them, but it does not apply them itself to + the output pixels. + + Currently it is defined only for Bayer sensors, and is an array + control taking 4 gain values, being the gains for each of the + Bayer channels. The gains are always in the order B, Gb, Gr and R, + irrespective of the exact Bayer order of the sensor itself. + + The use of an array allows this control to be extended to sensors + with, for example, non-Bayer CFAs (colour filter arrays). + + The units for the gain values are linear, with the default value + representing a gain of exactly 1.0. For example, if this default value + is reported as being (say) 128, then a value of 192 would represent + a gain of exactly 1.5. -- Gitee From b370b2b554b1aadd980703f61112951366d2fd4a Mon Sep 17 00:00:00 2001 From: Penk Chen Date: Mon, 20 Dec 2021 03:44:56 +0900 Subject: [PATCH 132/155] Extending ili9881c driver support for nwe080 panel Signed-off-by: Penk Chen --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 253 +++++++++++++++++- 1 file changed, 251 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 534dd7414d42..6e03d9b0be60 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017-2018, Bootlin + * Copyright (C) 2021, Henson Li + * Copyright (C) 2021, Penk Chen */ #include @@ -42,6 +44,7 @@ struct ili9881c_desc { const struct ili9881c_instr *init; const size_t init_length; const struct drm_display_mode *mode; + const unsigned flags; }; struct ili9881c { @@ -453,6 +456,225 @@ static const struct ili9881c_instr k101_im2byl02_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ }; +static const struct ili9881c_instr nwe080_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + //GIP_1 + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x73), + ILI9881C_COMMAND_INSTR(0x04, 0x00), + ILI9881C_COMMAND_INSTR(0x05, 0x00), + ILI9881C_COMMAND_INSTR(0x06, 0x0A), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x00), + ILI9881C_COMMAND_INSTR(0x09, 0x20), + ILI9881C_COMMAND_INSTR(0x0a, 0x20), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x00), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x1E), + ILI9881C_COMMAND_INSTR(0x10, 0x1E), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1A, 0x00), + ILI9881C_COMMAND_INSTR(0x1B, 0x00), + ILI9881C_COMMAND_INSTR(0x1C, 0x00), + ILI9881C_COMMAND_INSTR(0x1D, 0x00), + ILI9881C_COMMAND_INSTR(0x1E, 0x40), + ILI9881C_COMMAND_INSTR(0x1F, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x06), + ILI9881C_COMMAND_INSTR(0x21, 0x01), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x03), + ILI9881C_COMMAND_INSTR(0x2A, 0x00), + ILI9881C_COMMAND_INSTR(0x2B, 0x00), + ILI9881C_COMMAND_INSTR(0x2C, 0x00), + ILI9881C_COMMAND_INSTR(0x2D, 0x00), + ILI9881C_COMMAND_INSTR(0x2E, 0x00), + ILI9881C_COMMAND_INSTR(0x2F, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3C), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3A, 0x00), + ILI9881C_COMMAND_INSTR(0x3B, 0x00), + ILI9881C_COMMAND_INSTR(0x3C, 0x00), + ILI9881C_COMMAND_INSTR(0x3D, 0x00), + ILI9881C_COMMAND_INSTR(0x3E, 0x00), + ILI9881C_COMMAND_INSTR(0x3F, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + + ILI9881C_COMMAND_INSTR(0x50, 0x10), + ILI9881C_COMMAND_INSTR(0x51, 0x32), + ILI9881C_COMMAND_INSTR(0x52, 0x54), + ILI9881C_COMMAND_INSTR(0x53, 0x76), + ILI9881C_COMMAND_INSTR(0x54, 0x98), + ILI9881C_COMMAND_INSTR(0x55, 0xba), + ILI9881C_COMMAND_INSTR(0x56, 0x10), + ILI9881C_COMMAND_INSTR(0x57, 0x32), + ILI9881C_COMMAND_INSTR(0x58, 0x54), + ILI9881C_COMMAND_INSTR(0x59, 0x76), + ILI9881C_COMMAND_INSTR(0x5A, 0x98), + ILI9881C_COMMAND_INSTR(0x5B, 0xba), + ILI9881C_COMMAND_INSTR(0x5C, 0xdc), + ILI9881C_COMMAND_INSTR(0x5D, 0xfe), + + //GIP_3 + ILI9881C_COMMAND_INSTR(0x5E, 0x00), + ILI9881C_COMMAND_INSTR(0x5F, 0x01), + ILI9881C_COMMAND_INSTR(0x60, 0x00), + ILI9881C_COMMAND_INSTR(0x61, 0x15), + ILI9881C_COMMAND_INSTR(0x62, 0x14), + ILI9881C_COMMAND_INSTR(0x63, 0x0E), + ILI9881C_COMMAND_INSTR(0x64, 0x0F), + ILI9881C_COMMAND_INSTR(0x65, 0x0C), + ILI9881C_COMMAND_INSTR(0x66, 0x0D), + ILI9881C_COMMAND_INSTR(0x67, 0x06), + ILI9881C_COMMAND_INSTR(0x68, 0x02), + ILI9881C_COMMAND_INSTR(0x69, 0x02), + ILI9881C_COMMAND_INSTR(0x6A, 0x02), + ILI9881C_COMMAND_INSTR(0x6B, 0x02), + ILI9881C_COMMAND_INSTR(0x6C, 0x02), + ILI9881C_COMMAND_INSTR(0x6D, 0x02), + ILI9881C_COMMAND_INSTR(0x6E, 0x07), + ILI9881C_COMMAND_INSTR(0x6F, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + + ILI9881C_COMMAND_INSTR(0x75, 0x01), + ILI9881C_COMMAND_INSTR(0x76, 0x00), + ILI9881C_COMMAND_INSTR(0x77, 0x14), + ILI9881C_COMMAND_INSTR(0x78, 0x15), + ILI9881C_COMMAND_INSTR(0x79, 0x0E), + ILI9881C_COMMAND_INSTR(0x7A, 0x0F), + ILI9881C_COMMAND_INSTR(0x7B, 0x0C), + ILI9881C_COMMAND_INSTR(0x7C, 0x0D), + ILI9881C_COMMAND_INSTR(0x7D, 0x06), + ILI9881C_COMMAND_INSTR(0x7E, 0x02), + ILI9881C_COMMAND_INSTR(0x7F, 0x02), + ILI9881C_COMMAND_INSTR(0x80, 0x02), + ILI9881C_COMMAND_INSTR(0x81, 0x02), + ILI9881C_COMMAND_INSTR(0x82, 0x02), + ILI9881C_COMMAND_INSTR(0x83, 0x02), + ILI9881C_COMMAND_INSTR(0x84, 0x07), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8A, 0x02), + + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6C, 0x15), + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), + + //clamp 15V + ILI9881C_COMMAND_INSTR(0x6F, 0x35), + ILI9881C_COMMAND_INSTR(0x3A, 0x92), + ILI9881C_COMMAND_INSTR(0x8D, 0x1F), + ILI9881C_COMMAND_INSTR(0x87, 0xBA), + ILI9881C_COMMAND_INSTR(0x26, 0x76), + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), + ILI9881C_COMMAND_INSTR(0xB5, 0x27), + ILI9881C_COMMAND_INSTR(0x31, 0x75), + ILI9881C_COMMAND_INSTR(0x30, 0x03), + ILI9881C_COMMAND_INSTR(0x3B, 0x98), + ILI9881C_COMMAND_INSTR(0x35, 0x17), + ILI9881C_COMMAND_INSTR(0x33, 0x14), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + + ILI9881C_SWITCH_PAGE_INSTR(1), + // direction rotate + //ILI9881C_COMMAND_INSTR(0x22, 0x0B), + ILI9881C_COMMAND_INSTR(0x22, 0x0A), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x53, 0x63), + ILI9881C_COMMAND_INSTR(0x55, 0x69), + ILI9881C_COMMAND_INSTR(0x50, 0xC7), + ILI9881C_COMMAND_INSTR(0x51, 0xC2), + ILI9881C_COMMAND_INSTR(0x60, 0x26), + + ILI9881C_COMMAND_INSTR(0xA0, 0x08), + ILI9881C_COMMAND_INSTR(0xA1, 0x0F), + ILI9881C_COMMAND_INSTR(0xA2, 0x25), + ILI9881C_COMMAND_INSTR(0xA3, 0x01), + ILI9881C_COMMAND_INSTR(0xA4, 0x23), + ILI9881C_COMMAND_INSTR(0xA5, 0x18), + ILI9881C_COMMAND_INSTR(0xA6, 0x11), + ILI9881C_COMMAND_INSTR(0xA7, 0x1A), + ILI9881C_COMMAND_INSTR(0xA8, 0x81), + ILI9881C_COMMAND_INSTR(0xA9, 0x19), + ILI9881C_COMMAND_INSTR(0xAA, 0x26), + ILI9881C_COMMAND_INSTR(0xAB, 0x7C), + ILI9881C_COMMAND_INSTR(0xAC, 0x24), + ILI9881C_COMMAND_INSTR(0xAD, 0x1E), + ILI9881C_COMMAND_INSTR(0xAE, 0x5C), + ILI9881C_COMMAND_INSTR(0xAF, 0x2A), + ILI9881C_COMMAND_INSTR(0xB0, 0x2B), + ILI9881C_COMMAND_INSTR(0xB1, 0x50), + ILI9881C_COMMAND_INSTR(0xB2, 0x5C), + ILI9881C_COMMAND_INSTR(0xB3, 0x39), + + ILI9881C_COMMAND_INSTR(0xC0, 0x08), + ILI9881C_COMMAND_INSTR(0xC1, 0x1F), + ILI9881C_COMMAND_INSTR(0xC2, 0x24), + ILI9881C_COMMAND_INSTR(0xC3, 0x1D), + ILI9881C_COMMAND_INSTR(0xC4, 0x04), + ILI9881C_COMMAND_INSTR(0xC5, 0x32), + ILI9881C_COMMAND_INSTR(0xC6, 0x24), + ILI9881C_COMMAND_INSTR(0xC7, 0x1F), + ILI9881C_COMMAND_INSTR(0xC8, 0x90), + ILI9881C_COMMAND_INSTR(0xC9, 0x20), + ILI9881C_COMMAND_INSTR(0xCA, 0x2C), + ILI9881C_COMMAND_INSTR(0xCB, 0x82), + ILI9881C_COMMAND_INSTR(0xCC, 0x19), + ILI9881C_COMMAND_INSTR(0xCD, 0x22), + ILI9881C_COMMAND_INSTR(0xCE, 0x4E), + ILI9881C_COMMAND_INSTR(0xCF, 0x28), + ILI9881C_COMMAND_INSTR(0xD0, 0x2D), + ILI9881C_COMMAND_INSTR(0xD1, 0x51), + ILI9881C_COMMAND_INSTR(0xD2, 0x5D), + ILI9881C_COMMAND_INSTR(0xD3, 0x39), + + ILI9881C_SWITCH_PAGE_INSTR(0), + //PWM + ILI9881C_COMMAND_INSTR(0x51, 0x0F), + ILI9881C_COMMAND_INSTR(0x52, 0xFF), + ILI9881C_COMMAND_INSTR(0x53, 0x2C), + + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x29, 0x00), + ILI9881C_COMMAND_INSTR(0x35, 0x00), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -603,6 +825,23 @@ static const struct drm_display_mode k101_im2byl02_default_mode = { .height_mm = 217, }; +static const struct drm_display_mode nwe080_default_mode = { + .clock = 71750, + + .hdisplay = 800, + .hsync_start = 800 + 52, + .hsync_end = 800 + 52 + 8, + .htotal = 800 + 52 + 8 + 48, + + .vdisplay = 1280, + .vsync_start = 1280 + 16, + .vsync_end = 1280 + 16 + 6, + .vtotal = 1280 + 16 + 6 + 15, + + .width_mm = 107, + .height_mm = 170, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -670,7 +909,7 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) drm_panel_add(&ctx->panel); - dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE; + dsi->mode_flags = ctx->desc->flags; dsi->format = MIPI_DSI_FMT_RGB888; dsi->lanes = 4; @@ -691,18 +930,28 @@ static const struct ili9881c_desc lhr050h41_desc = { .init = lhr050h41_init, .init_length = ARRAY_SIZE(lhr050h41_init), .mode = &lhr050h41_default_mode, + .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, }; static const struct ili9881c_desc k101_im2byl02_desc = { .init = k101_im2byl02_init, .init_length = ARRAY_SIZE(k101_im2byl02_init), .mode = &k101_im2byl02_default_mode, + .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, +}; + +static const struct ili9881c_desc nwe080_desc = { + .init = nwe080_init, + .init_length = ARRAY_SIZE(nwe080_init), + .mode = &nwe080_default_mode, + .flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO, }; static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, - { } + { .compatible = "nwe,nwe080", .data = &nwe080_desc }, + {} }; MODULE_DEVICE_TABLE(of, ili9881c_of_match); -- Gitee From 096b97ee2c86760c6d08146354ba89641eb16da4 Mon Sep 17 00:00:00 2001 From: Penk Chen Date: Mon, 20 Dec 2021 03:45:46 +0900 Subject: [PATCH 133/155] Enable ili9881 panel and pwm backlight driver by default Signed-off-by: Penk Chen --- arch/arm/configs/bcm2711_defconfig | 2 ++ arch/arm64/configs/bcm2711_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index 6ef776884744..7c4cf3c700d9 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -953,6 +953,7 @@ CONFIG_DRM=m CONFIG_DRM_LOAD_EDID_FIRMWARE=y CONFIG_DRM_UDL=m CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m CONFIG_DRM_PANEL_JDI_LT070ME05000=m CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m CONFIG_DRM_DISPLAY_CONNECTOR=m @@ -974,6 +975,7 @@ CONFIG_FB_UDL=m CONFIG_FB_SIMPLE=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m +CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_RPI=m CONFIG_BACKLIGHT_GPIO=m CONFIG_FRAMEBUFFER_CONSOLE=y diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index c3bfafea4815..d712c932618c 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -956,6 +956,7 @@ CONFIG_DRM=m CONFIG_DRM_LOAD_EDID_FIRMWARE=y CONFIG_DRM_UDL=m CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m CONFIG_DRM_PANEL_JDI_LT070ME05000=m CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m CONFIG_DRM_DISPLAY_CONNECTOR=m @@ -977,6 +978,7 @@ CONFIG_FB_UDL=m CONFIG_FB_SIMPLE=y CONFIG_FB_SSD1307=m CONFIG_FB_RPISENSE=m +CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_RPI=m CONFIG_BACKLIGHT_GPIO=m CONFIG_FRAMEBUFFER_CONSOLE=y -- Gitee From 32556187bd2c6b7be29174a6e2baf7823825fdeb Mon Sep 17 00:00:00 2001 From: Penk Chen Date: Mon, 20 Dec 2021 03:46:26 +0900 Subject: [PATCH 134/155] Add panel overlay for CutiePi Signed-off-by: Penk Chen --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/README | 6 + .../dts/overlays/cutiepi-panel-overlay.dts | 117 ++++++++++++++++++ arch/arm/boot/dts/overlays/overlay_map.dts | 4 + 4 files changed, 128 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index 1c0da564b3c1..b925054d95e4 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -34,6 +34,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ cap1106.dtbo \ chipdip-dac.dtbo \ cma.dtbo \ + cutiepi-panel.dtbo \ dht11.dtbo \ dionaudio-loco.dtbo \ dionaudio-loco-v2.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 7e414672eafd..6b9a5ef7400a 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -679,6 +679,12 @@ Params: cma-512 CMA is 512MB (needs 1GB) cma-default Use upstream's default value +Name: cutiepi-panel +Info: 8" TFT LCD display and touch panel used by cutiepi.io +Load: dtoverlay=cutiepi-panel +Params: + + Name: dht11 Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors Also sometimes found with the part number(s) AM230x. diff --git a/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts b/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts new file mode 100644 index 000000000000..6f9694e81d6a --- /dev/null +++ b/arch/arm/boot/dts/overlays/cutiepi-panel-overlay.dts @@ -0,0 +1,117 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2711"; + + fragment@0 { + target=<&dsi1>; + + __overlay__ { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + port { + dsi1_out_port: endpoint { + remote-endpoint = <&panel_dsi_in1>; + }; + }; + + display1: panel@0 { + compatible = "nwe,nwe080"; + reg=<0>; + backlight = <&rpi_backlight>; + reset-gpios = <&gpio 20 0>; + port { + panel_dsi_in1: endpoint { + remote-endpoint = <&dsi1_out_port>; + }; + }; + }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { + pwm_pins: pwm_pins { + brcm,pins = <12>; + brcm,function = <4>; // ALT0 + }; + }; + }; + + fragment@2 { + target = <&pwm>; + frag1: __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; + assigned-clock-rates = <1000000>; + status = "okay"; + }; + }; + + fragment@3 { + target-path = "/"; + __overlay__ { + rpi_backlight: rpi_backlight { + compatible = "pwm-backlight"; + brightness-levels = <0 6 8 12 16 24 32 40 48 64 96 128 160 192 224 255>; + default-brightness-level = <6>; + pwms = <&pwm 0 200000>; + power-supply = <&vdd_3v3_reg>; + status = "okay"; + }; + }; + }; + + fragment@4 { + target = <&i2c6>; + frag0: __overlay__ { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_pins>; + clock-frequency = <100000>; + }; + }; + + fragment@5 { + target = <&i2c6_pins>; + __overlay__ { + brcm,pins = <22 23>; + }; + }; + + fragment@6 { + target = <&gpio>; + __overlay__ { + goodix_pins: goodix_pins { + brcm,pins = <21 26>; // interrupt and reset + brcm,function = <0 0>; // in + brcm,pull = <2 2>; // pull-up + }; + }; + }; + + fragment@7 { + target = <&i2c6>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + gt9xx: gt9xx@5d { + compatible = "goodix,gt9271"; + reg = <0x5D>; + pinctrl-names = "default"; + pinctrl-0 = <&goodix_pins>; + interrupt-parent = <&gpio>; + interrupts = <21 2>; // high-to-low edge triggered + irq-gpios = <&gpio 21 0>; + reset-gpios = <&gpio 26 0>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/overlays/overlay_map.dts b/arch/arm/boot/dts/overlays/overlay_map.dts index bc6e3bce22c7..9fd31bcd5569 100644 --- a/arch/arm/boot/dts/overlays/overlay_map.dts +++ b/arch/arm/boot/dts/overlays/overlay_map.dts @@ -5,6 +5,10 @@ deprecated = "use i2c-sensor,bmp085"; }; + cutiepi-panel { + bcm2711; + }; + highperi { bcm2711; }; -- Gitee From 7931f03d604708f6a01b70ba011d05db2301e7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Van=C4=9Bk?= Date: Tue, 28 Dec 2021 15:43:10 +0100 Subject: [PATCH 135/155] dtoverlays: Enable cam1_clock when using tc358743 or irs1125 This fixes a regression introduced in 131f1322039284932ccb601a5cffdd9ca5d36d96 (see also https://github.com/raspberrypi/linux/issues/4791). The tc358743 driver refused to bind to the device. The irs1125 driver is likely behaving similarly. The new unified cam1_clk node that represents the fixed on-board oscillator is marked as disabled by default. These overlays didn't expect this and so the clock nodes were stuck in disabled state. This commit just adds the required status = "okay" line. Other sensor drivers do this too. --- arch/arm/boot/dts/overlays/irs1125-overlay.dts | 1 + arch/arm/boot/dts/overlays/tc358743-overlay.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/overlays/irs1125-overlay.dts b/arch/arm/boot/dts/overlays/irs1125-overlay.dts index 0cdef42c3d16..8f8432c07a89 100644 --- a/arch/arm/boot/dts/overlays/irs1125-overlay.dts +++ b/arch/arm/boot/dts/overlays/irs1125-overlay.dts @@ -75,6 +75,7 @@ clk_frag: fragment@5 { target = <&cam1_clk>; __overlay__ { + status = "okay"; clock-frequency = <26000000>; }; }; diff --git a/arch/arm/boot/dts/overlays/tc358743-overlay.dts b/arch/arm/boot/dts/overlays/tc358743-overlay.dts index c85782688e39..c3eebfd1f6ee 100644 --- a/arch/arm/boot/dts/overlays/tc358743-overlay.dts +++ b/arch/arm/boot/dts/overlays/tc358743-overlay.dts @@ -78,6 +78,7 @@ clk_frag: fragment@6 { target = <&cam1_clk>; __overlay__ { + status = "okay"; clock-frequency = <27000000>; }; }; -- Gitee From 4e10fa065681f9523aec22f4bfd3b8a7f640a245 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Thu, 30 Dec 2021 14:28:37 +0100 Subject: [PATCH 136/155] drm/vc4: hdmi: Fix HDMI monitor detection in polled mode When vc4_hdmi_connector_detect() was called in connector_status_connected state it incorrectly cleared the hdmi_monitor flag, leading to no audio on RPi3. Fix this by clearing hdmi_monitor only when the hpd check indicated no connection or if reading the edid failed. Signed-off-by: Matthias Reichl --- drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 8489e1e1fe44..4539ec145328 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -245,7 +245,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) connected = true; } - vc4_hdmi->encoder.hdmi_monitor = false; if (connected) { if (connector->status != connector_status_connected) { struct edid *edid = drm_get_edid(connector, vc4_hdmi->ddc); @@ -254,6 +253,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); vc4_hdmi->encoder.hdmi_monitor = drm_detect_hdmi_monitor(edid); kfree(edid); + } else { + vc4_hdmi->encoder.hdmi_monitor = false; } } @@ -263,6 +264,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) goto out; } + vc4_hdmi->encoder.hdmi_monitor = false; + cec_phys_addr_invalidate(vc4_hdmi->cec_adap); out: -- Gitee From 802ed1a3f22cf0e703f0f39ef73d272d093d9232 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Thu, 30 Dec 2021 15:12:19 +0100 Subject: [PATCH 137/155] drm/vc4: hdmi: Fix no video output on DVI monitors The drm edid parser doesn't signal RGB support on DVI monitors with old edid versions, leading to 8-bit RGB mode being rejected and no video on DVI monitors. As 8-bit RGB is mandatory on HDMI and DVI monitors anyways we can simply drop the RGB format check, aligning vc4 with other drivers. Signed-off-by: Matthias Reichl --- drivers/gpu/drm/vc4/vc4_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 4539ec145328..ccfcfce39426 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1415,9 +1415,6 @@ vc4_hdmi_sink_supports_format_bpc(const struct vc4_hdmi *vc4_hdmi, case VC4_HDMI_OUTPUT_RGB: drm_dbg(dev, "RGB Format, checking the constraints.\n"); - if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) - return false; - if (bpc == 10 && !(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)) { drm_dbg(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); return false; -- Gitee From 09f1544be9411c26885daf7835fcd7a83458a5f0 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 2 Jan 2022 12:22:52 -0500 Subject: [PATCH 138/155] staging/bcm2835-codec: Fix typo Signed-off-by: Andriy Gelman --- .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c index fdbaa96c25a0..472d97d1d228 100644 --- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c @@ -1563,7 +1563,7 @@ static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline; q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage; - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calculated bpl as %u, size %u\n", q_data->bytesperline, q_data->sizeimage); if (ctx->dev->role == DECODE && -- Gitee From b61975214536e177f893eacdf2dd7f4b2c9a3f22 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 4 Jan 2022 14:46:01 +0000 Subject: [PATCH 139/155] media: i2c: ov9281: Increase diff between VTS and max exposure The driver did allow the exposure to go up to VTS - 4 lines, but this would produce a visible line on 1280x800, and a stall of the sensor at 640x480. Whilst it appears to work with a difference of 5, the datasheet states there should be at least 25 lines difference between VTS and exposure, so use that value. Signed-off-by: Dave Stevenson --- drivers/media/i2c/ov9281.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov9281.c b/drivers/media/i2c/ov9281.c index f7ec4470d356..ff1b99e26a20 100644 --- a/drivers/media/i2c/ov9281.c +++ b/drivers/media/i2c/ov9281.c @@ -52,7 +52,11 @@ #define OV9281_REG_EXPOSURE 0x3500 #define OV9281_EXPOSURE_MIN 4 #define OV9281_EXPOSURE_STEP 1 -#define OV9281_VTS_MAX 0x7fff +/* + * Number of lines less than frame length (VTS) that exposure must be. + * Datasheet states 25, although empirically 5 appears to work. + */ +#define OV9281_EXPOSURE_OFFSET 25 #define OV9281_REG_GAIN_H 0x3508 #define OV9281_REG_GAIN_L 0x3509 @@ -69,6 +73,7 @@ #define OV9281_TEST_PATTERN_DISABLE 0x0 #define OV9281_REG_VTS 0x380e +#define OV9281_VTS_MAX 0x7fff /* * OV9281 native and active pixel array size. @@ -964,7 +969,7 @@ static int ov9281_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = ov9281->cur_mode->height + ctrl->val - 4; + max = ov9281->cur_mode->height + ctrl->val - OV9281_EXPOSURE_OFFSET; __v4l2_ctrl_modify_range(ov9281->exposure, ov9281->exposure->minimum, max, ov9281->exposure->step, @@ -1059,7 +1064,7 @@ static int ov9281_initialize_controls(struct ov9281 *ov9281) OV9281_VTS_MAX - mode->height, 1, vblank_def); - exposure_max = mode->vts_def - 4; + exposure_max = mode->vts_def - OV9281_EXPOSURE_OFFSET; ov9281->exposure = v4l2_ctrl_new_std(handler, &ov9281_ctrl_ops, V4L2_CID_EXPOSURE, OV9281_EXPOSURE_MIN, exposure_max, -- Gitee From ab4ede74f709a0ec4c88c3dedf5045ac1bd4d583 Mon Sep 17 00:00:00 2001 From: Padmanabha Srinivasaiah Date: Thu, 30 Dec 2021 21:45:10 +0100 Subject: [PATCH 140/155] bcm2835-v4l2-isp: Add missing lock initialization ISP device allocation is dynamic hence the locks too. struct mutex queue_lock is not initialized which result in bug. Fixing same by initializing it. [ 29.847138] INFO: trying to register non-static key. [ 29.847156] The code is fine but needs lockdep annotation, or maybe [ 29.847159] you didn't initialize this object before use? [ 29.847161] turning off the locking correctness validator. [ 29.847167] CPU: 1 PID: 343 Comm: v4l_id Tainted: G C 5.15.11-rt24-v8+ #8 [ 29.847187] Hardware name: Raspberry Pi 4 Model B Rev 1.4 (DT) [ 29.847194] Call trace: [ 29.847197] dump_backtrace+0x0/0x1b8 [ 29.847227] show_stack+0x20/0x30 [ 29.847240] dump_stack_lvl+0x8c/0xb8 [ 29.847254] dump_stack+0x18/0x34 [ 29.847263] register_lock_class+0x494/0x4a0 [ 29.847278] __lock_acquire+0x80/0x1680 [ 29.847289] lock_acquire+0x214/0x3a0 [ 29.847300] mutex_lock_nested+0x70/0xc8 [ 29.847312] _vb2_fop_release+0x3c/0xa8 [videobuf2_v4l2] [ 29.847346] vb2_fop_release+0x34/0x60 [videobuf2_v4l2] [ 29.847367] v4l2_release+0xc8/0x108 [videodev] [ 29.847453] __fput+0x8c/0x258 [ 29.847476] ____fput+0x18/0x28 [ 29.847487] task_work_run+0x98/0x180 [ 29.847502] do_notify_resume+0x228/0x3f8 [ 29.847515] el0_svc+0xec/0xf0 [ 29.847523] el0t_64_sync_handler+0x90/0xb8 [ 29.847531] el0t_64_sync+0x180/0x184 Signed-off-by: Padmanabha Srinivasaiah --- drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c index 8166f8e62347..42c43438303c 100644 --- a/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c +++ b/drivers/staging/vc04_services/bcm2835-isp/bcm2835-v4l2-isp.c @@ -1294,6 +1294,7 @@ static int register_node(struct bcm2835_isp_dev *dev, int ret; mutex_init(&node->lock); + mutex_init(&node->queue_lock); node->dev = dev; vfd = &node->vfd; -- Gitee From e8a664b9c69c0a183ea72b5457c13735cda8167b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 7 Jan 2022 11:12:08 +0000 Subject: [PATCH 141/155] dtoverlays: Add backlight-gpio parameter to vc4-kms-dpi-generic To allow for the cases where a simple panel does have a GPIO controlled backlight. Defaults to having no backlight defined. Signed-off-by: Dave Stevenson --- arch/arm/boot/dts/overlays/README | 2 ++ .../overlays/vc4-kms-dpi-generic-overlay.dts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 6b9a5ef7400a..4d3448f047bf 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3625,6 +3625,8 @@ Params: clock-frequency Display clock frequency (Hz) rgb888 Change to RGB888 output on GPIOs 0-27 bus-format Override the bus format for a MEDIA_BUS_FMT_* value. NB also overridden by rgbXXX overrides. + backlight-gpio Defines a GPIO to be used for backlight control + (default of none). Name: vc4-kms-dsi-7inch diff --git a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts index def175746f66..7846d56c1d1a 100644 --- a/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts +++ b/arch/arm/boot/dts/overlays/vc4-kms-dpi-generic-overlay.dts @@ -63,6 +63,23 @@ }; }; + fragment@2 { + target = <&panel>; + __dormant__ { + backlight = <&backlight>; + }; + }; + + fragment@3 { + target-path = "/"; + __dormant__ { + backlight: backlight { + compatible = "gpio-backlight"; + gpios = <&gpio 255 GPIO_ACTIVE_HIGH>; + }; + }; + }; + __overrides__ { clock-frequency = <&timing>, "clock-frequency:0"; hactive = <&timing>, "hactive:0"; @@ -88,5 +105,7 @@ rgb888 = <&panel>, "bus-format:0=0x100a", <&dpi_node>, "pinctrl-0:0=",<&dpi_gpio0>; bus-format = <&panel>, "bus-format:0"; + backlight-gpio = <0>, "+2+3", + <&backlight>, "gpios:4"; }; }; -- Gitee From 469b32463db85639b1a1b375b96ae6f3a247efb6 Mon Sep 17 00:00:00 2001 From: marcone <48169102+marcone@users.noreply.github.com> Date: Mon, 10 Jan 2022 11:37:39 -0800 Subject: [PATCH 142/155] configs: add CONFIG_LEDS_TRIGGER_PATTERN=m Enable the pattern led trigger. Signed-off-by: Marco Nelissen --- arch/arm/configs/bcm2709_defconfig | 1 + arch/arm/configs/bcm2711_defconfig | 1 + arch/arm/configs/bcmrpi_defconfig | 1 + arch/arm64/configs/bcm2711_defconfig | 1 + arch/arm64/configs/bcmrpi3_defconfig | 1 + 5 files changed, 5 insertions(+) diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 90810323667d..04a38fe4c6d9 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -1257,6 +1257,7 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_ACCESSIBILITY=y CONFIG_SPEAKUP=m diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index 7c4cf3c700d9..77cccb33de2a 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -1279,6 +1279,7 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_ACCESSIBILITY=y CONFIG_SPEAKUP=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index 434f4aedd246..f2a474cdad56 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1250,6 +1250,7 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_ACCESSIBILITY=y CONFIG_SPEAKUP=m diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index d712c932618c..b8e434797aa9 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -1282,6 +1282,7 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_ACCESSIBILITY=y CONFIG_SPEAKUP=m diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index a86ef9c5ee4d..57073001891c 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -1143,6 +1143,7 @@ CONFIG_LEDS_TRIGGER_CAMERA=m CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_ACCESSIBILITY=y CONFIG_SPEAKUP=m -- Gitee From e39c87e5d6e622c32651d013fd42be342c56fecf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 11 Jan 2022 10:48:30 +0000 Subject: [PATCH 143/155] arm: Fix custom rpi __memset32 and __memset64 See: https://github.com/raspberrypi/linux/issues/4798 Signed-off-by: Phil Elwell --- arch/arm/lib/memset_rpi.S | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/lib/memset_rpi.S b/arch/arm/lib/memset_rpi.S index e8469cecabc1..2a2d86759397 100644 --- a/arch/arm/lib/memset_rpi.S +++ b/arch/arm/lib/memset_rpi.S @@ -52,8 +52,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ ENTRY(mmioset) ENTRY(memset) -ENTRY(__memset32) -ENTRY(__memset64) S .req a1 DAT0 .req a2 @@ -63,10 +61,14 @@ ENTRY(__memset64) DAT3 .req lr orr DAT0, DAT0, DAT0, lsl #8 - push {S, lr} orr DAT0, DAT0, DAT0, lsl #16 + +ENTRY(__memset32) mov DAT1, DAT0 +ENTRY(__memset64) + push {S, lr} + /* See if we're guaranteed to have at least one 16-byte aligned 16-byte write */ cmp N, #31 blo 170f @@ -88,7 +90,7 @@ ENTRY(__memset64) stmcsia S!, {DAT0, DAT1} 164: /* Delayed set up of DAT2 and DAT3 so we could use them as scratch registers above */ mov DAT2, DAT0 - mov DAT3, DAT0 + mov DAT3, DAT1 /* Now the inner loop of 16-byte stores */ 165: stmia S!, {DAT0, DAT1, DAT2, DAT3} subs N, N, #16 @@ -104,7 +106,7 @@ ENTRY(__memset64) 170: /* Short case */ mov DAT2, DAT0 - mov DAT3, DAT0 + mov DAT3, DAT1 tst S, #3 beq 174f 172: subs N, N, #1 -- Gitee From 95530706834d84e7d6d2f4d749e34bac956e283a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Jan 2022 12:48:53 +0000 Subject: [PATCH 144/155] overlays: Add vl805 overlay With the automatic VL805 support being removed from the standard CM4 dtb (since most CM4 carriers don't have a VL805), retain support on those that do by creating a "vl805" overlay that restores the deleted "usb@0,0" node. The "vl805" overlay will be loaded automatically (after an upcoming firmware update) on CM4 boards where the EEPROM config includes the setting VL805=1. See: https://forums.raspberrypi.com/viewtopic.php?t=326088 Signed-off-by: Phil Elwell --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/README | 8 ++++++++ arch/arm/boot/dts/overlays/vl805-overlay.dts | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 arch/arm/boot/dts/overlays/vl805-overlay.dts diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile index b925054d95e4..bff07c1748b7 100644 --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -242,6 +242,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ vc4-kms-v3d-pi4.dtbo \ vc4-kms-vga666.dtbo \ vga666.dtbo \ + vl805.dtbo \ w1-gpio.dtbo \ w1-gpio-pullup.dtbo \ w5500.dtbo \ diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index 4d3448f047bf..f848a7fc87af 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -3731,6 +3731,14 @@ Load: dtoverlay=vga666 Params: +Name: vl805 +Info: Overlay to enable a VIA VL805 USB3 controller on CM4 carriers + Will be loaded automatically by up-to-date firmware if "VL805=1" is + set in the EEPROM config. +Load: dtoverlay=vl805 +Params: + + Name: w1-gpio Info: Configures the w1-gpio Onewire interface module. Use this overlay if you *don't* need a GPIO to drive an external pullup. diff --git a/arch/arm/boot/dts/overlays/vl805-overlay.dts b/arch/arm/boot/dts/overlays/vl805-overlay.dts new file mode 100644 index 000000000000..81adf34b29f2 --- /dev/null +++ b/arch/arm/boot/dts/overlays/vl805-overlay.dts @@ -0,0 +1,18 @@ +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "pcie0/pci@0,0"; + __overlay__ { + usb@0,0 { + reg = <0 0 0 0 0>; + resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; + }; + }; + }; +}; -- Gitee From adaed631c682372ebea3407eb9a22c1a8fceb710 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Jan 2022 17:27:03 +0000 Subject: [PATCH 145/155] arm: Fix annoying .eh_frame section warnings Replace the cfi directives with the UNWIND equivalents. This prevents the .eh_frame section from being created, eliminating the warnings. Signed-off-by: Phil Elwell --- arch/arm/lib/memcpy_rpi.S | 2 ++ arch/arm/lib/memcpymove.h | 45 ++++++++++++-------------------------- arch/arm/lib/memmove_rpi.S | 2 ++ 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/arch/arm/lib/memcpy_rpi.S b/arch/arm/lib/memcpy_rpi.S index 30f8a9089a83..77a1dbe28a18 100644 --- a/arch/arm/lib/memcpy_rpi.S +++ b/arch/arm/lib/memcpy_rpi.S @@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include +#include #include "arm-mem.h" #include "memcpymove.h" diff --git a/arch/arm/lib/memcpymove.h b/arch/arm/lib/memcpymove.h index d8be5849c860..883023aaa6c2 100644 --- a/arch/arm/lib/memcpymove.h +++ b/arch/arm/lib/memcpymove.h @@ -280,6 +280,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 199: pop {DAT3, DAT4, DAT5, DAT6, DAT7} pop {D, DAT1, DAT2, pc} + UNWIND( .fnend ) .endm .macro memcpy_medium_inner_loop backwards, align @@ -358,19 +359,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LAST .req ip OFF .req lr - .cfi_startproc + UNWIND( .fnstart ) push {D, DAT1, DAT2, lr} + UNWIND( .fnend ) - .cfi_def_cfa_offset 16 - .cfi_rel_offset D, 0 - .cfi_undefined S - .cfi_undefined N - .cfi_undefined DAT0 - .cfi_rel_offset DAT1, 4 - .cfi_rel_offset DAT2, 8 - .cfi_undefined LAST - .cfi_rel_offset lr, 12 + UNWIND( .fnstart ) + UNWIND( .save {D, DAT1, DAT2, lr} ) .if backwards add D, D, N @@ -386,17 +381,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Long case */ push {DAT3, DAT4, DAT5, DAT6, DAT7} + UNWIND( .fnend ) - .cfi_def_cfa_offset 36 - .cfi_rel_offset D, 20 - .cfi_rel_offset DAT1, 24 - .cfi_rel_offset DAT2, 28 - .cfi_rel_offset DAT3, 0 - .cfi_rel_offset DAT4, 4 - .cfi_rel_offset DAT5, 8 - .cfi_rel_offset DAT6, 12 - .cfi_rel_offset DAT7, 16 - .cfi_rel_offset lr, 32 + UNWIND( .fnstart ) + UNWIND( .save {D, DAT1, DAT2, lr} ) + UNWIND( .save {DAT3, DAT4, DAT5, DAT6, DAT7} ) /* Adjust N so that the decrement instruction can also test for * inner loop termination. We want it to stop when there are @@ -436,16 +425,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 156: memcpy_long_inner_loop backwards, 2 157: memcpy_long_inner_loop backwards, 3 - .cfi_def_cfa_offset 16 - .cfi_rel_offset D, 0 - .cfi_rel_offset DAT1, 4 - .cfi_rel_offset DAT2, 8 - .cfi_same_value DAT3 - .cfi_same_value DAT4 - .cfi_same_value DAT5 - .cfi_same_value DAT6 - .cfi_same_value DAT7 - .cfi_rel_offset lr, 12 + UNWIND( .fnend ) + + UNWIND( .fnstart ) + UNWIND( .save {D, DAT1, DAT2, lr} ) 160: /* Medium case */ preload_all backwards, 0, 0, S, N, DAT2, OFF @@ -488,7 +471,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. memcpy_short_inner_loop backwards, 0 140: memcpy_short_inner_loop backwards, 1 - .cfi_endproc + UNWIND( .fnend ) .unreq D .unreq S diff --git a/arch/arm/lib/memmove_rpi.S b/arch/arm/lib/memmove_rpi.S index 8b0760c0904c..5715dfd95859 100644 --- a/arch/arm/lib/memmove_rpi.S +++ b/arch/arm/lib/memmove_rpi.S @@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include +#include #include "arm-mem.h" #include "memcpymove.h" -- Gitee From d3c60590340ef6687f5f19e3ca6597bf070660b6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 13 Jan 2022 11:30:42 +0000 Subject: [PATCH 146/155] drm/vc4: Disable Gamma control on HVS5 due to issues writing the table Still under investigation, but the conditions under which the HVS will accept values written to the gamma PWL are not straightforward. Disable gamma on HVS5 again until it can be resolved to avoid gamma being enabled with an incorrect table. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_crtc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index b6b41b3c664f..f73d73425f08 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1209,15 +1209,9 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, if (!vc4->hvs->hvs5) { drm_mode_crtc_set_gamma_size(crtc, ARRAY_SIZE(vc4_crtc->lut_r)); - } else { - /* This is a lie for hvs5 which uses a 16 point PWL, but it - * allows for something smarter than just 16 linearly spaced - * segments. Conversion is done in vc5_hvs_update_gamma_lut. - */ - drm_mode_crtc_set_gamma_size(crtc, 256); + drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); } - drm_crtc_enable_color_mgmt(crtc, 0, false, crtc->gamma_size); if (!vc4->hvs->hvs5) { /* We support CTM, but only for one CRTC at a time. It's therefore -- Gitee From 190ed28d632f9cda32bbf79df75d56e388820f3e Mon Sep 17 00:00:00 2001 From: Dom Cobley Date: Thu, 13 Jan 2022 15:47:23 +0000 Subject: [PATCH 147/155] drm/vc4: hdmi: Fix clock value used for validating hdmi modes We are using mode->crt_clock here which is filled by drm_mode_set_crtcinfo() which is called right after .mode_valid. Use mode->clock which is valid here. Fixes: 624d93a4f0 ("drm/vc4: hdmi: Move clock calculation into its own function") Signed-off-by: Dom Cobley --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index ccfcfce39426..d71cd4378505 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1496,7 +1496,7 @@ vc4_hdmi_encoder_compute_mode_clock(const struct drm_display_mode *mode, unsigned int bpc, enum vc4_hdmi_output_format fmt) { - unsigned long long clock = mode->crtc_clock * 1000; + unsigned long long clock = mode->clock * 1000; if (mode->flags & DRM_MODE_FLAG_DBLCLK) clock = clock * 2; -- Gitee From 32ba097caa726bced72ddf1c6f7b17d5d02fe130 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Sat, 8 Jan 2022 13:24:10 +0000 Subject: [PATCH 148/155] drm/vc4: Add alpha_blend_mode property to each plane. Move from only supporting the default of pre-multiplied alpha to supporting user specified blend mode using the standardised property. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_plane.c | 62 ++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 7947cf47b6e1..074bdfdb184c 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -667,6 +667,48 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { } }; +static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) +{ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); + + switch (state->pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); + default: + case DRM_MODE_BLEND_PREMULTI: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, + SCALER_POS2_ALPHA_MODE) | + SCALER_POS2_ALPHA_PREMULT; + case DRM_MODE_BLEND_COVERAGE: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, + SCALER_POS2_ALPHA_MODE); + } +} + +static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) +{ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); + + switch (state->pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); + default: + case DRM_MODE_BLEND_PREMULTI: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, + SCALER5_CTL2_ALPHA_MODE) | + SCALER5_CTL2_ALPHA_PREMULT; + case DRM_MODE_BLEND_COVERAGE: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, + SCALER5_CTL2_ALPHA_MODE); + } +} + /* Writes out a full display list for an active plane to the plane's * private dlist state. */ @@ -928,13 +970,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, /* Position Word 2: Source Image Size, Alpha */ vc4_state->pos2_offset = vc4_state->dlist_count; vc4_dlist_write(vc4_state, - VC4_SET_FIELD(fb->format->has_alpha ? - SCALER_POS2_ALPHA_MODE_PIPELINE : - SCALER_POS2_ALPHA_MODE_FIXED, - SCALER_POS2_ALPHA_MODE) | (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | - (fb->format->has_alpha ? - SCALER_POS2_ALPHA_PREMULT : 0) | + vc4_hvs4_get_alpha_blend_mode(state) | VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | VC4_SET_FIELD(vc4_state->src_h[0], @@ -979,14 +1016,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA) | - (fb->format->has_alpha ? - SCALER5_CTL2_ALPHA_PREMULT : 0) | + vc4_hvs5_get_alpha_blend_mode(state) | (mix_plane_alpha ? - SCALER5_CTL2_ALPHA_MIX : 0) | - VC4_SET_FIELD(fb->format->has_alpha ? - SCALER5_CTL2_ALPHA_MODE_PIPELINE : - SCALER5_CTL2_ALPHA_MODE_FIXED, - SCALER5_CTL2_ALPHA_MODE) + SCALER5_CTL2_ALPHA_MIX : 0) ); /* Position Word 1: Scaled Image Dimensions. */ @@ -1470,6 +1502,10 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, drm_plane_helper_add(plane, &vc4_plane_helper_funcs); drm_plane_create_alpha_property(plane); + drm_plane_create_blend_mode_property(plane, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | -- Gitee From 0faca8bc663635a91ccccc1061d73ee373d935b3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Jan 2022 14:39:46 +0000 Subject: [PATCH 149/155] ARM: dts: Remove VL805 USB node from CM4 dts Neither the CM4 module nor the CM4IO board have a VL805 USB3 controller. The existing "usb@0,0" node is a hangover from the Pi 4 dts; delete it. An up-to-date firmware will automatically load the vl805 overlay on CM4s with VL805=1 in the EEPROM config, ensuring that the firmware is notified of any PCIe reset. See: https://forums.raspberrypi.com/viewtopic.php?t=326088 Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2711-rpi-cm4.dts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts index 86de6bed42fb..5dbd1b77260b 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-cm4.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-cm4.dts @@ -3,8 +3,6 @@ #include "bcm2711.dtsi" #include "bcm2835-rpi.dtsi" -#include - / { compatible = "raspberrypi,4-compute-module", "brcm,bcm2711"; model = "Raspberry Pi Compute Module 4"; @@ -293,11 +291,6 @@ ranges; reg = <0 0 0 0 0>; - - usb@0,0 { - reg = <0 0 0 0 0>; - resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; - }; }; }; -- Gitee From 13b590640e8f670aea2c230b50ed39c881d063fe Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Tue, 18 Jan 2022 13:13:14 +0000 Subject: [PATCH 150/155] drivers: bcm2835_unicam: Disable trigger mode operation On a Pi3 B/B+ platform the imx219 sensor frequently generates a single corrupt frame when the sensor first starts. This can either be a missing line, or invalid samples within the line. This only occurrs using the Unicam kernel driver. Disabling trigger mode elimiates this corruption. Since trigger mode is a legacy feature copied from the firmware driver and not expected to be needed, remove it. Tested on the Raspberry Pi cameras and shows no ill effects. Signed-off-by: Naushir Patuck --- drivers/media/platform/bcm2835/bcm2835-unicam.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c index 3329a7b006f2..99edc044c934 100644 --- a/drivers/media/platform/bcm2835/bcm2835-unicam.c +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c @@ -983,11 +983,6 @@ static irqreturn_t unicam_isr(int irq, void *dev) } } - if (reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) { - /* Switch out of trigger mode if selected */ - reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC); - reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM); - } return IRQ_HANDLED; } @@ -2297,8 +2292,7 @@ static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr) reg_write_field(dev, UNICAM_ANA, 0, UNICAM_DDL); - /* Always start in trigger frame capture mode (UNICAM_FCM set) */ - val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB; + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_IBOB; set_field(&val, line_int_freq, UNICAM_LCIE_MASK); reg_write(dev, UNICAM_ICTL, val); reg_write(dev, UNICAM_STA, UNICAM_STA_MASK_ALL); @@ -2411,12 +2405,6 @@ static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr) /* Load embedded data buffer pointers if needed */ if (dev->node[METADATA_PAD].streaming && dev->sensor_embedded_data) reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP); - - /* - * Enable trigger only for the first frame to - * sync correctly to the FS from the source. - */ - reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_TFC); } static void unicam_disable(struct unicam_device *dev) -- Gitee From d5ecb80d3e024364558a8547b7c63a8da561cd50 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 21 Jan 2022 08:49:13 +0000 Subject: [PATCH 151/155] arm: Remove spurious .fnend directive ...a.k.a. Fix annoying build error Some toolchains rightly object to the fact that once the acros are expanded this results in multiple ".fnend"s without ".fnstart"s. See: https://github.com/raspberrypi/linux/issues/4836 Signed-off-by: Phil Elwell --- arch/arm/lib/memcpymove.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/lib/memcpymove.h b/arch/arm/lib/memcpymove.h index 883023aaa6c2..65a6e065a7f2 100644 --- a/arch/arm/lib/memcpymove.h +++ b/arch/arm/lib/memcpymove.h @@ -280,7 +280,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 199: pop {DAT3, DAT4, DAT5, DAT6, DAT7} pop {D, DAT1, DAT2, pc} - UNWIND( .fnend ) .endm .macro memcpy_medium_inner_loop backwards, align -- Gitee From 0b3597e86a932dc8175f0f10c5eb348a34e4ae0b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 21 Jan 2022 12:24:57 +0000 Subject: [PATCH 152/155] ARM: dts: BCM2711 AON_INTR2 generates IRQ edges THe AON_INTR2 controller manages the HDMI interrupts, combining them into a single interrupt passed to the GIC. bcm2711.dtsi declares the interrupt as being IRQ_TYPE_LEVEL_HIGH, but it should be IRQ_TYPE_EDGE_RISING. Most of the time the distinction shouldn't matter, but there is a small possibility of losing interrupts unless it is corrected. See: http://lists.infradead.org/pipermail/linux-arm-kernel/2022-January/710292.html Signed-off-by: Phil Elwell --- arch/arm/boot/dts/bcm2711.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm2711.dtsi b/arch/arm/boot/dts/bcm2711.dtsi index 544633a84433..2b834efddc06 100644 --- a/arch/arm/boot/dts/bcm2711.dtsi +++ b/arch/arm/boot/dts/bcm2711.dtsi @@ -319,7 +319,7 @@ aon_intr: interrupt-controller@7ef00100 { compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc"; reg = <0x7ef00100 0x30>; - interrupts = ; + interrupts = ; interrupt-controller; #interrupt-cells = <1>; status = "disabled"; @@ -402,7 +402,7 @@ <&clk_27MHz>; resets = <&dvp 1>; interrupt-parent = <&aon_intr>; - interrupts = <8>, <7>, <6>, + interrupts = <8>, <7>, <6>, // This is correct <9>, <10>, <11>; interrupt-names = "cec-tx", "cec-rx", "cec-low", "wakeup", "hpd-connected", "hpd-removed"; -- Gitee From 0f2b3f6432f786a206cb635fb1bfb9665a7fdc1c Mon Sep 17 00:00:00 2001 From: Andreas Watterott <1488433+awatterott@users.noreply.github.com> Date: Sat, 22 Jan 2022 12:32:09 +0100 Subject: [PATCH 153/155] update rpi-display-overlay.dts pins for 5.10+ backlight has been turned off --- arch/arm/boot/dts/overlays/rpi-display-overlay.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts index de87432ff2be..2cf937b56456 100644 --- a/arch/arm/boot/dts/overlays/rpi-display-overlay.dts +++ b/arch/arm/boot/dts/overlays/rpi-display-overlay.dts @@ -61,7 +61,7 @@ buswidth = <8>; reset-gpios = <&gpio 23 1>; dc-gpios = <&gpio 24 0>; - led-gpios = <&gpio 18 0>; + led-gpios = <&gpio 18 1>; debug = <0>; }; -- Gitee From ac450f92b2e20a3c9089864b980bb4d1e168aa24 Mon Sep 17 00:00:00 2001 From: yafen Date: Tue, 25 Jan 2022 23:16:45 +0800 Subject: [PATCH 154/155] rm scripts/gcc-plugin.sh --- scripts/gcc-plugin.sh | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100755 scripts/gcc-plugin.sh diff --git a/scripts/gcc-plugin.sh b/scripts/gcc-plugin.sh deleted file mode 100755 index b79fd0bea838..000000000000 --- a/scripts/gcc-plugin.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -set -e - -srctree=$(dirname "$0") - -gccplugins_dir=$($* -print-file-name=plugin) - -# we need a c++ compiler that supports the designated initializer GNU extension -$HOSTCC -c -x c++ -std=gnu++98 - -fsyntax-only -I $srctree/gcc-plugins -I $gccplugins_dir/include 2>/dev/null < Date: Tue, 25 Jan 2022 15:48:53 +0000 Subject: [PATCH 155/155] media: i2c: imx219: Correct the minimum vblanking value The datasheet for this sensor documents the minimum vblanking as being 32 lines. It does fix some problems with occasional black lines at the bottom of images (tested on Raspberry Pi). Signed-off-by: David Plowman --- drivers/media/i2c/imx219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 6aed851865ec..7f0fdd6fd7bc 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -55,7 +55,7 @@ #define IMX219_VTS_30FPS_640x480 0x06e3 #define IMX219_VTS_MAX 0xffff -#define IMX219_VBLANK_MIN 4 +#define IMX219_VBLANK_MIN 32 /*Frame Length Line*/ #define IMX219_FLL_MIN 0x08a6 -- Gitee